Smex is a M-x
enhancement for Emacs. Built on top of IDO, it provides a convenient interface to your recently and most frequently used commands. And to all the other commands, too.
Extras: Limit commands to those relevant to the active major mode. Show frequently used commands that have no key bindings.
Via package.el, el-get or http://github.com/nonsequitur/smex/blob/master/smex.el?raw=true
http://github.com/nonsequitur/smex/
How to modify smex so that typing a space will insert a hyphen ‘-’
like in normal M-x?
(defadvice smex (around space-inserts-hyphen activate compile) (let ((ido-cannot-complete-command `(lambda () (interactive) (if (string= " " (this-command-keys)) (insert ?-) (funcall ,ido-cannot-complete-command))))) ad-do-it))
If there is only one match it will be completed instead of inserting a hyphen (which may well be a desirable thing). To avoid that, fset ido-complete-space
to that lambda form above, then fset it back after ad-do-it
(flet
doesn’t work for interactive functions).
See also ido-complete-space-or-hyphen.
I don’t like to have smex update every time I run (auto-update is usually good enough, and is noticeably faster). But it’s annoying when I manually load a file and the new commands are not in smex. So I add a smex-update to after-load-functions.
(defun smex-update-after-load (unused) (when (boundp 'smex-cache) (smex-update))) (add-hook 'after-load-functions 'smex-update-after-load)
See also Update smex after function calls that are likely to define new commands
You can see mnemonical commands (within completion) before the others with this code snippet:
(defadvice ido-set-matches-1 (around ido-smex-acronym-matches activate) "Filters ITEMS by setting acronynms first." (if (and (fboundp 'smex-already-running) (smex-already-running) (> (length ido-text) 1)) ;; We use a hash table for the matches, <type> => <list of items>, where ;; <type> can be one of (e.g. `ido-text' is "ff"): ;; - strict: strict acronym match (i.e. "^f[^-]*-f[^-]*$"); ;; - relaxed: for relaxed match (i.e. "^f[^-]*-f[^-]*"); ;; - start: the text start with (i.e. "^ff.*"); ;; - contains: the text contains (i.e. ".*ff.*"); (let ((regex (concat "^" (mapconcat 'char-to-string ido-text "[^-]*-"))) (matches (make-hash-table :test 'eq))) ;; Filtering (dolist (item items) (let ((key)) (cond ;; strict match ((string-match (concat regex "[^-]*$") item) (setq key 'strict)) ;; relaxed match ((string-match regex item) (setq key 'relaxed)) ;; text that start with ido-text ((string-match (concat "^" ido-text) item) (setq key 'start)) ;; text that contains ido-text ((string-match ido-text item) (setq key 'contains))) (when key ;; We have a winner! Update its list. (let ((list (gethash key matches ()))) (puthash key (push item list) matches))))) ;; Finally, we can order and return the results (setq ad-return-value (append (gethash 'strict matches) (gethash 'relaxed matches) (gethash 'start matches) (gethash 'contains matches)))) ;; ...else, run the original ido-set-matches-1 ad-do-it))
e.g. without this code the completion of ‘ffow’ shows:
{ ediff-show-registry | Buffer-menu-1-window | Buffer-menu-2-window ...
with:
{ find-file-other-window | find-function-other-window | ediff-show-registry ...
See also smex with acronyms