]> code.delx.au - gnu-emacs-elpa/blob - company.el
Make sure completing stops further automatic completion.
[gnu-emacs-elpa] / company.el
1 (eval-when-compile (require 'cl))
2
3 (defgroup company nil
4 ""
5 :group 'abbrev
6 :group 'convenience
7 :group 'maching)
8
9 (defface company-tooltip
10 '((t :background "yellow"
11 :foreground "black"))
12 "*"
13 :group 'company)
14
15 (defface company-tooltip-selection
16 '((t :background "orange1"
17 :foreground "black"))
18 "*"
19 :group 'company)
20
21 (defface company-tooltip-common
22 '((t :inherit company-tooltip
23 :foreground "red"))
24 "*"
25 :group 'company)
26
27 (defface company-tooltip-common-selection
28 '((t :inherit company-tooltip-selection
29 :foreground "red"))
30 "*"
31 :group 'company)
32
33 (defcustom company-tooltip-limit 10
34 "*"
35 :group 'company
36 :type 'integer)
37
38 (defface company-preview
39 '((t :background "blue4"
40 :foreground "wheat"))
41 "*"
42 :group 'company)
43
44 (defface company-preview-common
45 '((t :inherit company-preview
46 :foreground "red"))
47 "*"
48 :group 'company)
49
50 (defface company-echo nil
51 "*"
52 :group 'company)
53
54 (defface company-echo-common
55 '((((background dark)) (:foreground "firebrick1"))
56 (((background light)) (:background "firebrick4")))
57 "*"
58 :group 'company)
59
60 (defcustom company-backends '(company-elisp-completion)
61 "*"
62 :group 'company
63 :type '(repeat (function :tag "function" nil)))
64
65 (defcustom company-minimum-prefix-length 3
66 "*"
67 :group 'company
68 :type '(integer :tag "prefix length"))
69
70 (defvar company-timer nil)
71
72 (defun company-timer-set (variable value)
73 (set variable value)
74 (when company-timer (cancel-timer company-timer))
75 (when (numberp value)
76 (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
77
78 (defcustom company-idle-delay .7
79 "*"
80 :set 'company-timer-set
81 :group 'company
82 :type '(choice (const :tag "never (nil)" nil)
83 (const :tag "immediate (t)" t)
84 (number :tag "seconds")))
85
86 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87
88 (defvar company-mode-map
89 (let ((keymap (make-sparse-keymap)))
90 (define-key keymap (kbd "M-n") 'company-select-next)
91 (define-key keymap (kbd "M-p") 'company-select-previous)
92 (define-key keymap (kbd "M-<return>") 'company-complete-selection)
93 (define-key keymap "\t" 'company-complete-common)
94 keymap))
95
96 ;;;###autoload
97 (define-minor-mode company-mode
98 ""
99 nil " comp" company-mode-map
100 (if company-mode
101 (progn
102 (add-hook 'pre-command-hook 'company-pre-command nil t)
103 (add-hook 'post-command-hook 'company-post-command nil t)
104 (company-timer-set 'company-idle-delay
105 company-idle-delay))
106 (remove-hook 'pre-command-hook 'company-pre-command t)
107 (remove-hook 'post-command-hook 'company-post-command t)
108 (company-cancel)
109 (kill-local-variable 'company-point)))
110
111 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112
113 (defun company-grab (regexp &optional expression)
114 (when (looking-back regexp)
115 (or (match-string-no-properties (or expression 0)) "")))
116
117 (defun company-in-string-or-comment (&optional point)
118 (let ((pos (syntax-ppss)))
119 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
120
121 ;;; elisp
122
123 (defvar company-lisp-symbol-regexp
124 "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
125
126 (defun company-grab-lisp-symbol ()
127 (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
128 (unless (and (company-in-string-or-comment (- (point) (length prefix)))
129 (/= (char-before (- (point) (length prefix))) ?`))
130 prefix)))
131
132 (defun company-elisp-completion (command &optional arg &rest ignored)
133 (case command
134 ('prefix (and (eq major-mode 'emacs-lisp-mode)
135 (company-grab-lisp-symbol)))
136 ('candidates (let ((completion-ignore-case nil))
137 (all-completions arg obarray
138 (lambda (symbol) (or (boundp symbol)
139 (fboundp symbol))))))))
140
141 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
142
143 (defvar company-backend nil)
144 (make-variable-buffer-local 'company-backend)
145
146 (defvar company-prefix nil)
147 (make-variable-buffer-local 'company-prefix)
148
149 (defvar company-candidates nil)
150 (make-variable-buffer-local 'company-candidates)
151
152 (defvar company-common nil)
153 (make-variable-buffer-local 'company-common)
154
155 (defvar company-selection 0)
156 (make-variable-buffer-local 'company-selection)
157
158 (defvar company-selection-changed nil)
159 (make-variable-buffer-local 'company-selection-changed)
160
161 (defvar company-point nil)
162 (make-variable-buffer-local 'company-point)
163
164 (defsubst company-strip-prefix (str)
165 (substring str (length company-prefix)))
166
167 (defsubst company-offset (display-limit)
168 (let ((offset (- company-selection display-limit -1)))
169 (max offset 0)))
170
171 (defsubst company-should-complete (prefix)
172 (and (eq company-idle-delay t)
173 (>= (length prefix) company-minimum-prefix-length)))
174
175 (defun company-idle-begin ()
176 (and company-mode
177 (not company-candidates)
178 (not (equal (point) company-point))
179 (let ((company-idle-delay t))
180 (company-begin)
181 (company-post-command))))
182
183 (defun company-manual-begin ()
184 (and company-mode
185 (not company-candidates)
186 (let ((company-idle-delay t)
187 (company-minimum-prefix-length 0))
188 (company-begin)))
189 ;; Return non-nil if active.
190 company-candidates)
191
192 (defun company-continue-or-cancel ()
193 (when company-candidates
194 (let ((old-point (- company-point (length company-prefix)))
195 (company-idle-delay t)
196 (company-minimum-prefix-length 0))
197 ;; TODO: Make more efficient.
198 (setq company-candidates nil)
199 (company-begin)
200 (unless (and company-candidates
201 (equal old-point (- company-point (length company-prefix))))
202 (company-cancel))
203 company-candidates)))
204
205 (defun company-begin ()
206 (or (company-continue-or-cancel)
207 (let ((completion-ignore-case nil) ;; TODO: make this optional
208 prefix)
209 (dolist (backend company-backends)
210 (when (setq prefix (funcall backend 'prefix))
211 (when (company-should-complete prefix)
212 (setq company-backend backend
213 company-prefix prefix
214 company-candidates
215 (funcall company-backend 'candidates prefix)
216 company-common (try-completion prefix company-candidates)
217 company-selection 0
218 company-point (point)))
219 (return prefix)))
220 (unless (and company-candidates
221 (not (eq t company-common)))
222 (company-cancel)))))
223
224 (defun company-cancel ()
225 (setq company-backend nil
226 company-prefix nil
227 company-candidates nil
228 company-common nil
229 company-selection 0
230 company-selection-changed nil
231 company-point nil)
232 (company-pseudo-tooltip-hide)
233 (company-echo-hide))
234
235 (defun company-abort ()
236 (company-cancel)
237 ;; Don't start again, unless started manually.
238 (setq company-point (point)))
239
240 (defun company-pre-command ()
241 (company-preview-hide)
242 (company-pseudo-tooltip-hide)
243 (company-echo-refresh))
244
245 (defun company-post-command ()
246 (unless (equal (point) company-point)
247 (company-begin))
248 (when company-candidates
249 (company-echo-show company-candidates))
250 (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
251 company-candidates
252 company-selection)
253 (company-preview-show-at-point (point) company-candidates
254 company-selection))
255
256 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257
258 (defun company-select-next ()
259 (interactive)
260 (when (company-manual-begin)
261 (setq company-selection (min (1- (length company-candidates))
262 (1+ company-selection))
263 company-selection-changed t)))
264
265 (defun company-select-previous ()
266 (interactive)
267 (when (company-manual-begin)
268 (setq company-selection (max 0 (1- company-selection))
269 company-selection-changed t)))
270
271 (defun company-complete-selection ()
272 (interactive)
273 (when (company-manual-begin)
274 (insert (company-strip-prefix (nth company-selection company-candidates)))
275 (company-abort)))
276
277 (defun company-complete-common ()
278 (interactive)
279 (when (company-manual-begin)
280 (insert (company-strip-prefix company-common))))
281
282 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
283
284 (defconst company-space-strings-limit 100)
285
286 (defconst company-space-strings
287 (let (lst)
288 (dotimes (i company-space-strings-limit)
289 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
290 (apply 'vector lst)))
291
292 (defsubst company-space-string (len)
293 (if (< len company-space-strings-limit)
294 (aref company-space-strings len)
295 (make-string len ?\ )))
296
297 (defsubst company-safe-substring (str from &optional to)
298 (let ((len (length str)))
299 (if (> from len)
300 ""
301 (if (and to (> to len))
302 (concat (substring str from)
303 (company-space-string (- to len)))
304 (substring str from to)))))
305
306 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
307
308 (defvar company-pseudo-tooltip-overlay nil)
309 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
310
311 ;;; propertize
312
313 (defun company-fill-propertize (line width selected)
314 (setq line (company-safe-substring line 0 width))
315 (add-text-properties 0 width
316 (list 'face (if selected
317 'company-tooltip-selection
318 'company-tooltip)) line)
319 (add-text-properties 0 (length company-common)
320 (list 'face (if selected
321 'company-tooltip-common-selection
322 'company-tooltip-common)) line)
323 line)
324
325 (defun company-fill-propertize-lines (column lines selection)
326 (let ((width 0)
327 (lines-copy lines)
328 (len (min company-tooltip-limit (length lines)))
329 new)
330 (dotimes (i len)
331 (setq width (max (length (pop lines-copy)) width)))
332 (setq width (min width (- (window-width) column)))
333 (dotimes (i len)
334 (push (company-fill-propertize (pop lines) width (equal i selection))
335 new))
336 (nreverse new)))
337
338 ;;; replace
339
340 (defun company-buffer-lines (beg end)
341 (goto-char beg)
342 (let ((row (cdr (posn-col-row (posn-at-point))))
343 lines)
344 (while (< (point) end)
345 (move-to-window-line (incf row))
346 (push (buffer-substring beg (min end (1- (point)))) lines)
347 (setq beg (point)))
348 (nreverse lines)))
349
350 (defun company-modify-line (old new offset)
351 (concat (company-safe-substring old 0 offset)
352 new
353 (company-safe-substring old (+ offset (length new)))))
354
355 (defun company-modified-substring (beg end lines column)
356 (let ((old (company-buffer-lines beg end))
357 new)
358 ;; Inject into old lines.
359 (while old
360 (push (company-modify-line (pop old) (pop lines) column) new))
361 ;; Append whole new lines.
362 (while lines
363 (push (company-modify-line "" (pop lines) column) new))
364 (concat (mapconcat 'identity (nreverse new) "\n")
365 "\n")))
366
367 ;; show
368
369 (defun company-pseudo-tooltip-show (row column lines &optional selection)
370 (company-pseudo-tooltip-hide)
371 (unless lines (error "No text provided"))
372 (save-excursion
373
374 ;; Scroll to offset.
375 (let ((offset (company-offset company-tooltip-limit)))
376 (setq lines (nthcdr offset lines))
377 (decf selection offset))
378
379 (setq lines (company-fill-propertize-lines column lines selection))
380
381
382 (move-to-column 0)
383 (move-to-window-line row)
384 (let ((beg (point))
385 (end (save-excursion
386 (move-to-window-line (min (window-height)
387 (+ row company-tooltip-limit)))
388 (point)))
389 str)
390
391 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
392
393 (overlay-put company-pseudo-tooltip-overlay 'before-string
394 (company-modified-substring beg end lines column))
395 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
396 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
397
398 (defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
399 (let ((col-row (posn-col-row (posn-at-point pos))))
400 (company-pseudo-tooltip-show (1+ (cdr col-row))
401 (car col-row) text selection)))
402
403 (defun company-pseudo-tooltip-hide ()
404 (when company-pseudo-tooltip-overlay
405 (delete-overlay company-pseudo-tooltip-overlay)
406 (setq company-pseudo-tooltip-overlay nil)))
407
408 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
409
410 (defvar company-preview-overlay nil)
411 (make-variable-buffer-local 'company-preview-overlay)
412
413 (defun company-preview-show-at-point (pos text &optional selection)
414 (company-preview-hide)
415
416 (setq company-preview-overlay (make-overlay pos pos))
417
418 (let ((completion (company-strip-prefix (nth company-selection
419 company-candidates))))
420 (and (equal pos (point))
421 (not (equal completion ""))
422 (add-text-properties 0 1 '(cursor t) completion))
423
424 (setq completion (propertize completion 'face 'company-preview))
425 (add-text-properties 0 (- (length company-common) (length company-prefix))
426 '(face company-preview-common) completion)
427
428 (overlay-put company-preview-overlay 'after-string completion)
429 (overlay-put company-preview-overlay 'window (selected-window))))
430
431 (defun company-preview-hide ()
432 (when company-preview-overlay
433 (delete-overlay company-preview-overlay)
434 (setq company-preview-overlay nil)))
435
436 ;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
437
438 (defvar company-echo-last-msg nil)
439 (make-variable-buffer-local 'company-echo-last-msg)
440
441 (defun company-echo-refresh ()
442 (let ((message-log-max nil))
443 (if company-echo-last-msg
444 (message "%s" company-echo-last-msg)
445 (message ""))))
446
447 (defun company-echo-show (candidates)
448
449 ;; Roll to selection.
450 (setq candidates (nthcdr company-selection candidates))
451
452 (let ((limit (window-width (minibuffer-window)))
453 (len 0)
454 comp msg)
455 (while candidates
456 (setq comp (pop candidates)
457 len (+ len 1 (length comp)))
458 (if (>= len limit)
459 (setq candidates nil)
460 (setq comp (propertize comp 'face 'company-echo))
461 (add-text-properties 0 (length company-common)
462 '(face company-echo-common) comp)
463 (push comp msg)))
464
465 (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
466 (company-echo-refresh)))
467
468 (defun company-echo-hide ()
469 (setq company-echo-last-msg nil))
470
471 (provide 'company)
472 ;;; company.el ends here