company.el
1 |
|
2 |
|
3 |
;; Copyright (C) 2009-2024 Free Software Foundation, Inc. |
4 |
;; FIXED by Maarten Vangeneugden on 2024/11/21 (L2516) |
5 |
|
6 |
;; Author: Nikolaj Schumacher |
7 |
;; Maintainer: Dmitry Gutov <dmitry@gutov.dev> |
8 |
;; URL: http://company-mode.github.io/ |
9 |
;; Package-Version: 20241106.2000 |
10 |
;; Package-Revision: 0ae7c2931122 |
11 |
;; Keywords: abbrev, convenience, matching |
12 |
;; Package-Requires: ((emacs "26.1")) |
13 |
|
14 |
;; This file is part of GNU Emacs. |
15 |
|
16 |
;; GNU Emacs is free software: you can redistribute it and/or modify |
17 |
;; it under the terms of the GNU General Public License as published by |
18 |
;; the Free Software Foundation, either version 3 of the License, or |
19 |
;; (at your option) any later version. |
20 |
|
21 |
;; GNU Emacs is distributed in the hope that it will be useful, |
22 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
23 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24 |
;; GNU General Public License for more details. |
25 |
|
26 |
;; You should have received a copy of the GNU General Public License |
27 |
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. |
28 |
|
29 |
;;; Commentary: |
30 |
;; |
31 |
;; Company is a modular completion framework. Modules for retrieving completion |
32 |
;; candidates are called backends, modules for displaying them are frontends. |
33 |
;; |
34 |
;; Company comes with many backends, e.g. `company-etags'. These are |
35 |
;; distributed in separate files and can be used individually. |
36 |
;; |
37 |
;; Enable `company-mode' in all buffers with M-x global-company-mode. For |
38 |
;; further information look at the documentation for `company-mode' (C-h f |
39 |
;; company-mode RET). |
40 |
;; |
41 |
;; If you want to start a specific backend, call it interactively or use |
42 |
;; `company-begin-backend'. For example: |
43 |
;; M-x company-abbrev will prompt for and insert an abbrev. |
44 |
;; |
45 |
;; To write your own backend, look at the documentation for `company-backends'. |
46 |
;; Here is a simple example completing "foo": |
47 |
;; |
48 |
;; (defun company-my-backend (command &optional arg &rest ignored) |
49 |
;; (interactive (list 'interactive)) |
50 |
;; (pcase command |
51 |
;; (`interactive (company-begin-backend 'company-my-backend)) |
52 |
;; (`prefix (company-grab-symbol)) |
53 |
;; (`candidates (list "foobar" "foobaz" "foobarbaz")) |
54 |
;; (`meta (format "This value is named %s" arg)))) |
55 |
;; |
56 |
;; Sometimes it is a good idea to mix several backends together, for example to |
57 |
;; enrich gtags with dabbrev-code results (to emulate local variables). To do |
58 |
;; this, add a list with both backends as an element in `company-backends'. |
59 |
;; |
60 |
;;; Change Log: |
61 |
;; |
62 |
;; See NEWS.md in the repository. |
63 |
|
64 |
;;; Code: |
65 |
|
66 |
(require 'cl-lib) |
67 |
(require 'subr-x) |
68 |
(require 'pcase) |
69 |
|
70 |
(defgroup company nil |
71 |
"Extensible inline text completion mechanism." |
72 |
:group 'abbrev |
73 |
:group 'convenience |
74 |
:group 'matching |
75 |
:link '(custom-manual "(company) Top")) |
76 |
|
77 |
(defgroup company-faces nil |
78 |
"Faces used by Company." |
79 |
:group 'company |
80 |
:group 'faces) |
81 |
|
82 |
(defface company-tooltip |
83 |
'((((class color) (min-colors 88) (background light)) |
84 |
(:foreground "black" :background "cornsilk")) |
85 |
(((class color) (min-colors 88) (background dark)) |
86 |
(:background "gray26")) |
87 |
(t (:foreground "black" :background "yellow"))) |
88 |
"Face used for the tooltip.") |
89 |
|
90 |
(defface company-tooltip-selection |
91 |
'((((class color) (min-colors 88) (background light)) |
92 |
(:background "light blue")) |
93 |
(((class color) (min-colors 88) (background dark)) |
94 |
(:background "gray31")) |
95 |
(t (:background "green"))) |
96 |
"Face used for the selection in the tooltip.") |
97 |
|
98 |
(defface company-tooltip-deprecated |
99 |
'((t (:strike-through t))) |
100 |
"Face used for the deprecated items.") |
101 |
|
102 |
(defface company-tooltip-search |
103 |
'((default :inherit highlight)) |
104 |
"Face used for the search string in the tooltip.") |
105 |
|
106 |
(defface company-tooltip-search-selection |
107 |
'((default :inherit highlight)) |
108 |
"Face used for the search string inside the selection in the tooltip.") |
109 |
|
110 |
(defface company-tooltip-mouse |
111 |
'((default :inherit highlight)) |
112 |
"Face used for the tooltip item under the mouse.") |
113 |
|
114 |
(defface company-tooltip-common |
115 |
'((((background light)) |
116 |
:foreground "darkred") |
117 |
(((background dark)) |
118 |
:foreground "pale turquoise")) |
119 |
"Face used for the common completion in the tooltip.") |
120 |
|
121 |
(defface company-tooltip-common-selection |
122 |
'((default :inherit company-tooltip-common)) |
123 |
"Face used for the selected common completion in the tooltip.") |
124 |
|
125 |
(defface company-tooltip-annotation |
126 |
'((((background light)) |
127 |
:foreground "firebrick4") |
128 |
(((background dark)) |
129 |
:foreground "LightCyan3")) |
130 |
"Face used for the completion annotation in the tooltip.") |
131 |
|
132 |
(defface company-tooltip-annotation-selection |
133 |
'((default :inherit company-tooltip-annotation)) |
134 |
"Face used for the selected completion annotation in the tooltip.") |
135 |
|
136 |
(defface company-tooltip-quick-access |
137 |
'((default :inherit company-tooltip-annotation)) |
138 |
"Face used for the quick-access hints shown in the tooltip." |
139 |
:package-version '(company . "0.10.0")) |
140 |
|
141 |
(defface company-tooltip-quick-access-selection |
142 |
'((default :inherit company-tooltip-annotation-selection)) |
143 |
"Face used for the selected quick-access hints shown in the tooltip." |
144 |
:package-version '(company . "0.10.0")) |
145 |
|
146 |
(define-obsolete-face-alias |
147 |
'company-scrollbar-fg |
148 |
'company-tooltip-scrollbar-thumb |
149 |
"0.10.0") |
150 |
|
151 |
(defface company-tooltip-scrollbar-thumb |
152 |
'((((background light)) |
153 |
:background "indian red") |
154 |
(((background dark)) |
155 |
:background "gray33")) |
156 |
"Face used for the tooltip scrollbar thumb (bar).") |
157 |
|
158 |
(define-obsolete-face-alias |
159 |
'company-scrollbar-bg |
160 |
'company-tooltip-scrollbar-track |
161 |
"0.10.0") |
162 |
|
163 |
(defface company-tooltip-scrollbar-track |
164 |
'((((background light)) |
165 |
:background "wheat") |
166 |
(((background dark)) |
167 |
:background "gray28")) |
168 |
"Face used for the tooltip scrollbar track (trough).") |
169 |
|
170 |
(defface company-preview |
171 |
'((default :inherit (company-tooltip-selection company-tooltip))) |
172 |
"Face used for the completion preview.") |
173 |
|
174 |
(defface company-preview-common |
175 |
'((default :inherit company-tooltip-common-selection)) |
176 |
"Face used for the common part of the completion preview.") |
177 |
|
178 |
(defface company-preview-search |
179 |
'((default :inherit company-tooltip-common-selection)) |
180 |
"Face used for the search string in the completion preview.") |
181 |
|
182 |
(defface company-echo nil |
183 |
"Face used for completions in the echo area.") |
184 |
|
185 |
(defface company-echo-common |
186 |
'((((background light)) (:foreground "firebrick4")) |
187 |
(((background dark)) (:foreground "firebrick1"))) |
188 |
"Face used for the common part of completions in the echo area.") |
189 |
|
190 |
;; Too lazy to re-add :group to all defcustoms down below. |
191 |
(setcdr (assoc load-file-name custom-current-group-alist) |
192 |
'company) |
193 |
|
194 |
(defun company-frontends-set (variable value) |
195 |
;; Uniquify. |
196 |
(let ((value (delete-dups (copy-sequence value)))) |
197 |
(and (or (and (memq 'company-pseudo-tooltip-unless-just-one-frontend value) |
198 |
(memq 'company-pseudo-tooltip-frontend value)) |
199 |
(and (memq 'company-pseudo-tooltip-unless-just-one-frontend-with-delay value) |
200 |
(memq 'company-pseudo-tooltip-frontend value)) |
201 |
(and (memq 'company-pseudo-tooltip-unless-just-one-frontend-with-delay value) |
202 |
(memq 'company-pseudo-tooltip-unless-just-one-frontend value))) |
203 |
(user-error "Pseudo tooltip frontend cannot be used more than once")) |
204 |
(and (or (and (memq 'company-preview-if-just-one-frontend value) |
205 |
(memq 'company-preview-frontend value)) |
206 |
(and (memq 'company-preview-if-just-one-frontend value) |
207 |
(memq 'company-preview-common-frontend value)) |
208 |
(and (memq 'company-preview-frontend value) |
209 |
(memq 'company-preview-common-frontend value)) |
210 |
) |
211 |
(user-error "Preview frontend cannot be used twice")) |
212 |
(and (memq 'company-echo value) |
213 |
(memq 'company-echo-metadata-frontend value) |
214 |
(user-error "Echo area cannot be used twice")) |
215 |
;; Preview must come last. |
216 |
(dolist (f '(company-preview-if-just-one-frontend company-preview-frontend company-preview-common-frontend)) |
217 |
(when (cdr (memq f value)) |
218 |
(setq value (append (delq f value) (list f))))) |
219 |
(set variable value))) |
220 |
|
221 |
(defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend |
222 |
company-preview-if-just-one-frontend |
223 |
company-echo-metadata-frontend) |
224 |
"The list of active frontends (visualizations). |
225 |
Each frontend is a function that takes one argument. It is called with |
226 |
one of the following arguments: |
227 |
|
228 |
`show': When the visualization should start. |
229 |
|
230 |
`hide': When the visualization should end. |
231 |
|
232 |
`update': When the data has been updated. |
233 |
|
234 |
`pre-command': Before every command that is executed while the |
235 |
visualization is active. |
236 |
|
237 |
`post-command': After every command that is executed while the |
238 |
visualization is active. |
239 |
|
240 |
`unhide': When an asynchronous backend is waiting for its completions. |
241 |
Only needed in frontends which hide their visualizations in `pre-command' |
242 |
for technical reasons. |
243 |
|
244 |
The visualized data is stored in `company-prefix', `company-candidates', |
245 |
`company-common', `company-selection', `company-point' and |
246 |
`company-search-string'." |
247 |
:set 'company-frontends-set |
248 |
:type '(repeat (choice (const :tag "echo" company-echo-frontend) |
249 |
(const :tag "echo, strip common" |
250 |
company-echo-strip-common-frontend) |
251 |
(const :tag "show echo meta-data in echo" |
252 |
company-echo-metadata-frontend) |
253 |
(const :tag "pseudo tooltip" |
254 |
company-pseudo-tooltip-frontend) |
255 |
(const :tag "pseudo tooltip, multiple only" |
256 |
company-pseudo-tooltip-unless-just-one-frontend) |
257 |
(const :tag "pseudo tooltip, multiple only, delayed" |
258 |
company-pseudo-tooltip-unless-just-one-frontend-with-delay) |
259 |
(const :tag "preview" company-preview-frontend) |
260 |
(const :tag "preview, unique only" |
261 |
company-preview-if-just-one-frontend) |
262 |
(const :tag "preview, common" |
263 |
company-preview-common-frontend) |
264 |
(function :tag "custom function" nil)))) |
265 |
|
266 |
(defcustom company-tooltip-limit 10 |
267 |
"The maximum number of candidates in the tooltip." |
268 |
:type 'integer) |
269 |
|
270 |
(defcustom company-tooltip-minimum 6 |
271 |
"Ensure visibility of this number of candidates. |
272 |
When that many lines are not available between point and the bottom of the |
273 |
window, display the tooltip above point." |
274 |
:type 'integer) |
275 |
|
276 |
(defcustom company-tooltip-minimum-width 0 |
277 |
"The minimum width of the tooltip's inner area. |
278 |
This doesn't include the margins and the scroll bar." |
279 |
:type 'integer |
280 |
:package-version '(company . "0.8.0")) |
281 |
|
282 |
(defcustom company-tooltip-maximum-width most-positive-fixnum |
283 |
"The maximum width of the tooltip's inner area. |
284 |
This doesn't include the margins and the scroll bar." |
285 |
:type 'integer |
286 |
:package-version '(company . "0.9.5")) |
287 |
|
288 |
(defcustom company-tooltip-width-grow-only nil |
289 |
"When non-nil, the tooltip width is not allowed to decrease." |
290 |
:type 'boolean |
291 |
:package-version '(company . "0.10.0")) |
292 |
|
293 |
(defcustom company-tooltip-margin 1 |
294 |
"Width of margin columns to show around the toolip." |
295 |
:type 'integer) |
296 |
|
297 |
(defcustom company-tooltip-offset-display 'scrollbar |
298 |
"Method using which the tooltip displays scrolling position. |
299 |
`scrollbar' means draw a scrollbar to the right of the items. |
300 |
`lines' means wrap items in lines with \"before\" and \"after\" counters." |
301 |
:type '(choice (const :tag "Scrollbar" scrollbar) |
302 |
(const :tag "Two lines" lines))) |
303 |
|
304 |
(defcustom company-tooltip-scrollbar-width 0.4 |
305 |
"Width of the scrollbar thumb, in columns." |
306 |
:type 'number |
307 |
:package-version '(company . "1.0.0")) |
308 |
|
309 |
(defcustom company-tooltip-align-annotations nil |
310 |
"When non-nil, align annotations to the right tooltip border." |
311 |
:type 'boolean |
312 |
:package-version '(company . "0.7.1")) |
313 |
|
314 |
(defcustom company-tooltip-flip-when-above nil |
315 |
"Whether to flip the tooltip when it's above the current line." |
316 |
:type 'boolean |
317 |
:package-version '(company . "0.8.1")) |
318 |
|
319 |
(defcustom company-tooltip-annotation-padding nil |
320 |
"Non-nil to specify the padding before annotation. |
321 |
|
322 |
Depending on the value of `company-tooltip-align-annotations', the default |
323 |
padding is either 0 or 1 space. This variable allows to override that |
324 |
value to increase the padding. When annotations are right-aligned, it sets |
325 |
the minimum padding, and otherwise just the constant one." |
326 |
:type 'number |
327 |
:package-version '(company "0.10.0")) |
328 |
|
329 |
(defvar company-safe-backends |
330 |
'((company-abbrev . "Abbrev") |
331 |
(company-bbdb . "BBDB") |
332 |
(company-capf . "completion-at-point-functions") |
333 |
(company-clang . "Clang") |
334 |
(company-cmake . "CMake") |
335 |
(company-css . "CSS (obsolete backend)") |
336 |
(company-dabbrev . "dabbrev for plain text") |
337 |
(company-dabbrev-code . "dabbrev for code") |
338 |
(company-elisp . "Emacs Lisp (obsolete backend)") |
339 |
(company-etags . "etags") |
340 |
(company-files . "Files") |
341 |
(company-gtags . "GNU Global") |
342 |
(company-ispell . "Ispell") |
343 |
(company-keywords . "Programming language keywords") |
344 |
(company-nxml . "nxml (obsolete backend)") |
345 |
(company-oddmuse . "Oddmuse") |
346 |
(company-semantic . "Semantic") |
347 |
(company-tempo . "Tempo templates"))) |
348 |
(put 'company-safe-backends 'risky-local-variable t) |
349 |
|
350 |
(defun company-safe-backends-p (backends) |
351 |
(and (consp backends) |
352 |
(not (cl-dolist (backend backends) |
353 |
(unless (if (consp backend) |
354 |
(company-safe-backends-p backend) |
355 |
(assq backend company-safe-backends)) |
356 |
(cl-return t)))))) |
357 |
|
358 |
(defcustom company-backends `(company-bbdb |
359 |
,@(unless (version<= "26" emacs-version) |
360 |
(list 'company-nxml)) |
361 |
,@(unless (version<= "26" emacs-version) |
362 |
(list 'company-css)) |
363 |
company-semantic |
364 |
company-cmake |
365 |
company-capf |
366 |
company-clang |
367 |
company-files |
368 |
(company-dabbrev-code company-gtags company-etags |
369 |
company-keywords) |
370 |
company-oddmuse company-dabbrev) |
371 |
"The list of active backends (completion engines). |
372 |
|
373 |
Only one backend is used at a time. The choice depends on the order of |
374 |
the items in this list, and on the values they return in response to the |
375 |
`prefix' command (see below). But a backend can also be a \"grouped\" |
376 |
one (see below). |
377 |
|
378 |
`company-begin-backend' can be used to start a specific backend, |
379 |
`company-other-backend' will skip to the next matching backend in the list. |
380 |
|
381 |
To debug which backend is currently in use, try `M-x company-diag'. |
382 |
|
383 |
Each backend is a function that takes a variable number of arguments. |
384 |
The first argument is the command requested from the backend. It is one |
385 |
of the following: |
386 |
|
387 |
`prefix': The backend should return the text to be completed. Returning |
388 |
nil from this command passes control to the next backend. |
389 |
|
390 |
The expected return value looks like (PREFIX SUFFIX &optional PREFIX-LEN). |
391 |
Where PREFIX is the text to be completed before point, SUFFIX - the |
392 |
remainder after point (when e.g. inside a symbol), and PREFIX-LEN, when |
393 |
non-nil, is the number to use in place of PREFIX's length when comparing |
394 |
against `company-minimum-prefix-length'. PREFIX-LEN can also be just t, |
395 |
and in the latter case the test automatically succeeds. |
396 |
|
397 |
The return value can also be just PREFIX, in which case SUFFIX is taken to |
398 |
be an empty string. |
399 |
|
400 |
`candidates': The second argument is the prefix to be completed. The |
401 |
return value should be a list of candidates that match the prefix. |
402 |
|
403 |
Non-prefix matches are also supported (candidates that don't start with the |
404 |
prefix, but match it in some backend-defined way). Backends that use this |
405 |
feature must disable cache (return t in response to `no-cache') and might |
406 |
also want to handle `match'. |
407 |
|
408 |
Optional commands |
409 |
================= |
410 |
|
411 |
`sorted': Return t here to indicate that the candidates are sorted and will |
412 |
not need to be sorted again. |
413 |
|
414 |
`duplicates': If non-nil, company will take care of removing duplicates |
415 |
from the list. |
416 |
|
417 |
`no-cache': Usually company doesn't ask for candidates again as completion |
418 |
progresses, unless the backend returns t for this command. The second |
419 |
argument is the latest prefix. |
420 |
|
421 |
`ignore-case': Return t here if the backend returns case-insensitive |
422 |
matches. This value is used to determine the longest common prefix (as |
423 |
used in `company-complete-common'), and to filter completions when fetching |
424 |
them from cache. |
425 |
|
426 |
`meta': The second argument is a completion candidate. Return a (short) |
427 |
documentation string for it. |
428 |
|
429 |
`doc-buffer': The second argument is a completion candidate. Return a |
430 |
buffer with documentation for it. Preferably use `company-doc-buffer'. If |
431 |
not all buffer contents pertain to this candidate, return a cons of buffer |
432 |
and window start position. |
433 |
|
434 |
`location': The second argument is a completion candidate. Return a cons |
435 |
of buffer and buffer location, or of file and line number where the |
436 |
completion candidate was defined. |
437 |
|
438 |
`annotation': The second argument is a completion candidate. Return a |
439 |
string to be displayed inline with the candidate in the popup. If |
440 |
duplicates are removed by company, candidates with equal string values will |
441 |
be kept if they have different annotations. For that to work properly, |
442 |
backends should store the related information on candidates using text |
443 |
properties. |
444 |
|
445 |
`deprecated': The second argument is a completion candidate. Return |
446 |
non-nil if the completion candidate is deprecated. |
447 |
|
448 |
`match': The second argument is a completion candidate. Return a positive |
449 |
integer, the index after the end of text matching `prefix' within the |
450 |
candidate string. Alternatively, return a list of (CHUNK-START |
451 |
. CHUNK-END) elements, where CHUNK-START and CHUNK-END are indexes within |
452 |
the candidate string. The corresponding regions are be used when rendering |
453 |
the popup. This command only makes sense for backends that provide |
454 |
non-prefix completion. |
455 |
|
456 |
`require-match': If this returns t, the user is not allowed to enter |
457 |
anything not offered as a candidate. Please don't use that value in normal |
458 |
backends. The default value nil gives the user that choice with |
459 |
`company-require-match'. Return value `never' overrides that option the |
460 |
other way around (using that value will indicate that the returned set of |
461 |
completions is often incomplete, so this behavior will not be useful). |
462 |
|
463 |
`init': Called once for each buffer. The backend can check for external |
464 |
programs and files and load any required libraries. Raising an error here |
465 |
will show up in message log once, and the backend will not be used for |
466 |
completion. |
467 |
|
468 |
`post-completion': Called after a completion candidate has been inserted |
469 |
into the buffer. The second argument is the candidate. Can be used to |
470 |
modify it, e.g. to expand a snippet. |
471 |
|
472 |
`kind': The second argument is a completion candidate. Return a symbol |
473 |
describing the kind of the candidate. Refer to `company-vscode-icons-mapping' |
474 |
for the possible values. |
475 |
|
476 |
`adjust-boundaries': The second argument is prefix and the third argument |
477 |
is suffix (previously returned by the `prefix' command). Return a |
478 |
cons (NEW-PREFIX . NEW-SUFFIX) where both parts correspond to the |
479 |
completion candidate. |
480 |
|
481 |
`expand-common': The first argument is prefix and the second argument is |
482 |
suffix. Return a cons (NEW-PREFIX . NEW-SUFFIX) that denote an edit in the |
483 |
current buffer which would be performed by `company-complete-common'. It |
484 |
should try to make the combined length of the prefix and suffix longer, |
485 |
while ensuring that the completions for the new inputs are the same. |
486 |
Othewise return the original inputs. If there are no matching completions, |
487 |
return the symbol `no-match'. |
488 |
|
489 |
The backend should return nil for all commands it does not support or |
490 |
does not know about. It should also be callable interactively and use |
491 |
`company-begin-backend' to start itself in that case. |
492 |
|
493 |
Grouped backends |
494 |
================ |
495 |
|
496 |
An element of `company-backends' can also be a list of backends. The |
497 |
completions from backends in such groups are merged, but only from those |
498 |
backends which return the same `prefix'. |
499 |
|
500 |
If a backend command takes a candidate as an argument (e.g. `meta'), the |
501 |
call is dispatched to the backend the candidate came from. In other |
502 |
cases (except for `duplicates' and `sorted'), the first non-nil value among |
503 |
all the backends is returned. |
504 |
|
505 |
The group can also contain keywords. Currently, `:with' and `:separate' |
506 |
keywords are defined. If the group contains keyword `:with', the backends |
507 |
listed after this keyword are ignored for the purpose of the `prefix' |
508 |
command. If the group contains keyword `:separate', the candidates that |
509 |
come from different backends are sorted separately in the combined list. |
510 |
|
511 |
Asynchronous backends |
512 |
===================== |
513 |
|
514 |
The return value of each command can also be a cons (:async . FETCHER) |
515 |
where FETCHER is a function of one argument, CALLBACK. When the data |
516 |
arrives, FETCHER must call CALLBACK and pass it the appropriate return |
517 |
value, as described above. That call must happen in the same buffer as |
518 |
where completion was initiated. |
519 |
|
520 |
True asynchronous operation is only supported for command `candidates', and |
521 |
only during idle completion. Other commands will block the user interface, |
522 |
even if the backend uses the asynchronous calling convention." |
523 |
:type `(repeat |
524 |
(choice |
525 |
:tag "backend" |
526 |
,@(mapcar (lambda (b) `(const :tag ,(cdr b) ,(car b))) |
527 |
company-safe-backends) |
528 |
(symbol :tag "User defined") |
529 |
(repeat :tag "Merged backends" |
530 |
(choice :tag "backend" |
531 |
,@(mapcar (lambda (b) |
532 |
`(const :tag ,(cdr b) ,(car b))) |
533 |
company-safe-backends) |
534 |
(const :tag "With" :with) |
535 |
(symbol :tag "User defined")))))) |
536 |
|
537 |
(put 'company-backends 'safe-local-variable 'company-safe-backends-p) |
538 |
|
539 |
(defcustom company-transformers nil |
540 |
"Functions to change the list of candidates received from backends. |
541 |
|
542 |
Each function gets called with the return value of the previous one. |
543 |
The first one gets passed the list of candidates, already sorted and |
544 |
without duplicates." |
545 |
:type '(choice |
546 |
(const :tag "None" nil) |
547 |
(const :tag "Sort by occurrence" (company-sort-by-occurrence)) |
548 |
(const :tag "Sort by backend importance" |
549 |
(company-sort-by-backend-importance)) |
550 |
(const :tag "Prefer case sensitive prefix" |
551 |
(company-sort-prefer-same-case-prefix)) |
552 |
(repeat :tag "User defined" function))) |
553 |
|
554 |
(defcustom company-completion-started-hook nil |
555 |
"Hook run when company starts completing. |
556 |
The hook is called with one argument that is non-nil if the completion was |
557 |
started manually." |
558 |
:type 'hook) |
559 |
|
560 |
(defcustom company-completion-cancelled-hook nil |
561 |
"Hook run when company cancels completing. |
562 |
The hook is called with one argument that is non-nil if the completion was |
563 |
aborted manually." |
564 |
:type 'hook) |
565 |
|
566 |
(defcustom company-completion-finished-hook nil |
567 |
"Hook run when company successfully completes. |
568 |
The hook is called with the selected candidate as an argument. |
569 |
|
570 |
If you indend to use it to post-process candidates from a specific |
571 |
backend, consider using the `post-completion' command instead." |
572 |
:type 'hook) |
573 |
|
574 |
(defcustom company-after-completion-hook nil |
575 |
"Hook run at the end of completion, successful or not. |
576 |
The hook is called with one argument which is either a string or a symbol." |
577 |
:type 'hook) |
578 |
|
579 |
(defcustom company-minimum-prefix-length 3 |
580 |
"The minimum prefix length for idle completion." |
581 |
:type '(integer :tag "prefix length")) |
582 |
|
583 |
(defcustom company-abort-manual-when-too-short nil |
584 |
"If enabled, cancel a manually started completion when the prefix gets |
585 |
shorter than both `company-minimum-prefix-length' and the length of the |
586 |
prefix it was started from." |
587 |
:type 'boolean |
588 |
:package-version '(company . "0.8.0")) |
589 |
|
590 |
(defcustom company-abort-on-unique-match t |
591 |
"If non-nil, typing a full unique match aborts completion. |
592 |
|
593 |
You can still invoke `company-complete' manually to run the |
594 |
`post-completion' handler, though. |
595 |
|
596 |
If it's nil, completion will remain active until you type a prefix that |
597 |
doesn't match anything or finish it manually, e.g. with RET." |
598 |
:type 'boolean) |
599 |
|
600 |
(defcustom company-require-match 'company-explicit-action-p |
601 |
"If enabled, disallow non-matching input. |
602 |
This can be a function do determine if a match is required. |
603 |
|
604 |
This can be overridden by the backend, if it returns t or `never' to |
605 |
`require-match'. `company-insertion-on-trigger' also takes precedence over |
606 |
this." |
607 |
:type '(choice (const :tag "Off" nil) |
608 |
(function :tag "Predicate function") |
609 |
(const :tag "On, if user interaction took place" |
610 |
company-explicit-action-p) |
611 |
(const :tag "On" t))) |
612 |
|
613 |
(define-obsolete-variable-alias |
614 |
'company-auto-complete |
615 |
'company-insertion-on-trigger |
616 |
"0.10.0") |
617 |
|
618 |
(define-obsolete-variable-alias |
619 |
'company-auto-commit |
620 |
'company-insertion-on-trigger |
621 |
"0.10.0") |
622 |
|
623 |
(defcustom company-insertion-on-trigger nil |
624 |
"If enabled, allow triggering insertion of the selected candidate. |
625 |
This can also be a predicate function, for example, |
626 |
`company-explicit-action-p'. |
627 |
|
628 |
See `company-insertion-triggers' for more details on how to define |
629 |
triggers." |
630 |
:type '(choice (const :tag "Off" nil) |
631 |
(function :tag "Predicate function") |
632 |
(const :tag "On, if user interaction took place" |
633 |
company-explicit-action-p) |
634 |
(const :tag "On" t)) |
635 |
:package-version '(company . "0.10.0")) |
636 |
|
637 |
(define-obsolete-variable-alias |
638 |
'company-auto-complete-chars |
639 |
'company-insertion-triggers |
640 |
"0.10.0") |
641 |
|
642 |
(define-obsolete-variable-alias |
643 |
'company-auto-commit-chars |
644 |
'company-insertion-triggers |
645 |
"0.10.0") |
646 |
|
647 |
(defcustom company-insertion-triggers '(?\ ?\) ?.) |
648 |
"Determine triggers for `company-insertion-on-trigger'. |
649 |
|
650 |
If this is a string, then each character in it can trigger insertion of the |
651 |
selected candidate. If it is a list of syntax description characters (see |
652 |
`modify-syntax-entry'), then characters with any of those syntaxes can act |
653 |
as triggers. |
654 |
|
655 |
This can also be a function, which is called with the new input. To |
656 |
trigger insertion, the function should return a non-nil value. |
657 |
|
658 |
Note that a character that is part of a valid completion never triggers |
659 |
insertion." |
660 |
:type '(choice (string :tag "Characters") |
661 |
(set :tag "Syntax" |
662 |
(const :tag "Whitespace" ?\ ) |
663 |
(const :tag "Symbol" ?_) |
664 |
(const :tag "Opening parentheses" ?\() |
665 |
(const :tag "Closing parentheses" ?\)) |
666 |
(const :tag "Word constituent" ?w) |
667 |
(const :tag "Punctuation." ?.) |
668 |
(const :tag "String quote." ?\") |
669 |
(const :tag "Paired delimiter." ?$) |
670 |
(const :tag "Expression quote or prefix operator." ?\') |
671 |
(const :tag "Comment starter." ?<) |
672 |
(const :tag "Comment ender." ?>) |
673 |
(const :tag "Character-quote." ?/) |
674 |
(const :tag "Generic string fence." ?|) |
675 |
(const :tag "Generic comment fence." ?!)) |
676 |
(function :tag "Predicate function")) |
677 |
:package-version '(company . "0.10.0")) |
678 |
|
679 |
(defcustom company-idle-delay .2 |
680 |
"The idle delay in seconds until completion starts automatically. |
681 |
The prefix still has to satisfy `company-minimum-prefix-length' before that |
682 |
happens. The value of nil means no idle completion." |
683 |
:type '(choice (const :tag "never (nil)" nil) |
684 |
(const :tag "immediate (0)" 0) |
685 |
(function :tag "Predicate function") |
686 |
(number :tag "seconds"))) |
687 |
|
688 |
(defcustom company-tooltip-idle-delay .5 |
689 |
"The idle delay in seconds until tooltip is shown when using |
690 |
`company-pseudo-tooltip-unless-just-one-frontend-with-delay'." |
691 |
:type '(choice (const :tag "never (nil)" nil) |
692 |
(const :tag "immediate (0)" 0) |
693 |
(number :tag "seconds"))) |
694 |
|
695 |
(defcustom company-inhibit-inside-symbols nil |
696 |
"Non-nil to inhibit idle completion when typing in the middle of a symbol. |
697 |
The symbol is in a generalized sense, indicated by the `prefix' backend |
698 |
action returning a non-empty SUFFIX element. When this variable is |
699 |
non-nil, completion inside symbol will onlytriggered by an explicit command |
700 |
invocation, such as \\[company-complete-common]." |
701 |
:type 'boolean |
702 |
:package-version '(company . "1.0.0")) |
703 |
|
704 |
(defcustom company-begin-commands '(self-insert-command |
705 |
org-self-insert-command |
706 |
orgtbl-self-insert-command |
707 |
c-scope-operator |
708 |
c-electric-colon |
709 |
c-electric-lt-gt |
710 |
c-electric-slash) |
711 |
"A list of commands after which idle completion is allowed. |
712 |
If this is t, it can show completions after any command except a few from a |
713 |
pre-defined list. See `company-idle-delay'. |
714 |
|
715 |
Alternatively, any command with a non-nil `company-begin' property is |
716 |
treated as if it was on this list." |
717 |
:type '(choice (const :tag "Any command" t) |
718 |
(const :tag "Self insert command" (self-insert-command)) |
719 |
(repeat :tag "Commands" function)) |
720 |
:package-version '(company . "0.8.4")) |
721 |
|
722 |
(defcustom company-continue-commands '(not save-buffer save-some-buffers |
723 |
save-buffers-kill-terminal |
724 |
save-buffers-kill-emacs |
725 |
completion-at-point |
726 |
complete-symbol |
727 |
completion-help-at-point) |
728 |
"A list of commands that are allowed during completion. |
729 |
If this is t, or if `company-begin-commands' is t, any command is allowed. |
730 |
Otherwise, the value must be a list of symbols. If it starts with `not', |
731 |
the cdr is the list of commands that abort completion. Otherwise, all |
732 |
commands except those in that list, or in `company-begin-commands', or |
733 |
commands in the `company-' namespace, abort completion." |
734 |
:type '(choice (const :tag "Any command" t) |
735 |
(cons :tag "Any except" |
736 |
(const not) |
737 |
(repeat :tag "Commands" function)) |
738 |
(repeat :tag "Commands" function))) |
739 |
|
740 |
(defun company-custom--set-quick-access (option value) |
741 |
"Re-bind quick-access key sequences on OPTION VALUE change." |
742 |
;; When upgrading from an earlier version of company, might not be. |
743 |
(when (fboundp #'company-keymap--unbind-quick-access) |
744 |
(when (boundp 'company-active-map) |
745 |
(company-keymap--unbind-quick-access company-active-map)) |
746 |
(when (boundp 'company-search-map) |
747 |
(company-keymap--unbind-quick-access company-search-map))) |
748 |
(custom-set-default option value) |
749 |
(when (fboundp #'company-keymap--bind-quick-access) |
750 |
(when (boundp 'company-active-map) |
751 |
(company-keymap--bind-quick-access company-active-map)) |
752 |
(when (boundp 'company-search-map) |
753 |
(company-keymap--bind-quick-access company-search-map)))) |
754 |
|
755 |
(defcustom company-quick-access-keys '("1" "2" "3" "4" "5" "6" "7" "8" "9" "0") |
756 |
"Character strings used as a part of quick-access key sequences. |
757 |
To change this value without Customize interface, use `customize-set-variable'. |
758 |
|
759 |
To change the quick-access key sequences modifier, customize |
760 |
`company-quick-access-modifier'. |
761 |
|
762 |
If `company-show-quick-access' is non-nil, show quick-access hints |
763 |
beside the candidates." |
764 |
:set #'company-custom--set-quick-access |
765 |
:type '(choice |
766 |
(const :tag "Digits" ("1" "2" "3" "4" "5" "6" "7" "8" "9" "0")) |
767 |
(const :tag "QWERTY home row" ("a" "s" "d" "f" "g" "h" "j" "k" "l" ";")) |
768 |
;; TODO un-comment on removal of `M-n' `company--select-next-and-warn'. |
769 |
;; (const :tag "Dvorak home row" ("a" "o" "e" "u" "i" "d" "h" "t" "n" "s")) |
770 |
(repeat :tag "User defined" string)) |
771 |
:package-version '(company . "0.10.0")) |
772 |
|
773 |
(defcustom company-quick-access-modifier 'meta |
774 |
"Modifier key used for quick-access keys sequences. |
775 |
To change this value without Customize interface, use `customize-set-variable'. |
776 |
See `company-quick-access-keys' for more details." |
777 |
:set #'company-custom--set-quick-access |
778 |
:type '(choice (const :tag "Meta key" meta) |
779 |
(const :tag "Super key" super) |
780 |
(const :tag "Hyper key" hyper) |
781 |
(const :tag "Control key" control)) |
782 |
:package-version '(company . "0.10.0")) |
783 |
|
784 |
(defun company-keymap--quick-access-modifier () |
785 |
"Return string representation of the `company-quick-access-modifier'." |
786 |
(if-let* ((modifier (assoc-default company-quick-access-modifier |
787 |
'((meta . "M") |
788 |
(super . "s") |
789 |
(hyper . "H") |
790 |
(control . "C"))))) |
791 |
modifier |
792 |
(warn "company-quick-access-modifier value unknown: %S" |
793 |
company-quick-access-modifier) |
794 |
"M")) |
795 |
|
796 |
(defun company-keymap--unbind-quick-access (keymap) |
797 |
(let ((modifier (company-keymap--quick-access-modifier))) |
798 |
(dolist (key company-quick-access-keys) |
799 |
(let ((key-seq (company-keymap--kbd-quick-access modifier key))) |
800 |
(when (equal (lookup-key keymap key-seq) 'company-complete-quick-access) |
801 |
(define-key keymap key-seq nil)))))) |
802 |
|
803 |
(defun company-keymap--bind-quick-access (keymap) |
804 |
(let ((modifier (company-keymap--quick-access-modifier))) |
805 |
(dolist (key company-quick-access-keys) |
806 |
(let ((key-seq (company-keymap--kbd-quick-access modifier key))) |
807 |
(if (lookup-key keymap key-seq) |
808 |
(warn "Key sequence %s already bound" (key-description key-seq)) |
809 |
(define-key keymap key-seq #'company-complete-quick-access)))))) |
810 |
|
811 |
(defun company-keymap--kbd-quick-access (modifier key) |
812 |
(kbd (format "%s-%s" modifier key))) |
813 |
|
814 |
(define-obsolete-variable-alias |
815 |
'company-show-numbers |
816 |
'company-show-quick-access |
817 |
"0.10.0") |
818 |
|
819 |
(defcustom company-show-quick-access nil |
820 |
"If non-nil, show quick-access hints beside the candidates. |
821 |
|
822 |
For a tooltip frontend, non-nil value enables a column with the hints |
823 |
on the right side of the tooltip, unless the configured value is `left'. |
824 |
|
825 |
To change the quick-access key bindings, customize `company-quick-access-keys' |
826 |
and `company-quick-access-modifier'. |
827 |
|
828 |
To change the shown quick-access hints, customize |
829 |
`company-quick-access-hint-function'." |
830 |
:type '(choice (const :tag "off" nil) |
831 |
(const :tag "left" left) |
832 |
(const :tag "on" t))) |
833 |
|
834 |
(defcustom company-show-numbers-function nil |
835 |
"Function called to get quick-access numbers for the first ten candidates. |
836 |
|
837 |
The function receives the candidate number (starting from 1) and should |
838 |
return a string prefixed with one space." |
839 |
:type 'function) |
840 |
(make-obsolete-variable |
841 |
'company-show-numbers-function |
842 |
"use `company-quick-access-hint-function' instead, |
843 |
but adjust the expected values appropriately." |
844 |
"0.10.0") |
845 |
|
846 |
(defcustom company-quick-access-hint-function #'company-quick-access-hint-key |
847 |
"Function called to get quick-access hints for the candidates. |
848 |
|
849 |
The function receives a candidate's 0-based number |
850 |
and should return a string. |
851 |
See `company-show-quick-access' for more details." |
852 |
:type 'function) |
853 |
|
854 |
(defun company-quick-access-hint-key (candidate) |
855 |
"Return a quick-access key for the CANDIDATE number. |
856 |
This is a default value of `company-quick-access-hint-function'." |
857 |
(if company-show-numbers-function |
858 |
(funcall company-show-numbers-function (1+ candidate)) |
859 |
(format "%s" |
860 |
(if (< candidate (length company-quick-access-keys)) |
861 |
(nth candidate company-quick-access-keys) |
862 |
"")))) |
863 |
|
864 |
(defcustom company-selection-wrap-around nil |
865 |
"If enabled, selecting item before first or after last wraps around." |
866 |
:type '(choice (const :tag "off" nil) |
867 |
(const :tag "on" t))) |
868 |
|
869 |
(defcustom company-async-redisplay-delay 0.005 |
870 |
"Delay before redisplay when fetching candidates asynchronously. |
871 |
|
872 |
You might want to set this to a higher value if your backends respond |
873 |
quickly, to avoid redisplaying twice per each typed character." |
874 |
:type 'number) |
875 |
|
876 |
(defvar company-async-wait 0.03 |
877 |
"Pause between checks to see if the value's been set when turning an |
878 |
asynchronous call into synchronous.") |
879 |
|
880 |
(defvar company-async-timeout 2 |
881 |
"Maximum wait time for a value to be set during asynchronous call.") |
882 |
|
883 |
;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
884 |
|
885 |
(defvar company-mode-map (make-sparse-keymap) |
886 |
"Keymap used by `company-mode'.") |
887 |
|
888 |
(defvar company-active-map |
889 |
(let ((keymap (make-sparse-keymap))) |
890 |
(define-key keymap "\e\e\e" 'company-abort) |
891 |
(define-key keymap "\C-g" 'company-abort) |
892 |
(define-key keymap (kbd "M-n") 'company--select-next-and-warn) |
893 |
(define-key keymap (kbd "M-p") 'company--select-previous-and-warn) |
894 |
(define-key keymap (kbd "C-n") 'company-select-next-or-abort) |
895 |
(define-key keymap (kbd "C-p") 'company-select-previous-or-abort) |
896 |
(define-key keymap (kbd "<down>") 'company-select-next-or-abort) |
897 |
(define-key keymap (kbd "<up>") 'company-select-previous-or-abort) |
898 |
(define-key keymap [remap scroll-up-command] 'company-next-page) |
899 |
(define-key keymap [remap scroll-down-command] 'company-previous-page) |
900 |
(define-key keymap [down-mouse-1] 'ignore) |
901 |
(define-key keymap [down-mouse-3] 'ignore) |
902 |
(define-key keymap [mouse-1] 'company-complete-mouse) |
903 |
(define-key keymap [mouse-3] 'company-select-mouse) |
904 |
(define-key keymap [up-mouse-1] 'ignore) |
905 |
(define-key keymap [up-mouse-3] 'ignore) |
906 |
(define-key keymap [return] 'company-complete-selection) |
907 |
(define-key keymap (kbd "RET") 'company-complete-selection) |
908 |
(define-key keymap [tab] 'company-complete-common-or-cycle) |
909 |
(define-key keymap (kbd "TAB") 'company-complete-common-or-cycle) |
910 |
(define-key keymap [backtab] 'company-cycle-backward) |
911 |
(define-key keymap (kbd "<f1>") 'company-show-doc-buffer) |
912 |
(define-key keymap (kbd "C-h") 'company-show-doc-buffer) |
913 |
(define-key keymap "\C-w" 'company-show-location) |
914 |
(define-key keymap "\C-s" 'company-search-candidates) |
915 |
(define-key keymap "\C-\M-s" 'company-filter-candidates) |
916 |
(company-keymap--bind-quick-access keymap) |
917 |
keymap) |
918 |
"Keymap that is enabled during an active completion.") |
919 |
|
920 |
(defvar company--disabled-backends nil) |
921 |
|
922 |
(defun company--select-next-and-warn (&optional arg) |
923 |
(interactive "p") |
924 |
(company--warn-changed-binding) |
925 |
(company-select-next arg)) |
926 |
|
927 |
(defun company--select-previous-and-warn (&optional arg) |
928 |
(interactive "p") |
929 |
(company--warn-changed-binding) |
930 |
(company-select-previous arg)) |
931 |
|
932 |
(defun company--warn-changed-binding () |
933 |
(interactive) |
934 |
(run-with-idle-timer |
935 |
0.01 nil |
936 |
(lambda () |
937 |
(message "Warning: default bindings are being changed to C-n and C-p")))) |
938 |
|
939 |
(defun company-init-backend (backend) |
940 |
(and (symbolp backend) |
941 |
(not (fboundp backend)) |
942 |
(ignore-errors (require backend nil t))) |
943 |
(cond |
944 |
((symbolp backend) |
945 |
(condition-case err |
946 |
(progn |
947 |
(funcall backend 'init) |
948 |
(put backend 'company-init t)) |
949 |
(error |
950 |
(put backend 'company-init 'failed) |
951 |
(unless (memq backend company--disabled-backends) |
952 |
(message "Company backend '%s' could not be initialized:\n%s" |
953 |
backend (error-message-string err))) |
954 |
(cl-pushnew backend company--disabled-backends) |
955 |
nil))) |
956 |
;; No initialization for lambdas. |
957 |
((functionp backend) t) |
958 |
(t ;; Must be a list. |
959 |
(cl-dolist (b backend) |
960 |
(unless (keywordp b) |
961 |
(company-init-backend b)))))) |
962 |
|
963 |
(defun company--maybe-init-backend (backend) |
964 |
(or (not (symbolp backend)) |
965 |
(eq t (get backend 'company-init)) |
966 |
(unless (get backend 'company-init) |
967 |
(company-init-backend backend)))) |
968 |
|
969 |
(defcustom company-lighter-base "company" |
970 |
"Base string to use for the `company-mode' lighter." |
971 |
:type 'string |
972 |
:package-version '(company . "0.8.10")) |
973 |
|
974 |
(defvar company-lighter '(" " |
975 |
(company-candidates |
976 |
(:eval |
977 |
(if (consp company-backend) |
978 |
(when company-selection |
979 |
(company--group-lighter (nth company-selection |
980 |
company-candidates) |
981 |
company-lighter-base)) |
982 |
(symbol-name company-backend))) |
983 |
company-lighter-base)) |
984 |
"Mode line lighter for Company. |
985 |
|
986 |
The value of this variable is a mode line template as in |
987 |
`mode-line-format'.") |
988 |
|
989 |
(put 'company-lighter 'risky-local-variable t) |
990 |
|
991 |
;;;###autoload |
992 |
(define-minor-mode company-mode |
993 |
"\"complete anything\"; is an in-buffer completion framework. |
994 |
Completion starts automatically, depending on the values |
995 |
`company-idle-delay' and `company-minimum-prefix-length'. |
996 |
|
997 |
Completion can be controlled with the commands: |
998 |
`company-complete-common', `company-complete-selection', `company-complete', |
999 |
`company-select-next', `company-select-previous'. If these commands are |
1000 |
called before `company-idle-delay', completion will also start. |
1001 |
|
1002 |
Completions can be searched with `company-search-candidates' or |
1003 |
`company-filter-candidates'. These can be used while completion is |
1004 |
inactive, as well. |
1005 |
|
1006 |
The completion data is retrieved using `company-backends' and displayed |
1007 |
using `company-frontends'. If you want to start a specific backend, call |
1008 |
it interactively or use `company-begin-backend'. |
1009 |
|
1010 |
By default, the completions list is sorted alphabetically, unless the |
1011 |
backend chooses otherwise, or `company-transformers' changes it later. |
1012 |
|
1013 |
regular keymap (`company-mode-map'): |
1014 |
|
1015 |
\\{company-mode-map} |
1016 |
keymap during active completions (`company-active-map'): |
1017 |
|
1018 |
\\{company-active-map}" |
1019 |
:lighter company-lighter |
1020 |
(if company-mode |
1021 |
(progn |
1022 |
(add-hook 'pre-command-hook 'company-pre-command nil t) |
1023 |
(add-hook 'post-command-hook 'company-post-command nil t) |
1024 |
(add-hook 'yas-keymap-disable-hook 'company--active-p nil t) |
1025 |
(mapc 'company-init-backend company-backends)) |
1026 |
(remove-hook 'pre-command-hook 'company-pre-command t) |
1027 |
(remove-hook 'post-command-hook 'company-post-command t) |
1028 |
(remove-hook 'yas-keymap-disable-hook 'company--active-p t) |
1029 |
(company-cancel))) |
1030 |
|
1031 |
(defcustom company-global-modes t |
1032 |
"Modes for which `company-mode' mode is turned on by `global-company-mode'. |
1033 |
If nil, means no modes. If t, then all major modes have it turned on. |
1034 |
If a list, it should be a list of `major-mode' symbol names for which |
1035 |
`company-mode' should be automatically turned on. The sense of the list is |
1036 |
negated if it begins with `not'. For example: |
1037 |
(c-mode c++-mode) |
1038 |
means that `company-mode' is turned on for buffers in C and C++ modes only. |
1039 |
(not message-mode) |
1040 |
means that `company-mode' is always turned on except in `message-mode' buffers." |
1041 |
:type '(choice (const :tag "none" nil) |
1042 |
(const :tag "all" t) |
1043 |
(set :menu-tag "mode specific" :tag "modes" |
1044 |
:value (not) |
1045 |
(const :tag "Except" not) |
1046 |
(repeat :inline t (symbol :tag "mode"))))) |
1047 |
|
1048 |
;;;###autoload |
1049 |
(define-globalized-minor-mode global-company-mode company-mode company-mode-on) |
1050 |
|
1051 |
(defun company-mode-on () |
1052 |
(when (and (not (or noninteractive (eq (aref (buffer-name) 0) ?\s))) |
1053 |
(cond ((eq company-global-modes t) |
1054 |
t) |
1055 |
((eq (car-safe company-global-modes) 'not) |
1056 |
(not (memq major-mode (cdr company-global-modes)))) |
1057 |
(t (memq major-mode company-global-modes)))) |
1058 |
(company-mode 1))) |
1059 |
|
1060 |
(defsubst company-assert-enabled () |
1061 |
(unless company-mode |
1062 |
(company-uninstall-map) |
1063 |
(user-error "Company not enabled"))) |
1064 |
|
1065 |
;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1066 |
|
1067 |
(defvar-local company-my-keymap nil) |
1068 |
|
1069 |
(defvar company-emulation-alist '((t . nil))) |
1070 |
|
1071 |
(defun company-enable-overriding-keymap (keymap) |
1072 |
(company-uninstall-map) |
1073 |
(setq company-my-keymap keymap)) |
1074 |
|
1075 |
(defun company-ensure-emulation-alist () |
1076 |
(unless (eq 'company-emulation-alist (car emulation-mode-map-alists)) |
1077 |
(setq emulation-mode-map-alists |
1078 |
(cons 'company-emulation-alist |
1079 |
(delq 'company-emulation-alist emulation-mode-map-alists))))) |
1080 |
|
1081 |
(defun company-install-map () |
1082 |
(unless (or (cdar company-emulation-alist) |
1083 |
(null company-my-keymap)) |
1084 |
(setq-local company-emulation-alist `((t . ,company-my-keymap))))) |
1085 |
|
1086 |
(defun company-uninstall-map () |
1087 |
(kill-local-variable 'company-emulation-alist)) |
1088 |
|
1089 |
(defun company--company-command-p (keys) |
1090 |
"Checks if the keys are part of company's overriding keymap" |
1091 |
(or (equal [company-dummy-event] keys) |
1092 |
(commandp (lookup-key company-my-keymap keys)))) |
1093 |
|
1094 |
;; To avoid warnings in Emacs < 26. |
1095 |
(declare-function line-number-display-width "indent.c") |
1096 |
|
1097 |
(defun company--posn-col-row (posn) |
1098 |
(let* ((col-row (if (>= emacs-major-version 29) |
1099 |
(with-no-warnings ;with 2 arguments, but accepts only 1 |
1100 |
(posn-col-row posn t)) |
1101 |
(posn-col-row posn))) |
1102 |
(col (car col-row)) |
1103 |
;; `posn-col-row' doesn't work well with lines of different height. |
1104 |
;; `posn-actual-col-row' doesn't handle multiple-width characters. |
1105 |
(row (cdr (or (posn-actual-col-row posn) |
1106 |
;; When position is non-visible for some reason. |
1107 |
col-row)))) |
1108 |
;; posn-col-row return value relative to the left |
1109 |
(when (eq (current-bidi-paragraph-direction) 'right-to-left) |
1110 |
;; `remap' as 3rd argument to window-body-width is E30+ only :-( |
1111 |
(let ((ww (window-body-width))) |
1112 |
(setq col (- ww col)))) |
1113 |
(when (bound-and-true-p display-line-numbers) |
1114 |
(cl-decf col (+ 2 (line-number-display-width)))) |
1115 |
(cons (+ col (window-hscroll)) row))) |
1116 |
|
1117 |
(defun company--col-row (&optional pos) |
1118 |
(company--posn-col-row (posn-at-point pos))) |
1119 |
|
1120 |
(defun company--row (&optional pos) |
1121 |
(cdr (company--col-row pos))) |
1122 |
|
1123 |
;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1124 |
|
1125 |
(defvar-local company-backend nil) |
1126 |
|
1127 |
(defun company-grab (regexp &optional expression limit) |
1128 |
(when (looking-back regexp limit) |
1129 |
(or (match-string-no-properties (or expression 0)) ""))) |
1130 |
|
1131 |
(defun company-grab-suffix (regexp &optional expression) |
1132 |
(when (looking-at regexp) |
1133 |
(or (match-string-no-properties (or expression 0)) ""))) |
1134 |
|
1135 |
(defun company-grab-line (regexp &optional expression) |
1136 |
"Return a match string for REGEXP if it matches text before point. |
1137 |
If EXPRESSION is non-nil, return the match string for the respective |
1138 |
parenthesized expression in REGEXP. |
1139 |
Matching is limited to the current line." |
1140 |
(let ((inhibit-field-text-motion t)) |
1141 |
(company-grab regexp expression (line-beginning-position)))) |
1142 |
|
1143 |
(defun company-grab-symbol () |
1144 |
"Return buffer substring from the beginning of the symbol until point." |
1145 |
(buffer-substring (point) (save-excursion (skip-syntax-backward "w_") |
1146 |
(point)))) |
1147 |
|
1148 |
(defun company-grab-symbol-suffix () |
1149 |
"Return buffer substring from point until the end of the symbol." |
1150 |
(buffer-substring (point) (save-excursion (skip-syntax-forward "w_") |
1151 |
(point)))) |
1152 |
|
1153 |
(defun company-grab-word () |
1154 |
"Return buffer substring from the beginning of the word until point." |
1155 |
(buffer-substring (point) (save-excursion (skip-syntax-backward "w") |
1156 |
(point)))) |
1157 |
|
1158 |
(defun company-grab-word-suffix () |
1159 |
"Return buffer substring from the beginning of the word until point." |
1160 |
(buffer-substring (point) (save-excursion (skip-syntax-forward "w") |
1161 |
(point)))) |
1162 |
|
1163 |
(defun company-grab-symbol-parts (&optional idle-begin-after-re max-len) |
1164 |
"Return a list (PREFIX SUFFIX &optional OVERRIDE). |
1165 |
|
1166 |
IDLE-BEGIN-AFTER-RE, if non-nil, must be a regexp. |
1167 |
|
1168 |
Where OVERRIDE might be t is IDLE-BEGIN-AFTER-RE is non-nil and the text |
1169 |
before prefix matches it. PREFIX and SUFFIX are as returned by |
1170 |
`company-grab-symbol' and `company-grab-symbol-suffix'. |
1171 |
MAX-LEN is how far back to try to match the IDLE-BEGIN-AFTER-RE regexp." |
1172 |
(let ((prefix (company-grab-symbol)) |
1173 |
suffix override) |
1174 |
(setq suffix (company-grab-symbol-suffix)) |
1175 |
(when idle-begin-after-re |
1176 |
(save-excursion |
1177 |
(forward-char (- (length prefix))) |
1178 |
(when (looking-back idle-begin-after-re (if max-len |
1179 |
(- (point) max-len) |
1180 |
(line-beginning-position))) |
1181 |
(setq override t)))) |
1182 |
(list prefix suffix override))) |
1183 |
|
1184 |
(define-obsolete-function-alias |
1185 |
'company-grab-symbol-cons |
1186 |
'company-grab-symbol-parts "1.0") |
1187 |
|
1188 |
(defun company-in-string-or-comment () |
1189 |
"Return non-nil if point is within a string or comment." |
1190 |
(let ((ppss (syntax-ppss))) |
1191 |
(or (car (setq ppss (nthcdr 3 ppss))) |
1192 |
(car (setq ppss (cdr ppss))) |
1193 |
(nth 3 ppss)))) |
1194 |
|
1195 |
(defun company-substitute-prefix (prefix strings) |
1196 |
(let ((len (length prefix))) |
1197 |
(mapcar |
1198 |
(lambda (s) |
1199 |
(if (eq t (compare-strings prefix 0 len s 0 len)) |
1200 |
s |
1201 |
(concat prefix (substring s len)))) |
1202 |
strings))) |
1203 |
|
1204 |
(defun company--match-from-capf-face (str) |
1205 |
"Compute `match' result from a CAPF's completion fontification." |
1206 |
(let* ((match-start nil) (pos -1) |
1207 |
(prop-value nil) (faces nil) |
1208 |
(has-face-p nil) chunks |
1209 |
(limit (length str))) |
1210 |
(while (< pos limit) |
1211 |
(setq pos |
1212 |
(if (< pos 0) 0 (next-property-change pos str limit))) |
1213 |
(setq prop-value (or (get-text-property pos 'face str) |
1214 |
(get-text-property pos 'font-lock-face str)) |
1215 |
faces (if (listp prop-value) prop-value (list prop-value)) |
1216 |
has-face-p (memq 'completions-common-part faces)) |
1217 |
(cond ((and (not match-start) has-face-p) |
1218 |
(setq match-start pos)) |
1219 |
((and match-start (not has-face-p)) |
1220 |
(push (cons match-start pos) chunks) |
1221 |
(setq match-start nil)))) |
1222 |
(nreverse chunks))) |
1223 |
|
1224 |
(defun company--capf-completions (prefix suffix table &optional pred meta) |
1225 |
(cl-letf* ((keep-suffix t) |
1226 |
(wrapper |
1227 |
(lambda (&rest args) |
1228 |
;; If emacs22 style is used, suffix is ignored. |
1229 |
;; That's the only popular completion style that does this. |
1230 |
(let ((res (apply #'completion-emacs22-all-completions args))) |
1231 |
(when res (setq keep-suffix nil)) |
1232 |
res))) |
1233 |
(completion-styles-alist (copy-tree completion-styles-alist)) |
1234 |
((nth 2 (assoc 'emacs22 completion-styles-alist)) |
1235 |
wrapper) |
1236 |
(all (completion-all-completions (concat prefix suffix) |
1237 |
table pred |
1238 |
(length prefix) |
1239 |
meta)) |
1240 |
(last (last all)) |
1241 |
(base-size (or (cdr last) 0)) |
1242 |
;; base-suffix-size is not available, but it's usually simple. |
1243 |
(bounds (completion-boundaries prefix table pred suffix))) |
1244 |
(when last |
1245 |
(setcdr last nil)) |
1246 |
(unless keep-suffix |
1247 |
(setcdr bounds 0)) |
1248 |
`((:completions . ,all) |
1249 |
(:boundaries . ,(cons (substring prefix base-size) |
1250 |
(substring suffix 0 (cdr bounds))))))) |
1251 |
|
1252 |
(defun company--capf-expand-common (prefix suffix table &optional pred metadata) |
1253 |
(let* ((res |
1254 |
(completion-try-completion (concat prefix suffix) |
1255 |
table pred (length prefix) metadata))) |
1256 |
(cond |
1257 |
((null res) |
1258 |
'no-match) |
1259 |
((memq res '(t nil)) |
1260 |
(cons prefix suffix)) |
1261 |
(t |
1262 |
(cons |
1263 |
(substring (car res) 0 (cdr res)) |
1264 |
(substring (car res) (cdr res))))))) |
1265 |
|
1266 |
;; We store boundaries as markers because when the `unhide' frontend action is |
1267 |
;; called, the completions are still being fetched. So the capf boundaries info |
1268 |
;; can't be relied to be fresh by other means. |
1269 |
(defun company--capf-boundaries-markers (string-pair &optional markers) |
1270 |
"STRING-PAIR is (PREFIX . SUFFIX) and MARKERS is a pair to reuse." |
1271 |
(when (or (not markers) |
1272 |
(stringp (car markers))) |
1273 |
(setq markers (cons (make-marker) |
1274 |
(make-marker)))) |
1275 |
(move-marker (car markers) (- (point) (length (car string-pair)))) |
1276 |
(move-marker (cdr markers) (+ (point) (length (cdr string-pair)))) |
1277 |
markers) |
1278 |
|
1279 |
(defun company--capf-boundaries (markers) |
1280 |
(let* ((beg (car markers)) |
1281 |
(end (cdr markers)) |
1282 |
res) |
1283 |
(when (> (point) end) (setq end (point))) |
1284 |
(setq res (cons (buffer-substring beg (point)) |
1285 |
(buffer-substring (point) end))) |
1286 |
res)) |
1287 |
|
1288 |
(defvar company--cache (make-hash-table :test #'equal :size 10)) |
1289 |
|
1290 |
(cl-defun company-cache-fetch (key |
1291 |
fetcher |
1292 |
&key expire check-tag) |
1293 |
"Fetch the value assigned to KEY in the cache. |
1294 |
When not found, or when found to be stale, calls FETCHER to compute the |
1295 |
result. When EXPIRE is non-nil, the value will be deleted at the end of |
1296 |
completion. CHECK-TAG, when present, is saved as well, and the entry will |
1297 |
be recomputed when this value changes." |
1298 |
;; We could make EXPIRE accept a time value as well. |
1299 |
(let ((res (gethash key company--cache 'none)) |
1300 |
value) |
1301 |
(if (and (not (eq res 'none)) |
1302 |
(or (not check-tag) |
1303 |
(equal check-tag (assoc-default :check-tag res)))) |
1304 |
(assoc-default :value res) |
1305 |
(setq res (list (cons :value (setq value (funcall fetcher))))) |
1306 |
(if expire (push '(:expire . t) res)) |
1307 |
(if check-tag (push `(:check-tag . ,check-tag) res)) |
1308 |
(puthash key res company--cache) |
1309 |
value))) |
1310 |
|
1311 |
(defun company-cache-delete (key) |
1312 |
"Delete KEY from cache." |
1313 |
(remhash key company--cache)) |
1314 |
|
1315 |
(defun company-cache-expire () |
1316 |
"Delete all keys from the cache that are set to be expired." |
1317 |
(maphash (lambda (k v) |
1318 |
(when (assoc-default :expire v) |
1319 |
(remhash k company--cache))) |
1320 |
company--cache)) |
1321 |
|
1322 |
(defun company-call-backend (&rest args) |
1323 |
(company--force-sync #'company-call-backend-raw args company-backend)) |
1324 |
|
1325 |
(defun company--force-sync (fun args backend) |
1326 |
(let ((value (apply fun args))) |
1327 |
(if (not (eq (car-safe value) :async)) |
1328 |
value |
1329 |
(let ((res 'trash) |
1330 |
(start (time-to-seconds))) |
1331 |
(funcall (cdr value) |
1332 |
(lambda (result) (setq res result))) |
1333 |
(while (eq res 'trash) |
1334 |
(if (> (- (time-to-seconds) start) company-async-timeout) |
1335 |
(error "Company: backend %s async timeout with args %s" |
1336 |
backend args) |
1337 |
;; XXX: Reusing the trick from company--fetch-candidates here |
1338 |
;; doesn't work well: sit-for isn't a good fit when we want to |
1339 |
;; ignore pending input (results in too many calls). |
1340 |
;; FIXME: We should deal with this by standardizing on a kind of |
1341 |
;; Future object that knows how to sync itself. In most cases (but |
1342 |
;; not all), by calling accept-process-output, probably. |
1343 |
(sleep-for company-async-wait))) |
1344 |
res)))) |
1345 |
|
1346 |
(defun company-call-backend-raw (&rest args) |
1347 |
(condition-case-unless-debug err |
1348 |
(if (functionp company-backend) |
1349 |
(apply company-backend args) |
1350 |
(apply #'company--multi-backend-adapter company-backend args)) |
1351 |
(user-error (user-error |
1352 |
"Company: backend %s user-error: %s" |
1353 |
company-backend (error-message-string err))) |
1354 |
(error (error "Company: backend %s error \"%s\" with args %s" |
1355 |
company-backend (error-message-string err) args)))) |
1356 |
|
1357 |
(defvar-local company--multi-uncached-backends nil) |
1358 |
(defvar-local company--multi-min-prefix nil) |
1359 |
|
1360 |
(defun company--multi-backend-adapter (backends command &rest args) |
1361 |
(let ((backends (cl-loop for b in backends |
1362 |
when (or (keywordp b) |
1363 |
(company--maybe-init-backend b)) |
1364 |
collect b)) |
1365 |
(separate (memq :separate backends))) |
1366 |
|
1367 |
(unless (eq command 'prefix) |
1368 |
(setq backends (cl-delete-if #'keywordp backends))) |
1369 |
|
1370 |
(pcase command |
1371 |
(`candidates |
1372 |
(company--multi-backend-adapter-candidates backends |
1373 |
(or company--multi-min-prefix 0) |
1374 |
separate)) |
1375 |
(`set-min-prefix (setq company--multi-min-prefix (car args))) |
1376 |
(`sorted separate) |
1377 |
(`duplicates (not separate)) |
1378 |
((and `no-cache |
1379 |
(pred (lambda (_) |
1380 |
(let* (found |
1381 |
(uncached company--multi-uncached-backends)) |
1382 |
(dolist (backend backends) |
1383 |
(when |
1384 |
(and (member backend uncached) |
1385 |
(company--good-prefix-p |
1386 |
(let ((company-backend backend)) |
1387 |
(company-call-backend 'prefix)) |
1388 |
(or company--multi-min-prefix 0))) |
1389 |
(setq found t |
1390 |
company--multi-uncached-backends |
1391 |
(delete backend |
1392 |
company--multi-uncached-backends)))) |
1393 |
found)))) |
1394 |
t) |
1395 |
((or `ignore-case `no-cache `require-match) |
1396 |
(let (value) |
1397 |
(cl-dolist (backend backends) |
1398 |
(when (setq value (company--force-sync |
1399 |
backend (cons command args) backend)) |
1400 |
(when (and (eq command 'ignore-case) |
1401 |
(eq value 'keep-prefix)) |
1402 |
(setq value t)) |
1403 |
(cl-return value))))) |
1404 |
(`prefix (company--multi-prefix backends)) |
1405 |
(`adjust-boundaries |
1406 |
(let ((arg (car args))) |
1407 |
(when (> (length arg) 0) |
1408 |
(let* ((backend (or (get-text-property 0 'company-backend arg) |
1409 |
(car backends))) |
1410 |
(entity (company--force-sync backend '(prefix) backend)) |
1411 |
(prefix (company--prefix-str entity)) |
1412 |
(suffix (company--suffix-str entity))) |
1413 |
(setq args (list arg prefix suffix)) |
1414 |
(or |
1415 |
(apply backend command args) |
1416 |
(cons prefix suffix)))))) |
1417 |
(`expand-common |
1418 |
(apply #'company--multi-expand-common |
1419 |
backends |
1420 |
(or company--multi-min-prefix 0) |
1421 |
args)) |
1422 |
(_ |
1423 |
(let ((arg (car args))) |
1424 |
(when (> (length arg) 0) |
1425 |
(let ((backend (or (get-text-property 0 'company-backend arg) |
1426 |
(car backends)))) |
1427 |
(apply backend command args)))))))) |
1428 |
|
1429 |
(defun company--multi-prefix (backends) |
1430 |
(let* ((backends-after-with (cdr (member :with backends))) |
1431 |
prefix suffix len) |
1432 |
|
1433 |
(dolist (backend backends) |
1434 |
(let* ((entity (and |
1435 |
(not (keywordp backend)) |
1436 |
(company--force-sync backend '(prefix) backend))) |
1437 |
(new-len (company--prefix-len entity))) |
1438 |
(when (stringp (company--prefix-str entity)) |
1439 |
(or (not backends-after-with) |
1440 |
(unless (memq backend backends-after-with) |
1441 |
(setq backends-after-with nil))) |
1442 |
(when (or |
1443 |
(null prefix) |
1444 |
(> (length (company--prefix-str entity)) |
1445 |
(length prefix))) |
1446 |
(setq prefix (company--prefix-str entity))) |
1447 |
(when (> (length (company--suffix-str entity)) |
1448 |
(length suffix)) |
1449 |
(setq suffix (company--suffix-str entity))) |
1450 |
(when (or (eq t new-len) |
1451 |
(and new-len |
1452 |
(not (eq t len)) |
1453 |
(or (not len) (> new-len len)))) |
1454 |
(setq len new-len))))) |
1455 |
(when (and prefix |
1456 |
(not backends-after-with)) |
1457 |
(list prefix suffix len)))) |
1458 |
|
1459 |
(defun company--multi-expand-common (backends min-length prefix suffix) |
1460 |
(let ((tuples |
1461 |
(cl-loop for backend in backends |
1462 |
for bp = (let ((company-backend backend)) |
1463 |
(company-call-backend 'prefix)) |
1464 |
for expansion = |
1465 |
(when (company--good-prefix-p bp min-length) |
1466 |
(let ((inhibit-redisplay t) |
1467 |
(company-backend backend)) |
1468 |
(company--expand-common (company--prefix-str bp) |
1469 |
(company--suffix-str bp)))) |
1470 |
when (consp expansion) |
1471 |
collect |
1472 |
(list backend bp expansion))) |
1473 |
replacements) |
1474 |
(dolist (tuple tuples) |
1475 |
(cl-assert (string-suffix-p (company--prefix-str (nth 1 tuple)) |
1476 |
prefix)) |
1477 |
(cl-assert (string-prefix-p (company--suffix-str (nth 1 tuple)) |
1478 |
suffix))) |
1479 |
;; We try to find the smallest possible edit for each backend's expansion |
1480 |
;; (minimum prefix and suffix, beyond which the area is unchanged). |
1481 |
(setq replacements |
1482 |
(mapcar |
1483 |
(lambda (tuple) |
1484 |
(let* ((backend-prefix (company--prefix-str (nth 1 tuple))) |
1485 |
(backend-suffix (company--suffix-str (nth 1 tuple))) |
1486 |
(bplen (length backend-prefix)) |
1487 |
(bslen (length backend-suffix)) |
1488 |
(beg 0) |
1489 |
(end 0) |
1490 |
(rep-suffix-len (length (cdr (nth 2 tuple)))) |
1491 |
(max-beg (min bplen (length (car (nth 2 tuple))))) |
1492 |
(max-end (min bslen rep-suffix-len))) |
1493 |
(while (and (< beg max-beg) |
1494 |
(= (aref backend-prefix beg) |
1495 |
(aref (car (nth 2 tuple)) beg))) |
1496 |
(cl-incf beg)) |
1497 |
(while (and (< end max-end) |
1498 |
(= (aref suffix (- bslen end 1)) |
1499 |
(aref (cdr (nth 2 tuple)) |
1500 |
(- rep-suffix-len end 1)))) |
1501 |
(cl-incf end)) |
1502 |
(list (- bplen beg) |
1503 |
(substring (car (nth 2 tuple)) beg) |
1504 |
(- bslen end) |
1505 |
(substring (cdr (nth 2 tuple)) 0 (- rep-suffix-len end)) |
1506 |
(nth 0 tuple)))) |
1507 |
tuples)) |
1508 |
(setq replacements (sort replacements |
1509 |
(lambda (t1 t2) (< (- (length (nth 1 t1)) (nth 0 t1)) |
1510 |
(- (length (nth 1 t2)) (nth 0 t2)))))) |
1511 |
(or |
1512 |
(let ((choice (car replacements))) |
1513 |
;; See if every replacement is similar enough to the one we selected: |
1514 |
;; same suffix and beg/end and a prefix that starts with the proposed. |
1515 |
;; |
1516 |
;; More advanced checks seem possible, but with some backends reacting to |
1517 |
;; buffer contents (not just string arguments) it seems we'd need to |
1518 |
;; change the buffer contents first, then fetch `candidates' for each, |
1519 |
;; and revert at the end. Might be error-prone. |
1520 |
(and |
1521 |
choice |
1522 |
(cl-every |
1523 |
(lambda (replacement) |
1524 |
(and |
1525 |
(= (car replacement) (car choice)) |
1526 |
(= (nth 2 replacement) (nth 2 choice)) |
1527 |
(equal (nth 3 replacement) (nth 3 choice)) |
1528 |
(string-prefix-p (nth 1 choice) (nth 1 replacement)))) |
1529 |
(cdr replacements)) |
1530 |
;; Proposed edit applied to the group's prefix and suffix. |
1531 |
(cons (concat (substring prefix 0 (- (length prefix) (nth 0 choice))) |
1532 |
(nth 1 choice)) |
1533 |
(concat (nth 3 choice) |
1534 |
(substring suffix (nth 2 choice)))))) |
1535 |
(and (null replacements) 'no-match) |
1536 |
;; Didn't find anything suitable - return entity parts unchanged. |
1537 |
(cons prefix suffix)))) |
1538 |
|
1539 |
(defun company--multi-backend-adapter-candidates (backends min-length separate) |
1540 |
(let* (backend-prefix suffix |
1541 |
(pairs (cl-loop for backend in backends |
1542 |
when (let ((bp (let ((company-backend backend)) |
1543 |
(company-call-backend 'prefix)))) |
1544 |
;; One might override min-length, another not. |
1545 |
(if (company--good-prefix-p bp min-length) |
1546 |
(setq backend-prefix (company--prefix-str bp) |
1547 |
suffix (company--suffix-str bp)) |
1548 |
(push backend company--multi-uncached-backends) |
1549 |
nil)) |
1550 |
collect (cons (funcall backend 'candidates backend-prefix suffix) |
1551 |
(company--multi-candidates-mapper |
1552 |
backend |
1553 |
separate |
1554 |
;; Small perf optimization: don't tag the |
1555 |
;; candidates received from the first |
1556 |
;; backend in the group. |
1557 |
(not (eq backend (car backends)))))))) |
1558 |
(company--merge-async pairs (lambda (values) (apply #'append values))))) |
1559 |
|
1560 |
(defun company--multi-candidates-mapper (backend separate tag) |
1561 |
(lambda (candidates) |
1562 |
(when separate |
1563 |
(let ((company-backend backend)) |
1564 |
(setq candidates |
1565 |
(company--preprocess-candidates candidates)))) |
1566 |
(when tag |
1567 |
(setq candidates |
1568 |
(mapcar |
1569 |
(lambda (str) |
1570 |
(propertize str 'company-backend backend)) |
1571 |
candidates))) |
1572 |
candidates)) |
1573 |
|
1574 |
(defun company--merge-async (pairs merger) |
1575 |
(let ((async (cl-loop for pair in pairs |
1576 |
thereis |
1577 |
(eq :async (car-safe (car pair)))))) |
1578 |
(if (not async) |
1579 |
(funcall merger (cl-loop for (val . mapper) in pairs |
1580 |
collect (funcall mapper val))) |
1581 |
(cons |
1582 |
:async |
1583 |
(lambda (callback) |
1584 |
(let* (lst |
1585 |
(pending (mapcar #'car pairs)) |
1586 |
(finisher (lambda () |
1587 |
(unless pending |
1588 |
(funcall callback |
1589 |
(funcall merger |
1590 |
(nreverse lst))))))) |
1591 |
(dolist (pair pairs) |
1592 |
(push nil lst) |
1593 |
(let* ((cell lst) |
1594 |
(val (car pair)) |
1595 |
(mapper (cdr pair)) |
1596 |
(this-finisher (lambda (res) |
1597 |
(setq pending (delq val pending)) |
1598 |
(setcar cell (funcall mapper res)) |
1599 |
(funcall-interactively finisher)))) |
1600 |
(if (not (eq :async (car-safe val))) |
1601 |
(funcall this-finisher val) |
1602 |
(let ((fetcher (cdr val))) |
1603 |
(funcall fetcher this-finisher))))))))))) |
1604 |
|
1605 |
(defun company--prefix-str (entity) |
1606 |
(or (car-safe entity) entity)) |
1607 |
|
1608 |
(defun company--prefix-len (entity) |
1609 |
(let ((cdr (cdr-safe entity)) |
1610 |
override) |
1611 |
(cond |
1612 |
((consp cdr) |
1613 |
(setq override (cadr cdr))) |
1614 |
((or (numberp cdr) (eq t cdr)) |
1615 |
(setq override cdr))) |
1616 |
(or override |
1617 |
(length |
1618 |
(if (stringp entity) |
1619 |
entity |
1620 |
(car entity)))))) |
1621 |
|
1622 |
(defun company--suffix-str (entity) |
1623 |
(if (stringp (car-safe (cdr-safe entity))) |
1624 |
(car-safe (cdr-safe entity)) |
1625 |
"")) |
1626 |
|
1627 |
;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1628 |
|
1629 |
(defvar-local company-prefix nil) |
1630 |
|
1631 |
(defvar-local company-suffix nil) |
1632 |
|
1633 |
(defvar-local company-candidates nil) |
1634 |
|
1635 |
(defvar-local company-candidates-length nil) |
1636 |
|
1637 |
(defvar-local company-candidates-cache nil) |
1638 |
|
1639 |
(defvar-local company-candidates-predicate nil) |
1640 |
|
1641 |
(defvar-local company-common nil) |
1642 |
|
1643 |
(defvar company-selection-default 0 |
1644 |
"The default value for `company-selection'.") |
1645 |
(defvar-local company-selection company-selection-default) |
1646 |
|
1647 |
(defvar-local company-selection-changed nil) |
1648 |
|
1649 |
(defvar-local company--manual-action nil |
1650 |
"Non-nil if manual completion was performed by the user.") |
1651 |
|
1652 |
(defvar-local company--manual-now nil |
1653 |
"Non-nil if manual completion is being performed now.") |
1654 |
|
1655 |
(defvar-local company--manual-prefix nil) |
1656 |
|
1657 |
(defvar-local company--point-max nil) |
1658 |
|
1659 |
(defvar-local company-point nil) |
1660 |
|
1661 |
(defvar-local company-valid-point nil) |
1662 |
|
1663 |
(defvar company-timer nil) |
1664 |
(defvar company-tooltip-timer nil) |
1665 |
|
1666 |
(defun company-strip-prefix (str prefix) |
1667 |
(substring str (length prefix))) |
1668 |
|
1669 |
(defun company--insert-candidate (candidate prefix) |
1670 |
(when (> (length candidate) 0) |
1671 |
(setq candidate (substring-no-properties candidate)) |
1672 |
;; XXX: Return value we check here is subject to change. |
1673 |
(if (eq (company-call-backend 'ignore-case) 'keep-prefix) |
1674 |
(insert (company-strip-prefix candidate prefix)) |
1675 |
(unless (equal prefix candidate) |
1676 |
(delete-region (- (point) (length prefix)) (point)) |
1677 |
(insert candidate))))) |
1678 |
|
1679 |
(defmacro company-with-candidate-inserted (candidate &rest body) |
1680 |
"Evaluate BODY with CANDIDATE temporarily inserted. |
1681 |
This is a tool for backends that need candidates inserted before they |
1682 |
can retrieve meta-data for them." |
1683 |
(declare (indent 1)) |
1684 |
`(let ((inhibit-modification-hooks t) |
1685 |
(inhibit-point-motion-hooks t) |
1686 |
(modified-p (buffer-modified-p))) |
1687 |
(company--insert-candidate ,candidate company-prefix) |
1688 |
(unwind-protect |
1689 |
(progn ,@body) |
1690 |
(delete-region company-point (point)) |
1691 |
(set-buffer-modified-p modified-p)))) |
1692 |
|
1693 |
(defun company-explicit-action-p () |
1694 |
"Return whether explicit completion action was taken by the user." |
1695 |
(or company--manual-action |
1696 |
company-selection-changed)) |
1697 |
|
1698 |
(defun company-reformat (candidate) |
1699 |
;; company-ispell needs this, because the results are always lower-case |
1700 |
;; It's mory efficient to fix it only when they are displayed. |
1701 |
;; FIXME: Adopt the current text's capitalization instead? |
1702 |
(if (eq (company-call-backend 'ignore-case) 'keep-prefix) |
1703 |
(concat company-prefix (substring candidate (length company-prefix))) |
1704 |
candidate)) |
1705 |
|
1706 |
(defun company--should-complete () |
1707 |
(and (eq company-idle-delay 'now) |
1708 |
(not (or buffer-read-only |
1709 |
overriding-local-map)) |
1710 |
;; Check if in the middle of entering a key combination. |
1711 |
(or (equal (this-command-keys-vector) []) |
1712 |
(not (keymapp (key-binding (this-command-keys-vector))))) |
1713 |
(not (and transient-mark-mode mark-active)))) |
1714 |
|
1715 |
(defun company--should-continue () |
1716 |
(or (eq t company-begin-commands) |
1717 |
(eq t company-continue-commands) |
1718 |
(if (eq 'not (car company-continue-commands)) |
1719 |
(not (memq this-command (cdr company-continue-commands))) |
1720 |
(or (memq this-command company-begin-commands) |
1721 |
(memq this-command company-continue-commands) |
1722 |
(and (symbolp this-command) |
1723 |
(string-match-p "\\`company-" (symbol-name this-command))))))) |
1724 |
|
1725 |
(defvar company-auto-update-doc nil |
1726 |
"If non-nil, update the documentation buffer on each selection change. |
1727 |
To toggle the value of this variable, call `company-show-doc-buffer' with a |
1728 |
prefix argument.") |
1729 |
|
1730 |
(defun company-call-frontends (command) |
1731 |
(cl-loop for frontend in company-frontends collect |
1732 |
(condition-case-unless-debug err |
1733 |
(funcall frontend command) |
1734 |
(error (error "Company: frontend %s error \"%s\" on command %s" |
1735 |
frontend (error-message-string err) command))))) |
1736 |
|
1737 |
(defun company-set-selection (selection &optional force-update) |
1738 |
"Set SELECTION for company candidates. |
1739 |
This will update `company-selection' and related variable. |
1740 |
Only update when the current selection is changed, but optionally always |
1741 |
update if FORCE-UPDATE." |
1742 |
(when selection |
1743 |
(let* ((offset (if company-selection-default 0 1)) |
1744 |
(company-candidates-length |
1745 |
(+ company-candidates-length offset))) |
1746 |
(setq selection (+ selection offset)) |
1747 |
(setq selection |
1748 |
(if company-selection-wrap-around |
1749 |
(mod selection company-candidates-length) |
1750 |
(max 0 (min (1- company-candidates-length) selection)))) |
1751 |
(setq selection (unless (< selection offset) |
1752 |
(- selection offset))))) |
1753 |
(when (or force-update (not (equal selection company-selection))) |
1754 |
(setq company-selection selection |
1755 |
company-selection-changed t) |
1756 |
(company-call-frontends 'update))) |
1757 |
|
1758 |
(defun company--group-lighter (candidate base) |
1759 |
(let ((backend (or (get-text-property 0 'company-backend candidate) |
1760 |
(cl-some (lambda (x) (and (not (keywordp x)) x)) |
1761 |
company-backend)))) |
1762 |
(when (and backend (symbolp backend)) |
1763 |
(let ((name (replace-regexp-in-string "company-\\|-company" "" |
1764 |
(symbol-name backend)))) |
1765 |
(format "%s-<%s>" base name))))) |
1766 |
|
1767 |
(defun company-update-candidates (candidates) |
1768 |
(setq company-candidates-length (length candidates) |
1769 |
company-valid-point company-point) |
1770 |
(if company-selection-changed |
1771 |
;; Try to restore the selection |
1772 |
(let ((selected (and company-selection |
1773 |
(nth company-selection company-candidates)))) |
1774 |
(setq company-candidates candidates) |
1775 |
(when selected |
1776 |
(setq company-selection 0) |
1777 |
(catch 'found |
1778 |
(while candidates |
1779 |
(let ((candidate (pop candidates))) |
1780 |
(when (and (string= candidate selected) |
1781 |
(equal (company-call-backend 'annotation candidate) |
1782 |
(company-call-backend 'annotation selected))) |
1783 |
(throw 'found t))) |
1784 |
(cl-incf company-selection)) |
1785 |
(setq company-selection company-selection-default |
1786 |
company-selection-changed nil)))) |
1787 |
(setq company-selection company-selection-default |
1788 |
company-candidates candidates)) |
1789 |
;; Calculate common. |
1790 |
(let ((completion-ignore-case (company-call-backend 'ignore-case))) |
1791 |
;; We want to support non-prefix completion, so filtering is the |
1792 |
;; responsibility of each respective backend, not ours. |
1793 |
;; On the other hand, we don't want to replace non-prefix input in |
1794 |
;; `company-complete-common', unless there's only one candidate. |
1795 |
(setq company-common |
1796 |
(if (cdr company-candidates) |
1797 |
(let ((common (try-completion "" company-candidates))) |
1798 |
(and (stringp common) |
1799 |
common)) |
1800 |
(car company-candidates))))) |
1801 |
|
1802 |
(defun company-calculate-candidates (prefix ignore-case suffix) |
1803 |
(let ((candidates (cdr (assoc prefix company-candidates-cache)))) |
1804 |
(or candidates |
1805 |
(when company-candidates-cache |
1806 |
(let ((len (length prefix)) |
1807 |
(completion-ignore-case ignore-case) |
1808 |
prev) |
1809 |
(cl-dotimes (i (1+ len)) |
1810 |
(when (setq prev (cdr (assoc (substring prefix 0 (- len i)) |
1811 |
company-candidates-cache))) |
1812 |
(setq candidates (all-completions prefix prev)) |
1813 |
(cl-return t))))) |
1814 |
;; No cache match, call the backend. |
1815 |
(let ((refresh-timer (run-with-timer company-async-redisplay-delay |
1816 |
nil |
1817 |
#'company--sneaky-refresh |
1818 |
prefix suffix))) |
1819 |
(unwind-protect |
1820 |
(setq candidates (company--preprocess-candidates |
1821 |
(company--fetch-candidates prefix suffix))) |
1822 |
;; If the backend is synchronous, no chance for the timer to run. |
1823 |
(cancel-timer refresh-timer)) |
1824 |
;; Save in cache. |
1825 |
(push (cons prefix candidates) company-candidates-cache))) |
1826 |
;; Only now apply the predicate and transformers. |
1827 |
(company--postprocess-candidates candidates))) |
1828 |
|
1829 |
(defun company--unique-match-p (candidates prefix suffix ignore-case) |
1830 |
(and candidates |
1831 |
(not (cdr candidates)) |
1832 |
(eq t (compare-strings (car candidates) nil nil |
1833 |
(concat prefix suffix) nil nil ignore-case)) |
1834 |
(not (eq (company-call-backend 'kind (car candidates)) |
1835 |
'snippet)))) |
1836 |
|
1837 |
(defun company--fetch-candidates (prefix suffix) |
1838 |
(let* ((non-essential (not company--manual-now)) |
1839 |
(inhibit-redisplay t) |
1840 |
;; At least we need "fresh" completions if the current command will |
1841 |
;; rely on the result (e.g. insert common, or finish completion). |
1842 |
(c (if company--manual-now |
1843 |
(company-call-backend 'candidates prefix suffix) |
1844 |
(company-call-backend-raw 'candidates prefix suffix)))) |
1845 |
(if (not (eq (car c) :async)) |
1846 |
c |
1847 |
(let ((res 'none)) |
1848 |
(funcall |
1849 |
(cdr c) |
1850 |
(lambda (candidates) |
1851 |
(when (eq res 'none) |
1852 |
(push 'company-foo unread-command-events)) |
1853 |
(setq res candidates))) |
1854 |
(if (company--flyspell-workaround-p) |
1855 |
(while (and (eq res 'none) |
1856 |
(not (input-pending-p))) |
1857 |
(sleep-for company-async-wait)) |
1858 |
(while (and (eq res 'none) |
1859 |
(sit-for 0.5 t)))) |
1860 |
(while (member (car unread-command-events) |
1861 |
'(company-foo (t . company-foo))) |
1862 |
(pop unread-command-events)) |
1863 |
(let ((res-was res)) |
1864 |
(setq res 'exited) |
1865 |
(if (eq 'none res-was) |
1866 |
(throw 'interrupted 'new-input) |
1867 |
res-was)))))) |
1868 |
|
1869 |
(defun company--sneaky-refresh (prefix suffix) |
1870 |
(when company-candidates |
1871 |
(let* ((company-prefix prefix) |
1872 |
(company-suffix suffix)) |
1873 |
(and prefix |
1874 |
(company-call-frontends 'unhide)))) |
1875 |
(let (inhibit-redisplay) |
1876 |
(redisplay)) |
1877 |
(when company-candidates (company-call-frontends 'pre-command))) |
1878 |
|
1879 |
(defun company--flyspell-workaround-p () |
1880 |
;; https://debbugs.gnu.org/23980 |
1881 |
(and (bound-and-true-p flyspell-mode) |
1882 |
(version< emacs-version "27"))) |
1883 |
|
1884 |
(defun company--preprocess-candidates (candidates) |
1885 |
(cl-assert (cl-every #'stringp candidates)) |
1886 |
(unless (company-call-backend 'sorted) |
1887 |
(setq candidates (sort candidates 'string<))) |
1888 |
(when (company-call-backend 'duplicates) |
1889 |
(company--strip-duplicates candidates)) |
1890 |
candidates) |
1891 |
|
1892 |
(defun company--postprocess-candidates (candidates) |
1893 |
(when (or company-candidates-predicate company-transformers) |
1894 |
(setq candidates (copy-sequence candidates))) |
1895 |
(when company-candidates-predicate |
1896 |
(setq candidates (cl-delete-if-not company-candidates-predicate candidates))) |
1897 |
(company--transform-candidates candidates)) |
1898 |
|
1899 |
(defun company--strip-duplicates (candidates) |
1900 |
(let ((c2 candidates) |
1901 |
(extras 'unk)) |
1902 |
(while c2 |
1903 |
(setcdr c2 |
1904 |
(let ((str (pop c2))) |
1905 |
(while (let ((str2 (car c2))) |
1906 |
(if (not (equal str str2)) |
1907 |
(progn |
1908 |
(setq extras 'unk) |
1909 |
nil) |
1910 |
(when (eq extras 'unk) |
1911 |
(setq extras (list (cons (company-call-backend |
1912 |
'annotation str) |
1913 |
(company-call-backend |
1914 |
'kind str))))) |
1915 |
(let ((extra2 (cons (company-call-backend |
1916 |
'annotation str2) |
1917 |
(company-call-backend |
1918 |
'kind str2)))) |
1919 |
(if (member extra2 extras) |
1920 |
t |
1921 |
(push extra2 extras) |
1922 |
nil)))) |
1923 |
(pop c2)) |
1924 |
c2))))) |
1925 |
|
1926 |
(defun company--transform-candidates (candidates) |
1927 |
(let ((c candidates)) |
1928 |
(dolist (tr company-transformers) |
1929 |
(setq c (funcall tr c))) |
1930 |
c)) |
1931 |
|
1932 |
(defcustom company-occurrence-weight-function |
1933 |
#'company-occurrence-prefer-closest-above |
1934 |
"Function to weigh matches in `company-sort-by-occurrence'. |
1935 |
It's called with three arguments: cursor position, the beginning and the |
1936 |
end of the match." |
1937 |
:type '(choice |
1938 |
(const :tag "First above point, then below point" |
1939 |
company-occurrence-prefer-closest-above) |
1940 |
(const :tag "Prefer closest in any direction" |
1941 |
company-occurrence-prefer-any-closest))) |
1942 |
|
1943 |
(defvar company-vscode-icons-mapping |
1944 |
'((array . "symbol-array.svg") |
1945 |
(boolean . "symbol-boolean.svg") |
1946 |
(class . "symbol-class.svg") |
1947 |
(color . "symbol-color.svg") |
1948 |
(constant . "symbol-constant.svg") |
1949 |
(constructor . "symbol-method.svg") |
1950 |
(enum-member . "symbol-enumerator-member.svg") |
1951 |
(enum . "symbol-enumerator.svg") |
1952 |
(event . "symbol-event.svg") |
1953 |
(field . "symbol-field.svg") |
1954 |
(file . "symbol-file.svg") |
1955 |
(folder . "folder.svg") |
1956 |
(interface . "symbol-interface.svg") |
1957 |
(keyword . "symbol-keyword.svg") |
1958 |
(method . "symbol-method.svg") |
1959 |
(function . "symbol-method.svg") |
1960 |
(module . "symbol-namespace.svg") |
1961 |
(numeric . "symbol-numeric.svg") |
1962 |
(operator . "symbol-operator.svg") |
1963 |
(property . "symbol-property.svg") |
1964 |
(reference . "references.svg") |
1965 |
(snippet . "symbol-snippet.svg") |
1966 |
(string . "symbol-string.svg") |
1967 |
(struct . "symbol-structure.svg") |
1968 |
(text . "symbol-key.svg") |
1969 |
(type-parameter . "symbol-parameter.svg") |
1970 |
(unit . "symbol-ruler.svg") |
1971 |
(value . "symbol-enumerator.svg") |
1972 |
(variable . "symbol-variable.svg") |
1973 |
(t . "symbol-misc.svg"))) |
1974 |
|
1975 |
(defconst company-icons-root |
1976 |
(file-name-as-directory |
1977 |
(expand-file-name "icons" |
1978 |
(file-name-directory (or load-file-name buffer-file-name))))) |
1979 |
|
1980 |
(defcustom company-icon-size '(auto-scale . 16) |
1981 |
"Size of icons indicating completion kind in the popup." |
1982 |
:type '(choice (integer :tag "Size in pixels" :value 16) |
1983 |
(cons :tag "Size in pixels, scaled 2x on HiDPI screens" |
1984 |
(const auto-scale) |
1985 |
(integer :value 16)))) |
1986 |
|
1987 |
(defcustom company-icon-margin 2 |
1988 |
"Width of the margin that shows the icons, in characters." |
1989 |
:type 'integer) |
1990 |
|
1991 |
(defun company--render-icons-margin (icon-mapping root-dir candidate selected) |
1992 |
(if-let* ((ws (window-system)) |
1993 |
(candidate candidate) |
1994 |
(kind (company-call-backend 'kind candidate)) |
1995 |
(icon-file (or (alist-get kind icon-mapping) |
1996 |
(alist-get t icon-mapping)))) |
1997 |
(let* ((bkg (face-attribute (if selected |
1998 |
'company-tooltip-selection |
1999 |
'company-tooltip) |
2000 |
:background)) |
2001 |
(dfw (default-font-width)) |
2002 |
(icon-size (cond |
2003 |
((integerp company-icon-size) |
2004 |
company-icon-size) |
2005 |
;; XXX: Also consider smooth scaling, e.g. using |
2006 |
;; (aref (font-info (face-font 'default)) 2) |
2007 |
((and (consp company-icon-size) |
2008 |
(eq 'auto-scale (car company-icon-size))) |
2009 |
(let ((base-size (cdr company-icon-size)) |
2010 |
(dfh (default-font-height))) |
2011 |
(min |
2012 |
(if (>= dfh (* 2 base-size)) |
2013 |
(* 2 base-size) |
2014 |
base-size) |
2015 |
(* company-icon-margin dfw)))))) |
2016 |
(spec (list 'image |
2017 |
:file (expand-file-name icon-file root-dir) |
2018 |
:type 'svg |
2019 |
:width icon-size |
2020 |
:height icon-size |
2021 |
:ascent 'center |
2022 |
;; Transparency requires Emacs 28+. |
2023 |
:background (unless (eq bkg 'unspecified) |
2024 |
bkg))) |
2025 |
(spacer-px-width (- (* company-icon-margin dfw) icon-size))) |
2026 |
(cond |
2027 |
((<= company-icon-margin 2) |
2028 |
(concat |
2029 |
(propertize " " 'display spec) |
2030 |
(propertize (company-space-string (1- company-icon-margin)) |
2031 |
'display `(space . (:width (,spacer-px-width)))))) |
2032 |
(t |
2033 |
(let* ((spacer-left (/ spacer-px-width 2)) |
2034 |
(spacer-right (- spacer-px-width spacer-left))) |
2035 |
(concat |
2036 |
(propertize (company-space-string 1) |
2037 |
'display `(space . (:width (,spacer-left)))) |
2038 |
(propertize " " 'display spec) |
2039 |
(propertize (company-space-string (- company-icon-margin 2)) |
2040 |
'display `(space . (:width (,spacer-right))))))))) |
2041 |
nil)) |
2042 |
|
2043 |
(defun company-vscode-dark-icons-margin (candidate selected) |
2044 |
"Margin function which returns icons from vscode's dark theme." |
2045 |
(company--render-icons-margin company-vscode-icons-mapping |
2046 |
(expand-file-name "vscode-dark" company-icons-root) |
2047 |
candidate |
2048 |
selected)) |
2049 |
|
2050 |
(defun company-vscode-light-icons-margin (candidate selected) |
2051 |
"Margin function which returns icons from vscode's light theme." |
2052 |
(company--render-icons-margin company-vscode-icons-mapping |
2053 |
(expand-file-name "vscode-light" company-icons-root) |
2054 |
candidate |
2055 |
selected)) |
2056 |
|
2057 |
(defcustom company-text-icons-mapping |
2058 |
'((array "a" font-lock-type-face) |
2059 |
(boolean "b" font-lock-builtin-face) |
2060 |
(class "c" font-lock-type-face) |
2061 |
(color "#" success) |
2062 |
(constant "c" font-lock-constant-face) |
2063 |
(constructor "c" font-lock-function-name-face) |
2064 |
(enum-member "e" font-lock-builtin-face) |
2065 |
(enum "e" font-lock-builtin-face) |
2066 |
(field "f" font-lock-variable-name-face) |
2067 |
(file "f" font-lock-string-face) |
2068 |
(folder "d" font-lock-doc-face) |
2069 |
(interface "i" font-lock-type-face) |
2070 |
(keyword "k" font-lock-keyword-face) |
2071 |
(method "m" font-lock-function-name-face) |
2072 |
(function "f" font-lock-function-name-face) |
2073 |
(module "{" font-lock-type-face) |
2074 |
(numeric "n" font-lock-builtin-face) |
2075 |
(operator "o" font-lock-comment-delimiter-face) |
2076 |
(property "p" font-lock-variable-name-face) |
2077 |
(reference "r" font-lock-doc-face) |
2078 |
(snippet "S" font-lock-string-face) |
2079 |
(string "s" font-lock-string-face) |
2080 |
(struct "%" font-lock-variable-name-face) |
2081 |
(text "w" shadow) |
2082 |
(type-parameter "p" font-lock-type-face) |
2083 |
(unit "u" shadow) |
2084 |
(value "v" font-lock-builtin-face) |
2085 |
(variable "v" font-lock-variable-name-face) |
2086 |
(t "." shadow)) |
2087 |
"Mapping of the text icons. |
2088 |
The format should be an alist of (KIND . CONF) where CONF is a list of the |
2089 |
form (ICON FG BG) which is used to propertize the icon to be shown for a |
2090 |
candidate of kind KIND. FG can either be color string or a face from which |
2091 |
we can get a color string (using the :foreground face-property). BG must be |
2092 |
of the same form as FG or a cons cell of (BG . BG-WHEN-SELECTED) which each |
2093 |
should be of the same form as FG. |
2094 |
|
2095 |
The only mandatory element in CONF is ICON, you can omit both the FG and BG |
2096 |
fields without issue. |
2097 |
|
2098 |
When BG is omitted and `company-text-icons-add-background' is non-nil, a BG |
2099 |
color is generated using a gradient between the active tooltip color and |
2100 |
the FG color." |
2101 |
:type '(repeat sexp)) |
2102 |
|
2103 |
(defcustom company-text-face-extra-attributes '(:weight bold) |
2104 |
"Additional attributes to add to text/dot icons faces. |
2105 |
If non-nil, an anonymous face is generated. |
2106 |
|
2107 |
Affects `company-text-icons-margin' and `company-dot-icons-margin'." |
2108 |
:type '(plist :tag "Face property list")) |
2109 |
|
2110 |
(defcustom company-text-icons-format " %s " |
2111 |
"Format string for printing the text icons." |
2112 |
:type 'string) |
2113 |
|
2114 |
(defcustom company-text-icons-add-background nil |
2115 |
"Generate a background color for text/dot icons when none is given. |
2116 |
See `company-text-icons-mapping'." |
2117 |
:type 'boolean) |
2118 |
|
2119 |
(defun company-text-icons-margin (candidate selected) |
2120 |
"Margin function which returns unicode icons." |
2121 |
(when-let* ((candidate candidate) |
2122 |
(kind (company-call-backend 'kind candidate)) |
2123 |
(conf (or (alist-get kind company-text-icons-mapping) |
2124 |
(alist-get t company-text-icons-mapping)))) |
2125 |
(cl-destructuring-bind (icon &optional fg bg) conf |
2126 |
(propertize |
2127 |
(format company-text-icons-format icon) |
2128 |
'face |
2129 |
(company-text-icons--face fg bg selected))))) |
2130 |
|
2131 |
(declare-function color-rgb-to-hex "color") |
2132 |
(declare-function color-gradient "color") |
2133 |
|
2134 |
(defun company-text-icons--extract-property (face property) |
2135 |
"Try to extract PROPERTY from FACE. |
2136 |
If FACE isn't a valid face return FACE as is. If FACE doesn't have |
2137 |
PROPERTY return nil." |
2138 |
(if (facep face) |
2139 |
(let ((value (face-attribute face property))) |
2140 |
(unless (eq value 'unspecified) |
2141 |
value)) |
2142 |
face)) |
2143 |
|
2144 |
(defun company-text-icons--face (fg bg selected) |
2145 |
(let ((fg-color (company-text-icons--extract-property fg :foreground))) |
2146 |
`(,@company-text-face-extra-attributes |
2147 |
,@(and fg-color |
2148 |
(list :foreground fg-color)) |
2149 |
,@(let* ((bg-is-cons (consp bg)) |
2150 |
(bg (if bg-is-cons (if selected (cdr bg) (car bg)) bg)) |
2151 |
(bg-color (company-text-icons--extract-property bg :background)) |
2152 |
(tooltip-bg-color (company-text-icons--extract-property |
2153 |
(if selected |
2154 |
'company-tooltip-selection |
2155 |
'company-tooltip) |
2156 |
:background))) |
2157 |
(cond |
2158 |
((and company-text-icons-add-background selected |
2159 |
(not bg-is-cons) bg-color tooltip-bg-color) |
2160 |
;; Adjust the coloring of the background when *selected* but user hasn't |
2161 |
;; specified an alternate background color for selected item icons. |
2162 |
(list :background |
2163 |
(apply #'color-rgb-to-hex |
2164 |
(nth 0 (color-gradient (color-name-to-rgb tooltip-bg-color) |
2165 |
(color-name-to-rgb bg-color) |
2166 |
2))))) |
2167 |
(bg |
2168 |
;; When background is configured we use it as is, even if it doesn't |
2169 |
;; constrast well with other candidates when selected. |
2170 |
(and bg-color |
2171 |
(list :background bg-color))) |
2172 |
((and company-text-icons-add-background fg-color tooltip-bg-color) |
2173 |
;; Lastly attempt to generate a background from the foreground. |
2174 |
(list :background |
2175 |
(apply #'color-rgb-to-hex |
2176 |
(nth 0 (color-gradient (color-name-to-rgb tooltip-bg-color) |
2177 |
(color-name-to-rgb fg-color) |
2178 |
10)))))))))) |
2179 |
|
2180 |
(defcustom company-dot-icons-format "● " |
2181 |
"Format string for `company-dot-icons-margin'." |
2182 |
:type 'string) |
2183 |
|
2184 |
(defun company-dot-icons-margin (candidate selected) |
2185 |
"Margin function that uses a colored dot to display completion kind." |
2186 |
(when-let* ((kind (company-call-backend 'kind candidate)) |
2187 |
(conf (or (assoc-default kind company-text-icons-mapping) |
2188 |
(assoc-default t company-text-icons-mapping)))) |
2189 |
(cl-destructuring-bind (_icon &optional fg bg) conf |
2190 |
(propertize company-dot-icons-format |
2191 |
'face |
2192 |
(company-text-icons--face fg bg selected))))) |
2193 |
|
2194 |
(defun company-detect-icons-margin (candidate selected) |
2195 |
"Margin function which picks the appropriate icon set automatically." |
2196 |
(if (and (display-graphic-p) |
2197 |
(image-type-available-p 'svg)) |
2198 |
(cl-case (frame-parameter nil 'background-mode) |
2199 |
(light (company-vscode-light-icons-margin candidate selected)) |
2200 |
(t (company-vscode-dark-icons-margin candidate selected))) |
2201 |
(company-text-icons-margin candidate selected))) |
2202 |
|
2203 |
(defcustom company-format-margin-function #'company-detect-icons-margin |
2204 |
"Function to format the margin. |
2205 |
It accepts 2 params `candidate' and `selected' and can be used for |
2206 |
inserting prefix/image before the completion items. Typically, the |
2207 |
functions call the backends with `kind' and then insert the appropriate |
2208 |
image for the returned kind image. Function is called with (nil nil) to get |
2209 |
the default margin." |
2210 |
:type '(choice |
2211 |
(const :tag "Disabled" nil) |
2212 |
(const :tag "Detect icons theme base on conditions" company-detect-icons-margin) |
2213 |
(const :tag "Text characters as icons" company-text-icons-margin) |
2214 |
(const :tag "Colored dots as icons" company-dot-icons-margin) |
2215 |
(const :tag "VScode dark icons theme" company-vscode-dark-icons-margin) |
2216 |
(const :tag "VScode light icons theme" company-vscode-light-icons-margin) |
2217 |
(function :tag "Custom icon function."))) |
2218 |
|
2219 |
(defun company-occurrence-prefer-closest-above (pos match-beg match-end) |
2220 |
"Give priority to the matches above point, then those below point." |
2221 |
(if (< match-beg pos) |
2222 |
(- pos match-end) |
2223 |
(- match-beg (window-start)))) |
2224 |
|
2225 |
(defun company-occurrence-prefer-any-closest (pos _match-beg match-end) |
2226 |
"Give priority to the matches closest to the point." |
2227 |
(abs (- pos match-end))) |
2228 |
|
2229 |
(defun company-sort-by-occurrence (candidates) |
2230 |
"Sort CANDIDATES according to their occurrences. |
2231 |
Searches for each in the currently visible part of the current buffer and |
2232 |
prioritizes the matches according to `company-occurrence-weight-function'. |
2233 |
The rest of the list is appended unchanged. |
2234 |
Keywords and function definition names are ignored." |
2235 |
(let* ((w-start (window-start)) |
2236 |
(w-end (window-end)) |
2237 |
(start-point (point)) |
2238 |
occurs |
2239 |
(noccurs |
2240 |
(save-excursion |
2241 |
(cl-delete-if |
2242 |
(lambda (candidate) |
2243 |
(goto-char w-start) |
2244 |
(when (and (not (string-empty-p candidate)) |
2245 |
(search-forward candidate w-end t) |
2246 |
;; ^^^ optimize for large lists where most elements |
2247 |
;; won't have a match. |
2248 |
(catch 'done |
2249 |
(goto-char (1- start-point)) |
2250 |
(while (search-backward candidate w-start t) |
2251 |
(when (save-match-data |
2252 |
(company--occurrence-predicate)) |
2253 |
(throw 'done t))) |
2254 |
(goto-char start-point) |
2255 |
(while (search-forward candidate w-end t) |
2256 |
(when (save-match-data |
2257 |
(company--occurrence-predicate)) |
2258 |
(throw 'done t))))) |
2259 |
(push |
2260 |
(cons candidate |
2261 |
(funcall company-occurrence-weight-function |
2262 |
start-point |
2263 |
(match-beginning 0) |
2264 |
(match-end 0))) |
2265 |
occurs) |
2266 |
t)) |
2267 |
candidates)))) |
2268 |
(nconc |
2269 |
(mapcar #'car (sort occurs (lambda (e1 e2) (<= (cdr e1) (cdr e2))))) |
2270 |
noccurs))) |
2271 |
|
2272 |
(defun company--occurrence-predicate () |
2273 |
(defvar comint-last-prompt) |
2274 |
(let ((beg (match-beginning 0)) |
2275 |
(end (match-end 0)) |
2276 |
(comint-last-prompt (bound-and-true-p comint-last-prompt))) |
2277 |
(save-excursion |
2278 |
(goto-char end) |
2279 |
;; Workaround for python-shell-completion-at-point's behavior: |
2280 |
;; https://github.com/company-mode/company-mode/issues/759 |
2281 |
;; https://github.com/company-mode/company-mode/issues/549 |
2282 |
(when (derived-mode-p 'inferior-python-mode) |
2283 |
(let ((lbp (line-beginning-position))) |
2284 |
(setq comint-last-prompt (cons lbp lbp)))) |
2285 |
(and (not (memq (get-text-property (1- (point)) 'face) |
2286 |
'(font-lock-function-name-face |
2287 |
font-lock-keyword-face))) |
2288 |
(let ((prefix (company--prefix-str |
2289 |
(company-call-backend 'prefix)))) |
2290 |
(and (stringp prefix) |
2291 |
(= (length prefix) (- end beg)))))))) |
2292 |
|
2293 |
(defun company-sort-by-backend-importance (candidates) |
2294 |
"Sort CANDIDATES as two priority groups. |
2295 |
If `company-backend' is a function, do nothing. If it's a list, move |
2296 |
candidates from backends before keyword `:with' to the front. Candidates |
2297 |
from the rest of the backends in the group, if any, will be left at the end." |
2298 |
(if (functionp company-backend) |
2299 |
candidates |
2300 |
(let ((low-priority (cdr (memq :with company-backend)))) |
2301 |
(if (null low-priority) |
2302 |
candidates |
2303 |
(sort candidates |
2304 |
(lambda (c1 c2) |
2305 |
(and |
2306 |
(let ((b2 (get-text-property 0 'company-backend c2))) |
2307 |
(and b2 (memq b2 low-priority))) |
2308 |
(let ((b1 (get-text-property 0 'company-backend c1))) |
2309 |
(or (not b1) (not (memq b1 low-priority))))))))))) |
2310 |
|
2311 |
(defun company-sort-prefer-same-case-prefix (candidates) |
2312 |
"Prefer CANDIDATES with the exact same prefix. |
2313 |
If a backend returns case insensitive matches, candidates with the an exact |
2314 |
prefix match (same case) will be prioritized." |
2315 |
(cl-loop for candidate in candidates |
2316 |
if (string-prefix-p company-prefix candidate) |
2317 |
collect candidate into same-case |
2318 |
else collect candidate into other-case |
2319 |
finally return (append same-case other-case))) |
2320 |
|
2321 |
(defun company-idle-begin (buf win tick pos) |
2322 |
(and (eq buf (current-buffer)) |
2323 |
(eq win (selected-window)) |
2324 |
(eq tick (buffer-chars-modified-tick)) |
2325 |
(eq pos (point)) |
2326 |
(let ((non-essential t)) |
2327 |
(when (company-auto-begin) |
2328 |
(let ((this-command 'company-idle-begin)) |
2329 |
(company-post-command)))))) |
2330 |
|
2331 |
(defun company-auto-begin () |
2332 |
(and company-mode |
2333 |
(not company-candidates) |
2334 |
(let ((company-idle-delay 'now)) |
2335 |
(condition-case-unless-debug err |
2336 |
(let ((inhibit-quit nil)) |
2337 |
(company--perform) |
2338 |
;; Return non-nil if active. |
2339 |
company-candidates) |
2340 |
(error (message "Company: An error occurred in auto-begin") |
2341 |
(message "%s" (error-message-string err)) |
2342 |
(company-cancel)) |
2343 |
(quit (company-cancel)))))) |
2344 |
|
2345 |
;;;###autoload |
2346 |
(defun company-manual-begin () |
2347 |
"Start the completion interface. |
2348 |
|
2349 |
Unlike `company-complete-selection' or `company-complete', this command |
2350 |
doesn't cause any immediate changes to the buffer text." |
2351 |
(interactive) |
2352 |
(company-assert-enabled) |
2353 |
(setq company--manual-action t) |
2354 |
(unwind-protect |
2355 |
(let ((company-minimum-prefix-length 0) |
2356 |
(company--manual-now t)) |
2357 |
(or (and company-candidates |
2358 |
(= company-valid-point (point))) |
2359 |
(company-auto-begin))) |
2360 |
(unless company-candidates |
2361 |
(setq company--manual-action nil)))) |
2362 |
|
2363 |
(defun company-other-backend (&optional backward) |
2364 |
(interactive (list current-prefix-arg)) |
2365 |
(company-assert-enabled) |
2366 |
(let* ((after (if company-backend |
2367 |
(cdr (member company-backend company-backends)) |
2368 |
company-backends)) |
2369 |
(before (cdr (member company-backend (reverse company-backends)))) |
2370 |
(next (if backward |
2371 |
(append before (reverse after)) |
2372 |
(append after (reverse before))))) |
2373 |
(company-cancel) |
2374 |
(cl-dolist (backend next) |
2375 |
(when (ignore-errors (company-begin-backend backend)) |
2376 |
(cl-return t)))) |
2377 |
(unless company-candidates |
2378 |
(user-error "No other backend"))) |
2379 |
|
2380 |
(defun company-require-match-p () |
2381 |
(let ((backend-value (company-call-backend 'require-match))) |
2382 |
(or (eq backend-value t) |
2383 |
(and (not (eq backend-value 'never)) |
2384 |
(if (functionp company-require-match) |
2385 |
(funcall company-require-match) |
2386 |
(eq company-require-match t)))))) |
2387 |
|
2388 |
(defun company-insertion-on-trigger-p (input) |
2389 |
"Return non-nil if INPUT should trigger insertion. |
2390 |
For more details see `company-insertion-on-trigger' and |
2391 |
`company-insertion-triggers'." |
2392 |
(and (if (functionp company-insertion-on-trigger) |
2393 |
(funcall company-insertion-on-trigger) |
2394 |
company-insertion-on-trigger) |
2395 |
(if (functionp company-insertion-triggers) |
2396 |
(funcall company-insertion-triggers input) |
2397 |
(if (consp company-insertion-triggers) |
2398 |
(memq (char-syntax (string-to-char input)) |
2399 |
company-insertion-triggers) |
2400 |
(string-match-p (regexp-quote (substring input 0 1)) |
2401 |
company-insertion-triggers))))) |
2402 |
|
2403 |
(defun company--incremental-p () |
2404 |
(and (> (point) company-point) |
2405 |
(> (point-max) company--point-max) |
2406 |
(not (eq this-command 'backward-delete-char-untabify)) |
2407 |
(equal (buffer-substring (- company-point (length company-prefix)) |
2408 |
company-point) |
2409 |
company-prefix))) |
2410 |
|
2411 |
(defun company--continue-failed (new-prefix) |
2412 |
(cond |
2413 |
((and (or (not (company-require-match-p)) |
2414 |
;; Don't require match if the new prefix |
2415 |
;; doesn't continue the old one, and the latter was a match. |
2416 |
(not (stringp new-prefix)) |
2417 |
(<= (length new-prefix) (length company-prefix))) |
2418 |
(member company-prefix company-candidates)) |
2419 |
;; Last input was a success, |
2420 |
;; but we're treating it as an abort + input anyway, |
2421 |
;; like the `unique' case below. |
2422 |
(company-cancel 'non-unique)) |
2423 |
((company-require-match-p) |
2424 |
;; Wrong incremental input, but required match. |
2425 |
(delete-char (- company-valid-point (point))) |
2426 |
(ding) |
2427 |
(message "Matching input is required") |
2428 |
company-candidates) |
2429 |
(t (company-cancel)))) |
2430 |
|
2431 |
(defun company--good-prefix-p (prefix min-length) |
2432 |
(and (stringp (company--prefix-str prefix)) ;excludes 'stop |
2433 |
(or (eq (company--prefix-len prefix) t) |
2434 |
(>= (company--prefix-len prefix) |
2435 |
min-length)))) |
2436 |
|
2437 |
(defun company--prefix-min-length () |
2438 |
(if company--manual-prefix |
2439 |
(if company-abort-manual-when-too-short |
2440 |
;; Must not be less than minimum or initial length. |
2441 |
(min company-minimum-prefix-length |
2442 |
(if-let* ((mp-len-override (cdr-safe company--manual-prefix))) |
2443 |
(if (numberp mp-len-override) |
2444 |
mp-len-override |
2445 |
(length (car-safe company--manual-prefix))) |
2446 |
(length company--manual-prefix))) |
2447 |
0) |
2448 |
company-minimum-prefix-length)) |
2449 |
|
2450 |
(defun company--continue () |
2451 |
(when (company-call-backend 'no-cache company-prefix) |
2452 |
;; Don't complete existing candidates, fetch new ones. |
2453 |
(setq company-candidates-cache nil)) |
2454 |
(let* ((new-prefix (company-call-backend 'prefix)) |
2455 |
(new-suffix (company--suffix-str new-prefix)) |
2456 |
(ignore-case (company-call-backend 'ignore-case)) |
2457 |
(c (catch 'interrupted |
2458 |
(when (and (company--good-prefix-p new-prefix |
2459 |
(company--prefix-min-length)) |
2460 |
(setq new-prefix (company--prefix-str new-prefix)) |
2461 |
(= (- (point) (length new-prefix)) |
2462 |
(- company-point (length company-prefix)))) |
2463 |
(company-calculate-candidates new-prefix ignore-case new-suffix))))) |
2464 |
(cond |
2465 |
((eq c 'new-input) ; Keep the old completions, but update the rest. |
2466 |
(setq company-prefix new-prefix |
2467 |
company-suffix new-suffix |
2468 |
company-point (point)) |
2469 |
t) |
2470 |
((and company-abort-on-unique-match |
2471 |
(company--unique-match-p c new-prefix new-suffix ignore-case)) |
2472 |
;; Handle it like completion was aborted, to differentiate from user |
2473 |
;; calling one of Company's commands to insert the candidate, |
2474 |
;; not to trigger template expansion, etc. |
2475 |
(company-cancel 'unique)) |
2476 |
((consp c) |
2477 |
;; incremental match |
2478 |
(setq company-prefix new-prefix |
2479 |
company-suffix new-suffix |
2480 |
company-point (point)) |
2481 |
(company-update-candidates c) |
2482 |
c) |
2483 |
((and (characterp last-command-event) |
2484 |
(company-insertion-on-trigger-p (string last-command-event))) |
2485 |
;; Insertion on trigger. |
2486 |
(save-excursion |
2487 |
(goto-char company-point) |
2488 |
(company-complete-selection) |
2489 |
nil)) |
2490 |
((not (company--incremental-p)) |
2491 |
(company-cancel)) |
2492 |
(t (company--continue-failed new-prefix))))) |
2493 |
|
2494 |
(defun company--begin-new () |
2495 |
(let ((min-prefix (company--prefix-min-length)) |
2496 |
entity c) |
2497 |
(cl-dolist (backend (if company-backend |
2498 |
;; prefer manual override |
2499 |
(list company-backend) |
2500 |
company-backends)) |
2501 |
(setq entity |
2502 |
(if (or (symbolp backend) |
2503 |
(functionp backend)) |
2504 |
(when (company--maybe-init-backend backend) |
2505 |
(let ((company-backend backend)) |
2506 |
(company-call-backend 'prefix))) |
2507 |
(company--multi-backend-adapter backend 'prefix))) |
2508 |
(when entity |
2509 |
(when (and (company--good-prefix-p entity min-prefix) |
2510 |
(or (not company-inhibit-inside-symbols) |
2511 |
company--manual-action |
2512 |
(zerop (length (company--suffix-str entity))))) |
2513 |
(let ((ignore-case (company-call-backend 'ignore-case))) |
2514 |
;; Keep this undocumented, esp. while only 1 backend needs it. |
2515 |
;(company-call-backend 'set-min-prefix min-prefix);;BUGGED LINE that |
2516 |
;I fixed by simply replacing it with a "0". God damn it... |
2517 |
(company-call-backend 'set-min-prefix "0") |
2518 |
(setq company-prefix (company--prefix-str entity) |
2519 |
company-suffix (company--suffix-str entity) |
2520 |
company-point (point) |
2521 |
company-backend backend |
2522 |
c (catch 'interrupted |
2523 |
(company-calculate-candidates company-prefix ignore-case |
2524 |
company-suffix))) |
2525 |
(cond |
2526 |
((or (null c) (eq c 'new-input)) |
2527 |
(when company--manual-action |
2528 |
(message "No completion found"))) |
2529 |
((and company-abort-on-unique-match |
2530 |
(company--unique-match-p c company-prefix company-suffix ignore-case) |
2531 |
(if company--manual-action |
2532 |
;; If `company-manual-begin' was called, the user |
2533 |
;; really wants something to happen. Otherwise... |
2534 |
(ignore (message "Sole completion")) |
2535 |
t)) |
2536 |
;; ...abort and run the hooks, e.g. to clear the cache. |
2537 |
(company-cancel 'unique)) |
2538 |
(t ;; We got completions! |
2539 |
(when company--manual-action |
2540 |
(setq company--manual-prefix entity)) |
2541 |
(company-update-candidates c) |
2542 |
(run-hook-with-args 'company-completion-started-hook |
2543 |
(company-explicit-action-p)) |
2544 |
(company-call-frontends 'show))))) |
2545 |
(cl-return c))))) |
2546 |
|
2547 |
(defun company--perform () |
2548 |
(cond |
2549 |
(company-candidates |
2550 |
(company--continue)) |
2551 |
((company--should-complete) |
2552 |
(company-cache-expire) |
2553 |
(company--begin-new))) |
2554 |
(if (not company-candidates) |
2555 |
(setq company-backend nil) |
2556 |
(setq company--point-max (point-max)) |
2557 |
(company-ensure-emulation-alist) |
2558 |
(company-enable-overriding-keymap company-active-map) |
2559 |
(company-call-frontends 'update))) |
2560 |
|
2561 |
(defun company-cancel (&optional result) |
2562 |
(let ((prefix company-prefix) |
2563 |
(backend company-backend)) |
2564 |
(setq company-backend nil |
2565 |
company-prefix nil |
2566 |
company-candidates nil |
2567 |
company-candidates-length nil |
2568 |
company-candidates-cache nil |
2569 |
company-candidates-predicate nil |
2570 |
company-common nil |
2571 |
company-selection company-selection-default |
2572 |
company-selection-changed nil |
2573 |
company--manual-action nil |
2574 |
company--manual-prefix nil |
2575 |
company--point-max nil |
2576 |
company--multi-uncached-backends nil |
2577 |
company--multi-min-prefix nil |
2578 |
company-point nil) |
2579 |
(when company-timer |
2580 |
(cancel-timer company-timer)) |
2581 |
(company-echo-cancel t) |
2582 |
(company-search-mode 0) |
2583 |
(company-call-frontends 'hide) |
2584 |
(company-enable-overriding-keymap nil) |
2585 |
(when prefix |
2586 |
(if (stringp result) |
2587 |
(let ((company-backend backend)) |
2588 |
(run-hook-with-args 'company-completion-finished-hook result) |
2589 |
(company-call-backend 'post-completion result)) |
2590 |
(run-hook-with-args 'company-completion-cancelled-hook result)) |
2591 |
(run-hook-with-args 'company-after-completion-hook result))) |
2592 |
;; Make return value explicit. |
2593 |
nil) |
2594 |
|
2595 |
(defun company-abort () |
2596 |
(interactive) |
2597 |
(company-cancel 'abort)) |
2598 |
|
2599 |
(defun company-finish (result) |
2600 |
(pcase-let ((`(,prefix . ,suffix) (company--boundaries result))) |
2601 |
(company--insert-candidate result (or prefix company-prefix)) |
2602 |
(and (> (length suffix) 0) |
2603 |
(delete-region (point) (+ (point) (length suffix)))) |
2604 |
(let ((tick (buffer-chars-modified-tick)) |
2605 |
(backend company-backend)) |
2606 |
;; Call backend's `post-completion' and run other hooks, then exit. |
2607 |
(company-cancel result) |
2608 |
;; Try restarting completion, to see if we moved into a new field. |
2609 |
;; Most commonly, this would be after entering a dir in file completion. |
2610 |
(when (= (buffer-chars-modified-tick) tick) |
2611 |
(let (company-require-match) |
2612 |
(setq company-backend backend |
2613 |
company--manual-prefix 0) |
2614 |
(company--begin-new)) |
2615 |
(unless (and company-candidates |
2616 |
(equal (company--boundaries) '("" . ""))) |
2617 |
(company-cancel)))))) |
2618 |
|
2619 |
(defsubst company-keep (command) |
2620 |
(and (symbolp command) (get command 'company-keep))) |
2621 |
|
2622 |
(defun company--proper-suffix-p (candidate) |
2623 |
(and |
2624 |
(>= (length candidate) |
2625 |
(+ (length company-prefix) |
2626 |
(length company-suffix))) |
2627 |
(string-suffix-p company-suffix candidate |
2628 |
(company-call-backend 'ignore-case)))) |
2629 |
|
2630 |
(defun company--boundaries (&optional candidate) |
2631 |
(unless candidate |
2632 |
(setq candidate (nth (or company-selection 0) company-candidates))) |
2633 |
(or |
2634 |
(company-call-backend 'adjust-boundaries |
2635 |
candidate |
2636 |
company-prefix company-suffix) |
2637 |
(and |
2638 |
;; Default to replacing the suffix only if the completion ends with it. |
2639 |
(company--proper-suffix-p candidate) |
2640 |
(cons company-prefix company-suffix)) |
2641 |
(cons company-prefix ""))) |
2642 |
|
2643 |
(defun company--active-p () |
2644 |
company-candidates) |
2645 |
|
2646 |
(defun company-pre-command () |
2647 |
(company--electric-restore-window-configuration) |
2648 |
(unless (company-keep this-command) |
2649 |
(condition-case-unless-debug err |
2650 |
(when company-candidates |
2651 |
(company-call-frontends 'pre-command) |
2652 |
(unless (company--should-continue) |
2653 |
(company-abort))) |
2654 |
(error (message "Company: An error occurred in pre-command") |
2655 |
(message "%s" (error-message-string err)) |
2656 |
(company-cancel)))) |
2657 |
(when company-timer |
2658 |
(cancel-timer company-timer) |
2659 |
(setq company-timer nil)) |
2660 |
(company-echo-cancel t) |
2661 |
(company-uninstall-map)) |
2662 |
|
2663 |
(defun company-post-command () |
2664 |
(when (and company-candidates |
2665 |
(null this-command)) |
2666 |
;; Happens when the user presses `C-g' while inside |
2667 |
;; `flyspell-post-command-hook', for example. |
2668 |
;; Or any other `post-command-hook' function that can call `sit-for', |
2669 |
;; or any quittable timer function. |
2670 |
(company-abort) |
2671 |
(setq this-command 'company-abort)) |
2672 |
(unless (company-keep this-command) |
2673 |
(condition-case-unless-debug err |
2674 |
(progn |
2675 |
(unless (and (equal (point) company-point) |
2676 |
(equal (point-max) company--point-max)) |
2677 |
(let (company-idle-delay) ; Against misbehavior while debugging. |
2678 |
(company--perform))) |
2679 |
(if company-candidates |
2680 |
(progn |
2681 |
(company-call-frontends 'post-command) |
2682 |
(when company-auto-update-doc |
2683 |
(condition-case nil |
2684 |
(unless (company--electric-command-p) |
2685 |
(company-show-doc-buffer)) |
2686 |
(user-error nil) |
2687 |
(quit nil)))) |
2688 |
(let ((delay (company--idle-delay))) |
2689 |
(and (numberp delay) |
2690 |
(not defining-kbd-macro) |
2691 |
(company--should-begin) |
2692 |
(setq company-timer |
2693 |
(run-with-timer delay nil |
2694 |
'company-idle-begin |
2695 |
(current-buffer) (selected-window) |
2696 |
(buffer-chars-modified-tick) (point))))))) |
2697 |
(error (message "Company: An error occurred in post-command") |
2698 |
(message "%s" (error-message-string err)) |
2699 |
(company-cancel)))) |
2700 |
(company-install-map)) |
2701 |
|
2702 |
(defun company--idle-delay () |
2703 |
(let ((delay |
2704 |
(if (functionp company-idle-delay) |
2705 |
(funcall company-idle-delay) |
2706 |
company-idle-delay))) |
2707 |
(if (memql delay '(t 0 0.0)) |
2708 |
0.01 |
2709 |
delay))) |
2710 |
|
2711 |
(defvar company--begin-inhibit-commands '(company-abort |
2712 |
company-complete-mouse |
2713 |
company-complete |
2714 |
company-complete-common |
2715 |
company-complete-selection |
2716 |
company-complete-tooltip-row) |
2717 |
"List of commands after which idle completion is (still) disabled when |
2718 |
`company-begin-commands' is t.") |
2719 |
|
2720 |
(defun company--should-begin () |
2721 |
(if (eq t company-begin-commands) |
2722 |
(not (memq this-command company--begin-inhibit-commands)) |
2723 |
(or |
2724 |
(memq this-command company-begin-commands) |
2725 |
(and (symbolp this-command) (get this-command 'company-begin))))) |
2726 |
|
2727 |
;;; search ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2728 |
|
2729 |
(defcustom company-search-regexp-function #'regexp-quote |
2730 |
"Function to construct the search regexp from input. |
2731 |
It's called with one argument, the current search input. It must return |
2732 |
either a regexp without groups, or one where groups don't intersect and |
2733 |
each one wraps a part of the input string." |
2734 |
:type '(choice |
2735 |
(const :tag "Exact match" regexp-quote) |
2736 |
(const :tag "Words separated with spaces" company-search-words-regexp) |
2737 |
(const :tag "Words separated with spaces, in any order" |
2738 |
company-search-words-in-any-order-regexp) |
2739 |
(const :tag "All characters in given order, with anything in between" |
2740 |
company-search-flex-regexp))) |
2741 |
|
2742 |
(defvar-local company-search-string "") |
2743 |
|
2744 |
(defvar company-search-lighter '(" " |
2745 |
(company-search-filtering "Filter" "Search") |
2746 |
": \"" |
2747 |
company-search-string |
2748 |
"\"")) |
2749 |
|
2750 |
(defvar-local company-search-filtering nil |
2751 |
"Non-nil to filter the completion candidates by the search string") |
2752 |
|
2753 |
(defvar-local company--search-old-selection 0) |
2754 |
|
2755 |
(defvar-local company--search-old-changed nil) |
2756 |
|
2757 |
(defun company-search-words-regexp (input) |
2758 |
(mapconcat (lambda (word) (format "\\(%s\\)" (regexp-quote word))) |
2759 |
(split-string input " +" t) ".*")) |
2760 |
|
2761 |
(defun company-search-words-in-any-order-regexp (input) |
2762 |
(let* ((words (mapcar (lambda (word) (format "\\(%s\\)" (regexp-quote word))) |
2763 |
(split-string input " +" t))) |
2764 |
(permutations (company--permutations words))) |
2765 |
(mapconcat (lambda (words) |
2766 |
(mapconcat #'identity words ".*")) |
2767 |
permutations |
2768 |
"\\|"))) |
2769 |
|
2770 |
(defun company-search-flex-regexp (input) |
2771 |
(if (zerop (length input)) |
2772 |
"" |
2773 |
(concat (regexp-quote (string (aref input 0))) |
2774 |
(mapconcat (lambda (c) |
2775 |
(concat "[^" (string c) "]*" |
2776 |
(regexp-quote (string c)))) |
2777 |
(substring input 1) "")))) |
2778 |
|
2779 |
(defun company--permutations (lst) |
2780 |
(if (not lst) |
2781 |
'(nil) |
2782 |
;; FIXME: Replace with `mapcan' in Emacs 26. |
2783 |
(cl-mapcan |
2784 |
(lambda (e) |
2785 |
(mapcar (lambda (perm) (cons e perm)) |
2786 |
(company--permutations (cl-remove e lst :count 1)))) |
2787 |
lst))) |
2788 |
|
2789 |
(defun company--search (text lines) |
2790 |
(let ((re (funcall company-search-regexp-function text)) |
2791 |
(i 0)) |
2792 |
(cl-dolist (line lines) |
2793 |
(when (string-match-p re line) |
2794 |
(cl-return i)) |
2795 |
(cl-incf i)))) |
2796 |
|
2797 |
(defun company-search-printing-char () |
2798 |
(interactive) |
2799 |
(company--search-assert-enabled) |
2800 |
(let* ((event-type (event-basic-type last-command-event)) |
2801 |
(event-string (if (characterp event-type) |
2802 |
(string last-command-event) |
2803 |
;; Handle key press on the keypad. |
2804 |
(let ((name (symbol-name event-type))) |
2805 |
(if (string-match "kp-\\([0-9]\\)" name) |
2806 |
(match-string 1 name) |
2807 |
(error "Unexpected printing char input"))))) |
2808 |
(ss (concat company-search-string event-string))) |
2809 |
(when company-search-filtering |
2810 |
(company--search-update-predicate ss)) |
2811 |
(company--search-update-string ss))) |
2812 |
|
2813 |
(defun company--search-update-predicate (ss) |
2814 |
(let* ((re (funcall company-search-regexp-function ss)) |
2815 |
(company-candidates-predicate |
2816 |
(and (not (string-empty-p re)) |
2817 |
company-search-filtering |
2818 |
(lambda (candidate) (string-match-p re candidate)))) |
2819 |
(cc (company-calculate-candidates company-prefix |
2820 |
(company-call-backend 'ignore-case) |
2821 |
company-suffix))) |
2822 |
(unless cc (user-error "No match")) |
2823 |
(company-update-candidates cc))) |
2824 |
|
2825 |
(defun company--search-update-string (new) |
2826 |
(let* ((selection (or company-selection 0)) |
2827 |
(pos (company--search new (nthcdr selection company-candidates)))) |
2828 |
(if (null pos) |
2829 |
(ding) |
2830 |
(setq company-search-string new) |
2831 |
(company-set-selection (+ selection pos) t)))) |
2832 |
|
2833 |
(defun company--search-assert-input () |
2834 |
(company--search-assert-enabled) |
2835 |
(when (string-empty-p company-search-string) |
2836 |
(user-error "Empty search string"))) |
2837 |
|
2838 |
(defun company-search-repeat-forward () |
2839 |
"Repeat the incremental search in completion candidates forward." |
2840 |
(interactive) |
2841 |
(company--search-assert-input) |
2842 |
(let* ((selection (or company-selection 0)) |
2843 |
(pos (company--search company-search-string |
2844 |
(cdr (nthcdr selection company-candidates))))) |
2845 |
(if (null pos) |
2846 |
(ding) |
2847 |
(company-set-selection (+ selection pos 1) t)))) |
2848 |
|
2849 |
(defun company-search-repeat-backward () |
2850 |
"Repeat the incremental search in completion candidates backwards." |
2851 |
(interactive) |
2852 |
(company--search-assert-input) |
2853 |
(let* ((selection (or company-selection 0)) |
2854 |
(pos (company--search company-search-string |
2855 |
(nthcdr (- company-candidates-length |
2856 |
selection) |
2857 |
(reverse company-candidates))))) |
2858 |
(if (null pos) |
2859 |
(ding) |
2860 |
(company-set-selection (- selection pos 1) t)))) |
2861 |
|
2862 |
(defun company-search-toggle-filtering () |
2863 |
"Toggle `company-search-filtering'." |
2864 |
(interactive) |
2865 |
(company--search-assert-enabled) |
2866 |
(setq company-search-filtering (not company-search-filtering)) |
2867 |
(let ((ss company-search-string)) |
2868 |
(company--search-update-predicate ss) |
2869 |
(company--search-update-string ss))) |
2870 |
|
2871 |
(defun company-search-abort () |
2872 |
"Abort searching the completion candidates." |
2873 |
(interactive) |
2874 |
(company--search-assert-enabled) |
2875 |
(company-search-mode 0) |
2876 |
(company-set-selection company--search-old-selection t) |
2877 |
(setq company-selection-changed company--search-old-changed)) |
2878 |
|
2879 |
(defun company-search-other-char () |
2880 |
(interactive) |
2881 |
(company--search-assert-enabled) |
2882 |
(company-search-mode 0) |
2883 |
(company--unread-this-command-keys)) |
2884 |
|
2885 |
(defun company-search-delete-char () |
2886 |
(interactive) |
2887 |
(company--search-assert-enabled) |
2888 |
(if (string-empty-p company-search-string) |
2889 |
(ding) |
2890 |
(let ((ss (substring company-search-string 0 -1))) |
2891 |
(when company-search-filtering |
2892 |
(company--search-update-predicate ss)) |
2893 |
(company--search-update-string ss)))) |
2894 |
|
2895 |
(defvar company-search-map |
2896 |
(let ((i 0) |
2897 |
(keymap (make-keymap))) |
2898 |
(if (fboundp 'max-char) |
2899 |
(set-char-table-range (nth 1 keymap) (cons #x100 (max-char)) |
2900 |
'company-search-printing-char) |
2901 |
(with-no-warnings |
2902 |
;; obsolete in Emacs 23 |
2903 |
(let ((l (generic-character-list)) |
2904 |
(table (nth 1 keymap))) |
2905 |
(while l |
2906 |
(set-char-table-default table (car l) 'company-search-printing-char) |
2907 |
(setq l (cdr l)))))) |
2908 |
(define-key keymap [t] 'company-search-other-char) |
2909 |
(while (< i ?\s) |
2910 |
(define-key keymap (make-string 1 i) 'company-search-other-char) |
2911 |
(cl-incf i)) |
2912 |
(while (< i 256) |
2913 |
(define-key keymap (vector i) 'company-search-printing-char) |
2914 |
(cl-incf i)) |
2915 |
(dotimes (i 10) |
2916 |
(define-key keymap (kbd (format "<kp-%d>" i)) 'company-search-printing-char)) |
2917 |
(let ((meta-map (make-sparse-keymap))) |
2918 |
(define-key keymap (char-to-string meta-prefix-char) meta-map) |
2919 |
(define-key keymap [escape] meta-map)) |
2920 |
(define-key keymap (vector meta-prefix-char t) 'company-search-other-char) |
2921 |
(define-key keymap (kbd "C-n") 'company-select-next-or-abort) |
2922 |
(define-key keymap (kbd "C-p") 'company-select-previous-or-abort) |
2923 |
(define-key keymap (kbd "M-n") 'company--select-next-and-warn) |
2924 |
(define-key keymap (kbd "M-p") 'company--select-previous-and-warn) |
2925 |
(define-key keymap (kbd "<down>") 'company-select-next-or-abort) |
2926 |
(define-key keymap (kbd "<up>") 'company-select-previous-or-abort) |
2927 |
(define-key keymap "\e\e\e" 'company-search-other-char) |
2928 |
(define-key keymap [escape escape escape] 'company-search-other-char) |
2929 |
(define-key keymap (kbd "DEL") 'company-search-delete-char) |
2930 |
(define-key keymap [backspace] 'company-search-delete-char) |
2931 |
(define-key keymap "\C-g" 'company-search-abort) |
2932 |
(define-key keymap "\C-s" 'company-search-repeat-forward) |
2933 |
(define-key keymap "\C-r" 'company-search-repeat-backward) |
2934 |
(define-key keymap "\C-o" 'company-search-toggle-filtering) |
2935 |
(company-keymap--bind-quick-access keymap) |
2936 |
keymap) |
2937 |
"Keymap used for incrementally searching the completion candidates.") |
2938 |
|
2939 |
(define-minor-mode company-search-mode |
2940 |
"Search mode for completion candidates. |
2941 |
Don't start this directly, use `company-search-candidates' or |
2942 |
`company-filter-candidates'." |
2943 |
:lighter company-search-lighter |
2944 |
(if company-search-mode |
2945 |
(if (company-manual-begin) |
2946 |
(progn |
2947 |
(setq company--search-old-selection company-selection |
2948 |
company--search-old-changed company-selection-changed) |
2949 |
(company-call-frontends 'update) |
2950 |
(company-enable-overriding-keymap company-search-map)) |
2951 |
(setq company-search-mode nil)) |
2952 |
(kill-local-variable 'company-search-string) |
2953 |
(kill-local-variable 'company-search-filtering) |
2954 |
(kill-local-variable 'company--search-old-selection) |
2955 |
(kill-local-variable 'company--search-old-changed) |
2956 |
(when company-backend |
2957 |
(company--search-update-predicate "") |
2958 |
(company-call-frontends 'update)) |
2959 |
(company-enable-overriding-keymap company-active-map))) |
2960 |
|
2961 |
(defun company--search-assert-enabled () |
2962 |
(company-assert-enabled) |
2963 |
(unless company-search-mode |
2964 |
(company-uninstall-map) |
2965 |
(user-error "Company not in search mode"))) |
2966 |
|
2967 |
(defun company-search-candidates () |
2968 |
"Start searching the completion candidates incrementally. |
2969 |
|
2970 |
\\<company-search-map>Search can be controlled with the commands: |
2971 |
- `company-search-repeat-forward' (\\[company-search-repeat-forward]) |
2972 |
- `company-search-repeat-backward' (\\[company-search-repeat-backward]) |
2973 |
- `company-search-abort' (\\[company-search-abort]) |
2974 |
- `company-search-delete-char' (\\[company-search-delete-char]) |
2975 |
|
2976 |
Regular characters are appended to the search string. |
2977 |
|
2978 |
Customize `company-search-regexp-function' to change how the input |
2979 |
is interpreted when searching. |
2980 |
|
2981 |
The command `company-search-toggle-filtering' (\\[company-search-toggle-filtering]) |
2982 |
uses the search string to filter the completion candidates." |
2983 |
(interactive) |
2984 |
(company-search-mode 1)) |
2985 |
|
2986 |
(defun company-filter-candidates () |
2987 |
"Start filtering the completion candidates incrementally. |
2988 |
This works the same way as `company-search-candidates' immediately |
2989 |
followed by `company-search-toggle-filtering'." |
2990 |
(interactive) |
2991 |
(company-search-mode 1) |
2992 |
(setq company-search-filtering t)) |
2993 |
|
2994 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2995 |
|
2996 |
(defun company-select-next (&optional arg) |
2997 |
"Select the next candidate in the list. |
2998 |
|
2999 |
With ARG, move by that many elements. |
3000 |
When `company-selection-default' is nil, add a special pseudo candidates |
3001 |
meant for no selection." |
3002 |
(interactive "p") |
3003 |
(when (company-manual-begin) |
3004 |
(let ((selection (+ (or arg 1) |
3005 |
(or company-selection |
3006 |
company-selection-default |
3007 |
-1)))) |
3008 |
(company-set-selection selection)))) |
3009 |
|
3010 |
(defun company-select-previous (&optional arg) |
3011 |
"Select the previous candidate in the list. |
3012 |
|
3013 |
With ARG, move by that many elements." |
3014 |
(interactive "p") |
3015 |
(company-select-next (if arg (- arg) -1))) |
3016 |
|
3017 |
(defun company-select-next-or-abort (&optional arg) |
3018 |
"Select the next candidate if more than one, else abort |
3019 |
and invoke the normal binding. |
3020 |
|
3021 |
With ARG, move by that many elements." |
3022 |
(interactive "p") |
3023 |
(if (or (not company-selection) |
3024 |
(> company-candidates-length 1)) |
3025 |
(company-select-next arg) |
3026 |
(company-abort) |
3027 |
(company--unread-this-command-keys))) |
3028 |
|
3029 |
(defun company-select-previous-or-abort (&optional arg) |
3030 |
"Select the previous candidate if more than one, else abort |
3031 |
and invoke the normal binding. |
3032 |
|
3033 |
With ARG, move by that many elements." |
3034 |
(interactive "p") |
3035 |
(if (> company-candidates-length 1) |
3036 |
(company-select-previous arg) |
3037 |
(company-abort) |
3038 |
(company--unread-this-command-keys))) |
3039 |
|
3040 |
(defun company-select-first () |
3041 |
"Select the first completion candidate." |
3042 |
(interactive) |
3043 |
(company-set-selection 0)) |
3044 |
|
3045 |
(defun company-select-last () |
3046 |
"Select the last completion candidate." |
3047 |
(interactive) |
3048 |
(company-set-selection (1- company-candidates-length))) |
3049 |
|
3050 |
(defun company-next-page () |
3051 |
"Select the candidate one page further." |
3052 |
(interactive) |
3053 |
(when (company-manual-begin) |
3054 |
(if (and company-selection-wrap-around |
3055 |
(= company-selection (1- company-candidates-length))) |
3056 |
(company-set-selection 0) |
3057 |
(let (company-selection-wrap-around) |
3058 |
(company-set-selection (+ company-selection |
3059 |
company-tooltip-limit)))))) |
3060 |
|
3061 |
(defun company-previous-page () |
3062 |
"Select the candidate one page earlier." |
3063 |
(interactive) |
3064 |
(when (company-manual-begin) |
3065 |
(if (and company-selection-wrap-around |
3066 |
(zerop company-selection)) |
3067 |
(company-set-selection (1- company-candidates-length)) |
3068 |
(let (company-selection-wrap-around) |
3069 |
(company-set-selection (- company-selection |
3070 |
company-tooltip-limit)))))) |
3071 |
|
3072 |
(defun company--event-col-row (event) |
3073 |
(company--posn-col-row (event-start event))) |
3074 |
|
3075 |
(defvar company-mouse-event nil |
3076 |
"Holds the mouse event from `company-select-mouse'. |
3077 |
For use in the `select-mouse' frontend action. `let'-bound.") |
3078 |
|
3079 |
(defun company-select-mouse (event) |
3080 |
"Select the candidate picked by the mouse." |
3081 |
(interactive "e") |
3082 |
(or (let ((company-mouse-event event)) |
3083 |
(cl-some #'identity (company-call-frontends 'select-mouse))) |
3084 |
(progn |
3085 |
(company-abort) |
3086 |
(company--unread-this-command-keys) |
3087 |
nil))) |
3088 |
|
3089 |
(defun company-complete-mouse (event) |
3090 |
"Insert the candidate picked by the mouse." |
3091 |
(interactive "e") |
3092 |
(when (company-select-mouse event) |
3093 |
(company-complete-selection))) |
3094 |
|
3095 |
(defun company-complete-selection () |
3096 |
"Insert the selected candidate. |
3097 |
|
3098 |
Restart completion if a new field is entered. A field is indicated by |
3099 |
`adjust-boundaries' as implemented in the backend. If both adjusted prefix |
3100 |
and adjusted suffix are empty strings, that means a new field." |
3101 |
(interactive) |
3102 |
(when (and (company-manual-begin) company-selection) |
3103 |
(let ((result (nth company-selection company-candidates))) |
3104 |
(company-finish result)))) |
3105 |
|
3106 |
(defun company--expand-common (prefix suffix) |
3107 |
(let ((expansion (company-call-backend 'expand-common prefix suffix))) |
3108 |
(unless expansion |
3109 |
;; Backend doesn't implement this, try emulating. |
3110 |
(let* (;; XXX: We could also filter/group `company-candidates'. |
3111 |
(candidates (company-call-backend 'candidates prefix suffix)) |
3112 |
;; Assuming that boundaries don't vary between completions here. |
3113 |
;; If they do, the backend should have a custom `expand-common'. |
3114 |
(boundaries-prefix (car (company--boundaries))) |
3115 |
(completion-ignore-case (company-call-backend 'ignore-case)) |
3116 |
(trycmp (try-completion boundaries-prefix candidates)) |
3117 |
(common (if (eq trycmp t) (car candidates) trycmp)) |
3118 |
(max-len (when (and common |
3119 |
(cl-every (lambda (s) (string-suffix-p |
3120 |
suffix s |
3121 |
completion-ignore-case)) |
3122 |
candidates)) |
3123 |
(- |
3124 |
(apply #'min |
3125 |
(mapcar #'length candidates)) |
3126 |
(length suffix)))) |
3127 |
(common (if max-len |
3128 |
(substring common 0 |
3129 |
(min max-len (length common))) |
3130 |
common))) |
3131 |
(setq expansion |
3132 |
(cond |
3133 |
((null candidates) |
3134 |
'no-match) |
3135 |
((string-prefix-p boundaries-prefix common t) |
3136 |
(cons (concat |
3137 |
(substring prefix |
3138 |
0 |
3139 |
(- (length prefix) |
3140 |
(length boundaries-prefix))) |
3141 |
common) |
3142 |
suffix)) |
3143 |
(t (cons prefix suffix)))))) |
3144 |
expansion)) |
3145 |
|
3146 |
(defun company-complete-common () |
3147 |
"Insert the common part of all candidates." |
3148 |
(interactive) |
3149 |
(when (company-manual-begin) |
3150 |
(if (and (not (cdr company-candidates)) |
3151 |
(equal company-common (car company-candidates))) |
3152 |
(company-complete-selection) |
3153 |
(let ((expansion (company--expand-common company-prefix |
3154 |
company-suffix))) |
3155 |
(when (eq expansion 'no-match) |
3156 |
(user-error "No matches for the current input")) |
3157 |
(unless (equal (car expansion) company-prefix) |
3158 |
(if (eq (company-call-backend 'ignore-case) 'keep-prefix) |
3159 |
(insert (substring (car expansion) (length company-prefix))) |
3160 |
(delete-region (- (point) (length company-prefix)) (point)) |
3161 |
(insert (car expansion)))) |
3162 |
(unless (equal (cdr expansion) company-suffix) |
3163 |
(save-excursion |
3164 |
(delete-region (point) (+ (point) (length company-suffix))) |
3165 |
(insert (cdr expansion)))))))) |
3166 |
|
3167 |
(defun company-complete-common-or-cycle (&optional arg) |
3168 |
"Insert the common part of all candidates, or select the next one. |
3169 |
|
3170 |
With ARG, move by that many elements." |
3171 |
(interactive "p") |
3172 |
(when (company-manual-begin) |
3173 |
(let ((tick (buffer-chars-modified-tick))) |
3174 |
(call-interactively 'company-complete-common) |
3175 |
(when (eq tick (buffer-chars-modified-tick)) |
3176 |
(let ((company-selection-wrap-around t) |
3177 |
(current-prefix-arg arg)) |
3178 |
(call-interactively 'company-select-next)))))) |
3179 |
|
3180 |
(defun company-cycle-backward (&optional arg) |
3181 |
(interactive "p") |
3182 |
(let ((company-selection-wrap-around t)) |
3183 |
(company-select-previous arg))) |
3184 |
|
3185 |
(defun company-complete-common-or-show-delayed-tooltip () |
3186 |
"Insert the common part of all candidates, or show a tooltip." |
3187 |
(interactive) |
3188 |
(when (company-manual-begin) |
3189 |
(let ((tick (buffer-chars-modified-tick))) |
3190 |
(call-interactively 'company-complete-common) |
3191 |
(when (eq tick (buffer-chars-modified-tick)) |
3192 |
(let ((company-tooltip-idle-delay 0.0)) |
3193 |
(company-complete) |
3194 |
(and company-candidates |
3195 |
(company-call-frontends 'post-command))))))) |
3196 |
|
3197 |
(defun company-indent-or-complete-common (arg) |
3198 |
"Indent the current line or region, or complete the common part." |
3199 |
(interactive "P") |
3200 |
(cond |
3201 |
((use-region-p) |
3202 |
(indent-region (region-beginning) (region-end))) |
3203 |
((memq indent-line-function |
3204 |
'(indent-relative indent-relative-maybe)) |
3205 |
(company-complete-common)) |
3206 |
((let ((old-point (point)) |
3207 |
(old-tick (buffer-chars-modified-tick)) |
3208 |
(tab-always-indent t)) |
3209 |
(indent-for-tab-command arg) |
3210 |
(when (and (eq old-point (point)) |
3211 |
(eq old-tick (buffer-chars-modified-tick))) |
3212 |
(company-complete-common)))))) |
3213 |
|
3214 |
(defun company-select-next-if-tooltip-visible-or-complete-selection () |
3215 |
"Insert selection if appropriate, or select the next candidate. |
3216 |
Insert selection if only preview is showing or only one candidate, |
3217 |
otherwise select the next candidate." |
3218 |
(interactive) |
3219 |
(if (and (company-tooltip-visible-p) (> company-candidates-length 1)) |
3220 |
(call-interactively 'company-select-next) |
3221 |
(call-interactively 'company-complete-selection))) |
3222 |
|
3223 |
;;;###autoload |
3224 |
(defun company-complete () |
3225 |
"Insert the common part of all candidates or the current selection. |
3226 |
The first time this is called, the common part is inserted, the second |
3227 |
time, or when the selection has been changed, the selected candidate is |
3228 |
inserted." |
3229 |
(interactive) |
3230 |
(when (company-manual-begin) |
3231 |
(if (or company-selection-changed |
3232 |
(and (eq real-last-command 'company-complete) |
3233 |
(eq last-command 'company-complete-common))) |
3234 |
(call-interactively 'company-complete-selection) |
3235 |
(call-interactively 'company-complete-common) |
3236 |
(when company-candidates |
3237 |
(setq this-command 'company-complete-common))) |
3238 |
this-command)) |
3239 |
|
3240 |
(define-obsolete-function-alias |
3241 |
'company-complete-number |
3242 |
'company-complete-tooltip-row |
3243 |
"0.10.0") |
3244 |
|
3245 |
(defun company-complete-tooltip-row (number) |
3246 |
"Insert a candidate visible on the tooltip's row NUMBER. |
3247 |
|
3248 |
Inserts one of the first ten candidates, |
3249 |
numbered according to the current scrolling position starting with 1. |
3250 |
|
3251 |
When called interactively, uses the last typed digit, stripping the |
3252 |
modifiers and translating 0 into 10, so `M-1' inserts the first visible |
3253 |
candidate, and `M-0' insert to 10th one. |
3254 |
|
3255 |
To show hint numbers beside the candidates, enable `company-show-quick-access'." |
3256 |
(interactive |
3257 |
(list (let* ((type (event-basic-type last-command-event)) |
3258 |
(char (if (characterp type) |
3259 |
;; Number on the main row. |
3260 |
type |
3261 |
;; Keypad number, if bound directly. |
3262 |
(car (last (string-to-list (symbol-name type)))))) |
3263 |
(number (- char ?0))) |
3264 |
(if (zerop number) 10 number)))) |
3265 |
(company--complete-nth (1- number))) |
3266 |
|
3267 |
(defun company-complete-quick-access (row) |
3268 |
"Insert a candidate visible on a ROW matched by a quick-access key binding. |
3269 |
See `company-quick-access-keys' for more details." |
3270 |
(interactive |
3271 |
(list (let* ((event-type (event-basic-type last-command-event)) |
3272 |
(event-string (if (characterp event-type) |
3273 |
(string event-type) |
3274 |
(error "Unexpected input")))) |
3275 |
(cl-position event-string company-quick-access-keys :test 'equal)))) |
3276 |
(when row |
3277 |
(company--complete-nth row))) |
3278 |
|
3279 |
(defvar-local company-tooltip-offset 0 |
3280 |
"Current scrolling state of the tooltip. |
3281 |
Represented by the index of the first visible completion candidate |
3282 |
from the candidates list.") |
3283 |
|
3284 |
(defun company--complete-nth (row) |
3285 |
"Insert a candidate visible on the tooltip's zero-based ROW." |
3286 |
(when (company-manual-begin) |
3287 |
(and (or (< row 0) (>= row (- company-candidates-length |
3288 |
company-tooltip-offset))) |
3289 |
(user-error "No candidate on the row number %d" row)) |
3290 |
(company-finish (nth (+ row company-tooltip-offset) |
3291 |
company-candidates)))) |
3292 |
|
3293 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
3294 |
|
3295 |
(defconst company-space-strings-limit 100) |
3296 |
|
3297 |
(defconst company-space-strings |
3298 |
(let (lst) |
3299 |
(dotimes (i company-space-strings-limit) |
3300 |
(push (make-string (- company-space-strings-limit 1 i) ?\ ) lst)) |
3301 |
(apply 'vector lst))) |
3302 |
|
3303 |
(defun company-space-string (len) |
3304 |
(if (< len company-space-strings-limit) |
3305 |
(aref company-space-strings len) |
3306 |
(make-string len ?\ ))) |
3307 |
|
3308 |
;; XXX: This is really a hack, but one that we could really get rid of only by |
3309 |
;; moving to the one-overlay-per-line scheme. |
3310 |
(defmacro company--with-face-remappings (&rest body) |
3311 |
`(let ((fra-local (and (local-variable-p 'face-remapping-alist) |
3312 |
face-remapping-alist)) |
3313 |
(bdt-local (and (local-variable-p 'buffer-display-table) |
3314 |
buffer-display-table)) |
3315 |
(bufs (list (get-buffer-create " *string-pixel-width*") |
3316 |
(get-buffer-create " *company-sps*")))) |
3317 |
(unwind-protect |
3318 |
(progn |
3319 |
(dolist (buf bufs) |
3320 |
(with-current-buffer buf |
3321 |
(when (bound-and-true-p display-line-numbers) |
3322 |
;; Workaround for debbugs#67248. |
3323 |
(setq-local display-line-numbers nil)) |
3324 |
(when fra-local |
3325 |
(setq-local face-remapping-alist fra-local)) |
3326 |
(when bdt-local |
3327 |
(setq-local buffer-display-table bdt-local)))) |
3328 |
,@body) |
3329 |
(dolist (buf bufs) |
3330 |
(and (buffer-live-p buf) |
3331 |
(with-current-buffer buf |
3332 |
(kill-local-variable 'face-remapping-alist) |
3333 |
(kill-local-variable 'buffer-display-table))))))) |
3334 |
|
3335 |
(declare-function buffer-text-pixel-size "xdisp.c") |
3336 |
|
3337 |
(defun company--string-pixel-width (string) |
3338 |
(if (zerop (length string)) |
3339 |
0 |
3340 |
;; Keeping a work buffer around is more efficient than creating a |
3341 |
;; new temporary buffer. |
3342 |
(with-current-buffer (get-buffer-create " *string-pixel-width*") |
3343 |
;; `display-line-numbers-mode' is enabled in internal buffers |
3344 |
;; that breaks width calculation, so need to disable (bug#59311) |
3345 |
(when (bound-and-true-p display-line-numbers-mode) |
3346 |
(with-no-warnings ;; Emacs 25 |
3347 |
(display-line-numbers-mode -1))) |
3348 |
(delete-region (point-min) (point-max)) |
3349 |
(insert string) |
3350 |
(if (fboundp #'buffer-text-pixel-size) |
3351 |
;; Emacs 29.1+ |
3352 |
(car (buffer-text-pixel-size nil nil t)) |
3353 |
(let ((wb (window-buffer)) |
3354 |
(hscroll (window-hscroll)) |
3355 |
(dedicated (window-dedicated-p)) |
3356 |
buffer-list-update-hook) |
3357 |
(unwind-protect |
3358 |
(progn |
3359 |
(when dedicated |
3360 |
(set-window-dedicated-p nil nil)) |
3361 |
(set-window-buffer nil (current-buffer)) |
3362 |
(car |
3363 |
(window-text-pixel-size nil nil nil 55555))) |
3364 |
(set-window-buffer nil wb) |
3365 |
(set-window-hscroll nil hscroll) |
3366 |
(when dedicated |
3367 |
(set-window-dedicated-p nil dedicated)))))))) |
3368 |
|
3369 |
(defun company--string-width (str) |
3370 |
(if (display-graphic-p) |
3371 |
(ceiling (/ (company--string-pixel-width str) |
3372 |
(float (default-font-width)))) |
3373 |
(string-width str))) |
3374 |
|
3375 |
;; TODO: Add more tests! |
3376 |
(defun company-safe-pixel-substring (str from &optional to) |
3377 |
(let ((from-chars 0) |
3378 |
(to-chars 0) |
3379 |
spw-from spw-to |
3380 |
spw-to-prev |
3381 |
front back |
3382 |
(orig-buf (window-buffer)) |
3383 |
(bis buffer-invisibility-spec) |
3384 |
(inhibit-read-only t) |
3385 |
(inhibit-modification-hooks t) |
3386 |
(dedicated (window-dedicated-p)) |
3387 |
(hscroll (window-hscroll)) |
3388 |
window-configuration-change-hook |
3389 |
buffer-list-update-hook) |
3390 |
(with-current-buffer (get-buffer-create " *company-sps*") |
3391 |
(unwind-protect |
3392 |
(progn |
3393 |
(delete-region (point-min) (point-max)) |
3394 |
(insert str) |
3395 |
(setq-local buffer-invisibility-spec bis) |
3396 |
(when dedicated (set-window-dedicated-p nil nil)) |
3397 |
(set-window-buffer nil (current-buffer) t) |
3398 |
|
3399 |
(vertical-motion (cons (/ from (frame-char-width)) 0)) |
3400 |
(setq from-chars (point)) |
3401 |
(setq spw-from |
3402 |
(if (bobp) 0 |
3403 |
(car (window-text-pixel-size nil (point-min) (point) 55555)))) |
3404 |
(while (and (< spw-from from) |
3405 |
(not (eolp))) |
3406 |
(forward-char 1) |
3407 |
(setq spw-from |
3408 |
(car (window-text-pixel-size nil (point-min) (point) 55555))) |
3409 |
(setq from-chars (point))) |
3410 |
|
3411 |
(if (= from-chars (point-max)) |
3412 |
(if (and to (> to from)) |
3413 |
(propertize " " 'display `(space . (:width (,(- to from))))) |
3414 |
"") |
3415 |
(if (not to) |
3416 |
(setq to-chars (point-max)) |
3417 |
(vertical-motion (cons (/ to (frame-char-width)) 0)) |
3418 |
(setq to-chars (point)) |
3419 |
(setq spw-to |
3420 |
(if (bobp) 0 |
3421 |
(car (window-text-pixel-size nil (point-min) (point) 55555)))) |
3422 |
(while (and (< spw-to to) |
3423 |
(not (eolp))) |
3424 |
(setq spw-to-prev spw-to) |
3425 |
(forward-char 1) |
3426 |
(setq spw-to |
3427 |
(car (window-text-pixel-size nil (point-min) (point) 55555))) |
3428 |
(when (<= spw-to to) |
3429 |
(setq to-chars (point))))) |
3430 |
|
3431 |
(unless spw-to-prev (setq spw-to-prev spw-to)) |
3432 |
|
3433 |
(when (> spw-from from) |
3434 |
(setq front (propertize " " 'display |
3435 |
`(space . (:width (,(- spw-from from))))))) |
3436 |
(when (and to (/= spw-to to)) |
3437 |
(setq back (propertize |
3438 |
" " 'display |
3439 |
`(space . (:width (,(- to |
3440 |
(if (< spw-to to) |
3441 |
spw-to |
3442 |
spw-to-prev)))))))) |
3443 |
(concat front (buffer-substring from-chars to-chars) back))) |
3444 |
(set-window-buffer nil orig-buf t) |
3445 |
(set-window-hscroll nil hscroll) |
3446 |
(when dedicated |
3447 |
(set-window-dedicated-p nil dedicated)))))) |
3448 |
|
3449 |
(defun company-safe-substring (str from &optional to) |
3450 |
(let ((ll (length str))) |
3451 |
(if (> from ll) |
3452 |
"" |
3453 |
(if to |
3454 |
(concat (substring str from (min to ll)) |
3455 |
(company-space-string (max 0 (- to ll)))) |
3456 |
(substring str from))))) |
3457 |
|
3458 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
3459 |
|
3460 |
(defvar-local company-last-metadata nil) |
3461 |
|
3462 |
(defun company-fetch-metadata () |
3463 |
(let ((selected (nth (or company-selection 0) company-candidates))) |
3464 |
(unless (eq selected (car company-last-metadata)) |
3465 |
(setq company-last-metadata |
3466 |
(cons selected (company-call-backend 'meta selected)))) |
3467 |
(cdr company-last-metadata))) |
3468 |
|
3469 |
(defun company-doc-buffer (&optional string) |
3470 |
(with-current-buffer (get-buffer-create "*company-documentation*") |
3471 |
(erase-buffer) |
3472 |
(fundamental-mode) |
3473 |
(when string |
3474 |
(save-excursion |
3475 |
(insert string) |
3476 |
(visual-line-mode))) |
3477 |
(current-buffer))) |
3478 |
|
3479 |
(defvar company--electric-saved-window-configuration nil) |
3480 |
|
3481 |
(defvar company--electric-commands |
3482 |
'(scroll-other-window scroll-other-window-down mwheel-scroll) |
3483 |
"List of Commands that won't break out of electric commands.") |
3484 |
|
3485 |
(defun company--electric-command-p () |
3486 |
(memq this-command company--electric-commands)) |
3487 |
|
3488 |
(defun company--electric-restore-window-configuration () |
3489 |
"Restore window configuration (after electric commands)." |
3490 |
(when (and company--electric-saved-window-configuration |
3491 |
(not (company--electric-command-p))) |
3492 |
(set-window-configuration company--electric-saved-window-configuration) |
3493 |
(setq company--electric-saved-window-configuration nil))) |
3494 |
|
3495 |
(defmacro company--electric-do (&rest body) |
3496 |
(declare (indent 0) (debug t)) |
3497 |
`(when company-candidates |
3498 |
(cl-assert (null company--electric-saved-window-configuration)) |
3499 |
(setq company--electric-saved-window-configuration (current-window-configuration)) |
3500 |
(let ((height (window-height)) |
3501 |
(row (company--row))) |
3502 |
,@body |
3503 |
(and (< (window-height) height) |
3504 |
(< (- (window-height) row 2) company-tooltip-limit) |
3505 |
(recenter (- (window-height) row 2)))))) |
3506 |
|
3507 |
(defun company--unread-this-command-keys () |
3508 |
(when (> (length (this-command-keys)) 0) |
3509 |
(setq unread-command-events (nconc |
3510 |
(listify-key-sequence (this-command-keys)) |
3511 |
unread-command-events)) |
3512 |
(clear-this-command-keys t))) |
3513 |
|
3514 |
(defun company--show-doc-buffer () |
3515 |
"Show the documentation buffer for the selection." |
3516 |
(let ((other-window-scroll-buffer) |
3517 |
(selection (or company-selection 0))) |
3518 |
(let* ((selected (nth selection company-candidates)) |
3519 |
(doc-buffer (or (company-call-backend 'doc-buffer selected) |
3520 |
(user-error "No documentation available"))) |
3521 |
start) |
3522 |
(when (consp doc-buffer) |
3523 |
(setq start (cdr doc-buffer) |
3524 |
doc-buffer (car doc-buffer))) |
3525 |
(setq other-window-scroll-buffer (get-buffer doc-buffer)) |
3526 |
(let ((win (display-buffer doc-buffer t))) |
3527 |
(set-window-start win (if start start (point-min))))))) |
3528 |
|
3529 |
(defun company-show-doc-buffer (&optional toggle-auto-update) |
3530 |
"Show the documentation buffer for the selection. |
3531 |
With a prefix argument TOGGLE-AUTO-UPDATE, toggle the value of |
3532 |
`company-auto-update-doc'. When `company-auto-update-doc' is non-nil, |
3533 |
automatically show the documentation buffer for each selection." |
3534 |
(interactive "P") |
3535 |
(when toggle-auto-update |
3536 |
(setq company-auto-update-doc (not company-auto-update-doc))) |
3537 |
(company--electric-do |
3538 |
(company--show-doc-buffer))) |
3539 |
(put 'company-show-doc-buffer 'company-keep t) |
3540 |
|
3541 |
(defun company-show-location () |
3542 |
"Temporarily display a buffer showing the selected candidate in context." |
3543 |
(interactive) |
3544 |
(let (other-window-scroll-buffer) |
3545 |
(company--electric-do |
3546 |
(let* ((selected (nth company-selection company-candidates)) |
3547 |
(location (company-call-backend 'location selected)) |
3548 |
(pos (or (cdr location) (user-error "No location available"))) |
3549 |
(buffer (or (and (bufferp (car location)) (car location)) |
3550 |
(find-file-noselect (car location) t)))) |
3551 |
(setq other-window-scroll-buffer (get-buffer buffer)) |
3552 |
(with-selected-window (display-buffer buffer t) |
3553 |
(save-restriction |
3554 |
(widen) |
3555 |
(if (bufferp (car location)) |
3556 |
(goto-char pos) |
3557 |
(goto-char (point-min)) |
3558 |
(forward-line (1- pos)))) |
3559 |
(set-window-start nil (point))))))) |
3560 |
(put 'company-show-location 'company-keep t) |
3561 |
|
3562 |
;;; package functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
3563 |
|
3564 |
(defvar-local company-callback nil) |
3565 |
|
3566 |
(defun company-remove-callback (&optional _ignored) |
3567 |
(remove-hook 'company-completion-finished-hook company-callback t) |
3568 |
(remove-hook 'company-completion-cancelled-hook 'company-remove-callback t) |
3569 |
(remove-hook 'company-completion-finished-hook 'company-remove-callback t)) |
3570 |
|
3571 |
(defun company-begin-backend (backend &optional callback) |
3572 |
"Start a completion at point using BACKEND." |
3573 |
(interactive (let ((val (completing-read "Company backend: " |
3574 |
obarray |
3575 |
'functionp nil "company-"))) |
3576 |
(when val |
3577 |
(list (intern val))))) |
3578 |
(when (setq company-callback callback) |
3579 |
(add-hook 'company-completion-finished-hook company-callback nil t)) |
3580 |
(add-hook 'company-completion-cancelled-hook 'company-remove-callback nil t) |
3581 |
(add-hook 'company-completion-finished-hook 'company-remove-callback nil t) |
3582 |
(setq company-backend backend) |
3583 |
;; Return non-nil if active. |
3584 |
(or (company-manual-begin) |
3585 |
(user-error "Cannot complete at point"))) |
3586 |
|
3587 |
(defun company-begin-with (candidates |
3588 |
&optional prefix-length require-match callback) |
3589 |
"Start a completion at point. |
3590 |
CANDIDATES is the list of candidates to use and PREFIX-LENGTH is the length |
3591 |
of the prefix that already is in the buffer before point. |
3592 |
It defaults to 0. |
3593 |
|
3594 |
CALLBACK is a function called with the selected result if the user |
3595 |
successfully completes the input. |
3596 |
|
3597 |
Example: \(company-begin-with \\='\(\"foo\" \"foobar\" \"foobarbaz\"\)\)" |
3598 |
(let ((begin-marker (copy-marker (point) t))) |
3599 |
(company-begin-backend |
3600 |
(lambda (command &optional arg &rest _ignored) |
3601 |
(pcase command |
3602 |
(`prefix |
3603 |
(when (equal (point) (marker-position begin-marker)) |
3604 |
(buffer-substring (- (point) (or prefix-length 0)) (point)))) |
3605 |
(`candidates |
3606 |
(all-completions arg candidates)) |
3607 |
(`require-match |
3608 |
require-match))) |
3609 |
callback))) |
3610 |
|
3611 |
(declare-function find-library-name "find-func") |
3612 |
(declare-function lm-version "lisp-mnt") |
3613 |
|
3614 |
(defun company-version (&optional show-version) |
3615 |
"Get the Company version as string. |
3616 |
|
3617 |
If SHOW-VERSION is non-nil, show the version in the echo area." |
3618 |
(interactive (list t)) |
3619 |
(with-temp-buffer |
3620 |
(require 'find-func) |
3621 |
(insert-file-contents (find-library-name "company")) |
3622 |
(require 'lisp-mnt) |
3623 |
(if show-version |
3624 |
(message "Company version: %s" (lm-version)) |
3625 |
(lm-version)))) |
3626 |
|
3627 |
(defun company-diag () |
3628 |
"Pop a buffer with information about completions at point." |
3629 |
(interactive) |
3630 |
(let* ((bb company-backends) |
3631 |
(mode (symbol-name major-mode)) |
3632 |
backend |
3633 |
(prefix (cl-loop for b in bb |
3634 |
thereis (let ((company-backend b)) |
3635 |
(setq backend b) |
3636 |
(company-call-backend 'prefix)))) |
3637 |
(c-a-p-f completion-at-point-functions) |
3638 |
cc annotations) |
3639 |
(when (or (stringp prefix) (consp prefix)) |
3640 |
(let ((company-backend backend)) |
3641 |
(condition-case nil |
3642 |
(setq cc (company-call-backend 'candidates |
3643 |
(company--prefix-str prefix) |
3644 |
(company--suffix-str prefix)) |
3645 |
annotations |
3646 |
(mapcar |
3647 |
(lambda (c) (cons c (company-call-backend 'annotation c))) |
3648 |
cc)) |
3649 |
(error (setq annotations 'error))))) |
3650 |
(pop-to-buffer (get-buffer-create "*company-diag*")) |
3651 |
(setq buffer-read-only nil) |
3652 |
(erase-buffer) |
3653 |
(insert (format "Emacs %s (%s) of %s on %s" |
3654 |
emacs-version system-configuration |
3655 |
(format-time-string "%Y-%m-%d" emacs-build-time) |
3656 |
emacs-build-system)) |
3657 |
(insert "\nCompany " (company-version) "\n\n") |
3658 |
(insert "company-backends: " (pp-to-string bb)) |
3659 |
(insert "\n") |
3660 |
(insert "Used backend: " (pp-to-string backend)) |
3661 |
(insert "\n") |
3662 |
(when (if (listp backend) |
3663 |
(memq 'company-capf backend) |
3664 |
(eq backend 'company-capf)) |
3665 |
(insert "Value of c-a-p-f: " |
3666 |
(pp-to-string c-a-p-f))) |
3667 |
(insert "Major mode: " mode) |
3668 |
(insert "\n") |
3669 |
(insert "Prefix: " (pp-to-string prefix)) |
3670 |
(insert "\n") |
3671 |
(insert "Completions:") |
3672 |
(unless cc (insert " none")) |
3673 |
(if (eq annotations 'error) |
3674 |
(insert "(error fetching)") |
3675 |
(save-excursion |
3676 |
(dolist (c annotations) |
3677 |
(insert "\n " (prin1-to-string (car c))) |
3678 |
(when (cdr c) |
3679 |
(insert " " (prin1-to-string (cdr c))))))) |
3680 |
(special-mode))) |
3681 |
|
3682 |
;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
3683 |
|
3684 |
(defvar-local company--tooltip-current-width 0) |
3685 |
|
3686 |
(defun company-tooltip--lines-update-offset (selection num-lines limit) |
3687 |
(cl-decf limit 2) |
3688 |
(setq company-tooltip-offset |
3689 |
(max (min selection company-tooltip-offset) |
3690 |
(- selection -1 limit))) |
3691 |
|
3692 |
(when (<= company-tooltip-offset 1) |
3693 |
(cl-incf limit) |
3694 |
(setq company-tooltip-offset 0)) |
3695 |
|
3696 |
(when (>= company-tooltip-offset (- num-lines limit 1)) |
3697 |
(cl-incf limit) |
3698 |
(when (= selection (1- num-lines)) |
3699 |
(cl-decf company-tooltip-offset) |
3700 |
(when (<= company-tooltip-offset 1) |
3701 |
(setq company-tooltip-offset 0) |
3702 |
(cl-incf limit)))) |
3703 |
|
3704 |
limit) |
3705 |
|
3706 |
(defun company-tooltip--simple-update-offset (selection _num-lines limit) |
3707 |
(setq company-tooltip-offset |
3708 |
(if (< selection company-tooltip-offset) |
3709 |
selection |
3710 |
(max company-tooltip-offset |
3711 |
(- selection limit -1))))) |
3712 |
|
3713 |
;;; propertize |
3714 |
|
3715 |
(defun company-round-tab (arg) |
3716 |
(* (/ (+ arg tab-width) tab-width) tab-width)) |
3717 |
|
3718 |
(defun company-plainify (str) |
3719 |
(let ((prefix (get-text-property 0 'line-prefix str))) |
3720 |
(when (stringp prefix) ; Keep the original value unmodified, for no special reason. |
3721 |
(setq str (concat prefix str)) |
3722 |
(remove-text-properties 0 (length str) '(line-prefix) str))) |
3723 |
(let* ((pieces (split-string str "\t")) |
3724 |
(copy pieces)) |
3725 |
(while (cdr copy) |
3726 |
(setcar copy (company-safe-substring |
3727 |
(car copy) 0 (company-round-tab (string-width (car copy))))) |
3728 |
(pop copy)) |
3729 |
(apply 'concat pieces))) |
3730 |
|
3731 |
(defun company--common-or-matches (value &optional suffix) |
3732 |
(let ((matches (company-call-backend 'match value))) |
3733 |
(when (integerp matches) |
3734 |
(setq matches `((0 . ,matches)))) |
3735 |
(or matches |
3736 |
(and company-common `((0 . ,(length company-common)) |
3737 |
,@(list |
3738 |
(cons |
3739 |
(- (length value) |
3740 |
(length (or suffix |
3741 |
(cdr (company--boundaries value))))) |
3742 |
(length value))))) |
3743 |
nil))) |
3744 |
|
3745 |
(defun company-fill-propertize (value annotation width selected left right) |
3746 |
(let* ((margin (length left)) |
3747 |
(common (company--common-or-matches value)) |
3748 |
(_ (setq value |
3749 |
(company--clean-string |
3750 |
(company-reformat (company--pre-render value))) |
3751 |
annotation (and annotation |
3752 |
(company--clean-string |
3753 |
(company--pre-render annotation t))))) |
3754 |
(ann-ralign company-tooltip-align-annotations) |
3755 |
(ann-padding (or company-tooltip-annotation-padding 0)) |
3756 |
(ann-truncate (< width |
3757 |
(+ (length value) (length annotation) |
3758 |
ann-padding))) |
3759 |
(ann-start (+ margin |
3760 |
(if ann-ralign |
3761 |
(if ann-truncate |
3762 |
(+ (length value) ann-padding) |
3763 |
(- width (length annotation))) |
3764 |
(+ (length value) ann-padding)))) |
3765 |
(ann-end (min (+ ann-start (length annotation)) (+ margin width))) |
3766 |
(line (concat left |
3767 |
(if (or ann-truncate (not ann-ralign)) |
3768 |
(company-safe-substring |
3769 |
(concat value |
3770 |
(when annotation |
3771 |
(company-space-string ann-padding)) |
3772 |
annotation) |
3773 |
0 width) |
3774 |
(concat |
3775 |
(company-safe-substring value 0 |
3776 |
(- width (length annotation))) |
3777 |
annotation)) |
3778 |
right))) |
3779 |
(setq width (+ width margin (length right))) |
3780 |
|
3781 |
(font-lock-append-text-property 0 width 'mouse-face |
3782 |
'company-tooltip-mouse |
3783 |
line) |
3784 |
(when (< ann-start ann-end) |
3785 |
(add-face-text-property ann-start ann-end |
3786 |
(if selected |
3787 |
'company-tooltip-annotation-selection |
3788 |
'company-tooltip-annotation) |
3789 |
t line)) |
3790 |
(cl-loop |
3791 |
with width = (- width (length right)) |
3792 |
for (comp-beg . comp-end) in common |
3793 |
for inline-beg = (+ margin comp-beg) |
3794 |
for inline-end = (min (+ margin comp-end) width) |
3795 |
when (< inline-beg width) |
3796 |
do (add-face-text-property inline-beg inline-end |
3797 |
(if selected |
3798 |
'company-tooltip-common-selection |
3799 |
'company-tooltip-common) |
3800 |
nil line)) |
3801 |
(when (let ((re (funcall company-search-regexp-function |
3802 |
company-search-string))) |
3803 |
(and (not (string-empty-p re)) |
3804 |
(string-match re value))) |
3805 |
(pcase-dolist (`(,mbeg . ,mend) (company--search-chunks)) |
3806 |
(let ((beg (+ margin mbeg)) |
3807 |
(end (+ margin mend)) |
3808 |
(width (- width (length right)))) |
3809 |
(when (< beg width) |
3810 |
(add-face-text-property beg (min end width) |
3811 |
(if selected |
3812 |
'company-tooltip-search-selection |
3813 |
'company-tooltip-search) |
3814 |
nil line))))) |
3815 |
(when selected |
3816 |
(add-face-text-property 0 width 'company-tooltip-selection t line)) |
3817 |
|
3818 |
(when (company-call-backend 'deprecated value) |
3819 |
(add-face-text-property margin |
3820 |
(min |
3821 |
(+ margin (length value)) |
3822 |
(- width (length right))) |
3823 |
'company-tooltip-deprecated t line)) |
3824 |
|
3825 |
(add-face-text-property 0 width 'company-tooltip t line) |
3826 |
line)) |
3827 |
|
3828 |
(defun company--search-chunks () |
3829 |
(let ((md (match-data t)) |
3830 |
res) |
3831 |
(if (<= (length md) 2) |
3832 |
(push (cons (nth 0 md) (nth 1 md)) res) |
3833 |
(while (setq md (nthcdr 2 md)) |
3834 |
(when (car md) |
3835 |
(push (cons (car md) (cadr md)) res)))) |
3836 |
res)) |
3837 |
|
3838 |
(defun company--pre-render (str &optional annotation-p) |
3839 |
(or (company-call-backend 'pre-render str annotation-p) |
3840 |
(progn |
3841 |
(when (or (text-property-not-all 0 (length str) 'face nil str) |
3842 |
(text-property-not-all 0 (length str) 'mouse-face nil str)) |
3843 |
(setq str (copy-sequence str)) |
3844 |
(remove-text-properties 0 (length str) |
3845 |
'(face nil font-lock-face nil mouse-face nil) |
3846 |
str)) |
3847 |
str))) |
3848 |
|
3849 |
(defun company--clean-string (str) |
3850 |
(let* ((add-pixels 0) |
3851 |
(add-length 0) |
3852 |
(new-str |
3853 |
(replace-regexp-in-string |
3854 |
"\\([^[:graph:] ]\\)\\|\\(\ufeff\\)\\|[[:multibyte:]]+" |
3855 |
(lambda (match) |
3856 |
(cond |
3857 |
((match-beginning 1) |
3858 |
;; FIXME: Better char for 'non-printable'? |
3859 |
;; We shouldn't get any of these, but sometimes we might. |
3860 |
;; The official "replacement character" is not supported by some fonts. |
3861 |
;;"\ufffd" |
3862 |
(if (equal match "\n") |
3863 |
(propertize "\\\\n" 'face 'font-lock-escape-face) |
3864 |
"?") |
3865 |
) |
3866 |
((match-beginning 2) |
3867 |
;; Zero-width non-breakable space. |
3868 |
"") |
3869 |
(t |
3870 |
;; FIXME: Maybe move that counting later to a non-replacement loop. |
3871 |
(let ((msw (company--string-width match))) |
3872 |
(cl-incf add-pixels |
3873 |
(- (* (default-font-width) |
3874 |
msw) |
3875 |
(company--string-pixel-width match))) |
3876 |
(cl-incf add-length (- msw (length match))) |
3877 |
match |
3878 |
)) |
3879 |
)) |
3880 |
str))) |
3881 |
(if (>= 0 add-length) |
3882 |
new-str |
3883 |
(concat new-str |
3884 |
(propertize |
3885 |
(make-string add-length ?\ufeff) |
3886 |
'display `(space . (:width (,add-pixels)))))))) |
3887 |
|
3888 |
;;; replace |
3889 |
|
3890 |
(defun company-buffer-lines (beg end) |
3891 |
(goto-char beg) |
3892 |
(let (lines lines-moved) |
3893 |
(while (and (not (eobp)) ; http://debbugs.gnu.org/19553 |
3894 |
(> (setq lines-moved (vertical-motion 1)) 0) |
3895 |
(<= (point) end)) |
3896 |
(let ((bound (min end (point)))) |
3897 |
;; A visual line can contain several physical lines (e.g. with outline's |
3898 |
;; folding overlay). Take only the first one. |
3899 |
(push (buffer-substring beg |
3900 |
(save-excursion |
3901 |
(goto-char beg) |
3902 |
(re-search-forward "$" bound 'move) |
3903 |
(point))) |
3904 |
lines)) |
3905 |
;; One physical line can be displayed as several visual ones as well: |
3906 |
;; add empty strings to the list, to even the count. |
3907 |
(dotimes (_ (1- lines-moved)) |
3908 |
(push "" lines)) |
3909 |
(setq beg (point))) |
3910 |
(unless (eq beg end) |
3911 |
(push (buffer-substring beg end) lines)) |
3912 |
(nreverse lines))) |
3913 |
|
3914 |
(defun company-modify-line (old new offset) |
3915 |
(if (not new) |
3916 |
;; Avoid modifying OLD, e.g. to avoid "blinking" with half-spaces for |
3917 |
;; double-width (or usually fractional) characters. |
3918 |
old |
3919 |
(concat (company-safe-pixel-substring old 0 offset) |
3920 |
new |
3921 |
(company-safe-pixel-substring old (+ offset (company--string-pixel-width new)))))) |
3922 |
|
3923 |
(defun company--show-numbers (numbered) |
3924 |
(format " %s" (if (<= numbered 10) |
3925 |
(mod numbered 10) |
3926 |
" "))) |
3927 |
(make-obsolete |
3928 |
'company--show-numbers |
3929 |
"use `company-quick-access-hint-key' instead, |
3930 |
but adjust the expected values appropriately." |
3931 |
"0.10.0") |
3932 |
|
3933 |
(defsubst company--window-height () |
3934 |
(if (fboundp 'window-screen-lines) |
3935 |
(floor (window-screen-lines)) |
3936 |
(window-body-height))) |
3937 |
|
3938 |
(defun company--window-width (&optional pixelwise) |
3939 |
(let ((ww (window-body-width nil pixelwise))) |
3940 |
;; Account for the line continuation column. |
3941 |
(when (zerop (cadr (window-fringes))) |
3942 |
(cl-decf ww (if pixelwise (company--string-pixel-width ">") 1))) |
3943 |
(when (bound-and-true-p display-line-numbers) |
3944 |
(cl-decf ww |
3945 |
(if pixelwise |
3946 |
(line-number-display-width t) |
3947 |
(+ 2 (line-number-display-width))))) |
3948 |
;; whitespace-mode with newline-mark |
3949 |
(when (and buffer-display-table |
3950 |
(aref buffer-display-table ?\n)) |
3951 |
(cl-decf ww |
3952 |
(if pixelwise |
3953 |
(company--string-pixel-width "\n") |
3954 |
(1- (length (aref buffer-display-table ?\n)))))) |
3955 |
ww)) |
3956 |
|
3957 |
(defun company--face-attribute (face attr) |
3958 |
;; Like `face-attribute', but accounts for faces that have been remapped to |
3959 |
;; another face, a list of faces, or a face spec. |
3960 |
(cond ((null face) nil) |
3961 |
((symbolp face) |
3962 |
(let ((remap (cdr (assq face face-remapping-alist)))) |
3963 |
(if remap |
3964 |
(company--face-attribute |
3965 |
;; Faces can be remapped to their unremapped selves, but that |
3966 |
;; would cause us infinite recursion. |
3967 |
(if (listp remap) (remq face remap) remap) |
3968 |
attr) |
3969 |
(face-attribute face attr nil t)))) |
3970 |
((keywordp (car-safe face)) |
3971 |
(or (plist-get face attr) |
3972 |
(company--face-attribute (plist-get face :inherit) attr))) |
3973 |
((listp face) |
3974 |
(cl-find-if #'stringp |
3975 |
(mapcar (lambda (f) (company--face-attribute f attr)) |
3976 |
face))))) |
3977 |
|
3978 |
(defun company--replacement-string (lines column-offset old column nl &optional align-top) |
3979 |
(cl-decf column column-offset) |
3980 |
|
3981 |
(when (< column 0) (setq column 0)) |
3982 |
|
3983 |
(when (and align-top company-tooltip-flip-when-above) |
3984 |
(setq lines (reverse lines))) |
3985 |
|
3986 |
(let* ((px-width (company--string-pixel-width (car lines))) |
3987 |
;; The (display (space :width (..))) spec is only applied to the |
3988 |
;; visible part of the buffer (past hscroll), so subtracting |
3989 |
;; window-scroll here is a good idea. But then we also need to slice |
3990 |
;; the "old" strings so the hidden contents don't get shown. |
3991 |
;; XXX: `auto-hscroll-mode' set to `current-line' is not supported. |
3992 |
(px-col (* (- column (window-hscroll)) (default-font-width))) |
3993 |
(remaining-px (- (company--window-width t) px-col)) |
3994 |
(hscroll-space (when (> (window-hscroll) 0) |
3995 |
(company-space-string (window-hscroll)))) |
3996 |
new) |
3997 |
(when (> px-width remaining-px) |
3998 |
(cl-decf px-col (- px-width remaining-px))) |
3999 |
(when hscroll-space |
4000 |
(setq old (mapcar (lambda (s) (company-safe-substring s (window-hscroll))) |
4001 |
old))) |
4002 |
(when align-top |
4003 |
;; untouched lines first |
4004 |
(dotimes (_ (- (length old) (length lines))) |
4005 |
(push (pop old) new))) |
4006 |
;; length into old lines. |
4007 |
(while old |
4008 |
(push (company-modify-line (pop old) (pop lines) px-col) |
4009 |
new)) |
4010 |
;; Append whole new lines. |
4011 |
(while lines |
4012 |
(push (concat (company-safe-pixel-substring "" 0 px-col) (pop lines)) |
4013 |
new)) |
4014 |
|
4015 |
;; XXX: Also see branch 'more-precise-extend'. |
4016 |
(let* ((nl-face `(,@(when (version<= "27" emacs-version) |
4017 |
'(:extend t)) |
4018 |
:inverse-video nil |
4019 |
:background ,(or (company--face-attribute 'default :background) |
4020 |
(face-attribute 'default :background nil t)))) |
4021 |
(str (apply #'concat |
4022 |
(when nl " \n") |
4023 |
(cl-mapcan |
4024 |
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=42552#23 |
4025 |
(lambda (line) (list hscroll-space line (propertize "\n" 'face nl-face))) |
4026 |
(nreverse new))))) |
4027 |
;; https://debbugs.gnu.org/38563 |
4028 |
(add-face-text-property 0 (length str) 'default t str) |
4029 |
(when nl (put-text-property 0 1 'cursor t str)) |
4030 |
str))) |
4031 |
|
4032 |
(defun company--create-lines (selection limit) |
4033 |
(let ((len company-candidates-length) |
4034 |
(window-width (company--window-width)) |
4035 |
(company-tooltip-annotation-padding |
4036 |
(or company-tooltip-annotation-padding |
4037 |
(if company-tooltip-align-annotations 1 0))) |
4038 |
left-margins |
4039 |
left-margin-size |
4040 |
right-margin |
4041 |
lines |
4042 |
width |
4043 |
lines-copy |
4044 |
items |
4045 |
previous |
4046 |
remainder |
4047 |
scrollbar-bounds) |
4048 |
|
4049 |
;; Maybe clear old offset. |
4050 |
(when (< len (+ company-tooltip-offset limit)) |
4051 |
(setq company-tooltip-offset 0)) |
4052 |
|
4053 |
(let ((selection (or selection 0))) |
4054 |
;; Scroll to offset. |
4055 |
(if (eq company-tooltip-offset-display 'lines) |
4056 |
(setq limit (company-tooltip--lines-update-offset selection len limit)) |
4057 |
(company-tooltip--simple-update-offset selection len limit)) |
4058 |
|
4059 |
(cond |
4060 |
((eq company-tooltip-offset-display 'scrollbar) |
4061 |
(setq scrollbar-bounds (company--scrollbar-bounds company-tooltip-offset |
4062 |
limit len))) |
4063 |
((eq company-tooltip-offset-display 'lines) |
4064 |
(when (> company-tooltip-offset 0) |
4065 |
(setq previous (format "...(%d)" company-tooltip-offset))) |
4066 |
(setq remainder (- len limit company-tooltip-offset) |
4067 |
remainder (when (> remainder 0) |
4068 |
(setq remainder (format "...(%d)" remainder))))))) |
4069 |
|
4070 |
(when selection |
4071 |
(cl-decf selection company-tooltip-offset)) |
4072 |
|
4073 |
(setq width (max (length previous) (length remainder)) |
4074 |
lines (nthcdr company-tooltip-offset company-candidates) |
4075 |
right-margin (company--right-margin limit len) |
4076 |
len (min limit len) |
4077 |
lines-copy lines) |
4078 |
|
4079 |
(when scrollbar-bounds (cl-decf window-width)) |
4080 |
|
4081 |
(when company-format-margin-function |
4082 |
(let ((lines-copy lines-copy) |
4083 |
res) |
4084 |
(dotimes (i len) |
4085 |
(push (funcall company-format-margin-function |
4086 |
(pop lines-copy) |
4087 |
(equal selection i)) |
4088 |
res)) |
4089 |
(setq left-margins (nreverse res)))) |
4090 |
|
4091 |
;; XXX: format-function outputting shorter strings than the |
4092 |
;; default margin is not supported (yet?). |
4093 |
(setq left-margin-size (apply #'max company-tooltip-margin |
4094 |
(mapcar #'length left-margins))) |
4095 |
|
4096 |
(cl-decf window-width company-tooltip-margin) |
4097 |
(cl-decf window-width left-margin-size) |
4098 |
|
4099 |
(dotimes (_ len) |
4100 |
(let* ((value (pop lines-copy)) |
4101 |
(annotation (company-call-backend 'annotation value)) |
4102 |
(left (or (pop left-margins) |
4103 |
(company-space-string left-margin-size)))) |
4104 |
(when annotation |
4105 |
(when company-tooltip-align-annotations |
4106 |
;; `lisp-completion-at-point' adds a space. |
4107 |
(setq annotation (string-trim-left annotation)))) |
4108 |
(push (list value annotation left) items) |
4109 |
(setq width (max (+ (company--string-width value) |
4110 |
(if annotation |
4111 |
(+ (company--string-width annotation) |
4112 |
company-tooltip-annotation-padding) |
4113 |
0)) |
4114 |
width)))) |
4115 |
|
4116 |
(setq width (min window-width |
4117 |
company-tooltip-maximum-width |
4118 |
(max company-tooltip-minimum-width |
4119 |
(if company-show-quick-access |
4120 |
(+ 2 width) |
4121 |
width)))) |
4122 |
|
4123 |
(when company-tooltip-width-grow-only |
4124 |
(setq width (max company--tooltip-current-width width)) |
4125 |
(setq company--tooltip-current-width width)) |
4126 |
|
4127 |
(let ((items (nreverse items)) |
4128 |
(row (if company-show-quick-access 0 99999)) |
4129 |
new) |
4130 |
(when previous |
4131 |
(push (company--scrollpos-line previous width left-margin-size) new)) |
4132 |
|
4133 |
(dotimes (i len) |
4134 |
(let* ((item (pop items)) |
4135 |
(str (car item)) |
4136 |
(annotation (cadr item)) |
4137 |
(left (nth 2 item)) |
4138 |
(right right-margin) |
4139 |
(width width) |
4140 |
(selected (equal selection i))) |
4141 |
(when company-show-quick-access |
4142 |
(let ((quick-access (gv-ref (if (eq company-show-quick-access 'left) |
4143 |
left right))) |
4144 |
(qa-hint (company-tooltip--format-quick-access-hint |
4145 |
row selected))) |
4146 |
(cl-decf width (company--string-width qa-hint)) |
4147 |
(setf (gv-deref quick-access) |
4148 |
(concat qa-hint (gv-deref quick-access)))) |
4149 |
(cl-incf row)) |
4150 |
(push (concat |
4151 |
(company-fill-propertize str annotation |
4152 |
width selected |
4153 |
left |
4154 |
right) |
4155 |
(when scrollbar-bounds |
4156 |
(company--scrollbar i scrollbar-bounds))) |
4157 |
new))) |
4158 |
|
4159 |
(when remainder |
4160 |
(push (company--scrollpos-line remainder width left-margin-size) new)) |
4161 |
|
4162 |
(cons |
4163 |
left-margin-size |
4164 |
(nreverse new))))) |
4165 |
|
4166 |
(defun company--scrollbar-bounds (offset limit length) |
4167 |
(when (> length limit) |
4168 |
(let* ((size (ceiling (* limit (float limit)) length)) |
4169 |
(lower (floor (* limit (float offset)) length)) |
4170 |
(upper (+ lower size -1))) |
4171 |
(cons lower upper)))) |
4172 |
|
4173 |
(defun company--scrollbar (i bounds) |
4174 |
(let* ((scroll-width (ceiling (* (default-font-width) |
4175 |
company-tooltip-scrollbar-width)))) |
4176 |
(propertize " " |
4177 |
'display `(space . (:width (,scroll-width))) |
4178 |
'face |
4179 |
(if (and (>= i (car bounds)) (<= i (cdr bounds))) |
4180 |
'company-tooltip-scrollbar-thumb |
4181 |
'company-tooltip-scrollbar-track)))) |
4182 |
|
4183 |
(defun company--right-margin (limit length) |
4184 |
(if (or (not (eq company-tooltip-offset-display 'scrollbar)) |
4185 |
(not (display-graphic-p)) |
4186 |
(= company-tooltip-scrollbar-width 1) |
4187 |
(<= length limit)) |
4188 |
(company-space-string company-tooltip-margin) |
4189 |
(let* ((scroll-width (ceiling (* (default-font-width) |
4190 |
company-tooltip-scrollbar-width))) |
4191 |
(rest-width (- (* (default-font-width) company-tooltip-margin) |
4192 |
scroll-width))) |
4193 |
(propertize |
4194 |
(company-space-string company-tooltip-margin) |
4195 |
'display `(space . (:width (,rest-width))))))) |
4196 |
|
4197 |
(defun company--scrollpos-line (text width fancy-margin-width) |
4198 |
(propertize (concat (company-space-string company-tooltip-margin) |
4199 |
(company-safe-substring text 0 width) |
4200 |
(company-space-string fancy-margin-width)) |
4201 |
'face 'company-tooltip)) |
4202 |
|
4203 |
(defun company-tooltip--format-quick-access-hint (row selected) |
4204 |
"Format a quick-access hint for outputting on a tooltip's ROW. |
4205 |
Value of SELECTED determines the added face." |
4206 |
(propertize (format "%2s" (funcall company-quick-access-hint-function row)) |
4207 |
'face |
4208 |
(if selected |
4209 |
'company-tooltip-quick-access-selection |
4210 |
'company-tooltip-quick-access))) |
4211 |
|
4212 |
;; show |
4213 |
|
4214 |
(defvar-local company-pseudo-tooltip-overlay nil) |
4215 |
|
4216 |
(defun company--inside-tooltip-p (event-col-row row height) |
4217 |
(let* ((ovl company-pseudo-tooltip-overlay) |
4218 |
(column (overlay-get ovl 'company-column)) |
4219 |
(width (overlay-get ovl 'company-width)) |
4220 |
(evt-col (car event-col-row)) |
4221 |
(evt-row (cdr event-col-row))) |
4222 |
(and (>= evt-col column) |
4223 |
(< evt-col (+ column width)) |
4224 |
(if (> height 0) |
4225 |
(and (> evt-row row) |
4226 |
(<= evt-row (+ row height) )) |
4227 |
(and (< evt-row row) |
4228 |
(>= evt-row (+ row height))))))) |
4229 |
|
4230 |
(defun company--pseudo-tooltip-height () |
4231 |
"Calculate the appropriate tooltip height. |
4232 |
Returns a negative number if the tooltip should be displayed above point." |
4233 |
(let* ((lines (company--row)) |
4234 |
(below (- (company--window-height) 1 lines))) |
4235 |
(if (and (< below (min company-tooltip-minimum company-candidates-length)) |
4236 |
(> lines below)) |
4237 |
(- (max 3 (min company-tooltip-limit lines))) |
4238 |
(max 3 (min company-tooltip-limit below))))) |
4239 |
|
4240 |
(defun company-pseudo-tooltip-show (row column selection) |
4241 |
(company-pseudo-tooltip-hide) |
4242 |
|
4243 |
(let* ((height (company--pseudo-tooltip-height)) |
4244 |
above) |
4245 |
|
4246 |
(when (< height 0) |
4247 |
(setq row (+ row height -1) |
4248 |
above t)) |
4249 |
|
4250 |
;; This can happen in Emacs versions which allow arbitrary scrolling, |
4251 |
;; such as Yamamoto's Mac Port. |
4252 |
(unless (pos-visible-in-window-p (window-start)) |
4253 |
(cl-decf row)) |
4254 |
|
4255 |
(let (nl beg end ov args) |
4256 |
(save-excursion |
4257 |
(setq nl (< (move-to-window-line row) row)) |
4258 |
;; HACK: Very specific to the log-edit buffer. Could alternatively |
4259 |
;; look up the `display-line-numbers-disable' property, but with |
4260 |
;; larger consequences. |
4261 |
(when (and (not nl) (> height 0)) |
4262 |
(while (eq (get-char-property (point) 'face) |
4263 |
'log-edit-headers-separator) |
4264 |
(vertical-motion 1))) |
4265 |
(setq beg (point) |
4266 |
end (save-excursion |
4267 |
(vertical-motion (abs height)) |
4268 |
(point)) |
4269 |
ov (make-overlay beg end nil t) |
4270 |
args (list (mapcar 'company-plainify |
4271 |
(company-buffer-lines beg end)) |
4272 |
column nl above))) |
4273 |
|
4274 |
(setq company-pseudo-tooltip-overlay ov) |
4275 |
(overlay-put ov 'company-replacement-args args) |
4276 |
|
4277 |
(let* ((lines-and-offset (company--create-lines selection (abs height))) |
4278 |
(lines (cdr lines-and-offset)) |
4279 |
(column-offset (car lines-and-offset))) |
4280 |
(overlay-put ov 'company-display |
4281 |
(apply 'company--replacement-string |
4282 |
lines column-offset args)) |
4283 |
(overlay-put ov 'company-width (company--string-width (car lines)))) |
4284 |
|
4285 |
(overlay-put ov 'company-column column) |
4286 |
(overlay-put ov 'company-height height)))) |
4287 |
|
4288 |
(defun company-pseudo-tooltip-show-at-point (pos column-offset) |
4289 |
(let* ((col-row (company--col-row pos)) |
4290 |
(col (- (car col-row) column-offset))) |
4291 |
(when (< col 0) (setq col 0)) |
4292 |
(company--with-face-remappings |
4293 |
(company-pseudo-tooltip-show (1+ (cdr col-row)) col company-selection)))) |
4294 |
|
4295 |
(defun company-pseudo-tooltip-edit (selection) |
4296 |
(let* ((height (overlay-get company-pseudo-tooltip-overlay 'company-height)) |
4297 |
(lines-and-offset (company--create-lines selection (abs height))) |
4298 |
(lines (cdr lines-and-offset)) |
4299 |
(column-offset (car lines-and-offset))) |
4300 |
(overlay-put company-pseudo-tooltip-overlay 'company-width |
4301 |
(company--string-width (car lines))) |
4302 |
(overlay-put company-pseudo-tooltip-overlay 'company-display |
4303 |
(apply 'company--replacement-string |
4304 |
lines column-offset |
4305 |
(overlay-get company-pseudo-tooltip-overlay |
4306 |
'company-replacement-args))))) |
4307 |
|
4308 |
(defun company-pseudo-tooltip-hide () |
4309 |
(when company-pseudo-tooltip-overlay |
4310 |
(delete-overlay company-pseudo-tooltip-overlay) |
4311 |
(setq company-pseudo-tooltip-overlay nil))) |
4312 |
|
4313 |
(defun company-pseudo-tooltip-hide-temporarily () |
4314 |
(when (overlayp company-pseudo-tooltip-overlay) |
4315 |
(overlay-put company-pseudo-tooltip-overlay 'invisible nil) |
4316 |
(overlay-put company-pseudo-tooltip-overlay 'line-prefix nil) |
4317 |
(overlay-put company-pseudo-tooltip-overlay 'before-string nil) |
4318 |
(overlay-put company-pseudo-tooltip-overlay 'display nil) |
4319 |
(overlay-put company-pseudo-tooltip-overlay 'face nil))) |
4320 |
|
4321 |
(defun company-pseudo-tooltip-unhide () |
4322 |
(when company-pseudo-tooltip-overlay |
4323 |
(let* ((ov company-pseudo-tooltip-overlay) |
4324 |
(disp (overlay-get ov 'company-display))) |
4325 |
;; Beat outline's folding overlays. |
4326 |
;; And Flymake (53). And Flycheck (110). |
4327 |
(overlay-put ov 'priority 111) |
4328 |
;; visual-line-mode |
4329 |
(when (and (memq (char-before (overlay-start ov)) '(?\s ?\t)) |
4330 |
;; not eob |
4331 |
(not (nth 2 (overlay-get ov 'company-replacement-args)))) |
4332 |
(setq disp (concat "\n" disp))) |
4333 |
;; No (extra) prefix for the first line. |
4334 |
(overlay-put ov 'line-prefix "") |
4335 |
(overlay-put ov 'before-string disp) |
4336 |
;; `display' is better than `invisible': |
4337 |
;; https://debbugs.gnu.org/18285 |
4338 |
;; https://debbugs.gnu.org/20847 |
4339 |
;; https://debbugs.gnu.org/42521 |
4340 |
(overlay-put ov 'display "") |
4341 |
(overlay-put ov 'window (selected-window))))) |
4342 |
|
4343 |
(defun company-pseudo-tooltip-guard (prefix) |
4344 |
(list |
4345 |
(- (point) (length prefix)) |
4346 |
(save-excursion (beginning-of-visual-line)) |
4347 |
(window-width) |
4348 |
(let ((ov company-pseudo-tooltip-overlay) |
4349 |
(overhang (save-excursion (end-of-visual-line) |
4350 |
(- (line-end-position) (point))))) |
4351 |
(when (>= (overlay-get ov 'company-height) 0) |
4352 |
(cons |
4353 |
(buffer-substring-no-properties (point) (overlay-start ov)) |
4354 |
(when (>= overhang 0) overhang)))))) |
4355 |
|
4356 |
(defun company-pseudo-tooltip-frontend (command) |
4357 |
"`company-mode' frontend similar to a tooltip but based on overlays." |
4358 |
(cl-case command |
4359 |
(pre-command (company-pseudo-tooltip-hide-temporarily)) |
4360 |
(unhide |
4361 |
(let ((ov company-pseudo-tooltip-overlay)) |
4362 |
(when (and ov (> (overlay-get ov 'company-height) 0)) |
4363 |
;; Sleight of hand: if the current line wraps, we adjust the |
4364 |
;; start of the overlay so that the popup does not zig-zag, |
4365 |
;; but don't update the popup's background. This seems just |
4366 |
;; non-annoying enough to avoid the work required for the latter. |
4367 |
(save-excursion |
4368 |
(vertical-motion 1) |
4369 |
(unless (= (point) (overlay-start ov)) |
4370 |
(move-overlay ov (point) (overlay-end ov)))))) |
4371 |
(company-pseudo-tooltip-unhide)) |
4372 |
(post-command |
4373 |
(let ((prefix (car (company--boundaries))) |
4374 |
guard) |
4375 |
(unless (when (overlayp company-pseudo-tooltip-overlay) |
4376 |
(let* ((ov company-pseudo-tooltip-overlay) |
4377 |
(old-height (overlay-get ov 'company-height)) |
4378 |
(new-height (company--pseudo-tooltip-height))) |
4379 |
(and |
4380 |
(>= (* old-height new-height) 0) |
4381 |
(>= (abs old-height) (abs new-height)) |
4382 |
(equal (setq guard (company-pseudo-tooltip-guard prefix)) |
4383 |
(overlay-get ov 'company-guard))))) |
4384 |
;; Redraw needed. |
4385 |
(company-pseudo-tooltip-show-at-point (point) |
4386 |
(length prefix)) |
4387 |
(overlay-put company-pseudo-tooltip-overlay |
4388 |
'company-guard (or guard |
4389 |
(company-pseudo-tooltip-guard prefix))))) |
4390 |
(company-pseudo-tooltip-unhide)) |
4391 |
(show (setq company--tooltip-current-width 0)) |
4392 |
(hide (company-pseudo-tooltip-hide) |
4393 |
(setq company-tooltip-offset 0)) |
4394 |
(update (when (overlayp company-pseudo-tooltip-overlay) |
4395 |
(company--with-face-remappings |
4396 |
(company-pseudo-tooltip-edit company-selection)))) |
4397 |
(select-mouse |
4398 |
(let ((event-col-row (company--event-col-row company-mouse-event)) |
4399 |
(ovl-row (company--row)) |
4400 |
(ovl-height (and company-pseudo-tooltip-overlay |
4401 |
(min (overlay-get company-pseudo-tooltip-overlay |
4402 |
'company-height) |
4403 |
company-candidates-length)))) |
4404 |
(cond ((and ovl-height |
4405 |
(company--inside-tooltip-p event-col-row ovl-row ovl-height)) |
4406 |
(company-set-selection (+ (cdr event-col-row) |
4407 |
(1- company-tooltip-offset) |
4408 |
(if (and (eq company-tooltip-offset-display 'lines) |
4409 |
(not (zerop company-tooltip-offset))) |
4410 |
-1 0) |
4411 |
(- ovl-row) |
4412 |
(if (< ovl-height 0) |
4413 |
(- 1 ovl-height) |
4414 |
0))) |
4415 |
t)))))) |
4416 |
|
4417 |
(defun company-pseudo-tooltip-unless-just-one-frontend (command) |
4418 |
"`company-pseudo-tooltip-frontend', but not shown for single candidates." |
4419 |
(unless (and (memq command '(post-command unhide)) |
4420 |
(company--show-inline-p)) |
4421 |
(company-pseudo-tooltip-frontend command))) |
4422 |
|
4423 |
(defun company-pseudo-tooltip--ujofwd-on-timer (command) |
4424 |
(when company-candidates |
4425 |
(company-pseudo-tooltip-unless-just-one-frontend-with-delay command))) |
4426 |
|
4427 |
(defun company-pseudo-tooltip-unless-just-one-frontend-with-delay (command) |
4428 |
"`compandy-pseudo-tooltip-frontend', but shown after a delay. |
4429 |
Delay is determined by `company-tooltip-idle-delay'." |
4430 |
(defvar company-preview-overlay) |
4431 |
(when (and (memq command '(pre-command hide)) |
4432 |
company-tooltip-timer) |
4433 |
(cancel-timer company-tooltip-timer) |
4434 |
(setq company-tooltip-timer nil)) |
4435 |
(cl-case command |
4436 |
(post-command |
4437 |
(if (or company-tooltip-timer |
4438 |
(overlayp company-pseudo-tooltip-overlay)) |
4439 |
(if (not (overlayp company-preview-overlay)) |
4440 |
(company-pseudo-tooltip-unless-just-one-frontend command) |
4441 |
(let (company-tooltip-timer) |
4442 |
(company-call-frontends 'pre-command)) |
4443 |
(company-call-frontends 'post-command)) |
4444 |
(setq company-tooltip-timer |
4445 |
(run-with-timer company-tooltip-idle-delay nil |
4446 |
'company-pseudo-tooltip--ujofwd-on-timer |
4447 |
'post-command)))) |
4448 |
(unhide |
4449 |
(when (overlayp company-pseudo-tooltip-overlay) |
4450 |
(company-pseudo-tooltip-unless-just-one-frontend command))) |
4451 |
(t |
4452 |
(company-pseudo-tooltip-unless-just-one-frontend command)))) |
4453 |
|
4454 |
;;; overlay ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
4455 |
|
4456 |
(defvar-local company-preview-overlay nil) |
4457 |
|
4458 |
(defun company-preview-show-at-point (pos completion &optional boundaries) |
4459 |
(company-preview-hide) |
4460 |
|
4461 |
(let* ((boundaries (or boundaries (company--boundaries completion))) |
4462 |
(prefix (car boundaries)) |
4463 |
(suffix (cdr boundaries)) |
4464 |
(company-common (and company-common |
4465 |
(string-prefix-p prefix company-common) |
4466 |
company-common)) |
4467 |
(common (company--common-or-matches completion suffix))) |
4468 |
(setq completion (copy-sequence (company--pre-render completion))) |
4469 |
(add-face-text-property 0 (length completion) 'company-preview |
4470 |
nil completion) |
4471 |
|
4472 |
(cl-loop for (beg . end) in common |
4473 |
do (add-face-text-property beg end 'company-preview-common |
4474 |
nil completion)) |
4475 |
|
4476 |
;; Add search string |
4477 |
(and (string-match (funcall company-search-regexp-function |
4478 |
company-search-string) |
4479 |
completion) |
4480 |
(pcase-dolist (`(,mbeg . ,mend) (company--search-chunks)) |
4481 |
(add-face-text-property mbeg mend 'company-preview-search |
4482 |
nil completion))) |
4483 |
|
4484 |
(setq completion (if (string-prefix-p prefix completion |
4485 |
(eq (company-call-backend 'ignore-case) |
4486 |
'keep-prefix)) |
4487 |
(company-strip-prefix completion prefix) |
4488 |
completion)) |
4489 |
|
4490 |
(when (string-prefix-p "\n" completion) |
4491 |
(setq completion (concat (propertize " " 'face 'company-preview) "\n" |
4492 |
(substring completion 1)))) |
4493 |
|
4494 |
(and (equal pos (point)) |
4495 |
(not (string-empty-p completion)) |
4496 |
(add-text-properties 0 1 '(cursor 1) completion)) |
4497 |
|
4498 |
(let* ((beg pos) |
4499 |
(pto company-pseudo-tooltip-overlay) |
4500 |
(ptf-workaround (and |
4501 |
pto |
4502 |
(char-before pos) |
4503 |
(eq pos (overlay-start pto)))) |
4504 |
(end pos)) |
4505 |
;; Try to accommodate for the pseudo-tooltip overlay, |
4506 |
;; which may start at the same position if it's at eol. |
4507 |
(when ptf-workaround |
4508 |
(cl-decf beg) |
4509 |
(setq completion (concat (buffer-substring beg pos) completion))) |
4510 |
|
4511 |
(when (string-suffix-p suffix completion) |
4512 |
(cl-incf end (length suffix))) |
4513 |
|
4514 |
(setq company-preview-overlay (make-overlay beg end)) |
4515 |
|
4516 |
(let ((ov company-preview-overlay)) |
4517 |
(overlay-put ov (if (> end beg) 'display 'after-string) |
4518 |
completion) |
4519 |
(overlay-put ov 'window (selected-window)))))) |
4520 |
|
4521 |
(defun company-preview-hide () |
4522 |
(when company-preview-overlay |
4523 |
(delete-overlay company-preview-overlay) |
4524 |
(setq company-preview-overlay nil))) |
4525 |
|
4526 |
(defun company-preview-frontend (command) |
4527 |
"`company-mode' frontend showing the selection as if it had been inserted." |
4528 |
(pcase command |
4529 |
(`pre-command (company-preview-hide)) |
4530 |
(`unhide |
4531 |
(when company-selection |
4532 |
(let* ((current (nth company-selection company-candidates))) |
4533 |
(company-preview-show-at-point (point) current)))) |
4534 |
(`post-command |
4535 |
(when company-selection |
4536 |
(company-preview-show-at-point (point) |
4537 |
(nth company-selection company-candidates)))) |
4538 |
(`hide (company-preview-hide)))) |
4539 |
|
4540 |
(defun company-preview-if-just-one-frontend (command) |
4541 |
"`company-preview-frontend', but only shown for single candidates." |
4542 |
(when (or (not (memq command '(post-command unhide))) |
4543 |
(company--show-inline-p)) |
4544 |
(company-preview-frontend command))) |
4545 |
|
4546 |
(defun company--show-inline-p () |
4547 |
(let* ((boundaries (and company-candidates (company--boundaries))) |
4548 |
(prefix (car boundaries)) |
4549 |
(suffix (cdr boundaries)) |
4550 |
(ignore-case (company-call-backend 'ignore-case)) |
4551 |
(candidate (car company-candidates))) |
4552 |
(and (not (cdr company-candidates)) |
4553 |
company-common |
4554 |
(not (eq t (compare-strings prefix nil nil |
4555 |
candidate nil nil |
4556 |
t))) |
4557 |
(string-suffix-p suffix candidate ignore-case) |
4558 |
(or (eq ignore-case 'keep-prefix) |
4559 |
(string-prefix-p prefix company-common))))) |
4560 |
|
4561 |
(defun company-tooltip-visible-p () |
4562 |
"Returns whether the tooltip is visible." |
4563 |
(when (overlayp company-pseudo-tooltip-overlay) |
4564 |
(not (overlay-get company-pseudo-tooltip-overlay 'invisible)))) |
4565 |
|
4566 |
(defun company-preview-common--show-p () |
4567 |
"Returns whether the preview of common can be showed or not" |
4568 |
(and company-common |
4569 |
(or (eq (company-call-backend 'ignore-case) 'keep-prefix) |
4570 |
(string-prefix-p company-prefix company-common)))) |
4571 |
|
4572 |
(defun company-preview-common-frontend (command) |
4573 |
"`company-mode' frontend preview the common part of candidates." |
4574 |
(when (or (not (memq command '(post-command unhide))) |
4575 |
(company-preview-common--show-p)) |
4576 |
(pcase command |
4577 |
(`pre-command (company-preview-hide)) |
4578 |
((or 'post-command 'unhide) |
4579 |
(company-preview-show-at-point (point) company-common)) |
4580 |
(`hide (company-preview-hide))))) |
4581 |
|
4582 |
;;; echo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
4583 |
|
4584 |
(defvar-local company-echo-last-msg nil) |
4585 |
|
4586 |
(defvar company-echo-timer nil) |
4587 |
|
4588 |
(defvar company-echo-delay .01) |
4589 |
|
4590 |
(defcustom company-echo-truncate-lines t |
4591 |
"Whether frontend messages written to the echo area should be truncated." |
4592 |
:type 'boolean |
4593 |
:package-version '(company . "0.9.3")) |
4594 |
|
4595 |
(defun company-echo-show (&optional getter) |
4596 |
(let ((last-msg company-echo-last-msg) |
4597 |
(message-log-max nil) |
4598 |
(message-truncate-lines company-echo-truncate-lines)) |
4599 |
(when getter |
4600 |
(setq company-echo-last-msg (funcall getter))) |
4601 |
;; Avoid modifying the echo area if we don't have anything to say, and we |
4602 |
;; didn't put the previous message there (thus there's nothing to clear), |
4603 |
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=62816#20 |
4604 |
(if (not (member company-echo-last-msg '(nil ""))) |
4605 |
(message "%s" company-echo-last-msg) |
4606 |
(unless (member last-msg '(nil "")) |
4607 |
(message ""))))) |
4608 |
|
4609 |
(defun company-echo-show-soon (&optional getter delay) |
4610 |
(company-echo-cancel) |
4611 |
(setq company-echo-timer (run-with-timer (or delay company-echo-delay) |
4612 |
nil |
4613 |
'company-echo-show getter))) |
4614 |
|
4615 |
(defun company-echo-cancel (&optional unset) |
4616 |
(when company-echo-timer |
4617 |
(cancel-timer company-echo-timer)) |
4618 |
(when unset |
4619 |
(setq company-echo-timer nil))) |
4620 |
|
4621 |
(defun company-echo-format () |
4622 |
(let ((selection (or company-selection 0))) |
4623 |
(let ((limit (window-body-width (minibuffer-window))) |
4624 |
(len -1) |
4625 |
(candidates (nthcdr selection company-candidates)) |
4626 |
(numbered (if company-show-quick-access selection 99999)) |
4627 |
(qa-keys-len (length company-quick-access-keys)) |
4628 |
comp msg) |
4629 |
|
4630 |
(while candidates |
4631 |
(setq comp (propertize |
4632 |
(company-reformat (company--clean-string (pop candidates))) |
4633 |
'face |
4634 |
'company-echo) |
4635 |
len (+ len 1 (length comp))) |
4636 |
(let ((beg 0) |
4637 |
(end (company--string-width (or company-common "")))) |
4638 |
(when (< numbered qa-keys-len) |
4639 |
(let ((qa-hint |
4640 |
(format "%s: " (funcall |
4641 |
company-quick-access-hint-function |
4642 |
numbered)))) |
4643 |
(setq beg (company--string-width qa-hint) |
4644 |
end (+ beg end)) |
4645 |
(cl-incf len beg) |
4646 |
(setq comp (propertize (concat qa-hint comp) 'face 'company-echo))) |
4647 |
(cl-incf numbered)) |
4648 |
;; FIXME: Add support for the `match' backend action, and thus, |
4649 |
;; non-prefix matches. |
4650 |
(add-text-properties beg end '(face company-echo-common) comp)) |
4651 |
(if (>= len limit) |
4652 |
(setq candidates nil) |
4653 |
(push comp msg))) |
4654 |
|
4655 |
(mapconcat 'identity (nreverse msg) " ")))) |
4656 |
|
4657 |
(defun company-echo-strip-common-format () |
4658 |
(let ((selection (or company-selection 0))) |
4659 |
(let ((limit (window-body-width (minibuffer-window))) |
4660 |
(len (+ (length company-prefix) 2)) |
4661 |
(candidates (nthcdr selection company-candidates)) |
4662 |
(numbered (if company-show-quick-access selection 99999)) |
4663 |
(qa-keys-len (length company-quick-access-keys)) |
4664 |
comp msg) |
4665 |
|
4666 |
(while candidates |
4667 |
(setq comp (company-strip-prefix (pop candidates) company-prefix) |
4668 |
len (+ len 2 (length comp))) |
4669 |
(when (< numbered qa-keys-len) |
4670 |
(let ((qa-hint (format " (%s)" |
4671 |
(funcall company-quick-access-hint-function |
4672 |
numbered)))) |
4673 |
(setq comp (concat comp qa-hint)) |
4674 |
(cl-incf len (company--string-width qa-hint))) |
4675 |
(cl-incf numbered)) |
4676 |
(if (>= len limit) |
4677 |
(setq candidates nil) |
4678 |
(push (propertize comp 'face 'company-echo) msg))) |
4679 |
|
4680 |
(concat (propertize company-prefix 'face 'company-echo-common) "{" |
4681 |
(mapconcat 'identity (nreverse msg) ", ") |
4682 |
"}")))) |
4683 |
|
4684 |
(defun company-echo-hide () |
4685 |
(unless (string-empty-p company-echo-last-msg) |
4686 |
(setq company-echo-last-msg "") |
4687 |
(company-echo-show))) |
4688 |
|
4689 |
(defun company-echo-frontend (command) |
4690 |
"`company-mode' frontend showing the candidates in the echo area." |
4691 |
(pcase command |
4692 |
(`post-command (company-echo-show-soon 'company-echo-format 0)) |
4693 |
(`hide (company-echo-hide)))) |
4694 |
|
4695 |
(defun company-echo-strip-common-frontend (command) |
4696 |
"`company-mode' frontend showing the candidates in the echo area." |
4697 |
(pcase command |
4698 |
(`post-command (company-echo-show-soon 'company-echo-strip-common-format 0)) |
4699 |
(`hide (company-echo-hide)))) |
4700 |
|
4701 |
(defun company-echo-metadata-frontend (command) |
4702 |
"`company-mode' frontend showing the documentation in the echo area." |
4703 |
(pcase command |
4704 |
(`post-command (company-echo-show-soon 'company-fetch-metadata)) |
4705 |
(`unhide (company-echo-show)) |
4706 |
(`hide (company-echo-hide)))) |
4707 |
|
4708 |
(provide 'company) |
4709 |
;;; company.el ends here |
4710 |