Reputation: 323
So I'm trying to add something into some elisp mode hooks — specifically, I'd like to define a hook's prettify-symbols-alist
and then specifically activate it by calling prettify-symbols-mode
.
In any case, I'm getting org-babel
to export the values into a pair of lists from a table, using pairlis
to tie them together as an alist, and add-hook
it into the desired mode using a anonymous function.
So, the thing is, right now if I use a global variable, like the following, it works:
(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
(code (quote (172 215 247 8594 8614 8800 8804 8805 955)))) ; Generated automatically using org-babel
(require 'cl)
(setq *globalvar (pairlis token code))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(setq prettify-symbols-alist *globalvar)
(prettify-symbols-mode 1))))
But if I try to not use a global variable, by doing it this way, it doesn't work:
(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
(code (quote (172 215 247 8594 8614 8800 8804 8805 955)))) ; Generated automatically using org-babel
(let (localv)
(require 'cl)
(setq localv (pairlis token code))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(setq prettify-symbols-alist localv)
(prettify-symbols-mode 1))))
I kind of know why: if I C-h v emacs-lisp-mode-hook
, I'll see that it refers to whatever variable I used in the let
form, which works when the variable exists, as in *globalvar
, but not when I use localvar
, which no longer exists outside of its let
form. But I'm not sure how to force evaluation of the local variable itself, as I'm still struggling with a lot of concepts in elisp that aren't immediately clear to me.
What am I missing? Where am I going wrong here?
Upvotes: 1
Views: 2097
Reputation: 908
I like this solution. With lexical-let
, the call to lambda
(inside add-hook
) generates a closure, as you can see if you type M-x ielm RET
and emacs-lisp-mode-hook RET
to examine its value.
You could also use old-school style backtick like this:
(add-hook 'emacs-lisp-mode-hook
`(lambda ()
(setq prettify-symbols-alist ',localv)
(prettify-symbols-mode 1)))
(EDIT)
Note the backtick
before the lambda
and (as tarikq mentioned) the quote-comma
before localv
.
I think you got the meaning!
Actually, instead of "expand this then quote it", I would say "insert its value (from the lexical environment), then quote it".
If you try something like:
(macroexpand '`(lambda ()
(setq prettify-symbols-alist ',localv)
(prettify-symbols-mode 1)))
then you will get what lisp will actually do at run time:
(cons 'lambda
(cons nil
(cons
(list 'setq 'prettify-symbols-alist (list 'quote localv))
'((prettify-symbols-mode 1)))))
and you will see how the whole list is constructed, and how localv
is normally evaluated, i.e. not quoted (compare with the symbols 'setq
and 'prettify-symbols-alist
and the list '((prettify-symbols-mode 1))
)
Upvotes: 0
Reputation: 323
Okay, here's what I did in the end:
(let ((token (quote ("not" "*" "/" "->" "map" "/=" "<=" ">=" "lambda")))
(code (quote (172 215 247 8594 8614 8800 8804 8805 955))))
(require 'cl)
(lexical-let (localv)
(setq localv (pairlis token code))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(setq prettify-symbols-alist localv)
(prettify-symbols-mode 1)))))
I ended up using phils' suggestion to use lexical-let
rather than Drew's suggestion mostly because I'm currently using org-babel
to tangle code blocks into my source code (basically I'm using org-mode
to organize my setting files), and there doesn't appear to be a way to set the lexical-binding
file-local variable — according to this page, you need to set it as the first line (using ;; -*- lexical-binding: t -*-
), and I can't find a way to do that yet.
In any case, thank you to everyone who helped me out on this question!
Upvotes: 2
Reputation: 30699
Start by setting lexical-binding
to non-nil
, or else localv
will be a free variable in your hook function. Preferably, set lexical-binding
as a file-local variable.
In addition, there is nothing in your code that makes localv
buffer-local. Presumably you want to give it a value that is local to the buffer that is in that mode. The code that binds it should be evaluated in the mode (i.e., in the buffer) in question.
Upvotes: 1