summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Bremner <bremner@debian.org>2019-01-24 07:31:02 -0400
committerDavid Bremner <bremner@debian.org>2019-01-24 07:31:02 -0400
commit51d123d5673d63849a45e6f6d18025aab7f9a834 (patch)
tree00e9211af546362877ede5d965f4f602b6f97381
parent1154b1a5b5189d5975b9e3155aa804e116733c74 (diff)
parentac82e875e144b227e926c09c53def9b0c059115c (diff)
Merge tag '0.9.9'
-rw-r--r--.travis.yml37
-rw-r--r--NEWS.md32
-rw-r--r--company-capf.el114
-rw-r--r--company-clang.el14
-rw-r--r--company-cmake.el12
-rw-r--r--company-css.el10
-rw-r--r--company-gtags.el8
-rw-r--r--company-ispell.el2
-rw-r--r--company-keywords.el38
-rw-r--r--company-nxml.el3
-rw-r--r--company-tng.el13
-rw-r--r--company.el108
-rw-r--r--test/all.el4
-rw-r--r--test/capf-tests.el140
-rw-r--r--test/cmake-tests.el44
15 files changed, 449 insertions, 130 deletions
diff --git a/.travis.yml b/.travis.yml
index b8eb249..03933bf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,26 +1,23 @@
-sudo: false
-
language: generic
-matrix:
- include:
- - env: EMACS=emacs24
- addons:
- apt:
- sources: [ { sourceline: 'ppa:cassou/emacs' } ]
- packages: [ emacs24, emacs24-el ]
- - env: EMACS=emacs25
- addons:
- apt:
- sources: [ { sourceline: 'ppa:kelleyk/emacs' } ]
- packages: [ emacs25 ]
- - env: EMACS=emacs-snapshot
- addons:
- apt:
- sources: [ { sourceline: 'ppa:ubuntu-elisp/ppa' } ]
- packages: [ emacs-snapshot ]
+sudo: false
+
+env:
+ global:
+ - CURL="curl -fsSkL --retry 9 --retry-delay 9"
+ matrix:
+ - EMACS_VERSION=24.5
+ - EMACS_VERSION=25.3
+ - EMACS_VERSION=26.1
+ - EMACS_VERSION=master
+ allow_failures:
+ - env: EMACS_VERSION=master
-install: true
+install:
+ - $CURL -O https://github.com/npostavs/emacs-travis/releases/download/bins/emacs-bin-${EMACS_VERSION}.tar.gz
+ - tar -xaf emacs-bin-${EMACS_VERSION}.tar.gz -C /
+ - export EMACS=/tmp/emacs/bin/emacs
+ - $EMACS --version
script:
make test-batch EMACS=${EMACS}
diff --git a/NEWS.md b/NEWS.md
index 520766f..72f86d7 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,37 @@
# History of user-visible changes
+## 2018-12-13 (0.9.9)
+
+* Fix for the changes in the previous release.
+* New hook `company-after-completion-hook`.
+* `company-clang` removes identity preprocessor #defines from completions
+ ([#841](https://github.com/company-mode/company-mode/issues/841)).
+
+## 2018-12-08 (0.9.8)
+
+* CAPF backend fixed to use the right `:exit-function`. It can now safely be a
+ closure with lexical context capturing the buffer state at the moment when the
+ completion table was returned
+ ([#845](https://github.com/company-mode/company-mode/pull/845)).
+
+## 2018-11-06 (0.9.7)
+
+* For more sophisticated highlighting in non-prefix completion, a backend may
+ now respond to a `match` request with a list of regions. See
+ `company-backends`.
+ ([#798](https://github.com/company-mode/company-mode/issues/798),
+ [#762](https://github.com/company-mode/company-mode/issues/762))
+* The `company-capf` backend will pick up on a `:company-match` metadata element
+ on the capf function (similar to `:company-location` or `:company-doc-buffer`)
+ and use it as a response to aforementioned `match` request.
+* `company-cmake` supports completion inside string interpolations
+ ([#714](https://github.com/company-mode/company-mode/pull/714)).
+* Workaround for the conflict between `inferior-python-mode`'s completion code
+ and `company-sort-by-occurrence`.
+* In Emacs 26 and newer, `company-css` is removed from `company-backends`.
+ `company-capf` is used instead.
+* Same for `company-nxml`.
+
## 2018-02-23 (0.9.6)
* Workaround for Emacs' ([bug#23980](https://debbugs.gnu.org/23980)) triggered
diff --git a/company-capf.el b/company-capf.el
index 06384c7..64b3de9 100644
--- a/company-capf.el
+++ b/company-capf.el
@@ -1,6 +1,6 @@
;;; company-capf.el --- company-mode completion-at-point-functions backend -*- lexical-binding: t -*-
-;; Copyright (C) 2013-2017 Free Software Foundation, Inc.
+;; Copyright (C) 2013-2018 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
@@ -24,7 +24,8 @@
;;
;; The CAPF back-end provides a bridge to the standard
;; completion-at-point-functions facility, and thus can support any major mode
-;; that defines a proper completion function, including emacs-lisp-mode.
+;; that defines a proper completion function, including emacs-lisp-mode,
+;; css-mode and nxml-mode.
;;; Code:
@@ -33,6 +34,13 @@
(defvar company--capf-cache nil)
+;; FIXME: Provide a way to save this info once in Company itself
+;; (https://github.com/company-mode/company-mode/pull/845).
+(defvar-local company-capf--current-completion-data nil
+ "Value last returned by `company-capf' when called with `candidates'.
+For most properties/actions, this is just what we need: the exact values
+that accompanied the completion table that's currently is use.")
+
(defun company--capf-data ()
(let ((cache company--capf-cache))
(if (and (equal (current-buffer) (car cache))
@@ -67,6 +75,14 @@
completion-at-point-functions
(remq 'python-completion-complete-at-point completion-at-point-functions)))
+(defun company-capf--save-current-data (data)
+ (setq company-capf--current-completion-data data)
+ (add-hook 'company-after-completion-hook
+ #'company-capf--clear-current-data nil t))
+
+(defun company-capf--clear-current-data (_ignored)
+ (setq company-capf--current-completion-data nil))
+
(defun company-capf (command &optional arg &rest _args)
"`company-mode' backend using `completion-at-point-functions'."
(interactive (list 'interactive))
@@ -83,12 +99,13 @@
(t prefix))))))
(`candidates
(let ((res (company--capf-data)))
+ (company-capf--save-current-data res)
(when res
(let* ((table (nth 3 res))
(pred (plist-get (nthcdr 4 res) :predicate))
(meta (completion-metadata
- (buffer-substring (nth 1 res) (nth 2 res))
- table pred))
+ (buffer-substring (nth 1 res) (nth 2 res))
+ table pred))
(sortfun (cdr (assq 'display-sort-function meta)))
(candidates (completion-all-completions arg table pred (length arg)))
(last (last candidates))
@@ -104,67 +121,78 @@
candidates))
candidates)))))
(`sorted
- (let ((res (company--capf-data)))
+ (let ((res company-capf--current-completion-data))
(when res
(let ((meta (completion-metadata
(buffer-substring (nth 1 res) (nth 2 res))
(nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
(cdr (assq 'display-sort-function meta))))))
(`match
- ;; Can't just use 0 when base-size (see above) is non-zero.
- (let ((start (if (get-text-property 0 'face arg)
- 0
- (next-single-property-change 0 'face arg))))
- (when start
- ;; completions-common-part comes first, but we can't just look for this
- ;; value because it can be in a list.
- (or
- (let ((value (get-text-property start 'face arg)))
- (text-property-not-all start (length arg)
- 'face value arg))
- (length arg)))))
+ ;; Ask the for the `:company-match' function. If that doesn't help,
+ ;; fallback to sniffing for face changes to get a suitable value.
+ (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
+ :company-match)))
+ (if f (funcall f arg)
+ (let* ((match-start nil) (pos -1)
+ (prop-value nil) (faces nil)
+ (has-face-p nil) chunks
+ (limit (length arg)))
+ (while (< pos limit)
+ (setq pos
+ (if (< pos 0) 0 (next-property-change pos arg limit)))
+ (setq prop-value (or
+ (get-text-property pos 'face arg)
+ (get-text-property pos 'font-lock-face arg))
+ faces (if (listp prop-value) prop-value (list prop-value))
+ has-face-p (memq 'completions-common-part faces))
+ (cond ((and (not match-start) has-face-p)
+ (setq match-start pos))
+ ((and match-start (not has-face-p))
+ (push (cons match-start pos) chunks)
+ (setq match-start nil))))
+ (nreverse chunks)))))
(`duplicates t)
(`no-cache t) ;Not much can be done here, as long as we handle
;non-prefix matches.
(`meta
- (let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-docsig)))
+ (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
+ :company-docsig)))
(when f (funcall f arg))))
(`doc-buffer
- (let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-doc-buffer)))
+ (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
+ :company-doc-buffer)))
(when f (funcall f arg))))
(`location
- (let ((f (plist-get (nthcdr 4 (company--capf-data)) :company-location)))
+ (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
+ :company-location)))
(when f (funcall f arg))))
(`annotation
- (save-excursion
- ;; FIXME: `company-begin' sets `company-point' after calling
- ;; `company--begin-new'. We shouldn't rely on `company-point' here,
- ;; better to cache the capf-data value instead. However: we can't just
- ;; save the last capf-data value in `prefix', because that command can
- ;; get called more often than `candidates', and at any point in the
- ;; buffer (https://github.com/company-mode/company-mode/issues/153).
- ;; We could try propertizing the returned prefix string, but it's not
- ;; passed to `annotation', and `company-prefix' is set only after
- ;; `company--strip-duplicates' is called.
- (when company-point
- (goto-char company-point))
- (let ((f (plist-get (nthcdr 4 (company--capf-data)) :annotation-function)))
- (when f (funcall f arg)))))
+ (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
+ :annotation-function)))
+ (when f (funcall f arg))))
(`require-match
(plist-get (nthcdr 4 (company--capf-data)) :company-require-match))
(`init nil) ;Don't bother: plenty of other ways to initialize the code.
(`post-completion
- (let* ((res (company--capf-data))
- (exit-function (plist-get (nthcdr 4 res) :exit-function))
- (table (nth 3 res))
- (pred (plist-get (nthcdr 4 res) :predicate)))
- (if exit-function
- ;; Follow the example of `completion--done'.
- (funcall exit-function arg
- (if (eq (try-completion arg table pred) t)
- 'finished 'sole)))))
+ (company--capf-post-completion arg))
))
+(defun company--capf-post-completion (arg)
+ (let* ((res company-capf--current-completion-data)
+ (exit-function (plist-get (nthcdr 4 res) :exit-function))
+ (table (nth 3 res))
+ (pred (plist-get (nthcdr 4 res) :predicate)))
+ (if exit-function
+ ;; Follow the example of `completion--done'.
+ (funcall exit-function arg
+ ;; FIXME: Should probably use an additional heuristic:
+ ;; completion-at-point doesn't know when the user picked a
+ ;; particular candidate explicitly (it only checks whether
+ ;; futher completions exist). Whereas company user can press
+ ;; RET (or use implicit completion with company-tng).
+ (if (eq (try-completion arg table pred) t)
+ 'finished 'sole)))))
+
(provide 'company-capf)
;;; company-capf.el ends here
diff --git a/company-clang.el b/company-clang.el
index 90a372e..d43eebb 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -134,11 +134,12 @@ or automatically through a custom `company-clang-prefix-guesser'."
(when (string-match ":" match)
(setq match (substring match 0 (match-beginning 0)))))
(let ((meta (match-string-no-properties 2)))
- (when (and meta (not (string= match meta)))
- (put-text-property 0 1 'meta
- (company-clang--strip-formatting meta)
- match)))
- (push match lines)))
+ (unless (equal match meta)
+ (when meta
+ (put-text-property 0 1 'meta
+ (company-clang--strip-formatting meta)
+ match))
+ (push match lines)))))
lines))
(defun company-clang--meta (candidate)
@@ -183,11 +184,12 @@ or automatically through a custom `company-clang-prefix-guesser'."
(let* ((buf (get-buffer-create company-clang--error-buffer-name))
(cmd (concat company-clang-executable " " (mapconcat 'identity args " ")))
(pattern (format company-clang--completion-pattern ""))
+ (message-truncate-lines t)
(err (if (re-search-forward pattern nil t)
(buffer-substring-no-properties (point-min)
(1- (match-beginning 0)))
;; Warn the user more aggressively if no match was found.
- (message "clang failed with error %d:\n%s" res cmd)
+ (message "clang failed with error %d: %s" res cmd)
(buffer-string))))
(with-current-buffer buf
diff --git a/company-cmake.el b/company-cmake.el
index 010df32..1bfb20b 100644
--- a/company-cmake.el
+++ b/company-cmake.el
@@ -1,6 +1,6 @@
;;; company-cmake.el --- company-mode completion backend for CMake
-;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2013-2014, 2017-2018 Free Software Foundation, Inc.
;; Author: Chen Bin <chenbin DOT sh AT gmail>
;; Version: 0.2
@@ -177,6 +177,13 @@ They affect which types of symbols we get completion candidates for.")
(buffer-substring-no-properties (line-beginning-position)
(point-max))))))
+(defun company-cmake-prefix-dollar-brace-p ()
+ "Test if the current symbol follows ${."
+ (save-excursion
+ (skip-syntax-backward "w_")
+ (and (eq (char-before (point)) ?\{)
+ (eq (char-before (1- (point))) ?$))))
+
(defun company-cmake (command &optional arg &rest ignored)
"`company-mode' completion backend for CMake.
CMake is a cross-platform, open-source make system."
@@ -187,7 +194,8 @@ CMake is a cross-platform, open-source make system."
(unless company-cmake-executable
(error "Company found no cmake executable"))))
(prefix (and (memq major-mode company-cmake-modes)
- (not (company-in-string-or-comment))
+ (or (not (company-in-string-or-comment))
+ (company-cmake-prefix-dollar-brace-p))
(company-grab-symbol)))
(candidates (company-cmake--candidates arg))
(meta (company-cmake--meta arg))
diff --git a/company-css.el b/company-css.el
index cf8c683..d3ece74 100644
--- a/company-css.el
+++ b/company-css.el
@@ -1,6 +1,6 @@
;;; company-css.el --- company-mode completion backend for css-mode -*- lexical-binding: t -*-
-;; Copyright (C) 2009, 2011, 2014 Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2014, 2018 Free Software Foundation, Inc.
;; Author: Nikolaj Schumacher
@@ -20,6 +20,8 @@
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
+;;
+;; In Emacs >= 26, company-capf is used instead.
;;; Code:
@@ -422,7 +424,8 @@ Returns \"\" if no property found, but feasible at this position."
(string= (web-mode-language-at-pos) "css")))
(or (company-grab company-css-tag-regexp 1)
(company-grab company-css-pseudo-regexp 1)
- (company-grab company-css-property-value-regexp 2)
+ (company-grab company-css-property-value-regexp 2
+ (line-beginning-position))
(company-css-grab-property))))
(candidates
(cond
@@ -430,7 +433,8 @@ Returns \"\" if no property found, but feasible at this position."
(all-completions arg company-css-html-tags))
((company-grab company-css-pseudo-regexp 1)
(all-completions arg company-css-pseudo-classes))
- ((company-grab company-css-property-value-regexp 2)
+ ((company-grab company-css-property-value-regexp 2
+ (line-beginning-position))
(all-completions arg
(company-css-property-values
(company-grab company-css-property-value-regexp 1))))
diff --git a/company-gtags.el b/company-gtags.el
index 02513ca..2a85f23 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -33,15 +33,15 @@
"Completion backend for GNU Global."
:group 'company)
+(define-obsolete-variable-alias
+ 'company-gtags-gnu-global-program-name
+ 'company-gtags-executable "earlier")
+
(defcustom company-gtags-executable
(executable-find "global")
"Location of GNU global executable."
:type 'string)
-(define-obsolete-variable-alias
- 'company-gtags-gnu-global-program-name
- 'company-gtags-executable "earlier")
-
(defcustom company-gtags-insert-arguments t
"When non-nil, insert function arguments as a template after completion."
:type 'boolean
diff --git a/company-ispell.el b/company-ispell.el
index c275bbe..ed658f2 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -53,7 +53,7 @@ If nil, use `ispell-complete-word-dict'."
(company-ispell--lookup-words "WHATEVER")
(setq company-ispell-available t))
(error
- (message "Company: ispell-look-command not found")
+ (message "Company-Ispell: %s" (error-message-string err))
(setq company-ispell-available nil))))
company-ispell-available)
diff --git a/company-keywords.el b/company-keywords.el
index 414c7b0..b6dfd1d 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -141,6 +141,16 @@
"sum_suffix" "system_clock" "tan" "tanh" "target" "template" "then"
"tiny" "transfer" "transpose" "trim" "true" "type" "ubound" "unpack"
"use" "value" "verify" "volatile" "wait" "where" "while" "with" "write"))
+ (go-mode
+ ;; 1. Keywords ref: https://golang.org/ref/spec#Keywords
+ ;; 2. Builtin functions and types ref: https://golang.org/pkg/builtin/
+ "append" "bool" "break" "byte" "cap" "case" "chan" "close" "complex" "complex128"
+ "complex64" "const" "continue" "copy" "default" "defer" "delete" "else" "error"
+ "fallthrough" "false" "float32" "float64" "for" "func" "go" "goto" "if" "imag"
+ "import" "int" "int16" "int32" "int64" "int8" "interface" "len" "make"
+ "map" "new" "nil" "package" "panic" "print" "println" "range" "real" "recover"
+ "return" "rune" "select" "string" "struct" "switch" "true" "type" "uint" "uint16"
+ "uint32" "uint64" "uint8" "uintptr" "var")
(java-mode
"abstract" "assert" "boolean" "break" "byte" "case" "catch" "char" "class"
"continue" "default" "do" "double" "else" "enum" "extends" "final"
@@ -149,9 +159,12 @@
"return" "short" "static" "strictfp" "super" "switch" "synchronized"
"this" "throw" "throws" "transient" "try" "void" "volatile" "while")
(javascript-mode
- "break" "catch" "const" "continue" "delete" "do" "else" "export" "for"
- "function" "if" "import" "in" "instanceOf" "label" "let" "new" "return"
- "switch" "this" "throw" "try" "typeof" "var" "void" "while" "with" "yield")
+ ;; https://tc39.github.io/ecma262/ + async, static and undefined
+ "async" "await" "break" "case" "catch" "class" "const" "continue"
+ "debugger" "default" "delete" "do" "else" "enum" "export" "extends" "false"
+ "finally" "for" "function" "if" "import" "in" "instanceof" "let" "new"
+ "null" "return" "static" "super" "switch" "this" "throw" "true" "try"
+ "typeof" "undefined" "var" "void" "while" "with" "yield")
(kotlin-mode
"abstract" "annotation" "as" "break" "by" "catch" "class" "companion"
"const" "constructor" "continue" "data" "do" "else" "enum" "false" "final"
@@ -209,9 +222,11 @@
"print" "private" "protected" "public" "require" "require_once" "return"
"static" "switch" "this" "throw" "try" "unset" "use" "var" "while" "xor")
(python-mode
- "and" "assert" "break" "class" "continue" "def" "del" "elif" "else"
- "except" "exec" "finally" "for" "from" "global" "if" "import" "in" "is"
- "lambda" "not" "or" "pass" "print" "raise" "return" "try" "while" "yield")
+ ;; https://docs.python.org/3/reference/lexical_analysis.html#keywords
+ "False" "None" "True" "and" "as" "assert" "break" "class" "continue" "def"
+ "del" "elif" "else" "except" "exec" "finally" "for" "from" "global" "if"
+ "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass" "print" "raise"
+ "return" "try" "while" "with" "yield")
(ruby-mode
"BEGIN" "END" "alias" "and" "begin" "break" "case" "class" "def" "defined?"
"do" "else" "elsif" "end" "ensure" "false" "for" "if" "in" "module"
@@ -219,10 +234,6 @@
"then" "true" "undef" "unless" "until" "when" "while" "yield")
;; From https://doc.rust-lang.org/grammar.html#keywords
;; but excluding unused reserved words: https://www.reddit.com/r/rust/comments/34fq0k/is_there_a_good_list_of_rusts_keywords/cqucvnj
- (go-mode
- "break" "case" "chan" "const" "continue" "default" "defer" "else" "fallthrough"
- "for" "func" "go" "goto" "if" "import" "interface" "map" "package" "range"
- "return" "select" "struct" "switch" "type" "var")
(rust-mode
"Self"
"as" "box" "break" "const" "continue" "crate" "else" "enum" "extern"
@@ -255,12 +266,19 @@
"otherwise" "quote" "return" "switch" "throw" "true" "try" "type"
"typealias" "using" "while"
)
+ ;; From https://github.com/apache/thrift/blob/master/contrib/thrift.el
+ (thrift-mode
+ "binary" "bool" "byte" "const" "double" "enum" "exception" "extends"
+ "i16" "i32" "i64" "include" "list" "map" "oneway" "optional" "required"
+ "service" "set" "string" "struct" "throws" "typedef" "void"
+ )
;; aliases
(js2-mode . javascript-mode)
(js2-jsx-mode . javascript-mode)
(espresso-mode . javascript-mode)
(js-mode . javascript-mode)
(js-jsx-mode . javascript-mode)
+ (rjsx-mode . javascript-mode)
(cperl-mode . perl-mode)
(jde-mode . java-mode)
(ess-julia-mode . julia-mode)
diff --git a/company-nxml.el b/company-nxml.el
index 5afa00e..36ff1ce 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -1,6 +1,6 @@
;;; company-nxml.el --- company-mode completion backend for nxml-mode
-;; Copyright (C) 2009-2011, 2013 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013, 2018 Free Software Foundation, Inc.
;; Author: Nikolaj Schumacher
@@ -22,6 +22,7 @@
;;; Commentary:
;;
+;; In Emacs >= 26, company-capf is used instead.
;;; Code:
diff --git a/company-tng.el b/company-tng.el
index 46592da..a1d7173 100644
--- a/company-tng.el
+++ b/company-tng.el
@@ -102,7 +102,8 @@ confirm the selection and finish the completion."
(when (and company-selection-changed
(not (company--company-command-p (this-command-keys))))
(company--unread-this-command-keys)
- (setq this-command 'company-complete-selection)))))
+ (setq this-command 'company-complete-selection)
+ (advice-add 'company-call-backend :before-until 'company-tng--supress-post-completion)))))
;;;###autoload
(defun company-tng-configure-default ()
@@ -159,5 +160,15 @@ made explicitly (i.e. `company-selection-changed' is true)"
(setf (nth 3 args) nil))
args)
+(defun company-tng--supress-post-completion (command &rest args)
+ "Installed as a :before-until advice on `company-call-backend' and
+prevents the 'post-completion command from being delivered to the backend
+for the next iteration. post-completion do things like expand snippets
+which are undesirable because completions are implicit in company-tng and
+visible side-effects after the completion are surprising."
+ (when (eq command 'post-completion)
+ (advice-remove 'company-call-backend 'company-tng--supress-post-completion)
+ t))
+
(provide 'company-tng)
;;; company-tng.el ends here
diff --git a/company.el b/company.el
index 13481db..1e91d06 100644
--- a/company.el
+++ b/company.el
@@ -5,7 +5,7 @@
;; Author: Nikolaj Schumacher
;; Maintainer: Dmitry Gutov <dgutov@yandex.ru>
;; URL: http://company-mode.github.io/
-;; Version: 0.9.6
+;; Version: 0.9.9
;; Keywords: abbrev, convenience, matching
;; Package-Requires: ((emacs "24.3"))
@@ -44,7 +44,9 @@
;; Here is a simple example completing "foo":
;;
;; (defun company-my-backend (command &optional arg &rest ignored)
+;; (interactive (list 'interactive))
;; (pcase command
+;; (`interactive (company-begin-backend 'company-my-backend))
;; (`prefix (company-grab-symbol))
;; (`candidates (list "foobar" "foobaz" "foobarbaz"))
;; (`meta (format "This value is named %s" arg))))
@@ -322,7 +324,10 @@ This doesn't include the margins and the scroll bar."
(defcustom company-backends `(,@(unless (version< "24.3.51" emacs-version)
(list 'company-elisp))
company-bbdb
- company-nxml company-css
+ ,@(unless (version<= "26" emacs-version)
+ (list 'company-nxml))
+ ,@(unless (version<= "26" emacs-version)
+ (list 'company-css))
company-eclim company-semantic company-clang
company-xcode company-cmake
company-capf
@@ -398,10 +403,13 @@ be kept if they have different annotations. For that to work properly,
backends should store the related information on candidates using text
properties.
-`match': The second argument is a completion candidate. Return the index
-after the end of text matching `prefix' within the candidate string. It
-will be used when rendering the popup. This command only makes sense for
-backends that provide non-prefix completion.
+`match': The second argument is a completion candidate. Return a positive
+integer, the index after the end of text matching `prefix' within the
+candidate string. Alternatively, return a list of (CHUNK-START
+. CHUNK-END) elements, where CHUNK-START and CHUNK-END are indexes within
+the candidate string. The corresponding regions are be used when rendering
+the popup. This command only makes sense for backends that provide
+non-prefix completion.
`require-match': If this returns t, the user is not allowed to enter
anything not offered as a candidate. Please don't use that value in normal
@@ -503,6 +511,11 @@ If you indend to use it to post-process candidates from a specific
backend, consider using the `post-completion' command instead."
:type 'hook)
+(defcustom company-after-completion-hook nil
+ "Hook run at the end of completion, successful or not.
+The hook is called with one argument which is either a string or a symbol."
+ :type 'hook)
+
(defcustom company-minimum-prefix-length 3
"The minimum prefix length for idle completion."
:type '(integer :tag "prefix length"))
@@ -600,7 +613,8 @@ treated as if it was on this list."
(defcustom company-continue-commands '(not save-buffer save-some-buffers
save-buffers-kill-terminal
- save-buffers-kill-emacs)
+ save-buffers-kill-emacs
+ completion-at-point)
"A list of commands that are allowed during completion.
If this is t, or if `company-begin-commands' is t, any command is allowed.
Otherwise, the value must be a list of symbols. If it starts with `not',
@@ -1358,10 +1372,18 @@ Keywords and function definition names are ignored."
noccurs)))
(defun company--occurrence-predicate ()
+ (defvar comint-last-prompt)
(let ((beg (match-beginning 0))
- (end (match-end 0)))
+ (end (match-end 0))
+ (comint-last-prompt (bound-and-true-p comint-last-prompt)))
(save-excursion
(goto-char end)
+ ;; Workaround for python-shell-completion-at-point's behavior:
+ ;; https://github.com/company-mode/company-mode/issues/759
+ ;; https://github.com/company-mode/company-mode/issues/549
+ (when (derived-mode-p 'inferior-python-mode)
+ (let ((lbp (line-beginning-position)))
+ (setq comint-last-prompt (cons lbp lbp))))
(and (not (memq (get-text-property (1- (point)) 'face)
'(font-lock-function-name-face
font-lock-keyword-face)))
@@ -1413,7 +1435,7 @@ prefix match (same case) will be prioritized."
(not company-candidates)
(let ((company-idle-delay 'now))
(condition-case-unless-debug err
- (progn
+ (let ((inhibit-quit nil))
(company--perform)
;; Return non-nil if active.
company-candidates)
@@ -1618,10 +1640,10 @@ prefix match (same case) will be prioritized."
;; `company-completion-finished-hook' in that case, with right argument.
(if (stringp result)
(let ((company-backend backend))
- (company-call-backend 'pre-completion result)
(run-hook-with-args 'company-completion-finished-hook result)
(company-call-backend 'post-completion result))
- (run-hook-with-args 'company-completion-cancelled-hook result))))
+ (run-hook-with-args 'company-completion-cancelled-hook result))
+ (run-hook-with-args 'company-after-completion-hook result)))
;; Make return value explicit.
nil)
@@ -2378,11 +2400,13 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
cc annotations)
(when (or (stringp prefix) (consp prefix))
(let ((company-backend backend))
- (setq cc (company-call-backend 'candidates prefix)
- annotations
- (mapcar
- (lambda (c) (cons c (company-call-backend 'annotation c)))
- cc))))
+ (condition-case nil
+ (setq cc (company-call-backend 'candidates (company--prefix-str prefix))
+ annotations
+ (mapcar
+ (lambda (c) (cons c (company-call-backend 'annotation c)))
+ cc))
+ (error (setq annotations 'error)))))
(pop-to-buffer (get-buffer-create "*company-diag*"))
(setq buffer-read-only nil)
(erase-buffer)
@@ -2401,11 +2425,13 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
(insert "\n")
(insert (message "Completions:"))
(unless cc (insert " none"))
- (save-excursion
- (dolist (c annotations)
- (insert "\n " (prin1-to-string (car c)))
- (when (cdr c)
- (insert " " (prin1-to-string (cdr c))))))
+ (if (eq annotations 'error)
+ (insert "(error fetching)")
+ (save-excursion
+ (dolist (c annotations)
+ (insert "\n " (prin1-to-string (car c)))
+ (when (cdr c)
+ (insert " " (prin1-to-string (cdr c)))))))
(special-mode)))
;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2490,7 +2516,6 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
(- width (length annotation)))
annotation))
right)))
- (setq common (+ (min common width) margin))
(setq width (+ width margin (length right)))
(font-lock-append-text-property 0 width 'mouse-face
@@ -2502,11 +2527,17 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
'company-tooltip-annotation-selection
'company-tooltip-annotation)
line))
- (font-lock-prepend-text-property margin common 'face
- (if selected
- 'company-tooltip-common-selection
- 'company-tooltip-common)
- line)
+ (cl-loop
+ with width = (- width (length right))
+ for (comp-beg . comp-end) in (if (integerp common) `((0 . ,common)) common)
+ for inline-beg = (+ margin comp-beg)
+ for inline-end = (min (+ margin comp-end) width)
+ when (< inline-beg width)
+ do (font-lock-prepend-text-property inline-beg inline-end 'face
+ (if selected
+ 'company-tooltip-common-selection
+ 'company-tooltip-common)
+ line))
(when (let ((re (funcall company-search-regexp-function
company-search-string)))
(and (not (string= re ""))
@@ -2802,7 +2833,6 @@ Returns a negative number if the tooltip should be displayed above point."
(defun company-pseudo-tooltip-show (row column selection)
(company-pseudo-tooltip-hide)
- (save-excursion
(let* ((height (company--pseudo-tooltip-height))
above)
@@ -2811,15 +2841,17 @@ Returns a negative number if the tooltip should be displayed above point."
(setq row (+ row height -1)
above t))
- (let* ((nl (< (move-to-window-line row) row))
- (beg (point))
- (end (save-excursion
- (move-to-window-line (+ row (abs height)))
- (point)))
- (ov (make-overlay beg end nil t))
- (args (list (mapcar 'company-plainify
- (company-buffer-lines beg end))
- column nl above)))
+ (let (nl beg end ov args)
+ (save-excursion
+ (setq nl (< (move-to-window-line row) row)
+ beg (point)
+ end (save-excursion
+ (move-to-window-line (+ row (abs height)))
+ (point))
+ ov (make-overlay beg end nil t)
+ args (list (mapcar 'company-plainify
+ (company-buffer-lines beg end))
+ column nl above)))
(setq company-pseudo-tooltip-overlay ov)
(overlay-put ov 'company-replacement-args args)
@@ -2830,7 +2862,7 @@ Returns a negative number if the tooltip should be displayed above point."
(overlay-put ov 'company-width (string-width (car lines))))
(overlay-put ov 'company-column column)
- (overlay-put ov 'company-height height)))))
+ (overlay-put ov 'company-height height))))
(defun company-pseudo-tooltip-show-at-point (pos column-offset)
(let* ((col-row (company--col-row pos))
diff --git a/test/all.el b/test/all.el
index 6d64a62..3d7758f 100644
--- a/test/all.el
+++ b/test/all.el
@@ -25,4 +25,6 @@
(require 'ert)
(dolist (test-file (directory-files company-test-path t "-tests.el$"))
- (load test-file nil t))
+ (unless (and (= emacs-major-version 24)
+ (equal (file-name-base test-file) "capf-tests"))
+ (load test-file nil t)))
diff --git a/test/capf-tests.el b/test/capf-tests.el
new file mode 100644
index 0000000..c8d4202
--- /dev/null
+++ b/test/capf-tests.el
@@ -0,0 +1,140 @@
+;;; capf-tests.el --- company tests for the company-capf backend -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; Author: João Távora <joaotavora@gmail.com>
+;; Keywords:
+
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'company-tests)
+(require 'company-capf)
+
+(defmacro company-capf-with-buffer (contents &rest body)
+ (declare (indent 0) (debug (sexp &rest form)))
+ `(with-temp-buffer
+ (insert ,contents)
+ (emacs-lisp-mode)
+ (re-search-backward "|")
+ (replace-match "")
+ (let ((completion-at-point-functions '(elisp-completion-at-point))
+ (company-backends '(company-capf)))
+ ,@body)))
+
+(ert-deftest company-basic-capf ()
+ "Test basic `company-capf' support."
+ (company-capf-with-buffer
+ "(with-current-buffer|)"
+ (company-mode)
+ (company-complete)
+ (should company-candidates)))
+
+(ert-deftest company-non-prefix-capf ()
+ "Test non-prefix `company-capf' in elisp"
+ (company-capf-with-buffer
+ "(w-c-b|)"
+ (company-mode)
+ (company-complete)
+ (should company-candidates)
+ (should (member "with-current-buffer" company-candidates))))
+
+(ert-deftest company-basic-capf-highlighting ()
+ "Test basic `company-capf' support, with basic prefix completion."
+ (company-capf-with-buffer
+ "(with|)"
+ (company-mode)
+ (company-complete)
+ (should company-candidates)
+ (let* ((cand (car (member "with-current-buffer" company-candidates)))
+ (render
+ (and cand
+ (company-fill-propertize cand nil (length cand) nil nil nil))))
+ ;; remove `font-lock-face' and `mouse-face' text properties that aren't
+ ;; relevant to our test
+ (remove-list-of-text-properties
+ 0 (length cand) '(font-lock-face mouse-face) render)
+ (should
+ (ert-equal-including-properties
+ render
+ #("with-current-buffer"
+ 0 4 (face (company-tooltip-common company-tooltip)) ; "with"
+ 4 19 (face (company-tooltip))))))))
+
+
+
+;; Re. "perfect" highlighting of the non-prefix in company-capf matches, it is
+;; only working-out-of-the box (i.e. without the `:company-match' meta) in
+;; recent Emacsen containing the following commit. The two tests that follow
+;; reflect that.
+;;
+;; commit 325ef57b0e3977f9509f1049c826999e8b7c226d
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
+;; Date: Tue Nov 7 12:17:34 2017 -0500
+
+(ert-deftest company-non-prefix-fancy-capf-highlighting ()
+ "Test highlighting for non-prefix `company-capf' in elisp"
+ (skip-unless (version<= "27.0" emacs-version))
+ (company-capf-with-buffer
+ "(w-c-b|)"
+ (company-mode)
+ (company-complete)
+ (let* ((cand (car (member "with-current-buffer" company-candidates)))
+ (render
+ (and cand
+ (company-fill-propertize cand nil (length cand) nil nil nil))))
+ ;; remove `font-lock-face' and `mouse-face' text properties that aren't
+ ;; relevant to our test
+ (remove-list-of-text-properties
+ 0 (length cand) '(font-lock-face mouse-face) render)
+ (should
+ (ert-equal-including-properties
+ render
+ #("with-current-buffer"
+ 0 1 (face (company-tooltip-common company-tooltip)) ; "w"
+ 1 4 (face (company-tooltip)) ; "ith"
+ 4 6 (face (company-tooltip-common company-tooltip)) ; "-c"
+ 6 12 (face (company-tooltip)) ; "urrent"
+ 12 14 (face (company-tooltip-common company-tooltip)) ; "-b"
+ 14 19 (face (company-tooltip)))))))) ; "uffer"
+
+(ert-deftest company-non-prefix-modest-capf-highlighting ()
+ "Test highlighting for non-prefix `company-capf' in elisp"
+ (skip-unless (version< emacs-version "27.0"))
+ (company-capf-with-buffer
+ "(w-c-b|)"
+ (company-mode)
+ (company-complete)
+ (let* ((cand (car (member "with-current-buffer" company-candidates)))
+ (render
+ (and cand
+ (company-fill-propertize cand nil (length cand) nil nil nil))))
+ ;; remove `font-lock-face' and `mouse-face' text properties that aren't
+ ;; relevant to our test
+ (remove-list-of-text-properties
+ 0 (length cand) '(font-lock-face mouse-face) render)
+ (should
+ (ert-equal-including-properties
+ render
+ #("with-current-buffer"
+ 0 14 (face (company-tooltip-common company-tooltip)); "with-current-b"
+ 14 19 (face (company-tooltip)))))))) ; "uffer"
+
+(provide 'capf-tests)
+;;; capf-tests.el ends here
diff --git a/test/cmake-tests.el b/test/cmake-tests.el
new file mode 100644
index 0000000..52467cc
--- /dev/null
+++ b/test/cmake-tests.el
@@ -0,0 +1,44 @@
+;;; cmake-tests.el --- company-mode tests -*- lexical-binding: t -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; Author: Zuogong Yue
+
+;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company-tests)
+(require 'company-cmake)
+
+(ert-deftest company-cmake-complete-in-string-prefix-quotes ()
+ (with-temp-buffer
+ (insert "set(MyFlags \"${CMAKE_CXX_FLAGS_R")
+ (setq-local major-mode 'cmake-mode)
+ (should (equal (company-cmake 'prefix)
+ "CMAKE_CXX_FLAGS_R"))))
+
+(ert-deftest company-cmake-complete-in-string-more-prefix ()
+ (with-temp-buffer
+ (insert "set(MyFlags \"${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_R")
+ (setq-local major-mode 'cmake-mode)
+ (should (equal (company-cmake 'prefix)
+ "CMAKE_CXX_FLAGS_R"))))
+
+(ert-deftest company-cmake-complete-in-string-more-prefix-2 ()
+ (with-temp-buffer
+ (insert "set(MyFlags \"${CMAKE_CXX_FLAGS} CMAKE_CXX_FLAGS_R")
+ (setq-local major-mode 'cmake-mode)
+ (should (equal (company-cmake 'prefix)
+ nil))))