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