Oops! It appears that you have disabled your Javascript. In order for you to see this page as it is meant to appear, we ask that you please re-enable your Javascript!

Emacs PredictiveAbbreviation (pabbrev) – Smart Autocompletion

I’m an Emacs user and although I like it very much, sometimes it requires quite a bit of digging and tweaking to get the features you need and make them work as you want.

I’ve been willing to have this feature in Emacs for quite a while, but never had the time to search for the dependencies and make it work within my .emacs.

Finally I’ve found some good guidelines in Emacs Wiki and managed to get this autocompletion to work.

I’ve been using the DynamicAbbreviations for a while now and even though it is much better then nothing, I don’t like having to press TAB numerous times to get to the word I’m looking for (even worse when you do not remember exactly what you are actually looking for :-)).

PredictiveAbbreviation (aka pabbrev) predicts (while you are typing) the possible completion for the work you are writing, and displays it. You can also make it work with Popup, so when pressing TAB twice, a nice popup window will appear, showing all the possible completions and allowing you to choose among them. It is definitely not an Intellisense, but it is quite more useful then a simple autocompletion.

If you are interested in having this feature in your Emacs, here’s what you have to do:

  1. Download the auto-complete package for Emacs here. You can also get my local copy here.
  2. Download the popup package for Emacs here. You can also get my local copy here.
  3. Download the pabbrev package for Emacs here. You can also get my local copy here.
  4. Add the following to your excerpt to your .emacs (mind to change the load lines with the correct paths in the beginning of the code):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
;; ==================== Pabbrev ====================

(load "YOUR PATH TO popup.el")
(load "YOUR PATH TO auto-complete.el")
(load "YOUR PATH TO pabbrev.el")

(require 'auto-complete)

(defun pabbrevx-ac-on-pre-command ()
  (if (or (eq this-command 'self-insert-command)
          (and (not (ac-trigger-command-p))
               (or (not (symbolp this-command))
                   (not (string-match "^ac-" (symbol-name this-command))))))
      (progn
        (remove-hook 'post-command-hook 'pabbrevx-ac-on-post-command t)
        (remove-hook 'pre-command-hook 'pabbrevx-ac-on-pre-command t)
        (ac-abort))))

(defun pabbrevx-ac-on-post-command ()
  (if (and (not isearch-mode)
           (ac-trigger-command-p))
      (pabbrevx-ac-start)))

(defun pabbrevx-ac-start ()
  (let ((candidates (mapcar 'car pabbrev-expansion-suggestions)))
    (add-hook 'pre-command-hook 'pabbrevx-ac-on-pre-command nil t)
    (add-hook 'post-command-hook 'pabbrevx-ac-on-post-command nil t)
    ;; ripped straight from ac-start
    (let* ((point (save-excursion (funcall ac-prefix-function)))
           (reposition (or (not (equal ac-point point))
                           ;; If menu direction is positive and next visual line belongs
                           ;; to same buffer line, then need reposition
                           (and (> ac-menu-direction 0)
                                (ac-menu-at-wrapped-line)))))
      (if (null point)
          (progn
            ;; need to nil this so pabbrev-expand-maybe-full we won't try
            ;; pabbrev expansion if user hits another TAB after ac aborts
            (setq pabbrev-last-expansion-suggestions nil)
            (ac-abort))          
        (setq ac-buffer (current-buffer))
        (setq ac-point point)
        (when (not (equal ac-point ac-old-point))
          (setq ac-old-point point))
        (setq ac-prefix (buffer-substring-no-properties point (point)))
        (setq ac-limit ac-candidate-limit)
        (if (or reposition (null ac-menu))
            (save-excursion
              (funcall ac-init-function)))
        (let (;;candidates
              width
              (current-width (if ac-menu (ac-menu-width ac-menu) 0)))
          ;; (setq candidates (if (or ac-completing
          ;;                          (not (integerp ac-auto-start))
          ;;                          (>= (length ac-prefix) ac-auto-start))
          ;;                      (save-excursion
          ;;                        (funcall ac-candidate-function))))
          ;;(if ac-candidate-filter-function
          ;;    (setq candidates (funcall ac-candidate-filter-function candidates)))
          (setq width (let ((w '(0)) s)
                        (dotimes (i ac-candidate-menu-height)
                          (setq s (nth i candidates))
                          (if (stringp s) (push (string-width s) w)))
                        (apply 'max w)))
          (if (or reposition
                  (null ac-menu)
                  (> width current-width)
                  (< width (- current-width 10)))
              (ac-setup (* (ceiling (/ width 10.0)) 10)))
          (ac-update-candidates candidates))))))

(defun pabbrevx-suggestions-goto-buffer (suggestions)
  (pabbrevx-ac-start))

(fset 'pabbrev-suggestions-goto-buffer 'pabbrevx-suggestions-goto-buffer)

(require 'popup)

(defun pabbrevx-suggestions-goto-buffer (suggestions)
  (let* ((candidates (mapcar 'car suggestions))
         (bounds (pabbrev-bounds-of-thing-at-point))
         (selection (popup-menu* candidates
                                 :point (car bounds)
                                 :scroll-bar t)))
    (when selection
      ;; modified version of pabbrev-suggestions-insert
      (let ((point))
        (save-excursion
          (progn
            (delete-region (car bounds) (cdr bounds))
            (insert selection)
            (setq point (point))))
        (if point
            (goto-char point))
        ;; need to nil this so pabbrev-expand-maybe-full won't try
        ;; pabbrev expansion if user hits another TAB after ac aborts
        (setq pabbrev-last-expansion-suggestions nil)
        ))))
     
(fset 'pabbrev-suggestions-goto-buffer 'pabbrevx-suggestions-goto-buffer)

This should be enough to get pabbrev working and save you some precious time while coding!

Hope you enjoy as much as I did!

© 2011 – 2012, fbastian. All rights reserved.

Leave a Reply

%d bloggers like this: