I don’t like the way Emacs highlights C++. Not the colours themselves but how it decides to assign them.
Emacs is on the left with the badger theme, Vim on the right with sorcerer:
Classes and functions get different colours, variables get different colours where they’re defined and used, numbers don’t stand out, etc. It’s a jumble of different colours, distracting and difficult to read.
I want it to look like Vim, and also want separate colours for C++, independent of the theme affecting the rest of Emacs.
This stack overflow answer describes how to add support for C++11 keywords. It copies the faces from the theme, then adds new regexes with font-lock-add-keywords, so I just expanded it and added some make-local-variable calls to vary the string and comment colours in the buffer.
(require 'font-lock)
(load-theme 'badger)
; http://stackoverflow.com/a/12934513
(defun --copy-face (new-face face)
"Define NEW-FACE from existing FACE."
(copy-face face new-face)
(eval `(defvar ,new-face nil))
(set new-face new-face))
(--copy-face 'font-lock-mykeyword-face 'font-lock-keyword-face)
(--copy-face 'font-lock-mytype-face 'font-lock-type-face)
(--copy-face 'font-lock-myidentifier-face 'font-lock-builtin-face)
(--copy-face 'font-lock-mydefault-face 'font-lock-builtin-face)
(--copy-face 'font-lock-myconstant-face 'font-lock-constant-face)
(--copy-face 'font-lock-mypreprocessor-face 'font-lock-preprocessor-face)
(--copy-face 'font-lock-mynewline-face 'font-lock-string-face)
(--copy-face 'font-lock-mystring-face 'font-lock-string-face)
(--copy-face 'font-lock-mycomment-face 'font-lock-comment-face)
(--copy-face 'font-lock-mywarning-face 'font-lock-warning-face)
(global-font-lock-mode t)
(setq font-lock-maximum-decoration t)
(defun my-cpp-colours ()
(set (make-local-variable 'font-lock-string-face) 'font-lock-mystring-face)
(set (make-local-variable 'font-lock-comment-face) 'font-lock-mycomment-face)
(font-lock-add-keywords
nil '(
;; preprocessor
("#.*\\(<.*>\\)" 1 font-lock-mystring-face)
("#\\(include\\) *\\\".*\\\"" 1 font-lock-mypreprocessor-face)
("#\\(include\\) *<.*>" 1 font-lock-mypreprocessor-face)
("#\\<\\(define\\|include\\|undef\\|ifdef\\|ifndef\\|if\\|endif\\|pragma\\)\\>.*"
. font-lock-mypreprocessor-face)
("#" . font-lock-mypreprocessor-face)
;; keywords and types
("\\<\\(void\\|unsigned\\|signed\\|char\\|short\\|bool\\|int\\|long\\|float\\|double\\)\\>"
. font-lock-mytype-face)
("\\<\\(typename\\|template\\|inline\\|namespace\\|public\\|protected\\|private\\)\\>"
. font-lock-mytype-face)
("\\<\\(auto\\|volatile\\|static\\|const\\)\\>"
. font-lock-mytype-face)
("\\<\\(alignof\\|alignas\\|constexpr\\|decltype\\|noexcept\\|nullptr\\|static_assert\\|thread_local\\|override\\|final\\)\\>"
. font-lock-mykeyword-face)
("\\<\\(char[0-9]+_t\\|u?int[0-9]+_t\\)\\>"
. font-lock-mykeyword-face)
("\\<\\(for\\|while\\|do\\|if\\|else\\|return\\|continue\\|break\\|switch\\|case\\|default\\)\\>"
. font-lock-mykeyword-face)
("\\<\\(new\\|delete\\|this\\)\\>"
. font-lock-mykeyword-face)
("\\<\\(using\\|class\\|struct\\|virtual\\)\\>"
. font-lock-mykeyword-face)
;; hexadecimal numbers
("\\<0[xX][0-9A-Fa-f]+\\>"
. font-lock-myconstant-face)
;; booleans
("\\<\\(false\\|true\\)\\>"
. font-lock-myconstant-face)
;; integer/float/scientific numbers
("\\<[\\-+]*[0-9]*\\.?[0-9]+\\([ulULf]+\\|[eE][\\-+]?[0-9]+\\)?\\>"
. font-lock-myconstant-face)
;; quote/newline/tab
("\\(\\\\\"\\|\\\\n\\|\\\\t\\)"
1 font-lock-mynewline-face t)
("\\<\\(FIXME\\|TODO\\)\\>"
1 font-lock-mywarning-face t)
("\\<[A-Za-z_]+[A-Za-z_0-9]*\\>"
. font-lock-myidentifier-face)
("." . font-lock-mydefault-face)
) 'set)
)
I also want the text between #if 0 and #endif greyed out. I tried a few methods, this stack overflow answer worked best:
; https://stackoverflow.com/a/7215951
(defun cpp-highlight-if-0/1 ()
"Modify the face of text in between #if 0 ... #endif."
(interactive)
(setq cpp-known-face '(foreground-color . "#686858"))
(setq cpp-unknown-face 'default)
(setq cpp-face-type 'dark)
(setq cpp-known-writable 't)
(setq cpp-unknown-writable 't)
(setq cpp-edit-list
'((#("1" 0 1
(fontified nil))
nil
(foreground-color . "#686858")
both nil)
(#("0" 0 1
(fontified nil))
(foreground-color . "#686858")
nil
both nil)))
(cpp-highlight-buffer t))
Call them from the mode hook:
(defun my-cpp-mode-hook () ;;(evil-local-set-key 'normal (kbd "M-m") 'projectile-compile-project) (auto-fill-mode -1) (cpp-highlight-if-0/1) (add-hook 'after-save-hook 'cpp-highlight-if-0/1 'append 'local) (my-cpp-colours) ) (add-hook 'c++-mode-hook 'my-cpp-mode-hook t) (add-hook 'c-mode-hook 'my-cpp-mode-hook t)
Add entries to custom-set-faces to make the colours match sorcerer:
(custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. ;; ... '(font-lock-mycomment-face ((t (:foreground "#686858" :slant italic))) t) '(font-lock-myconstant-face ((t (:foreground "#ff9800"))) t) '(font-lock-mydefault-face ((t (:foreground "#c2c2b0"))) t) '(font-lock-myidentifier-face ((t (:foreground "#c2c2b0"))) t) '(font-lock-mykeyword-face ((t (:foreground "#90b0d1"))) t) '(font-lock-mynewline-face ((t (:foreground "#119611"))) t) '(font-lock-mypreprocessor-face ((t (:foreground "#528b8b"))) t) '(font-lock-mystring-face ((t (:foreground "#779b70"))) t) '(font-lock-mytype-face ((t (:foreground "#7e8aa2"))) t) '(font-lock-mywarning-face ((t ( :foreground "#cf7fcf" :background "#202020" :slant italic :underline t :bold t))) t) ;; ... )
Now Emacs renders C++ closer to the style in Vim:
Thank you for very informative post. How would I go about highlighting function calls?
In the example above I want to highlight this:
do_something
LikeLike
In the list for font-lock-add-keywords, try adding this between the FIXME|TODO expression and the myidentifier one:
(I would have pasted that in as text, but this wordpress comment field keeps destroying the code and collapsing it to nothing, even with code tags around it.)
Define font-lock-myfuncall-face in the same way as the others. That should get function calls, but it will also get function definitions. I don’t know a straightforward way to isolate only the calls. I’m sure it’s possible, but more work.
LikeLike