Toggling symbol highlighting in Emacs with unique colors for each symbol using built-in functions

Symbol highlighting is a useful feature for quickly identifying occurrences of a symbol in a buffer. For example, when reading an algorithm with nested loops and multiple function calls, the distinct colors for each symbol, variable, or function make it easier to identify where each is used by simply scanning the highlighted symbols. This article presents a function that simplifies toggling the highlight for the symbol at point in Emacs using the built-in hi-lock package, which provides dynamic text highlighting.

(The function provided in this article can serve as a replacement for packages like symbol-overlay or highlight-symbol if your primary goal is simply highlighting symbols. However, if you require advanced features such as jumping between occurrences, I recommend using a more full-featured package.)

The function to toggle symbol highlighting

Here is the function that enables or disables highlighting for the symbol at point:

(require 'hi-lock)  ; Built-in Emacs package

(defun simple-toggle-highlight-symbol-at-point ()
  "Toggle highlighting for the symbol at point."
  (interactive)
  (when-let* ((regexp (find-tag-default-as-symbol-regexp)))
    (if (member regexp (hi-lock--regexps-at-point))
        ;; Unhighlight symbol at point
        (hi-lock-unface-buffer regexp)
      ;; Highlight symbol at point
      (hi-lock-face-symbol-at-point))))Code language: Lisp (lisp)

One advantage of the built-in hi-lock function is that it highlights each symbol with a unique color, making it easier to distinguish between different symbols.

Here is how it works:

  1. Checking if the symbol is already highlighted: The function first retrieves a list of regular expressions corresponding to currently highlighted text in the buffer using hi-lock--regexps-at-point. It then checks whether the symbol at point is among the highlighted expressions using member.
  2. Unhighlighting the symbol: If the symbol is already highlighted, the function calls hi-lock-unface-buffer with the appropriate regular expression, removing the highlighting.
  3. Highlighting the symbol: If the symbol is not currently highlighted, the function invokes hi-lock-face-symbol-at-point, which applies highlighting to the symbol.

Usage

You can configure a key binding, such as C-c h, with the following:

(global-set-key (kbd "C-c h") #'simple-toggle-highlight-symbol-at-point)Code language: Lisp (lisp)

Alternatively, you can use the function interactively by placing the cursor on a symbol and executing:

M-x simple-toggle-highlight-symbol-at-point

(If the symbol is not highlighted, it will be highlighted. If it is already highlighted, the function will remove the highlighting.)

You can also remove a symbol highlight from the entire buffer by selecting it from the list and removing it using:

M-x hi-lock-unface-buffer

Conclusion

The simple-toggle-highlight-symbol-at-point function provides an efficient way to toggle symbol highlighting in Emacs without relying on external packages. It offers a lightweight solution for users who primarily need highlighting functionality. While it does not include advanced navigation features found in third-party packages, it serves as a simple and effective alternative for quick visual identification of symbols in a buffer.

Emacs: Highlighting Codetags Like TODO, FIXME, BUG, NOTE…

Highlighting keywords such as TODO, FIXME, NOTE, BUG, and others (often referred to as tags, codetags, or tokens) enhances workflow by making key annotations more visible. This allows developers to quickly identify tasks, warnings, and notes within the code, reducing the time spent searching for unfinished work or potential issues.

This article outlines an Elisp code that highlights these codetags.

(There are packages like hl-todo and comment-tags that can highlight these codetags for those who need a more feature-rich solution. However, they contain hundreds of lines of code, which is excessive if your only goal is to just highlight codetags. While these packages likely offer additional features, such as navigating to the next codetag, the Elisp code in this article provides a much simpler solution for those who just want to highlight them.)

Elisp code to highlight codetags

To highlight these codetags, you can use the following Emacs Lisp code:

(defvar highlight-codetags-keywords
  '(("\\<\\(TODO\\|FIXME\\|BUG\\|XXX\\)\\>" 1 font-lock-warning-face prepend)
    ("\\<\\(NOTE\\|HACK\\)\\>" 1 font-lock-doc-face prepend)))

(define-minor-mode highlight-codetags-local-mode
  "Highlight codetags like TODO, FIXME..."
  :global nil
  (if highlight-codetags-local-mode
      (font-lock-add-keywords nil highlight-codetags-keywords)
    (font-lock-remove-keywords nil highlight-codetags-keywords))

  ;; Fontify the current buffer
  (when (bound-and-true-p font-lock-mode)
    (if (fboundp 'font-lock-flush)
        (font-lock-flush)
      (with-no-warnings (font-lock-fontify-buffer)))))Code language: Lisp (lisp)

To apply codetag highlighting across all programming modes, add highlight-codetags-local-mode to the prog-mode-hook:

(add-hook 'prog-mode-hook #'highlight-codetags-local-mode)Code language: Lisp (lisp)

If you call highlight-codetags-local-mode interactively, you can toggle the highlighting of codetags on and off.

Customizations

If desired (though not required), you can further customize the Elisp code:

  • You can customize the highlighting by substituting font-lock-warning-face or font-lock-doc-face with any other face of your choice. (You can view all available faces by executing the command: M-x list-faces-display)
  • Additionally, you can add more keywords to the regular expression.
    For instance, to add the MAYBE codetag to the \\<\\(NOTE\\|HACK\\)\\> pattern, simply append \\|MAYBE before the closing parenthesis \\):
    \\<\\(NOTE\\|HACK\\|MAYBE\\)>.

Conslusion

This simple configuration enhances keyword visibility in Emacs, making it easier to track important annotations while editing source code.