completion-ui-sources.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. ;;; completion-ui-sources.el --- Completion-UI completion sources
  2. ;; Copyright (C) 2009, 2012 Toby Cubitt
  3. ;; Author: Toby Cubitt <toby-predictive@dr-qubit.org>
  4. ;; Version: 0.3
  5. ;; Keywords: completion, UI, user interface, sources
  6. ;; URL: http://www.dr-qubit.org/emacs.php
  7. ;; This file is NOT part of Emacs.
  8. ;;
  9. ;; This file is free software: you can redistribute it and/or modify it under
  10. ;; the terms of the GNU General Public License as published by the Free
  11. ;; Software Foundation, either version 3 of the License, or (at your option)
  12. ;; any later version.
  13. ;;
  14. ;; This program is distributed in the hope that it will be useful, but WITHOUT
  15. ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. ;; more details.
  18. ;;
  19. ;; You should have received a copy of the GNU General Public License along
  20. ;; with this program. If not, see <http://www.gnu.org/licenses/>.
  21. ;;; Code:
  22. (require 'completion-ui)
  23. ;; suppress compiler warnings
  24. (eval-when-compile
  25. (defvar semanticdb-find-default-throttle nil)
  26. (require 'ispell)
  27. (require 'dabbrev)
  28. (require 'etags)
  29. (require 'flyspell)
  30. (require 'nxml nil t)
  31. (require 'reftex nil t)
  32. (require 'semantic-ia nil t)
  33. (if (fboundp 'declare-function)
  34. (progn
  35. (declare-function dabbrev--reset-global-variables
  36. "dabbrev.el" nil)
  37. (declare-function dabbrev--find-all-expansions
  38. "dabbrev.el" (arg1 arg2))
  39. (declare-function tags-lazy-completion-table
  40. "etags.el" nil)
  41. (declare-function semantic-idle-summary-useful-context-p
  42. "ext:semantic-idle.el" nil)
  43. (declare-function semantic-ctxt-current-symbol
  44. "ext:semantic-ctxt.el" (&optional arg1))
  45. (declare-function semantic-analyze-current-context
  46. "ext:semantic-analyze.el" nil)
  47. (declare-function semantic-analyze-possible-completions
  48. "ext:semantic-analyze-complete.el" (arg1)))
  49. (defun dabbrev--reset-global-variables nil)
  50. (defun dabbrev--find-all-expansions (arg1 arg2))
  51. (defun tags-lazy-complete-table nil)
  52. (defun semantic-idle-summary-useful-context-p nil)
  53. (defun semantic-ctxt-current-symbol (&optional arg1))
  54. (defun semantic-analyze-current-context nil)
  55. (defun semantic-analyze-possible-completions (arg1)))
  56. )
  57. ;;;=========================================================
  58. ;;; combining completion sources
  59. (defcustom completion-ui-combine-sources-alist nil
  60. "Alist specifying completion sources to be combined.
  61. Each element of the alist must be a cons cell of the form
  62. (SOURCE . TEST)
  63. where SOURCE is a completion source (a symbol), and TEST
  64. specifies a test used to determine whether SOURCE is used. TEST
  65. must be one of the following:
  66. function
  67. called with no arguments
  68. source is used if it returns non-nil
  69. regexp
  70. `re-search-backward' to beginning of line
  71. source is used if regexp matches
  72. sexp
  73. `eval'ed
  74. source is used if it evals to non-nil.
  75. To specify that a source should always be used, set its TEST
  76. to t."
  77. :group 'completion-ui
  78. :type '(alist :key-type (choice :tag "source" (const nil))
  79. :value-type (choice :tag "test" :value t
  80. regexp function sexp)))
  81. (defun* completion-ui-update-combine-sources-defcustom
  82. (completion-function
  83. &key name non-prefix-completion no-combining &allow-other-keys)
  84. "Update source choices in `completion-ui-combine-sources-alist' defcustom.
  85. Called from `completion-ui-resiter-source-functions' hook after a
  86. new source is registered.
  87. Passing a non-nil :no-combining keyword argument to
  88. `completion-ui-register-source' prevents the new source being
  89. available for combining."
  90. (if (or no-combining non-prefix-completion)
  91. (delete `(const ,name)
  92. (plist-get (cdr (get 'completion-ui-combine-sources-alist
  93. 'custom-type))
  94. :key-type))
  95. (let ((choices (plist-get (cdr (get 'completion-ui-combine-sources-alist
  96. 'custom-type))
  97. :key-type)))
  98. (unless (member `(const ,name) choices)
  99. (delete `(const nil) choices)
  100. (nconc choices `((const ,name)))))))
  101. (add-hook 'completion-ui-register-source-functions
  102. 'completion-ui-update-combine-sources-defcustom)
  103. (defun completion-ui-combining-complete (source-spec prefix &optional maxnum)
  104. "Return a combined list of all completions
  105. from sources in SOURCE-SPEC.
  106. SOURCE-SPEC should be a list specifying how the completion
  107. sources are to be combined. Each element can be either a
  108. completion source (a symbol) in which case the source is always
  109. used, or a cons cell of the form
  110. (SOURCE . TEST)
  111. where SOURCE is a completion source (a symbol), and TEST
  112. specifies a test used to determine whether SOURCE is used. TEST
  113. must be one of the following:
  114. function
  115. called with no arguments
  116. source is used if it returns non-nil
  117. regexp
  118. `re-search-backward' to beginning of line
  119. source is used if regexp matches
  120. sexp
  121. `eval'ed
  122. source is used if it evals to non-nil."
  123. (let (completions)
  124. (dolist (s source-spec)
  125. (when (cond
  126. ((symbolp s) t)
  127. ((functionp (cdr s))
  128. (funcall (cdr s)))
  129. ((stringp (cdr s))
  130. (save-excursion
  131. (re-search-backward (cdr s) (line-beginning-position) t)))
  132. (t (eval (cdr s))))
  133. (setq completions
  134. (nconc completions (completion-ui-complete (car s) prefix maxnum))))
  135. (if maxnum
  136. (butlast completions (- (length completions) maxnum))
  137. completions))))
  138. (completion-ui-register-source
  139. completion-ui-combining-complete
  140. :completion-args (2 3)
  141. :other-args (completion-ui-combine-sources-alist)
  142. :name Combine
  143. :no-combining t)
  144. ;;;=========================================================
  145. ;;; dabbrevs
  146. (completion-ui-register-source
  147. (lambda (prefix)
  148. (require 'dabbrev)
  149. (dabbrev--reset-global-variables)
  150. (dabbrev--find-all-expansions prefix case-fold-search))
  151. :name dabbrev)
  152. ;;;=========================================================
  153. ;;; etags
  154. (completion-ui-register-source
  155. (lambda (prefix)
  156. (require 'etags)
  157. (all-completions prefix (tags-lazy-completion-table)))
  158. :name etags)
  159. ;;;=========================================================
  160. ;;; Elisp
  161. (completion-ui-register-source
  162. all-completions
  163. :completion-args 1
  164. :other-args (obarray)
  165. :name elisp
  166. :word-thing symbol)
  167. ;;;=========================================================
  168. ;;; file names
  169. (defun completion--filename-wrapper (prefix)
  170. ;; Return filename completions of prefix
  171. (let ((dir (file-name-directory prefix))
  172. completions)
  173. (mapc (lambda (file)
  174. (unless (or (string= file "../") (string= file "./"))
  175. (push (concat dir file) completions)))
  176. (file-name-all-completions
  177. (file-name-nondirectory prefix) dir))
  178. (nreverse completions)))
  179. (completion-ui-register-source
  180. completion--filename-wrapper
  181. :name files)
  182. ;;;=========================================================
  183. ;;; ispell
  184. (defun completion--ispell-wrapper (word)
  185. (require 'flyspell)
  186. (let (suggestions ispell-filter)
  187. ;; Now check spelling of word.
  188. (ispell-send-string "%\n") ; put in verbose mode
  189. (ispell-send-string (concat "^" word "\n")) ; lookup the word
  190. ;; Wait until ispell has processed word.
  191. (while (progn
  192. (accept-process-output ispell-process)
  193. (not (string= "" (car ispell-filter)))))
  194. ;; Remove leading empty element
  195. (setq ispell-filter (cdr ispell-filter))
  196. ;; ispell process should return something after word is sent.
  197. ;; Tag word as valid (i.e., skip) otherwise
  198. (or ispell-filter
  199. (setq ispell-filter '(*)))
  200. (when (consp ispell-filter)
  201. (setq suggestions (ispell-parse-output (car ispell-filter))))
  202. (cond
  203. ((or (eq suggestions t) (stringp suggestions))
  204. (message "Ispell: %s is correct" word)
  205. nil)
  206. ((null suggestions)
  207. (error "Ispell: error in Ispell process")
  208. nil)
  209. (t (car (cdr (cdr suggestions)))))))
  210. (completion-ui-register-source
  211. completion--ispell-wrapper
  212. :non-prefix-completion t
  213. :name ispell)
  214. ;;;=========================================================
  215. ;;; NXML
  216. (when (locate-library "nxml")
  217. (completion-ui-register-source
  218. (lambda (prefix)
  219. (require nxml)
  220. (rng-complete-qname-function prefix))
  221. :completion-args 1
  222. :other-args (t t)
  223. :name nxml)
  224. )
  225. ;;;=========================================================
  226. ;;; RefTeX
  227. (when (locate-library "reftex")
  228. (put 'latex-label 'forward-op 'latex-label-forward-word)
  229. ;; copied from predictive-latex.el
  230. (defun latex-label-forward-word (&optional n)
  231. ;; going backwards...
  232. (if (and n (< n 0))
  233. (unless (bobp)
  234. (setq n (- n))
  235. (when (eq (char-before) ?\\)
  236. (while (eq (char-before) ?\\) (backward-char))
  237. (setq n (1- n)))
  238. (dotimes (i n)
  239. (when (and (char-before) (= (char-syntax (char-before)) ?w))
  240. (backward-word 1)) ; argument not optional in Emacs 21
  241. (while (and (char-before)
  242. (or (= (char-syntax (char-before)) ?w)
  243. (= (char-syntax (char-before)) ?_)
  244. (and (= (char-syntax (char-before)) ?.)
  245. (/= (char-before) ?{))))
  246. (backward-char))))
  247. ;; going forwards...
  248. (unless (eobp)
  249. (setq n (if n n 1))
  250. (dotimes (i n)
  251. (when (and (char-after) (= (char-syntax (char-after)) ?w))
  252. (forward-word 1)) ; argument not optional in Emacs 21
  253. (while (and (char-after)
  254. (or (= (char-syntax (char-after)) ?w)
  255. (= (char-syntax (char-after)) ?_)
  256. (and (= (char-syntax (char-after)) ?.)
  257. (/= (char-after) ?}))))
  258. (forward-char))))))
  259. (completion-ui-register-source
  260. (lambda (prefix)
  261. (all-completions
  262. prefix
  263. (delq nil (mapcar (lambda (c) (when (stringp (car c)) (car c)))
  264. reftex-docstruct-symbol-1))))
  265. :name reftex
  266. :word-thing latex-label
  267. :no-auto-completion t
  268. :no-predictive t)
  269. )
  270. ;;;=========================================================
  271. ;;; Semantic
  272. (when (locate-library "semantic")
  273. (defun completion--semantic-prefix-wrapper ()
  274. ;; Return prefix at point that Semantic would complete.
  275. (require 'semantic-ia)
  276. (when (semantic-idle-summary-useful-context-p)
  277. (let ((prefix (semantic-ctxt-current-symbol (point))))
  278. (setq prefix (nth (1- (length prefix)) prefix))
  279. (set-text-properties 0 (length prefix) nil prefix)
  280. prefix)))
  281. (defun completion--semantic-wrapper (prefix &optional maxnum)
  282. ;; Return list of Semantic completions for PREFIX at point. Optional
  283. ;; argument MAXNUM is the maximum number of completions to return.
  284. (require 'semantic-ia)
  285. (when (semantic-idle-summary-useful-context-p)
  286. (let* (
  287. ;; don't go loading in oodles of header libraries for minor
  288. ;; completions if using auto-completion-mode
  289. ;; FIXME: don't do this iff the user invoked completion manually
  290. (semanticdb-find-default-throttle
  291. (when (and (featurep 'semanticdb-find)
  292. auto-completion-mode)
  293. (remq 'unloaded semanticdb-find-default-throttle)))
  294. (ctxt (semantic-analyze-current-context))
  295. (acomp (semantic-analyze-possible-completions ctxt)))
  296. (when (and maxnum (> (length acomp) maxnum))
  297. (setq acomp (butlast acomp (- (length acomp) maxnum))))
  298. (mapcar 'semantic-tag-name acomp))))
  299. (defun completion--semantic-enable-auto-completion nil
  300. ;; set variables buffer-locally when enabling Semantic auto-completion
  301. (when (eq auto-completion-default-source 'semantic)
  302. (set (make-local-variable 'auto-completion-override-syntax-alist)
  303. '((?. . (add word))))))
  304. (defun completion--semantic-disable-auto-completion nil
  305. ;; unset buffer-local variables when disabling Semantic auto-completion
  306. (when (eq auto-completion-default-source 'semantic)
  307. (kill-local-variable 'auto-completion-override-syntax-alist)))
  308. (add-hook 'auto-completion-mode-enable-hook
  309. 'completion--semantic-enable-auto-completion)
  310. (add-hook 'auto-completion-mode-disable-hook
  311. 'completion--semantic-disable-auto-completion)
  312. ;; register the Semantic source
  313. (completion-ui-register-source
  314. completion--semantic-wrapper
  315. :prefix-function completion--semantic-prefix-wrapper
  316. :completion-args 2
  317. :name semantic)
  318. )
  319. (provide 'completion-ui-sources)
  320. ;;; completion-ui-sources.el ends here