In emacs how to create a mapping to a function returned by another function? - emacs

I'm using emacs with evil-mode, I want to map <leader>tt to the function projectile-dired however if a dired buffer is being shown then it should be mapped to the evil-delete-buffer, so in essence creating a map to a toggle function.
After learning the basics of emacs lisp I came up with this solution:
(defun toggle-projectile-dired ()
"Toggles projectile-dired buffer."
(interactive)
(or
(when (derived-mode-p 'dired-mode)
(evil-delete-buffer (current-buffer)))
(projectile-dired)))
;; This is how the mapping is done
(evil-leader/set-key "tt" 'toggle-projectile-dired)
But what I did with this solution was to create a map to a function that in the end calls to another function.
While my solution works (and I'm fine with it) what I could not do was to return the function to be called (instead of calling it, as I did) how such approach should be written?
Or in other words, how to return a function name and make that mapping call the returning function?.
PD: This question is just for the sake of learn some elisp. Thanks!
EDIT:
Here is some pseudo code (javascript) of what I want to achieve:
function toggleProjectileDired() {
if (derivedModeP == 'dired-mode') {
// We're in dired buffer
return 'evilDeleteBuffer';
} else {
return 'projectileDired';
}
}
evilLeaderSetKey("tt", toggleProjectileDired());
My solution in pseudo code is:
function toggleProjectileDired() {
if (derivedModeP == 'dired-mode') {
// We're in dired buffer
evilDeleteBuffer();
} else {
projectileDired();
}
}
evilLeaderSetKey("tt", toggleProjectileDired);
As you can see, one returns the function name to be called while the other calls the function. How to return a function name to be called in elisp?

(Caveat: I don't use evil, and am not familiar with its custom keybinding functions.)
The canonical approach to making a key do one thing in dired-mode and another thing elsewhere is to define one binding in dired's keymap, and another binding in the global keymap (or whatever is appropriate). I would recommend that you try to follow this approach in most circumstances, because it makes it much simpler to see what's happening.
However, there is a way to do what you're asking for. These pages demonstrate some variations on the approach:
https://stackoverflow.com/a/22863701
http://endlessparentheses.com/define-context-aware-keys-in-emacs.html
http://paste.lisp.org/display/304865
In essence you use the :filter facility of menu items (n.b. menus are actually fancy keymaps in Emacs) to determine the command at run-time. Note that if the filter function returns nil, Emacs treats it as if no binding exists in that keymap, and continues looking for a binding in the remaining keymaps; so this feature facilitates bindings which are only conditionally active.
A non-evil version of your example might look like this:
(define-key global-map (kbd "<f6>")
`(menu-item "" projectile-dired
:filter ,(lambda (default)
(if (derived-mode-p 'dired-mode)
'evil-delete-buffer
default))))
Again, this would be more usual:
(global-set-key (kbd "<f6>") 'projectile-dired)
(eval-after-load "dired"
'(define-key dired-mode-map (kbd "<f6>") 'evil-delete-buffer))
FWIW, I actually think the general approach you started with is probably the best one in this instance. If typing KEY should always toggle dired in that window, then binding it to a toggle-dired command seems like the most self-explanatory implementation.

Related

Why does key binding cause Emacs to execute my function on startup?

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)

How to extend Neotree to open a file using hexl?

I'm trying to extend Neotree to open a file using hexl-mode with the shortcut C-c C-x. How would one do this?
I've tried to evaluate a key definition after the Neotree load where it uses my/neotree-hex to open a file path using neo-buffer--get-filename-current-line.
(defun my/neotree-hex
(hexl-find-file neo-buffer--get-filename-current-line))
(with-eval-after-load 'neotree
(define-key neotree-mode-map (kbd "C-c C-x")
'my/neotree-hex))
At the very least, you are missing the (empty) argument list in the function:
(defun my/neotree-hex ()
(hexl-find-file neo-buffer--get-filename-current-line))
I don't know what neo-buffer--get-filename-current-line is: if it is a function, then you are not calling it correctly - in lisp, you call a function by enclosing the (name of the) function and its arguments in parens: (func arg1 arg2 ...)[1]; so if it is a function and it takes no arguments, then your function should probably look like this:
(defun my/neotree-hex ()
(interactive)
(hexl-find-file (neo-buffer--get-filename-current-line)))
In order to be able to bind it to a key, you have to make your function a command, which means that you need to add the (interactive) form.
Disclaimer: I know nothing about neotree.
[1] You might want to read an introduction to lisp. One (specifically tailored to Emasc Lisp) is included with the emacs documentation, but is also available online. Eventually, you will want to read the Emacs Lisp Reference Manual. Calling a function is covered in the Introduction and is covered in detail in the Reference.

How to find the location, where an an Emacs Lisp function is bound to a key?

I'm trying to figure out where M-m is bound to back-to-indentation function. When I issue C-h k M-m (describe-key), I get the following output
M-m runs the command back-to-indentation, which is an interactive
compiled Lisp function in `simple.el'.
It is bound to M-m.
(back-to-indentation)
Move point to the first non-whitespace character on this line.
When I look at simple.el, I'm seeing only the definition of function back-to-indentation. I searched throughout the file and I didn't see any keybinding done for that function using define-key. I'm assuming that it happens elsewhere.
How can I identify the location where the function is bound to M-m key?
Emacs version: GNU Emacs 24.2.1 (x86_64-apple-darwin12.2.0, NS apple-appkit-1187.34)
I don't know if that's possible in general, but my guess would be that Emacs doesn't remember where the code was that defined a given key.
C-hb will show the current bindings, from which you can establish which keymap you're interested in, and work from there. For most major or minor mode maps, it won't be too difficult to find the code.
Your specific example is a global binding which Emacs configures in bindings.el.
Adding this at the beginning of my .emacs did the trick for me:
(let ((old-func (symbol-function 'define-key))
(bindings-buffer (get-buffer-create "*Bindings*")))
(defun define-key (keymap key def)
(with-current-buffer bindings-buffer
(insert (format "%s -> %s\n" key def))
(mapbacktrace (lambda (evald func args flags)
(insert (format "* %s\n" (cons func args))))))
(funcall old-func keymap key def)))
The idea is that I redefine the define-key function (which is used to bind key within keymap to def) to first log its arguments to a buffer *Bindings*, together with the stacktrace of where it's being called from. After that it calls the old version of the function.
This creates a closure to store the old value of define-key, so it depends of lexical-bindings being t. In retrospect, I think it would have been possible to use function advising instead; but using a closure felt simpler.
Since I had this at the beginning of my .emacs, this recorded all calls to define-key during initialization. So I just had to switch to that buffer once initialization finished, find the call where the particular key was bound, and then inspect the backtrace to find the site from which that happened.

How can I easily reload Emacs lisp code as I am editing it?

As an Emacs beginner, I am working on writing a minor mode. My current (naive) method of programming elisp consists of making a change, closing out Emacs, restarting Emacs, and observing the change. How can I streamline this process? Is there a command to refresh everything?
You might try using M-C-x (eval-defun), which will re-evaluate the top-level form around point. Unlike M-x eval-buffer or C-x C-e (exal-last-sexp), this will reset variables declared with defvar and defcustom to their initial values, which might be what's tripping you up.
Also try out C-u C-M-x which evaluates the definition at point and sets a breakpoint there, so you get dropped into the debugger when you hit that function.
M-x ielm is also very useful as a more feature-rich Lisp REPL when developing Emacs code.
M-x eval-buffer should do it.
What Sean said. In addition, I have (eval-defun) bound to a key, along with a test. The development loop then becomes: 1) edit function, 2) press eval-and-test key, 3) observe results, 4) repeat. This is extremely fast.
During development I write a test, bind it to jmc-test, then use the above key to run it on my just-edited function. I edit more, then press key again, testing it again. When the function works, I zap jmc-test, edit another function, and write another jmc-test function. They're nearly always one line of code, so easy to just bang out.
(defun jmc-eval-and-test ()
(interactive)
(eval-defun nil)
(jmc-test))
(define-key emacs-lisp-mode-map (kbd "<kp-enter>") 'jmc-eval-and-test)
(when t
(defun myfunc (beer yum)
(+ beer yum))
(defun jmc-test () (message "out: %s" (myfunc 1 2))))
When editing "myfunc", if I hit keypad enter, it prints "out: 3".
It all depends on what you're writing and how you've written it. Toggling the mode should get you the new behavior. If you're using [define-minor-mode][1], you can add code in the body of the macro that keys off the mode variable:
(define-minor-mode my-minor-mode
"doc string"
nil
""
nil
(if my-minor-mode
(progn
;; do something when minor mode is on
)
;; do something when minor mode is off
)
But, another way to check it quickly would be to spawn a new Emacs from your existing one:
M-x shell-command emacs&
I just define a function called ldf (short for load-file) in my .emacs file,
like this:
(defun ldf (arg) (interactive "P") (load-file (buffer-file-name)))
As you can see, this little function looks up the filename of the current buffer and then loads the file. Whenever I need to reload the current buffer elisp file, just type "M-x ldf"

Globally override key binding in Emacs

How can I set a key binding that globally overrides and takes precedence over all other bindings for that key? I want to override all major/minor mode maps and make sure my binding is always in effect.
This of course doesn't work:
(global-set-key "\C-i" 'some-function)
It works in text-mode, but when I use lisp-mode, C-i is rebound to lisp-indent-line.
I can go through and override this binding in lisp-mode and in every other mode individually, but there must be an easier way. Every time I install a new mode for a new file type, I'd have to go back and check to make sure that all of my key bindings aren't being overridden by the new mode.
I want to do this because I want to emulate bindings I've already learned and ingrained from other editors.
I use a minor mode for all my "override" key bindings:
(defvar my-keys-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-i") 'some-function)
map)
"my-keys-minor-mode keymap.")
(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " my-keys")
(my-keys-minor-mode 1)
This has the added benefit of being able to turn off all my modifications in one fell swoop (just disable the minor mode) in case someone else is driving the keyboard or if I need to see what a default key binding does.
Note that you may need to turn this off in the minibuffer:
(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
As an addition to scottfrazer's answer, I've written the following so that my keybindings retain precedence, even if subsequently-loaded libraries bring in new keymaps of their own.
Because keymaps can be generated at compile time, load seemed like the best place to do this.
(add-hook 'after-load-functions 'my-keys-have-priority)
(defun my-keys-have-priority (_file)
"Try to ensure that my keybindings retain priority over other minor modes.
Called via the `after-load-functions' special hook."
(unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
(let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
(assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))
Install use-package, eval and you're done:
(require 'bind-key)
(bind-key* "C-i" 'some-function)
I found this question while searching for "emacs undefine org mode keybindings", because I wanted to unbind the existing C-c C-b behavior to allow my global map to bury-buffer to work in an org buffer.
This ended up being the simplest solution for me:
(add-hook 'org-mode-hook
(lambda ()
(local-unset-key (kbd "C-c C-b"))))
Although scottfrazer's answer is exactly what you asked for, I will mention for posterity another solution.
From The Emacs Manual:
"Don't define C-c letter as a key in Lisp programs. Sequences consisting of C-c and a letter (either upper or lower case) are reserved for users; they are the only sequences reserved for users, so do not block them."
If you bind your personal global bindings to C-c plus a letter, then you "should" be safe. However, this is merely a convention, and any mode is still able to override your bindings.
If you want to "always use the keybinds in the map, unless I explicitly override them for a specific mode-map", and assuming you are using scottfrazier's approach, you want:
(defun locally-override (key cmd)
(unless (local-variable-p 'my-keys-minor-mode-map)
(set (make-variable-buffer-local 'my-keys-minor-mode-map)
(make-sparse-keymap))
(set-keymap-parent my-keys-minor-mode-map
(default-value 'my-keys-minor-mode-map)))
(define-key my-keys-minor-mode-map key cmd))
So
(locally-override "\C-i" nil)
should remove the "\C-i" binding from the minor mode in the current buffer only. Warning: this is completely untested, but seems like the right approach. The point of setting the parent rather than just coping the global value of my-keys-minor-mode-map is so any later changes to the global value are automatically reflected in the local value.
I don't think you can. That is roughly equivalent to saying that you want to define a global variable that cannot be hidden by local variable declarations in functions. Scope just doesn't work that way.
However, there might be a way to write an elisp function to go through the mode list and reassign it in every single one for you.
Unless you really want to do this yourself, you should check around and see if anyone else already has done it.
There is a package for Emacs which gives your windows-like keybindings. You should be able to find it through google.