DynamicAbbreviations

See also: AbbrevMode.

Dynamic Abbrevs

Dynamic Abbreviations are one of the coolest functions in Emacs.

A dynamic abbreviation (dabbrev) is almost like a normal abbreviation that you define, with the following differences:

  1. You do not have to define it :)
  2. You need to call the dabbrev-expand command explicitly to use it

What it does is to look at the “word” to the left of point and try to expand that word by looking for text in the current buffer, and if not found there, in all open buffers (e.g. /usr/share/dict/words) ;-) --Andre

Examples

Did I say that this is extremely cool? :)

Let’s say you define

 thisLongVariableName 

somewhere in the code. Somewhere further down in the code you want to write the variable name again. Instead of doing this, just type a few letters, for example “this”, and then activate the dabbrev-expand command.

Instant magic!

If the expansion is not what you wanted, you can cycle through all possible expansions by repeatedly executing the command again.

This works on all kinds of text in all buffers.

Bindings

This is bound to M-/ by default. Since that is rather hard to type on some keyboards, try this:

    (global-set-key (kbd "C-<tab>") 'dabbrev-expand)
    (define-key minibuffer-local-map (kbd "C-<tab>") 'dabbrev-expand)

You need the second statement because in the MiniBuffer, `C-<tab>’ has a separate binding which overrides the global one.

Getting Character Case Right

I’ve been writing C# code with Emacs and it has a lot of StudlyCaps style variable names. I use dabbrev-expand (and sometimes also hippie-expand) a lot to ‘tab-complete’ my words. When given two variable names, ‘ThisWord’ and ‘thisWord’, ‘Th’ + dabbrev-expand yields correctly ‘ThisName’, but ‘th’ + dabbrev-expand produces ‘thisname’, instead of ‘thisName’. Is there a way to correct this? – DuncanMak

Heh, I figured it out myself. Set dabbrev-case-fold-search to make dabbrev-expand match for case.
YES, thanks a lot for this hint.

Finding the Right Expansion

If there is more than one expansion for the same prefix, using dabbrev-expand repeatedly will cause it to search for other possible expansions. For example, if you have a buffer that looks like this:

    thisLongVariable
    thisOtherLongVariable

and you type “this” then execute dabbrev-expand, “this” will be expanded as “thisOtherLongVariableName”. If you immediately execute dabbrev-expand again, the expansion will be replaced with “thisLongVariable”.

Continuing Expansion

Once you have successfully used dabbrev-expand to expand a word, hitting <space> then immediately using dabbrev-expand again will continue to expand from the point that the expansion was found. For example. If previously in the buffer, you had made the function call:

    thisLongVariableName.someFunction(someArgument)

Then at some point later in the buffer you type: “this” then use dabbrev-expand to expand “this” to “thisLongVariableName”, if you then type <space> and then use dabbrev-expand again, it will expand “thisLongVariableName” to “thisLongVariableName.someFunction”. Continuing this, if you type <space> again then dabbrev-expand again, it will add “(someArgument” and the following word to the expansion.

Vim Style c file expansion

In Vim, C-p/C-n expands current words according by parsing #include lines recursively. This could be done like the following:

(require 'cl)
(defvar cdsb-include-re "^\\s-*#\\s-*\\(?:include\\|import\\)\\s-*\\([\"<]\\)\\([^\">]+\\)[\">]\\s-*$")
(defun cdsb-extract-includes-in-buffer (buffer)
  (with-current-buffer buffer
    (save-excursion
      (goto-char (point-min))
      (loop while (re-search-forward cdsb-include-re nil t)
            collect (cons (match-string-no-properties 2) (not (string-equal (match-string-no-properties 1) "\"")))))))
(defun cdsb-acc-buffers (buffer non-system-files buffer-list)
  (loop with new-buffer-list = nil
        for (name . system-include-p) in (cdsb-extract-includes-in-buffer buffer)
        do (let* ((file (if system-include-p
                            (ffap-c-mode name)
                          (let ((name-re (concat "/" (regexp-quote name) "$")))
                            (loop for file in non-system-files
                                  if (string-match name-re file)
                                  return file))))
                  (buf (and file (find-file-noselect file t))))
             ;; (message "check %s => %s" name file)
             (and buf
                  (not (position buf buffer-list))
                  (setq buffer-list (cdsb-acc-buffers buf non-system-files (cons buf buffer-list)))))
        finally return buffer-list))
(defun c-dabbrev--select-buffers ()
  (if (memq major-mode '(c-mode c++-mode objc-mode))
      (save-excursion
        (require 'ffap)
        (let ((top (project-top-directory))
              (cur (current-buffer)))
          (nreverse
           (cdr
            (nreverse
             (cdsb-acc-buffers cur (and top (project-source-files top)) (list cur)))))))
    (dabbrev--select-buffers)))

(add-hook 'c-mode-common-hook 
  (lambda () 
    (set (make-variable-buffer-local 'dabbrev-select-buffers-function) 'c-dabbrev--select-buffers)))

Packages which extend standard Emacs Dynamic Abbreviation


CategoryCompletion