]> code.delx.au - gnu-emacs-elpa/commitdiff
Merge commit '51c140ca9ee32d27cacc7b2b07d4539bf98ae575' from company-master
authorDmitry Gutov <dgutov@yandex.ru>
Sat, 19 Apr 2014 10:11:04 +0000 (14:11 +0400)
committerDmitry Gutov <dgutov@yandex.ru>
Sat, 19 Apr 2014 10:11:04 +0000 (14:11 +0400)
Conflicts:
packages/company/company-pysmell.el

30 files changed:
packages/company/.travis.yml
packages/company/Makefile
packages/company/NEWS.md
packages/company/company-abbrev.el
packages/company/company-bbdb.el
packages/company/company-capf.el
packages/company/company-clang.el
packages/company/company-cmake.el
packages/company/company-css.el
packages/company/company-dabbrev-code.el
packages/company/company-dabbrev.el
packages/company/company-eclim.el
packages/company/company-elisp-tests.el [new file with mode: 0644]
packages/company/company-elisp.el
packages/company/company-etags.el
packages/company/company-files.el
packages/company/company-gtags.el
packages/company/company-ispell.el
packages/company/company-keywords.el
packages/company/company-nxml.el
packages/company/company-oddmuse.el
packages/company/company-pysmell.el
packages/company/company-ropemacs.el
packages/company/company-semantic.el
packages/company/company-template.el
packages/company/company-tempo.el
packages/company/company-tests.el
packages/company/company-xcode.el
packages/company/company-yasnippet.el
packages/company/company.el

index cdf55d1ec01fceb8f10e3bed7c0c3cbe8bdb7a89..11d7fd48291546a4008079bf1797ab5b00589cd8 100644 (file)
@@ -4,25 +4,19 @@ language: emacs-lisp
 
 env:
   matrix:
-    - EMACS=emacs23
     - EMACS=emacs24
     - EMACS=emacs-snapshot
 
 install:
-  - if [ "$EMACS" = "emacs23" ]; then
-        sudo apt-get update -qq &&
-        sudo apt-get install -qq emacs23-gtk emacs23-el;
-    fi
   - if [ "$EMACS" = "emacs24" ]; then
         sudo add-apt-repository -y ppa:cassou/emacs &&
         sudo apt-get update -qq &&
         sudo apt-get install -qq emacs24 emacs24-el;
     fi
   - if [ "$EMACS" = "emacs-snapshot" ]; then
-        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo add-apt-repository -y ppa:ubuntu-elisp/ppa &&
         sudo apt-get update -qq &&
-        sudo apt-get install -qq emacs-snapshot &&
-        sudo apt-get install -qq emacs-snapshot-el emacs-snapshot-gtk;
+        sudo apt-get install -qq emacs-snapshot;
     fi
 
 before_script:
index 2602191aa7e4f709960fc0a49a860a9c15f45c0e..4d7a9ad1c3cbaac6d37483a9915e0d0671c5201e 100644 (file)
@@ -22,11 +22,11 @@ clean:
        @rm -rf company-*/ company-*.tar company-*.tar.bz2 *.elc ert.el
 
 test:
-       ${EMACS} -Q -nw -L . -l company-tests.el \
+       ${EMACS} -Q -nw -L . -l company-tests.el -l company-elisp-tests.el \
        --eval "(let (pop-up-windows) (ert t))"
 
 test-batch:
-       ${EMACS} -Q --batch -L . -l company-tests.el \
+       ${EMACS} -Q --batch -L . -l company-tests.el -l company-elisp-tests.el \
        --eval "(ert-run-tests-batch-and-exit '(not (tag interactive)))"
 
 downloads:
index b72f53455fff656b3caf36004754487f3fd3af17..97dc2849d558b0c962c407523293201f987a355a 100644 (file)
@@ -1,5 +1,19 @@
 # History of user-visible changes
 
+## 2014-04-19 (0.8.0)
+
+* `company-capf` is included in `company-backends` in any supported Emacs
+  version (>= 24.1). `company-elisp` goes before it if Emacs version is < 24.4.
+* New user option `company-clang-insert-arguments`, by default t.
+* Default value of `company-idle-delay` lowered to `0.5`.
+* New user option `company-tooltip-minimum-width`, by default 0.
+* New function `company-grab-symbol-cons`.
+* `company-clang` fetches completion candidates asynchronously.
+* Added support for asynchronous back-ends (experimental).
+* Support for back-end command `crop` dropped (it was never documented).
+* Support for Emacs 23 dropped.
+* New user option `company-abort-manual-when-too-short`.
+
 ## 2014-03-25 (0.7.3)
 
 * New user option `company-etags-ignore-case`.
