;; Author: Nikolaj Schumacher
;; Maintainer: Dmitry Gutov <dgutov@yandex.ru>
;; URL: http://company-mode.github.io/
-;; Version: 0.8.10-cvs
+;; Version: 0.9.0-cvs
;; Keywords: abbrev, convenience, matching
;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
(company-keywords . "Programming language keywords")
(company-nxml . "nxml")
(company-oddmuse . "Oddmuse")
- (company-pysmell . "PySmell")
- (company-ropemacs . "ropemacs")
(company-semantic . "Semantic")
(company-tempo . "Tempo templates")
(company-xcode . "Xcode")))
(assq backend company-safe-backends))
(cl-return t))))))
-(defcustom company-backends `(,@(unless (version< "24.3.50" emacs-version)
+(defcustom company-backends `(,@(unless (version< "24.3.51" emacs-version)
(list 'company-elisp))
company-bbdb
company-nxml company-css
company-eclim company-semantic company-clang
- company-xcode company-ropemacs company-cmake
+ company-xcode company-cmake
company-capf
(company-dabbrev-code company-gtags company-etags
company-keywords)
control to the next back-end. The function should return `stop' if it
should complete but cannot (e.g. if it is in the middle of a string).
Instead of a string, the back-end may return a cons where car is the prefix
-and cdr is used in `company-minimum-prefix-length' test. It must be either
-number or t, and in the latter case the test automatically succeeds.
+and cdr is used instead of the actual prefix length in the comparison
+against `company-minimum-prefix-length'. It must be either number or t,
+and in the latter case the test automatically succeeds.
`candidates': The second argument is the prefix to be completed. The
return value should be a list of candidates that match the prefix.
(unless (keywordp b)
(company-init-backend b))))))
-(defvar company-default-lighter " company")
+(defcustom company-lighter-base "company"
+ "Base string to use for the `company-mode' lighter."
+ :type 'string
+ :package-version '(company . "0.8.10"))
-(defvar-local company-lighter company-default-lighter)
+(defvar company-lighter '(" "
+ (company-candidates
+ (:eval
+ (if (consp company-backend)
+ (company--group-lighter (nth company-selection
+ company-candidates)
+ company-lighter-base)
+ (symbol-name company-backend)))
+ company-lighter-base))
+ "Mode line lighter for Company.
+
+The value of this variable is a mode line template as in
+`mode-line-format'.")
+
+(put 'company-lighter 'risky-local-variable t)
;;;###autoload
(define-minor-mode company-mode
(cons
:async
(lambda (callback)
- (let* (lst pending
+ (let* (lst
+ (pending (mapcar #'car pairs))
(finisher (lambda ()
(unless pending
(funcall callback
(funcall merger
(nreverse lst)))))))
(dolist (pair pairs)
- (let ((val (car pair))
- (mapper (cdr pair)))
+ (push nil lst)
+ (let* ((cell lst)
+ (val (car pair))
+ (mapper (cdr pair))
+ (this-finisher (lambda (res)
+ (setq pending (delq val pending))
+ (setcar cell (funcall mapper res))
+ (funcall finisher))))
(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)))))))))))))
+ (funcall this-finisher val)
+ (let ((fetcher (cdr val)))
+ (funcall fetcher this-finisher)))))))))))
(defun company--prefix-str (prefix)
(or (car-safe prefix) prefix))
(substring str (length company-prefix)))
(defun company--insert-candidate (candidate)
- (setq candidate (substring-no-properties candidate))
- ;; XXX: Return value we check here is subject to change.
- (if (eq (company-call-backend 'ignore-case) 'keep-prefix)
- (insert (company-strip-prefix candidate))
- (unless (equal company-prefix candidate)
- (delete-region (- (point) (length company-prefix)) (point))
- (insert candidate))))
+ (when (> (length candidate) 0)
+ (setq candidate (substring-no-properties candidate))
+ ;; XXX: Return value we check here is subject to change.
+ (if (eq (company-call-backend 'ignore-case) 'keep-prefix)
+ (insert (company-strip-prefix candidate))
+ (unless (equal company-prefix candidate)
+ (delete-region (- (point) (length company-prefix)) (point))
+ (insert candidate)))))
(defmacro company-with-candidate-inserted (candidate &rest body)
"Evaluate BODY with CANDIDATE temporarily inserted.
(mod selection company-candidates-length)
(max 0 (min (1- company-candidates-length) selection))))
(when (or force-update (not (equal selection company-selection)))
- (company--update-group-lighter (nth selection company-candidates))
(setq company-selection selection
company-selection-changed t)
(company-call-frontends 'update)))
-(defun company--update-group-lighter (candidate)
- (when (listp company-backend)
- (let ((backend (or (get-text-property 0 'company-backend candidate)
- (car company-backend))))
- (when (and backend (symbolp backend))
- (let ((name (replace-regexp-in-string "company-\\|-company" ""
- (symbol-name backend))))
- (setq company-lighter (format " company-<%s>" name)))))))
+(defun company--group-lighter (candidate base)
+ (let ((backend (or (get-text-property 0 'company-backend candidate)
+ (car company-backend))))
+ (when (and backend (symbolp backend))
+ (let ((name (replace-regexp-in-string "company-\\|-company" ""
+ (symbol-name backend))))
+ (format "%s-<%s>" base name)))))
(defun company-update-candidates (candidates)
(setq company-candidates-length (length candidates))
- (if (> company-selection 0)
+ (if company-selection-changed
;; Try to restore the selection
(let ((selected (nth company-selection company-candidates)))
(setq company-selection 0
company-candidates candidates)
(when selected
- (while (and candidates (string< (pop candidates) selected))
- (cl-incf company-selection))
- (unless candidates
- ;; Make sure selection isn't out of bounds.
- (setq company-selection (min (1- company-candidates-length)
- company-selection)))))
+ (catch 'found
+ (while candidates
+ (let ((candidate (pop candidates)))
+ (when (and (string= candidate selected)
+ (equal (company-call-backend 'annotation candidate)
+ (company-call-backend 'annotation selected)))
+ (throw 'found t)))
+ (cl-incf company-selection))
+ (setq company-selection 0
+ company-selection-changed nil))))
(setq company-selection 0
company-candidates candidates))
;; Calculate common.
(message "No completion found"))
(when company--manual-action
(setq company--manual-prefix prefix))
- (if (symbolp backend)
- (setq company-lighter (concat " " (symbol-name backend)))
- (company--update-group-lighter (car c)))
(company-update-candidates c)
(run-hook-with-args 'company-completion-started-hook
(company-explicit-action-p))
company-selection-changed nil
company--manual-action nil
company--manual-prefix nil
- company-lighter company-default-lighter
company--point-max nil
company-point nil)
(when company-timer
(defvar-local company--search-old-selection 0)
+(defvar-local company--search-old-changed nil)
+
(defun company--search (text lines)
(let ((quoted (regexp-quote text))
(i 0))
(interactive)
(company--search-assert-enabled)
(company-search-mode 0)
- (company-set-selection company--search-old-selection t))
+ (company-set-selection company--search-old-selection t)
+ (setq company-selection-changed company--search-old-changed))
(defun company-search-other-char ()
(interactive)
(define-key keymap "\C-s" 'company-search-repeat-forward)
(define-key keymap "\C-r" 'company-search-repeat-backward)
(define-key keymap "\C-o" 'company-search-toggle-filtering)
+ (dotimes (i 10)
+ (define-key keymap (read-kbd-macro (format "M-%d" i)) 'company-complete-number))
keymap)
"Keymap used for incrementally searching the completion candidates.")
(if company-search-mode
(if (company-manual-begin)
(progn
- (setq company--search-old-selection company-selection)
+ (setq company--search-old-selection company-selection
+ company--search-old-changed company-selection-changed)
(company-call-frontends 'update)
(company-enable-overriding-keymap company-search-map))
(setq company-search-mode nil))
(kill-local-variable 'company-search-string)
(kill-local-variable 'company-search-filtering)
(kill-local-variable 'company--search-old-selection)
+ (kill-local-variable 'company--search-old-changed)
(when company-backend
(company--search-update-predicate "")
(company-call-frontends 'update))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defun company-select-next ()
- "Select the next candidate in the list."
- (interactive)
- (when (company-manual-begin)
- (company-set-selection (1+ company-selection))))
+(defun company-select-next (&optional arg)
+ "Select the next candidate in the list.
-(defun company-select-previous ()
- "Select the previous candidate in the list."
- (interactive)
+With ARG, move by that many elements."
+ (interactive "p")
(when (company-manual-begin)
- (company-set-selection (1- company-selection))))
+ (company-set-selection (+ (or arg 1) company-selection))))
+
+(defun company-select-previous (&optional arg)
+ "Select the previous candidate in the list.
+
+With ARG, move by that many elements."
+ (interactive "p")
+ (company-select-next (if arg (- arg) -1)))
-(defun company-select-next-or-abort ()
+(defun company-select-next-or-abort (&optional arg)
"Select the next candidate if more than one, else abort
-and invoke the normal binding."
- (interactive)
+and invoke the normal binding.
+
+With ARG, move by that many elements."
+ (interactive "p")
(if (> company-candidates-length 1)
- (company-select-next)
+ (company-select-next arg)
(company-abort)
(company--unread-last-input)))
-(defun company-select-previous-or-abort ()
+(defun company-select-previous-or-abort (&optional arg)
"Select the previous candidate if more than one, else abort
-and invoke the normal binding."
- (interactive)
+and invoke the normal binding.
+
+With ARG, move by that many elements."
+ (interactive "p")
(if (> company-candidates-length 1)
- (company-select-previous)
+ (company-select-previous arg)
(company-abort)
(company--unread-last-input)))
(if (and (not (cdr company-candidates))
(equal company-common (car company-candidates)))
(company-complete-selection)
- (when company-common
- (company--insert-candidate company-common)))))
+ (company--insert-candidate company-common))))
-(defun company-complete-common-or-cycle ()
- "Insert the common part of all candidates, or select the next one."
- (interactive)
+(defun company-complete-common-or-cycle (&optional arg)
+ "Insert the common part of all candidates, or select the next one.
+
+With ARG, move by that many elements."
+ (interactive "p")
(when (company-manual-begin)
(let ((tick (buffer-chars-modified-tick)))
(call-interactively 'company-complete-common)
(when (eq tick (buffer-chars-modified-tick))
- (let ((company-selection-wrap-around t))
+ (let ((company-selection-wrap-around t)
+ (current-prefix-arg arg))
(call-interactively 'company-select-next))))))
(defun company-complete ()
(current-buffer)))
(defvar company--electric-commands
- '(scroll-other-window scroll-other-window-down)
+ '(scroll-other-window scroll-other-window-down mwheel-scroll)
"List of Commands that won't break out of electric commands.")
(defmacro company--electric-do (&rest body)
(and (< (window-height) height)
(< (- (window-height) row 2) company-tooltip-limit)
(recenter (- (window-height) row 2)))
- (while (memq (setq cmd (key-binding (vector (list (read-event)))))
+ (while (memq (setq cmd (key-binding (read-key-sequence-vector nil)))
company--electric-commands)
- (call-interactively cmd))
+ (condition-case err
+ (call-interactively cmd)
+ ((beginning-of-buffer end-of-buffer)
+ (message (error-message-string err)))))
(company--unread-last-input)))))
(defun company--unread-last-input ()
(defun company-show-doc-buffer ()
"Temporarily show the documentation buffer for the selection."
(interactive)
- (company--electric-do
- (let* ((selected (nth company-selection company-candidates))
- (doc-buffer (or (company-call-backend 'doc-buffer selected)
- (error "No documentation available"))))
- (with-current-buffer doc-buffer
- (goto-char (point-min)))
- (display-buffer doc-buffer t))))
+ (let (other-window-scroll-buffer)
+ (company--electric-do
+ (let* ((selected (nth company-selection company-candidates))
+ (doc-buffer (or (company-call-backend 'doc-buffer selected)
+ (error "No documentation available"))))
+ (setq other-window-scroll-buffer (get-buffer doc-buffer))
+ (with-current-buffer doc-buffer
+ (goto-char (point-min)))
+ (display-buffer doc-buffer t)))))
(put 'company-show-doc-buffer 'company-keep t)
(defun company-show-location ()
"Temporarily display a buffer showing the selected candidate in context."
(interactive)
- (company--electric-do
- (let* ((selected (nth company-selection company-candidates))
- (location (company-call-backend 'location selected))
- (pos (or (cdr location) (error "No location available")))
- (buffer (or (and (bufferp (car location)) (car location))
- (find-file-noselect (car location) t))))
- (with-selected-window (display-buffer buffer t)
- (save-restriction
- (widen)
- (if (bufferp (car location))
- (goto-char pos)
- (goto-char (point-min))
- (forward-line (1- pos))))
- (set-window-start nil (point))))))
+ (let (other-window-scroll-buffer)
+ (company--electric-do
+ (let* ((selected (nth company-selection company-candidates))
+ (location (company-call-backend 'location selected))
+ (pos (or (cdr location) (error "No location available")))
+ (buffer (or (and (bufferp (car location)) (car location))
+ (find-file-noselect (car location) t))))
+ (setq other-window-scroll-buffer (get-buffer buffer))
+ (with-selected-window (display-buffer buffer t)
+ (save-restriction
+ (widen)
+ (if (bufferp (car location))
+ (goto-char pos)
+ (goto-char (point-min))
+ (forward-line (1- pos))))
+ (set-window-start nil (point)))))))
(put 'company-show-location 'company-keep t)
;;; package functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(message "Company version: %s" (lm-version))
(lm-version))))
+(defun company-diag ()
+ "Pop a buffer with information about completions at point."
+ (interactive)
+ (let* ((bb company-backends)
+ backend
+ (prefix (cl-loop for b in bb
+ thereis (let ((company-backend b))
+ (setq backend b)
+ (company-call-backend 'prefix))))
+ cc annotations)
+ (when (stringp prefix)
+ (let ((company-backend backend))
+ (setq cc (company-call-backend 'candidates prefix)
+ annotations
+ (mapcar
+ (lambda (c) (cons c (company-call-backend 'annotation c)))
+ cc))))
+ (pop-to-buffer (get-buffer-create "*company-diag*"))
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (insert (format "Emacs %s (%s) of %s on %s"
+ emacs-version system-configuration
+ (format-time-string "%Y-%m-%d" emacs-build-time)
+ emacs-build-system))
+ (insert "\nCompany " (company-version) "\n\n")
+ (insert "company-backends: " (pp-to-string bb))
+ (insert "\n")
+ (insert "Used backend: " (pp-to-string backend))
+ (insert "\n")
+ (insert "Prefix: " (pp-to-string prefix))
+ (insert "\n")
+ (insert (message "Completions:"))
+ (unless cc (insert " none"))
+ (save-excursion
+ (dolist (c annotations)
+ (insert "\n " (prin1-to-string (car c)))
+ (when (cdr c)
+ (insert " " (prin1-to-string (cdr c))))))
+ (special-mode)))
+
;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar-local company-pseudo-tooltip-overlay nil)
(string-match (regexp-quote company-search-string) value
(length company-prefix)))
(let ((beg (+ margin (match-beginning 0)))
- (end (+ margin (match-end 0))))
- (add-text-properties beg end '(face company-tooltip-search)
- line))
+ (end (+ margin (match-end 0)))
+ (width (- width (length right))))
+ (when (< beg width)
+ (add-text-properties beg (min end width)
+ '(face company-tooltip-search)
+ line)))
(add-text-properties 0 width '(face company-tooltip-selection
mouse-face company-tooltip-selection)
line)