1 (eval-when-compile (require 'cl))
9 (defface company-tooltip
10 '((t :background "yellow"
15 (defface company-tooltip-selection
16 '((t :background "orange1"
21 (defface company-tooltip-common
22 '((t :inherit company-tooltip
27 (defface company-tooltip-common-selection
28 '((t :inherit company-tooltip-selection
33 (defcustom company-tooltip-limit 10
38 (defface company-preview
39 '((t :background "blue4"
44 (defface company-preview-common
45 '((t :inherit company-preview
50 (defcustom company-backends '(company-elisp-completion)
53 :type '(repeat (function :tag "function" nil)))
55 (defcustom company-minimum-prefix-length 3
58 :type '(integer :tag "prefix length"))
60 ;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
62 (defvar company-mode-map
63 (let ((keymap (make-sparse-keymap)))
64 (define-key keymap (kbd "M-n") 'company-select-next)
65 (define-key keymap (kbd "M-p") 'company-select-previous)
66 (define-key keymap (kbd "M-<return>") 'company-complete-selection)
67 (define-key keymap "\t" 'company-complete-common)
71 (define-minor-mode company-mode
73 nil " comp" company-mode-map
76 (add-hook 'pre-command-hook 'company-pre-command nil t)
77 (add-hook 'post-command-hook 'company-post-command nil t))
78 (remove-hook 'pre-command-hook 'company-pre-command t)
79 (remove-hook 'post-command-hook 'company-post-command t)
82 ;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
84 (defun company-grab (regexp &optional expression)
85 (when (looking-back regexp)
86 (or (match-string-no-properties (or expression 0)) "")))
88 (defun company-in-string-or-comment (&optional point)
89 (let ((pos (syntax-ppss)))
90 (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
94 (defvar company-lisp-symbol-regexp
95 "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
97 (defun company-grab-lisp-symbol ()
98 (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
99 (unless (and (company-in-string-or-comment (- (point) (length prefix)))
100 (/= (char-before (- (point) (length prefix))) ?`))
103 (defun company-elisp-completion (command &optional arg &rest ignored)
105 ('prefix (and (eq major-mode 'emacs-lisp-mode)
106 (company-grab-lisp-symbol)))
107 ('candidates (let ((completion-ignore-case nil))
108 (all-completions arg obarray
109 (lambda (symbol) (or (boundp symbol)
110 (fboundp symbol))))))))
112 ;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
114 (defvar company-backend nil)
115 (make-variable-buffer-local 'company-backend)
117 (defvar company-prefix nil)
118 (make-variable-buffer-local 'company-prefix)
120 (defvar company-candidates nil)
121 (make-variable-buffer-local 'company-candidates)
123 (defvar company-common nil)
124 (make-variable-buffer-local 'company-common)
126 (defvar company-selection 0)
127 (make-variable-buffer-local 'company-selection)
129 (defvar company-selection-changed nil)
130 (make-variable-buffer-local 'company-selection-changed)
132 (defvar company-point nil)
133 (make-variable-buffer-local 'company-point)
135 (defsubst company-strip-prefix (str)
136 (substring str (length company-prefix)))
138 (defsubst company-offset (display-limit)
139 (let ((offset (- company-selection display-limit -1)))
142 (defsubst company-should-complete (prefix)
143 (>= (length prefix) company-minimum-prefix-length))
145 (defun company-begin ()
146 (when company-candidates
148 (let ((completion-ignore-case nil) ;; TODO: make this optional
150 (dolist (backend company-backends)
151 (when (setq prefix (funcall backend 'prefix))
152 (when (company-should-complete prefix)
153 (setq company-backend backend
154 company-prefix prefix
156 (funcall company-backend 'candidates prefix)
157 company-common (try-completion prefix company-candidates)
159 company-point (point)))
161 (unless (and company-candidates
162 (not (eq t company-common)))
165 (defun company-cancel ()
166 (setq company-backend nil
168 company-candidates nil
171 company-selection-changed nil
173 (company-pseudo-tooltip-hide))
175 (defun company-pre-command ()
176 (company-preview-hide)
177 (company-pseudo-tooltip-hide))
179 (defun company-post-command ()
180 (unless (equal (point) company-point)
182 (when company-candidates
183 (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
186 (company-preview-show-at-point (point) company-candidates
189 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
191 (defun company-select-next ()
193 (setq company-selection (min (1- (length company-candidates))
194 (1+ company-selection))
195 company-selection-changed t))
197 (defun company-select-previous ()
199 (setq company-selection (max 0 (1- company-selection))
200 company-selection-changed t))
202 (defun company-complete-selection ()
204 (insert (company-strip-prefix (nth company-selection company-candidates))))
206 (defun company-complete-common ()
208 (insert (company-strip-prefix company-common)))
210 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
212 (defconst company-space-strings-limit 100)
214 (defconst company-space-strings
216 (dotimes (i company-space-strings-limit)
217 (push (make-string (- company-space-strings-limit 1 i) ?\ ) lst))
218 (apply 'vector lst)))
220 (defsubst company-space-string (len)
221 (if (< len company-space-strings-limit)
222 (aref company-space-strings len)
223 (make-string len ?\ )))
225 (defsubst company-safe-substring (str from &optional to)
226 (let ((len (length str)))
229 (if (and to (> to len))
230 (concat (substring str from)
231 (company-space-string (- to len)))
232 (substring str from to)))))
234 ;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
236 (defvar company-pseudo-tooltip-overlay nil)
237 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
241 (defun company-fill-propertize (line width selected)
242 (setq line (company-safe-substring line 0 width))
243 (add-text-properties 0 width
244 (list 'face (if selected
245 'company-tooltip-selection
246 'company-tooltip)) line)
247 (add-text-properties 0 (length company-common)
248 (list 'face (if selected
249 'company-tooltip-common-selection
250 'company-tooltip-common)) line)
253 (defun company-fill-propertize-lines (column lines selection)
256 (len (min company-tooltip-limit (length lines)))
259 (setq width (max (length (pop lines-copy)) width)))
260 (setq width (min width (- (window-width) column)))
262 (push (company-fill-propertize (pop lines) width (equal i selection))
268 (defun company-buffer-lines (beg end)
270 (let ((row (cdr (posn-col-row (posn-at-point))))
272 (while (< (point) end)
273 (move-to-window-line (incf row))
274 (push (buffer-substring beg (min end (1- (point)))) lines)
278 (defun company-modify-line (old new offset)
279 (concat (company-safe-substring old 0 offset)
281 (company-safe-substring old (+ offset (length new)))))
283 (defun company-modified-substring (beg end lines column)
284 (let ((old (company-buffer-lines beg end))
286 ;; Inject into old lines.
288 (push (company-modify-line (pop old) (pop lines) column) new))
289 ;; Append whole new lines.
291 (push (company-modify-line "" (pop lines) column) new))
292 (concat (mapconcat 'identity (nreverse new) "\n")
297 (defun company-pseudo-tooltip-show (row column lines &optional selection)
298 (company-pseudo-tooltip-hide)
299 (unless lines (error "No text provided"))
303 (let ((offset (company-offset company-tooltip-limit)))
304 (setq lines (nthcdr offset lines))
305 (decf selection offset))
307 (setq lines (company-fill-propertize-lines column lines selection))
311 (move-to-window-line row)
314 (move-to-window-line (min (window-height)
315 (+ row company-tooltip-limit)))
319 (setq company-pseudo-tooltip-overlay (make-overlay beg end))
321 (overlay-put company-pseudo-tooltip-overlay 'before-string
322 (company-modified-substring beg end lines column))
323 (overlay-put company-pseudo-tooltip-overlay 'invisible t)
324 (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
326 (defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
327 (let ((col-row (posn-col-row (posn-at-point pos))))
328 (company-pseudo-tooltip-show (1+ (cdr col-row))
329 (car col-row) text selection)))
331 (defun company-pseudo-tooltip-hide ()
332 (when company-pseudo-tooltip-overlay
333 (delete-overlay company-pseudo-tooltip-overlay)
334 (setq company-pseudo-tooltip-overlay nil)))
336 ;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
338 (defvar company-preview-overlay nil)
339 (make-variable-buffer-local 'company-preview-overlay)
341 (defun company-preview-show-at-point (pos text &optional selection)
342 (company-preview-hide)
344 (setq company-preview-overlay (make-overlay pos pos))
346 (let ((completion (company-strip-prefix (nth company-selection
347 company-candidates))))
348 (and (equal pos (point))
349 (not (equal completion ""))
350 (add-text-properties 0 1 '(cursor t) completion))
352 (setq completion (propertize completion 'face 'company-preview))
353 (add-text-properties 0 (- (length company-common) (length company-prefix))
354 '(face company-preview-common) completion)
356 (overlay-put company-preview-overlay 'after-string completion)
357 (overlay-put company-preview-overlay 'window (selected-window))))
359 (defun company-preview-hide ()
360 (when company-preview-overlay
361 (delete-overlay company-preview-overlay)
362 (setq company-preview-overlay nil)))
365 ;;; company.el ends here