I am pretty new to emacs and I am not sure I understand what lisp should actually behave.
Suppose I have two function
(add-hook 'python-mode-hook
(lambda ()
add-to-list (make-local-variable 'company-backends) 'company-jedi))
(add-hook 'js2-mode-hook
(lambda ()
add-to-list (make-local-variable 'company-backends) 'company-tern))
I wrote the following function
(defun auto-complete (mode-hook backend)
(add-hook mode-hook
(lambda ()
add-to-list (make-local-variable 'company-backends) backend)))
(auto-complete 'js2-mode-hook 'company-tern)
but it does not work. I looked online and I found it is because elisp does not have closure!
So, how should I refactor these two code block?
add-to-list is a function, so you need to use it with parentheses, as (add-to-list...). Or invoke it using funcall or apply.
Elisp has closures. Do one of the following:
With file-local-variable lexical-binding non-nil:
(defun auto-complete (mode-hook backend)
(add-hook mode-hook
(lambda ()
(add-to-list (make-local-variable 'company-backends) backend))))
With lexical binding you get a closure, which encapsulates an environment where variable backend is defined. Its value in that environment is the value it has when the closure is created, but the variable remains when the anonymous function is used - you can use it as a variable.
See the Elisp manual, node Using Lexical Binding.
Regardless of the value of lexical-binding:
(defun auto-complete (mode-hook backend)
(add-hook mode-hook
`(lambda ()
(add-to-list (make-local-variable 'company-backends) ',backend))))
In this case, there is no closure, and there is no variable backend in the function. Instead, that variable is replaced by its value at the time and in the context where the defun is evaluated. You can use this if you do not need to use the variable when the anonymous function is called, and all you need is its value (at the time of definition of that function).
If you use a closure then the anonymous function can be byte-compiled. If you use the variable-replacement technique then it cannot - in that case, you are not creating an anonymous function at the time of defun evaluation (or for byte-compilation). Instead, you are creating a list: (lambda...), and that list is later interpreted as a function.
Related
I have a function in my Emacs init.el file that lets me rebuild and byte-compile it from a literate source file. It consists of a lambda function wrapped by defun and works exactly as I expect. So far, so good.
(defun tangle-init-and-reload ()
"Tangle the code blocks in init.org, byte-compile, and reload."
(lambda ()
(interactive)
;; Don't run hooks when tangling.
(let ((prog-mode-hook nil))
(org-babel-tangle-file (concat user-emacs-directory "init.org"))
(byte-compile-file (concat user-emacs-directory "init.el"))
(load-file user-init-file))))
When I read about functions in Elisp, it appears to me that I should be able to simply use defun to define a named function and skip the lambda, so I removed the lambda and otherwise left the function intact, like so:
(defun tangle-init-and-reload ()
"Tangle the code blocks in init.org, byte-compile, and reload."
(interactive)
;; Don't run hooks when tangling.
(let ((prog-mode-hook nil))
(org-babel-tangle-file (concat user-emacs-directory "init.org"))
(byte-compile-file (concat user-emacs-directory "init.el"))
(load-file user-init-file)))
Written this way, the function also works as expected -- as long as I call it with M-x tangle-init-and-reload RET. If I assign it a key binding, it executes on startup with one of two different side effects: With some key bindings, it attempts to overwrite init.elc while Emacs still has it open, and with others it successfully overwrites init.elc, but then re-executes on reload, causing an infinite recursion.
I'm perfectly happy to stick with the lambda version, which has no issues with key binding, but I would like to understand what magic lambda is performing and/or what it is about key binding that causes the second version to execute at startup. Can anybody explain?
For whatever it's worth, my key bindings are in a custom minor mode like so:
(defvar custom-map (make-keymap)
"Custom key bindings.")
(define-key custom-map (kbd "C-c C-i") (tangle-init-and-reload))
(define-minor-mode custom-bindings-mode
"Activates custom key bindings."
t nil custom-map)
When you define the key binding, you associate a key to a value, which in your case is:
(tangle-init-and-reload)
This is an expression that is evaluated normally, ie. you call the function when you associate the binding.
In the previous version, evaluating the same function returned a closure, you had one level of indirection, so you established a binding from a key to the function returned by the call to tangle-init-and-reload.
You can simply give the name of the function associated with the binding, by quoting it:
(define-key custom-map (kbd "C-c C-i") 'tangle-init-and-reload)
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?
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!
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.
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)))
In elisp I have the following
(setq lexical-binding t)
(fset 'boom (cl-flet*
((tickle ()
(message "hi"))
(pickle ()
(tickle)))
(lambda ()
(pickle))))
(boom)
When I run the boom function I get the error
Symbol's value as variable is void: --cl-pickle--
What's going on here?
My intent is I would like to wrap private/helper functions and variables in a closure so I can better organize my code than everything being global.
Don't (setq lexical-binding t). You don't want to execute a command that sets this variable. Instead you want to describe to Emacs that the code you write uses lexical binding, and for that you need to add:
-*- lexical-binding:t -*-
somewhere on the first line of the file.
I would like to have a global keyboard shortcut that shows the value of a variable. However, the variable's value could change according to the current major mode in the current buffer.
I tried to add the following to my ~/.emacs:
(defun my-elisp-mode-setup ()
(defvar-local *current-mode-var* "elisp-mode")
)
(defun my-sh-mode-setup ()
(defvar-local *current-mode-var* "sh-mode")
)
(add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-setup)
(add-hook 'sh-mode-hook 'my-sh-mode-setup)
If I now start Emacs with emacs test.sh and then type M-x describe-variable *current-mode-var* in the test.sh buffer, I get
*current-mode-var*'s value is "elisp-mode"
Automatically becomes buffer-local when set.
Documentation:
Not documented as a variable.
while I expected to get *current-mode-var*'s value is "sh-mode"
The variables are evaled only at first declaration. All further declarations are skipped.
You need a setq instead.
If all you want to do is examine a variable to determine the major mode (which it seems is what you are doing), then just examine variable major-mode. That's what it's for.
And if you want a key/command to do that, then just create one:
(defun which-mode ()
"Echo the current major mode in the echo area."
(interactive)
(message "Major mode: %s" major-mode))
Or use variable mode-name if you prefer a human-friendly major-mode name.
I prefer official native package https://www.emacswiki.org/emacs/ModeLocal .
It is better configurable, because you do not require add-hook
For example
(require 'mode-local)
(setq-mode-local sh-mode *current-mode-var* "sh-mode")
(setq-mode-local emacs-lisp-mode *current-mode-var* "elisp-mode")
Then by just changing mode cause changing the value of *current-mode-var*
defvar-local is a macro calling defvar and make-variable-buffer-local under the hood.
defvar SYMBOL [VALUE [DOC-STRING]
... But if SYMBOL is not void, VALUE is not evaluated, and SYMBOL’s value is left unchanged...
You code should be:
(defvar-local *current-mode-var*)
(defun my-elisp-mode-setup ()
(setq *current-mode-var* "elisp-mode"))
(add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-setup)
(defun my-sh-mode-setup ()
(setq *current-mode-var* "sh-mode"))
(add-hook 'sh-mode-hook 'my-sh-mode-setup)
I'd like to implement a command that types the first few characters into an existing command and lets me type the rest.
For example, a variant of icicle-execute-extended-command that starts with "icicle-" already entered.
I have tried:
keyboard macros
fail (even on simple things like M-x i c i c l e s) for no apparent reason.
functions
calling icicle-execute-extended-command block the command sequence
How would I go about doing this in a generalized manner?
Nice question.
Here's something generic you can try:
(defun no-mondays ()
(interactive)
(minibuffer-with-setup-hook
(lambda()
(insert "monday"))
(call-interactively 'query-replace)))
And here's a refactoring:
(defun with-initial-minibuffer (str fun)
`(lambda ()
(interactive)
(minibuffer-with-setup-hook
(lambda ()
(insert ,str))
(call-interactively ',fun))))
(defalias 'no-weekends
(with-initial-minibuffer
"\\(?:satur\\|sun\\)day"
'query-replace-regexp))
If you are calling completing-read yourself in your command definition, then just pass the text to insert as the INITIAL-INPUT argument. That's what it's for.
If you use icicle-define-command or icicle-define-file-command (so that your command will be a multi-command), then same thing: pass the INITIAL-INPUT arg.
If you use such a macro, be sure to put something like this in the file that defines the command, so the macro definition is available a byte-compilation time:
(eval-when-compile
(or (condition-case nil
(load-library "icicles-mac") ; Use load-library to ensure latest .elc.
(error nil))
(require 'icicles-mac)))