With prettify-symbols-mode it is possible to replace strings by a character, or a character composition, e.g.

;; \lambda → λ
(push '("\\lambda" . ?λ) prettify-symbols-alist) 

Optionally, it allows combining multiple characters, which will be put on top of each other, e.g. in order to create an underline bold character,

(push '("\\mathbf x" . "xx_") prettify-symbols-alist)

But does Emacs also have a feature, that allows multi-character replacements, e.g. allowing a prettification

\section{Hello World}  → ###{Hello World} ?

I found a solution by looking into the implementation of ``prettify-symbols-mode''.

   ;; Special form for section etc.
   (let ((spec '(("\\\\part\\b"          font-latex-sectioning-0-face "#")
                 ("\\\\chapter\\b"       font-latex-sectioning-1-face "##")
                 ("\\\\section\\b"       font-latex-sectioning-2-face "###")
                 ("\\\\subsection\\b"    font-latex-sectioning-3-face "####")
                 ("\\\\subsubsection\\b" font-latex-sectioning-4-face "#####")
                 ("\\\\paragraph\\b"     shadow "¶"))))
     (dolist (s spec)
       (let ((regexp (nth 0 s))
             (face (nth 1 s))
             (repl (nth 2 s)))
         (font-lock-add-keywords nil 
           `((,regexp 0 
               (prog1 ',face 
                 (add-text-properties (match-beginning 0) (match-end 0)
                   '(display ,repl)))))))))
   (push 'display font-lock-extra-managed-props) ;; Allow removal of display property by font-lock
   (push 'composition font-lock-extra-managed-props)

How it works

  • font-lock-mode uses regexp matching to find the keywords.
  • When a keyword is found, the prog1 part is evaluated; Its return value is used as face for the regexp, but it can also be used for side-effects.
  • Using the region found by the regexp matcher (match-beginning, match-end), a display test property is applied, which visually replaces the region by the given string.
  • Font-lock mode must be told, that it should remove the display and composition properties, by adding the symbols to font-lock-extra-managed-props. Without this, the composition/display properties would remain after editing the text, such that it doesn't match the keyword anymore.
  • Sadly, this can conflict with other 'display properties, such as the (raise FLOAT) property used by AucTeX for subscripts and superscripts. In such cases some tinkering is required, in order to create a 'display string, which itself inherits the display/raise property, and is applied after superscript fontification, since AucTeX is not aware of such customizations. You'd end up with a string object with nested display properties, such as

    ;; (buffer-string)
    #("Hello Original Content World" 6 22
         #("Replacement" 0 11
              (raise -0.5)))))

Your Answer

