3

I added the following code to my .emacs file.

(defun delete-right-window ()
  (interactive)
  (windmove-right)
  (delete-window))

(defun delete-left-window ()
  (interactive)
  (windmove-left)
  (delete-window))

(defun delete-below-window ()
  (interactive)
  (windmove-down)
  (delete-window))

(defun delete-above-window ()
  (interactive)
  (windmove-up)
  (delete-window))

(global-set-key (kbd "C-s-<right>") 'delete-right-window)
(global-set-key (kbd "C-s-<left>") 'delete-left-window)
(global-set-key (kbd "C-s-<down>") 'delete-below-window)
(global-set-key (kbd "C-s-<up>") 'delete-above-window)

As you can see, most of the codes are repetitive. I read How do I pass a function as a parameter to in elisp? and tried to refactor the code to passing windmove-* function as follow:

(defun delete-other-window (callback)
  (interactive)
  (funcall callback)
  (delete-window))
...

(defun delete-right ()
  (delete-other-window 'windmove-right))

And I bound keystroke like this:

(global-set-key (kbd "C-s-<right>") 'delete-right)

But when I hit C-s-<right> it doesn't work, only display Wrong type argument: commandp, delete-right in the mini buffer.

What am I missing or what should I do to work the code correctly?

Community
  • 1
  • 1
ntalbs
  • 28,700
  • 8
  • 66
  • 83

3 Answers3

2

Here's a fix:

(defun delete-after (fn)
  `(lambda () (interactive)
      (,fn)
      (delete-window)))

(global-set-key (kbd "C-s-<right>") (delete-after 'windmove-right))
(global-set-key (kbd "C-s-<left>") (delete-after 'windmove-left))
(global-set-key (kbd "C-s-<down>") (delete-after 'windmove-down))
(global-set-key (kbd "C-s-<up>") (delete-after 'windmove-up))
abo-abo
  • 20,038
  • 3
  • 50
  • 71
  • Ok, here we have a user who is just starting to learn elisp. Do you really think it's a good idea to offer a solution with a function generating anonymous functions using advances tricks like lambda and backticks, especially when he already had a simple, straight forward way to implement this? – Lindydancer Mar 04 '14 at 10:40
  • Yes. The op's implementation problem is clearly solved before the question is asked. OP is asking for elegance and I show it to him. – abo-abo Mar 04 '14 at 10:48
  • Binding a lambda to a key or adding it to a hook is never elegant. When the user checks what a key is bound to or a hook contains, an anonymous lambda is like a dead end, with a pile of rubble in it (taken with a grain of salt, of course ;) – Lindydancer Mar 04 '14 at 11:29
  • In my Emacs, `f1 k` shows the code of the anonymous lambda. One could argue that it's even more efficient since I don't have to jump to definition to see the source:) – abo-abo Mar 04 '14 at 11:33
  • Hi indydancer. IMO I expect a lot of different answer. Same answer is less valuable. Don't you think so? So abo-abo's answer is valuable for me. I think OP is just one of a people who expect answer. So you don't need answer for just OP. If you have another possible answer, please post it. Thanks. – Kei Minagawa Mar 04 '14 at 12:46
  • Although I'm new to elisp, I've studied clojure for a while and I think I can understand the proposed code. Well, using `delete-other-window` could reduce the repetitive codes, it still need to define four function looks similar and each of them should be bound respectively. So I thought I could go further after I solve this problem, this code can be my ultimatum. – ntalbs Mar 04 '14 at 23:33
2

To make a function into a command, you need to add the special form interactive to it:

(defun delete-right ()
  (interactive)
  (delete-other-window 'windmove-right))
Lindydancer
  • 25,428
  • 4
  • 49
  • 68
2

The problem with your code is that it's the function bind to the key that should be interactive. Not one of the function it call:

(defun delete-other-window (callback)
  (funcall callback)
  (delete-window))

(defun delete-right ()
  (interactive)
  (delete-other-window 'windmove-right))

You could also use a macro:

(defmacro defun-delete-other-window (direction)
  `(defun ,(intern (concat "delete-" direction)) ()
     (interactive)
     (,(intern (concat "windmove-" direction)))
     (delete-window)))

(defun-delete-other-window "right")
Rémi
  • 8,172
  • 2
  • 27
  • 32
  • A small disadvantage of the macro approach is that you can no longer jump to definition of e.g. `windmove-right`. – abo-abo Mar 04 '14 at 10:58
  • Thank you for teaching me that `interactive` should be in the function that is bound to keystroke. After moving `interactive` to `delete-right`, it works well. – ntalbs Mar 04 '14 at 23:39