index 0c4e327bc46baef1983269ae4267a33d616fbdac..a454aaa90d277c2d3950b7a5177969152fa2090f 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 (require 'abbrev)
 
 (defun company-abbrev-insert (match)
@@ -37,7 +37,7 @@
 (defun company-abbrev (command &optional arg &rest ignored)
   "`company-mode' completion back-end for abbrev."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-abbrev
                                         'company-abbrev-insert))
     (prefix (company-grab-symbol))
index 8e4705f73910437c958d04e50d5a659c42def25b..acdd30ac14922aeb683bb1e14984cd3202736c06 100644 (file)
@@ -20,7 +20,7 @@
 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (declare-function bbdb-record-get-field "bbdb")
 (declare-function bbdb-records "bbdb")
 (defun company-bbdb (command &optional arg &rest ignore)
   "`company-mode' completion back-end for `bbdb'."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-bbdb))
     (prefix (and (eq major-mode 'message-mode)
                  (featurep 'bbdb-com)
                  (looking-back "^\\(To\\|Cc\\|Bcc\\):.*"
                                (line-beginning-position))
                  (company-grab-symbol)))
-    (candidates (mapcan (lambda (record)
-                          (mapcar (lambda (mail) (bbdb-dwim-mail record mail))
-                                  (bbdb-record-get-field record 'mail)))
-                        (bbdb-search (bbdb-records) arg nil arg)))
+    (candidates (cl-mapcan (lambda (record)
+                             (mapcar (lambda (mail) (bbdb-dwim-mail record mail))
+                                     (bbdb-record-get-field record 'mail)))
+                           (bbdb-search (bbdb-records) arg nil arg)))
     (sorted t)
     (no-cache t)))
 
index 17be772126736ab282b2524fd509c8cc190a9c7f..3aaeb137a8000550d61b5be4388651cb6a775235 100644 (file)
@@ -25,7 +25,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defvar company--capf-data nil)
 (make-variable-buffer-local 'company--capf-data)
 (defun company--capf-data ()
   ;; Ignore tags-completion-at-point-function because it subverts company-etags
   ;; in the default value of company-backends, where the latter comes later.
-  (letf* (((default-value 'completion-at-point-functions) nil)
-          (data (run-hook-wrapped 'completion-at-point-functions
-                                  ;; Ignore misbehaving functions.
-                                  #'completion--capf-wrapper 'optimist)))
+  (cl-letf* (((default-value 'completion-at-point-functions) nil)
+             (data (run-hook-wrapped 'completion-at-point-functions
+                                     ;; Ignore misbehaving functions.
+                                     #'completion--capf-wrapper 'optimist)))
     (when (and (consp (cdr data)) (numberp (nth 1 data))) data)))
 
 (defun company-capf (command &optional arg &rest _args)
-  "`company-mode' back-end using `completion-at-point-functions'.
-Requires Emacs 24.1 or newer."
+  "`company-mode' back-end using `completion-at-point-functions'."
   (interactive (list 'interactive))
   (pcase command
     (`interactive (company-begin-backend 'company-capf))
index 787ecef6eaa6e87d88115a099e72e3002cb06dcb..4f0f3189eb45e4db3c6e9d86f50817b79bb1dee8 100644 (file)
@@ -1,6 +1,6 @@
-;;; company-clang.el --- company-mode completion back-end for Clang
+;;; company-clang.el --- company-mode completion back-end for Clang  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2013-2014  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -27,7 +27,7 @@
 
 (require 'company)
 (require 'company-template)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-clang nil
   "Completion back-end for Clang."
@@ -60,6 +60,9 @@ or automatically through a custom `company-clang-prefix-guesser'."
 (defvar company-clang-modes '(c-mode c++-mode objc-mode)
   "Major modes which clang may complete.")
 
+(defcustom company-clang-insert-arguments t
+  "When non-nil, insert function arguments as a template after completion.")
+
 ;; prefix ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-clang--prefix nil)
@@ -107,7 +110,7 @@ or automatically through a custom `company-clang-prefix-guesser'."
 (defconst company-clang--completion-pattern
   "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$")
 
-(defconst company-clang--error-buffer-name "*clang error*")
+(defconst company-clang--error-buffer-name "*clang-error*")
 
 (defun company-clang--lang-option ()
      (if (eq major-mode 'objc-mode)
@@ -115,7 +118,7 @@ or automatically through a custom `company-clang-prefix-guesser'."
              "objective-c" "objective-c++")
        (substring (symbol-name major-mode) 0 -5)))
 
-(defun company-clang--parse-output (prefix objc)
+(defun company-clang--parse-output (prefix _objc)
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
                          (regexp-quote prefix)))
@@ -175,20 +178,30 @@ or automatically through a custom `company-clang-prefix-guesser'."
         (setq buffer-read-only t)
         (goto-char (point-min))))))
 
-(defun company-clang--call-process (prefix &rest args)
+(defun company-clang--start-process (prefix callback &rest args)
   (let ((objc (derived-mode-p 'objc-mode))
-        (buf (get-buffer-create "*clang-output*"))
-        res)
+        (buf (get-buffer-create "*clang-output*")))
     (with-current-buffer buf (erase-buffer))
-    (setq res (if (company-clang--auto-save-p)
-                  (apply 'call-process company-clang-executable nil buf nil args)
-                (apply 'call-process-region (point-min) (point-max)
-                       company-clang-executable nil buf nil args)))
-    (with-current-buffer buf
-      (unless (eq 0 res)
-        (company-clang--handle-error res args))
-      ;; Still try to get any useful input.
-      (company-clang--parse-output prefix objc))))
+    (if (get-buffer-process buf)
+        (funcall callback nil)
+      (let ((process (apply #'start-process "company-clang" buf
+                            company-clang-executable args)))
+        (set-process-sentinel
+         process
+         (lambda (proc status)
+           (unless (string-match-p "hangup" status)
+             (funcall
+              callback
+              (let ((res (process-exit-status proc)))
+                (with-current-buffer buf
+                  (unless (eq 0 res)
+                    (company-clang--handle-error res args))
+                  ;; Still try to get any useful input.
+                  (company-clang--parse-output prefix objc)))))))
+        (unless (company-clang--auto-save-p)
+          (send-region process (point-min) (point-max))
+          (send-string process "\n")
+          (process-send-eof process))))))
 
 (defsubst company-clang--build-location (pos)
   (save-excursion
@@ -214,27 +227,22 @@ or automatically through a custom `company-clang-prefix-guesser'."
           (list (company-clang--build-location pos))
           (list (if (company-clang--auto-save-p) buffer-file-name "-"))))
 
-(defun company-clang--candidates (prefix)
+(defun company-clang--candidates (prefix callback)
   (and (company-clang--auto-save-p)
        (buffer-modified-p)
        (basic-save-buffer))
   (when (null company-clang--prefix)
     (company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
                                   'none)))
-  (apply 'company-clang--call-process
+  (apply 'company-clang--start-process
          prefix
+         callback
          (company-clang--build-complete-args (- (point) (length prefix)))))
 
 (defun company-clang--prefix ()
-  (let ((symbol (company-grab-symbol)))
-    (if symbol
-        (if (and company-clang-begin-after-member-access
-                 (save-excursion
-                   (forward-char (- (length symbol)))
-                   (looking-back "\\.\\|->\\|::" (- (point) 2))))
-            (cons symbol t)
-          symbol)
-      'stop)))
+  (if company-clang-begin-after-member-access
+      (company-grab-symbol-cons "\\.\\|->\\|::" 2)
+    (company-grab-symbol)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -272,7 +280,7 @@ or automatically through a custom `company-clang-prefix-guesser'."
           (if (< (point) end)
               (insert " ")
             (throw 'stop t))
-          (incf cnt))))
+          (cl-incf cnt))))
     (company-template-move-to-first templ)))
 
 (defun company-clang (command &optional arg &rest ignored)
@@ -288,7 +296,7 @@ With Clang versions before 2.9, we have to save the buffer before
 performing completion.  With Clang 2.9 and later, buffer contents are
 passed via standard input."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-clang))
     (init (when (memq major-mode company-clang-modes)
             (unless company-clang-executable
@@ -300,12 +308,13 @@ passed via standard input."
                  buffer-file-name
                  company-clang-executable
                  (not (company-in-string-or-comment))
-                 (company-clang--prefix)))
-    (candidates (company-clang--candidates arg))
+                 (or (company-clang--prefix) 'stop)))
+    (candidates (cons :async
+                      (lambda (cb) (company-clang--candidates arg cb))))
     (meta       (company-clang--meta arg))
     (annotation (company-clang--annotation arg))
     (post-completion (let ((anno (company-clang--annotation arg)))
-                       (when anno
+                       (when (and company-clang-insert-arguments anno)
                          (insert anno)
                          (if (string-match ":" anno)
                              (company-clang-objc-templatify anno)
index 34359dc7ab011a1e0a9b298cfcd66e8fa29c9136..a466f60b7a75b5abdad3ec06a4fd3e367ca9a46f 100644 (file)
@@ -25,8 +25,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
 (require 'company)
+(require 'cl-lib)
 
 (defgroup company-cmake nil
   "Completion back-end for CMake."
@@ -112,7 +112,7 @@ They affect which types of symbols we get completion candidates for.")
   "`company-mode' completion back-end for CMake.
 CMake is a cross-platform, open-source make system."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-cmake))
     (init (when (memq major-mode company-cmake-modes)
             (unless company-cmake-executable
index 11e195adabdf2c03584be1d63826a8a8a1224d98..c4154c2ec4efa85847d4d289c0e354cc22c0b8d5 100644 (file)
@@ -24,7 +24,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defconst company-css-property-alist
   ;; see http://www.w3.org/TR/CSS21/propidx.html
@@ -280,7 +280,7 @@ Returns \"\" if no property found, but feasible at this position."
 (defun company-css (command &optional arg &rest ignored)
   "`company-mode' completion back-end for `css-mode'."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-css))
     (prefix (and (derived-mode-p 'css-mode)
                  (or (company-grab company-css-tag-regexp 1)
index 6f827cd50d7e71bb8ee250f7651829774203f809..1039e4a66d192e511bc5e989f3067b564d4a0c6f 100644 (file)
@@ -27,7 +27,7 @@
 
 (require 'company)
 (require 'company-dabbrev)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-dabbrev-code nil
   "dabbrev-like completion back-end for code."
@@ -80,7 +80,7 @@ See also `company-dabbrev-code-time-limit'."
 The back-end looks for all symbols in the current buffer that aren't in
 comments or strings."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-dabbrev-code))
     (prefix (and (or (eq t company-dabbrev-code-modes)
                      (apply 'derived-mode-p company-dabbrev-code-modes))
index c0cd0e0ab6818ee0150a4a4b9d75492a38fb34cf..401fcc9181f5391ebcdae07f20b37aedfdc78b0d 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-dabbrev nil
   "dabbrev-like completion back-end."
@@ -73,7 +73,7 @@ If you set this value to nil, you may also want to set
        (while ,test
          ,@body
          (and ,limit
-              (eq (incf company-time-limit-while-counter) 25)
+              (eq (cl-incf company-time-limit-while-counter) 25)
               (setq company-time-limit-while-counter 0)
               (> (float-time (time-since ,start)) ,limit)
               (throw 'done 'company-time-out))))))
@@ -114,7 +114,7 @@ If you set this value to nil, you may also want to set
          (symbols (company-dabbrev--search-buffer regexp (point) nil start limit
                                                   ignore-comments)))
     (when other-buffers
-      (dolist (buffer (delq (current-buffer) (buffer-list)))
+      (cl-dolist (buffer (delq (current-buffer) (buffer-list)))
         (and (or (eq other-buffers 'all)
                  (eq (buffer-local-value 'major-mode buffer) major-mode))
              (with-current-buffer buffer
@@ -123,14 +123,14 @@ If you set this value to nil, you may also want to set
                                                      limit ignore-comments))))
         (and limit
              (> (float-time (time-since start)) limit)
-             (return))))
+             (cl-return))))
     symbols))
 
 ;;;###autoload
 (defun company-dabbrev (command &optional arg &rest ignored)
   "dabbrev-like `company-mode' completion back-end."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-dabbrev))
     (prefix (company-grab-word))
     (candidates
index d6f699a9d4de055effc43717ea4ff828c823c804..0eaf38228675de1d41467a7a2e32c986f2197037 100644 (file)
@@ -32,7 +32,7 @@
 
 (require 'company)
 (require 'company-template)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-eclim nil
   "Completion back-end for Eclim."
 
 (defun company-eclim-executable-find ()
   (let (file)
-    (dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
+    (cl-dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
                             "/usr/local/lib/eclipse"))
       (and (file-exists-p (setq file (expand-file-name "plugins" eclipse-root)))
            (setq file (car (last (directory-files file t "^org.eclim_"))))
            (file-exists-p (setq file (expand-file-name "bin/eclim" file)))
-           (return file)))))
+           (cl-return file)))))
 
 (defcustom company-eclim-executable
   (or (executable-find "eclim") (company-eclim-executable-find))
@@ -92,7 +92,7 @@ eclim can only complete correctly when the buffer has been saved."
       (setq company-eclim--project-dir
             (directory-file-name
              (expand-file-name
-              (company-locate-dominating-file buffer-file-name ".project"))))
+              (locate-dominating-file buffer-file-name ".project"))))
     company-eclim--project-dir))
 
 (defun company-eclim--project-name ()
@@ -100,9 +100,9 @@ eclim can only complete correctly when the buffer has been saved."
       (let ((dir (company-eclim--project-dir)))
         (when dir
           (setq company-eclim--project-name
-                (loop for project in (company-eclim--project-list)
-                      when (equal (cdr (assoc 'path project)) dir)
-                      return (cdr (assoc 'name project))))))))
+                (cl-loop for project in (company-eclim--project-list)
+                         when (equal (cdr (assoc 'path project)) dir)
+                         return (cdr (assoc 'name project))))))))
 
 (defun company-eclim--candidates (prefix)
   (interactive "d")
@@ -134,7 +134,7 @@ eclim can only complete correctly when the buffer has been saved."
       (all-completions prefix completions))))
 
 (defun company-eclim--search-point (prefix)
-  (if (or (plusp (length prefix)) (eq (char-before) ?.))
+  (if (or (cl-plusp (length prefix)) (eq (char-before) ?.))
       (1- (point))
     (point)))
 
@@ -163,7 +163,7 @@ Eclim version 1.7.13 or newer (?) is required.
 Completions only work correctly when the buffer has been saved.
 `company-eclim-auto-save' determines whether to do this automatically."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-eclim))
     (prefix (and (derived-mode-p 'java-mode 'jde-mode)
                  buffer-file-name
diff --git a/packages/company/company-elisp-tests.el b/packages/company/company-elisp-tests.el
new file mode 100644 (file)
index 0000000..9b7cba3
--- /dev/null
@@ -0,0 +1,193 @@
+;;; company-elisp-tests.el --- company-elisp tests
+
+;; Copyright (C) 2013-2014  Free Software Foundation, Inc.
+
+;; Author: Dmitry Gutov
+
+;; 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/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
+
+(require 'company-elisp)
+
+(defmacro company-elisp-with-buffer (contents &rest body)
+  (declare (indent 0))
+  `(with-temp-buffer
+     (insert ,contents)
+     (setq major-mode 'emacs-lisp-mode)
+     (re-search-backward "|")
+     (replace-match "")
+     (let ((company-elisp-detect-function-context t))
+       ,@body)))
+
+(ert-deftest company-elisp-candidates-predicate ()
+  (company-elisp-with-buffer
+    "(foo ba|)"
+    (should (eq (company-elisp--candidates-predicate "ba")
+                'boundp))
+    (should (eq (let (company-elisp-detect-function-context)
+                  (company-elisp--candidates-predicate "ba"))
+                'company-elisp--predicate)))
+  (company-elisp-with-buffer
+    "(foo| )"
+    (should (eq (company-elisp--candidates-predicate "foo")
+                'fboundp))
+    (should (eq (let (company-elisp-detect-function-context)
+                  (company-elisp--candidates-predicate "foo"))
+                'company-elisp--predicate)))
+  (company-elisp-with-buffer
+    "(foo 'b|)"
+    (should (eq (company-elisp--candidates-predicate "b")
+                'company-elisp--predicate))))
+
+(ert-deftest company-elisp-candidates-predicate-in-docstring ()
+  (company-elisp-with-buffer
+   "(def foo () \"Doo be doo `ide|"
+   (should (eq 'company-elisp--predicate
+               (company-elisp--candidates-predicate "ide")))))
+
+;; This one's also an integration test.
+(ert-deftest company-elisp-candidates-recognizes-binding-form ()
+  (let ((company-elisp-detect-function-context t)
+        (obarray [when what whelp])
+        (what 1)
+        (whelp 2)
+        (wisp 3))
+    (company-elisp-with-buffer
+      "(let ((foo 7) (wh| )))"
+      (should (equal '("what" "whelp")
+                     (company-elisp-candidates "wh"))))
+    (company-elisp-with-buffer
+      "(cond ((null nil) (wh| )))"
+      (should (equal '("when")
+                     (company-elisp-candidates "wh"))))))
+
+(ert-deftest company-elisp-candidates-predicate-binding-without-value ()
+  (cl-loop for (text prefix predicate) in '(("(let (foo|" "foo" boundp)
+                                            ("(let (foo (bar|" "bar" boundp)
+                                            ("(let (foo) (bar|" "bar" fboundp))
+           do
+           (eval `(company-elisp-with-buffer
+                   ,text
+                   (should (eq ',predicate
+                               (company-elisp--candidates-predicate ,prefix)))))))
+
+(ert-deftest company-elisp-finds-vars ()
+  (let ((obarray [boo bar baz backquote])
+        (boo t)
+        (bar t)
+        (baz t))
+    (should (equal '("bar" "baz")
+                   (company-elisp--globals "ba" 'boundp)))))
+
+(ert-deftest company-elisp-finds-functions ()
+  (let ((obarray [when what whelp])
+        (what t)
+        (whelp t))
+    (should (equal '("when")
+                   (company-elisp--globals "wh" 'fboundp)))))
+
+(ert-deftest company-elisp-finds-things ()
+  (let ((obarray [when what whelp])
+        (what t)
+        (whelp t))
+    (should (equal '("what" "whelp" "when")
+                   (sort (company-elisp--globals "wh" 'company-elisp--predicate)
+                         'string<)))))
+
+(ert-deftest company-elisp-locals-vars ()
+  (company-elisp-with-buffer
+    "(let ((foo 5) (bar 6))
+       (cl-labels ((borg ()))
+         (lambda (boo baz)
+           b|)))"
+    (should (equal '("bar" "baz" "boo")
+                   (company-elisp--locals "b" nil)))))
+
+(ert-deftest company-elisp-locals-single-var ()
+  (company-elisp-with-buffer
+    "(dotimes (itk 100)
+       (dolist (item items)
+         it|))"
+    (should (equal '("itk" "item")
+                   (company-elisp--locals "it" nil)))))
+
+(ert-deftest company-elisp-locals-funs ()
+  (company-elisp-with-buffer
+    "(cl-labels ((foo ())
+                 (fee ()))
+       (let ((fun 4))
+         (f| )))"
+    (should (equal '("fee" "foo")
+                   (sort (company-elisp--locals "f" t) 'string<)))))
+
+(ert-deftest company-elisp-locals-skips-current-varlist ()
+  (company-elisp-with-buffer
+    "(let ((foo 1)
+           (f| )))"
+    (should (null (company-elisp--locals "f" nil)))))
+
+(ert-deftest company-elisp-show-locals-first ()
+  (company-elisp-with-buffer
+    "(let ((floo 1)
+           (flop 2)
+           (flee 3))
+       fl|)"
+    (let ((obarray [float-pi]))
+      (let (company-elisp-show-locals-first)
+        (should (eq nil (company-elisp 'sorted))))
+      (let ((company-elisp-show-locals-first t))
+        (should (eq t (company-elisp 'sorted)))
+        (should (equal '("flee" "floo" "flop" "float-pi")
+                       (company-elisp-candidates "fl")))))))
+
+(ert-deftest company-elisp-candidates-no-duplicates ()
+  (company-elisp-with-buffer
+    "(let ((float-pi 4))
+       f|)"
+    (let ((obarray [float-pi])
+          (company-elisp-show-locals-first t))
+      (should (equal '("float-pi") (company-elisp-candidates "f"))))))
+
+(ert-deftest company-elisp-shouldnt-complete-defun-name ()
+  (company-elisp-with-buffer
+    "(defun foob|)"
+    (should (null (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-should-complete-def-call ()
+  (company-elisp-with-buffer
+    "(defu|"
+    (should (equal "defu" (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-should-complete-in-defvar ()
+  ;; It will also complete the var name, at least for now.
+  (company-elisp-with-buffer
+    "(defvar abc de|"
+    (should (equal "de" (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-shouldnt-complete-in-defun-arglist ()
+  (company-elisp-with-buffer
+    "(defsubst foobar (ba|"
+    (should (null (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-prefix-in-defun-body ()
+  (company-elisp-with-buffer
+    "(defun foob ()|)"
+    (should (equal "" (company-elisp 'prefix)))))
index 0ea4c69403f67739b9071e971b5a235541b70695..5efd8d051e2104e803bfdb4bbd5ad161011b3c32 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 (require 'help-mode)
 (require 'find-func)
 
@@ -131,14 +131,14 @@ first in the candidates list."
                             (when (looking-at "[ \t\n]*(")
                               (down-list 1))
                             (when (looking-at regexp)
-                              (pushnew (match-string-no-properties 1) res)))
+                              (cl-pushnew (match-string-no-properties 1) res)))
                           (forward-sexp))
                       (scan-error nil)))
                    ((unless functions-p
                       (looking-at company-elisp-var-binding-regexp-1))
                     (down-list 1)
                     (when (looking-at regexp)
-                      (pushnew (match-string-no-properties 1) res)))))))))
+                      (cl-pushnew (match-string-no-properties 1) res)))))))))
       (scan-error nil))
     res))
 
@@ -146,9 +146,9 @@ first in the candidates list."
   (let* ((predicate (company-elisp--candidates-predicate prefix))
          (locals (company-elisp--locals prefix (eq predicate 'fboundp)))
          (globals (company-elisp--globals prefix predicate))
-         (locals (loop for local in locals
-                       when (not (member local globals))
-                       collect local)))
+         (locals (cl-loop for local in locals
+                          when (not (member local globals))
+                          collect local)))
     (if company-elisp-show-locals-first
         (append (sort locals 'string<)
                 (sort globals 'string<))
@@ -195,7 +195,7 @@ first in the candidates list."
 (defun company-elisp (command &optional arg &rest ignored)
   "`company-mode' completion back-end for Emacs Lisp."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-elisp))
     (prefix (and (derived-mode-p 'emacs-lisp-mode 'inferior-emacs-lisp-mode)
                  (company-elisp--prefix)))
index 0c84458a1b8f278e035a05678a3c8339d9b4d86e..8634103fe9f346df1c15819dd3294f93bec90e36 100644 (file)
@@ -25,8 +25,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
 (require 'company)
+(require 'cl-lib)
 (require 'etags)
 
 (defgroup company-etags nil
@@ -51,9 +51,9 @@ buffer automatically."
 (make-variable-buffer-local 'company-etags-buffer-table)
 
 (defun company-etags-find-table ()
-  (let ((file (company-locate-dominating-file (or buffer-file-name
-                                                  default-directory)
-                                              "TAGS")))
+  (let ((file (locate-dominating-file (or buffer-file-name
+                                          default-directory)
+                                      "TAGS")))
     (when file
       (list (expand-file-name file)))))
 
@@ -76,7 +76,7 @@ buffer automatically."
 (defun company-etags (command &optional arg &rest ignored)
   "`company-mode' completion back-end for etags."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-etags))
     (prefix (and (apply 'derived-mode-p company-etags-modes)
                  (not (company-in-string-or-comment))
index b897e3d3751404b358652bfa00f6b3ed247a0816..a839f799ee5cafe6ab3a167f50baeb628d9de174 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defun company-files-directory-files (dir prefix)
   (ignore-errors
@@ -45,9 +45,9 @@
 (defun company-files-grab-existing-name ()
   ;; Grab file names with spaces, only when they include quotes.
   (let (file dir)
-    (and (dolist (regexp company-files-regexps)
+    (and (cl-dolist (regexp company-files-regexps)
            (when (setq file (company-grab-line regexp 1))
-             (return file)))
+             (cl-return file)))
          (setq dir (file-name-directory file))
          (not (string-match "//" dir))
          (file-exists-p dir)
@@ -78,7 +78,7 @@
 (defun company-files (command &optional arg &rest ignored)
   "`company-mode' completion back-end existing file names."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-files))
     (prefix (company-files-grab-existing-name))
     (candidates (company-files-complete arg))
index 6b4e399420618407c57d2f0eb05ec1981f75fe14..0ae98d7d62e0d66a33327c27a816398b980056de 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-gtags nil
   "Completion back-end for GNU Global."
@@ -49,7 +49,7 @@
 (defun company-gtags--tags-available-p ()
   (if (eq company-gtags--tags-available-p 'unknown)
       (setq company-gtags--tags-available-p
-            (company-locate-dominating-file buffer-file-name "GTAGS"))
+            (locate-dominating-file buffer-file-name "GTAGS"))
     company-gtags--tags-available-p))
 
 (defun company-gtags-fetch-tags (prefix)
@@ -75,7 +75,7 @@
 (defun company-gtags (command &optional arg &rest ignored)
   "`company-mode' completion back-end for GNU Global."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-gtags))
     (prefix (and company-gtags-executable
                  (memq major-mode company-gtags-modes)
index 3e599f03e51fee11468c71f2c5b9724134617ba5..1561beef1a1b62e633c79ae4451c5a53d8fa1be8 100644 (file)
@@ -26,8 +26,8 @@
 ;;; Code:
 
 (require 'company)
+(require 'cl-lib)
 (require 'ispell)
-(eval-when-compile (require 'cl))
 
 (defgroup company-ispell nil
   "Completion back-end using Ispell."
@@ -56,7 +56,7 @@ If nil, use `ispell-complete-word-dict'."
 (defun company-ispell (command &optional arg &rest ignored)
   "`company-mode' completion back-end using Ispell."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-ispell))
     (prefix (when (company-ispell-available)
               (company-grab-word)))
index 461fdf6b04ec4b506073c945a7e7c952224bd737..c700af769bee7b235ae94f2dfa160092d6e5cdb7 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defun company-keywords-upper-lower (&rest lst)
   ;; Upcase order is different for _.
 (defun company-keywords (command &optional arg &rest ignored)
   "`company-mode' back-end for programming language keywords."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-keywords))
     (prefix (and (assq major-mode company-keywords-alist)
                  (not (company-in-string-or-comment))
index 62e6e31543af65d2a6df2fdff4b2b6987821c677..70e1c096bf31b561d403a5ade0d22187c5e10b3f 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defvar rng-open-elements)
 (defvar rng-validate-mode)
@@ -76,7 +76,7 @@
        ,@body)))
 
 (defun company-nxml-tag (command &optional arg &rest ignored)
-  (case command
+  (cl-case command
     (prefix (and (derived-mode-p 'nxml-mode)
                  rng-validate-mode
                  (company-grab company-nxml-in-tag-name-regexp 1)))
@@ -86,7 +86,7 @@
     (sorted t)))
 
 (defun company-nxml-attribute (command &optional arg &rest ignored)
-  (case command
+  (cl-case command
     (prefix (and (derived-mode-p 'nxml-mode)
                  rng-validate-mode
                  (memq (char-after) '(?\  ?\t ?\n)) ;; outside word
@@ -99,7 +99,7 @@
     (sorted t)))
 
 (defun company-nxml-attribute-value (command &optional arg &rest ignored)
-  (case command
+  (cl-case command
     (prefix (and (derived-mode-p 'nxml-mode)
                  rng-validate-mode
                  (and (memq (char-after) '(?' ?\" ?\  ?\t ?\n)) ;; outside word
 (defun company-nxml (command &optional arg &rest ignored)
   "`company-mode' completion back-end for `nxml-mode'."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-nxml))
     (prefix (or (company-nxml-tag 'prefix)
                 (company-nxml-attribute 'prefix)
index 358d5ea9258333584c8b82488904d635ac2d4dc7..aa30f2a296794456d2c717b934f5710d138d5f00 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 (eval-when-compile (require 'yaooddmuse nil t))
 (eval-when-compile (require 'oddmuse nil t))
 
@@ -34,7 +34,7 @@
   "\\(\\<[A-Z][[:alnum:]]*\\>\\)\\|\\[\\[\\([[:alnum:]]+\\>\\|\\)")
 
 (defun company-oddmuse-get-page-table ()
-  (case major-mode
+  (cl-case major-mode
     (yaoddmuse-mode (with-no-warnings
                       (yaoddmuse-get-pagename-table yaoddmuse-wikiname)))
     (oddmuse-mode (with-no-warnings
@@ -44,7 +44,7 @@
 (defun company-oddmuse (command &optional arg &rest ignored)
   "`company-mode' completion back-end for `oddmuse-mode'."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-oddmuse))
     (prefix (let ((case-fold-search nil))
               (and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
index 5c44f06aafa799a522dcfac1546f8e6776d31f50..2f22bf0f53d5d1501d27220b4260f7eb65220952 100644 (file)
@@ -1,6 +1,6 @@
 ;;; company-pysmell.el --- company-mode completion back-end for pysmell.el
 
-;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013-2014  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -27,8 +27,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
 (if t (require 'pysmell))               ;Don't load during compilation.
+(require 'cl-lib)
 
 (defvar company-pysmell--available-p 'unknown)
 (make-variable-buffer-local 'company-pysmell--available-p)
@@ -36,7 +36,7 @@
 (defun company-pysmell--available-p ()
   (if (eq company-pysmell--available-p 'unknown)
       (setq company-pysmell--available-p
-            (company-locate-dominating-file buffer-file-name "PYSMELLTAGS"))
+            (locate-dominating-file buffer-file-name "PYSMELLTAGS"))
     company-pysmell--available-p))
 
 (defun company-pysmell--grab-symbol ()
@@ -56,7 +56,7 @@
   "`company-mode' completion back-end for pysmell.
 This requires pysmell.el and pymacs.el."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-pysmell))
     (prefix (and (derived-mode-p 'python-mode)
                  buffer-file-name
index 0ba26e68b2a8f8ee6b0ca3801c3c7fc564bc59db..677c4536bc59aff209b3d44b7e867fcf521e123b 100644 (file)
@@ -25,7 +25,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defun company-ropemacs--grab-symbol ()
   (let ((symbol (company-grab-symbol)))
@@ -58,7 +58,7 @@
 Depends on third-party code: Pymacs (both Python and Emacs packages),
 rope, ropemacs and ropemode."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (init (when (and (derived-mode-p 'python-mode)
                      (not (fboundp 'rope-completions)))
             (require 'pymacs)
index 372a6f6c9e60ba93f007043568a3489b4d87a433..110d4fd8946adf0bb26994609bc0fca324067700 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defvar semantic-idle-summary-function)
 (declare-function semantic-documentation-for-tag "semantic/doc" )
@@ -121,7 +121,7 @@ Symbols are chained by \".\" or \"->\"."
 (defun company-semantic (command &optional arg &rest ignored)
   "`company-mode' completion back-end using CEDET Semantic."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-semantic))
     (prefix (and (featurep 'semantic)
                  (semantic-active-p)
index ab180166ca00ef7d66c02088b483adf34e4d88fb..d689183b97099b202174fcf5551bc669c578213b 100644 (file)
@@ -21,7 +21,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defface company-template-field
   '((((background dark)) (:background "yellow" :foreground "black"))
@@ -59,8 +59,8 @@
   (let* ((start (point))
          (templates (company-template-templates-at (point)))
          (minimum (apply 'max (mapcar 'overlay-end templates)))
-         (fields (loop for templ in templates
-                       append (overlay-get templ 'company-template-fields))))
+         (fields (cl-loop for templ in templates
+                          append (overlay-get templ 'company-template-fields))))
     (dolist (pos (mapcar 'overlay-start fields))
       (and pos
            (> pos (point))
@@ -71,9 +71,9 @@
     (company-template-remove-field (company-template-field-at start))))
 
 (defun company-template-field-at (&optional point)
-  (loop for ovl in (overlays-at (or point (point)))
-        when (overlay-get ovl 'company-template-parent)
-        return ovl))
+  (cl-loop for ovl in (overlays-at (or point (point)))
+           when (overlay-get ovl 'company-template-parent)
+           return ovl))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -98,7 +98,7 @@
   "Add new field to template TEMPL at POS, inserting TEXT.
 When DISPLAY is non-nil, set the respective property on the overlay.
 Leave point at the end of the field."
-  (assert templ)
+  (cl-assert templ)
   (goto-char pos)
   (insert text)
   (when (> (point) (overlay-end templ))
@@ -164,7 +164,7 @@ Leave point at the end of the field."
               (save-excursion
                 (company-template-add-field templ (match-beginning 1)
                                             (format "arg%d" cnt) sig))
-              (incf cnt)))
+              (cl-incf cnt)))
           (company-template-move-to-first templ))))))
 
 (provide 'company-template)
index feea6982a47badd018b3699074308b5b7bb8eb28..ac91988623d3d1a8ea4b926e8474d81212933b96 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 (require 'tempo)
 
 (defsubst company-tempo-lookup (match)
@@ -50,7 +50,7 @@
 (defun company-tempo (command &optional arg &rest ignored)
   "`company-mode' completion back-end for tempo."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-tempo
                                         'company-tempo-insert))
     (prefix (or (car (tempo-find-match-string tempo-match-finder)) ""))
index 5a2608632ffb0009a2b3f7f8d3deef3cd3156460..abd970423e110c6ca898e554d22edd7f1fa942fe 100644 (file)
@@ -1,4 +1,4 @@
-;;; company-tests.el --- company-mode tests
+;;; company-tests.el --- company-mode tests  -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2011, 2013-2014  Free Software Foundation, Inc.
 
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
 (require 'ert)
 (require 'company)
 (require 'company-keywords)
-(require 'company-elisp)
 (require 'company-clang)
 
 ;;; Core
 
 (ert-deftest company-good-prefix ()
   (let ((company-minimum-prefix-length 5)
-        company--explicit-action)
+        company-abort-manual-when-too-short
+        company--manual-action            ;idle begin
+        (company-selection-changed t))    ;has no effect
     (should (eq t (company--good-prefix-p "!@#$%")))
     (should (eq nil (company--good-prefix-p "abcd")))
     (should (eq nil (company--good-prefix-p 'stop)))
     (should (eq t (company--good-prefix-p '("foo" . 5))))
-    (should (eq nil (company--good-prefix-p '("foo" . 4))))))
+    (should (eq nil (company--good-prefix-p '("foo" . 4))))
+    (should (eq t (company--good-prefix-p '("foo" . t))))))
+
+(ert-deftest company--manual-prefix-set-and-unset ()
+  (with-temp-buffer
+    (insert "ab")
+    (company-mode)
+    (let (company-frontends
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (cl-case command
+                     (prefix (buffer-substring (point-min) (point)))
+                     (candidates '("abc" "abd")))))))
+      (company-manual-begin)
+      (should (equal "ab" company--manual-prefix))
+      (company-abort)
+      (should (null company--manual-prefix)))))
+
+(ert-deftest company-abort-manual-when-too-short ()
+  (let ((company-minimum-prefix-length 5)
+        (company-abort-manual-when-too-short t)
+        (company-selection-changed t))    ;has not effect
+    (let ((company--manual-action nil))   ;idle begin
+      (should (eq t (company--good-prefix-p "!@#$%")))
+      (should (eq t (company--good-prefix-p '("foo" . 5))))
+      (should (eq t (company--good-prefix-p '("foo" . t)))))
+    (let ((company--manual-action t)
+          (company--manual-prefix "abc")) ;manual begin from this prefix
+      (should (eq t (company--good-prefix-p "!@#$")))
+      (should (eq nil (company--good-prefix-p "ab")))
+      (should (eq nil (company--good-prefix-p 'stop)))
+      (should (eq t (company--good-prefix-p '("foo" . 4))))
+      (should (eq t (company--good-prefix-p "abcd")))
+      (should (eq t (company--good-prefix-p "abc")))
+      (should (eq t (company--good-prefix-p '("bar" . t)))))))
 
 (ert-deftest company-multi-backend-with-lambdas ()
   (let ((company-backend
          (list (lambda (command &optional arg &rest ignore)
-                 (case command
+                 (cl-case command
                    (prefix "z")
                    (candidates '("a" "b"))))
                (lambda (command &optional arg &rest ignore)
-                 (case command
+                 (cl-case command
                    (prefix "z")
                    (candidates '("c" "d")))))))
     (should (equal (company-call-backend 'candidates "z") '("a" "b" "c" "d")))))
 
 (ert-deftest company-multi-backend-remembers-candidate-backend ()
   (let ((company-backend
-         (list (lambda (command &optional arg &rest ignore)
-                 (case command
+         (list (lambda (command &optional arg)
+                 (cl-case command
                    (ignore-case nil)
                    (annotation "1")
                    (candidates '("a" "c"))
                    (post-completion "13")))
-               (lambda (command &optional arg &rest ignore)
-                 (case command
+               (lambda (command &optional arg)
+                 (cl-case command
                    (ignore-case t)
                    (annotation "2")
                    (candidates '("b" "d"))
-                   (post-completion "42"))))))
+                   (post-completion "42")))
+               (lambda (command &optional arg)
+                 (cl-case command
+                   (annotation "3")
+                   (candidates '("e"))
+                   (post-completion "74"))))))
     (let ((candidates (company-calculate-candidates nil)))
-      (should (equal candidates '("a" "b" "c" "d")))
+      (should (equal candidates '("a" "b" "c" "d" "e")))
       (should (equal t (company-call-backend 'ignore-case)))
       (should (equal "1" (company-call-backend 'annotation (nth 0 candidates))))
       (should (equal "2" (company-call-backend 'annotation (nth 1 candidates))))
       (should (equal "13" (company-call-backend 'post-completion (nth 2 candidates))))
-      (should (equal "42" (company-call-backend 'post-completion (nth 3 candidates)))))))
+      (should (equal "42" (company-call-backend 'post-completion (nth 3 candidates))))
+      (should (equal "3" (company-call-backend 'annotation (nth 4 candidates))))
+      (should (equal "74" (company-call-backend 'post-completion (nth 4 candidates)))))))
 
 (ert-deftest company-multi-backend-handles-keyword-with ()
   (let ((primo (lambda (command &optional arg)
-                 (case command
+                 (cl-case command
                    (prefix "a")
                    (candidates '("abb" "abc" "abd")))))
         (secundo (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix "a")
                      (candidates '("acc" "acd"))))))
     (let ((company-backend (list 'ignore 'ignore :with secundo)))
     (let (company-frontends
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix "a")
                      (candidates '("a" "ab" "ac")))))))
       (let (this-command)
           (company-require-match 'company-explicit-action-p)
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abc" "abd")))))))
       (let (this-command)
           (company-require-match 'company-explicit-action-p)
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abc" "abd")))))))
       (company-idle-begin (current-buffer) (selected-window)
           company-begin-commands
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abc" "abd")))))))
       (let ((company-continue-commands nil))
           company-begin-commands
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abc" "abd")))))))
       (let ((company-continue-commands '(not backward-delete-char)))
           (company-auto-complete-chars '(? ))
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abcd" "abef")))))))
       (let (this-command)
           (company-auto-complete-chars '(? ))
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abcd" "abef")))))))
       (company-idle-begin (current-buffer) (selected-window)
           company-end-of-buffer-workaround
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abcd" "abef"))
                      (ignore-case t))))))
     (let (company-frontends
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("abcd" "abef"))
                      (ignore-case 'keep-prefix))))))
           company-end-of-buffer-workaround
           (company-backends
            (list (lambda (command &optional arg)
-                   (case command
+                   (cl-case command
                      (prefix (buffer-substring (point-min) (point)))
                      (candidates '("tea-cup" "teal-color")))))))
       (let (this-command)
             (company-begin-commands '(self-insert-command))
             (company-backends
              (list (lambda (c &optional arg)
-                     (case c (prefix "") (candidates '("a" "b" "c")))))))
+                     (cl-case c (prefix "") (candidates '("a" "b" "c")))))))
         (let (this-command)
           (company-call 'complete))
         (company-call 'open-line 1)
   (should (equal '(1 . 2) (company--scrollbar-bounds 3 4 12)))
   (should (equal '(1 . 3) (company--scrollbar-bounds 4 5 11))))
 
+;;; Async
+
+(defun company-async-backend (command &optional arg)
+  (pcase command
+    (`prefix "foo")
+    (`candidates
+     (cons :async
+           (lambda (cb)
+             (run-with-timer 0.05 nil
+                             #'funcall cb '("abc" "abd")))))))
+
+(ert-deftest company-call-backend-forces-sync ()
+  (let ((company-backend 'company-async-backend)
+        (company-async-timeout 0.1))
+    (should (equal '("abc" "abd") (company-call-backend 'candidates)))))
+
+(ert-deftest company-call-backend-errors-on-timeout ()
+  (with-temp-buffer
+    (let* ((company-backend (lambda (command &optional _arg)
+                              (pcase command
+                                (`candidates (cons :async 'ignore)))))
+           (company-async-timeout 0.1)
+           (err (should-error (company-call-backend 'candidates "foo"))))
+      (should (string-match-p "async timeout" (cadr err))))))
+
+(ert-deftest company-call-backend-raw-passes-return-value-verbatim ()
+  (let ((company-backend 'company-async-backend))
+    (should (equal "foo" (company-call-backend-raw 'prefix)))
+    (should (equal :async (car (company-call-backend-raw 'candidates "foo"))))
+    (should (equal 'closure (cadr (company-call-backend-raw 'candidates "foo"))))))
+
+(ert-deftest company-manual-begin-forces-async-candidates-to-sync ()
+  (with-temp-buffer
+    (company-mode)
+    (let (company-frontends
+          (company-backends (list 'company-async-backend)))
+      (company-manual-begin)
+      (should (equal "foo" company-prefix))
+      (should (equal '("abc" "abd") company-candidates)))))
+
+(ert-deftest company-idle-begin-allows-async-candidates ()
+  (with-temp-buffer
+    (company-mode)
+    (let (company-frontends
+          (company-backends (list 'company-async-backend)))
+      (company-idle-begin (current-buffer) (selected-window)
+                          (buffer-chars-modified-tick) (point))
+      (should (null company-candidates))
+      (sleep-for 0.1)
+      (should (equal "foo" company-prefix))
+      (should (equal '("abc" "abd") company-candidates)))))
+
+(ert-deftest company-idle-begin-cancels-async-candidates-if-buffer-changed ()
+  (with-temp-buffer
+    (company-mode)
+    (let (company-frontends
+          (company-backends (list 'company-async-backend)))
+      (company-idle-begin (current-buffer) (selected-window)
+                          (buffer-chars-modified-tick) (point))
+      (should (null company-candidates))
+      (insert "a")
+      (sleep-for 0.1)
+      (should (null company-prefix))
+      (should (null company-candidates)))))
+
+(ert-deftest company-idle-begin-async-allows-immediate-callbacks ()
+  (with-temp-buffer
+    (company-mode)
+    (let (company-frontends
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (pcase command
+                     (`prefix (buffer-substring (point-min) (point)))
+                     (`candidates
+                      (let ((c (all-completions arg '("abc" "def"))))
+                        (cons :async
+                              (lambda (cb) (funcall cb c)))))
+                     (`no-cache t)))))
+          (company-minimum-prefix-length 0))
+      (company-idle-begin (current-buffer) (selected-window)
+                          (buffer-chars-modified-tick) (point))
+      (should (equal '("abc" "def") company-candidates))
+      (let ((last-command-event ?a))
+        (company-call 'self-insert-command 1))
+      (should (equal '("abc") company-candidates)))))
+
+(ert-deftest company-multi-backend-forces-prefix-to-sync ()
+  (with-temp-buffer
+    (let ((company-backend (list 'ignore
+                                 (lambda (command)
+                                   (should (eq command 'prefix))
+                                   (cons :async
+                                         (lambda (cb)
+                                           (run-with-timer
+                                            0.01 nil
+                                            (lambda () (funcall cb nil))))))
+                                 (lambda (command)
+                                   (should (eq command 'prefix))
+                                   "foo"))))
+      (should (equal "foo" (company-call-backend-raw 'prefix))))
+    (let ((company-backend (list (lambda (_command)
+                                   (cons :async
+                                         (lambda (cb)
+                                           (run-with-timer
+                                            0.01 nil
+                                            (lambda () (funcall cb "bar"))))))
+                                 (lambda (_command)
+                                   "foo"))))
+      (should (equal "bar" (company-call-backend-raw 'prefix))))))
+
+(ert-deftest company-multi-backend-merges-deferred-candidates ()
+  (with-temp-buffer
+    (let* ((immediate (lambda (command &optional arg)
+                        (pcase command
+                          (`prefix "foo")
+                          (`candidates
+                           (cons :async
+                                 (lambda (cb) (funcall cb '("f"))))))))
+           (company-backend (list 'ignore
+                                  (lambda (command &optional arg)
+                                    (pcase command
+                                      (`prefix "foo")
+                                      (`candidates
+                                       (should (equal arg "foo"))
+                                       (cons :async
+                                             (lambda (cb)
+                                               (run-with-timer
+                                                0.01 nil
+                                                (lambda () (funcall cb '("a" "b")))))))))
+                                  (lambda (command &optional arg)
+                                    (pcase command
+                                      (`prefix "foo")
+                                      (`candidates '("c" "d" "e"))))
+                                  immediate)))
+      (should (equal :async (car (company-call-backend-raw 'candidates "foo"))))
+      (should (equal '("a" "b" "c" "d" "e" "f")
+                     (company-call-backend 'candidates "foo")))
+      (let ((company-backend (list immediate)))
+        (should (equal '("f") (company-call-backend 'candidates "foo")))))))
+
 ;;; Template
 
 (ert-deftest company-template-removed-after-the-last-jump ()
       (should (equal "foo(arg0, arg1)" (buffer-string)))
       (should (looking-at "arg0")))))
 
-;;; Elisp
-
-(defmacro company-elisp-with-buffer (contents &rest body)
-  (declare (indent 0))
-  `(with-temp-buffer
-     (insert ,contents)
-     (setq major-mode 'emacs-lisp-mode)
-     (re-search-backward "|")
-     (replace-match "")
-     (let ((company-elisp-detect-function-context t))
-       ,@body)))
-
-(ert-deftest company-elisp-candidates-predicate ()
-  (company-elisp-with-buffer
-    "(foo ba|)"
-    (should (eq (company-elisp--candidates-predicate "ba")
-                'boundp))
-    (should (eq (let (company-elisp-detect-function-context)
-                  (company-elisp--candidates-predicate "ba"))
-                'company-elisp--predicate)))
-  (company-elisp-with-buffer
-    "(foo| )"
-    (should (eq (company-elisp--candidates-predicate "foo")
-                'fboundp))
-    (should (eq (let (company-elisp-detect-function-context)
-                  (company-elisp--candidates-predicate "foo"))
-                'company-elisp--predicate)))
-  (company-elisp-with-buffer
-    "(foo 'b|)"
-    (should (eq (company-elisp--candidates-predicate "b")
-                'company-elisp--predicate))))
-
-(ert-deftest company-elisp-candidates-predicate-in-docstring ()
-  (company-elisp-with-buffer
-   "(def foo () \"Doo be doo `ide|"
-   (should (eq 'company-elisp--predicate
-               (company-elisp--candidates-predicate "ide")))))
-
-;; This one's also an integration test.
-(ert-deftest company-elisp-candidates-recognizes-binding-form ()
-  (let ((company-elisp-detect-function-context t)
-        (obarray [when what whelp])
-        (what 1)
-        (whelp 2)
-        (wisp 3))
-    (company-elisp-with-buffer
-      "(let ((foo 7) (wh| )))"
-      (should (equal '("what" "whelp")
-                     (company-elisp-candidates "wh"))))
-    (company-elisp-with-buffer
-      "(cond ((null nil) (wh| )))"
-      (should (equal '("when")
-                     (company-elisp-candidates "wh"))))))
-
-(ert-deftest company-elisp-candidates-predicate-binding-without-value ()
-  (loop for (text prefix predicate) in '(("(let (foo|" "foo" boundp)
-                                         ("(let (foo (bar|" "bar" boundp)
-                                         ("(let (foo) (bar|" "bar" fboundp))
-        do
-        (eval `(company-elisp-with-buffer
-                 ,text
-                 (should (eq ',predicate
-                             (company-elisp--candidates-predicate ,prefix)))))))
-
-(ert-deftest company-elisp-finds-vars ()
-  (let ((obarray [boo bar baz backquote])
-        (boo t)
-        (bar t)
-        (baz t))
-    (should (equal '("bar" "baz")
-                   (company-elisp--globals "ba" 'boundp)))))
-
-(ert-deftest company-elisp-finds-functions ()
-  (let ((obarray [when what whelp])
-        (what t)
-        (whelp t))
-    (should (equal '("when")
-                   (company-elisp--globals "wh" 'fboundp)))))
-
-(ert-deftest company-elisp-finds-things ()
-  (let ((obarray [when what whelp])
-        (what t)
-        (whelp t))
-    (should (equal '("what" "whelp" "when")
-                   (sort (company-elisp--globals "wh" 'company-elisp--predicate)
-                         'string<)))))
-
-(ert-deftest company-elisp-locals-vars ()
-  (company-elisp-with-buffer
-    "(let ((foo 5) (bar 6))
-       (cl-labels ((borg ()))
-         (lambda (boo baz)
-           b|)))"
-    (should (equal '("bar" "baz" "boo")
-                   (company-elisp--locals "b" nil)))))
-
-(ert-deftest company-elisp-locals-single-var ()
-  (company-elisp-with-buffer
-    "(dotimes (itk 100)
-       (dolist (item items)
-         it|))"
-    (should (equal '("itk" "item")
-                   (company-elisp--locals "it" nil)))))
-
-(ert-deftest company-elisp-locals-funs ()
-  (company-elisp-with-buffer
-    "(cl-labels ((foo ())
-                 (fee ()))
-       (let ((fun 4))
-         (f| )))"
-    (should (equal '("fee" "foo")
-                   (sort (company-elisp--locals "f" t) 'string<)))))
-
-(ert-deftest company-elisp-locals-skips-current-varlist ()
-  (company-elisp-with-buffer
-    "(let ((foo 1)
-           (f| )))"
-    (should (null (company-elisp--locals "f" nil)))))
-
-(ert-deftest company-elisp-show-locals-first ()
-  (company-elisp-with-buffer
-    "(let ((floo 1)
-           (flop 2)
-           (flee 3))
-       fl|)"
-    (let ((obarray [float-pi]))
-      (let (company-elisp-show-locals-first)
-        (should (eq nil (company-elisp 'sorted))))
-      (let ((company-elisp-show-locals-first t))
-        (should (eq t (company-elisp 'sorted)))
-        (should (equal '("flee" "floo" "flop" "float-pi")
-                       (company-elisp-candidates "fl")))))))
-
-(ert-deftest company-elisp-candidates-no-duplicates ()
-  (company-elisp-with-buffer
-    "(let ((float-pi 4))
-       f|)"
-    (let ((obarray [float-pi])
-          (company-elisp-show-locals-first t))
-      (should (equal '("float-pi") (company-elisp-candidates "f"))))))
-
-(ert-deftest company-elisp-shouldnt-complete-defun-name ()
-  (company-elisp-with-buffer
-    "(defun foob|)"
-    (should (null (company-elisp 'prefix)))))
-
-(ert-deftest company-elisp-should-complete-def-call ()
-  (company-elisp-with-buffer
-    "(defu|"
-    (should (equal "defu" (company-elisp 'prefix)))))
-
-(ert-deftest company-elisp-should-complete-in-defvar ()
-  ;; It will also complete the var name, at least for now.
-  (company-elisp-with-buffer
-    "(defvar abc de|"
-    (should (equal "de" (company-elisp 'prefix)))))
-
-(ert-deftest company-elisp-shouldnt-complete-in-defun-arglist ()
-  (company-elisp-with-buffer
-    "(defsubst foobar (ba|"
-    (should (null (company-elisp 'prefix)))))
-
-(ert-deftest company-elisp-prefix-in-defun-body ()
-  (company-elisp-with-buffer
-    "(defun foob ()|)"
-    (should (equal "" (company-elisp 'prefix)))))
-
 ;;; Clang
 
 (ert-deftest company-clang-objc-templatify ()
index ac8d133454e8626ae49ac3cecaf560df2a583fb1..7a985aaedc2e183bb419a1dc41b7391378738e61 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'company)
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 
 (defgroup company-xcode nil
   "Completion back-end for Xcode projects."
@@ -109,7 +109,7 @@ valid in most contexts."
 (defun company-xcode (command &optional arg &rest ignored)
   "`company-mode' completion back-end for Xcode projects."
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-xcode))
     (prefix (and company-xcode-xcodeindex-executable
                  (company-xcode-tags)
index ae370c78feca440e0eb64cc024604e3fd88fb111..4730b211b7989e09d2639155a511b1154d79ccf6 100644 (file)
@@ -25,6 +25,7 @@
 
 ;;; Code:
 
+(require 'cl-lib)
 (require 'yasnippet)
 
 (defun company-yasnippet--candidates (prefix)
@@ -74,7 +75,7 @@ shadow back-ends that come after it.  Recommended usages:
   (global-set-key (kbd \"C-c y\") 'company-yasnippet)
 "
   (interactive (list 'interactive))
-  (case command
+  (cl-case command
     (interactive (company-begin-backend 'company-yasnippet))
     (prefix
      ;; Should probably use `yas--current-key', but that's bound to be slower.
index a633af3aee97cc0d6b24b394f6892b9786c5ed04..632b7dc64de6b179e7de1628e9f789f2e789dec1 100644 (file)
@@ -1,13 +1,13 @@
-;;; company.el --- Modular in-buffer completion framework  -*- lexical-binding: t -*-
+;;; company.el --- Modular text completion framework  -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2009-2014  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <dgutov@yandex.ru>
-;; Version: 0.7.3
-;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.io/
-;; Compatibility: GNU Emacs 23.x, GNU Emacs 24.x
+;; Version: 0.8.0
+;; Keywords: abbrev, convenience, matching
+;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
 
 ;; This file is part of GNU Emacs.
 
 ;; Here is a simple example completing "foo":
 ;;
 ;; (defun company-my-backend (command &optional arg &rest ignored)
-;;   (case command
-;;     (prefix (when (looking-back "foo\\>")
+;;   (pcase command
+;;     (`prefix (when (looking-back "foo\\>")
 ;;               (match-string 0)))
-;;     (candidates (list "foobar" "foobaz" "foobarbaz"))
-;;     (meta (format "This value is named %s" arg))))
+;;     (`candidates (list "foobar" "foobaz" "foobarbaz"))
+;;     (`meta (format "This value is named %s" arg))))
 ;;
 ;; 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).
@@ -69,7 +69,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(require 'cl-lib)
 (require 'newcomment)
 
 ;; FIXME: Use `user-error'.
@@ -244,6 +244,11 @@ The visualized data is stored in `company-prefix', `company-candidates',
 If this many lines are not available, prefer to display the tooltip above."
   :type 'integer)
 
+(defcustom company-tooltip-minimum-width 0
+  "The minimum width of the tooltip's inner area.
+This doesn't include the margins and the scroll bar."
+  :type 'integer)
+
 (defcustom company-tooltip-margin 1
   "Width of margin columns to show around the toolip."
   :type 'integer)
@@ -286,22 +291,19 @@ If this many lines are not available, prefer to display the tooltip above."
 
 (defun company-safe-backends-p (backends)
   (and (consp backends)
-       (not (dolist (backend backends)
+       (not (cl-dolist (backend backends)
               (unless (if (consp backend)
                           (company-safe-backends-p backend)
                         (assq backend company-safe-backends))
-                (return t))))))
-
-(defvar company--include-capf (version< "24.3.50" emacs-version))
+                (cl-return t))))))
 
-(defcustom company-backends `(,@(unless company--include-capf
+(defcustom company-backends `(,@(unless (version< "24.3.50" emacs-version)
                                   (list 'company-elisp))
                               company-bbdb
                               company-nxml company-css
                               company-eclim company-semantic company-clang
                               company-xcode company-ropemacs company-cmake
-                              ,@(when company--include-capf
-                                  (list 'company-capf))
+                              company-capf
                               (company-dabbrev-code company-gtags company-etags
                                company-keywords)
                               company-oddmuse company-files company-dabbrev)
@@ -395,7 +397,18 @@ The latter is the case for the `prefix' command.  But if the group contains
 the keyword `:with', the back-ends after it are ignored for this command.
 
 The completions from back-ends in a group are merged (but only from those
-that return the same `prefix')."
+that return the same `prefix').
+
+Asynchronous back-ends:
+
+The return value of each command can also be a cons (:async . FETCHER)
+where FETCHER is a function of one argument, CALLBACK.  When the data
+arrives, FETCHER must call CALLBACK and pass it the appropriate return
+value, as described above.
+
+True asynchronous operation is only supported for command `candidates', and
+only during idle completion.  Other commands will block the user interface,
+even if the back-end uses the asynchronous calling convention."
   :type `(repeat
           (choice
            :tag "Back-end"
@@ -445,6 +458,12 @@ back-end, consider using the `post-completion' command instead."
   "The minimum prefix length for idle completion."
   :type '(integer :tag "prefix length"))
 
+(defcustom company-abort-manual-when-too-short nil
+  "If enabled, cancel a manually started completion when the prefix gets
+shorter than both `company-minimum-prefix-length' and the length of the
+prefix it was started from."
+  :type 'boolean)
+
 (defcustom company-require-match 'company-explicit-action-p
   "If enabled, disallow non-matching input.
 This can be a function do determine if a match is required.
@@ -496,7 +515,7 @@ A character that is part of a valid candidate never triggers auto-completion."
                       (const :tag "Generic comment fence." ?!))
                  (function :tag "Predicate function")))
 
-(defcustom company-idle-delay .7
+(defcustom company-idle-delay .5
   "The idle delay in seconds until completion starts automatically.
 A value of nil means no idle completion, t means show candidates
 immediately when a prefix of `company-minimum-prefix-length' is reached."
@@ -544,6 +563,13 @@ commands in the `company-' namespace, abort completion."
   "Work around a visualization bug when completing at the end of the buffer.
 The work-around consists of adding a newline.")
 
+(defvar company-async-wait 0.03
+  "Pause between checks to see if the value's been set when turning an
+asynchronous call into synchronous.")
+
+(defvar company-async-timeout 2
+  "Maximum wait time for a value to be set during asynchronous call.")
+
 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-mode-map (make-sparse-keymap)
@@ -595,12 +621,12 @@ 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)))
-       (pushnew backend company--disabled-backends)
+       (cl-pushnew backend company--disabled-backends)
        nil)))
    ;; No initialization for lambdas.
    ((functionp backend) t)
    (t ;; Must be a list.
-    (dolist (b backend)
+    (cl-dolist (b backend)
       (unless (keywordp b)
         (company-init-backend b))))))
 
@@ -760,67 +786,126 @@ means that `company-mode' is always turned on except in `message-mode' buffers."
     (unless (and (char-after) (eq (char-syntax (char-after)) ?w))
       "")))
 
+(defun company-grab-symbol-cons (idle-begin-after-re &optional max-len)
+  (let ((symbol (company-grab-symbol)))
+    (when symbol
+      (save-excursion
+        (forward-char (- (length symbol)))
+        (if (looking-back idle-begin-after-re (if max-len
+                                                  (- (point) max-len)
+                                                (line-beginning-position)))
+            (cons symbol t)
+          symbol)))))
+
 (defun company-in-string-or-comment ()
   (let ((ppss (syntax-ppss)))
     (or (car (setq ppss (nthcdr 3 ppss)))
         (car (setq ppss (cdr ppss)))
         (nth 3 ppss))))
 
-(if (fboundp 'locate-dominating-file)
-    (defalias 'company-locate-dominating-file 'locate-dominating-file)
-  (defun company-locate-dominating-file (file name)
-    (catch 'root
-      (let ((dir (file-name-directory file))
-            (prev-dir nil))
-        (while (not (equal dir prev-dir))
-          (when (file-exists-p (expand-file-name name dir))
-            (throw 'root dir))
-          (setq prev-dir dir
-                dir (file-name-directory (directory-file-name dir))))))))
-
 (defun company-call-backend (&rest args)
+  (company--force-sync #'company-call-backend-raw args company-backend))
+
+(defun company--force-sync (fun args backend)
+  (let ((value (apply fun args)))
+    (if (not (eq (car-safe value) :async))
+        value
+      (let ((res 'trash)
+            (start (time-to-seconds)))
+        (funcall (cdr value)
+                 (lambda (result) (setq res result)))
+        (while (eq res 'trash)
+          (if (> (- (time-to-seconds) start) company-async-timeout)
+              (error "Company: Back-end %s async timeout with args %s"
+                     backend args)
+            (sleep-for company-async-wait)))
+        res))))
+
+(defun company-call-backend-raw (&rest args)
   (condition-case err
       (if (functionp company-backend)
           (apply company-backend args)
-        (apply 'company--multi-backend-adapter company-backend args))
+        (apply #'company--multi-backend-adapter company-backend args))
     (error (error "Company: Back-end %s error \"%s\" with args %s"
-                    company-backend (error-message-string err) args))))
+                  company-backend (error-message-string err) args))))
 
 (defun company--multi-backend-adapter (backends command &rest args)
-  (let ((backends (loop for b in backends
-                        when (not (and (symbolp b)
-                                       (eq 'failed (get b 'company-init))))
-                        collect b)))
+  (let ((backends (cl-loop for b in backends
+                           when (not (and (symbolp b)
+                                          (eq 'failed (get b 'company-init))))
+                           collect b)))
     (setq backends
           (if (eq command 'prefix)
               (butlast backends (length (member :with backends)))
             (delq :with backends)))
-    (case command
-      (candidates
-       ;; Small perf optimization: don't tag the candidates received
-       ;; from the first backend in the group.
-       (append (apply (car backends) 'candidates args)
-               (loop for backend in (cdr backends)
-                     when (equal (funcall backend 'prefix)
-                                 (car args))
-                     append (mapcar
-                             (lambda (str)
-                               (propertize str 'company-backend backend))
-                             (apply backend 'candidates args)))))
-      (sorted nil)
-      (duplicates t)
-      ((prefix ignore-case no-cache require-match)
+    (pcase command
+      (`candidates
+       (company--multi-backend-adapter-candidates backends (car args)))
+      (`sorted nil)
+      (`duplicates t)
+      ((or `prefix `ignore-case `no-cache `require-match)
        (let (value)
-         (dolist (backend backends)
-           (when (setq value (apply backend command args))
-             (return value)))))
-      (otherwise
+         (cl-dolist (backend backends)
+           (when (setq value (company--force-sync
+                              backend (cons command args) backend))
+             (cl-return value)))))
+      (_
        (let ((arg (car args)))
          (when (> (length arg) 0)
            (let ((backend (or (get-text-property 0 'company-backend arg)
                               (car backends))))
              (apply backend command args))))))))
 
+(defun company--multi-backend-adapter-candidates (backends prefix)
+  (let ((pairs (cl-loop for backend in (cdr backends)
+                        when (equal (funcall backend 'prefix)
+                                    prefix)
+                        collect (cons (funcall backend 'candidates prefix)
+                                      (let ((b backend))
+                                        (lambda (candidates)
+                                          (mapcar
+                                           (lambda (str)
+                                             (propertize str 'company-backend b))
+                                           candidates)))))))
+    (when (equal (funcall (car backends) 'prefix) prefix)
+      ;; Small perf optimization: don't tag the candidates received
+      ;; from the first backend in the group.
+      (push (cons (funcall (car backends) 'candidates prefix)
+                  'identity)
+            pairs))
+    (company--merge-async pairs (lambda (values) (apply #'append values)))))
+
+(defun company--merge-async (pairs merger)
+  (let ((async (cl-loop for pair in pairs
+                        thereis
+                        (eq :async (car-safe (car pair))))))
+    (if (not async)
+        (funcall merger (cl-loop for (val . mapper) in pairs
+                                 collect (funcall mapper val)))
+      (cons
+       :async
+       (lambda (callback)
+         (let* (lst pending
+                (finisher (lambda ()
+                            (unless pending
+                              (funcall callback
+                                       (funcall merger
+                                                (nreverse lst)))))))
+           (dolist (pair pairs)
+             (let ((val (car pair))
+                   (mapper (cdr pair)))
+               (if (not (eq :async (car-safe val)))
+                   (push (funcall mapper val) lst)
+                 (push nil lst)
+                 (let ((cell lst)
+                       (fetcher (cdr val)))
+                   (push fetcher pending)
+                   (funcall fetcher
+                            (lambda (res)
+                              (setq pending (delq fetcher pending))
+                              (setcar cell (funcall mapper res))
+                              (funcall finisher)))))))))))))
+
 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-prefix nil)
@@ -847,9 +932,12 @@ means that `company-mode' is always turned on except in `message-mode' buffers."
 (defvar company-selection-changed nil)
 (make-variable-buffer-local 'company-selection-changed)
 
-(defvar company--explicit-action nil
-  "Non-nil, if explicit completion took place.")
-(make-variable-buffer-local 'company--explicit-action)
+(defvar company--manual-action nil
+  "Non-nil, if manual completion took place.")
+(make-variable-buffer-local 'company--manual-action)
+
+(defvar company--manual-prefix nil)
+(make-variable-buffer-local 'company--manual-prefix)
 
 (defvar company--auto-completion nil
   "Non-nil when current candidate is being inserted automatically.
@@ -892,7 +980,7 @@ can retrieve meta-data for them."
 
 (defun company-explicit-action-p ()
   "Return whether explicit completion action was taken by the user."
-  (or company--explicit-action
+  (or company--manual-action
       company-selection-changed))
 
 (defun company-reformat (candidate)
@@ -957,7 +1045,7 @@ can retrieve meta-data for them."
               company-candidates candidates)
         (when selected
           (while (and candidates (string< (pop candidates) selected))
-            (incf company-selection))
+            (cl-incf company-selection))
           (unless candidates
             ;; Make sure selection isn't out of bounds.
             (setq company-selection (min (1- company-candidates-length)
@@ -974,20 +1062,14 @@ can retrieve meta-data for them."
     ;; `company-complete-common'.
     (setq company-common
           (if (cdr company-candidates)
-              (company--safe-candidate
-               (let ((common (try-completion company-prefix company-candidates)))
-                 (if (eq common t)
-                     ;; Mulple equal strings, probably with different
-                     ;; annotations.
-                     company-prefix
-                   common)))
+              (let ((common (try-completion company-prefix company-candidates)))
+                (if (eq common t)
+                    ;; Mulple equal strings, probably with different
+                    ;; annotations.
+                    company-prefix
+                  common))
             (car company-candidates)))))
 
-(defun company--safe-candidate (str)
-  ;; XXX: This feature is deprecated.
-  (or (company-call-backend 'crop str)
-      str))
-
 (defun company-calculate-candidates (prefix)
   (let ((candidates (cdr (assoc prefix company-candidates-cache)))
         (ignore-case (company-call-backend 'ignore-case)))
@@ -996,22 +1078,15 @@ can retrieve meta-data for them."
           (let ((len (length prefix))
                 (completion-ignore-case ignore-case)
                 prev)
-            (dotimes (i (1+ len))
+            (cl-dotimes (i (1+ len))
               (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
                                            company-candidates-cache)))
                 (setq candidates (all-completions prefix prev))
-                (return t)))))
+                (cl-return t)))))
         ;; no cache match, call back-end
-        (progn
-          (setq candidates (company-call-backend 'candidates prefix))
-          (when company-candidates-predicate
-            (setq candidates
-                  (company-apply-predicate candidates
-                                           company-candidates-predicate)))
-          (unless (company-call-backend 'sorted)
-            (setq candidates (sort candidates 'string<)))
-          (when (company-call-backend 'duplicates)
-            (company--strip-duplicates candidates))))
+        (setq candidates
+              (company--process-candidates
+               (company--fetch-candidates prefix))))
     (setq candidates (company--transform-candidates candidates))
     (when candidates
       (if (or (cdr candidates)
@@ -1021,6 +1096,47 @@ can retrieve meta-data for them."
         ;; Already completed and unique; don't start.
         t))))
 
+(defun company--fetch-candidates (prefix)
+  (let ((c (if company--manual-action
+               (company-call-backend 'candidates prefix)
+             (company-call-backend-raw 'candidates prefix)))
+        res)
+    (if (not (eq (car c) :async))
+        c
+      (let ((buf (current-buffer))
+            (win (selected-window))
+            (tick (buffer-chars-modified-tick))
+            (pt (point))
+            (backend company-backend))
+        (funcall
+         (cdr c)
+         (lambda (candidates)
+           (if (not (and candidates (eq res 'done)))
+               ;; Fetcher called us right back.
+               (setq res candidates)
+             (setq company-backend backend
+                   company-candidates-cache
+                   (list (cons prefix
+                               (company--process-candidates
+                                candidates))))
+             (company-idle-begin buf win tick pt)))))
+      ;; FIXME: Relying on the fact that the callers
+      ;; will interpret nil as "do nothing" is shaky.
+      ;; A throw-catch would be one possible improvement.
+      (or res
+          (progn (setq res 'done) nil)))))
+
+(defun company--process-candidates (candidates)
+  (when company-candidates-predicate
+    (setq candidates
+          (company-apply-predicate candidates
+                                   company-candidates-predicate)))
+  (unless (company-call-backend 'sorted)
+    (setq candidates (sort candidates 'string<)))
+  (when (company-call-backend 'duplicates)
+    (company--strip-duplicates candidates))
+  candidates)
+
 (defun company--strip-duplicates (candidates)
   (let ((c2 candidates))
     (while c2
@@ -1054,7 +1170,7 @@ point. The rest of the list is appended unchanged.
 Keywords and function definition names are ignored."
   (let* (occurs
          (noccurs
-          (delete-if
+          (cl-delete-if
            (lambda (candidate)
              (when (or
                     (save-excursion
@@ -1088,7 +1204,6 @@ Keywords and function definition names are ignored."
        (eq win (selected-window))
        (eq tick (buffer-chars-modified-tick))
        (eq pos (point))
-       (not (equal (point) company-point))
        (when (company-auto-begin)
          (when (version< emacs-version "24.3.50")
            (company-input-noop))
@@ -1099,7 +1214,7 @@ Keywords and function definition names are ignored."
        (not company-candidates)
        (let ((company-idle-delay t)
              (company-begin-commands t))
-         (condition-case-no-debug err
+         (condition-case-unless-debug err
              (company-begin)
            (error (message "Company: An error occurred in auto-begin")
                   (message "%s" (error-message-string err))
@@ -1113,27 +1228,27 @@ Keywords and function definition names are ignored."
 (defun company-manual-begin ()
   (interactive)
   (company-assert-enabled)
-  (setq company--explicit-action t)
+  (setq company--manual-action t)
   (unwind-protect
       (let ((company-minimum-prefix-length 0))
         (company-auto-begin))
     (unless company-candidates
-      (setq company--explicit-action nil))))
+      (setq company--manual-action nil))))
 
 (defun company-other-backend (&optional backward)
   (interactive (list current-prefix-arg))
   (company-assert-enabled)
-  (if company-backend
-      (let* ((after (cdr (member company-backend company-backends)))
-             (before (cdr (member company-backend (reverse company-backends))))
-             (next (if backward
-                       (append before (reverse after))
-                     (append after (reverse before)))))
-        (company-cancel)
-        (dolist (backend next)
-          (when (ignore-errors (company-begin-backend backend))
-            (return t))))
-    (company-manual-begin))
+  (let* ((after (if company-backend
+                    (cdr (member company-backend company-backends))
+                  company-backends))
+         (before (cdr (member company-backend (reverse company-backends))))
+         (next (if backward
+                   (append before (reverse after))
+                 (append after (reverse before)))))
+    (company-cancel)
+    (cl-dolist (backend next)
+      (when (ignore-errors (company-begin-backend backend))
+        (cl-return t))))
   (unless company-candidates
     (error "No other back-end")))
 
@@ -1187,12 +1302,15 @@ Keywords and function definition names are ignored."
      (t (company-cancel)))))
 
 (defun company--good-prefix-p (prefix)
-  (and (or (company-explicit-action-p)
-           (unless (eq prefix 'stop)
-             (or (eq (cdr-safe prefix) t)
-                 (>= (or (cdr-safe prefix) (length prefix))
-                     company-minimum-prefix-length))))
-       (stringp (or (car-safe prefix) prefix))))
+  (and (stringp (or (car-safe prefix) prefix)) ;excludes 'stop
+       (or (eq (cdr-safe prefix) t)
+           (let ((len (or (cdr-safe prefix) (length prefix))))
+             (if company--manual-prefix
+                 (or (not company-abort-manual-when-too-short)
+                     ;; Must not be less than minimum or initial length.
+                     (>= len (min company-minimum-prefix-length
+                                  (length company--manual-prefix))))
+               (>= len company-minimum-prefix-length))))))
 
 (defun company--continue ()
   (when (company-call-backend 'no-cache company-prefix)
@@ -1219,10 +1337,10 @@ Keywords and function definition names are ignored."
 
 (defun company--begin-new ()
   (let (prefix c)
-    (dolist (backend (if company-backend
-                         ;; prefer manual override
-                         (list company-backend)
-                       company-backends))
+    (cl-dolist (backend (if company-backend
+                            ;; prefer manual override
+                            (list company-backend)
+                          company-backends))
       (setq prefix
             (if (or (symbolp backend)
                     (functionp backend))
@@ -1239,16 +1357,18 @@ Keywords and function definition names are ignored."
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
           (if (not (consp c))
-              (when company--explicit-action
+              (when company--manual-action
                 (message "No completion found"))
             (setq company-prefix prefix)
+            (when company--manual-action
+              (setq company--manual-prefix prefix))
             (when (symbolp backend)
               (setq company-lighter (concat " " (symbol-name backend))))
             (company-update-candidates c)
             (run-hook-with-args 'company-completion-started-hook
                                 (company-explicit-action-p))
             (company-call-frontends 'show)))
-        (return c)))))
+        (cl-return c)))))
 
 (defun company-begin ()
   (or (and company-candidates (company--continue))
@@ -1291,7 +1411,8 @@ Keywords and function definition names are ignored."
         company-common nil
         company-selection 0
         company-selection-changed nil
-        company--explicit-action nil
+        company--manual-action nil
+        company--manual-prefix nil
         company-lighter company-default-lighter
         company--point-max nil
         company-point nil)
@@ -1344,6 +1465,7 @@ Keywords and function definition names are ignored."
             (and (numberp company-idle-delay)
                  (or (eq t company-begin-commands)
                      (memq this-command company-begin-commands))
+                 (not (equal (point) company-point))
                  (setq company-timer
                        (run-with-timer company-idle-delay nil
                                        'company-idle-begin
@@ -1371,10 +1493,10 @@ Keywords and function definition names are ignored."
 (defun company-search (text lines)
   (let ((quoted (regexp-quote text))
         (i 0))
-    (dolist (line lines)
+    (cl-dolist (line lines)
       (when (string-match quoted line (length company-prefix))
-        (return i))
-      (incf i))))
+        (cl-return i))
+      (cl-incf i))))
 
 (defun company-search-printing-char ()
   (interactive)
@@ -1469,10 +1591,10 @@ Keywords and function definition names are ignored."
     (define-key keymap [t] 'company-search-other-char)
     (while (< i ?\s)
       (define-key keymap (make-string 1 i) 'company-search-other-char)
-      (incf i))
+      (cl-incf i))
     (while (< i 256)
       (define-key keymap (vector i) 'company-search-printing-char)
-      (incf i))
+      (cl-incf i))
     (let ((meta-map (make-sparse-keymap)))
       (define-key keymap (char-to-string meta-prefix-char) meta-map)
       (define-key keymap [escape] meta-map))
@@ -1595,10 +1717,10 @@ and invoke the normal binding."
   (let* ((col-row (posn-actual-col-row (event-start event)))
          (col (car col-row))
          (row (cdr col-row)))
-    (incf col (window-hscroll))
+    (cl-incf col (window-hscroll))
     (and header-line-format
          (version< "24" emacs-version)
-         (decf row))
+         (cl-decf row))
     (cons col row)))
 
 (defun company-select-mouse (event)
@@ -1638,8 +1760,6 @@ and invoke the normal binding."
   (interactive)
   (when (company-manual-begin)
     (let ((result (nth company-selection company-candidates)))
-      (when company--auto-completion
-        (setq result (company--safe-candidate result)))
       (company-finish result))))
 
 (defun company-complete-common ()
@@ -1672,7 +1792,7 @@ To show the number next to the candidates in some back-ends, enable
   (when (company-manual-begin)
     (and (< n 1) (> n company-candidates-length)
          (error "No candidate number %d" n))
-    (decf n)
+    (cl-decf n)
     (company-finish (nth n company-candidates))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1787,15 +1907,10 @@ To show the number next to the candidates in some back-ends, enable
 (defvar company-callback nil)
 (make-variable-buffer-local 'company-callback)
 
-(defvar company-begin-with-marker nil)
-(make-variable-buffer-local 'company-begin-with-marker)
-
 (defun company-remove-callback (&optional ignored)
   (remove-hook 'company-completion-finished-hook company-callback t)
   (remove-hook 'company-completion-cancelled-hook 'company-remove-callback t)
-  (remove-hook 'company-completion-finished-hook 'company-remove-callback t)
-  (when company-begin-with-marker
-    (set-marker company-begin-with-marker nil)))
+  (remove-hook 'company-completion-finished-hook 'company-remove-callback t))
 
 (defun company-begin-backend (backend &optional callback)
   "Start a completion at point using BACKEND."
@@ -1824,20 +1939,18 @@ CALLBACK is a function called with the selected result if the user
 successfully completes the input.
 
 Example: \(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
-  ;; FIXME: When Emacs 23 is no longer a concern, replace
-  ;; `company-begin-with-marker' with a lexical variable; use a lexical closure.
-  (setq company-begin-with-marker (copy-marker (point) t))
-  (company-begin-backend
-   `(lambda (command &optional arg &rest ignored)
-      (cond
-       ((eq command 'prefix)
-        (when (equal (point) (marker-position company-begin-with-marker))
-          (buffer-substring ,(- (point) (or prefix-length 0)) (point))))
-       ((eq command 'candidates)
-        (all-completions arg ',candidates))
-       ((eq command 'require-match)
-        ,require-match)))
-   callback))
+  (let ((begin-marker (copy-marker (point) t)))
+    (company-begin-backend
+     (lambda (command &optional arg &rest ignored)
+       (pcase command
+        (`prefix
+         (when (equal (point) (marker-position begin-marker))
+           (buffer-substring (- (point) (or prefix-length 0)) (point))))
+        (`candidates
+         (all-completions arg candidates))
+        (`require-match
+         require-match)))
+     callback)))
 
 (defun company-version (&optional show-version)
   "Get the Company version as string.
@@ -1860,26 +1973,26 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
 (make-variable-buffer-local 'company-tooltip-offset)
 
 (defun company-tooltip--lines-update-offset (selection num-lines limit)
-  (decf limit 2)
+  (cl-decf limit 2)
   (setq company-tooltip-offset
         (max (min selection company-tooltip-offset)
              (- selection -1 limit)))
 
   (when (<= company-tooltip-offset 1)
-    (incf limit)
+    (cl-incf limit)
     (setq company-tooltip-offset 0))
 
   (when (>= company-tooltip-offset (- num-lines limit 1))
-    (incf limit)
+    (cl-incf limit)
     (when (= selection (1- num-lines))
-      (decf company-tooltip-offset)
+      (cl-decf company-tooltip-offset)
       (when (<= company-tooltip-offset 1)
         (setq company-tooltip-offset 0)
-        (incf limit))))
+        (cl-incf limit))))
 
   limit)
 
-(defun company-tooltip--simple-update-offset (selection num-lines limit)
+(defun company-tooltip--simple-update-offset (selection _num-lines limit)
   (setq company-tooltip-offset
         (if (< selection company-tooltip-offset)
             selection
@@ -1998,13 +2111,13 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
     (length lst)))
 
 (defun company--replacement-string (lines old column nl &optional align-top)
-  (decf column company-tooltip-margin)
+  (cl-decf column company-tooltip-margin)
 
   (let ((width (length (car lines)))
         (remaining-cols (- (+ (company--window-width) (window-hscroll))
                            column)))
     (when (> width remaining-cols)
-      (decf column (- width remaining-cols))))
+      (cl-decf column (- width remaining-cols))))
 
   (let ((offset (and (< column 0) (- column)))
         new)
@@ -2068,14 +2181,14 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
             remainder (when (> remainder 0)
                         (setq remainder (format "...(%d)" remainder))))))
 
-    (decf selection company-tooltip-offset)
+    (cl-decf selection company-tooltip-offset)
     (setq width (max (length previous) (length remainder))
           lines (nthcdr company-tooltip-offset company-candidates)
           len (min limit len)
           lines-copy lines)
 
-    (decf window-width (* 2 company-tooltip-margin))
-    (when scrollbar-bounds (decf window-width))
+    (cl-decf window-width (* 2 company-tooltip-margin))
+    (when scrollbar-bounds (cl-decf window-width))
 
     (dotimes (_ len)
       (let* ((value (pop lines-copy))
@@ -2091,10 +2204,11 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
                          width))))
 
     (setq width (min window-width
-                     (if (and company-show-numbers
-                              (< company-tooltip-offset 10))
-                         (+ 2 width)
-                       width)))
+                     (max company-tooltip-minimum-width
+                          (if (and company-show-numbers
+                                   (< company-tooltip-offset 10))
+                              (+ 2 width)
+                            width))))
 
     ;; number can make tooltip too long
     (when company-show-numbers
@@ -2111,8 +2225,8 @@ If SHOW-VERSION is non-nil, show the version in the echo area."
                (right (company-space-string company-tooltip-margin))
                (width width))
           (when (< numbered 10)
-            (decf width 2)
-            (incf numbered)
+            (cl-decf width 2)
+            (cl-incf numbered)
             (setq right (concat (format " %d" (mod numbered 10)) right)))
           (push (concat
                  (company-fill-propertize str annotation
@@ -2249,7 +2363,7 @@ Returns a negative number if the tooltip should be displayed above point."
 
 (defun company-pseudo-tooltip-frontend (command)
   "`company-mode' front-end similar to a tooltip but based on overlays."
-  (case command
+  (cl-case command
     (pre-command (company-pseudo-tooltip-hide-temporarily))
     (post-command
      (let ((old-height (if (overlayp company-pseudo-tooltip-overlay)
@@ -2320,10 +2434,10 @@ Returns a negative number if the tooltip should be displayed above point."
 
 (defun company-preview-frontend (command)
   "`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))))
+  (pcase command
+    (`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."
@@ -2380,8 +2494,8 @@ Returns a negative number if the tooltip should be displayed above point."
           (progn
             (setq comp (propertize (format "%d: %s" i comp)
                                    'face 'company-echo))
-            (incf len 3)
-            (incf i)
+            (cl-incf len 3)
+            (cl-incf i)
             (add-text-properties 3 (+ 3 (length company-common))
                                  '(face company-echo-common) comp))
         (setq comp (propertize comp 'face 'company-echo))
@@ -2408,8 +2522,8 @@ Returns a negative number if the tooltip should be displayed above point."
       (when (< i 10)
         ;; Add number.
         (setq comp (format "%s (%d)" comp i))
-        (incf len 4)
-        (incf i))
+        (cl-incf len 4)
+        (cl-incf i))
       (if (>= len limit)
           (setq candidates nil)
         (push (propertize comp 'face 'company-echo) msg)))
@@ -2425,21 +2539,21 @@ Returns a negative number if the tooltip should be displayed above point."
 
 (defun company-echo-frontend (command)
   "`company-mode' front-end showing the candidates in the echo area."
-  (case command
-    (post-command (company-echo-show-soon 'company-echo-format))
-    (hide (company-echo-hide))))
+  (pcase command
+    (`post-command (company-echo-show-soon 'company-echo-format))
+    (`hide (company-echo-hide))))
 
 (defun company-echo-strip-common-frontend (command)
   "`company-mode' front-end showing the candidates in the echo area."
-  (case command
-    (post-command (company-echo-show-soon 'company-echo-strip-common-format))
-    (hide (company-echo-hide))))
+  (pcase command
+    (`post-command (company-echo-show-soon 'company-echo-strip-common-format))
+    (`hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
   "`company-mode' front-end showing the documentation in the echo area."
-  (case command
-    (post-command (company-echo-show-when-idle 'company-fetch-metadata))
-    (hide (company-echo-hide))))
+  (pcase command
+    (`post-command (company-echo-show-when-idle 'company-fetch-metadata))
+    (`hide (company-echo-hide))))
 
 (provide 'company)
 ;;; company.el ends here