6

One thing that has bugged me about Emacs since I switched to it is that I can only get it to syntax highlight decimal numbers correctly in C code. For example, these numbers are highlighted correctly:

1234
1234l
1234.5f

However these numbers are NOT highlighted correctly:

0x1234  // x is different colour
0xabcd  // no hex digits are coloured
019     // invalid digit 9 is coloured like it is correct

Is it possible to have Emacs colour every character in these numbers the same? Even better if invalid numbers (like 019 or 0x0g) can be coloured differently to make them stand out.

Malvineous
  • 25,144
  • 16
  • 116
  • 151
  • Emacs has several different highlighting packages; `font-lock-mode` and `hilit19`, among others. Which are you using? – Ernest Friedman-Hill Jan 14 '12 at 04:15
  • I doubt standard C-mode use hilit19 which I've never heard about until now. font-lock is much more likely. – Tom Jan 14 '12 at 06:51
  • I'm not sure how to tell - I would imagine I'm still using whatever the default is. – Malvineous Jan 14 '12 at 07:18
  • 1
    Standard Emacs does not highlight normal numbers like `1234`, so you must have some kind of additional package to get it. Anyway, the best way to get all numbers to be highlighted is to use `font-lock-add-keywords`, unless you can find a package to do it for you. – Lindydancer Jan 14 '12 at 09:17
  • Ah, my mistake - I had added (font-lock-add-keywords nil '(("[0-9][0-9.]*[lLfF]?" 0 font-lock-string-face))) to my init.el – Malvineous Jan 15 '12 at 00:48

3 Answers3

6

Thanks for the pointer Mischa Arefiev, it got me looking in the right places. This is what I have come up with, and it covers all of my original requirements. The only limitation I'm aware of right now is that it will highlight an invalid number suffix as if it were correct (e.g. "123ulu")

(add-hook 'c-mode-common-hook (lambda ()
    (font-lock-add-keywords nil '(

        ; Valid hex number (will highlight invalid suffix though)
        ("\\b0x[[:xdigit:]]+[uUlL]*\\b" . font-lock-string-face)

        ; Invalid hex number
        ("\\b0x\\(\\w\\|\\.\\)+\\b" . font-lock-warning-face)

        ; Valid floating point number.
        ("\\(\\b[0-9]+\\|\\)\\(\\.\\)\\([0-9]+\\(e[-]?[0-9]+\\)?\\([lL]?\\|[dD]?[fF]?\\)\\)\\b" (1 font-lock-string-face) (3 font-lock-string-face))

        ; Invalid floating point number.  Must be before valid decimal.
        ("\\b[0-9].*?\\..+?\\b" . font-lock-warning-face)

        ; Valid decimal number.  Must be before octal regexes otherwise 0 and 0l
        ; will be highlighted as errors.  Will highlight invalid suffix though.
        ("\\b\\(\\(0\\|[1-9][0-9]*\\)[uUlL]*\\)\\b" 1 font-lock-string-face)

        ; Valid octal number
        ("\\b0[0-7]+[uUlL]*\\b" . font-lock-string-face)

        ; Floating point number with no digits after the period.  This must be
        ; after the invalid numbers, otherwise it will "steal" some invalid
        ; numbers and highlight them as valid.
        ("\\b\\([0-9]+\\)\\." (1 font-lock-string-face))

        ; Invalid number.  Must be last so it only highlights anything not
        ; matched above.
        ("\\b[0-9]\\(\\w\\|\\.\\)+?\\b" . font-lock-warning-face)
    ))
))

Any suggestions/optimisations/fixes welcome!

EDIT: Stopped it from highlighting numbers within comments.

Malvineous
  • 25,144
  • 16
  • 116
  • 151
  • seems that this will highlight `0` in `a.0` as a valid number and `0].a` in `a[0].a` as an invalid number? (also `f(0).a` has the same issue with `a[0].a`) – yuyichao Jul 07 '12 at 13:51
  • @yuyichao: It does, unfortunately. Please advise if you know how to fix! – Malvineous Jul 09 '12 at 11:41
  • I have tried to do that, an incomplete version is here https://github.com/yuyichao/emacsrc/blob/master/script/c-cpp.el. however, it doesn't highlight invalid floating really well, and it doesn't highlight binary number either (might complete it if I have time, suggestion welcome =D) – yuyichao Jul 09 '12 at 14:31
1

Perhaps this will work:

  (font-lock-add-keywords
   'c-mode
   '(("0x\\([0-9a-fA-F]+\\)" . font-lock-builtin-face)))
Mischa Arefiev
  • 5,227
  • 4
  • 26
  • 34
0

We can use the Emacs regular expression

\<0[xX][0-9A-Fa-f]+

to match hexadecimal numbers and

\<[\-+]*[0-9]*\.?[0-9]+\([ulUL]+\|[eE][\-+]?[0-9]+\)?

to match any integer/float/scientific number. They shall be applied in sequence, i.e. first register the hexadecimal number expression. These are working well for me now for a long time. Look this post for the complete Lisp code, which also adds C++11 keywords.

Community
  • 1
  • 1
Andreas Spindler
  • 7,568
  • 4
  • 43
  • 34