root/dotfiles/emacs/yappo/.emacs.d/elisp/auto-complete.el @ 26364

Revision 26364, 26.9 kB (checked in by yappo, 4 years ago)

import yappo's emacs

Line 
1;;; auto-complete.el --- Auto completion with popup menu
2
3;; Copyright (C) 2008  MATSUYAMA Tomohiro
4
5;; Author: MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
6;; Keywords: convenience
7;; Version: 0.1.0
8
9;; This program is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; This program is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;; This extension provides a way to select a completion with
25;; popup menu.
26;;
27;; I checked that this extension can work properly on GNU Emacs 22 or higher.
28
29;; To use this extension, locate this file to load-path directory,
30;; and add the following code to your .emacs.
31;; ------------------------------
32;; (require 'auto-complete)
33;; (global-auto-complete-mode t)
34;; ------------------------------
35
36;; After installation, you can try this:
37;;
38;; 1. Switch to emacs-lisp-mode buffer such as .emacs
39;; 2. Goto anywhere
40;; 3. Type "def"
41;; 4. You may see a pop menu after the cursor like:
42;;    def-!-
43;;    +-----------------+
44;;    |defun            |    <- highlight
45;;    |defvar           |
46;;    |defmacro         |
47;;    |       ...       |
48;;    +-----------------+
49;; 5. You can complete by seleting the menu item
50;;    by pressing TAB, <down>, <up>, and RET.
51
52;;; Tips:
53;;
54;; ================================
55;; Use C-n/C-p to select candidates
56;; ================================
57;;
58;; Add following code to your .emacs.
59;;
60;; ------------------------------
61;; (define-key ac-complete-mode-map "\C-n" 'ac-next)
62;; (define-key ac-complete-mode-map "\C-p" 'ac-previous)
63;; ------------------------------
64;;
65;;
66;; ====================================
67;; Don't start completion automatically
68;; ====================================
69;;
70;; Add following code to your .emacs.
71;;
72;; ------------------------------
73;; (setq ac-auto-start nil)
74;; (global-set-key "\M-/" 'ac-start)
75;; ------------------------------
76;;
77;; Or
78;;
79;; ------------------------------
80;; ;; start completion when entered 3 characters
81;; (setq ac-auto-start 3)
82;; ------------------------------
83;;
84;;
85;; =================
86;; Completion by TAB
87;; =================
88;;
89;; Add following code to your .emacs.
90;;
91;; ------------------------------
92;; (define-key ac-complete-mode-map "\t" 'ac-complete)
93;; (define-key ac-complete-mode-map "\r" nil)
94;; ------------------------------
95;;
96;;
97;; ===================
98;; Do What I Mean mode
99;; ===================
100;;
101;; If DWIM (Do What I Mean) mode is enabled,
102;; the following features is available:
103;;
104;; a. TAB (ac-expand) behave as completion (ac-complete)
105;;    when only one candidate is left
106;; b. TAB (ac-expand) behave as completion (ac-complete)
107;;    after you select candidate
108;;
109;; DWIM mode is enabled by default.
110;; You can disable this feature by
111;; setting `ac-dwim' to nil.
112
113;; This extension is so simple that you can extend
114;; how Emacs find a target and how Emacs enumerate
115;; candidates.
116;; I don't have intention to implement heavy functions :-)
117;;
118;; Enjoy!
119
120;;; History:
121
122;; 2008-11-26 MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
123;;
124;;      * auto-complete.el 0.1.0 released
125;;
126;; 2008-11-19 MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
127;;
128;;      * thanks for Taiki SUGAWARA <buzz.taiki@gmail.com>
129;;      *   added source ac-source-abbrev
130;;      *   added source ac-source-symbols
131;;      * added ac-expand-common to expand common part
132;;
133;; 2008-11-18 MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
134;;
135;;      * added ac-auto-start switch
136;;      * added ac-dwim switch
137;;      * changed menu popup behavior at end of window
138;;      *   thanks rubikitch <rubikitch@ruby-lang.org>, kazu-yamamoto.
139;;      * fixed canceler bug
140;;      * changed to use overriding-local-map instead of minor mode map
141;;      * changed default key bindings
142;;
143;; 2008-11-16 MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
144;;
145;;      * supported candidates by using sources
146;;      * added automatically start swtich
147;;      * fixed some bug
148;;      * added source ac-source-files-in-current-dir
149;;      * added source ac-source-words-in-buffer
150;;      * added source ac-source-yasnippet
151;;      * renamed ac-enum-candidates-function to ac-candidate-function
152;;      * renamed ac-find-target-function to ac-find-function
153;;      * ac-find-function and ac-candidate-function is not buffer local variable now
154;;      * made candidates visible when you are end of line
155;;
156;; 2008-11-11 MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
157;;
158;;      * by reporting from rubikitch <rubikitch@ruby-lang.org>
159;;      *   renamed hook name
160;;      *   registered backward-delete-char as special command
161;;      * fixed code for creating candidates
162;;      * made auto-complete disabled when isearch-mode enabled
163;;      * added some major-mode into ac-modes
164;;
165;; 2008-11-09  MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
166;;
167;;      * auto-complete.el 0.0.1 released
168;;      * fixed double-width character displaying problem
169;;      * fixed menu position following tab character
170;;      * made candidates visible when you are end of window
171
172;;; TODO:
173;;
174;; - performance issue (cache issue)
175;; - single source mode
176;; - fix narrowing bug (reported by Yuto Hayamizu <y.hayamizu@gmail.com>)
177;; - care about undo (buffer-disable-undo)
178;; - support scroll in menu
179;; - use double candidate menu
180;; - omni completion
181;; - show description
182;; - demo movie (YouTube)
183;; - backward menu in tiny buffer
184;; - dictionary
185;; - semantic
186
187;;; Code:
188
189
190
191(defgroup auto-complete nil
192  "Auto completion with popup menu"
193  :group 'convenience
194  :prefix "auto-complete-")
195
196(defcustom ac-candidate-menu-width 25
197  "Max width of candidate menu."
198  :type 'number
199  :group 'auto-complete)
200
201(defcustom ac-candidate-menu-height 10
202  "Max height of candidate menu."
203  :type 'number
204  :group 'auto-complete)
205
206(defcustom ac-candidate-max 10
207  "Max of number of candidates."
208  :type 'number
209  :group 'auto-complete)
210
211(defcustom ac-modes
212  '(emacs-lisp-mode lisp-interaction-mode
213                    c-mode cc-mode c++-mode java-mode
214                    perl-mode cperl-mode python-mode ruby-mode
215                    ecmascript-mode javascript-mode php-mode css-mode
216                    makefile-mode sh-mode fortran-mode f90-mode ada-mode
217                    xml-mode sgml-mode)
218  "Major modes `auto-complete-mode' can run on."
219  :type '(list symbol)
220  :group 'auto-complete)
221
222(defcustom ac-auto-start t
223  "Non-nil means completion will be started automatically.
224Positive integer means if a length of a word you entered is larger than the value,
225completion will be started automatically.
226If you specify `nil', never be started automatically."
227  :group 'auto-complete)
228
229(defcustom ac-dwim t
230  "Non-nil means `auto-complete' works based on Do What I Mean."
231  :type 'boolean
232  :group 'auto-complete)
233
234(defface ac-selection-face
235  '((t (:background "blue" :foreground "white")))
236  "Face for the selected candidate."
237  :group 'auto-complete)
238
239(defface ac-menu-face
240  '((t (:background "lightgray" :foreground "black")))
241  "Face for candidate menu."
242  :group 'auto-complete)
243
244(defvar auto-complete-mode-hook nil
245  "Hook for `auto-complete-mode'.")
246
247(defvar ac-menu nil
248  "Menu instance.")
249
250(defvar ac-menu-direction 1
251  "Positive integer means `ac-menu' grows forward.
252Or, `ac-menu' grows backward.")
253
254(defvar ac-menu-offset 0
255  "Offset to contents.")
256
257(defvar ac-completing nil
258  "Non-nil means `auto-complete-mode' is now working on completion.")
259
260(defvar ac-saved-window-start nil
261  "Saved window start value for restore.")
262
263(defvar ac-saved-window-hscroll nil
264  "Saved window hscroll value for restore.")
265
266(defvar ac-point nil
267  "Start point of target.")
268
269(defvar ac-target nil
270  "Target string.")
271
272(defvar ac-limit 0
273  "Limit of number of candidates.")
274
275(defvar ac-candidates nil
276  "Current candidates.")
277
278(defvar ac-selection nil
279  "Current candidate index.")
280
281(defvar ac-dwim-enable nil
282  "Non-nil means DWIM completion will be allowed.")
283
284(defvar ac-find-function 'ac-default-find
285  "When `auto-complete-mode' finds it can start completion
286or update candidates, it will call this function to find a
287start point of the completion target.
288
289If this function returns an integer, `auto-complete-mode'
290will set the substring between the point and current point to `ac-target'.
291And also it will start completion or update candidates by using
292the `ac-target'.
293
294If this function returns `nil', `auto-complete-mode'
295ignore starting completion or stop completing.")
296
297(defvar ac-init-function 'ac-sources-init
298  "This function will be called when candidate menu is setupped.")
299
300(defvar ac-candidate-function 'ac-sources-candidate
301  "This function can return candidates as list by
302using the `TARGET' that is given as a first argument.")
303
304(defvar ac-complete-mode-map
305  (let ((map (make-sparse-keymap)))
306    (define-key map "\t" 'ac-expand)
307    (define-key map "\r" 'ac-complete)
308   
309    (define-key map [down] 'ac-next)
310    (define-key map [up] 'ac-previous)
311
312    map)
313  "Keymap for completion.")
314
315(or (assq 'ac-completing minor-mode-map-alist)
316    (push (cons 'ac-completing ac-complete-mode-map) minor-mode-map-alist))
317
318(defvar ac-saved-local-map nil
319  "Old keymap before `auto-complete' activated.")
320
321
322
323;;;; Auto completion
324
325(defun ac-setup (point)
326  "Setup popup menu."
327  (save-excursion
328    (goto-char point)
329    (let ((column (current-column))
330          (line (line-number-at-pos)))
331      (setq ac-saved-window-start (window-start))
332      (setq ac-saved-window-hscroll (window-hscroll))
333      (setq ac-menu-direction
334            (if (and (> line ac-candidate-max)
335                     (> ac-candidate-max
336                        (-
337                         (max 1 (- (window-height)
338                                   (if mode-line-format 1 0)
339                                   (if header-line-format 1 0)))
340                         (1+ (count-lines (window-start) (point))))))
341                -1
342              1))
343      (let ((window-width (window-width))
344            (right (- (+ column ac-candidate-menu-width)
345                      (window-hscroll))))
346        (if (and (> right window-width)
347                 (>= right ac-candidate-menu-width))
348            (setq column (- column ac-candidate-menu-width))))
349      (if (> ac-menu-direction 0)
350          (progn
351            (forward-line)
352            (if (eq line (line-number-at-pos))
353                (newline)
354              (forward-line -1))
355            (setq ac-menu (ac-menu-create (1+ line) column ac-candidate-menu-width ac-candidate-menu-height))
356            (setq ac-point point))
357        (setq ac-menu (ac-menu-create (- line ac-candidate-max) column ac-candidate-menu-width ac-candidate-menu-height))
358        (setq ac-point point)))))
359
360(defun ac-cleanup ()
361  "Destroy popup menu."
362  (ac-deactivate-mode-map)
363  (when ac-menu
364    (ac-menu-delete ac-menu)
365    (set-window-start (selected-window) ac-saved-window-start)
366    (set-window-hscroll (selected-window) ac-saved-window-hscroll))
367  (setq ac-menu nil)
368  (setq ac-completing nil)
369  (setq ac-point nil)
370  (setq ac-candidates nil)
371  (setq ac-selection 0))
372
373(defun ac-activate-mode-map ()
374  "Activate `ac-complete-mode-map'."
375  (setq ac-saved-local-map overriding-terminal-local-map)
376  (if (eq ac-saved-local-map ac-complete-mode-map)
377      ;; maybe never reach here
378      (setq ac-saved-local-map nil))
379  (setq overriding-terminal-local-map ac-complete-mode-map))
380
381(defun ac-deactivate-mode-map ()
382  "Deactivate `ac-complete-mode-map'."
383  (when (eq overriding-terminal-local-map ac-complete-mode-map)
384    (setq overriding-terminal-local-map ac-saved-local-map)
385    (setq ac-saved-local-map nil)))
386
387(defun ac-next ()
388  "Select next candidate."
389  (interactive)
390  (if (interactive-p)
391      (setq ac-dwim-enable t))
392  (if ac-candidates
393      (ac-select-candidate
394       (let ((selection (1+ ac-selection)))
395         (if (= selection (+ ac-menu-offset (min ac-candidate-menu-height (length ac-candidates))))
396             ac-menu-offset
397           selection)))))
398
399(defun ac-previous ()
400  "Select previous candidate."
401  (interactive)
402  (if (interactive-p)
403      (setq ac-dwim-enable t))
404  (if ac-candidates
405      (ac-select-candidate
406       (let ((selection (1- ac-selection)))
407         (if (< selection ac-menu-offset)
408             (1- (+ ac-menu-offset (min ac-candidate-menu-height (length ac-candidates))))
409           selection)))))
410
411(defun ac-expand-1 ()
412  "Try expansion."
413  (let ((string (overlay-get (ac-menu-line-overlay ac-menu ac-selection) 'real-string)))
414    (delete-region ac-point (point))
415    (insert string)
416    (setq ac-target string)))
417
418(defun ac-expand ()
419  "Try expansion but select next if expanded twice."
420  (interactive)
421  (if (and ac-dwim ac-dwim-enable)
422      (ac-complete)
423    (let ((target ac-target)
424          (string (ac-expand-1)))
425      (when (equal target string)
426        (ac-next)
427        (ac-expand-1)))))
428
429(defun ac-expand-common ()
430  "Try expansion common part."
431  (interactive)
432  (let ((common (try-completion ac-target ac-candidates)))
433    (when (stringp common)
434      (delete-region ac-point (point))
435      (insert common)
436      (setq ac-target common))))
437
438(defun ac-complete ()
439  "Try completion."
440  (interactive)
441  (let* ((string (overlay-get (ac-menu-line-overlay ac-menu ac-selection) 'real-string))
442         (source (get-text-property 0 'source string))
443         (complete-function (and source (cdr-safe (assq 'action source)))))
444    (ac-expand-1)
445    (if complete-function
446        (funcall complete-function))
447    (ac-abort)))
448
449(defun ac-abort ()
450  "Abort completion."
451  (ac-cleanup))
452
453(defun ac-update-candidates (candidates)
454  "Update candidates of popup menu."
455  (setq ac-menu-offset (if (> ac-menu-direction 0)
456                           0
457                         (- ac-candidate-menu-height
458                            (min ac-candidate-menu-height
459                                 (length candidates)))))
460  (setq ac-selection ac-menu-offset)
461  (setq ac-candidates candidates)
462  (setq ac-dwim-enable (= (length candidates) 1))
463  (if candidates
464      (progn
465        (setq ac-completing t)
466        (ac-activate-mode-map))
467    (setq ac-completing nil)
468    (ac-deactivate-mode-map))
469  (let ((i ac-menu-offset))
470    ;; show line and set string to the line
471    (mapcar
472     (lambda (candidate)
473       (when (< i ac-candidate-menu-height)
474         (ac-menu-show-line ac-menu i)
475         (ac-menu-set-line-string ac-menu i candidate (if (= i ac-selection) 'ac-selection-face))
476         (setq i (1+ i))))
477     candidates)
478    ;; ensure lines visible
479    (if (and (> ac-menu-direction 0)
480             (> i (-
481                   (max 1 (- (window-height)
482                             (if mode-line-format 1 0)
483                             (if header-line-format 1 0)))
484                   (1+ (count-lines (window-start) (point))))))
485        (recenter (- (1+ i))))
486    (if (> i ac-menu-offset)
487        (let ((window-width (window-width))
488              (right (- (+ (ac-menu-column ac-menu) ac-candidate-menu-width)
489                        (window-hscroll))))
490          (if (> right window-width)
491              (scroll-left (- right window-width)))))
492    ;; hide remaining lines
493    (if (> ac-menu-direction 0)
494        (while (< i ac-candidate-menu-height)
495          (ac-menu-hide-line ac-menu i)
496          (setq i (1+ i)))
497      (dotimes (i ac-menu-offset)
498        (ac-menu-hide-line ac-menu i)))))
499
500(defun ac-select-candidate (selection)
501  "Select candidate pointed by `SELECTION'."
502  (when ac-candidates
503    (ac-menu-set-line-string ac-menu ac-selection (nth (- ac-selection ac-menu-offset) ac-candidates))
504    (ac-menu-set-line-string ac-menu selection (nth (- selection ac-menu-offset) ac-candidates) 'ac-selection-face)
505    (setq ac-selection selection)))
506
507(defun ac-default-find ()
508  "Default implemention for `ac-find-function'."
509  (require 'thingatpt)
510  (car-safe (bounds-of-thing-at-point 'symbol)))
511
512(defun ac-start ()
513  "Start completion."
514  (interactive)
515  (let ((point (funcall ac-find-function)))
516    (if (or (null point)
517            (and ac-menu
518                 (/= point ac-point)))
519        (ac-abort)
520      (when (null ac-menu)
521        (ac-setup point)
522        (funcall ac-init-function))
523      (setq ac-target (buffer-substring-no-properties point (point)))
524      (setq ac-limit ac-candidate-max)
525      (ac-update-candidates
526       (if (or ac-completing
527               (not (integerp ac-auto-start))
528               (>= (length ac-target) ac-auto-start))
529           (funcall ac-candidate-function))))))
530
531(defun ac-trigger-command-p ()
532  "Return non-nil if `this-command' is a trigger command."
533  (or (eq this-command 'self-insert-command)
534      (and ac-completing
535           (memq this-command
536                 '(delete-backward-char
537                   backward-delete-char
538                   backward-delete-char-untabify)))))
539
540(defun ac-on-pre-command ()
541  (if (and (not (ac-trigger-command-p))
542           (or (not (symbolp this-command))
543               (not (string-match "^ac-" (symbol-name this-command)))))
544      (ac-abort)))
545
546(defun ac-on-post-command ()
547  (if (and ac-auto-start
548           (not isearch-mode)
549           (ac-trigger-command-p))
550      (ac-start)))
551
552(defun auto-complete-mode-maybe ()
553  "What buffer `auto-complete-mode' prefers."
554  (if (and (not (minibufferp (current-buffer)))
555           (memq major-mode ac-modes))
556      (auto-complete-mode 1)))
557
558(require 'easy-mmode)
559
560(define-minor-mode auto-complete-mode
561  "AutoComplete mode"
562  :lighter " AC"
563  :group 'auto-complete
564  (if auto-complete-mode
565      (progn
566        (add-hook 'post-command-hook 'ac-on-post-command nil t)
567        (add-hook 'pre-command-hook 'ac-on-pre-command nil t)
568        (run-hooks 'auto-complete-mode-hook))
569    (remove-hook 'post-command-hook 'ac-on-post-command t)
570    (remove-hook 'pre-command-hook 'ac-on-pre-command t)
571    (ac-abort)))
572
573(if (fboundp 'define-global-minor-mode)
574    (define-global-minor-mode global-auto-complete-mode
575      auto-complete-mode auto-complete-mode-maybe
576      :group 'auto-complete))
577
578
579
580;;;; Sources implementation
581
582(defvar ac-sources '(ac-source-words-in-buffer)
583  "Sources.")
584
585(defun ac-sources-init ()
586  "Implementation for `ac-init-function' by sources."
587  (dolist (source ac-sources)
588    (if (symbolp source)
589        (setq source (symbol-value source)))
590    (let ((init-function (cdr-safe (assq 'init source))))
591      (if init-function
592          (funcall init-function)))))
593
594(defun ac-sources-candidate ()
595  "Implementation for `ac-cadidates-function' by sources."
596  (when (> (length ac-target) 0)
597    (let (candidates)
598      (dolist (source ac-sources)
599        (if (symbolp source)
600            (setq source (symbol-value source)))
601        (let* ((ac-limit (or (cdr-safe (assq 'limit source)) ac-limit))
602               (requires (cdr-safe (assq 'requires source)))
603               cand)
604          (if (or (null requires)
605                  (>= (length ac-target) requires))
606              (setq cand
607                    (delq nil
608                          (mapcar (lambda (candidate)
609                                    (propertize candidate 'source source))
610                                  (funcall (cdr (assq 'candidates source)))))))
611          (if (and (> ac-limit 1)
612                   (> (length cand) ac-limit))
613              (setcdr (nthcdr (1- ac-limit) cand) nil))
614          (setq candidates (append candidates cand))))
615      (delete-dups candidates))))
616
617(defun ac-candidate-words-in-buffer ()
618  "Default implemention for `ac-candidate-function'."
619  (if (> (length ac-target) 0)
620      (let ((i 0)
621            candidate
622            candidates
623            (regexp (concat "\\b" (regexp-quote ac-target) "\\(\\s_\\|\\sw\\)*\\b")))
624        (save-excursion
625          ;; search backward
626          (goto-char ac-point)
627          (while (and (< i ac-limit)
628                      (re-search-backward regexp nil t))
629            (setq candidate (match-string-no-properties 0))
630            (unless (member candidate candidates)
631              (push candidate candidates)
632              (setq i (1+ i))))
633          ;; search backward
634          (goto-char (+ ac-point (length ac-target)))
635          (while (and (< i ac-limit)
636                      (re-search-forward regexp nil t))
637            (setq candidate (match-string-no-properties 0))
638            (unless (member candidate candidates)
639              (push candidate candidates)
640              (setq i (1+ i))))
641          (nreverse candidates)))))
642
643(defvar ac-source-words-in-buffer
644  '((candidates . ac-candidate-words-in-buffer))
645  "Simple source like dabbrev.")
646
647(defvar ac-source-symbols
648  '((candidates
649     . (lambda ()
650         (all-completions ac-target obarray))))
651  "Source for Emacs lisp symbols.")
652
653(defvar ac-source-abbrev
654  `((candidates
655     . (lambda ()
656         (all-completions ac-target local-abbrev-table)))
657    (action
658     . expand-abbrev))
659  "Source for abbrev.")
660
661(defvar ac-source-files-in-current-dir
662  '((candidates
663     . (lambda () (all-completions ac-target (directory-files default-directory)))))
664  "Source for listing files in current directory.")
665
666(defvar ac-imenu-index nil
667  "Imenu index.")
668
669(defun ac-imenu-candidate ()
670  (require 'imenu)
671  (let ((i 0)
672        (stack ac-imenu-index)
673        candidates
674        node)
675    (while (and stack
676                (< i ac-limit))
677      (setq node (pop stack))
678      (when (consp node)
679        (let ((car (car node))
680              (cdr (cdr node)))
681          (if (consp cdr)
682              (mapcar (lambda (child)
683                        (push child stack))
684                      cdr)
685            (when (and (stringp car)
686                       (string-match (concat "^" (regexp-quote ac-target)) car))
687              (push car candidates)
688              (setq i (1+ i)))))))
689    (nreverse candidates)))
690
691(defvar ac-source-imenu
692  '((init
693     . (lambda ()
694         (require 'imenu)
695         (setq ac-imenu-index
696               (condition-case nil
697                   (imenu--make-index-alist)
698                 (error nil)))))
699    (candidates . ac-imenu-candidate))
700  "Source for imenu.")
701
702(defun ac-yasnippet-candidate-1 (table)
703  (let ((hashtab (yas/snippet-table-hash table))
704        (parent (yas/snippet-table-parent table))
705        candidates)
706    (maphash (lambda (key value)
707               (push key candidates))
708             hashtab)
709    (setq candidates (all-completions ac-target (nreverse candidates)))
710    (if parent
711        (setq candidates
712              (append candidates (ac-yasnippet-candidate-1 parent))))
713    candidates))
714
715(defun ac-yasnippet-candidate ()
716  (require 'yasnippet)
717  (let ((table (yas/snippet-table major-mode)))
718    (if table
719        (ac-yasnippet-candidate-1 table))))
720
721(defvar ac-source-yasnippet
722  '((candidates . ac-yasnippet-candidate)
723    (action . yas/expand)
724    (limit . 3))
725  "Source for Yasnippet.")
726
727
728
729;;;; Popup menu
730
731(defun ac-menu-line (menu)
732  "Line number of `MENU'."
733  (nth 0 menu))
734
735(defun ac-menu-column (menu)
736  "Column of `MENU'."
737  (nth 1 menu))
738
739(defun ac-menu-width (menu)
740  "Popup menu width of `MENU'."
741  (nth 2 menu))
742
743(defun ac-menu-height (menu)
744  "Popup menu height of `MENU'."
745  (nth 3 menu))
746
747(defun ac-menu-overlays (menu)
748  "Overlays that `MENU' contains."
749  (nth 4 menu))
750
751(defun ac-menu-line-overlay (menu line)
752  "Return a overlay of `MENU' at `LINE'."
753  (aref (ac-menu-overlays menu) line))
754
755(defun ac-menu-hide-line (menu line)
756  "Hide `LINE' in `MENU'."
757  (let ((overlay (ac-menu-line-overlay menu line)))
758    (overlay-put overlay 'invisible nil)
759    (overlay-put overlay 'after-string nil)))
760
761(defun ac-menu-show-line (menu line)
762  "Show `LINE' in `MENU'."
763  (let ((overlay (ac-menu-line-overlay menu line)))
764    (overlay-put overlay 'invisible t)))
765
766(defun ac-menu-set-line-string (menu line string &optional face)
767  "Set contents of `LINE' in `MENU'."
768  (let ((overlay (ac-menu-line-overlay menu line)))
769    (overlay-put overlay 'real-string string)
770    (funcall (overlay-get overlay 'set-string-function) overlay string face)))
771
772(defun ac-menu-create-line-string (menu string)
773  "Adjust `STRING' into `MENU'."
774  (let ((length 0)
775        (width 0)
776        (menu-width (ac-menu-width menu))
777        (chars (append string nil)))
778    (while (and
779            chars
780            (<= (setq width (+ width (char-width (car chars)))) menu-width))
781      (setq length (1+ length))
782      (setq chars (cdr chars)))
783    (if (< length (length string))
784        (setq string (substring string 0 length)))
785    (let ((string-width (string-width string)))
786      (if (< string-width menu-width)
787          (setq string (concat string
788                               (make-string (- menu-width string-width) ? )))))
789    string))
790
791(defun ac-menu-hide (menu)
792  "Hide `MENU'."
793  (dotimes (i (ac-menu-height menu))
794    (ac-menu-hide-line menu i)))
795
796(defun ac-menu-last-line-of-buffer ()
797  (save-excursion
798    (not (eq (forward-line) 0))))
799
800(defun ac-menu-create (line column width height)
801  "Create popup menu."
802  (save-excursion
803    (let ((overlays (make-vector height nil))
804          (window (selected-window)))
805      (goto-line line)
806      (dotimes (i height)
807        (move-to-column column)
808        (let (overlay begin w current-column (prefix "") (postfix ""))
809          (setq current-column (current-column))
810          (cond
811           ((> current-column column)
812            (backward-char)
813            (setq current-column (current-column))
814            (if (< current-column column)
815                (setq prefix (make-string (- column current-column) ? ))))
816           ((< current-column column)
817            (setq prefix (make-string (- column current-column) ? ))))
818
819          (setq begin (point))
820          (setq w (+ width (length prefix)))
821          (while (and (not (eolp))
822                      (> w 0))
823            (setq w (- w (char-width (char-after))))
824            (forward-char))
825          (if (< w 0)
826              (setq postfix (make-string (- w) ? )))
827          (if (ac-menu-last-line-of-buffer)
828              (setq postfix (concat postfix "\n")))
829
830          (setq overlay (make-overlay begin (point)))
831          (overlay-put overlay 'window window)
832          (overlay-put overlay 'prefix prefix)
833          (overlay-put overlay 'postfix postfix)
834          (overlay-put overlay 'width width)
835          (overlay-put overlay 'set-string-function
836                       (lambda (overlay string &optional face)
837                         (overlay-put overlay
838                                      'after-string
839                                      (concat (overlay-get overlay 'prefix)
840                                              (propertize (ac-menu-create-line-string menu string) 'face (or face 'ac-menu-face))
841                                              (overlay-get overlay 'postfix)))))
842          (aset overlays i overlay))
843        (forward-line))
844      (let ((i 100))
845        (mapcar (lambda (overlay)
846                  (overlay-put overlay 'priority i)
847                  (setq i (1+ i)))
848                (nreverse (append overlays nil))))
849      (list line column width height overlays))))
850
851(defun ac-menu-delete (menu)
852  "Delete `MENU'."
853  (mapcar 'delete-overlay (ac-menu-overlays menu)))
854
855(provide 'auto-complete)
856;;; auto-complete.el ends here
Note: See TracBrowser for help on using the browser.