]> code.delx.au - gnu-emacs-elpa/blob - company.el
Keep selection when updating completions.
[gnu-emacs-elpa] / company.el
1 ;;; company.el --- extensible inline text completion mechanism
2 ;;
3 ;; Copyright (C) 2009 Nikolaj Schumacher
4 ;;
5 ;; Author: Nikolaj Schumacher <bugs * nschum de>
6 ;; Version:
7 ;; Keywords: abbrev, convenience, matchis
8 ;; URL: http://nschum.de/src/emacs/company/
9 ;; Compatibility: GNU Emacs 23.x
10 ;;
11 ;; This file is NOT part of GNU Emacs.
12 ;;
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License
15 ;; as published by the Free Software Foundation; either version 2
16 ;; of the License, or (at your option) any later version.
17 ;;
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22 ;;
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ;;
26 ;;; Commentary:
27 ;;
28 ;;; Change Log:
29 ;;
30 ;; Initial release.
31 ;;
32 ;;; Code:
33
34 (eval-when-compile (require 'cl))
35
36 (add-to-list 'debug-ignored-errors
37 "^Pseudo tooltip frontend cannot be used twice$")
38 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
39 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
40 (add-to-list 'debug-ignored-errors "^No documentation available$")
41
42 (defgroup company nil
43 ""
44 :group 'abbrev
45 :group 'convenience
46 :group 'maching)
47
48 (defface company-tooltip
49 '((t :background "yellow"
50 :foreground "black"))
51 "*"
52 :group 'company)
53
54 (defface company-tooltip-selection
55 '((t :background "orange1"
56 :foreground "black"))
57 "*"
58 :group 'company)
59
60 (defface company-tooltip-common
61 '((t :inherit company-tooltip
62 :foreground "red"))
63 "*"
64 :group 'company)
65
66 (defface company-tooltip-common-selection
67 '((t :inherit company-tooltip-selection
68 :foreground "red"))
69 "*"
70 :group 'company)
71
72 (defcustom company-tooltip-limit 10
73 "*"
74 :group 'company
75 :type 'integer)
76
77 (defface company-preview
78 '((t :background "blue4"
79 :foreground "wheat"))
80 "*"
81 :group 'company)
82
83 (defface company-preview-common
84 '((t :inherit company-preview
85 :foreground "red"))
86 "*"
87 :group 'company)
88
89 (defface company-echo nil
90 "*"
91 :group 'company)
92
93 (defface company-echo-common
94 '((((background dark)) (:foreground "firebrick1"))
95 (((background light)) (:background "firebrick4")))
96 "*"
97 :group 'company)
98
99 (defun company-frontends-set (variable value)
100 ;; uniquify
101 (let ((remainder value))
102 (setcdr remainder (delq (car remainder) (cdr remainder))))
103 (and (memq 'company-pseudo-tooltip-unless-just-one-frontend value)
104 (memq 'company-pseudo-tooltip-frontend value)
105 (error "Pseudo tooltip frontend cannot be used twice"))
106 (and (memq 'company-preview-if-just-one-frontend value)
107 (memq 'company-preview-frontend value)
108 (error "Preview frontend cannot be used twice"))
109 (and (memq 'company-echo value)
110 (memq 'company-echo-metadata-frontend value)
111 (error "Echo area cannot be used twice"))
112 ;; preview must come last
113 (dolist (f '(company-preview-if-just-one-frontend company-preview-frontend))
114 (when (memq f value)
115 (setq value (append (delq f value) (list f)))))
116 (set variable value))
117
118 (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
119 company-preview-if-just-one-frontend
120 company-echo-metadata-frontend)
121 "*"
122 :set 'company-frontends-set
123 :group 'company
124 :type '(repeat (choice (const :tag "echo" company-echo-frontend)
125 (const :tag "pseudo tooltip"
126 company-pseudo-tooltip-frontend)
127 (const :tag "pseudo tooltip, multiple only"
128 company-pseudo-tooltip-unless-just-one-frontend)
129 (const :tag "preview" company-preview-frontend)
130 (const :tag "preview, unique only"
131 company-preview-if-just-one-frontend)
132 (function :tag "custom function" nil))))
133
134 (defcustom company-backends '(company-elisp company-nxml company-css
135 company-semantic company-oddmuse
136 company-files company-dabbrev)
137 "*"
138 :group 'company
139 :type '(repeat (function :tag "function" nil)))
140
141 (defcustom company-minimum-prefix-length 3
142 "*"
143 :group 'company
144 :type '(integer :tag "prefix length"))
145
146 (defvar company-timer nil)
147
148 (defun company-timer-set (variable value)
149 (set variable value)
150 (when company-timer (cancel-timer company-timer))
151 (when (numberp value)
152 (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
153
154 (defcustom company-idle-delay .7
155 "*"
156 :set 'company-timer-set
157 :group 'company
158 :type '(choice (const :tag "never (nil)" nil)
159 (const :tag "immediate (t)" t)
160 (number :tag "seconds")))
161
162 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
163
164 (defvar company-mode-map (make-sparse-keymap))
165
166 (defvar company-active-map
167 (let ((keymap (make-sparse-keymap)))
168 (define-key keymap (kbd "M-n") 'company-select-next)
169 (define-key keymap (kbd "M-p") 'company-select-previous)
170 (define-key keymap "\C-m" 'company-complete-selection)
171 (define-key keymap "\t" 'company-complete-common)
172 (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
173 (define-key keymap "\C-s" 'company-search-candidates)
174 keymap))
175
176 ;;;###autoload
177 (define-minor-mode company-mode
178 ""
179 nil " comp" company-mode-map
180 (if company-mode
181 (progn
182 (add-hook 'pre-command-hook 'company-pre-command nil t)
183 (add-hook 'post-command-hook 'company-post-command nil t)
184 (company-timer-set 'company-idle-delay
185 company-idle-delay))
186 (remove-hook 'pre-command-hook 'company-pre-command t)
187 (remove-hook 'post-command-hook 'company-post-command t)
188 (company-cancel)
189 (kill-local-variable 'company-point)))
190
191 ;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
192
193 (defvar company-overriding-keymap-bound nil)
194 (make-variable-buffer-local 'company-overriding-keymap-bound)
195
196 (defvar company-old-keymap nil)
197 (make-variable-buffer-local 'company-old-keymap)
198
199 (defvar company-my-keymap nil)
200 (make-variable-buffer-local 'company-my-keymap)
201
202 (defsubst company-enable-overriding-keymap (keymap)
203 (setq company-my-keymap keymap)
204 (when company-overriding-keymap-bound
205 (company-uninstall-map)))
206
207 (defun company-install-map ()
208 (unless (or company-overriding-keymap-bound
209 (null company-my-keymap))
210 (setq company-old-keymap overriding-terminal-local-map
211 overriding-terminal-local-map company-my-keymap
212 company-overriding-keymap-bound t)))
213
214 (defun company-uninstall-map ()
215 (when (and company-overriding-keymap-bound
216 (eq overriding-terminal-local-map company-my-keymap))
217 (setq overriding-terminal-local-map company-old-keymap
218 company-overriding-keymap-bound nil)))
219
220 ;; Hack:
221 ;; Emacs calculates the active keymaps before reading the event. That means we
222 ;; cannot change the keymap from a timer. So we send a bogus command.
223 (defun company-ignore ()
224 (interactive))
225
226 (global-set-key '[31415926] 'company-ignore)
227
228 (defun company-input-noop ()
229 (push 31415926 unread-command-events))
230
231 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
232
233 (defun company-grab (regexp &optional expression)
234 (when (looking-back regexp)
235 (or (match-string-no-properties (or expression 0)) "")))
236
237 (defun company-in-string-or-comment (&optional point)
238 (let ((pos (syntax-ppss)))
239 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
240
241 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
242
243 (defvar company-backend nil)
244 (make-variable-buffer-local 'company-backend)
245
246 (defvar company-prefix nil)
247 (make-variable-buffer-local 'company-prefix)
248
249 (defvar company-candidates nil)
250 (make-variable-buffer-local 'company-candidates)
251
252 (defvar company-candidates-cache nil)
253 (make-variable-buffer-local 'company-candidates-cache)
254
255 (defvar company-candidates-predicate nil)
256 (make-variable-buffer-local 'company-candidates-predicate)
257
258 (defvar company-common nil)
259 (make-variable-buffer-local 'company-common)
260
261 (defvar company-selection 0)
262 (make-variable-buffer-local 'company-selection)
263
264 (defvar company-selection-changed nil)
265 (make-variable-buffer-local 'company-selection-changed)
266
267 (defvar company-point nil)
268 (make-variable-buffer-local 'company-point)
269
270 (defvar company-disabled-backends nil)
271
272 (defsubst company-strip-prefix (str)
273 (substring str (length company-prefix)))
274
275 (defsubst company-reformat (candidate)
276 ;; company-ispell needs this, because the results are always lower-case
277 ;; It's mory efficient to fix it only when they are displayed.
278 (concat company-prefix (substring candidate (length company-prefix))))
279
280 (defsubst company-should-complete (prefix)
281 (and (eq company-idle-delay t)
282 (>= (length prefix) company-minimum-prefix-length)))
283
284 (defsubst company-call-frontends (command)
285 (dolist (frontend company-frontends)
286 (funcall frontend command)))
287
288 (defsubst company-set-selection (selection &optional force-update)
289 (setq selection (max 0 (min (1- (length company-candidates)) selection)))
290 (when (or force-update (not (equal selection company-selection)))
291 (setq company-selection selection
292 company-selection-changed t)
293 (company-call-frontends 'update)))
294
295 (defun company-apply-predicate (candidates predicate)
296 (let (new)
297 (dolist (c candidates)
298 (when (funcall predicate c)
299 (push c new)))
300 (nreverse new)))
301
302 (defun company-update-candidates (candidates)
303 (if (> company-selection 0)
304 ;; Try to restore the selection
305 (let ((selected (nth company-selection company-candidates)))
306 (setq company-selection 0
307 company-candidates candidates)
308 (when selected
309 (while (and candidates (string< (pop candidates) selected))
310 (incf company-selection))
311 (unless candidates
312 ;; Make sure selection isn't out of bounds.
313 (setq company-selection (min (1- (length company-candidates))
314 company-selection)))))
315 (setq company-selection 0
316 company-candidates candidates))
317 ;; Calculate common.
318 (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
319 (setq company-common (try-completion company-prefix company-candidates)))
320 (when (eq company-common t)
321 (setq company-candidates nil)))
322
323 (defsubst company-calculate-candidates (prefix)
324 (setq company-prefix prefix)
325 (company-update-candidates
326 (or (cdr (assoc prefix company-candidates-cache))
327 (let ((len (length prefix))
328 (completion-ignore-case (funcall company-backend 'ignore-case))
329 prev)
330 (dotimes (i len)
331 (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
332 company-candidates-cache)))
333 (return (all-completions prefix prev)))))
334 (let ((candidates (funcall company-backend 'candidates prefix)))
335 (and company-candidates-predicate
336 (setq candidates
337 (company-apply-predicate candidates
338 company-candidates-predicate)))
339 (unless (funcall company-backend 'sorted)
340 (setq candidates (sort candidates 'string<)))
341 candidates)))
342 (unless (assoc prefix company-candidates-cache)
343 (push (cons prefix company-candidates) company-candidates-cache))
344 company-candidates)
345
346 (defun company-idle-begin ()
347 (and company-mode
348 (not company-candidates)
349 (not (equal (point) company-point))
350 (let ((company-idle-delay t))
351 (company-begin)
352 (when company-candidates
353 (company-input-noop)
354 (company-post-command)))))
355
356 (defun company-manual-begin ()
357 (and company-mode
358 (not company-candidates)
359 (let ((company-idle-delay t)
360 (company-minimum-prefix-length 0))
361 (company-begin)))
362 ;; Return non-nil if active.
363 company-candidates)
364
365 (defun company-continue ()
366 (when company-candidates
367 (when (funcall company-backend 'no-cache)
368 ;; Don't complete existing candidates, fetch new ones.
369 (setq company-candidates-cache nil))
370 (let ((new-prefix (funcall company-backend 'prefix)))
371 (unless (and (= (- (point) (length new-prefix))
372 (- company-point (length company-prefix)))
373 (or (equal company-prefix new-prefix)
374 (company-calculate-candidates new-prefix)))
375 (setq company-candidates nil)))))
376
377 (defun company-begin ()
378 (if (or buffer-read-only overriding-terminal-local-map overriding-local-map)
379 ;; Don't complete in these cases.
380 (setq company-candidates nil)
381 (company-continue)
382 (unless company-candidates
383 (let (prefix)
384 (dolist (backend company-backends)
385 (unless (fboundp backend)
386 (ignore-errors (require backend nil t)))
387 (if (fboundp backend)
388 (when (setq prefix (funcall backend 'prefix))
389 (when (company-should-complete prefix)
390 (setq company-backend backend)
391 (company-calculate-candidates prefix))
392 (return prefix))
393 (unless (memq backend company-disabled-backends)
394 (push backend company-disabled-backends)
395 (message "Company back-end '%s' could not be initialized"
396 backend)))))))
397 (if company-candidates
398 (progn
399 (setq company-point (point))
400 (company-enable-overriding-keymap company-active-map)
401 (company-call-frontends 'update))
402 (company-cancel)))
403
404 (defun company-cancel ()
405 (setq company-backend nil
406 company-prefix nil
407 company-candidates nil
408 company-candidates-cache nil
409 company-candidates-predicate nil
410 company-common nil
411 company-selection 0
412 company-selection-changed nil
413 company-point nil)
414 (company-search-mode 0)
415 (company-call-frontends 'hide)
416 (company-enable-overriding-keymap nil))
417
418 (defun company-abort ()
419 (company-cancel)
420 ;; Don't start again, unless started manually.
421 (setq company-point (point)))
422
423 (defun company-pre-command ()
424 (unless (eq this-command 'company-show-doc-buffer)
425 (condition-case err
426 (when company-candidates
427 (company-call-frontends 'pre-command))
428 (error (message "Company: An error occurred in pre-command")
429 (message "%s" (error-message-string err))
430 (company-cancel))))
431 (company-uninstall-map))
432
433 (defun company-post-command ()
434 (unless (eq this-command 'company-show-doc-buffer)
435 (condition-case err
436 (progn
437 (unless (equal (point) company-point)
438 (company-begin))
439 (when company-candidates
440 (company-call-frontends 'post-command)))
441 (error (message "Company: An error occurred in post-command")
442 (message "%s" (error-message-string err))
443 (company-cancel))))
444 (company-install-map))
445
446 ;;; search ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447
448 (defvar company-search-string nil)
449 (make-variable-buffer-local 'company-search-string)
450
451 (defvar company-search-lighter " Search: \"\"")
452 (make-variable-buffer-local 'company-search-lighter)
453
454 (defvar company-search-old-map nil)
455 (make-variable-buffer-local 'company-search-old-map)
456
457 (defvar company-search-old-selection 0)
458 (make-variable-buffer-local 'company-search-old-selection)
459
460 (defun company-search (text lines)
461 (let ((quoted (regexp-quote text))
462 (i 0))
463 (dolist (line lines)
464 (when (string-match quoted line (length company-prefix))
465 (return i))
466 (incf i))))
467
468 (defun company-search-printing-char ()
469 (interactive)
470 (setq company-search-string
471 (concat (or company-search-string "") (string last-command-event))
472 company-search-lighter (concat " Search: \"" company-search-string
473 "\""))
474 (let ((pos (company-search company-search-string
475 (nthcdr company-selection company-candidates))))
476 (if (null pos)
477 (ding)
478 (company-set-selection (+ company-selection pos) t))))
479
480 (defun company-search-repeat-forward ()
481 (interactive)
482 (let ((pos (company-search company-search-string
483 (cdr (nthcdr company-selection
484 company-candidates)))))
485 (if (null pos)
486 (ding)
487 (company-set-selection (+ company-selection pos 1) t))))
488
489 (defun company-search-repeat-backward ()
490 (interactive)
491 (let ((pos (company-search company-search-string
492 (nthcdr (- (length company-candidates)
493 company-selection)
494 (reverse company-candidates)))))
495 (if (null pos)
496 (ding)
497 (company-set-selection (- company-selection pos 1) t))))
498
499 (defun company-search-kill-others ()
500 (interactive)
501 (let ((predicate `(lambda (candidate)
502 (string-match ,company-search-string candidate))))
503 (company-cancel)
504 (setq company-candidates-predicate predicate)
505 (company-manual-begin)))
506
507 (defun company-search-abort ()
508 (interactive)
509 (company-set-selection company-search-old-selection t)
510 (company-search-mode 0))
511
512 (defun company-search-other-char ()
513 (interactive)
514 (company-search-mode 0)
515 (when last-input-event
516 (clear-this-command-keys t)
517 (setq unread-command-events (list last-input-event))))
518
519 (defvar company-search-map
520 (let ((i 0)
521 (keymap (make-keymap)))
522 (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
523 'company-search-printing-char)
524 (define-key keymap [t] 'company-search-other-char)
525 (while (< i ?\s)
526 (define-key keymap (make-string 1 i) 'company-search-other-char)
527 (incf i))
528 (while (< i 256)
529 (define-key keymap (vector i) 'company-search-printing-char)
530 (incf i))
531 (let ((meta-map (make-sparse-keymap)))
532 (define-key keymap (char-to-string meta-prefix-char) meta-map)
533 (define-key keymap [escape] meta-map))
534 (define-key keymap (vector meta-prefix-char t) 'company-search-other-char)
535 (define-key keymap "\e\e\e" 'company-search-other-char)
536 (define-key keymap [escape escape escape] 'company-search-other-char)
537
538 (define-key keymap "\C-g" 'company-search-abort)
539 (define-key keymap "\C-s" 'company-search-repeat-forward)
540 (define-key keymap "\C-r" 'company-search-repeat-backward)
541 (define-key keymap "\C-o" 'company-search-kill-others)
542 keymap))
543
544 (define-minor-mode company-search-mode
545 ""
546 nil company-search-lighter nil
547 (if company-search-mode
548 (if (company-manual-begin)
549 (progn
550 (setq company-search-old-selection company-selection)
551 (company-enable-overriding-keymap company-search-map)
552 (company-call-frontends 'update))
553 (setq company-search-mode nil))
554 (kill-local-variable 'company-search-string)
555 (kill-local-variable 'company-search-lighter)
556 (kill-local-variable 'company-search-old-selection)
557 (company-enable-overriding-keymap company-active-map)))
558
559 (defun company-search-candidates ()
560 (interactive)
561 (company-search-mode 1))
562
563 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
564
565 (defun company-select-next ()
566 (interactive)
567 (when (company-manual-begin)
568 (company-set-selection (1+ company-selection))))
569
570 (defun company-select-previous ()
571 (interactive)
572 (when (company-manual-begin)
573 (company-set-selection (1- company-selection))))
574
575 (defun company-complete-selection ()
576 (interactive)
577 (when (company-manual-begin)
578 (insert (company-strip-prefix (nth company-selection company-candidates)))
579 (company-abort)))
580
581 (defun company-complete-common ()
582 (interactive)
583 (when (company-manual-begin)
584 (insert (company-strip-prefix company-common))))
585
586 (defun company-complete ()
587 (interactive)
588 (when (company-manual-begin)
589 (if (or company-selection-changed
590 (eq last-command 'company-complete-common))
591 (call-interactively 'company-complete-selection)
592 (call-interactively 'company-complete-common)
593 (setq this-command 'company-complete-common))))
594
595 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
596
597 (defconst company-space-strings-limit 100)
598
599 (defconst company-space-strings
600 (let (lst)
601 (dotimes (i company-space-strings-limit)
602 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
603 (apply 'vector lst)))
604
605 (defsubst company-space-string (len)
606 (if (< len company-space-strings-limit)
607 (aref company-space-strings len)
608 (make-string len ?\ )))
609
610 (defsubst company-safe-substring (str from &optional to)
611 (let ((len (length str)))
612 (if (> from len)
613 ""
614 (if (and to (> to len))
615 (concat (substring str from)
616 (company-space-string (- to len)))
617 (substring str from to)))))
618
619 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
620
621 (defvar company-last-metadata nil)
622 (make-variable-buffer-local 'company-last-metadata)
623
624 (defun company-fetch-metadata ()
625 (let ((selected (nth company-selection company-candidates)))
626 (unless (equal selected (car company-last-metadata))
627 (setq company-last-metadata
628 (cons selected (funcall company-backend 'meta selected))))
629 (cdr company-last-metadata)))
630
631 (defun company-doc-buffer (&optional string)
632 (with-current-buffer (get-buffer-create "*Company meta-data*")
633 (erase-buffer)
634 (current-buffer)))
635
636 (defun company-show-doc-buffer ()
637 (interactive)
638 (when company-candidates
639 (save-window-excursion
640 (let* ((height (window-height))
641 (row (cdr (posn-col-row (posn-at-point))))
642 (selected (nth company-selection company-candidates))
643 (buffer (funcall company-backend 'doc-buffer selected)))
644 (if (not buffer)
645 (error "No documentation available.")
646 (display-buffer buffer)
647 (and (< (window-height) height)
648 (< (- (window-height) row 2) company-tooltip-limit)
649 (recenter (- (window-height) row 2)))
650 (read-event)
651 (when last-input-event
652 (clear-this-command-keys t)
653 (setq unread-command-events (list last-input-event))))))))
654
655 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
656
657 (defvar company-pseudo-tooltip-overlay nil)
658 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
659
660 (defvar company-tooltip-offset 0)
661 (make-variable-buffer-local 'company-tooltip-offset)
662
663 (defun company-pseudo-tooltip-update-offset (selection num-lines limit)
664
665 (decf limit 2)
666 (setq company-tooltip-offset
667 (max (min selection company-tooltip-offset)
668 (- selection -1 limit)))
669
670 (when (<= company-tooltip-offset 1)
671 (incf limit)
672 (setq company-tooltip-offset 0))
673
674 (when (>= company-tooltip-offset (- num-lines limit 1))
675 (incf limit)
676 (when (= selection (1- num-lines))
677 (decf company-tooltip-offset)
678 (when (<= company-tooltip-offset 1)
679 (setq company-tooltip-offset 0)
680 (incf limit))))
681
682 limit)
683
684 ;;; propertize
685
686 (defun company-fill-propertize (line width selected)
687 (setq line (company-safe-substring line 0 width))
688 (add-text-properties 0 width (list 'face 'company-tooltip) line)
689 (add-text-properties 0 (length company-common)
690 (list 'face 'company-tooltip-common) line)
691 (when selected
692 (if (and company-search-string
693 (string-match (regexp-quote company-search-string) line
694 (length company-prefix)))
695 (progn
696 (add-text-properties (match-beginning 0) (match-end 0)
697 '(face company-tooltip-selection) line)
698 (when (< (match-beginning 0) (length company-common))
699 (add-text-properties (match-beginning 0) (length company-common)
700 '(face company-tooltip-common-selection)
701 line)))
702 (add-text-properties 0 width '(face company-tooltip-selection) line)
703 (add-text-properties 0 (length company-common)
704 (list 'face 'company-tooltip-common-selection)
705 line)))
706 line)
707
708 ;;; replace
709
710 (defun company-buffer-lines (beg end)
711 (goto-char beg)
712 (let ((row (cdr (posn-col-row (posn-at-point))))
713 lines)
714 (while (and (equal (move-to-window-line (incf row)) row)
715 (<= (point) end))
716 (push (buffer-substring beg (min end (1- (point)))) lines)
717 (setq beg (point)))
718 (unless (eq beg end)
719 (push (buffer-substring beg end) lines))
720 (nreverse lines)))
721
722 (defun company-modify-line (old new offset)
723 (concat (company-safe-substring old 0 offset)
724 new
725 (company-safe-substring old (+ offset (length new)))))
726
727 (defun company-replacement-string (old lines column nl)
728 (let (new)
729 ;; Inject into old lines.
730 (while old
731 (push (company-modify-line (pop old) (pop lines) column) new))
732 ;; Append whole new lines.
733 (while lines
734 (push (company-modify-line "" (pop lines) column) new))
735 (concat (when nl "\n")
736 (mapconcat 'identity (nreverse new) "\n")
737 "\n")))
738
739 (defun company-create-lines (column lines selection limit)
740
741 (let ((len (length lines))
742 width
743 lines-copy
744 previous
745 remainder
746 new)
747
748 ;; Scroll to offset.
749 (setq limit (company-pseudo-tooltip-update-offset selection len limit))
750
751 (when (> company-tooltip-offset 0)
752 (setq previous (format "...(%d)" company-tooltip-offset)))
753
754 (setq remainder (- len limit company-tooltip-offset)
755 remainder (when (> remainder 0)
756 (setq remainder (format "...(%d)" remainder))))
757
758 (decf selection company-tooltip-offset)
759 (setq width (min (length previous) (length remainder))
760 lines (nthcdr company-tooltip-offset lines)
761 len (min limit (length lines))
762 lines-copy lines)
763
764 (dotimes (i len)
765 (setq width (max (length (pop lines-copy)) width)))
766 (setq width (min width (- (window-width) column)))
767
768 (when previous
769 (push (propertize (company-safe-substring previous 0 width)
770 'face 'company-tooltip)
771 new))
772
773 (dotimes (i len)
774 (push (company-fill-propertize (company-reformat (pop lines))
775 width (equal i selection))
776 new))
777
778 (when remainder
779 (push (propertize (company-safe-substring remainder 0 width)
780 'face 'company-tooltip)
781 new))
782
783 (setq lines (nreverse new))))
784
785 ;; show
786
787 (defsubst company-pseudo-tooltip-height ()
788 "Calculate the appropriate tooltip height."
789 (max 3 (min company-tooltip-limit
790 (- (window-height) (cdr (posn-col-row (posn-at-point))) 2))))
791
792 (defun company-pseudo-tooltip-show (row column lines selection)
793 (company-pseudo-tooltip-hide)
794 (unless lines (error "No text provided"))
795 (save-excursion
796
797 (move-to-column 0)
798
799 (let* ((height (company-pseudo-tooltip-height))
800 (lines (company-create-lines column lines selection height))
801 (nl (< (move-to-window-line row) row))
802 (beg (point))
803 (end (save-excursion
804 (move-to-window-line (+ row height))
805 (point)))
806 (old-string (company-buffer-lines beg end))
807 str)
808
809 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
810
811 (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
812 (overlay-put company-pseudo-tooltip-overlay 'company-column column)
813 (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
814 (overlay-put company-pseudo-tooltip-overlay 'company-before
815 (company-replacement-string old-string lines column nl))
816 (overlay-put company-pseudo-tooltip-overlay 'company-height height)
817
818 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
819
820 (defun company-pseudo-tooltip-show-at-point (pos)
821 (let ((col-row (posn-col-row (posn-at-point pos))))
822 (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
823 company-candidates company-selection)))
824
825 (defun company-pseudo-tooltip-edit (lines selection)
826 (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
827 (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
828 (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
829 (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
830 (lines (company-create-lines column lines selection height)))
831 (overlay-put company-pseudo-tooltip-overlay 'company-before
832 (company-replacement-string old-string lines column nl))))
833
834 (defun company-pseudo-tooltip-hide ()
835 (when company-pseudo-tooltip-overlay
836 (delete-overlay company-pseudo-tooltip-overlay)
837 (setq company-pseudo-tooltip-overlay nil)))
838
839 (defun company-pseudo-tooltip-hide-temporarily ()
840 (when (overlayp company-pseudo-tooltip-overlay)
841 (overlay-put company-pseudo-tooltip-overlay 'invisible nil)
842 (overlay-put company-pseudo-tooltip-overlay 'before-string nil)))
843
844 (defun company-pseudo-tooltip-unhide ()
845 (when company-pseudo-tooltip-overlay
846 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
847 (overlay-put company-pseudo-tooltip-overlay 'before-string
848 (overlay-get company-pseudo-tooltip-overlay 'company-before))))
849
850 (defun company-pseudo-tooltip-frontend (command)
851 (case command
852 ('pre-command (company-pseudo-tooltip-hide-temporarily))
853 ('post-command
854 (unless (and (overlayp company-pseudo-tooltip-overlay)
855 (equal (overlay-get company-pseudo-tooltip-overlay
856 'company-height)
857 (company-pseudo-tooltip-height)))
858 ;; Redraw needed.
859 (company-pseudo-tooltip-show-at-point (- (point)
860 (length company-prefix))))
861 (company-pseudo-tooltip-unhide))
862 ('hide (company-pseudo-tooltip-hide)
863 (setq company-tooltip-offset 0))
864 ('update (when (overlayp company-pseudo-tooltip-overlay)
865 (company-pseudo-tooltip-edit company-candidates
866 company-selection)))))
867
868 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
869 (unless (and (eq command 'post-command)
870 (not (cdr company-candidates)))
871 (company-pseudo-tooltip-frontend command)))
872
873 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
874
875 (defvar company-preview-overlay nil)
876 (make-variable-buffer-local 'company-preview-overlay)
877
878 (defun company-preview-show-at-point (pos)
879 (company-preview-hide)
880
881 (setq company-preview-overlay (make-overlay pos pos))
882
883 (let ((completion (company-strip-prefix (nth company-selection
884 company-candidates))))
885 (and (equal pos (point))
886 (not (equal completion ""))
887 (add-text-properties 0 1 '(cursor t) completion))
888
889 (setq completion (propertize completion 'face 'company-preview))
890 (add-text-properties 0 (- (length company-common) (length company-prefix))
891 '(face company-preview-common) completion)
892
893 (overlay-put company-preview-overlay 'after-string completion)
894 (overlay-put company-preview-overlay 'window (selected-window))))
895
896 (defun company-preview-hide ()
897 (when company-preview-overlay
898 (delete-overlay company-preview-overlay)
899 (setq company-preview-overlay nil)))
900
901 (defun company-preview-frontend (command)
902 (case command
903 ('pre-command (company-preview-hide))
904 ('post-command (company-preview-show-at-point (point)))
905 ('hide (company-preview-hide))))
906
907 (defun company-preview-if-just-one-frontend (command)
908 (unless (and (eq command 'post-command)
909 (cdr company-candidates))
910 (company-preview-frontend command)))
911
912 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
913
914 (defvar company-echo-last-msg nil)
915 (make-variable-buffer-local 'company-echo-last-msg)
916
917 (defun company-echo-refresh ()
918 (let ((message-log-max nil))
919 (if company-echo-last-msg
920 (message "%s" company-echo-last-msg)
921 (message ""))))
922
923 (defun company-echo-show (candidates)
924
925 ;; Roll to selection.
926 (setq candidates (nthcdr company-selection candidates))
927
928 (let ((limit (window-width (minibuffer-window)))
929 (len -1)
930 comp msg)
931 (while candidates
932 (setq comp (company-reformat (pop candidates))
933 len (+ len 1 (length comp)))
934 (if (>= len limit)
935 (setq candidates nil)
936 (setq comp (propertize comp 'face 'company-echo))
937 (add-text-properties 0 (length company-common)
938 '(face company-echo-common) comp)
939 (push comp msg)))
940
941 (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
942 (company-echo-refresh)))
943
944 (defun company-echo-frontend (command)
945 (case command
946 ('pre-command (company-echo-refresh))
947 ('post-command (company-echo-show company-candidates))
948 ('hide (setq company-echo-last-msg nil))))
949
950 (defun company-echo-metadata-frontend (command)
951 (case command
952 ('pre-command (company-echo-refresh))
953 ('post-command (setq company-echo-last-msg (company-fetch-metadata))
954 (company-echo-refresh))
955 ('hide (setq company-echo-last-msg nil))))
956
957
958 (provide 'company)
959 ;;; company.el ends here