]> code.delx.au - gnu-emacs-elpa/blob - company.el
b2a4582adbfd8bb30ae63ee34eba079ca1a8bac2
[gnu-emacs-elpa] / company.el
1 (eval-when-compile (require 'cl))
2
3 (add-to-list 'debug-ignored-errors
4 "^Pseudo tooltip frontend cannot be used twice$")
5 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
6
7 (defgroup company nil
8 ""
9 :group 'abbrev
10 :group 'convenience
11 :group 'maching)
12
13 (defface company-tooltip
14 '((t :background "yellow"
15 :foreground "black"))
16 "*"
17 :group 'company)
18
19 (defface company-tooltip-selection
20 '((t :background "orange1"
21 :foreground "black"))
22 "*"
23 :group 'company)
24
25 (defface company-tooltip-common
26 '((t :inherit company-tooltip
27 :foreground "red"))
28 "*"
29 :group 'company)
30
31 (defface company-tooltip-common-selection
32 '((t :inherit company-tooltip-selection
33 :foreground "red"))
34 "*"
35 :group 'company)
36
37 (defcustom company-tooltip-limit 10
38 "*"
39 :group 'company
40 :type 'integer)
41
42 (defface company-preview
43 '((t :background "blue4"
44 :foreground "wheat"))
45 "*"
46 :group 'company)
47
48 (defface company-preview-common
49 '((t :inherit company-preview
50 :foreground "red"))
51 "*"
52 :group 'company)
53
54 (defface company-echo nil
55 "*"
56 :group 'company)
57
58 (defface company-echo-common
59 '((((background dark)) (:foreground "firebrick1"))
60 (((background light)) (:background "firebrick4")))
61 "*"
62 :group 'company)
63
64 (defun company-frontends-set (variable value)
65 ;; uniquify
66 (let ((remainder value))
67 (setcdr remainder (delq (car remainder) (cdr remainder))))
68 (and (memq 'company-pseudo-tooltip-unless-just-one-frontend value)
69 (memq 'company-pseudo-tooltip-frontend value)
70 (error "Pseudo tooltip frontend cannot be used twice"))
71 (and (memq 'company-preview-if-just-one-frontend value)
72 (memq 'company-preview-frontend value)
73 (error "Preview frontend cannot be used twice"))
74 ;; preview must come last
75 (dolist (f '(company-preview-if-just-one-frontend company-preview-frontend))
76 (when (memq f value)
77 (setq value (append (delq f value) (list f)))))
78 (set variable value))
79
80 (defcustom company-frontends '(company-echo-frontend
81 company-pseudo-tooltip-unless-just-one-frontend
82 company-preview-if-just-one-frontend)
83 "*"
84 :set 'company-frontends-set
85 :group 'company
86 :type '(repeat (choice (const :tag "echo" company-echo-frontend)
87 (const :tag "pseudo tooltip"
88 company-pseudo-tooltip-frontend)
89 (const :tag "pseudo tooltip, multiple only"
90 company-pseudo-tooltip-unless-just-one-frontend)
91 (const :tag "preview" company-preview-frontend)
92 (const :tag "preview, unique only"
93 company-preview-if-just-one-frontend)
94 (function :tag "custom function" nil))))
95
96 (defcustom company-backends '(company-elisp company-nxml company-css
97 company-semantic company-ispell)
98 "*"
99 :group 'company
100 :type '(repeat (function :tag "function" nil)))
101
102 (defcustom company-minimum-prefix-length 3
103 "*"
104 :group 'company
105 :type '(integer :tag "prefix length"))
106
107 (defvar company-timer nil)
108
109 (defun company-timer-set (variable value)
110 (set variable value)
111 (when company-timer (cancel-timer company-timer))
112 (when (numberp value)
113 (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
114
115 (defcustom company-idle-delay .7
116 "*"
117 :set 'company-timer-set
118 :group 'company
119 :type '(choice (const :tag "never (nil)" nil)
120 (const :tag "immediate (t)" t)
121 (number :tag "seconds")))
122
123 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124
125 (defvar company-mode-map
126 (let ((keymap (make-sparse-keymap)))
127 (define-key keymap (kbd "M-n") 'company-select-next)
128 (define-key keymap (kbd "M-p") 'company-select-previous)
129 (define-key keymap (kbd "M-<return>") 'company-complete-selection)
130 (define-key keymap "\t" 'company-complete)
131 keymap))
132
133 ;;;###autoload
134 (define-minor-mode company-mode
135 ""
136 nil " comp" company-mode-map
137 (if company-mode
138 (progn
139 (add-hook 'pre-command-hook 'company-pre-command nil t)
140 (add-hook 'post-command-hook 'company-post-command nil t)
141 (company-timer-set 'company-idle-delay
142 company-idle-delay))
143 (remove-hook 'pre-command-hook 'company-pre-command t)
144 (remove-hook 'post-command-hook 'company-post-command t)
145 (company-cancel)
146 (kill-local-variable 'company-point)))
147
148 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
149
150 (defun company-grab (regexp &optional expression)
151 (when (looking-back regexp)
152 (or (match-string-no-properties (or expression 0)) "")))
153
154 (defun company-in-string-or-comment (&optional point)
155 (let ((pos (syntax-ppss)))
156 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
157
158 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159
160 (defvar company-backend nil)
161 (make-variable-buffer-local 'company-backend)
162
163 (defvar company-prefix nil)
164 (make-variable-buffer-local 'company-prefix)
165
166 (defvar company-candidates nil)
167 (make-variable-buffer-local 'company-candidates)
168
169 (defvar company-candidates-cache nil)
170 (make-variable-buffer-local 'company-candidates-cache)
171
172 (defvar company-common nil)
173 (make-variable-buffer-local 'company-common)
174
175 (defvar company-selection 0)
176 (make-variable-buffer-local 'company-selection)
177
178 (defvar company-selection-changed nil)
179 (make-variable-buffer-local 'company-selection-changed)
180
181 (defvar company-point nil)
182 (make-variable-buffer-local 'company-point)
183
184 (defvar company-disabled-backends nil)
185
186 (defsubst company-strip-prefix (str)
187 (substring str (length company-prefix)))
188
189 (defsubst company-reformat (candidate)
190 ;; company-ispell needs this, because the results are always lower-case
191 ;; It's mory efficient to fix it only when they are displayed.
192 (concat company-prefix (substring candidate (length company-prefix))))
193
194 (defsubst company-should-complete (prefix)
195 (and (eq company-idle-delay t)
196 (>= (length prefix) company-minimum-prefix-length)))
197
198 (defsubst company-call-frontends (command)
199 (dolist (frontend company-frontends)
200 (funcall frontend command)))
201
202 (defsubst company-calculate-candidates (prefix)
203 (or (setq company-candidates (cdr (assoc prefix company-candidates-cache)))
204 (let ((len (length prefix))
205 (completion-ignore-case (funcall company-backend 'ignore-case))
206 prev)
207 (dotimes (i len)
208 (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
209 company-candidates-cache)))
210 (setq company-candidates (all-completions prefix prev))
211 (return t))))
212 (progn
213 (setq company-candidates (funcall company-backend 'candidates prefix))
214 (unless (funcall company-backend 'sorted)
215 (setq company-candidates (sort company-candidates 'string<)))))
216 (unless (assoc prefix company-candidates-cache)
217 (push (cons prefix company-candidates) company-candidates-cache))
218 (setq company-selection 0
219 company-prefix prefix)
220 (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
221 (setq company-common (try-completion company-prefix company-candidates)))
222 (when (eq company-common t)
223 (setq company-candidates nil))
224 company-candidates)
225
226 (defun company-idle-begin ()
227 (and company-mode
228 (not company-candidates)
229 (not (equal (point) company-point))
230 (let ((company-idle-delay t))
231 (company-begin)
232 (company-post-command))))
233
234 (defun company-manual-begin ()
235 (and company-mode
236 (not company-candidates)
237 (let ((company-idle-delay t)
238 (company-minimum-prefix-length 0))
239 (company-begin)))
240 ;; Return non-nil if active.
241 company-candidates)
242
243 (defun company-continue ()
244 (when company-candidates
245 (let ((new-prefix (funcall company-backend 'prefix)))
246 (unless (and (= (- (point) (length new-prefix))
247 (- company-point (length company-prefix)))
248 (or (equal company-prefix new-prefix)
249 (company-calculate-candidates new-prefix)))
250 (setq company-candidates nil)))))
251
252 (defun company-begin ()
253 (company-continue)
254 (unless company-candidates
255 (let (prefix)
256 (dolist (backend company-backends)
257 (unless (fboundp backend)
258 (ignore-errors (require backend nil t)))
259 (if (fboundp backend)
260 (when (setq prefix (funcall backend 'prefix))
261 (when (company-should-complete prefix)
262 (setq company-backend backend)
263 (company-calculate-candidates prefix))
264 (return prefix))
265 (unless (memq backend company-disabled-backends)
266 (push backend company-disabled-backends)
267 (message "Company back-end '%s' could not be initialized"
268 backend))))))
269 (if company-candidates
270 (progn
271 (setq company-point (point))
272 (company-call-frontends 'update))
273 (company-cancel)))
274
275 (defun company-cancel ()
276 (setq company-backend nil
277 company-prefix nil
278 company-candidates nil
279 company-candidates-cache nil
280 company-common nil
281 company-selection 0
282 company-selection-changed nil
283 company-point nil)
284 (company-call-frontends 'hide))
285
286 (defun company-abort ()
287 (company-cancel)
288 ;; Don't start again, unless started manually.
289 (setq company-point (point)))
290
291 (defun company-pre-command ()
292 (when company-candidates
293 (company-call-frontends 'pre-command)))
294
295 (defun company-post-command ()
296 (unless (equal (point) company-point)
297 (company-begin))
298 (when company-candidates
299 (company-call-frontends 'post-command)))
300
301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
302
303 (defun company-select-next ()
304 (interactive)
305 (when (company-manual-begin)
306 (setq company-selection (min (1- (length company-candidates))
307 (1+ company-selection))
308 company-selection-changed t))
309 (company-call-frontends 'update))
310
311 (defun company-select-previous ()
312 (interactive)
313 (when (company-manual-begin)
314 (setq company-selection (max 0 (1- company-selection))
315 company-selection-changed t))
316 (company-call-frontends 'update))
317
318 (defun company-complete-selection ()
319 (interactive)
320 (when (company-manual-begin)
321 (insert (company-strip-prefix (nth company-selection company-candidates)))
322 (company-abort)))
323
324 (defun company-complete-common ()
325 (interactive)
326 (when (company-manual-begin)
327 (insert (company-strip-prefix company-common))))
328
329 (defun company-complete ()
330 (interactive)
331 (when (company-manual-begin)
332 (if (or company-selection-changed
333 (eq last-command 'company-complete-common))
334 (call-interactively 'company-complete-selection)
335 (call-interactively 'company-complete-common)
336 (setq this-command 'company-complete-common))))
337
338 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
339
340 (defconst company-space-strings-limit 100)
341
342 (defconst company-space-strings
343 (let (lst)
344 (dotimes (i company-space-strings-limit)
345 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
346 (apply 'vector lst)))
347
348 (defsubst company-space-string (len)
349 (if (< len company-space-strings-limit)
350 (aref company-space-strings len)
351 (make-string len ?\ )))
352
353 (defsubst company-safe-substring (str from &optional to)
354 (let ((len (length str)))
355 (if (> from len)
356 ""
357 (if (and to (> to len))
358 (concat (substring str from)
359 (company-space-string (- to len)))
360 (substring str from to)))))
361
362 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
363
364 (defvar company-pseudo-tooltip-overlay nil)
365 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
366
367 (defvar company-tooltip-offset 0)
368 (make-variable-buffer-local 'company-tooltip-offset)
369
370 (defun company-pseudo-tooltip-update-offset (selection num-lines limit)
371
372 (decf limit 2)
373 (setq company-tooltip-offset
374 (max (min selection company-tooltip-offset)
375 (- selection -1 limit)))
376
377 (when (<= company-tooltip-offset 1)
378 (incf limit)
379 (setq company-tooltip-offset 0))
380
381 (when (>= company-tooltip-offset (- num-lines limit 1))
382 (incf limit)
383 (when (= selection (1- num-lines))
384 (setq company-tooltip-offset (max (1- company-tooltip-offset) 0))))
385
386 limit)
387
388 ;;; propertize
389
390 (defun company-fill-propertize (line width selected)
391 (setq line (company-safe-substring line 0 width))
392 (add-text-properties 0 width
393 (list 'face (if selected
394 'company-tooltip-selection
395 'company-tooltip)) line)
396 (add-text-properties 0 (length company-common)
397 (list 'face (if selected
398 'company-tooltip-common-selection
399 'company-tooltip-common)) line)
400 line)
401
402 ;;; replace
403
404 (defun company-buffer-lines (beg end)
405 (goto-char beg)
406 (let ((row (cdr (posn-col-row (posn-at-point))))
407 lines)
408 (while (< (point) end)
409 (move-to-window-line (incf row))
410 (push (buffer-substring beg (min end (1- (point)))) lines)
411 (setq beg (point)))
412 (nreverse lines)))
413
414 (defun company-modify-line (old new offset)
415 (concat (company-safe-substring old 0 offset)
416 new
417 (company-safe-substring old (+ offset (length new)))))
418
419 (defun company-replacement-string (old lines column nl)
420 (let (new)
421 ;; Inject into old lines.
422 (while old
423 (push (company-modify-line (pop old) (pop lines) column) new))
424 ;; Append whole new lines.
425 (while lines
426 (push (company-modify-line "" (pop lines) column) new))
427 (concat (when nl "\n")
428 (mapconcat 'identity (nreverse new) "\n")
429 "\n")))
430
431 (defun company-create-lines (column lines selection)
432
433 (let ((limit (max company-tooltip-limit 3))
434 (len (length lines))
435 width
436 lines-copy
437 previous
438 remainder
439 new)
440
441 ;; Scroll to offset.
442 (setq limit (company-pseudo-tooltip-update-offset selection len limit))
443
444 (when (> company-tooltip-offset 0)
445 (setq previous (format "...(%d)" company-tooltip-offset)))
446
447 (setq remainder (- len limit company-tooltip-offset)
448 remainder (when (> remainder 0)
449 (setq remainder (format "...(%d)" remainder))))
450
451 (decf selection company-tooltip-offset)
452 (setq width (min (length previous) (length remainder))
453 lines (nthcdr company-tooltip-offset lines)
454 len (min limit (length lines))
455 lines-copy lines)
456
457 (dotimes (i len)
458 (setq width (max (length (pop lines-copy)) width)))
459 (setq width (min width (- (window-width) column)))
460
461 (when previous
462 (push (propertize (company-safe-substring previous 0 width)
463 'face 'company-tooltip)
464 new))
465
466 (dotimes (i len)
467 (push (company-fill-propertize (company-reformat (pop lines))
468 width (equal i selection))
469 new))
470
471 (when remainder
472 (push (propertize (company-safe-substring remainder 0 width)
473 'face 'company-tooltip)
474 new))
475
476 (setq lines (nreverse new))))
477
478 ;; show
479
480 (defun company-pseudo-tooltip-show (row column lines selection)
481 (company-pseudo-tooltip-hide)
482 (unless lines (error "No text provided"))
483 (save-excursion
484
485 (move-to-column 0)
486
487 (let* ((lines (company-create-lines column lines selection))
488 (nl (< (move-to-window-line row) row))
489 (beg (point))
490 (end (save-excursion
491 (move-to-window-line (min (window-height)
492 (+ row company-tooltip-limit)))
493 (point)))
494 (old-string (company-buffer-lines beg end))
495 str)
496
497 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
498
499 (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
500 (overlay-put company-pseudo-tooltip-overlay 'company-column column)
501 (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
502 (overlay-put company-pseudo-tooltip-overlay 'company-before
503 (company-replacement-string old-string lines column nl))
504
505 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
506
507 (defun company-pseudo-tooltip-show-at-point (pos)
508 (let ((col-row (posn-col-row (posn-at-point pos))))
509 (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
510 company-candidates company-selection)))
511
512 (defun company-pseudo-tooltip-edit (lines selection)
513 (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
514 (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
515 (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
516 (lines (company-create-lines column lines selection)))
517 (overlay-put company-pseudo-tooltip-overlay 'company-before
518 (company-replacement-string old-string lines column nl))))
519
520 (defun company-pseudo-tooltip-hide ()
521 (when company-pseudo-tooltip-overlay
522 (delete-overlay company-pseudo-tooltip-overlay)
523 (setq company-pseudo-tooltip-overlay nil)))
524
525 (defun company-pseudo-tooltip-hide-temporarily ()
526 (when (overlayp company-pseudo-tooltip-overlay)
527 (overlay-put company-pseudo-tooltip-overlay 'invisible nil)
528 (overlay-put company-pseudo-tooltip-overlay 'before-string nil)))
529
530 (defun company-pseudo-tooltip-unhide ()
531 (when company-pseudo-tooltip-overlay
532 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
533 (overlay-put company-pseudo-tooltip-overlay 'before-string
534 (overlay-get company-pseudo-tooltip-overlay 'company-before))))
535
536 (defun company-pseudo-tooltip-frontend (command)
537 (case command
538 ('pre-command (company-pseudo-tooltip-hide-temporarily))
539 ('post-command
540 (unless (overlayp company-pseudo-tooltip-overlay)
541 (company-pseudo-tooltip-show-at-point (- (point)
542 (length company-prefix))))
543 (company-pseudo-tooltip-unhide))
544 ('hide (company-pseudo-tooltip-hide)
545 (setq company-tooltip-offset 0))
546 ('update (when (overlayp company-pseudo-tooltip-overlay)
547 (company-pseudo-tooltip-edit company-candidates
548 company-selection)))))
549
550 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
551 (unless (and (eq command 'post-command)
552 (not (cdr company-candidates)))
553 (company-pseudo-tooltip-frontend command)))
554
555 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
556
557 (defvar company-preview-overlay nil)
558 (make-variable-buffer-local 'company-preview-overlay)
559
560 (defun company-preview-show-at-point (pos)
561 (company-preview-hide)
562
563 (setq company-preview-overlay (make-overlay pos pos))
564
565 (let ((completion (company-strip-prefix (nth company-selection
566 company-candidates))))
567 (and (equal pos (point))
568 (not (equal completion ""))
569 (add-text-properties 0 1 '(cursor t) completion))
570
571 (setq completion (propertize completion 'face 'company-preview))
572 (add-text-properties 0 (- (length company-common) (length company-prefix))
573 '(face company-preview-common) completion)
574
575 (overlay-put company-preview-overlay 'after-string completion)
576 (overlay-put company-preview-overlay 'window (selected-window))))
577
578 (defun company-preview-hide ()
579 (when company-preview-overlay
580 (delete-overlay company-preview-overlay)
581 (setq company-preview-overlay nil)))
582
583 (defun company-preview-frontend (command)
584 (case command
585 ('pre-command (company-preview-hide))
586 ('post-command (company-preview-show-at-point (point)))
587 ('hide (company-preview-hide))))
588
589 (defun company-preview-if-just-one-frontend (command)
590 (unless (and (eq command 'post-command)
591 (cdr company-candidates))
592 (company-preview-frontend command)))
593
594 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
595
596 (defvar company-echo-last-msg nil)
597 (make-variable-buffer-local 'company-echo-last-msg)
598
599 (defun company-echo-refresh ()
600 (let ((message-log-max nil))
601 (if company-echo-last-msg
602 (message "%s" company-echo-last-msg)
603 (message ""))))
604
605 (defun company-echo-show (candidates)
606
607 ;; Roll to selection.
608 (setq candidates (nthcdr company-selection candidates))
609
610 (let ((limit (window-width (minibuffer-window)))
611 (len -1)
612 comp msg)
613 (while candidates
614 (setq comp (company-reformat (pop candidates))
615 len (+ len 1 (length comp)))
616 (if (>= len limit)
617 (setq candidates nil)
618 (setq comp (propertize comp 'face 'company-echo))
619 (add-text-properties 0 (length company-common)
620 '(face company-echo-common) comp)
621 (push comp msg)))
622
623 (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
624 (company-echo-refresh)))
625
626 (defun company-echo-frontend (command)
627 (case command
628 ('pre-command (company-echo-refresh))
629 ('post-command (company-echo-show company-candidates))
630 ('hide (setq company-echo-last-msg nil))))
631
632 (provide 'company)
633 ;;; company.el ends here