1 (eval-when-compile (require 'cl))
9 (defface company-tooltip
10 '((t :background "yellow"
15 (defface company-tooltip-selection
16 '((t :background "orange1"
21 (defface company-tooltip-common
22 '((t :inherit company-tooltip
27 (defface company-tooltip-common-selection
28 '((t :inherit company-tooltip-selection
33 (defcustom company-tooltip-limit 10
38 (defface company-preview
39 '((t :background "blue4"
44 (defface company-preview-common
45 '((t :inherit company-preview
50 (defface company-echo nil
54 (defface company-echo-common
55 '((((background dark)) (:foreground "firebrick1"))
56 (((background light)) (:background "firebrick4")))
60 (defcustom company-frontends '(company-echo-frontend
61 company-pseudo-tooltip-frontend
62 company-completion-frontend)
65 :type '(repeat (function :tag "function" nil)))
67 (defcustom company-backends '(company-elisp-completion)
70 :type '(repeat (function :tag "function" nil)))
72 (defcustom company-minimum-prefix-length 3
75 :type '(integer :tag "prefix length"))
77 (defvar company-timer nil)
79 (defun company-timer-set (variable value)
81 (when company-timer (cancel-timer company-timer))
83 (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
85 (defcustom company-idle-delay .7
87 :set 'company-timer-set
89 :type '(choice (const :tag "never (nil)" nil)
90 (const :tag "immediate (t)" t)
91 (number :tag "seconds")))
93 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
95 (defvar company-mode-map
96 (let ((keymap (make-sparse-keymap)))
97 (define-key keymap (kbd "M-n") 'company-select-next)
98 (define-key keymap (kbd "M-p") 'company-select-previous)
99 (define-key keymap (kbd "M-<return>") 'company-complete-selection)
100 (define-key keymap "\t" 'company-complete-common)
104 (define-minor-mode company-mode
106 nil " comp" company-mode-map
109 (add-hook 'pre-command-hook 'company-pre-command nil t)
110 (add-hook 'post-command-hook 'company-post-command nil t)
111 (company-timer-set 'company-idle-delay
113 (remove-hook 'pre-command-hook 'company-pre-command t)
114 (remove-hook 'post-command-hook 'company-post-command t)
116 (kill-local-variable 'company-point)))
118 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
120 (defun company-grab (regexp &optional expression)
121 (when (looking-back regexp)
122 (or (match-string-no-properties (or expression 0)) "")))
124 (defun company-in-string-or-comment (&optional point)
125 (let ((pos (syntax-ppss)))
126 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
130 (defvar company-lisp-symbol-regexp
131 "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
133 (defun company-grab-lisp-symbol ()
134 (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
135 (unless (and (company-in-string-or-comment (- (point) (length prefix)))
136 (/= (char-before (- (point) (length prefix))) ?`))
139 (defun company-elisp-completion (command &optional arg &rest ignored)
141 ('prefix (and (eq major-mode 'emacs-lisp-mode)
142 (company-grab-lisp-symbol)))
143 ('candidates (let ((completion-ignore-case nil))
144 (all-completions arg obarray
145 (lambda (symbol) (or (boundp symbol)
146 (fboundp symbol))))))))
148 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150 (defvar company-backend nil)
151 (make-variable-buffer-local 'company-backend)
153 (defvar company-prefix nil)
154 (make-variable-buffer-local 'company-prefix)
156 (defvar company-candidates nil)
157 (make-variable-buffer-local 'company-candidates)
159 (defvar company-common nil)
160 (make-variable-buffer-local 'company-common)
162 (defvar company-selection 0)
163 (make-variable-buffer-local 'company-selection)
165 (defvar company-selection-changed nil)
166 (make-variable-buffer-local 'company-selection-changed)
168 (defvar company-point nil)
169 (make-variable-buffer-local 'company-point)
171 (defsubst company-strip-prefix (str)
172 (substring str (length company-prefix)))
174 (defsubst company-offset (display-limit)
175 (let ((offset (- company-selection display-limit -1)))
178 (defsubst company-should-complete (prefix)
179 (and (eq company-idle-delay t)
180 (>= (length prefix) company-minimum-prefix-length)))
182 (defsubst company-call-frontends (command)
183 (dolist (frontend company-frontends)
184 (funcall frontend command)))
186 (defun company-idle-begin ()
188 (not company-candidates)
189 (not (equal (point) company-point))
190 (let ((company-idle-delay t))
192 (company-post-command))))
194 (defun company-manual-begin ()
196 (not company-candidates)
197 (let ((company-idle-delay t)
198 (company-minimum-prefix-length 0))
200 ;; Return non-nil if active.
203 (defun company-continue-or-cancel ()
204 (when company-candidates
205 (let ((old-point (- company-point (length company-prefix)))
206 (company-idle-delay t)
207 (company-minimum-prefix-length 0))
208 ;; TODO: Make more efficient.
209 (setq company-candidates nil)
211 (unless (and company-candidates
212 (equal old-point (- company-point (length company-prefix))))
214 company-candidates)))
216 (defun company-begin ()
217 (or (company-continue-or-cancel)
218 (let ((completion-ignore-case nil) ;; TODO: make this optional
220 (dolist (backend company-backends)
221 (when (setq prefix (funcall backend 'prefix))
222 (when (company-should-complete prefix)
223 (setq company-backend backend
224 company-prefix prefix
226 (funcall company-backend 'candidates prefix)
227 company-common (try-completion prefix company-candidates)
229 company-point (point))
230 (company-call-frontends 'update))
232 (unless (and company-candidates
233 (not (eq t company-common)))
236 (defun company-cancel ()
237 (setq company-backend nil
239 company-candidates nil
242 company-selection-changed nil
244 (company-call-frontends 'hide))
246 (defun company-abort ()
248 ;; Don't start again, unless started manually.
249 (setq company-point (point)))
251 (defun company-pre-command ()
252 (when company-candidates
253 (company-call-frontends 'pre-command)))
255 (defun company-post-command ()
256 (unless (equal (point) company-point)
258 (when company-candidates
259 (company-call-frontends 'post-command)))
261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
263 (defun company-select-next ()
265 (when (company-manual-begin)
266 (setq company-selection (min (1- (length company-candidates))
267 (1+ company-selection))
268 company-selection-changed t)))
270 (defun company-select-previous ()
272 (when (company-manual-begin)
273 (setq company-selection (max 0 (1- company-selection))
274 company-selection-changed t)))
276 (defun company-complete-selection ()
278 (when (company-manual-begin)
279 (insert (company-strip-prefix (nth company-selection company-candidates)))
282 (defun company-complete-common ()
284 (when (company-manual-begin)
285 (insert (company-strip-prefix company-common))))
287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
289 (defconst company-space-strings-limit 100)
291 (defconst company-space-strings
293 (dotimes (i company-space-strings-limit)
294 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
295 (apply 'vector lst)))
297 (defsubst company-space-string (len)
298 (if (< len company-space-strings-limit)
299 (aref company-space-strings len)
300 (make-string len ?\ )))
302 (defsubst company-safe-substring (str from &optional to)
303 (let ((len (length str)))
306 (if (and to (> to len))
307 (concat (substring str from)
308 (company-space-string (- to len)))
309 (substring str from to)))))
311 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
313 (defvar company-pseudo-tooltip-overlay nil)
314 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
318 (defun company-fill-propertize (line width selected)
319 (setq line (company-safe-substring line 0 width))
320 (add-text-properties 0 width
321 (list 'face (if selected
322 'company-tooltip-selection
323 'company-tooltip)) line)
324 (add-text-properties 0 (length company-common)
325 (list 'face (if selected
326 'company-tooltip-common-selection
327 'company-tooltip-common)) line)
330 (defun company-fill-propertize-lines (column lines selection)
333 (len (min company-tooltip-limit (length lines)))
336 (setq width (max (length (pop lines-copy)) width)))
337 (setq width (min width (- (window-width) column)))
339 (push (company-fill-propertize (pop lines) width (equal i selection))
345 (defun company-buffer-lines (beg end)
347 (let ((row (cdr (posn-col-row (posn-at-point))))
349 (while (< (point) end)
350 (move-to-window-line (incf row))
351 (push (buffer-substring beg (min end (1- (point)))) lines)
355 (defun company-modify-line (old new offset)
356 (concat (company-safe-substring old 0 offset)
358 (company-safe-substring old (+ offset (length new)))))
360 (defun company-modified-substring (beg end lines column)
361 (let ((old (company-buffer-lines beg end))
363 ;; Inject into old lines.
365 (push (company-modify-line (pop old) (pop lines) column) new))
366 ;; Append whole new lines.
368 (push (company-modify-line "" (pop lines) column) new))
369 (concat (mapconcat 'identity (nreverse new) "\n")
374 (defun company-pseudo-tooltip-show (row column lines selection)
375 (company-pseudo-tooltip-hide)
376 (unless lines (error "No text provided"))
380 (let ((offset (company-offset company-tooltip-limit)))
381 (setq lines (nthcdr offset lines))
382 (decf selection offset))
384 (setq lines (company-fill-propertize-lines column lines selection))
388 (move-to-window-line row)
391 (move-to-window-line (min (window-height)
392 (+ row company-tooltip-limit)))
396 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
398 (overlay-put company-pseudo-tooltip-overlay 'before-string
399 (company-modified-substring beg end lines column))
400 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
401 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
403 (defun company-pseudo-tooltip-show-at-point (pos)
404 (let ((col-row (posn-col-row (posn-at-point pos))))
405 (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
406 company-candidates company-selection)))
408 (defun company-pseudo-tooltip-hide ()
409 (when company-pseudo-tooltip-overlay
410 (delete-overlay company-pseudo-tooltip-overlay)
411 (setq company-pseudo-tooltip-overlay nil)))
413 (defun company-pseudo-tooltip-frontend (command)
415 ('pre-command (company-pseudo-tooltip-hide))
416 ('post-command (company-pseudo-tooltip-show-at-point
417 (- (point) (length company-prefix))))
418 ('hide (company-pseudo-tooltip-hide))))
420 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
422 (defvar company-preview-overlay nil)
423 (make-variable-buffer-local 'company-preview-overlay)
425 (defun company-preview-show-at-point (pos)
426 (company-preview-hide)
428 (setq company-preview-overlay (make-overlay pos pos))
430 (let ((completion (company-strip-prefix (nth company-selection
431 company-candidates))))
432 (and (equal pos (point))
433 (not (equal completion ""))
434 (add-text-properties 0 1 '(cursor t) completion))
436 (setq completion (propertize completion 'face 'company-preview))
437 (add-text-properties 0 (- (length company-common) (length company-prefix))
438 '(face company-preview-common) completion)
440 (overlay-put company-preview-overlay 'after-string completion)
441 (overlay-put company-preview-overlay 'window (selected-window))))
443 (defun company-preview-hide ()
444 (when company-preview-overlay
445 (delete-overlay company-preview-overlay)
446 (setq company-preview-overlay nil)))
448 (defun company-preview-frontend (command)
450 ('pre-command (company-preview-hide))
451 ('post-command (company-preview-show-at-point (point)))
452 ('hide (company-preview-hide))))
454 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
456 (defvar company-echo-last-msg nil)
457 (make-variable-buffer-local 'company-echo-last-msg)
459 (defun company-echo-refresh ()
460 (let ((message-log-max nil))
461 (if company-echo-last-msg
462 (message "%s" company-echo-last-msg)
465 (defun company-echo-show (candidates)
467 ;; Roll to selection.
468 (setq candidates (nthcdr company-selection candidates))
470 (let ((limit (window-width (minibuffer-window)))
474 (setq comp (pop candidates)
475 len (+ len 1 (length comp)))
477 (setq candidates nil)
478 (setq comp (propertize comp 'face 'company-echo))
479 (add-text-properties 0 (length company-common)
480 '(face company-echo-common) comp)
483 (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
484 (company-echo-refresh)))
486 (defun company-echo-frontend (command)
488 ('pre-command (company-echo-refresh))
489 ('post-command (company-echo-show company-candidates))
490 ('hide (setq company-echo-last-msg nil))))
493 ;;; company.el ends here