6

Is it possible for Emacs to highlight backslash escape (e.g. \n) and format keyword (e.g. %s) inside string, without messing up current modes' faces? Like this:

enter image description here

3

One way to do this is using library Highlight (highlight.el).

Use command hlt-highlight-regexp-region (bound by default to C-x X h x), specifying a regexp that matches either or both things you want to highlight. Examples:

  • Interactively:

    C-x X h x \\. RET
    
  • From Lisp:

    (hlt-highlight-regexp-region nil nil "\\\\." 'success)
    
| improve this answer | |
  • I cannot find this function. And I don't sure if this is correct: (hlt-highlight-regexp-region (point-min) (point-max) "\\." 'font-lock-regexp-grouping-backslash). It not works... – kuanyui Oct 24 '14 at 3:12
  • Yes, that is the function. But in Lisp you have to double backslashes in strings (always) - use 4 backslashes in your sexp and it should work. If you call the command interactively, then you need only type 2 backslashes. – Drew Oct 24 '14 at 3:40
  • Is there any way to make it highlight automatically? – kuanyui Oct 24 '14 at 9:35
  • 1
    You could also use the built-in hi-lock package, depending on your needs. The command highlight-regexp is bound to M-s h r by default. This operates on the whole buffer rather than the region. – glucas Oct 24 '14 at 14:53
  • 1
    @kuanyui: If you want to highlight a regexp only within certain contexts (e.g. strings) then you need to specify/control that. hlt-highlight-regexp-region does what it says: it highlights regexp matches in the region. Limit the region to a string and it will limit its highlighting to that string. It is a function; you can call it in your own code; use, for example, narrow-to-region to operate on specific strings, in a loop that advances over the area you want to affect. – Drew Oct 26 '14 at 16:44
3

You can use the built-in hi-lock feature to highlight patterns in the current buffer. As @Drew suggested in his answer, you can use this interactively or in a mode hook to highlight interesting patterns.

The command highlight-regexp is bound to M-s h r by default and prompts for a regular expression and a highlight color.

You can also define a mode hook to highlight patterns automatically. For example you can highlight alphabetic characters preceded by \ or % in all programming modes using something like:

(add-hook 'prog-mode-hook '(lambda () 
        (highlight-regexp "%[[:alpha:]]\\|\\\\[[:alpha:]]")))
| improve this answer | |
  • 1
    A faster regexp would be \\(?:\\\\\\|%\\)[[:alpha:]], if I understand emacs' engine well enough. – Sean Allred Oct 26 '14 at 23:51
  • Actually, using a [%\\] set for the first character might be best? [%\\][[:alpha:]] – glucas Oct 28 '14 at 19:18
  • Oh shoot, yeah. Dunno how I forgot about [ab] syntax. – Sean Allred Oct 28 '14 at 19:20
2

There's the highly incomplete highlight-escape-sequences package that does exactly that, it seems to support Ruby and Javascript only. It's one of the very many briefly illustrated packages from Wilfred's guide to syntax highlighting.

| improve this answer | |
  • highlight-escape-sequences not works at all even if having set the hes-simple-modes. – kuanyui Oct 24 '14 at 3:03
  • You are aware hes-simple-modes is only set correctly via customize? If you want to avoid using it, you'd need to figure out the right instructions from the :set keyword in the customization code in the sources. – wasamasa Oct 24 '14 at 9:04
  • I found the problem, it doesn't accept prog-mode, but the real mode name like emacs-lisp-mode. Sadly, this cannot highlight string format keyword. :( – kuanyui Oct 24 '14 at 9:31
  • Sounds like an idea for a new package actually :) – wasamasa Oct 24 '14 at 9:42
2

The following handles the basic case:

(defface my-backslash-escape-backslash-face
  '((t :inherit font-lock-regexp-grouping-backslash))
  "Face for the back-slash component of a back-slash escape."
  :group 'font-lock-faces)

(defface my-backslash-escape-char-face
  '((t :inherit font-lock-regexp-grouping-construct))
  "Face for the charcter component of a back-slash escape."
  :group 'font-lock-faces)

(defface my-format-code-format-face
  '((t :inherit font-lock-regexp-grouping-backslash))
  "Face for the % component of a printf format code."
  :group 'font-lock-faces)

(defface my-format-code-directive-face
  '((t :inherit font-lock-regexp-grouping-construct))
  "Face for the directive component of a printf format code."
  :group 'font-lock-faces)


(font-lock-add-keywords 'c-mode
   '(("\\(\\\\\\)." 1 'my-backslash-escape-backslash-face prepend)
     ("\\\\\\(.\\)" 1 'my-backslash-escape-char-face      prepend)
     ("\\(%\\)."    1 'my-format-code-format-face         prepend)
     ("%\\(.\\)"    1 'my-format-code-directive-face      prepend)))

You don't often type backslash escapes outside of strings but a more elaborate regex might handle that.

Format specifiers have a lot of options so you might also want a more elaborate regex to handle those.

(Feel free to edit this if you're a regex ninja...)

| improve this answer | |
0

I took Billy Highlights' solution and modified the regular expression so it would correctly capture the printf format based on cplusplus.com. I used this as a reference to get going.

(font-lock-add-keywords 'c-mode
  '(("\\(\\\\\\)." 1 'my-backslash-escape-backslash-face prepend)
    ("\\\\\\(.\\)" 1 'my-backslash-escape-char-face      prepend)
    ("\\(%\\)\\(\\(\\([-0 #\\+]\\)?\\([0-9]+\\|\\*\\)?\\(\\.\\*\\|\\.[0-9]+\\)?\\([hljztL]\\|l\\{2\\}\\|h\\{2\\}\\)?\\([diuoxXfFeEgGaAcspn]\\)\\)\\|%\\)"
      (1 'my-format-code-format-face         prepend)
      (2 'my-format-code-directive-face      prepend))))
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.