Skip to main content
Fixed the issue of lacking de-fontification, and added an explanation on nested display properties.
Source Link
kdb
  • 1.6k
  • 12
  • 24

I found a solution by looking into the implementation of ``prettify-symbols-mode'', though it is lackluster (no editing once fontified):.

   ;; 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)
  • font-lock-mode uses regexp matching to find the keywords.

    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.

    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.

    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
         (display
           #("Replacement" 0 11
              (display
                (raise -0.5)))))
    

I found a solution by looking into the implementation of ``prettify-symbols-mode'', though it is lackluster (no editing once fontified):

   ;; 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)))))))))
  • 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.

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)
  • 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
         (display
           #("Replacement" 0 11
              (display
                (raise -0.5)))))
    
Source Link
kdb
  • 1.6k
  • 12
  • 24

I found a solution by looking into the implementation of ``prettify-symbols-mode'', though it is lackluster (no editing once fontified):

   ;; 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)))))))))

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.