]> rtime.felk.cvut.cz Git - sojka/company-mode.git/blob - company.el
Allowed scrolling of the documentation window.
[sojka/company-mode.git] / 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     (setq company-candidates-predicate predicate)
504     (company-update-candidates (company-apply-predicate company-candidates
505                                                         predicate))
506     (company-search-mode 0)
507     (company-call-frontends 'update)))
508
509 (defun company-search-abort ()
510   (interactive)
511   (company-set-selection company-search-old-selection t)
512   (company-search-mode 0))
513
514 (defun company-search-other-char ()
515   (interactive)
516   (company-search-mode 0)
517   (when last-input-event
518     (clear-this-command-keys t)
519     (setq unread-command-events (list last-input-event))))
520
521 (defvar company-search-map
522   (let ((i 0)
523         (keymap (make-keymap)))
524     (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
525                           'company-search-printing-char)
526     (define-key keymap [t] 'company-search-other-char)
527     (while (< i ?\s)
528       (define-key keymap (make-string 1 i) 'company-search-other-char)
529       (incf i))
530     (while (< i 256)
531       (define-key keymap (vector i) 'company-search-printing-char)
532       (incf i))
533     (let ((meta-map (make-sparse-keymap)))
534       (define-key keymap (char-to-string meta-prefix-char) meta-map)
535       (define-key keymap [escape] meta-map))
536     (define-key keymap (vector meta-prefix-char t) 'company-search-other-char)
537     (define-key keymap "\e\e\e" 'company-search-other-char)
538     (define-key keymap  [escape escape escape] 'company-search-other-char)
539
540     (define-key keymap "\C-g" 'company-search-abort)
541     (define-key keymap "\C-s" 'company-search-repeat-forward)
542     (define-key keymap "\C-r" 'company-search-repeat-backward)
543     (define-key keymap "\C-o" 'company-search-kill-others)
544     keymap))
545
546 (define-minor-mode company-search-mode
547   ""
548   nil company-search-lighter nil
549   (if company-search-mode
550       (if (company-manual-begin)
551           (progn
552             (setq company-search-old-selection company-selection)
553             (company-enable-overriding-keymap company-search-map)
554             (company-call-frontends 'update))
555         (setq company-search-mode nil))
556     (kill-local-variable 'company-search-string)
557     (kill-local-variable 'company-search-lighter)
558     (kill-local-variable 'company-search-old-selection)
559     (company-enable-overriding-keymap company-active-map)))
560
561 (defun company-search-candidates ()
562   (interactive)
563   (company-search-mode 1))
564
565 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
566
567 (defun company-select-next ()
568   (interactive)
569   (when (company-manual-begin)
570     (company-set-selection (1+ company-selection))))
571
572 (defun company-select-previous ()
573   (interactive)
574   (when (company-manual-begin)
575     (company-set-selection (1- company-selection))))
576
577 (defun company-complete-selection ()
578   (interactive)
579   (when (company-manual-begin)
580     (insert (company-strip-prefix (nth company-selection company-candidates)))
581     (company-abort)))
582
583 (defun company-complete-common ()
584   (interactive)
585   (when (company-manual-begin)
586     (insert (company-strip-prefix company-common))))
587
588 (defun company-complete ()
589   (interactive)
590   (when (company-manual-begin)
591     (if (or company-selection-changed
592             (eq last-command 'company-complete-common))
593         (call-interactively 'company-complete-selection)
594       (call-interactively 'company-complete-common)
595       (setq this-command 'company-complete-common))))
596
597 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
598
599 (defconst company-space-strings-limit 100)
600
601 (defconst company-space-strings
602   (let (lst)
603     (dotimes (i company-space-strings-limit)
604       (push (make-string (- company-space-strings-limit 1 i) ?\  ) lst))
605     (apply 'vector lst)))
606
607 (defsubst company-space-string (len)
608   (if (< len company-space-strings-limit)
609       (aref company-space-strings len)
610     (make-string len ?\ )))
611
612 (defsubst company-safe-substring (str from &optional to)
613   (let ((len (length str)))
614     (if (> from len)
615         ""
616       (if (and to (> to len))
617           (concat (substring str from)
618                   (company-space-string (- to len)))
619         (substring str from to)))))
620
621 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
622
623 (defvar company-last-metadata nil)
624 (make-variable-buffer-local 'company-last-metadata)
625
626 (defun company-fetch-metadata ()
627   (let ((selected (nth company-selection company-candidates)))
628     (unless (equal selected (car company-last-metadata))
629       (setq company-last-metadata
630             (cons selected (funcall company-backend 'meta selected))))
631     (cdr company-last-metadata)))
632
633 (defun company-doc-buffer (&optional string)
634   (with-current-buffer (get-buffer-create "*Company meta-data*")
635     (erase-buffer)
636     (current-buffer)))
637
638 (defun company-show-doc-buffer ()
639   (interactive)
640   (when company-candidates
641     (save-window-excursion
642       (let* ((height (window-height))
643              (row (cdr (posn-col-row (posn-at-point))))
644              (selected (nth company-selection company-candidates))
645              (buffer (funcall company-backend 'doc-buffer selected)))
646         (if (not buffer)
647             (error "No documentation available.")
648           (display-buffer buffer)
649           (and (< (window-height) height)
650                (< (- (window-height) row 2) company-tooltip-limit)
651                (recenter (- (window-height) row 2)))
652           (while (eq 'scroll-other-window
653                      (key-binding (vector (list (read-event)))))
654             (scroll-other-window))
655           (when last-input-event
656             (clear-this-command-keys t)
657             (setq unread-command-events (list last-input-event))))))))
658
659 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
660
661 (defvar company-pseudo-tooltip-overlay nil)
662 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
663
664 (defvar company-tooltip-offset 0)
665 (make-variable-buffer-local 'company-tooltip-offset)
666
667 (defun company-pseudo-tooltip-update-offset (selection num-lines limit)
668
669   (decf limit 2)
670   (setq company-tooltip-offset
671         (max (min selection company-tooltip-offset)
672              (- selection -1 limit)))
673
674   (when (<= company-tooltip-offset 1)
675     (incf limit)
676     (setq company-tooltip-offset 0))
677
678   (when (>= company-tooltip-offset (- num-lines limit 1))
679     (incf limit)
680     (when (= selection (1- num-lines))
681       (decf company-tooltip-offset)
682       (when (<= company-tooltip-offset 1)
683         (setq company-tooltip-offset 0)
684         (incf limit))))
685
686   limit)
687
688 ;;; propertize
689
690 (defun company-fill-propertize (line width selected)
691   (setq line (company-safe-substring line 0 width))
692   (add-text-properties 0 width (list 'face 'company-tooltip) line)
693   (add-text-properties 0 (length company-common)
694                        (list 'face 'company-tooltip-common) line)
695   (when selected
696     (if (and company-search-string
697              (string-match (regexp-quote company-search-string) line
698                            (length company-prefix)))
699         (progn
700           (add-text-properties (match-beginning 0) (match-end 0)
701                                '(face company-tooltip-selection) line)
702           (when (< (match-beginning 0) (length company-common))
703             (add-text-properties (match-beginning 0) (length company-common)
704                                  '(face company-tooltip-common-selection)
705                                  line)))
706       (add-text-properties 0 width '(face company-tooltip-selection) line)
707       (add-text-properties 0 (length company-common)
708                            (list 'face 'company-tooltip-common-selection)
709                            line)))
710   line)
711
712 ;;; replace
713
714 (defun company-buffer-lines (beg end)
715   (goto-char beg)
716   (let ((row (cdr (posn-col-row (posn-at-point))))
717         lines)
718     (while (and (equal (move-to-window-line (incf row)) row)
719                 (<= (point) end))
720       (push (buffer-substring beg (min end (1- (point)))) lines)
721       (setq beg (point)))
722     (unless (eq beg end)
723       (push (buffer-substring beg end) lines))
724     (nreverse lines)))
725
726 (defun company-modify-line (old new offset)
727   (concat (company-safe-substring old 0 offset)
728           new
729           (company-safe-substring old (+ offset (length new)))))
730
731 (defun company-replacement-string (old lines column nl)
732   (let (new)
733     ;; Inject into old lines.
734     (while old
735       (push (company-modify-line (pop old) (pop lines) column) new))
736     ;; Append whole new lines.
737     (while lines
738       (push (company-modify-line "" (pop lines) column) new))
739     (concat (when nl "\n")
740             (mapconcat 'identity (nreverse new) "\n")
741             "\n")))
742
743 (defun company-create-lines (column lines selection limit)
744
745   (let ((len (length lines))
746         width
747         lines-copy
748         previous
749         remainder
750         new)
751
752     ;; Scroll to offset.
753     (setq limit (company-pseudo-tooltip-update-offset selection len limit))
754
755     (when (> company-tooltip-offset 0)
756       (setq previous (format "...(%d)" company-tooltip-offset)))
757
758     (setq remainder (- len limit company-tooltip-offset)
759           remainder (when (> remainder 0)
760                       (setq remainder (format "...(%d)" remainder))))
761
762     (decf selection company-tooltip-offset)
763     (setq width (min (length previous) (length remainder))
764           lines (nthcdr company-tooltip-offset lines)
765           len (min limit (length lines))
766           lines-copy lines)
767
768     (dotimes (i len)
769       (setq width (max (length (pop lines-copy)) width)))
770     (setq width (min width (- (window-width) column)))
771
772     (when previous
773       (push (propertize (company-safe-substring previous 0 width)
774                         'face 'company-tooltip)
775             new))
776
777     (dotimes (i len)
778       (push (company-fill-propertize (company-reformat (pop lines))
779                                      width (equal i selection))
780             new))
781
782     (when remainder
783       (push (propertize (company-safe-substring remainder 0 width)
784                         'face 'company-tooltip)
785             new))
786
787     (setq lines (nreverse new))))
788
789 ;; show
790
791 (defsubst company-pseudo-tooltip-height ()
792   "Calculate the appropriate tooltip height."
793   (max 3 (min company-tooltip-limit
794               (- (window-height) (cdr (posn-col-row (posn-at-point))) 2))))
795
796 (defun company-pseudo-tooltip-show (row column lines selection)
797   (company-pseudo-tooltip-hide)
798   (unless lines (error "No text provided"))
799   (save-excursion
800
801     (move-to-column 0)
802
803     (let* ((height (company-pseudo-tooltip-height))
804            (lines (company-create-lines column lines selection height))
805            (nl (< (move-to-window-line row) row))
806            (beg (point))
807            (end (save-excursion
808                   (move-to-window-line (+ row height))
809                   (point)))
810            (old-string (company-buffer-lines beg end))
811            str)
812
813       (setq company-pseudo-tooltip-overlay (make-overlay beg end))
814
815       (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
816       (overlay-put company-pseudo-tooltip-overlay 'company-column column)
817       (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
818       (overlay-put company-pseudo-tooltip-overlay 'company-before
819                    (company-replacement-string old-string lines column nl))
820       (overlay-put company-pseudo-tooltip-overlay 'company-height height)
821
822       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
823
824 (defun company-pseudo-tooltip-show-at-point (pos)
825   (let ((col-row (posn-col-row (posn-at-point pos))))
826     (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
827                                  company-candidates company-selection)))
828
829 (defun company-pseudo-tooltip-edit (lines selection)
830   (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
831          (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
832          (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
833          (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
834          (lines (company-create-lines column lines selection height)))
835     (overlay-put company-pseudo-tooltip-overlay 'company-before
836                  (company-replacement-string old-string lines column nl))))
837
838 (defun company-pseudo-tooltip-hide ()
839   (when company-pseudo-tooltip-overlay
840     (delete-overlay company-pseudo-tooltip-overlay)
841     (setq company-pseudo-tooltip-overlay nil)))
842
843 (defun company-pseudo-tooltip-hide-temporarily ()
844   (when (overlayp company-pseudo-tooltip-overlay)
845     (overlay-put company-pseudo-tooltip-overlay 'invisible nil)
846     (overlay-put company-pseudo-tooltip-overlay 'before-string nil)))
847
848 (defun company-pseudo-tooltip-unhide ()
849   (when company-pseudo-tooltip-overlay
850     (overlay-put company-pseudo-tooltip-overlay 'invisible t)
851     (overlay-put company-pseudo-tooltip-overlay 'before-string
852                  (overlay-get company-pseudo-tooltip-overlay 'company-before))))
853
854 (defun company-pseudo-tooltip-frontend (command)
855   (case command
856     ('pre-command (company-pseudo-tooltip-hide-temporarily))
857     ('post-command
858      (unless (and (overlayp company-pseudo-tooltip-overlay)
859                   (equal (overlay-get company-pseudo-tooltip-overlay
860                                       'company-height)
861                          (company-pseudo-tooltip-height)))
862        ;; Redraw needed.
863        (company-pseudo-tooltip-show-at-point (- (point)
864                                                 (length company-prefix))))
865      (company-pseudo-tooltip-unhide))
866     ('hide (company-pseudo-tooltip-hide)
867            (setq company-tooltip-offset 0))
868     ('update (when (overlayp company-pseudo-tooltip-overlay)
869                (company-pseudo-tooltip-edit company-candidates
870                                             company-selection)))))
871
872 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
873   (unless (and (eq command 'post-command)
874                (not (cdr company-candidates)))
875     (company-pseudo-tooltip-frontend command)))
876
877 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
878
879 (defvar company-preview-overlay nil)
880 (make-variable-buffer-local 'company-preview-overlay)
881
882 (defun company-preview-show-at-point (pos)
883   (company-preview-hide)
884
885   (setq company-preview-overlay (make-overlay pos pos))
886
887   (let ((completion (company-strip-prefix (nth company-selection
888                                                company-candidates))))
889     (and (equal pos (point))
890          (not (equal completion ""))
891          (add-text-properties 0 1 '(cursor t) completion))
892
893     (setq completion (propertize completion 'face 'company-preview))
894     (add-text-properties 0 (- (length company-common) (length company-prefix))
895                          '(face company-preview-common) completion)
896
897     (overlay-put company-preview-overlay 'after-string completion)
898     (overlay-put company-preview-overlay 'window (selected-window))))
899
900 (defun company-preview-hide ()
901   (when company-preview-overlay
902     (delete-overlay company-preview-overlay)
903     (setq company-preview-overlay nil)))
904
905 (defun company-preview-frontend (command)
906   (case command
907     ('pre-command (company-preview-hide))
908     ('post-command (company-preview-show-at-point (point)))
909     ('hide (company-preview-hide))))
910
911 (defun company-preview-if-just-one-frontend (command)
912   (unless (and (eq command 'post-command)
913                (cdr company-candidates))
914     (company-preview-frontend command)))
915
916 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
917
918 (defvar company-echo-last-msg nil)
919 (make-variable-buffer-local 'company-echo-last-msg)
920
921 (defun company-echo-refresh ()
922   (let ((message-log-max nil))
923     (if company-echo-last-msg
924         (message "%s" company-echo-last-msg)
925       (message ""))))
926
927 (defun company-echo-show (candidates)
928
929   ;; Roll to selection.
930   (setq candidates (nthcdr company-selection candidates))
931
932   (let ((limit (window-width (minibuffer-window)))
933         (len -1)
934         comp msg)
935     (while candidates
936       (setq comp (company-reformat (pop candidates))
937             len (+ len 1 (length comp)))
938       (if (>= len limit)
939           (setq candidates nil)
940         (setq comp (propertize comp 'face 'company-echo))
941         (add-text-properties 0 (length company-common)
942                              '(face company-echo-common) comp)
943         (push comp msg)))
944
945     (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
946     (company-echo-refresh)))
947
948 (defun company-echo-frontend (command)
949   (case command
950     ('pre-command (company-echo-refresh))
951     ('post-command (company-echo-show company-candidates))
952     ('hide (setq company-echo-last-msg nil))))
953
954 (defun company-echo-metadata-frontend (command)
955   (case command
956     ('pre-command (company-echo-refresh))
957     ('post-command (setq company-echo-last-msg (company-fetch-metadata))
958                    (company-echo-refresh))
959     ('hide (setq company-echo-last-msg nil))))
960
961
962 (provide 'company)
963 ;;; company.el ends here