Highlight `symbols` and other miscellanea in your program code

In an earlier article 1,  you learned how to highlight portions of your text file to get a better overview of it’s organization and contents.   In this article, you will learn how to  highlight variables in your program to make better sense of it.

This article is a continuation of the earlier article, and introduces two convenience features that you could put to good use.

As a motivation for this article, let us note the two inconveniences you may stumble upon as part of your highlight operations.

  1.  Regular expression for matching program variables is hard to type and remember: The regular expression for a program variable is a bit hard to remember and type.  For example, in order to highlight an identifier called hi-lock-set-pattern, the regular expression you need to type is \_<hi-lock-set-pattern\_>.  (If you can remember the regexp backslash patterns for beginning and end of symbols1, you definitely need to consider applying for a memory championship)
  2. When you need to highlight in quick succession, choosing a face gets in the  way:  In the article linked above, you learn that highlighting was a two step-process. In the first step, you chose a pattern.  In the second step, you picked a face.  When you highlight stuff in quick succession, inputting a face to be used for highlighting gets in the way.

To alleviate (1), Emacs provides a highlight-symbol-at-point command.  To alleviate (2), Emacs provides a hi-lock-auto-select-face option.

This article is primarily intended for programmers.  If you are not a programmer, it is possible that you lose interest in this article.  In that case, it would suffice if you note how to turn on auto-selection of faces.

Motivation

When you are a programmer, you spend most of the time looking at and analyzing source code.  Much of analyzing and comprehending a program code,  comes down to  tracking how a data or a value (transforms and) flows through different program variables. When doing this analysis, you will find that highlighting the variables helps you in understanding the data flow better.

For the purpose of this article,  we will spend some time analyzing  hi-lock-set-pattern1, the  workhorse function of  hi-lock-mode1.   Before you do that, here are a few preparatory steps.

Step 1: Install a custom menu

Copy the Emacs Lisp snippet1 below to your .emacs and restart your Emacs. This snippet adds a submenu named Customize Regexp Highlighting to the Edit menu.

