From: Paul Nelson Date: Mon, 31 Mar 2025 13:37:14 +0000 (+0200) Subject: Restrict symbol prettification to displayable glyphs X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=85ae30e7b973c23c9ca06d04d6aca21b1632404f;p=emacs.git Restrict symbol prettification to displayable glyphs * lisp/international/mule.el (char-displayable-on-frame-p): New function used to determine whether a character can be meaningfully displayed on a given frame. * doc/lispref/display.texi (Fontsets): Document it. * lisp/progmodes/prog-mode.el (prettify-symbols--composition-displayable-p): New function used to restrict to displayable prettification symbols. This prevents issues with missing characters appearing as boxes. (prettify-symbols--make-keywords): Use it. (Bug#77381) (cherry picked from commit 2d0b5f34a008979d34f337c872bcf93a296c6ec2) --- diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 14c0eb82077..446169ec711 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4146,6 +4146,14 @@ available, since it also checks whether the coding system for the text terminal can encode the character (@pxref{Terminal I/O Encoding}). @end defun +@defun char-displayable-on-frame-p char frame +This function behaves like @code{char-displayable-p} does (relative to +@var{frame}), but in the graphical case, it does not perform the final +check of whether the underlying text terminal can encode the character. +It thus provides a displayability check for @var{char} more specific to +@var{frame}. +@end defun + @node Low-Level Font @subsection Low-Level Font Representation @cindex font property diff --git a/lisp/international/mule.el b/lisp/international/mule.el index f72cc815287..cb2aa5b9480 100644 --- a/lisp/international/mule.el +++ b/lisp/international/mule.el @@ -528,6 +528,32 @@ per-character basis, this may not be accurate." (throw 'tag3 charset))) charset-list) nil))))))))))) + +(defun char-displayable-on-frame-p (char &optional frame) + "Return non-nil if CHAR can be displayed in FRAME. +FRAME nil means the selected frame. + +This function provides a stricter test than `char-displayable-p' does +for determining if a character will display properly: in the graphical +case, it does not check whether the underlying terminal can encode the +character. + +Specifically, this function returns non-nil: + +- for a text terminal, if `char-displayable-p' returns non-nil. + +- for a graphical terminal, if `char-displayable-p' returns either t or + a font object. + +The two functions differ in behavior (i.e., `char-displayable-strict-p' +returns nil but `char-displayable-p' does not) if the underlying +terminal is graphical and can encode the character, but FRAME cannot." + (let ((display-capability (with-selected-frame (or frame (selected-frame)) + (char-displayable-p char)))) + (if (display-graphic-p frame) + (or (eq display-capability t) + (fontp display-capability)) + display-capability))) ;; Save the ASCII case table in case we need it later. Some locales ;; (such as Turkish) modify the case behavior of ASCII characters, diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index 0f67fb1585e..47bf5bede7e 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -232,10 +232,37 @@ Regexp match data 0 specifies the characters to be composed." ;; Return nil because we're not adding any face property. nil) +(defun prettify-symbols--composition-displayable-p (composition) + "Return non-nil if COMPOSITION can be displayed with the current fonts. +COMPOSITION can be a single character, a string, or a sequence (vector or +list) of characters and composition rules as described in the documentation +of `prettify-symbols-alist' and `compose-region'." + (cond + ((characterp composition) + (char-displayable-on-frame-p composition)) + ((stringp composition) + (seq-every-p #'char-displayable-on-frame-p composition)) + ((seqp composition) + ;; check that every even-indexed element is displayable + (seq-every-p + (lambda (idx-elt) + (if (evenp (car idx-elt)) + (char-displayable-on-frame-p (cdr idx-elt)) + t)) + (seq-map-indexed #'cons composition))) + (t + ;; silently ignore invalid compositions + t))) + (defun prettify-symbols--make-keywords () (if prettify-symbols-alist - `((,(regexp-opt (mapcar 'car prettify-symbols-alist) t) - (0 (prettify-symbols--compose-symbol ',prettify-symbols-alist)))) + (let ((filtered-alist + (seq-filter + (lambda (elt) + (prettify-symbols--composition-displayable-p (cdr elt))) + prettify-symbols-alist))) + `((,(regexp-opt (mapcar 'car filtered-alist) t) + (0 (prettify-symbols--compose-symbol ',filtered-alist))))) nil)) (defvar-local prettify-symbols--keywords nil)