Klimi's new dotfiles with stow.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

198 строки
8.5 KiB

4 лет назад
  1. ;;; company-capf.el --- company-mode completion-at-point-functions backend -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2013-2018 Free Software Foundation, Inc.
  3. ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;; The CAPF back-end provides a bridge to the standard
  18. ;; completion-at-point-functions facility, and thus can support any major mode
  19. ;; that defines a proper completion function, including emacs-lisp-mode,
  20. ;; css-mode and nxml-mode.
  21. ;;; Code:
  22. (require 'company)
  23. (require 'cl-lib)
  24. (defvar company--capf-cache nil)
  25. ;; FIXME: Provide a way to save this info once in Company itself
  26. ;; (https://github.com/company-mode/company-mode/pull/845).
  27. (defvar-local company-capf--current-completion-data nil
  28. "Value last returned by `company-capf' when called with `candidates'.
  29. For most properties/actions, this is just what we need: the exact values
  30. that accompanied the completion table that's currently is use.")
  31. (defun company--capf-data ()
  32. (let ((cache company--capf-cache))
  33. (if (and (equal (current-buffer) (car cache))
  34. (equal (point) (car (setq cache (cdr cache))))
  35. (equal (buffer-chars-modified-tick) (car (setq cache (cdr cache)))))
  36. (cadr cache)
  37. (let ((data (company--capf-data-real)))
  38. (setq company--capf-cache
  39. (list (current-buffer) (point) (buffer-chars-modified-tick) data))
  40. data))))
  41. (defun company--capf-data-real ()
  42. (cl-letf* (((default-value 'completion-at-point-functions)
  43. ;; Ignore tags-completion-at-point-function because it subverts
  44. ;; company-etags in the default value of company-backends, where
  45. ;; the latter comes later.
  46. (remove 'tags-completion-at-point-function
  47. (default-value 'completion-at-point-functions)))
  48. (completion-at-point-functions (company--capf-workaround))
  49. (data (run-hook-wrapped 'completion-at-point-functions
  50. ;; Ignore misbehaving functions.
  51. #'completion--capf-wrapper 'optimist)))
  52. (when (and (consp (cdr data)) (integer-or-marker-p (nth 1 data))) data)))
  53. (declare-function python-shell-get-process "python")
  54. (defun company--capf-workaround ()
  55. ;; For http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18067
  56. (if (or (not (listp completion-at-point-functions))
  57. (not (memq 'python-completion-complete-at-point completion-at-point-functions))
  58. (python-shell-get-process))
  59. completion-at-point-functions
  60. (remq 'python-completion-complete-at-point completion-at-point-functions)))
  61. (defun company-capf--save-current-data (data)
  62. (setq company-capf--current-completion-data data)
  63. (add-hook 'company-after-completion-hook
  64. #'company-capf--clear-current-data nil t))
  65. (defun company-capf--clear-current-data (_ignored)
  66. (setq company-capf--current-completion-data nil))
  67. (defun company-capf (command &optional arg &rest _args)
  68. "`company-mode' backend using `completion-at-point-functions'."
  69. (interactive (list 'interactive))
  70. (pcase command
  71. (`interactive (company-begin-backend 'company-capf))
  72. (`prefix
  73. (let ((res (company--capf-data)))
  74. (when res
  75. (let ((length (plist-get (nthcdr 4 res) :company-prefix-length))
  76. (prefix (buffer-substring-no-properties (nth 1 res) (point))))
  77. (cond
  78. ((> (nth 2 res) (point)) 'stop)
  79. (length (cons prefix length))
  80. (t prefix))))))
  81. (`candidates
  82. (let ((res (company--capf-data)))
  83. (company-capf--save-current-data res)
  84. (when res
  85. (let* ((table (nth 3 res))
  86. (pred (plist-get (nthcdr 4 res) :predicate))
  87. (meta (completion-metadata
  88. (buffer-substring (nth 1 res) (nth 2 res))
  89. table pred))
  90. (sortfun (cdr (assq 'display-sort-function meta)))
  91. (candidates (completion-all-completions arg table pred (length arg)))
  92. (last (last candidates))
  93. (base-size (and (numberp (cdr last)) (cdr last))))
  94. (when base-size
  95. (setcdr last nil))
  96. (when sortfun
  97. (setq candidates (funcall sortfun candidates)))
  98. (if (not (zerop (or base-size 0)))
  99. (let ((before (substring arg 0 base-size)))
  100. (mapcar (lambda (candidate)
  101. (concat before candidate))
  102. candidates))
  103. candidates)))))
  104. (`sorted
  105. (let ((res company-capf--current-completion-data))
  106. (when res
  107. (let ((meta (completion-metadata
  108. (buffer-substring (nth 1 res) (nth 2 res))
  109. (nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
  110. (cdr (assq 'display-sort-function meta))))))
  111. (`match
  112. ;; Ask the for the `:company-match' function. If that doesn't help,
  113. ;; fallback to sniffing for face changes to get a suitable value.
  114. (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
  115. :company-match)))
  116. (if f (funcall f arg)
  117. (let* ((match-start nil) (pos -1)
  118. (prop-value nil) (faces nil)
  119. (has-face-p nil) chunks
  120. (limit (length arg)))
  121. (while (< pos limit)
  122. (setq pos
  123. (if (< pos 0) 0 (next-property-change pos arg limit)))
  124. (setq prop-value (or
  125. (get-text-property pos 'face arg)
  126. (get-text-property pos 'font-lock-face arg))
  127. faces (if (listp prop-value) prop-value (list prop-value))
  128. has-face-p (memq 'completions-common-part faces))
  129. (cond ((and (not match-start) has-face-p)
  130. (setq match-start pos))
  131. ((and match-start (not has-face-p))
  132. (push (cons match-start pos) chunks)
  133. (setq match-start nil))))
  134. (nreverse chunks)))))
  135. (`duplicates t)
  136. (`no-cache t) ;Not much can be done here, as long as we handle
  137. ;non-prefix matches.
  138. (`meta
  139. (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
  140. :company-docsig)))
  141. (when f (funcall f arg))))
  142. (`doc-buffer
  143. (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
  144. :company-doc-buffer)))
  145. (when f (funcall f arg))))
  146. (`location
  147. (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
  148. :company-location)))
  149. (when f (funcall f arg))))
  150. (`annotation
  151. (let ((f (plist-get (nthcdr 4 company-capf--current-completion-data)
  152. :annotation-function)))
  153. (when f (funcall f arg))))
  154. (`require-match
  155. (plist-get (nthcdr 4 (company--capf-data)) :company-require-match))
  156. (`init nil) ;Don't bother: plenty of other ways to initialize the code.
  157. (`post-completion
  158. (company--capf-post-completion arg))
  159. ))
  160. (defun company--capf-post-completion (arg)
  161. (let* ((res company-capf--current-completion-data)
  162. (exit-function (plist-get (nthcdr 4 res) :exit-function))
  163. (table (nth 3 res))
  164. (pred (plist-get (nthcdr 4 res) :predicate)))
  165. (if exit-function
  166. ;; Follow the example of `completion--done'.
  167. (funcall exit-function arg
  168. ;; FIXME: Should probably use an additional heuristic:
  169. ;; completion-at-point doesn't know when the user picked a
  170. ;; particular candidate explicitly (it only checks whether
  171. ;; futher completions exist). Whereas company user can press
  172. ;; RET (or use implicit completion with company-tng).
  173. (if (eq (try-completion arg table pred) t)
  174. 'finished 'sole)))))
  175. (provide 'company-capf)
  176. ;;; company-capf.el ends here