Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
9.0 KiB

  1. ;;; ein-ac.el --- Auto-complete extension
  2. ;; Copyright (C) 2012- Takafumi Arakaki
  3. ;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
  4. ;; This file is NOT part of GNU Emacs.
  5. ;; ein-ac.el 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. ;; ein-ac.el 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 ein-ac.el. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;;; Code:
  18. (require 'auto-complete)
  19. (require 'ein-core)
  20. (eval-when-compile (require 'ein-notebook)
  21. (defvar ein:mumamo-codecell-mode))
  22. ;;; Configuration
  23. (defcustom ein:use-auto-complete-superpack nil
  24. "Set to `t' to use preset a little bit hacky auto-complete configuration.
  25. When this option is enabled, cached omni completion is available."
  26. :type 'boolean
  27. :group 'ein)
  28. (defvar ein:ac-sources (and (boundp 'ac-sources)
  29. (default-value 'ac-sources))
  30. "Extra `ac-sources' used in notebook.")
  31. ;;; Chunk (adapted from auto-complete-chunk.el)
  32. (defvar ein:ac-chunk-regex
  33. (rx (group (| (syntax whitespace)
  34. (syntax open-parenthesis)
  35. (syntax close-parenthesis)
  36. (syntax string-quote) ; Complete files for `open("path/..`
  37. bol))
  38. (? (syntax punctuation)) ; to complete ``~/PATH/...``
  39. (* (+ (| (syntax word) (syntax symbol)))
  40. (syntax punctuation))
  41. (+ (| (syntax word) (syntax symbol)))
  42. (? (syntax punctuation))
  43. point)
  44. "A regexp that matches to a \"chunk\" containing words and dots.")
  45. (defun ein:ac-chunk-beginning ()
  46. "Return the position where the chunk begins."
  47. (ignore-errors
  48. (save-excursion
  49. (+ (re-search-backward ein:ac-chunk-regex) (length (match-string 1))))))
  50. (defun ein:ac-chunk-candidates-from-list (chunk-list)
  51. "Return matched candidates in CHUNK-LIST."
  52. (let* ((start (ein:ac-chunk-beginning)))
  53. (when start
  54. (cl-loop with prefix = (buffer-substring start (point))
  55. for cc in chunk-list
  56. when (string-prefix-p prefix cc)
  57. collect cc))))
  58. ;;; AC Source
  59. (defvar ein:ac-direct-matches nil
  60. "Variable to store completion candidates for `auto-completion'.")
  61. ;; FIXME: Maybe this should be buffer-local?
  62. (defun ein:ac-direct-get-matches ()
  63. (ein:ac-chunk-candidates-from-list ein:ac-direct-matches))
  64. (define-obsolete-function-alias 'ac-complete-ein-cached 'ac-complete-ein-async
  65. "0.2.1")
  66. (define-obsolete-variable-alias 'ac-source-ein-cached 'ac-source-ein-async
  67. "0.2.1")
  68. (defun ein:ac-request-in-background ()
  69. (cl-case ein:completion-backend
  70. (ein:use-ac-backend (ein:aif (ein:get-kernel)
  71. (ein:completer-complete
  72. it
  73. (list :complete_reply
  74. (cons (lambda (_ content __)
  75. (ein:ac-prepare-completion (plist-get content :matches)))
  76. nil))
  77. #'ignore)))))
  78. ;;; Completer interface
  79. (defun ein:ac-dot-complete (callback)
  80. "Insert a dot and request completion via CALLBACK of 0-arity"
  81. (interactive (list (lambda () (call-interactively #'ein:completer-complete))))
  82. (insert ".")
  83. (if (not (ac-cursor-on-diable-face-p))
  84. (funcall callback)))
  85. (defun ein:ac-prepare-completion (matches)
  86. "Prepare `ac-source-ein-direct' using MATCHES from kernel.
  87. Call this function before calling `auto-complete'."
  88. (when matches
  89. (setq ein:ac-direct-matches matches))) ; let-binding won't work
  90. (cl-defun ein:completer-finish-completing-ac
  91. (matched-text
  92. matches
  93. &key (expand ac-expand-on-auto-complete)
  94. &allow-other-keys)
  95. "Invoke completion using `auto-complete'.
  96. Only the argument MATCHES is used. MATCHED-TEXT is for
  97. compatibility with `ein:completer-finish-completing-default'."
  98. ;; I don't need to check if the point is at right position, as in
  99. ;; `ein:completer-finish-completing-default' because `auto-complete'
  100. ;; checks it anyway.
  101. (ein:log 'debug "COMPLETER-FINISH-COMPLETING-AC: matched-text=%S matches=%S"
  102. matched-text matches)
  103. (ein:ac-prepare-completion matches)
  104. (when matches ; No auto-complete drop-down list when no matches
  105. (let ((ac-expand-on-auto-complete expand))
  106. (ac-start))))
  107. ;;; Async document request hack
  108. (defun ein:ac-request-document-for-selected-candidate ()
  109. "Request object information for the candidate at point.
  110. This is called via `ac-next'/`ac-previous'/`ac-update' and set
  111. `document' property of the current candidate string. If server
  112. replied within `ac-quick-help-delay' seconds, auto-complete will
  113. popup help string."
  114. (ein:aif (ein:get-kernel)
  115. (let* ((candidate (ac-selected-candidate))
  116. (kernel it)
  117. (api-version (ein:$kernel-api-version kernel))
  118. (callbacks (list (if (< api-version 3)
  119. :object_info_reply
  120. :inspect_request)
  121. (cons #'ein:ac-set-document candidate))))
  122. (when (and candidate
  123. (ein:kernel-live-p kernel)
  124. (not (get-text-property 0 'document candidate)))
  125. (ein:log 'debug "Requesting object info for AC candidate %S"
  126. candidate)
  127. (ein:kernel-object-info-request kernel candidate callbacks)))))
  128. (defun ein:ac-set-document (candidate content -metadata-not-used-)
  129. (ein:log 'debug "EIN:AC-SET-DOCUMENT candidate=%S content=%S"
  130. candidate content)
  131. (put-text-property 0 (length candidate)
  132. 'document (ein:kernel-construct-help-string content)
  133. candidate))
  134. (defadvice ac-next (after ein:ac-next-request)
  135. "Monkey patch `auto-complete' internal function to request
  136. help documentation asynchronously."
  137. (ein:ac-request-document-for-selected-candidate))
  138. (defadvice ac-previous (after ein:ac-previous-request)
  139. "Monkey patch `auto-complete' internal function to request
  140. help documentation asynchronously."
  141. (ein:ac-request-document-for-selected-candidate))
  142. (defadvice ac-update (after ein:ac-update-request)
  143. "Monkey patch `auto-complete' internal function to request help
  144. documentation asynchronously. This will request info for the
  145. first candidate when the `ac-menu' pops up."
  146. (ein:ac-request-document-for-selected-candidate))
  147. ;;; Setup
  148. (defun ein:ac-superpack ()
  149. "Enable richer auto-completion.
  150. * Enable auto-completion help by monkey patching `ac-next'/`ac-previous'"
  151. (interactive)
  152. (ad-enable-advice 'ac-next 'after 'ein:ac-next-request)
  153. (ad-enable-advice 'ac-previous 'after 'ein:ac-previous-request)
  154. (ad-enable-advice 'ac-update 'after 'ein:ac-update-request)
  155. (ad-activate 'ac-next)
  156. (ad-activate 'ac-previous)
  157. (ad-activate 'ac-update))
  158. (defun ein:ac-setup ()
  159. "Call this function from mode hook (see `ein:ac-config')."
  160. (setq ac-sources (append '(ac-source-ein-async) ein:ac-sources)))
  161. (defun ein:ac-setup-maybe ()
  162. "Setup `ac-sources' for mumamo.
  163. .. note:: Setting `ein:notebook-mumamo-mode-hook' does not work
  164. because `ac-sources' in `ein:notebook-mumamo-mode'-enabled
  165. buffer is *chunk local*, rather than buffer local.
  166. Making `ac-sources' permanent-local also addresses issue of
  167. MuMaMo discarding `ac-sources'. However, it effects to entire
  168. Emacs setting. So this is not the right way to do it.
  169. Using `mumamo-make-variable-buffer-permanent' (i.e., adding
  170. `ac-sources' to `mumamo-per-buffer-local-vars' or
  171. `mumamo-per-main-major-local-vars') is also not appropriate.
  172. Adding `ac-sources' to them makes it impossible to different
  173. `ac-sources' between chunks, which is good for EIN but may not
  174. for other package."
  175. (and (ein:eval-if-bound 'ein:notebook-mode)
  176. (ein:eval-if-bound 'ein:notebook-mumamo-mode)
  177. (eql major-mode ein:mumamo-codecell-mode)
  178. (ein:ac-setup)))
  179. (defun ein:ac-config (&optional superpack)
  180. "Install auto-complete-mode for notebook modes.
  181. Specifying non-`nil' to SUPERPACK enables richer auto-completion
  182. \(see `ein:ac-superpack')."
  183. (add-hook 'after-change-major-mode-hook 'ein:ac-setup-maybe)
  184. (add-hook 'ein:notebook-mode-hook 'ein:ac-setup)
  185. (when superpack
  186. (ein:ac-superpack)))
  187. (defun ein:ac-install-backend ()
  188. (ac-define-source ein-direct
  189. '((candidates . ein:ac-direct-get-matches)
  190. (requires . 0)
  191. (prefix . ein:ac-chunk-beginning)
  192. (symbol . "s")))
  193. (ac-define-source ein-async
  194. '((candidates . ein:ac-direct-get-matches)
  195. (requires . 0)
  196. (prefix . ein:ac-chunk-beginning)
  197. (init . ein:ac-request-in-background)
  198. (symbol . "c")))
  199. (ein:ac-config ein:use-auto-complete-superpack))
  200. (provide 'ein-ac)
  201. ;;; ein-ac.el ends here