(easy-menu-define my-hi-lock-menu nil "Menu for customizing regexp highlighting."
  `("Customize Regexp Highlighting"
    ["Global Hi Lock Mode"
     (progn
       (customize-set-variable 'global-hi-lock-mode
                   (not global-hi-lock-mode))
       (customize-save-variable 'global-hi-lock-mode global-hi-lock-mode))
     :style toggle :selected global-hi-lock-mode :help "Toggle Hi-Lock mode in all buffers"]
    ["Hi Lock Mode" hi-lock-mode :style toggle :selected hi-lock-mode :help "Toggle selective highlighting of patterns"]
    ["Auto Select Face"
     (customize-save-variable 'hi-lock-auto-select-face
                  (not hi-lock-auto-select-face))
     :style toggle :selected hi-lock-auto-select-face :enable
     (featurep 'hi-lock)
     :help "\"Non-nil means highlighting commands do not prompt for the face to use.\nInstead, each hi-lock command will cycle through the faces in\n`hi-lock-face-defaults'.\""]
    "--"
    ["Customize"
     (customize-group 'hi-lock)]))

(easy-menu-add-item menu-bar-edit-menu nil my-hi-lock-menu)

(with-eval-after-load 'hi-lock
  (define-key-after hi-lock-menu
    [unhighlight-regexp-all]
    `(menu-item "Remove All Highlighting"
        (lambda nil
          (interactive)
          (unhighlight-regexp t))
        :enable hi-lock-interactive-patterns :help ,(documentation 'unhighlight-regexp))
    'unhighlight-regexp))

Step 2: Enable global-hi-lock-mode or hi-lock-mode

Screenshot from 2018-09-10 21-10-29

Step 3: Enable Auto Select Face

Screenshot from 2018-09-10 21-11-00

Step 4: Jump to a function, say hi-lock-set-pattern

For the purpose of this article,  we will spend some time analyzing  hi-lock-set-pattern1, the  workhorse function of  hi-lock-mode1.   Here is a screenshot of this function.

Screenshot from 2018-09-11 09-47-40

Note the Hi in the modeline.  If you aren’t seeing a Hi, it means that you haven’t enabled hi-lock-mode.  Please revisit the previous step.

Step 4: Highlight a variable / symbol that you would like to track

In this article we will trace how the first formal parameter regexp flows and transforms itself within the function, hi-lock-set-pattern.  To this end, place your cursor over regexp and highlight it as below.

Screenshot from 2018-09-01 18-51-01

Screenshot from 2018-09-01 18-52-00

From the screenshot above, you realize that formal parameter regexp transforms in to the local variable pattern.  It is also used as input to re-search-forward to identify  places where the regexp pattern appears.

Step 3: Highlight more symbols, based on results from earlier step

Now highlight the local variable pattern identified in the previous step.  You would see that it gets collected in to hi-lock-interactive-patterns and it is used to construct an argument to font-lock-add-keywords.

The matches from re-search-forward for pattern, is used to construct an overlay.  So, highlight the local variable overlay as well.

At the end of the above steps, this is what your buffer looks like.

Screenshot from 2018-09-01 18-55-28

A quick look at screenshot above shows that hi-lock library achieves highlighting  using font-lock in buffers that are in font-lock-mode and uses overlays in buffers that aren’t in font-lock-mode.

Step 4: Un-highlight all symbols

Once your analysis is over, you can remove all the highlights and start all over again.  For example, you can track down how the path of the second formal parameter, face.

Screenshot from 2018-09-01 20-14-50

Step 4′: Unhighlight a symbol

Occasionally, you might want to turn off highlights on a particular symbol. This  could either be because you highlighted the wrong symbol  or you have so many highlights that your code becomes less comprehensible.

For the sake of illustration, let us un-highlight one of the symbols from the previous step.

Screenshot from 2018-09-01 22-14-51.png

Screenshot from 2018-09-01 22-15-37.png

Screenshot from 2018-09-01 22-16-06.png

A note on faces used for highlighting

When you are using auto-selection for faces, Emacs circles among a set of 9 faces, and picks a face that is as yet unused in that buffer.  This ensures that each subsequent highlight is distinct from earlier highlights.

You can look at the 9 faces as below.  Some of these faces uses a background color (just like a conventional highlighter), but others use foreground color and other text properties.  This mix of foreground and background highlighting annoys me at times.  So, I tend to use background colors on all faces.

Screenshot from 2018-09-11 10-26-37

Screenshot from 2018-09-11 10-27-47

Screenshot from 2018-09-11 10-28-10

How to turn-off auto-selection

I usually leave auto-selection of highlight faces on.  There are instances, where one might want to momentarily turn-off auto selection and pick a face explicitly.  You ran across one such instance in the earlier article.  In such cases, you can use the C-u prefix to highlight commands above, and you will be prompted for a face to use.  Generally speaking, the C-u prefix to highlight commands, momentarily toggles your  custom setting for auto-selection of faces.

Gotcha for  Emacs 27 (and later) users

In future Emacs 27, the prefix arg for highlight commands is interpreted differently1
and gets in the way of how the prefix arg is interpreted now 1.  You may want to bring the above conflict to the notice of Emacs Developers, and explore ways that will get you both the current behaviour and the proposed enhancement. The two behaviours, which are right now in direct conflict, are useful in their own rights.

Highlighting FIXMES, TODOs etc in your program

When you are working on large codebases, it is very common to find FIXMEs and TODOs.  Whether you are tracking down a bug or implementing new features, you would very much want to be aware of these.  In that case, you can add the following snippet to your .emacs

(add-hook 'hi-lock-mode-hook
      (lambda nil
        (highlight-regexp "FIXME" (quote hi-red-b))
        (highlight-regexp "TODO" (quote hi-red-b))
        )
      t)

Once you restart Emacs, this is how FIXMEs1 in hi-lock.el gets displayed.

Screenshot from 2018-09-11 12-13-39

The snippet above uses highlight-regexp, and easy for a layman to comprehend and modify.  If you are comfortable with Emacs Lisp, and want more sophisticated highlighting you could explore font-lock-add-keywords 1.

Advertisements
Categories gnu

1 thought on “Highlight `symbols` and other miscellanea in your program code

  1. I’m a big fan of highlighting symbols to help spot changes to a variable I’m interested in 🙂

    Have you tried highlight-symbols-mode? This automatically highlights other instance of the symbol under point. It’s very lightweight and gives a similar workflow.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close