summaryrefslogtreecommitdiffstats
path: root/emacs.d/lisp/auto-complete/auto-complete.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/lisp/auto-complete/auto-complete.el')
-rw-r--r--emacs.d/lisp/auto-complete/auto-complete.el1138
1 files changed, 1138 insertions, 0 deletions
diff --git a/emacs.d/lisp/auto-complete/auto-complete.el b/emacs.d/lisp/auto-complete/auto-complete.el
new file mode 100644
index 0000000..cdc4e86
--- /dev/null
+++ b/emacs.d/lisp/auto-complete/auto-complete.el
@@ -0,0 +1,1138 @@
+;;; auto-complete.el --- Inline auto completion
+
+;; Copyright (C) 2008, 2009 MATSUYAMA Tomohiro
+
+;; Author: MATSUYAMA Tomohiro <t.matsuyama.pub@gmail.com>
+;; Keywords: convenience
+;; Version: 0.2.0
+
+;; 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 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This extension provides a way to complete with popup menu like:
+;;
+;; def-!-
+;; +-----------------+
+;; |defun::::::::::::|
+;; |defvar |
+;; |defmacro |
+;; | ... |
+;; +-----------------+
+;;
+;; You can complete by typing and selecting menu.
+;; Enjoy!
+
+;;; Qualification:
+;;
+;; This extension can work property on GNU Emacs 22 or higher.
+
+;;; Installation:
+;;
+;; To use this extension, locate all .el files of this package to your load-path directory.
+;;
+;; $ cp auto-complete-x.x.x/*.el ~/.emacs.d/
+;;
+;; And write following code into your .emacs.
+;;
+;; (require 'auto-complete)
+;; (global-auto-complete-mode t)
+
+;;; Tips:
+;;
+;; Use C-n/C-p to select candidates
+;; --------------------------------
+;;
+;; Add following code to your .emacs.
+;;
+;; (define-key ac-complete-mode-map "\C-n" 'ac-next)
+;; (define-key ac-complete-mode-map "\C-p" 'ac-previous)
+;;
+;;
+;; Don't start completion automatically
+;; ------------------------------------
+;;
+;; Add following code to your .emacs.
+;;
+;; (setq ac-auto-start nil)
+;; (global-set-key "\M-/" 'ac-start)
+;;
+;; or
+;;
+;; ;; start completion when entered 3 characters
+;; (setq ac-auto-start 3)
+;;
+;;
+;; Stop completion
+;; ---------------
+;;
+;; Add following code to your .emacs.
+;;
+;; (define-key ac-complete-mode-map "\M-/" 'ac-stop)
+;;
+;; Now you can stop completion by pressing M-/.
+;;
+;;
+;; Completion by TAB
+;; -----------------
+;;
+;; Add following code to your .emacs.
+;;
+;; (define-key ac-complete-mode-map "\t" 'ac-complete)
+;; (define-key ac-complete-mode-map "\r" nil)
+;;
+;;
+;; Do What I Mean mode
+;; -------------------
+;;
+;; If DWIM (Do What I Mean) mode is enabled,
+;; the following features is available:
+;;
+;; a. TAB (ac-expand) behave as completion (ac-complete)
+;; when only one candidate is left
+;; b. TAB (ac-expand) behave as completion (ac-complete)
+;; after you select candidate
+;; c. Disapear automatically when you
+;; complete a candidate.
+;;
+;; DWIM mode is enabled by default.
+;; You can enable this feature by
+;; setting `ac-dwim' to t.
+;;
+;; (setq ac-dwim t)
+;;
+;;
+;; Change default sources
+;; ----------------------
+;;
+;; (setq-default ac-sources '(ac-source-abbrev ac-source-words-in-buffer))
+;;
+;;
+;; Change sources for particular mode
+;; ----------------------------------
+;;
+;; (add-hook 'emacs-lisp-mode-hook
+;; (lambda ()
+;; (setq ac-sources '(ac-source-words-in-buffer ac-source-symbols))))
+
+;;; History:
+;;
+;; 2008-03-18
+;; * auto-complete.el 0.2.0 released
+;;
+;; 2008-03-04
+;; * fixed menu position bug
+;;
+;; 2008-03-02
+;; * made a source be able to be just a function which returns candidates
+;; * added ac-source-words-in-all-buffer
+;;
+;; 2008-03-01
+;; * added basic cache facility
+;;
+;; 2008-02-20
+;; * fixed menu position bug at long line (thanks rubikitch <rubikitch@ruby-lang.org>)
+;; * made dictionary source generator (ac-define-dictionary-source)
+;; * devided into some files (auto-complete-ruby.el, auto-complete-yasnippet.el, etc)
+;;
+;; 2008-02-19
+;; * added ac-trigger-commands switch
+;;
+;; 2008-02-10
+;; * added ac-stop function (suggestion from Andy Stewart)
+;; * added ac-override-local-map switch (suggestion from Andy Stewart)
+;;
+;; 2008-02-03
+;; * omni completion redesign
+;; * ac-sources is now buffer local for every buffer
+;; * fixed a menu position bug (thanks Andy Stewart)
+;; * fixed byte-compile warnings (thanks Andy Stewart)
+;;
+;; 2008-01-22
+;; * added face/selection-face property for sources
+;; * supported menu scroll
+;;
+;; 2008-01-20
+;; * omni completion
+;;
+;; 2008-12-24
+;; * suppress errors on command hook
+;;
+;; 2008-12-03
+;; * changed ac-dwim to nil by default
+;; * made menu to be able to adjust width
+;;
+;; 2008-12-03
+;; * renamed ac-find-function to ac-prefix-function
+;; * renamed ac-target to ac-prefix
+;;
+;; 2008-11-26
+;; * auto-complete.el 0.1.0 released
+;;
+;; 2008-11-19
+;; * thanks for Taiki SUGAWARA <buzz.taiki@gmail.com>
+;; * added source ac-source-abbrev
+;; * added source ac-source-symbols
+;; * added ac-expand-common to expand common part
+;;
+;; 2008-11-18
+;; * added ac-auto-start switch
+;; * added ac-dwim switch
+;; * changed menu popup behavior at end of window
+;; * thanks rubikitch <rubikitch@ruby-lang.org>, kazu-yamamoto.
+;; * fixed canceler bug
+;; * changed to use overriding-local-map instead of minor mode map
+;; * changed default key bindings
+;;
+;; 2008-11-16
+;; * supported candidates by using sources
+;; * added automatically start swtich
+;; * fixed some bug
+;; * added source ac-source-files-in-current-dir
+;; * added source ac-source-words-in-buffer
+;; * added source ac-source-yasnippet
+;; * renamed ac-enum-candidates-function to ac-candidate-function
+;; * renamed ac-find-target-function to ac-find-function
+;; * ac-find-function and ac-candidate-function is not buffer local variable now
+;; * made candidates visible when you are end of line
+;;
+;; 2008-11-11
+;; * by reporting from rubikitch <rubikitch@ruby-lang.org>
+;; * renamed hook name
+;; * registered backward-delete-char as special command
+;; * fixed code for creating candidates
+;; * made auto-complete disabled when isearch-mode enabled
+;; * added some major-mode into ac-modes
+;;
+;; 2008-11-09
+;; * auto-complete.el 0.0.1 released
+;; * fixed double-width character displaying problem
+;; * fixed menu position following tab character
+;; * made candidates visible when you are end of window
+
+;;; TODO:
+;;
+;; - test facility
+;; - support composed chars
+;; - fuzzy match
+;; - minibuffer completion
+;; - dictionary
+;; - documentation
+;; - performance issue (cache issue)
+;; - fix narrowing bug (reported by Yuto Hayamizu <y.hayamizu@gmail.com>)
+;; - care about undo (buffer-disable-undo)
+;; - scroll bar (visual)
+;; - show description
+;; - semantic
+;; - use cl
+;; - icon
+;; - refactoring (especially menu)
+;; - linum.el bug (reported by Andy Stewart)
+;; - flymake bug (reported by TiagoCamargo)
+
+;;; Code:
+
+
+
+(defgroup auto-complete nil
+ "Auto completion with popup menu"
+ :group 'convenience
+ :prefix "auto-complete-")
+
+(defcustom ac-candidate-menu-height 10
+ "Max height of candidate menu."
+ :type 'number
+ :group 'auto-complete)
+
+(defcustom ac-candidate-max 10
+ "Max of number of candidates."
+ :type 'number
+ :group 'auto-complete)
+
+(defcustom ac-modes
+ '(emacs-lisp-mode lisp-interaction-mode
+ c-mode cc-mode c++-mode java-mode
+ perl-mode cperl-mode python-mode ruby-mode
+ ecmascript-mode javascript-mode js2-mode php-mode css-mode
+ makefile-mode sh-mode fortran-mode f90-mode ada-mode
+ xml-mode sgml-mode)
+ "Major modes `auto-complete-mode' can run on."
+ :type '(list symbol)
+ :group 'auto-complete)
+
+(defcustom ac-trigger-commands
+ '(self-insert-command)
+ "Trigger commands that specify whether `auto-complete' should start or not."
+ :type '(list symbol)
+ :group 'auto-complete)
+
+(defcustom ac-auto-start t
+ "Non-nil means completion will be started automatically.
+Positive integer means if a length of a word you entered is larger than the value,
+completion will be started automatically.
+If you specify `nil', never be started automatically."
+ :group 'auto-complete)
+
+(defcustom ac-dwim nil
+ "Non-nil means `auto-complete' works based on Do What I Mean."
+ :type 'boolean
+ :group 'auto-complete)
+
+(defcustom ac-override-local-map nil
+ "Non-nil mean use `ac-complete-mode-map' override local map.
+Please set it to non-nil only if you faced to some problem about
+minor-mode keymap conflicts."
+ :type 'boolean
+ :group 'auto-complete)
+
+(defface ac-candidate-face
+ '((t (:background "lightgray" :foreground "black")))
+ "Face for candidate."
+ :group 'auto-complete)
+
+(defface ac-selection-face
+ '((t (:background "blue" :foreground "white")))
+ "Face for the selected candidate."
+ :group 'auto-complete)
+
+(defvar auto-complete-mode-hook nil
+ "Hook for `auto-complete-mode'.")
+
+(defvar ac-menu nil
+ "Menu instance.")
+
+(defvar ac-menu-direction 1
+ "Positive integer means `ac-menu' grows forward.
+Or, `ac-menu' grows backward.")
+
+(defvar ac-menu-offset 0
+ "Offset to contents.")
+
+(defvar ac-menu-scroll 0
+ "Scroll top of `ac-menu'.")
+
+(defvar ac-completing nil
+ "Non-nil means `auto-complete-mode' is now working on completion.")
+
+(defvar ac-saved-window-start nil
+ "Saved window start value for restore.")
+
+(defvar ac-saved-window-hscroll nil
+ "Saved window hscroll value for restore.")
+
+(defvar ac-buffer nil
+ "A buffer where auto-complete is started.")
+
+(defvar ac-point nil
+ "Start point of prefix.")
+
+(defvar ac-old-point nil
+ "Previous start point of prefix.")
+
+(defvar ac-prefix nil
+ "Prefix.")
+(defvaralias 'ac-target 'ac-prefix)
+
+(defvar ac-limit 0
+ "Limit of number of candidates.")
+
+(defvar ac-candidates nil
+ "Current candidates.")
+
+(defvar ac-selection nil
+ "Current candidate index.")
+
+(defvar ac-dwim-enable nil
+ "Non-nil means DWIM completion will be allowed.")
+
+(defvar ac-setup-function 'ac-sources-setup
+ "This function will be called when `auto-complete-mode' is enabled.")
+
+(defvar ac-prefix-function 'ac-sources-prefix
+ "When `auto-complete-mode' finds it can start completion
+or update candidates, it will call this function to find a
+start point of the prefix.
+
+If this function returns a point `auto-complete-mode'
+will set the substring between the point and current point to `ac-prefix'.
+And also it will start completion or update candidates by using
+the `ac-prefix'.
+
+If this function returns `nil', `auto-complete-mode'
+ignore starting completion or stop completing.")
+(defvaralias 'ac-find-function 'ac-prefix-function)
+
+(defvar ac-init-function 'ac-sources-init
+ "This function will be called when candidate menu is setupped.")
+
+(defvar ac-cleanup-function 'ac-sources-cleanup
+ "This function will be called when candidate menu is cleanupped")
+
+(defvar ac-candidate-function 'ac-sources-candidate
+ "This function can return candidates as list by
+using the `TARGET' that is given as a first argument.")
+
+(defvar ac-complete-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\t" 'ac-expand)
+ (define-key map "\r" 'ac-complete)
+
+ (define-key map [down] 'ac-next)
+ (define-key map [up] 'ac-previous)
+
+ map)
+ "Keymap for completion.")
+
+(defvar ac-saved-local-map nil
+ "Old keymap before `auto-complete' activated.")
+
+
+
+;;;; Auto completion
+
+(defun ac-setup-menu (point width)
+ "Setup popup menu."
+ (when ac-menu
+ ;; reposition
+ (ac-menu-delete ac-menu)
+ (setq ac-menu nil))
+ (save-excursion
+ (goto-char point)
+ (let ((column (ac-current-physical-column))
+ (line (line-number-at-pos)))
+ (setq ac-saved-window-start (window-start))
+ (setq ac-saved-window-hscroll (window-hscroll))
+ (setq ac-menu-direction
+ (if (and (> line ac-candidate-menu-height)
+ (> ac-candidate-menu-height
+ (-
+ (max 1 (- (window-height)
+ (if mode-line-format 1 0)
+ (if header-line-format 1 0)))
+ (count-lines (window-start) (point)))))
+ -1
+ 1))
+ (let ((window-width (window-width))
+ (right (- (+ column width)
+ (window-hscroll))))
+ (if (and (> right window-width)
+ (>= right width)
+ (>= column width))
+ (setq column (- column width))))
+ (if (> ac-menu-direction 0)
+ (progn
+ (forward-line)
+ (if (eq line (line-number-at-pos))
+ (newline)
+ (forward-line -1))
+ (setq ac-menu (ac-menu-create (1+ line) column width ac-candidate-menu-height))
+ (setq ac-point point))
+ (setq ac-menu (ac-menu-create (- line ac-candidate-menu-height) column width ac-candidate-menu-height))
+ (setq ac-point point)))))
+
+(defun ac-cleanup ()
+ "Destroy popup menu."
+ (ac-deactivate-mode-map)
+ (when ac-menu
+ (ac-menu-delete ac-menu)
+ (set-window-start (selected-window) ac-saved-window-start)
+ (set-window-hscroll (selected-window) ac-saved-window-hscroll))
+ (setq ac-menu nil)
+ (setq ac-menu-scroll 0)
+ (setq ac-completing nil)
+ (setq ac-point nil)
+ (setq ac-candidates nil)
+ (setq ac-selection 0)
+ (setq ac-selection-scroll-top 0)
+ (funcall ac-cleanup-function))
+
+(defun ac-activate-mode-map ()
+ "Activate `ac-complete-mode-map'."
+ (if ac-override-local-map
+ (progn
+ (setq ac-saved-local-map overriding-terminal-local-map)
+ (if (eq ac-saved-local-map ac-complete-mode-map)
+ ;; maybe never reach here
+ (setq ac-saved-local-map nil))
+ (setq overriding-terminal-local-map ac-complete-mode-map))
+ ;; rearrange ac-mode-map pair first
+ (assq-delete-all 'ac-completing minor-mode-map-alist)
+ (push (cons 'ac-completing ac-complete-mode-map) minor-mode-map-alist)))
+
+(defun ac-deactivate-mode-map ()
+ "Deactivate `ac-complete-mode-map'."
+ (when (and ac-override-local-map
+ (eq overriding-terminal-local-map ac-complete-mode-map))
+ (setq overriding-terminal-local-map ac-saved-local-map)
+ (setq ac-saved-local-map nil)))
+
+(defun ac-next ()
+ "Select next candidate."
+ (interactive)
+ (if (interactive-p)
+ (setq ac-dwim-enable t))
+ (if ac-candidates
+ (ac-select-candidate
+ (let ((selection (1+ ac-selection)))
+ (if (= selection (+ ac-menu-offset (min ac-candidate-menu-height (length ac-candidates))))
+ (if (< (+ (- ac-selection ac-menu-offset) ac-menu-scroll) (1- (length ac-candidates)))
+ (prog1 ac-selection
+ (setq ac-menu-scroll (1+ ac-menu-scroll))
+ (ac-redraw-candidates))
+ (setq ac-menu-scroll 0)
+ (ac-redraw-candidates)
+ ac-menu-offset)
+ selection)))))
+
+(defun ac-previous ()
+ "Select previous candidate."
+ (interactive)
+ (if (interactive-p)
+ (setq ac-dwim-enable t))
+ (if ac-candidates
+ (ac-select-candidate
+ (let ((selection (1- ac-selection)))
+ (if (< selection ac-menu-offset)
+ (if (= ac-menu-scroll 0)
+ (prog1 (1- (+ ac-menu-offset (min ac-candidate-menu-height (length ac-candidates))))
+ (setq ac-menu-scroll (- (length ac-candidates) (min ac-candidate-menu-height (length ac-candidates))))
+ (ac-redraw-candidates))
+ (setq ac-menu-scroll (1- ac-menu-scroll))
+ (ac-redraw-candidates)
+ ac-selection)
+ selection)))))
+
+(defun ac-expand-1 ()
+ "Try expansion."
+ (let ((string (overlay-get (ac-menu-line-overlay ac-menu ac-selection) 'real-string)))
+ (delete-region ac-point (point))
+ (insert string)
+ (setq ac-prefix string)))
+
+(defun ac-expand ()
+ "Try expansion but select next if expanded twice."
+ (interactive)
+ (if (and ac-dwim ac-dwim-enable)
+ (ac-complete)
+ (let ((target ac-prefix)
+ (string (ac-expand-1)))
+ (when (equal target string)
+ (ac-next)
+ (ac-expand-1)))))
+
+(defun ac-expand-common ()
+ "Try expansion common part."
+ (interactive)
+ (let ((common (try-completion ac-prefix ac-candidates))
+ (buffer-undo-list t))
+ (when (stringp common)
+ (delete-region ac-point (point))
+ (insert common)
+ (setq ac-prefix common))))
+
+(defun ac-complete ()
+ "Try completion."
+ (interactive)
+ (let* ((candidate (ac-get-selected-candidate))
+ (action (ac-get-candidate-action candidate)))
+ (ac-expand-1)
+ (if action
+ (funcall action))
+ (ac-abort)))
+
+(defun ac-abort ()
+ "Abort completion."
+ (ac-cleanup))
+
+(defun ac-stop ()
+ "Stop completiong."
+ (interactive)
+ (ac-abort))
+
+(defun ac-redraw-candidates ()
+ "Redraw the menu contents."
+ (let ((i ac-menu-offset))
+ ;; show line and set string to the line
+ (mapc
+ (lambda (candidate)
+ (when (< i ac-candidate-menu-height)
+ (ac-menu-show-line ac-menu i)
+ (ac-menu-set-line-string ac-menu i candidate
+ (if (= i ac-selection)
+ (or (ac-get-candidate-property 'selection-face candidate) 'ac-selection-face)
+ (or (ac-get-candidate-property 'candidate-face candidate) 'ac-candidate-face)))
+ (setq i (1+ i))))
+ (nthcdr ac-menu-scroll ac-candidates))
+ ;; ensure lines visible
+ (if (and (> ac-menu-direction 0)
+ (> i (-
+ (max 1 (- (window-height)
+ (if mode-line-format 1 0)
+ (if header-line-format 1 0)))
+ (count-lines (window-start) (point)))))
+ (recenter (- (1+ i))))
+ (if (> i ac-menu-offset)
+ (let ((window-width (window-width))
+ (right (- (+ (ac-menu-column ac-menu) (ac-menu-width ac-menu))
+ (window-hscroll))))
+ (if (> right window-width)
+ (scroll-left (- right window-width)))))
+ ;; hide remaining lines
+ (if (> ac-menu-direction 0)
+ (while (< i ac-candidate-menu-height)
+ (ac-menu-hide-line ac-menu i)
+ (setq i (1+ i)))
+ (dotimes (i ac-menu-offset)
+ (ac-menu-hide-line ac-menu i)))))
+
+(defun ac-update-candidates (candidates)
+ "Update candidates of popup menu."
+ (setq ac-menu-offset (if (> ac-menu-direction 0)
+ 0
+ (- ac-candidate-menu-height
+ (min ac-candidate-menu-height
+ (length candidates)))))
+ (setq ac-selection ac-menu-offset)
+ (setq ac-candidates candidates)
+ (setq ac-dwim-enable (= (length candidates) 1))
+ (if candidates
+ (progn
+ (setq ac-completing t)
+ (ac-activate-mode-map))
+ (setq ac-completing nil)
+ (ac-deactivate-mode-map))
+ (ac-redraw-candidates))
+
+(defun ac-get-selected-candidate ()
+ (overlay-get (ac-menu-line-overlay ac-menu ac-selection) 'real-string))
+
+(defun ac-get-candidate-action (candidate)
+ (ac-get-candidate-property 'action candidate))
+
+(defun ac-propertize-candidate (candidate &rest properties)
+ (apply 'propertize candidate properties))
+
+(defun ac-get-candidate-property (prop candidate)
+ (get-text-property 0 prop candidate))
+
+(defun ac-select-candidate (selection)
+ "Select candidate pointed by `SELECTION'."
+ (when ac-candidates
+ (let ((c1 (nth (+ (- ac-selection ac-menu-offset) ac-menu-scroll) ac-candidates))
+ (c2 (nth (+ (- selection ac-menu-offset) ac-menu-scroll) ac-candidates)))
+ (ac-menu-set-line-string ac-menu ac-selection c1
+ (or (ac-get-candidate-property 'candidate-face c1)
+ 'ac-candidate-face))
+ (ac-menu-set-line-string ac-menu selection c2
+ (or (ac-get-candidate-property 'selection-face c2)
+ 'ac-selection-face))
+ (setq ac-selection selection))))
+
+(defun ac-start ()
+ "Start completion."
+ (interactive)
+ (let* ((point (save-excursion (funcall ac-prefix-function)))
+ (reposition (not (equal ac-point point))))
+ (if (null point)
+ (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-max)
+ (if (or reposition (null ac-menu))
+ (save-excursion
+ (funcall ac-init-function)))
+ (let* ((candidates
+ (if (or ac-completing
+ (not (integerp ac-auto-start))
+ (>= (length ac-prefix) ac-auto-start))
+ (save-excursion
+ (funcall ac-candidate-function))))
+ (current-width (if ac-menu (ac-menu-width ac-menu) 0))
+ (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-menu point (* (ceiling (/ width 10.0)) 10)))
+ (if (and ac-dwim
+ (= (length candidates) 1)
+ (equal (car candidates) ac-prefix)
+ (null (ac-get-candidate-action (car candidates))))
+ (setq candidates nil))
+ (ac-update-candidates candidates)))))
+
+(defun ac-trigger-command-p ()
+ "Return non-nil if `this-command' is a trigger command."
+ (or (memq this-command ac-trigger-commands)
+ (and ac-completing
+ (memq this-command
+ '(delete-backward-char
+ backward-delete-char
+ backward-delete-char-untabify)))))
+
+(defun ac-current-physical-column ()
+ "Current physical column. (not logical column)"
+ (- (point) (save-excursion (vertical-motion 0) (point))))
+
+(defun ac-on-pre-command ()
+ (progn ; ignore-errors
+ (if (and (not (ac-trigger-command-p))
+ (or (not (symbolp this-command))
+ (not (string-match "^ac-" (symbol-name this-command)))))
+ (ac-abort))))
+
+(defun ac-on-post-command ()
+ (progn ; ignore-errors
+ (if (and (or ac-auto-start
+ ac-completing)
+ (not isearch-mode)
+ (ac-trigger-command-p))
+ (ac-start))))
+
+(defun auto-complete-mode-maybe ()
+ "What buffer `auto-complete-mode' prefers."
+ (if (and (not (minibufferp (current-buffer)))
+ (memq major-mode ac-modes))
+ (auto-complete-mode 1)))
+
+(require 'easy-mmode)
+
+(define-minor-mode auto-complete-mode
+ "AutoComplete mode"
+ :lighter " AC"
+ :group 'auto-complete
+ (if auto-complete-mode
+ (progn
+ (funcall ac-setup-function)
+ (add-hook 'post-command-hook 'ac-on-post-command nil t)
+ (add-hook 'pre-command-hook 'ac-on-pre-command nil t)
+ (run-hooks 'auto-complete-mode-hook))
+ (remove-hook 'post-command-hook 'ac-on-post-command t)
+ (remove-hook 'pre-command-hook 'ac-on-pre-command t)
+ (ac-abort)))
+
+(define-global-minor-mode global-auto-complete-mode
+ auto-complete-mode auto-complete-mode-maybe
+ :group 'auto-complete)
+
+
+
+;;;; Basic cache facility
+
+(defvar ac-clear-variables-after-save nil)
+
+(defun ac-clear-variable-after-save (variable)
+ (push variable ac-clear-variables-after-save))
+
+(defun ac-clear-variables-after-save ()
+ (dolist (variable ac-clear-variables-after-save)
+ (set variable nil)))
+
+
+
+;;;; Sources implementation
+
+(defvar ac-sources '(ac-source-words-in-buffer)
+ "Sources for completion.
+
+Source takes a form of just function which returns candidates or alist:
+
+init INIT-FUNC
+ INIT-FUNC will be called before creating candidate every time.
+
+candidates CANDIDATE-FUNC
+ CANDIDATE-FUNC will return a list of string as candidates.
+CANDIDATE-FUNC should care about `ac-limit' that is specified at limit for performance.
+
+action ACTION-FUNC
+ ACTION-FUNC will be called when `ac-complete' is called.
+
+limit LIMIT-NUM
+ A limit of candidates.
+
+requires REQUIRES-NUM
+ This source will be included when `ac-prefix' length is larger than REQUIRES-NUM.")
+(make-variable-buffer-local 'ac-sources)
+
+(defvar ac-sources-prefix-function 'ac-sources-prefix-default
+ "Default prefix function for sources.
+You should override this variable instead of ac-prefix-function.")
+
+(defvar ac-current-sources nil
+ "Current working sources.")
+
+(defvar ac-omni-completion-sources nil
+ "An alist of REGEXP and SOURCES.
+If matched regexp, switch to omni-completion mode and
+use SOURCES as `ac-sources'.")
+(make-variable-buffer-local 'ac-omni-completion-sources)
+
+(defvar ac-sources-omni-completion nil
+ "Non-nil means `auto-complete-mode' is now working on omni-completion.")
+
+(defun ac-sources-setup ()
+ "Implementation for `ac-setup-function' by sources."
+ (make-local-variable 'ac-clear-variables-after-save)
+ (add-hook 'after-save-hook 'ac-clear-variables-after-save nil t))
+
+(defun ac-sources-init ()
+ "Implementation for `ac-init-function' by sources."
+ (or ac-current-sources (setq ac-current-sources ac-sources))
+ (dolist (source ac-current-sources)
+ (let ((init-function (ac-get-source-property 'init source)))
+ (if init-function
+ (funcall init-function)))))
+
+(defun ac-sources-cleanup ()
+ "Implementation for `ac-cleanup-function' by sources."
+ (setq ac-current-sources nil)
+ (setq ac-sources-omni-completion nil))
+
+(defun ac-sources-prefix ()
+ "Implemention for `ac-prefix-function' by sources."
+ (let (point)
+ (dolist (pair ac-omni-completion-sources)
+ (when (looking-back (car pair))
+ (setq ac-current-sources (cdr pair))
+ (setq ac-sources-omni-completion t)
+ (setq ac-completing t)
+ (setq point (match-end 0))))
+ (or point
+ (if (and ac-completing ac-sources-omni-completion)
+ ac-point
+ (setq ac-current-sources ac-sources)
+ (setq ac-sources-omni-completion nil)
+ (funcall ac-sources-prefix-function)))))
+
+(defun ac-sources-prefix-default ()
+ "Default implementation for `ac-sources-prefix-function'."
+ (require 'thingatpt)
+ (car-safe (bounds-of-thing-at-point 'symbol)))
+
+(defun ac-sources-candidate ()
+ "Implementation for `ac-cadidates-function' by sources."
+ (let (candidates)
+ (dolist (source ac-current-sources)
+ (let* ((ac-limit (or (ac-get-source-property 'limit source) ac-limit))
+ (requires (ac-get-source-property 'requires source))
+ cand)
+ (when (or ac-sources-omni-completion
+ (>= (length ac-prefix)
+ (if (integerp requires)
+ requires
+ 1)))
+ (setq cand
+ (delq nil
+ (mapcar (lambda (candidate)
+ (ac-propertize-candidate candidate
+ 'action (ac-get-source-property 'action source)
+ 'face (ac-get-source-property 'candidate-face source)
+ 'candidate-face (ac-get-source-property 'candidate-face source)
+ 'selection-face (ac-get-source-property 'selection-face source)))
+ (funcall (ac-get-source-property 'candidates source))))))
+ (if (and (> ac-limit 1)
+ (> (length cand) ac-limit))
+ (setcdr (nthcdr (1- ac-limit) (copy-sequence cand)) nil))
+ (setq candidates (append candidates cand))))
+ (delete-dups candidates)))
+
+(defun ac-get-source-property (property source)
+ (if (symbolp source)
+ (setq source (symbol-value source)))
+ (if (and (functionp source)
+ (eq property 'candidates))
+ source
+ (if (consp source)
+ (assoc-default property source))))
+
+
+
+;;;; Standard sources
+
+(defun ac-candidate-words-in-buffer ()
+ "Default implemention for `ac-candidate-function'."
+ (if (> (length ac-prefix) 0)
+ (let ((i 0)
+ candidate
+ candidates
+ (regexp (concat "\\b" (regexp-quote ac-prefix) "\\(\\s_\\|\\sw\\)*\\b")))
+ (save-excursion
+ ;; search backward
+ (goto-char ac-point)
+ (while (and (< i ac-limit)
+ (re-search-backward regexp nil t))
+ (setq candidate (match-string-no-properties 0))
+ (unless (member candidate candidates)
+ (push candidate candidates)
+ (setq i (1+ i))))
+ ;; search backward
+ (goto-char (+ ac-point (length ac-prefix)))
+ (while (and (< i ac-limit)
+ (re-search-forward regexp nil t))
+ (setq candidate (match-string-no-properties 0))
+ (unless (member candidate candidates)
+ (push candidate candidates)
+ (setq i (1+ i))))
+ (nreverse candidates)))))
+
+(defvar ac-source-words-in-buffer
+ '((candidates . ac-candidate-words-in-buffer))
+ "Source for completing words in current buffer.")
+
+(defvar ac-word-index nil
+ "Word index for individual buffer.")
+
+(ac-clear-variable-after-save 'ac-word-index)
+
+(defvar ac-source-words-in-all-buffer
+ '((init
+ . (lambda ()
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (if (not (local-variable-p 'ac-word-index))
+ (make-local-variable 'ac-word-index))
+ (if (eq buffer ac-buffer)
+ (setq ac-word-index (ac-candidate-words-in-buffer))
+ (if (and (null ac-word-index)
+ (< (buffer-size) 102400))
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "\\b\\(\\s_\\|\\sw\\)+\\b" nil t)
+ (let ((candidate (match-string-no-properties 0)))
+ (if (not (member candidate ac-word-index))
+ (push candidate ac-word-index))))
+ (setq ac-word-index (nreverse ac-word-index)))))))))
+ (candidates
+ . (lambda ()
+ (let ((candidates)
+ (buffers (buffer-list)))
+ (while (and (< (length candidates) ac-limit)
+ buffers)
+ (setq candidates (append candidates (all-completions ac-prefix (buffer-local-value 'ac-word-index (car buffers)))))
+ (setq buffers (cdr buffers)))
+ candidates))))
+ "Source for completing words in all buffer.")
+
+(defvar ac-source-symbols
+ '((candidates
+ . (lambda ()
+ (all-completions ac-prefix obarray))))
+ "Source for Emacs lisp symbols.")
+
+(defvar ac-source-abbrev
+ `((candidates
+ . (lambda ()
+ (all-completions ac-prefix local-abbrev-table)))
+ (action
+ . expand-abbrev))
+ "Source for abbrev.")
+
+(defvar ac-source-files-in-current-dir
+ '((candidates
+ . (lambda ()
+ (all-completions ac-prefix (directory-files default-directory)))))
+ "Source for listing files in current directory.")
+
+(defun ac-filename-candidate ()
+ (let ((dir (file-name-directory ac-prefix)))
+ (ignore-errors
+ (delq nil
+ (mapcar (lambda (file)
+ (if (not (member file '("./" "../")))
+ (concat dir file)))
+ (file-name-all-completions
+ (file-name-nondirectory ac-prefix) dir))))))
+
+(defvar ac-source-filename
+ '((candidates . ac-filename-candidate))
+ "Source for completing file name.")
+
+(defvar ac-imenu-index nil
+ "Imenu index.")
+
+(defun ac-imenu-candidate ()
+ (require 'imenu)
+ (let ((i 0)
+ (stack ac-imenu-index)
+ candidates
+ node)
+ (while (and stack
+ (< i ac-limit))
+ (setq node (pop stack))
+ (when (consp node)
+ (let ((car (car node))
+ (cdr (cdr node)))
+ (if (consp cdr)
+ (mapc (lambda (child)
+ (push child stack))
+ cdr)
+ (when (and (stringp car)
+ (string-match (concat "^" (regexp-quote ac-prefix)) car))
+ (push car candidates)
+ (setq i (1+ i)))))))
+ (nreverse candidates)))
+
+(defvar ac-source-imenu
+ '((init
+ . (lambda ()
+ (require 'imenu)
+ (setq ac-imenu-index
+ (ignore-errors (imenu--make-index-alist)))))
+ (candidates . ac-imenu-candidate))
+ "Source for imenu.")
+
+(defmacro ac-define-dictionary-source (name list)
+ "Define dictionary source named `NAME'.
+`LIST' is a list of string.
+This is useful if you just want to define a dictionary/keywords source."
+ `(defvar ,name
+ '((candidates . (lambda () (all-completions ac-prefix ,list))))))
+
+
+
+;;;; Popup menu
+
+(defun ac-menu-line (menu)
+ "Line number of `MENU'."
+ (nth 0 menu))
+
+(defun ac-menu-column (menu)
+ "Column of `MENU'."
+ (nth 1 menu))
+
+(defun ac-menu-width (menu)
+ "Popup menu width of `MENU'."
+ (nth 2 menu))
+
+(defun ac-menu-height (menu)
+ "Popup menu height of `MENU'."
+ (nth 3 menu))
+
+(defun ac-menu-overlays (menu)
+ "Overlays that `MENU' contains."
+ (nth 4 menu))
+
+(defun ac-menu-line-overlay (menu line)
+ "Return a overlay of `MENU' at `LINE'."
+ (aref (ac-menu-overlays menu) line))
+
+(defun ac-menu-hide-line (menu line)
+ "Hide `LINE' in `MENU'."
+ (let ((overlay (ac-menu-line-overlay menu line)))
+ (overlay-put overlay 'invisible nil)
+ (overlay-put overlay 'after-string nil)))
+
+(defun ac-menu-show-line (menu line)
+ "Show `LINE' in `MENU'."
+ (let ((overlay (ac-menu-line-overlay menu line)))
+ (overlay-put overlay 'invisible t)))
+
+(defun ac-menu-set-line-string (menu line string &optional face)
+ "Set contents of `LINE' in `MENU'."
+ (let ((overlay (ac-menu-line-overlay menu line)))
+ (overlay-put overlay 'real-string string)
+ (funcall (overlay-get overlay 'set-string-function) menu overlay string face)))
+
+(defun ac-menu-create-line-string (menu string)
+ "Adjust `STRING' into `MENU'."
+ (let ((length 0)
+ (width 0)
+ (menu-width (ac-menu-width menu))
+ (chars (append string nil)))
+ (while (and
+ chars
+ (<= (setq width (+ width (char-width (car chars)))) menu-width))
+ (setq length (1+ length))
+ (setq chars (cdr chars)))
+ (if (< length (length string))
+ (setq string (substring string 0 length)))
+ (let ((string-width (string-width string)))
+ (if (< string-width menu-width)
+ (setq string (concat string
+ (make-string (- menu-width string-width) ? )))))
+ string))
+
+(defun ac-menu-hide (menu)
+ "Hide `MENU'."
+ (dotimes (i (ac-menu-height menu))
+ (ac-menu-hide-line menu i)))
+
+(defun ac-menu-last-line-of-buffer ()
+ (save-excursion
+ (not (eq (forward-line) 0))))
+
+(defun ac-menu-create (line column width height)
+ "Create popup menu."
+ (save-excursion
+ (let ((overlays (make-vector height nil))
+ (window (selected-window)))
+ (goto-line line)
+ (dotimes (i height)
+ (move-to-column column)
+ (let (overlay begin w current-column (prefix "") (postfix ""))
+ (setq current-column (current-column))
+ (cond
+ ((> current-column column)
+ (backward-char)
+ (setq current-column (current-column))
+ (if (< current-column column)
+ (setq prefix (make-string (- column current-column) ? ))))
+ ((< current-column column)
+ (setq prefix (make-string (- column current-column) ? ))))
+
+ (setq begin (point))
+ (setq w (+ width (length prefix)))
+ (while (and (not (eolp))
+ (> w 0))
+ (setq w (- w (char-width (char-after))))
+ (forward-char))
+ (if (< w 0)
+ (setq postfix (make-string (- w) ? )))
+ (if (ac-menu-last-line-of-buffer)
+ (setq postfix (concat postfix "\n")))
+
+ (setq overlay (make-overlay begin (point)))
+ (overlay-put overlay 'window window)
+ (overlay-put overlay 'prefix prefix)
+ (overlay-put overlay 'postfix postfix)
+ (overlay-put overlay 'width width)
+ (overlay-put overlay 'set-string-function
+ (lambda (menu overlay string &optional face)
+ (overlay-put overlay
+ 'after-string
+ (concat (overlay-get overlay 'prefix)
+ (propertize (ac-menu-create-line-string menu string) 'face face)
+ (overlay-get overlay 'postfix)))))
+ (aset overlays i overlay))
+ (forward-line))
+ (let ((i 100))
+ (mapc (lambda (overlay)
+ (overlay-put overlay 'priority i)
+ (setq i (1+ i)))
+ (nreverse (append overlays nil))))
+ (list line column width height overlays))))
+
+(defun ac-menu-delete (menu)
+ "Delete `MENU'."
+ (mapcar 'delete-overlay (ac-menu-overlays menu)))
+
+(provide 'auto-complete)
+;;; auto-complete.el ends here