Klimi's new dotfiles with stow.
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.

305 line
12 KiB

4 年之前
  1. (require 'slime)
  2. (require 'cl-lib)
  3. (defvar slime-c-p-c-init-undo-stack nil)
  4. (define-slime-contrib slime-c-p-c
  5. "ILISP style Compound Prefix Completion."
  6. (:authors "Luke Gorrie <luke@synap.se>"
  7. "Edi Weitz <edi@agharta.de>"
  8. "Matthias Koeppe <mkoeppe@mail.math.uni-magdeburg.de>"
  9. "Tobias C. Rittweiler <tcr@freebits.de>")
  10. (:license "GPL")
  11. (:slime-dependencies slime-parse slime-editing-commands slime-autodoc)
  12. (:swank-dependencies swank-c-p-c)
  13. (:on-load
  14. (push
  15. `(progn
  16. (remove-hook 'slime-completion-at-point-functions
  17. #'slime-c-p-c-completion-at-point)
  18. (remove-hook 'slime-connected-hook 'slime-c-p-c-on-connect)
  19. ,@(when (featurep 'slime-repl)
  20. `((define-key slime-mode-map "\C-c\C-s"
  21. ',(lookup-key slime-mode-map "\C-c\C-s"))
  22. (define-key slime-repl-mode-map "\C-c\C-s"
  23. ',(lookup-key slime-repl-mode-map "\C-c\C-s")))))
  24. slime-c-p-c-init-undo-stack)
  25. (add-hook 'slime-completion-at-point-functions
  26. #'slime-c-p-c-completion-at-point)
  27. (define-key slime-mode-map "\C-c\C-s" 'slime-complete-form)
  28. (when (featurep 'slime-repl)
  29. (define-key slime-repl-mode-map "\C-c\C-s" 'slime-complete-form)))
  30. (:on-unload
  31. (while slime-c-p-c-init-undo-stack
  32. (eval (pop slime-c-p-c-init-undo-stack)))))
  33. (defcustom slime-c-p-c-unambiguous-prefix-p t
  34. "If true, set point after the unambigous prefix.
  35. If false, move point to the end of the inserted text."
  36. :type 'boolean
  37. :group 'slime-ui)
  38. (defcustom slime-complete-symbol*-fancy nil
  39. "Use information from argument lists for DWIM'ish symbol completion."
  40. :group 'slime-mode
  41. :type 'boolean)
  42. ;; FIXME: this is the old code to display completions. Remove it once
  43. ;; `slime-complete-symbol*' and `slime-fuzzy-complete-symbol' can be
  44. ;; used together with `completion-at-point'.
  45. (defvar slime-completions-buffer-name "*Completions*")
  46. ;; FIXME: can probably use quit-window instead
  47. (make-variable-buffer-local
  48. (defvar slime-complete-saved-window-configuration nil
  49. "Window configuration before we show the *Completions* buffer.
  50. This is buffer local in the buffer where the completion is
  51. performed."))
  52. (make-variable-buffer-local
  53. (defvar slime-completions-window nil
  54. "The window displaying *Completions* after saving window configuration.
  55. If this window is no longer active or displaying the completions
  56. buffer then we can ignore `slime-complete-saved-window-configuration'."))
  57. (defun slime-complete-maybe-save-window-configuration ()
  58. "Maybe save the current window configuration.
  59. Return true if the configuration was saved."
  60. (unless (or slime-complete-saved-window-configuration
  61. (get-buffer-window slime-completions-buffer-name))
  62. (setq slime-complete-saved-window-configuration
  63. (current-window-configuration))
  64. t))
  65. (defun slime-complete-delay-restoration ()
  66. (add-hook 'pre-command-hook
  67. 'slime-complete-maybe-restore-window-configuration
  68. 'append
  69. 'local))
  70. (defun slime-complete-forget-window-configuration ()
  71. (setq slime-complete-saved-window-configuration nil)
  72. (setq slime-completions-window nil))
  73. (defun slime-complete-restore-window-configuration ()
  74. "Restore the window config if available."
  75. (remove-hook 'pre-command-hook
  76. 'slime-complete-maybe-restore-window-configuration)
  77. (when (and slime-complete-saved-window-configuration
  78. (slime-completion-window-active-p))
  79. (save-excursion (set-window-configuration
  80. slime-complete-saved-window-configuration))
  81. (setq slime-complete-saved-window-configuration nil)
  82. (when (buffer-live-p slime-completions-buffer-name)
  83. (kill-buffer slime-completions-buffer-name))))
  84. (defun slime-complete-maybe-restore-window-configuration ()
  85. "Restore the window configuration, if the following command
  86. terminates a current completion."
  87. (remove-hook 'pre-command-hook
  88. 'slime-complete-maybe-restore-window-configuration)
  89. (condition-case err
  90. (cond ((cl-find last-command-event "()\"'`,# \r\n:")
  91. (slime-complete-restore-window-configuration))
  92. ((not (slime-completion-window-active-p))
  93. (slime-complete-forget-window-configuration))
  94. (t
  95. (slime-complete-delay-restoration)))
  96. (error
  97. ;; Because this is called on the pre-command-hook, we mustn't let
  98. ;; errors propagate.
  99. (message "Error in slime-complete-restore-window-configuration: %S"
  100. err))))
  101. (defun slime-completion-window-active-p ()
  102. "Is the completion window currently active?"
  103. (and (window-live-p slime-completions-window)
  104. (equal (buffer-name (window-buffer slime-completions-window))
  105. slime-completions-buffer-name)))
  106. (defun slime-display-completion-list (completions start end)
  107. (let ((savedp (slime-complete-maybe-save-window-configuration)))
  108. (with-output-to-temp-buffer slime-completions-buffer-name
  109. (display-completion-list completions)
  110. (with-current-buffer standard-output
  111. (setq completion-base-position (list start end))
  112. (set-syntax-table lisp-mode-syntax-table)))
  113. (when savedp
  114. (setq slime-completions-window
  115. (get-buffer-window slime-completions-buffer-name)))))
  116. (defun slime-display-or-scroll-completions (completions start end)
  117. (cond ((and (eq last-command this-command)
  118. (slime-completion-window-active-p))
  119. (slime-scroll-completions))
  120. (t
  121. (slime-display-completion-list completions start end)))
  122. (slime-complete-delay-restoration))
  123. (defun slime-scroll-completions ()
  124. (let ((window slime-completions-window))
  125. (with-current-buffer (window-buffer window)
  126. (if (pos-visible-in-window-p (point-max) window)
  127. (set-window-start window (point-min))
  128. (save-selected-window
  129. (select-window window)
  130. (scroll-up))))))
  131. (defun slime-minibuffer-respecting-message (format &rest format-args)
  132. "Display TEXT as a message, without hiding any minibuffer contents."
  133. (let ((text (format " [%s]" (apply #'format format format-args))))
  134. (if (minibuffer-window-active-p (minibuffer-window))
  135. (minibuffer-message text)
  136. (message "%s" text))))
  137. (defun slime-maybe-complete-as-filename ()
  138. "If point is at a string starting with \", complete it as filename.
  139. Return nil if point is not at filename."
  140. (when (save-excursion (re-search-backward "\"[^ \t\n]+\\="
  141. (max (point-min)
  142. (- (point) 1000)) t))
  143. (let ((comint-completion-addsuffix '("/" . "\"")))
  144. (comint-replace-by-expanded-filename)
  145. t)))
  146. (defun slime-complete-symbol* ()
  147. "Expand abbreviations and complete the symbol at point."
  148. ;; NB: It is only the name part of the symbol that we actually want
  149. ;; to complete -- the package prefix, if given, is just context.
  150. (or (slime-maybe-complete-as-filename)
  151. (slime-expand-abbreviations-and-complete)))
  152. (defun slime-c-p-c-completion-at-point ()
  153. #'slime-complete-symbol*)
  154. ;; FIXME: factorize
  155. (defun slime-expand-abbreviations-and-complete ()
  156. (let* ((end (move-marker (make-marker) (slime-symbol-end-pos)))
  157. (beg (move-marker (make-marker) (slime-symbol-start-pos)))
  158. (prefix (buffer-substring-no-properties beg end))
  159. (completion-result (slime-contextual-completions beg end))
  160. (completion-set (cl-first completion-result))
  161. (completed-prefix (cl-second completion-result)))
  162. (if (null completion-set)
  163. (progn (slime-minibuffer-respecting-message
  164. "Can't find completion for \"%s\"" prefix)
  165. (ding)
  166. (slime-complete-restore-window-configuration))
  167. ;; some XEmacs issue makes this distinction necessary
  168. (cond ((> (length completed-prefix) (- end beg))
  169. (goto-char end)
  170. (insert-and-inherit completed-prefix)
  171. (delete-region beg end)
  172. (goto-char (+ beg (length completed-prefix))))
  173. (t nil))
  174. (cond ((and (member completed-prefix completion-set)
  175. (slime-length= completion-set 1))
  176. (slime-minibuffer-respecting-message "Sole completion")
  177. (when slime-complete-symbol*-fancy
  178. (slime-complete-symbol*-fancy-bit))
  179. (slime-complete-restore-window-configuration))
  180. ;; Incomplete
  181. (t
  182. (when (member completed-prefix completion-set)
  183. (slime-minibuffer-respecting-message
  184. "Complete but not unique"))
  185. (when slime-c-p-c-unambiguous-prefix-p
  186. (let ((unambiguous-completion-length
  187. (cl-loop for c in completion-set
  188. minimizing (or (cl-mismatch completed-prefix c)
  189. (length completed-prefix)))))
  190. (goto-char (+ beg unambiguous-completion-length))))
  191. (slime-display-or-scroll-completions completion-set
  192. beg
  193. (max (point) end)))))))
  194. (defun slime-complete-symbol*-fancy-bit ()
  195. "Do fancy tricks after completing a symbol.
  196. \(Insert a space or close-paren based on arglist information.)"
  197. (let ((arglist (slime-retrieve-arglist (slime-symbol-at-point))))
  198. (unless (eq arglist :not-available)
  199. (let ((args
  200. ;; Don't intern these symbols
  201. (let ((obarray (make-vector 10 0)))
  202. (cdr (read arglist))))
  203. (function-call-position-p
  204. (save-excursion
  205. (backward-sexp)
  206. (equal (char-before) ?\())))
  207. (when function-call-position-p
  208. (if (null args)
  209. (execute-kbd-macro ")")
  210. (execute-kbd-macro " ")
  211. (when (and (slime-background-activities-enabled-p)
  212. (not (minibuffer-window-active-p (minibuffer-window))))
  213. (slime-echo-arglist))))))))
  214. (cl-defun slime-contextual-completions (beg end)
  215. "Return a list of completions of the token from BEG to END in the
  216. current buffer."
  217. (let ((token (buffer-substring-no-properties beg end)))
  218. (cond
  219. ((and (< beg (point-max))
  220. (string= (buffer-substring-no-properties beg (1+ beg)) ":"))
  221. ;; Contextual keyword completion
  222. (let ((completions
  223. (slime-completions-for-keyword token
  224. (save-excursion
  225. (goto-char beg)
  226. (slime-parse-form-upto-point)))))
  227. (when (cl-first completions)
  228. (cl-return-from slime-contextual-completions completions))
  229. ;; If no matching keyword was found, do regular symbol
  230. ;; completion.
  231. ))
  232. ((and (>= (length token) 2)
  233. (string= (cl-subseq token 0 2) "#\\"))
  234. ;; Character name completion
  235. (cl-return-from slime-contextual-completions
  236. (slime-completions-for-character token))))
  237. ;; Regular symbol completion
  238. (slime-completions token)))
  239. (defun slime-completions (prefix)
  240. (slime-eval `(swank:completions ,prefix ',(slime-current-package))))
  241. (defun slime-completions-for-keyword (prefix buffer-form)
  242. (slime-eval `(swank:completions-for-keyword ,prefix ',buffer-form)))
  243. (defun slime-completions-for-character (prefix)
  244. (cl-labels ((append-char-syntax (string) (concat "#\\" string)))
  245. (let ((result (slime-eval `(swank:completions-for-character
  246. ,(cl-subseq prefix 2)))))
  247. (when (car result)
  248. (list (mapcar #'append-char-syntax (car result))
  249. (append-char-syntax (cadr result)))))))
  250. ;;; Complete form
  251. (defun slime-complete-form ()
  252. "Complete the form at point.
  253. This is a superset of the functionality of `slime-insert-arglist'."
  254. (interactive)
  255. ;; Find the (possibly incomplete) form around point.
  256. (let ((buffer-form (slime-parse-form-upto-point)))
  257. (let ((result (slime-eval `(swank:complete-form ',buffer-form))))
  258. (if (eq result :not-available)
  259. (error "Could not generate completion for the form `%s'" buffer-form)
  260. (progn
  261. (just-one-space (if (looking-back "\\s(" (1- (point)))
  262. 0
  263. 1))
  264. (save-excursion
  265. (insert result)
  266. (let ((slime-close-parens-limit 1))
  267. (slime-close-all-parens-in-sexp)))
  268. (save-excursion
  269. (backward-up-list 1)
  270. (indent-sexp)))))))
  271. (provide 'slime-c-p-c)