Execute commands by giving its abbreviation

Posted: July 25, 2007 in Emacs
Tags: ,

Today I looked at my ~/.emacs file and I saw that I defined a lot of aliases for commands I frequently use. Most of the time the aliases are words that are built by taking each first char of a word in the command, e.g. nsn for newsticker-show-news, eb for emms-browser or omm for outline-minor-mode. But what should I do when I want to create an alias for ediff-buffers since eb is already used?

My solution was to write a function that calls a command by its abbreviation.

(defun th-execute-abbreviated-command (prefixarg)
  "Queries for a command abbreviation like "mbm" and calculates
a list of all commands of the form "m[^-]*-b[^-]*-m[^-]*$". If
this list has only one item, this command will be called
interactively. If there a more choices, the user will be queried
which one to call.

The PREFIXARG is passed on to the invoked command."
  (interactive "P")
  (let* ((abbrev (read-from-minibuffer "Command Abbrev: "))
         (regexp (let ((char-list (append abbrev nil)) ;; string => list of chars
                       (str "^"))
                   (dolist (c char-list)
                     (setq str (concat str (list c) "[^-]*-")))
                   (concat (substring str 0 (1- (length str))) "$")))
         (commands (remove-if-not (lambda (string) (string-match regexp string))
                                  (let (c)
                                    (mapatoms (lambda (a)
                                                (if (commandp a)
                                                    (push (symbol-name a) c))))
                                    c))))
    (cond ((> (length commands) 1)
           (call-interactively (intern
                                (if ido-mode
                                    (ido-completing-read "Command: " commands)
                                  (completing-read "Command: " commands)))
                               t))
          ((= (length commands) 1)
           (call-interactively (intern (car commands)) t))
          (t (message "No such command.")))))

To make it quickly accessible I’ve bound it to C-x x.

(global-set-key (kbd "C-x x") 'th-execute-abbreviated-command)

UPDATE:
Alex Schröder pointed me to the builtin partial-completion-mode which allows nearly the same. It requires that you type the separator (- or _), too, so you need a few keystrokes more when you know the commands name. On the other hand it completes not only function names, but also files, e.g. f_b.c will expand to foo_bar.c.

UPDATE2:
The version above uses ido-completing-read when ido-mode is enabled.

Advertisements
Comments
  1. hsu says:

    I have a ton of defalias too…This helps in a big way!
    I tried partial-completion-mode when you said but found it not very practical. Now I’d like to change that function to use ido to select on multiple matches. (Once you get started with iswitchb/ido, the extra tabs you need to enter in plain emacs become very annoying)

    Many thanks!

  2. Tassilo Horn says:

    Hi, cool idea. Above is an updated version.

  3. Mathias Dahl says:

    A small comment about partial-completion-mode: you do not have to type the hyphen (-), you can type a space instead, which for me is more convenient. So to execute, f.ex., `customize-option’, do M-x c u SPC o TAB RET. Yes, a few more keys than C-x x c o RET, but I thought I should mention it, as I discovered this myself just now.

  4. Tassilo Horn says:

    Hi Mathias. What annoys me with partial-completion-mode is that it doesn’t play well with ido-mode. If I could enable it only for completion of commands I’d definitively do it.

  5. […] commands with abbreviations, reloaded 26Jul07 Yesterday I posted a command that executes emacs commands by giving an abbreviation. Today I’ve built a […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s