X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/dc7d01f89b664abcbdf482b9db6e5e8a1a369e04..b7f831babd449ba7ed04f1e3a7e82ff178af2c18:/company.el diff --git a/company.el b/company.el index d22dfd556..9f13518f0 100644 --- a/company.el +++ b/company.el @@ -1,35 +1,36 @@ -;;; company.el --- extensible inline text completion mechanism -;; -;; Copyright (C) 2009-2010 Nikolaj Schumacher -;; -;; Author: Nikolaj Schumacher -;; Version: 0.5 +;;; company.el --- Modular in-buffer completion framework -*- lexical-binding: t -*- + +;; Copyright (C) 2009-2013 Free Software Foundation, Inc. + +;; Author: Nikolaj Schumacher +;; Maintainer: Dmitry Gutov +;; Version: 0.6.7 ;; Keywords: abbrev, convenience, matching -;; URL: http://nschum.de/src/emacs/company/ -;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x -;; -;; This file is NOT part of GNU Emacs. -;; -;; 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 2 -;; of the License, or (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, +;; URL: http://company-mode.github.com/ +;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . -;; +;; along with GNU Emacs. If not, see . + ;;; Commentary: ;; ;; Company is a modular completion mechanism. Modules for retrieving completion ;; candidates are called back-ends, modules for displaying them are front-ends. ;; ;; Company comes with many back-ends, e.g. `company-elisp'. These are -;; distributed in individual files and can be used individually. +;; distributed in separate files and can be used individually. ;; ;; Place company.el and the back-ends you want to use in a directory and add the ;; following to your .emacs: @@ -48,15 +49,14 @@ ;; ;; (defun company-my-backend (command &optional arg &rest ignored) ;; (case command -;; ('prefix (when (looking-back "foo\\>") -;; (match-string 0))) -;; ('candidates (list "foobar" "foobaz" "foobarbaz")) -;; ('meta (format "This value is named %s" arg)))) +;; (prefix (when (looking-back "foo\\>") +;; (match-string 0))) +;; (candidates (list "foobar" "foobaz" "foobarbaz")) +;; (meta (format "This value is named %s" arg)))) ;; -;; Sometimes it is a good idea to mix two back-ends together, for example to -;; enrich gtags with dabbrev-code results (to emulate local variables): -;; To do this, add a list with the merged back-ends as an element in -;; company-backends. +;; Sometimes it is a good idea to mix several back-ends together, for example to +;; enrich gtags with dabbrev-code results (to emulate local variables). +;; To do this, add a list with both back-ends as an element in company-backends. ;; ;; Known Issues: ;; When point is at the very end of the buffer, the pseudo-tooltip appears very @@ -65,74 +65,8 @@ ;; ;;; Change Log: ;; -;; 2010-02-24 (0.5) -;; `company-ropemacs' now provides location and docs. (Fernando H. Silva) -;; Added `company-with-candidate-inserted' macro. -;; Added `company-clang' back-end. -;; Added new mechanism for non-consecutive insertion. -;; (So far only used by clang for ObjC.) -;; The semantic back-end now shows meta information for local symbols. -;; Added compatibility for CEDET in Emacs 23.2 and from CVS. (Oleg Andreev) -;; -;; 2009-05-07 (0.4.3) -;; Added `company-other-backend'. -;; Idle completion no longer interrupts multi-key command input. -;; Added `company-ropemacs' and `company-pysmell' back-ends. -;; -;; 2009-04-25 (0.4.2) -;; In C modes . and -> now count towards `company-minimum-prefix-length'. -;; Reverted default front-end back to `company-preview-if-just-one-frontend'. -;; The pseudo tooltip will no longer be clipped at the right window edge. -;; Added `company-tooltip-minimum'. -;; Windows compatibility fixes. -;; -;; 2009-04-19 (0.4.1) -;; Added `global-company-mode'. -;; Performance enhancements. -;; Added `company-eclim' back-end. -;; Added safer workaround for Emacs `posn-col-row' bug. -;; -;; 2009-04-18 (0.4) -;; Automatic completion is now aborted if the prefix gets too short. -;; Added option `company-dabbrev-time-limit'. -;; `company-backends' now supports merging back-ends. -;; Added back-end `company-dabbrev-code' for generic code. -;; Fixed `company-begin-with'. -;; -;; 2009-04-15 (0.3.1) -;; Added 'stop prefix to prevent dabbrev from completing inside of symbols. -;; Fixed issues with tabbar-mode and line-spacing. -;; Performance enhancements. -;; -;; 2009-04-12 (0.3) -;; Added `company-begin-commands' option. -;; Added abbrev, tempo and Xcode back-ends. -;; Back-ends are now interactive. You can start them with M-x backend-name. -;; Added `company-begin-with' for starting company from elisp-code. -;; Added hooks. -;; Added `company-require-match' and `company-auto-complete' options. -;; -;; 2009-04-05 (0.2.1) -;; Improved Emacs Lisp back-end behavior for local variables. -;; Added `company-elisp-detect-function-context' option. -;; The mouse can now be used for selection. -;; -;; 2009-03-22 (0.2) -;; Added `company-show-location'. -;; Added etags back-end. -;; Added work-around for end-of-buffer bug. -;; Added `company-filter-candidates'. -;; More local Lisp variables are now included in the candidates. -;; -;; 2009-03-21 (0.1.5) -;; Fixed elisp documentation buffer always showing the same doc. -;; Added `company-echo-strip-common-frontend'. -;; Added `company-show-numbers' option and M-0 ... M-9 default bindings. -;; Don't hide the echo message if it isn't shown. -;; -;; 2009-03-20 (0.1) -;; Initial release. -;; +;; See NEWS.md in the repository. + ;;; Code: (eval-when-compile (require 'cl)) @@ -152,62 +86,64 @@ :group 'matching) (defface company-tooltip - '((t :background "yellow" - :foreground "black")) - "*Face used for the tool tip." - :group 'company) + '((default :foreground "black") + (((class color) (min-colors 88) (background light)) + (:background "cornsilk")) + (((class color) (min-colors 88) (background dark)) + (:background "yellow"))) + "Face used for the tooltip.") (defface company-tooltip-selection '((default :inherit company-tooltip) - (((class color) (min-colors 88)) (:background "orange1")) + (((class color) (min-colors 88) (background light)) + (:background "light blue")) + (((class color) (min-colors 88) (background dark)) + (:background "orange1")) (t (:background "green"))) - "*Face used for the selection in the tool tip." - :group 'company) + "Face used for the selection in the tooltip.") (defface company-tooltip-mouse '((default :inherit highlight)) - "*Face used for the tool tip item under the mouse." - :group 'company) + "Face used for the tooltip item under the mouse.") (defface company-tooltip-common - '((t :inherit company-tooltip - :foreground "red")) - "*Face used for the common completion in the tool tip." - :group 'company) + '((default :inherit company-tooltip) + (((background light)) + :foreground "darkred") + (((background dark)) + :foreground "red")) + "Face used for the common completion in the tooltip.") (defface company-tooltip-common-selection - '((t :inherit company-tooltip-selection - :foreground "red")) - "*Face used for the selected common completion in the tool tip." - :group 'company) + '((default :inherit company-tooltip-selection) + (((background light)) + :foreground "darkred") + (((background dark)) + :foreground "red")) + "Face used for the selected common completion in the tooltip.") (defface company-preview '((t :background "blue4" :foreground "wheat")) - "*Face used for the completion preview." - :group 'company) + "Face used for the completion preview.") (defface company-preview-common '((t :inherit company-preview :foreground "red")) - "*Face used for the common part of the completion preview." - :group 'company) + "Face used for the common part of the completion preview.") (defface company-preview-search '((t :inherit company-preview :background "blue1")) - "*Face used for the search string in the completion preview." - :group 'company) + "Face used for the search string in the completion preview.") (defface company-echo nil - "*Face used for completions in the echo area." - :group 'company) + "Face used for completions in the echo area.") (defface company-echo-common '((((background dark)) (:foreground "firebrick1")) (((background light)) (:background "firebrick4"))) - "*Face used for the common part of completions in the echo area." - :group 'company) + "Face used for the common part of completions in the echo area.") (defun company-frontends-set (variable value) ;; uniquify @@ -231,7 +167,7 @@ (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend company-preview-if-just-one-frontend company-echo-metadata-frontend) - "*The list of active front-ends (visualizations). + "The list of active front-ends (visualizations). Each front-end is a function that takes one argument. It is called with one of the following arguments: @@ -251,7 +187,6 @@ The visualized data is stored in `company-prefix', `company-candidates', `company-common', `company-selection', `company-point' and `company-search-string'." :set 'company-frontends-set - :group 'company :type '(repeat (choice (const :tag "echo" company-echo-frontend) (const :tag "echo, strip common" company-echo-strip-common-frontend) @@ -267,34 +202,32 @@ The visualized data is stored in `company-prefix', `company-candidates', (function :tag "custom function" nil)))) (defcustom company-tooltip-limit 10 - "*The maximum number of candidates in the tool tip" - :group 'company + "The maximum number of candidates in the tooltip" :type 'integer) (defcustom company-tooltip-minimum 6 - "*The minimum height of the tool tip. + "The minimum height of the tooltip. If this many lines are not available, prefer to display the tooltip above." - :group 'company :type 'integer) (defvar company-safe-backends '((company-abbrev . "Abbrev") - (company-clang . "clang") + (company-clang . "Clang") (company-css . "CSS") (company-dabbrev . "dabbrev for plain text") (company-dabbrev-code . "dabbrev for code") - (company-eclim . "eclim (an Eclipse interace)") + (company-eclim . "Eclim (an Eclipse interface)") (company-elisp . "Emacs Lisp") (company-etags . "etags") (company-files . "Files") (company-gtags . "GNU Global") - (company-ispell . "ispell") + (company-ispell . "Ispell") (company-keywords . "Programming language keywords") (company-nxml . "nxml") (company-oddmuse . "Oddmuse") (company-pysmell . "PySmell") (company-ropemacs . "ropemacs") - (company-semantic . "CEDET Semantic") + (company-semantic . "Semantic") (company-tempo . "Tempo templates") (company-xcode . "Xcode"))) (put 'company-safe-backends 'risky-local-variable t) @@ -307,13 +240,35 @@ If this many lines are not available, prefer to display the tooltip above." (assq backend company-safe-backends)) (return t)))))) +(defun company-capf (command &optional arg &rest args) + "`company-mode' back-end using `completion-at-point-functions'. +Requires Emacs 24.1 or newer." + (interactive (list 'interactive)) + (case command + (interactive (company-begin-backend 'company-capf)) + (prefix + (let ((res (run-hook-wrapped 'completion-at-point-functions + ;; Ignore misbehaving functions. + #'completion--capf-wrapper 'optimist))) + (when (consp res) + (if (> (nth 2 res) (point)) + 'stop + (buffer-substring-no-properties (nth 1 res) (point)))))) + (candidates + (let ((res (run-hook-wrapped 'completion-at-point-functions + ;; Ignore misbehaving functions. + #'completion--capf-wrapper 'optimist))) + (when (consp res) + (all-completions arg (nth 3 res) + (plist-get (nthcdr 4 res) :predicate))))))) + (defcustom company-backends '(company-elisp company-nxml company-css - company-eclim company-semantic company-clang + company-semantic company-clang company-eclim company-xcode company-ropemacs (company-gtags company-etags company-dabbrev-code - company-pysmell company-keywords) + company-keywords) company-oddmuse company-files company-dabbrev) - "*The list of active back-ends (completion engines). + "The list of active back-ends (completion engines). Each list elements can itself be a list of back-ends. In that case their completions are merged. Otherwise only the first matching back-end returns results. @@ -325,7 +280,7 @@ Each back-end is a function that takes a variable number of arguments. The first argument is the command requested from the back-end. It is one of the following: -'prefix: The back-end should return the text to be completed. It must be +`prefix': The back-end should return the text to be completed. It must be text immediately before `point'. Returning nil passes control to the next back-end. The function should return 'stop if it should complete but cannot \(e.g. if it is in the middle of a string\). If the returned value is only @@ -333,41 +288,48 @@ part of the prefix (e.g. the part after \"->\" in C), the back-end may return a cons of prefix and prefix length, which is then used in the `company-minimum-prefix-length' test. -'candidates: The second argument is the prefix to be completed. The +`candidates': The second argument is the prefix to be completed. The return value should be a list of candidates that start with the prefix. Optional commands: -'sorted: The back-end may return t here to indicate that the candidates +`sorted': The back-end may return t here to indicate that the candidates are sorted and will not need to be sorted again. -'duplicates: If non-nil, company will take care of removing duplicates +`duplicates': If non-nil, company will take care of removing duplicates from the list. -'no-cache: Usually company doesn't ask for candidates again as completion +`no-cache': Usually company doesn't ask for candidates again as completion progresses, unless the back-end returns t for this command. The second argument is the latest prefix. -'meta: The second argument is a completion candidate. The back-end should +`meta': The second argument is a completion candidate. The back-end should return a (short) documentation string for it. -'doc-buffer: The second argument is a completion candidate. The back-end should -create a buffer (preferably with `company-doc-buffer'), fill it with -documentation and return it. +`doc-buffer': The second argument is a completion candidate. +The back-end should create a buffer (preferably with `company-doc-buffer'), +fill it with documentation and return it. -'location: The second argument is a completion candidate. The back-end can +`location': The second argument is a completion candidate. The back-end can return the cons of buffer and buffer location, or of file and line number where the completion candidate was defined. -'require-match: If this value is t, the user is not allowed to enter anything -not offering as a candidate. Use with care! The default value nil gives the +`require-match': If this value is t, the user is not allowed to enter anything +not offered as a candidate. Use with care! The default value nil gives the user that choice with `company-require-match'. Return value 'never overrides that option the other way around. +`init': Called once for each buffer, the back-end can check for external +programs and files and load any required libraries. Raising an error here will +show up in message log once, and the backend will not be used for completion. + +`post-completion': Called after a completion candidate has been inserted into +the buffer. The second argument is the candidate. Can be used to modify it, +e.g. to expand a snippet. + The back-end should return nil for all commands it does not support or does not know about. It should also be callable interactively and use `company-begin-backend' to start itself in that case." - :group 'company :type `(repeat (choice :tag "Back-end" @@ -384,55 +346,52 @@ does not know about. It should also be callable interactively and use (put 'company-backends 'safe-local-variable 'company-safe-backends-p) (defcustom company-completion-started-hook nil - "*Hook run when company starts completing. + "Hook run when company starts completing. The hook is called with one argument that is non-nil if the completion was started manually." - :group 'company :type 'hook) (defcustom company-completion-cancelled-hook nil - "*Hook run when company cancels completing. + "Hook run when company cancels completing. The hook is called with one argument that is non-nil if the completion was aborted manually." - :group 'company :type 'hook) (defcustom company-completion-finished-hook nil - "*Hook run when company successfully completes. -The hook is called with the selected candidate as an argument." - :group 'company + "Hook run when company successfully completes. +The hook is called with the selected candidate as an argument. + +If you indend to use it to post-process candidates from a specific back-end, +consider using the `post-completion' command instead." :type 'hook) (defcustom company-minimum-prefix-length 3 - "*The minimum prefix length for automatic completion." - :group 'company + "The minimum prefix length for automatic completion." :type '(integer :tag "prefix length")) (defcustom company-require-match 'company-explicit-action-p - "*If enabled, disallow non-matching input. + "If enabled, disallow non-matching input. This can be a function do determine if a match is required. This can be overridden by the back-end, if it returns t or 'never to 'require-match. `company-auto-complete' also takes precedence over this." - :group 'company :type '(choice (const :tag "Off" nil) (function :tag "Predicate function") (const :tag "On, if user interaction took place" 'company-explicit-action-p) (const :tag "On" t))) -(defcustom company-auto-complete 'company-explicit-action-p +(defcustom company-auto-complete nil "Determines when to auto-complete. If this is enabled, all characters from `company-auto-complete-chars' complete the selected completion. This can also be a function." - :group 'company :type '(choice (const :tag "Off" nil) (function :tag "Predicate function") (const :tag "On, if user interaction took place" 'company-explicit-action-p) (const :tag "On" t))) -(defcustom company-auto-complete-chars '(?\ ?\( ?\) ?. ?\" ?$ ?\' ?< ?| ?!) +(defcustom company-auto-complete-chars '(?\ ?\) ?.) "Determines which characters trigger an automatic completion. See `company-auto-complete'. If this is a string, each string character causes completion. If it is a list of syntax description characters (see @@ -441,8 +400,7 @@ completion. If it is a list of syntax description characters (see This can also be a function, which is called with the new input and should return non-nil if company should auto-complete. -A character that is part of a valid candidate never starts auto-completion." - :group 'company +A character that is part of a valid candidate never triggers auto-completion." :type '(choice (string :tag "Characters") (set :tag "Syntax" (const :tag "Whitespace" ?\ ) @@ -462,33 +420,30 @@ A character that is part of a valid candidate never starts auto-completion." (function :tag "Predicate function"))) (defcustom company-idle-delay .7 - "*The idle delay in seconds until automatic completions starts. + "The idle delay in seconds until automatic completions starts. A value of nil means never complete automatically, t means complete immediately when a prefix of `company-minimum-prefix-length' is reached." - :group 'company :type '(choice (const :tag "never (nil)" nil) (const :tag "immediate (t)" t) (number :tag "seconds"))) (defcustom company-begin-commands t - "*A list of commands following which company will start completing. + "A list of commands following which company will start completing. If this is t, it will complete after any command. See `company-idle-delay'. Alternatively any command with a non-nil 'company-begin property is treated as if it was on this list." - :group 'company :type '(choice (const :tag "Any command" t) (const :tag "Self insert command" '(self-insert-command)) (repeat :tag "Commands" function))) (defcustom company-show-numbers nil - "*If enabled, show quick-access numbers for the first ten candidates." - :group 'company + "If enabled, show quick-access numbers for the first ten candidates." :type '(choice (const :tag "off" nil) (const :tag "on" t))) (defvar company-end-of-buffer-workaround t - "*Work around a visualization bug when completing at the end of the buffer. + "Work around a visualization bug when completing at the end of the buffer. The work-around consists of adding a newline.") ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -502,16 +457,18 @@ The work-around consists of adding a newline.") (define-key keymap "\C-g" 'company-abort) (define-key keymap (kbd "M-n") 'company-select-next) (define-key keymap (kbd "M-p") 'company-select-previous) - (define-key keymap (kbd "") 'company-select-next) - (define-key keymap (kbd "") 'company-select-previous) + (define-key keymap (kbd "") 'company-select-next-or-abort) + (define-key keymap (kbd "") 'company-select-previous-or-abort) (define-key keymap [down-mouse-1] 'ignore) (define-key keymap [down-mouse-3] 'ignore) (define-key keymap [mouse-1] 'company-complete-mouse) (define-key keymap [mouse-3] 'company-select-mouse) (define-key keymap [up-mouse-1] 'ignore) (define-key keymap [up-mouse-3] 'ignore) - (define-key keymap "\C-m" 'company-complete-selection) - (define-key keymap "\t" 'company-complete-common) + (define-key keymap [return] 'company-complete-selection) + (define-key keymap (kbd "RET") 'company-complete-selection) + (define-key keymap [tab] 'company-complete-common) + (define-key keymap (kbd "TAB") 'company-complete-common) (define-key keymap (kbd "") 'company-show-doc-buffer) (define-key keymap "\C-w" 'company-show-location) (define-key keymap "\C-s" 'company-search-candidates) @@ -541,7 +498,7 @@ The work-around consists of adding a newline.") (unless (memq backend company--disabled-backends) (message "Company back-end '%s' could not be initialized:\n%s" backend (error-message-string err))) - (push backend company--disabled-backends) + (pushnew backend company--disabled-backends) nil)) (mapc 'company-init-backend backend))) @@ -552,7 +509,7 @@ The work-around consists of adding a newline.") ;;;###autoload (define-minor-mode company-mode - "\"complete anything\"; in in-buffer completion framework. + "\"complete anything\"; is an in-buffer completion framework. Completion starts automatically, depending on the values `company-idle-delay' and `company-minimum-prefix-length'. @@ -586,8 +543,12 @@ keymap during active completions (`company-active-map'): (company-cancel) (kill-local-variable 'company-point))) -(define-globalized-minor-mode global-company-mode company-mode - (lambda () (company-mode 1))) +;;;###autoload +(define-globalized-minor-mode global-company-mode company-mode company-mode-on) + +(defun company-mode-on () + (unless (or noninteractive (eq (aref (buffer-name) 0) ?\s)) + (company-mode 1))) (defsubst company-assert-enabled () (unless company-mode @@ -596,31 +557,28 @@ keymap during active completions (`company-active-map'): ;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defvar company-overriding-keymap-bound nil) -(make-variable-buffer-local 'company-overriding-keymap-bound) - -(defvar company-old-keymap nil) -(make-variable-buffer-local 'company-old-keymap) - (defvar company-my-keymap nil) (make-variable-buffer-local 'company-my-keymap) +(defvar company-emulation-alist '((t . nil))) + (defsubst company-enable-overriding-keymap (keymap) - (setq company-my-keymap keymap) - (when company-overriding-keymap-bound - (company-uninstall-map))) + (company-uninstall-map) + (setq company-my-keymap keymap)) + +(defun company-ensure-emulation-alist () + (unless (eq 'company-emulation-alist (car emulation-mode-map-alists)) + (setq emulation-mode-map-alists + (cons 'company-emulation-alist + (delq 'company-emulation-alist emulation-mode-map-alists))))) (defun company-install-map () - (unless (or company-overriding-keymap-bound + (unless (or (cdar company-emulation-alist) (null company-my-keymap)) - (setq company-old-keymap overriding-terminal-local-map - overriding-terminal-local-map company-my-keymap - company-overriding-keymap-bound t))) + (setf (cdar company-emulation-alist) company-my-keymap))) (defun company-uninstall-map () - (when (eq overriding-terminal-local-map company-my-keymap) - (setq overriding-terminal-local-map company-old-keymap - company-overriding-keymap-bound nil))) + (setf (cdar company-emulation-alist) nil)) ;; Hack: ;; Emacs calculates the active keymaps before reading the event. That means we @@ -693,17 +651,23 @@ keymap during active completions (`company-active-map'): (apply 'company--multi-backend-adapter company-backend args))) (defun company--multi-backend-adapter (backends command &rest args) - (case command - ('candidates - (apply 'append (mapcar (lambda (backend) (apply backend command args)) - backends))) - ('sorted nil) - ('duplicates t) - (otherwise - (let (value) - (dolist (backend backends) - (when (setq value (apply backend command args)) - (return value))))))) + (let ((backends (loop for b in backends + when (not (and (symbolp b) + (eq 'failed (get b 'company-init)))) + collect b))) + (case command + (candidates + (loop for backend in backends + when (equal (funcall backend 'prefix) + (car args)) + append (apply backend 'candidates args))) + (sorted nil) + (duplicates t) + (otherwise + (let (value) + (dolist (backend backends) + (when (setq value (apply backend command args)) + (return value)))))))) ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -738,6 +702,10 @@ keymap during active completions (`company-active-map'): "Non-nil, if explicit completion took place.") (make-variable-buffer-local 'company--explicit-action) +(defvar company--auto-completion nil + "Non-nil when current candidate is being completed automatically. +Controlled by `company-auto-complete'.") + (defvar company--point-max nil) (make-variable-buffer-local 'company--point-max) @@ -777,7 +745,8 @@ can retrieve meta-data for them." (defun company--should-complete () (and (not (or buffer-read-only overriding-terminal-local-map - overriding-local-map)) + overriding-local-map + (minibufferp))) ;; Check if in the middle of entering a key combination. (or (equal (this-command-keys-vector) []) (not (keymapp (key-binding (this-command-keys-vector))))) @@ -828,16 +797,22 @@ can retrieve meta-data for them." (push (cons company-prefix company-candidates) company-candidates-cache) ;; Calculate common. (let ((completion-ignore-case (company-call-backend 'ignore-case))) - (setq company-common (try-completion company-prefix company-candidates))) + (setq company-common (company--safe-candidate + (try-completion company-prefix company-candidates)))) (when (eq company-common t) (setq company-candidates nil))) +(defun company--safe-candidate (str) + (or (company-call-backend 'crop str) + str)) + (defun company-calculate-candidates (prefix) - (let ((candidates (cdr (assoc prefix company-candidates-cache)))) + (let ((candidates (cdr (assoc prefix company-candidates-cache))) + (ignore-case (company-call-backend 'ignore-case))) (or candidates (when company-candidates-cache (let ((len (length prefix)) - (completion-ignore-case (company-call-backend 'ignore-case)) + (completion-ignore-case ignore-case) prev) (dotimes (i (1+ len)) (when (setq prev (cdr (assoc (substring prefix 0 (- len i)) @@ -859,12 +834,13 @@ can retrieve meta-data for them." (while c2 (setcdr c2 (progn (while (equal (pop c2) (car c2))) c2))))))) - (if (or (cdr candidates) - (not (equal (car candidates) prefix))) - ;; Don't start when already completed and unique. - candidates - ;; Not the right place? maybe when setting? - (and company-candidates t)))) + (when candidates + (if (or (cdr candidates) + (not (eq t (compare-strings (car candidates) nil nil + prefix nil nil ignore-case)))) + candidates + ;; Already completed and unique; don't start. + t)))) (defun company-idle-begin (buf win tick pos) (and company-mode @@ -895,7 +871,10 @@ can retrieve meta-data for them." (defun company-manual-begin () (interactive) (setq company--explicit-action t) - (company-auto-begin)) + (unwind-protect + (company-auto-begin) + (unless company-candidates + (setq company--explicit-action nil)))) (defun company-other-backend (&optional backward) (interactive (list current-prefix-arg)) @@ -922,10 +901,6 @@ can retrieve meta-data for them." (eq company-require-match t)) (not (eq backend-value 'never)))))) -(defun company-punctuation-p (input) - "Return non-nil, if input starts with punctuation or parentheses." - (memq (char-syntax (string-to-char input)) '(?. ?\( ?\)))) - (defun company-auto-complete-p (input) "Return non-nil, if input starts with punctuation or parentheses." (and (if (functionp company-auto-complete) @@ -958,7 +933,8 @@ can retrieve meta-data for them." ;; auto-complete (save-excursion (goto-char company-point) - (company-complete-selection) + (let ((company--auto-completion t)) + (company-complete-selection)) nil)) ((and (company--string-incremental-p company-prefix new-prefix) (company-require-match-p)) @@ -974,8 +950,9 @@ can retrieve meta-data for them." (defun company--good-prefix-p (prefix) (and (or (company-explicit-action-p) - (>= (or (cdr-safe prefix) (length prefix)) - company-minimum-prefix-length)) + (unless (eq prefix 'stop) + (>= (or (cdr-safe prefix) (length prefix)) + company-minimum-prefix-length))) (stringp (or (car-safe prefix) prefix)))) (defun company--continue () @@ -1036,15 +1013,15 @@ can retrieve meta-data for them." (return c))))) (defun company-begin () - (setq company-candidates - (or (and company-candidates (company--continue)) - (and (company--should-complete) (company--begin-new)))) + (or (and company-candidates (company--continue)) + (and (company--should-complete) (company--begin-new))) (when company-candidates (when (and company-end-of-buffer-workaround (eobp)) (save-excursion (insert "\n")) (setq company-added-newline (buffer-chars-modified-tick))) (setq company-point (point) company--point-max (point-max)) + (company-ensure-emulation-alist) (company-enable-overriding-keymap company-active-map) (company-call-frontends 'update))) @@ -1229,9 +1206,7 @@ can retrieve meta-data for them." (interactive) (company-search-assert-enabled) (company-search-mode 0) - (when last-input-event - (clear-this-command-keys t) - (setq unread-command-events (list last-input-event)))) + (company--unread-last-input)) (defvar company-search-map (let ((i 0) @@ -1240,7 +1215,7 @@ can retrieve meta-data for them." (set-char-table-range (nth 1 keymap) (cons #x100 (max-char)) 'company-search-printing-char) (with-no-warnings - ;; obselete in Emacs 23 + ;; obsolete in Emacs 23 (let ((l (generic-character-list)) (table (nth 1 keymap))) (while l @@ -1335,6 +1310,24 @@ followed by `company-search-kill-others' after each input." (when (company-manual-begin) (company-set-selection (1- company-selection)))) +(defun company-select-next-or-abort () + "Select the next candidate if more than one, else abort +and invoke the normal binding." + (interactive) + (if (> company-candidates-length 1) + (company-select-next) + (company-abort) + (company--unread-last-input))) + +(defun company-select-previous-or-abort () + "Select the previous candidate if more than one, else abort +and invoke the normal binding." + (interactive) + (if (> company-candidates-length 1) + (company-select-previous) + (company-abort) + (company--unread-last-input))) + (defun company-select-mouse (event) "Select the candidate picked by the mouse." (interactive "e") @@ -1354,7 +1347,10 @@ followed by `company-search-kill-others' after each input." "Complete the selected candidate." (interactive) (when (company-manual-begin) - (company-finish (nth company-selection company-candidates)))) + (let ((result (nth company-selection company-candidates))) + (when company--auto-completion + (setq result (company--safe-candidate result))) + (company-finish result)))) (defun company-complete-common () "Complete the common part of all candidates." @@ -1403,13 +1399,20 @@ To show the number next to the candidates in some back-ends, enable (make-string len ?\ ))) (defsubst company-safe-substring (str from &optional to) - (let ((len (length str))) - (if (> from len) - "" - (if (and to (> to len)) - (concat (substring str from) - (company-space-string (- to len))) - (substring str from to))))) + (if (> from (string-width str)) + "" + (with-temp-buffer + (insert str) + (move-to-column from) + (let ((beg (point))) + (if to + (progn + (move-to-column to) + (concat (buffer-substring beg (point)) + (let ((padding (- to (current-column)))) + (when (> padding 0) + (company-space-string padding))))) + (buffer-substring beg (point-max))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1446,9 +1449,12 @@ To show the number next to the candidates in some back-ends, enable (while (memq (setq cmd (key-binding (vector (list (read-event))))) company--electric-commands) (call-interactively cmd)) - (when last-input-event - (clear-this-command-keys t) - (setq unread-command-events (list last-input-event))))))) + (company--unread-last-input))))) + +(defun company--unread-last-input () + (when last-input-event + (clear-this-command-keys t) + (setq unread-command-events (list last-input-event)))) (defun company-show-doc-buffer () "Temporarily show a buffer with the complete documentation for the selection." @@ -1510,7 +1516,9 @@ To show the number next to the candidates in some back-ends, enable (setq company-backend backend) ;; Return non-nil if active. (or (company-manual-begin) - (error "Cannot complete at point"))) + (progn + (setq company-backend nil) + (error "Cannot complete at point")))) (defun company-begin-with (candidates &optional prefix-length require-match callback) @@ -1613,9 +1621,8 @@ Example: (defun company-buffer-lines (beg end) (goto-char beg) - (let ((row (company--row)) - lines) - (while (and (equal (move-to-window-line (incf row)) row) + (let (lines) + (while (and (= 1 (vertical-motion 1)) (<= (point) end)) (push (buffer-substring beg (min end (1- (point)))) lines) (setq beg (point))) @@ -1650,9 +1657,12 @@ Example: ;; Append whole new lines. (while lines (push (concat (company-space-string column) (pop lines)) new)) - (concat (when nl "\n") - (mapconcat 'identity (nreverse new) "\n") - "\n"))) + + (let ((str (concat (when nl "\n") + (mapconcat 'identity (nreverse new) "\n") + "\n"))) + (font-lock-append-text-property 0 (length str) 'face 'default str) + str))) (defun company--create-lines (selection limit) @@ -1724,7 +1734,7 @@ Example: (defsubst company--pseudo-tooltip-height () "Calculate the appropriate tooltip height. Returns a negative number if the tooltip should be displayed above point." - (let* ((lines (count-lines (window-start) (point-at-bol))) + (let* ((lines (company--row)) (below (- (company--window-inner-height) 1 lines))) (if (and (< below (min company-tooltip-minimum company-candidates-length)) (> lines below)) @@ -1762,8 +1772,7 @@ Returns a negative number if the tooltip should be displayed above point." args)) (overlay-put ov 'company-column column) - (overlay-put ov 'company-height (abs height)) - (overlay-put ov 'window (selected-window)))))) + (overlay-put ov 'company-height height))))) (defun company-pseudo-tooltip-show-at-point (pos) (let ((col-row (company--col-row pos))) @@ -1776,7 +1785,7 @@ Returns a negative number if the tooltip should be displayed above point." (height (overlay-get company-pseudo-tooltip-overlay 'company-height))) (overlay-put company-pseudo-tooltip-overlay 'company-before (apply 'company--replacement-string - (company--create-lines selection height) + (company--create-lines selection (abs height)) (overlay-get company-pseudo-tooltip-overlay 'company-replacement-args))))) @@ -1797,27 +1806,36 @@ Returns a negative number if the tooltip should be displayed above point." (overlay-get company-pseudo-tooltip-overlay 'company-before)) (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))) +(defun company-pseudo-tooltip-guard () + (buffer-substring-no-properties + (point) (overlay-start company-pseudo-tooltip-overlay))) + (defun company-pseudo-tooltip-frontend (command) - "A `company-mode' front-end similar to a tool-tip but based on overlays." + "`company-mode' front-end similar to a tooltip but based on overlays." (case command - ('pre-command (company-pseudo-tooltip-hide-temporarily)) - ('post-command + (pre-command (company-pseudo-tooltip-hide-temporarily)) + (post-command (let ((old-height (if (overlayp company-pseudo-tooltip-overlay) (overlay-get company-pseudo-tooltip-overlay 'company-height) 0)) (new-height (company--pseudo-tooltip-height))) (unless (and (>= (* old-height new-height) 0) - (>= (abs old-height) (abs new-height))) + (>= (abs old-height) (abs new-height)) + (equal (company-pseudo-tooltip-guard) + (overlay-get company-pseudo-tooltip-overlay + 'company-guard))) ;; Redraw needed. (company-pseudo-tooltip-show-at-point (- (point) - (length company-prefix))))) + (length company-prefix))) + (overlay-put company-pseudo-tooltip-overlay + 'company-guard (company-pseudo-tooltip-guard)))) (company-pseudo-tooltip-unhide)) - ('hide (company-pseudo-tooltip-hide) - (setq company-tooltip-offset 0)) - ('update (when (overlayp company-pseudo-tooltip-overlay) - (company-pseudo-tooltip-edit company-candidates - company-selection))))) + (hide (company-pseudo-tooltip-hide) + (setq company-tooltip-offset 0)) + (update (when (overlayp company-pseudo-tooltip-overlay) + (company-pseudo-tooltip-edit company-candidates + company-selection))))) (defun company-pseudo-tooltip-unless-just-one-frontend (command) "`company-pseudo-tooltip-frontend', but not shown for single candidates." @@ -1863,11 +1881,11 @@ Returns a negative number if the tooltip should be displayed above point." (setq company-preview-overlay nil))) (defun company-preview-frontend (command) - "A `company-mode' front-end showing the selection as if it had been inserted." + "`company-mode' front-end showing the selection as if it had been inserted." (case command - ('pre-command (company-preview-hide)) - ('post-command (company-preview-show-at-point (point))) - ('hide (company-preview-hide)))) + (pre-command (company-preview-hide)) + (post-command (company-preview-show-at-point (point))) + (hide (company-preview-hide)))) (defun company-preview-if-just-one-frontend (command) "`company-preview-frontend', but only shown for single candidates." @@ -1895,8 +1913,16 @@ Returns a negative number if the tooltip should be displayed above point." (defsubst company-echo-show-soon (&optional getter) (when company-echo-timer (cancel-timer company-echo-timer)) - (setq company-echo-timer (run-with-timer company-echo-delay nil - 'company-echo-show getter))) + (setq company-echo-timer (run-with-timer 0 nil 'company-echo-show getter))) + +(defsubst company-echo-show-when-idle (&optional getter) + (when (sit-for .01) + (company-echo-show getter))) + +(defsubst company-echo-show-when-not-busy (&optional getter) + "Run `company-echo-show' with arg GETTER once Emacs isn't busy." + (when (sit-for company-echo-delay) + (company-echo-show getter))) (defun company-echo-format () @@ -1954,36 +1980,27 @@ Returns a negative number if the tooltip should be displayed above point." "}"))) (defun company-echo-hide () - (when company-echo-timer - (cancel-timer company-echo-timer)) (unless (equal company-echo-last-msg "") (setq company-echo-last-msg "") (company-echo-show))) (defun company-echo-frontend (command) - "A `company-mode' front-end showing the candidates in the echo area." + "`company-mode' front-end showing the candidates in the echo area." (case command - ('pre-command (company-echo-show-soon)) - ('post-command (company-echo-show-soon 'company-echo-format)) - ('hide (company-echo-hide)))) + (post-command (company-echo-show-soon 'company-echo-format)) + (hide (company-echo-hide)))) (defun company-echo-strip-common-frontend (command) - "A `company-mode' front-end showing the candidates in the echo area." + "`company-mode' front-end showing the candidates in the echo area." (case command - ('pre-command (company-echo-show-soon)) - ('post-command (company-echo-show-soon 'company-echo-strip-common-format)) - ('hide (company-echo-hide)))) + (post-command (company-echo-show-soon 'company-echo-strip-common-format)) + (hide (company-echo-hide)))) (defun company-echo-metadata-frontend (command) - "A `company-mode' front-end showing the documentation in the echo area." + "`company-mode' front-end showing the documentation in the echo area." (case command - ('pre-command (company-echo-show-soon)) - ('post-command (company-echo-show-soon 'company-fetch-metadata)) - ('hide (company-echo-hide)))) - -;; templates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(autoload 'company-template-declare-template "company-template") + (post-command (company-echo-show-when-idle 'company-fetch-metadata)) + (hide (company-echo-hide)))) (provide 'company) ;;; company.el ends here