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-backends '(company-elisp-completion)
63 :type '(repeat (function :tag "function" nil)))
65 (defcustom company-minimum-prefix-length 3
68 :type '(integer :tag "prefix length"))
70 (defvar company-timer nil)
72 (defun company-timer-set (variable value)
74 (when company-timer (cancel-timer company-timer))
76 (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
78 (defcustom company-idle-delay .7
80 :set 'company-timer-set
82 :type '(choice (const :tag "never (nil)" nil)
83 (const :tag "immediate (t)" t)
84 (number :tag "seconds")))
86 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
88 (defvar company-mode-map
89 (let ((keymap (make-sparse-keymap)))
90 (define-key keymap (kbd "M-n") 'company-select-next)
91 (define-key keymap (kbd "M-p") 'company-select-previous)
92 (define-key keymap (kbd "M-<return>") 'company-complete-selection)
93 (define-key keymap "\t" 'company-complete-common)
97 (define-minor-mode company-mode
99 nil " comp" company-mode-map
102 (add-hook 'pre-command-hook 'company-pre-command nil t)
103 (add-hook 'post-command-hook 'company-post-command nil t)
104 (company-timer-set 'company-idle-delay
106 (remove-hook 'pre-command-hook 'company-pre-command t)
107 (remove-hook 'post-command-hook 'company-post-command t)
110 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112 (defun company-grab (regexp &optional expression)
113 (when (looking-back regexp)
114 (or (match-string-no-properties (or expression 0)) "")))
116 (defun company-in-string-or-comment (&optional point)
117 (let ((pos (syntax-ppss)))
118 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
122 (defvar company-lisp-symbol-regexp
123 "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
125 (defun company-grab-lisp-symbol ()
126 (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
127 (unless (and (company-in-string-or-comment (- (point) (length prefix)))
128 (/= (char-before (- (point) (length prefix))) ?`))
131 (defun company-elisp-completion (command &optional arg &rest ignored)
133 ('prefix (and (eq major-mode 'emacs-lisp-mode)
134 (company-grab-lisp-symbol)))
135 ('candidates (let ((completion-ignore-case nil))
136 (all-completions arg obarray
137 (lambda (symbol) (or (boundp symbol)
138 (fboundp symbol))))))))
140 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
142 (defvar company-backend nil)
143 (make-variable-buffer-local 'company-backend)
145 (defvar company-prefix nil)
146 (make-variable-buffer-local 'company-prefix)
148 (defvar company-candidates nil)
149 (make-variable-buffer-local 'company-candidates)
151 (defvar company-common nil)
152 (make-variable-buffer-local 'company-common)
154 (defvar company-selection 0)
155 (make-variable-buffer-local 'company-selection)
157 (defvar company-selection-changed nil)
158 (make-variable-buffer-local 'company-selection-changed)
160 (defvar company-point nil)
161 (make-variable-buffer-local 'company-point)
163 (defsubst company-strip-prefix (str)
164 (substring str (length company-prefix)))
166 (defsubst company-offset (display-limit)
167 (let ((offset (- company-selection display-limit -1)))
170 (defsubst company-should-complete (prefix)
171 (and (eq company-idle-delay t)
172 (>= (length prefix) company-minimum-prefix-length)))
174 (defun company-idle-begin ()
176 (not company-candidates)
177 (let ((company-idle-delay t))
179 (company-post-command))))
181 (defun company-manual-begin ()
183 (not company-candidates)
184 (let ((company-idle-delay t)
185 (company-minimum-prefix-length 0))
187 ;; Return non-nil if active.
190 (defun company-continue-or-cancel ()
191 (when company-candidates
192 (let ((old-point (- company-point (length company-prefix)))
193 (company-idle-delay t)
194 (company-minimum-prefix-length 0))
195 ;; TODO: Make more efficient.
196 (setq company-candidates nil)
198 (unless (and company-candidates
199 (equal old-point (- company-point (length company-prefix))))
201 company-candidates)))
203 (defun company-begin ()
204 (or (company-continue-or-cancel)
205 (let ((completion-ignore-case nil) ;; TODO: make this optional
207 (dolist (backend company-backends)
208 (when (setq prefix (funcall backend 'prefix))
209 (when (company-should-complete prefix)
210 (setq company-backend backend
211 company-prefix prefix
213 (funcall company-backend 'candidates prefix)
214 company-common (try-completion prefix company-candidates)
216 company-point (point)))
218 (unless (and company-candidates
219 (not (eq t company-common)))
222 (defun company-cancel ()
223 (setq company-backend nil
225 company-candidates nil
228 company-selection-changed nil
230 (company-pseudo-tooltip-hide)
233 (defun company-pre-command ()
234 (company-preview-hide)
235 (company-pseudo-tooltip-hide)
236 (company-echo-refresh))
238 (defun company-post-command ()
239 (unless (equal (point) company-point)
241 (when company-candidates
242 (company-echo-show company-candidates))
243 (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
246 (company-preview-show-at-point (point) company-candidates
249 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251 (defun company-select-next ()
253 (when (company-manual-begin)
254 (setq company-selection (min (1- (length company-candidates))
255 (1+ company-selection))
256 company-selection-changed t)))
258 (defun company-select-previous ()
260 (when (company-manual-begin)
261 (setq company-selection (max 0 (1- company-selection))
262 company-selection-changed t)))
264 (defun company-complete-selection ()
266 (when (company-manual-begin)
267 (insert (company-strip-prefix (nth company-selection company-candidates)))))
269 (defun company-complete-common ()
271 (when (company-manual-begin)
272 (insert (company-strip-prefix company-common))))
274 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
276 (defconst company-space-strings-limit 100)
278 (defconst company-space-strings
280 (dotimes (i company-space-strings-limit)
281 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
282 (apply 'vector lst)))
284 (defsubst company-space-string (len)
285 (if (< len company-space-strings-limit)
286 (aref company-space-strings len)
287 (make-string len ?\ )))
289 (defsubst company-safe-substring (str from &optional to)
290 (let ((len (length str)))
293 (if (and to (> to len))
294 (concat (substring str from)
295 (company-space-string (- to len)))
296 (substring str from to)))))
298 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
300 (defvar company-pseudo-tooltip-overlay nil)
301 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
305 (defun company-fill-propertize (line width selected)
306 (setq line (company-safe-substring line 0 width))
307 (add-text-properties 0 width
308 (list 'face (if selected
309 'company-tooltip-selection
310 'company-tooltip)) line)
311 (add-text-properties 0 (length company-common)
312 (list 'face (if selected
313 'company-tooltip-common-selection
314 'company-tooltip-common)) line)
317 (defun company-fill-propertize-lines (column lines selection)
320 (len (min company-tooltip-limit (length lines)))
323 (setq width (max (length (pop lines-copy)) width)))
324 (setq width (min width (- (window-width) column)))
326 (push (company-fill-propertize (pop lines) width (equal i selection))
332 (defun company-buffer-lines (beg end)
334 (let ((row (cdr (posn-col-row (posn-at-point))))
336 (while (< (point) end)
337 (move-to-window-line (incf row))
338 (push (buffer-substring beg (min end (1- (point)))) lines)
342 (defun company-modify-line (old new offset)
343 (concat (company-safe-substring old 0 offset)
345 (company-safe-substring old (+ offset (length new)))))
347 (defun company-modified-substring (beg end lines column)
348 (let ((old (company-buffer-lines beg end))
350 ;; Inject into old lines.
352 (push (company-modify-line (pop old) (pop lines) column) new))
353 ;; Append whole new lines.
355 (push (company-modify-line "" (pop lines) column) new))
356 (concat (mapconcat 'identity (nreverse new) "\n")
361 (defun company-pseudo-tooltip-show (row column lines &optional selection)
362 (company-pseudo-tooltip-hide)
363 (unless lines (error "No text provided"))
367 (let ((offset (company-offset company-tooltip-limit)))
368 (setq lines (nthcdr offset lines))
369 (decf selection offset))
371 (setq lines (company-fill-propertize-lines column lines selection))
375 (move-to-window-line row)
378 (move-to-window-line (min (window-height)
379 (+ row company-tooltip-limit)))
383 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
385 (overlay-put company-pseudo-tooltip-overlay 'before-string
386 (company-modified-substring beg end lines column))
387 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
388 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
390 (defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
391 (let ((col-row (posn-col-row (posn-at-point pos))))
392 (company-pseudo-tooltip-show (1+ (cdr col-row))
393 (car col-row) text selection)))
395 (defun company-pseudo-tooltip-hide ()
396 (when company-pseudo-tooltip-overlay
397 (delete-overlay company-pseudo-tooltip-overlay)
398 (setq company-pseudo-tooltip-overlay nil)))
400 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
402 (defvar company-preview-overlay nil)
403 (make-variable-buffer-local 'company-preview-overlay)
405 (defun company-preview-show-at-point (pos text &optional selection)
406 (company-preview-hide)
408 (setq company-preview-overlay (make-overlay pos pos))
410 (let ((completion (company-strip-prefix (nth company-selection
411 company-candidates))))
412 (and (equal pos (point))
413 (not (equal completion ""))
414 (add-text-properties 0 1 '(cursor t) completion))
416 (setq completion (propertize completion 'face 'company-preview))
417 (add-text-properties 0 (- (length company-common) (length company-prefix))
418 '(face company-preview-common) completion)
420 (overlay-put company-preview-overlay 'after-string completion)
421 (overlay-put company-preview-overlay 'window (selected-window))))
423 (defun company-preview-hide ()
424 (when company-preview-overlay
425 (delete-overlay company-preview-overlay)
426 (setq company-preview-overlay nil)))
428 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
430 (defvar company-echo-last-msg nil)
431 (make-variable-buffer-local 'company-echo-last-msg)
433 (defun company-echo-refresh ()
434 (let ((message-log-max nil))
435 (if company-echo-last-msg
436 (message "%s" company-echo-last-msg)
439 (defun company-echo-show (candidates)
441 ;; Roll to selection.
442 (setq candidates (nthcdr company-selection candidates))
444 (let ((limit (window-width (minibuffer-window)))
448 (setq comp (pop candidates)
449 len (+ len 1 (length comp)))
451 (setq candidates nil)
452 (setq comp (propertize comp 'face 'company-echo))
453 (add-text-properties 0 (length company-common)
454 '(face company-echo-common) comp)
457 (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
458 (company-echo-refresh)))
460 (defun company-echo-hide ()
461 (setq company-echo-last-msg nil))
464 ;;; company.el ends here