Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highlight non-local variables in Emacs Lisp

Tags:

emacs

elisp

In js2-mode, global variables are automatically highlighted for me:

enter image description here

How can I do the same in Emacs lisp? I'd like to be able to highlight flymake-log-level and barr in the following:

(defun foo ()
  (let (bar baz)
    (setq baz flymake-log-level) ;; flymake-log-level isn't locally bound
    (setq barr (1+ flymake-log-level)))) ;; misspelled bar
like image 868
Wilfred Hughes Avatar asked Feb 16 '23 13:02

Wilfred Hughes


2 Answers

It's possible to take advantage of the byte-compiler by installing flycheck. Flycheck is an alternative to flymake and has support for Elisp.

It won't help you for the first example, but it will for the second (assuming the necessary require is present):

(require 'flymake)

(defun foo ()
  (let (bar baz)
    (setq baz flymake-log-level) ;; no complaints here
    (setq barr (1+ flymake-log-level)))) ;; assignment to free variable `barr'

There's also hl-defined.el, a minor mode that does almost exactly what is described in the question. Install it, then run hdefd-highlight-mode in an emacs-lisp-mode buffer. You can then run the command hdefd-cycle until you are only showing variables that aren't already defined. This gives something like:

hl-defined screenshot

(This isn't perfect, hl-defined doesn't recognise that fn is a parameter not a free variable, and it confuses the function list with the parameter used here. Still, it's very helpful for the use case described in the question.)

Finally, some packages include highlighting for the functions they define. For example, dash.el provides highlighting for its functions, plus the variable names it uses in anaphoric macros (i.e it highlights it).

;; Enable syntax highlighting of dash functions
(eval-after-load "dash" '(dash-enable-font-lock))
like image 173
Wilfred Hughes Avatar answered Feb 24 '23 00:02

Wilfred Hughes


I would say that this is quite a bit of work...

The best way is to use font-lock-mode and add a new rule. Normally, rules contains a regexp to match something, however, it is also legal to use a function to do this. This function could then search for identifiers, and for each identifier it finds it could check if it's bound locally by checking if the variable occurs in the parameter list, in a let, dolist or similar construct.

An example of a package that similar things is cwarn mode, which highlight (among else) assignments inside expressions, for C-like languages.

like image 42
Lindydancer Avatar answered Feb 24 '23 01:02

Lindydancer