0

There are some text actions that I use so often in emacs that the user-made commands I currently use, invoked with the standard M-x ... RET procedure do not satisfy me. I would like to replace their key bindings with shorter ones, with as few keystrokes as possible (ideally two, as it is in elaborate IDEs). It seems I cannot use keyboard macros here because according to the manual, Keyboard macros are not "powerful enough" to achieve what ordinary Emacs commands do (according to https://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html).

Perhaps I can override some builtin C- or M- commands ? There are several that I will probably never need anyway. Is there a safe, recommended way to do this ?

An example : wrap the currently selected text into phpbb italics tags. All the solutions I could find, here or there, use M-x. I tried to make a non-interactive version as follows :

(defun wrap-with-italics-phpbb-tag (start end)
  "Wraps the selected text or the point with a tag"
  (let (string)
    (if mark-active 
        (list (setq string (buffer-substring start end))
          (delete-region start end)))
    (yas/expand-snippet (point)
                        (point)
                        (concat "[i]" string "[/i]"))))

(global-set-key (kbd "C-i") 'wrap-with-italics-phpbb-tag)

This does not work because global-set-keys expects an interactive command.

1
  • This is a commonly asked Q&A. Sometimes the Q is phrased differently, and sometimes the A is different (different cause of an attempt to use a non-commandp function as a command). But we should all try to see if a command-related question might be a duplicate of the community Q&A for this.
    – Drew
    Commented Nov 4, 2018 at 15:44

2 Answers 2

2

The interactive declaration at the beginning of a function distinguishes an ordinary function, to be used only programmatically, from a "command", to be used (in addition or solely) by the user. A command bound to a key is thus nothing more than an interactive function bound to a key.

All functions bound to keys are also available via M-x*: You can actually do M-x forward-char.

So, it's really that simple. If you want to bind a function to a key, declare it to be interactive by adding an interactive spec. Think of it as a type declaration and of binding a non-interactive function to a key as the semantic equivalent of a type error.

In other words: all you have to do in order to get a key binding from the (already interactive) functions you were linking to is to add your global-set-key. That's it.

Footnote:

[*] Striktly speaking, you can have anonymous interactive functions, e.g.

(define-key global-map (kbd "C-c c")
  (lambda () (interactive) (message "Help! I'm crazy")))

Whether that is a good idea is another matter.

1
  • 1
    I'd like to add that this fact -- commands are just function calls bound to keys -- touches in some ways the very essence of Emacs: it's nothing but a giant Lisp REPL. Commented Nov 4, 2018 at 10:37
2

You seem to be confused by (interactive).

Anything that you call by yourself using M-x or using a keyboard sequence has to be marked interactive. Add that and your example above works. You are supposed to do that.

Also, the very idea of emacs is that commands are defined by names and they tend to be long to be descriptive. You are supposed to come up with your own keybindings (i.e. your "short names"). However, it is highly recommended to follow conventions.

I highly recommend you start using hydras to define groups of key binding.

5
  • Thank you for your feedback. It seems though that you did not really understand my question. So let me rephrase : according to the emacs manual quote I gave, it is not possible to define non-M-x commands (what you call "keyboard sequences, key bindings") except for very simple tasks which would not include what I need. You seem to disagree with that. If so, can you show me one simple example of how it is done ? Commented Nov 4, 2018 at 9:00
  • I started looking at the hydra package you recommended me. Correct me if I wrong, but this is useful only to create "modes", i.e. environments in which you need to apply several related commands in succession. This is not my situation at all. For example, with my "wrap into tags" example, this is something I need to do just once, and then return to "usual" text editing. Commented Nov 4, 2018 at 9:36
  • 1
    @EwanDelanoy I think you didn't understand the answer, actually. In order to define a “non-M-x command”, you first define a “M-x command”, which Emacs calls a command or interactive command, and then you define a key binding for it. Add (interactive) to your function, and then call global-set-key with the name of the function. Commented Nov 4, 2018 at 9:49
  • @EwanDelanoy, your first comment shows that there is still some conceptual problem that you need to get solve to speak the same language as the rest of us. Once you solve it, please ask an other question.
    – Heikki
    Commented Nov 4, 2018 at 19:11
  • @EwanDelanoy, hydras are fully able to be used for commads that return immediately to normal editing. See for example github.com/abo-abo/hydra/wiki/Unicode-input. Selection of the kind of hydra commands depends on on your needs. See other examples in the hydra wiki.
    – Heikki
    Commented Nov 4, 2018 at 19:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.