[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

exec-abbrev-cmd.el: Execute commands by giving an abbreviation

From: Tassilo Horn
Subject: exec-abbrev-cmd.el: Execute commands by giving an abbreviation
Date: Thu, 26 Jul 2007 17:31:48 +0200
User-agent: Gnus/5.110007 (No Gnus v0.7) Emacs/22.1.50 (gnu/linux)

Hi all,

because there are some commands I use quite regularly but not often
enough to justify a global keybinding, I hacked up this little
mode. Have fun with it!

--8<---------------cut here---------------start------------->8---
;;; exec-abbrev-cmd.el --- Execute commands by giving an abbreviation

;; Copyright 2007 Tassilo Horn
;; Author: Tassilo Horn <address@hidden>
;; Version: 0.1
;; Homepage:

;; This  program is free  software; you  can redistribute  it and/or  modify it
;; under the terms  of the GNU General Public License as  published by the Free
;; Software  Foundation;  either version  3,  or  (at  your option)  any  later
;; version.
;; This program is distributed in the  hope that it will be useful, but WITHOUT
;; ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
;; FITNESS FOR  A PARTICULAR PURPOSE.  See  the GNU General  Public License for
;; more details.
;; You should have received a copy of the GNU General Public License along with
;; this program; if not, write to  the Free Software Foundation, Inc., 675 Mass
;; Ave, Cambridge, MA 02139, USA.

;;; Commentary:

;; This file  includes the command  `exec-abbrev-cmd' which lets you  execute a
;; command by  giving it in an  abbreviated form, where  the abbreviation takes
;; the first character of each word in the command name.  For example "g" is an
;; abbreviation  for   the  command  `gnus',   "eb"  is  an   abbreviation  for
;; `emms-browser'  and "omm"  is an  abbreviation for  `outline-minor-mode'. Of
;; course  it  is possible,  that  an  abbreviation  matches several  commands,
;; e.g. "g" matches  not only `gnus' but `grep', `gdb' and  some more.  In such
;; cases you will be queried, which command to use.
;; To have this  functionality quickly accessible you might want  to bind it to
;; some key.  That's what I use:
;;     (add-to-list 'load-path "~/elisp") ;; Where is exec-abbrev-cmd.el?
;;     (require 'exec-abbrev-cmd)         ;; Load it.
;;     (global-set-key (kbd "C-x x") 'exec-abbrev-cmd)
;; Now you'll say,  "Wow, what a nice feature!", but  it's even getting better.
;; Let's say  you often invoke  `customize-face' with `C-x  x cf RET'  and then
;; choosing from the completion  list between `copy-file' and `customize-face'.
;; Always `copy-file' is selected  first, because it's lexicographically before
;; `customize-face'.     As    a    solution    to   this    problem    there's
;; `exec-abbrev-cmd-mode', a global minor  mode that does bookkeeping how often
;; you invoke  a command with `exec-abbrev-cmd',  so that the  list of commands
;; you have  to choose from is  sorted by the frequency  of command invokation.
;; After a while in most cases `C-x x <abbrev> RET RET' will do what you want.
;; If you want to enable this feature put this in your ~/.emacs:
;;     (exec-abbrev-cmd-mode 1)
;; Have fun!

;;; Notes:

;; You should have a look  at `partial-completion-mode' which comes with emacs,
;; too. I like this  mode better because `partial-completion-mode' doesn't play
;; well with `ido-mode', but your mileage may vary.

;;; History:

;; Version 0.1: initial release

;;; Code:

(require 'cl)  ;; for remove-if-not
(require 'ido) ;; for ido-completing-read

(defvar exec-abbrev-cmd-file "~/.emacs.d/exec-abbrev-cmd.el"
  "The file where `exec-abbrev-cmd-alist' will be saved.")

(defvar exec-abbrev-cmd-alist
    (if (not (file-exists-p exec-abbrev-cmd-file))
      (insert-file-contents exec-abbrev-cmd-file)
      (read (current-buffer))))
  "An alist with items of the form (COMMAND . NO-OF-EXECUTIONS)
that will be used to sort the possible completions of
`exec-abbrev-cmd' so that most frequently commands come first.")

(defun exec-abbrev-cmd-record (command)
  "Record the execution of COMMAND to `exec-abbrev-cmd-alist'."
  (let ((pair (assq command exec-abbrev-cmd-alist)))
    (if (not pair)
        ;; Command was never used till now
        (push (cons command 1) exec-abbrev-cmd-alist)
      ;; Ok, it's in, so we need to increase NO-OF-EXECUTIONS.
      (setq exec-abbrev-cmd-alist
            (cons (cons command (1+ (cdr pair)))
                  (delete pair exec-abbrev-cmd-alist))))))

(defun exec-abbrev-cmd-save ()
  "Save `exec-abbrev-cmd-alist' to `exec-abbrev-cmd-file'."
    (print exec-abbrev-cmd-alist (current-buffer))
    (write-file exec-abbrev-cmd-file)))

(defun exec-abbrev-cmd-more-frequently-used-p (c1 c2)
  "Return t if C1 should be sorted before C2.
That is if C1 was more frequently used than C2 or both were used
equally often."
  (>= (or (cdr (assq c1 exec-abbrev-cmd-alist)) 0)
      (or (cdr (assq c2 exec-abbrev-cmd-alist)) 0)))

(defun exec-abbrev-cmd-sort (commands)
  "Return the sorted list of COMMANDS.
Each command in COMMANDS is a string, not a symbol."
  (mapcar 'symbol-name
          (sort (mapcar 'intern commands)

(defun exec-abbrev-cmd (prefixarg)
  "Query for a command abbreviation like \"mbm\" and calculate a
list of all commands of the form \"m[^-]*-b[^-]*-m[^-]*$\".

If this list has only one item, this command will be executed
directly. 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))
                       (str "^"))
                   (dolist (c char-list)
                     (setq str (concat str (list c) "[^-]*-")))
                   (concat (substring str 0 (1- (length str))) "$")))
         (commands (exec-abbrev-cmd-sort
                    (remove-if-not (lambda (string)
                                     (string-match regexp string))
                                   (let (c)
                                      (lambda (a)
                                        (if (commandp a)
                                            (push (symbol-name a) c))))
    (if (not commands)
        (message "No such command.")
      (let ((c (cond ((> (length commands) 1)
                      (intern (ido-completing-read "Command: " commands)))
                     (t (intern (car commands))))))
        (call-interactively c t)
        (when exec-abbrev-cmd-mode
          (exec-abbrev-cmd-record c))))))

(define-minor-mode exec-abbrev-cmd-mode
  "If enabled bookkeeping of command executions with
`exec-abbrev-cmd-execute' will be done, so that the list of
possible command completions is sorted by frequency of
  :init-value nil
  :global t
  (if exec-abbrev-cmd-mode

      ;; Toggled on!
      (add-hook 'kill-emacs-hook 'exec-abbrev-cmd-save)

    ;; Toggled off!
    (remove-hook 'kill-emacs-hook 'exec-abbrev-cmd-save)))

(provide 'exec-abbrev-cmd)

;; Local Variables:
;; mode: outline-minor
;; end

;;; exec-abbrev-cmd.el ends here
--8<---------------cut here---------------end--------------->8---

reply via email to

[Prev in Thread] Current Thread [Next in Thread]