sym-comp.el 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. ;;; sym-comp.el --- mode-dependent symbol completion
  2. ;; Copyright (C) 2004, 2008-2012 Free Software Foundation, Inc.
  3. ;; Author: Dave Love <fx@gnu.org>
  4. ;; Keywords: extensions
  5. ;; URL: http://www.loveshack.ukfsn.org/emacs
  6. ;; Obsolete-since: 23.2
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; This defines `symbol-complete', which is a generalization of the
  20. ;; old `lisp-complete-symbol'. It provides the following hooks to
  21. ;; allow major modes to set up completion appropriate for the mode:
  22. ;; `symbol-completion-symbol-function',
  23. ;; `symbol-completion-completions-function',
  24. ;; `symbol-completion-predicate-function',
  25. ;; `symbol-completion-transform-function'. Typically it is only
  26. ;; necessary for a mode to set
  27. ;; `symbol-completion-completions-function' locally and to bind
  28. ;; `symbol-complete' appropriately.
  29. ;; It's unfortunate that there doesn't seem to be a good way of
  30. ;; combining this with `complete-symbol'.
  31. ;; There is also `symbol-completion-try-complete', for use with
  32. ;; Hippie-exp.
  33. ;;; Code:
  34. ;;;; Mode-dependent symbol completion.
  35. (defun symbol-completion-symbol ()
  36. "Default `symbol-completion-symbol-function'.
  37. Uses `current-word' with the buffer narrowed to the part before
  38. point."
  39. (save-restriction
  40. ;; Narrow in case point is in the middle of a symbol -- we want
  41. ;; just the preceding part.
  42. (narrow-to-region (point-min) (point))
  43. (current-word)))
  44. (defvar symbol-completion-symbol-function 'symbol-completion-symbol
  45. "Function to return a partial symbol before point for completion.
  46. The value it returns should be a string (or nil).
  47. Major modes may set this locally if the default isn't appropriate.
  48. Beware: the length of the string STR returned need to be equal to the length
  49. of text before point that's subject to completion. Typically, this amounts
  50. to saying that STR is equal to
  51. \(buffer-substring (- (point) (length STR)) (point)).")
  52. (defvar symbol-completion-completions-function nil
  53. "Function to return possible symbol completions.
  54. It takes an argument which is the string to be completed and
  55. returns a value suitable for the second argument of
  56. `try-completion'. This value need not use the argument, i.e. it
  57. may be all possible completions, such as `obarray' in the case of
  58. Emacs Lisp.
  59. Major modes may set this locally to allow them to support
  60. `symbol-complete'. See also `symbol-completion-symbol-function',
  61. `symbol-completion-predicate-function' and
  62. `symbol-completion-transform-function'.")
  63. (defvar symbol-completion-predicate-function nil
  64. "If non-nil, function to return a predicate for selecting symbol completions.
  65. The function gets two args, the positions of the beginning and
  66. end of the symbol to be completed.
  67. Major modes may set this locally if the default isn't
  68. appropriate. This is a function returning a predicate so that
  69. the predicate can be context-dependent, e.g. to select only
  70. function names if point is at a function call position. The
  71. function's args may be useful for determining the context.")
  72. (defvar symbol-completion-transform-function nil
  73. "If non-nil, function to transform symbols in the symbol-completion buffer.
  74. E.g., for Lisp, it may annotate the symbol as being a function,
  75. not a variable.
  76. The function takes the symbol name as argument. If it needs to
  77. annotate this, it should return a value suitable as an element of
  78. the list passed to `display-completion-list'.
  79. The predicate being used for selecting completions (from
  80. `symbol-completion-predicate-function') is available
  81. dynamically-bound as `symbol-completion-predicate' in case the
  82. transform needs it.")
  83. (defvar symbol-completion-predicate)
  84. ;;;###autoload
  85. (defun symbol-complete (&optional predicate)
  86. "Perform completion of the symbol preceding point.
  87. This is done in a way appropriate to the current major mode,
  88. perhaps by interrogating an inferior interpreter. Compare
  89. `complete-symbol'.
  90. If no characters can be completed, display a list of possible completions.
  91. Repeating the command at that point scrolls the list.
  92. When called from a program, optional arg PREDICATE is a predicate
  93. determining which symbols are considered.
  94. This function requires `symbol-completion-completions-function'
  95. to be set buffer-locally. Variables `symbol-completion-symbol-function',
  96. `symbol-completion-predicate-function' and
  97. `symbol-completion-transform-function' are also consulted."
  98. (interactive)
  99. ;; Fixme: Punt to `complete-symbol' in this case?
  100. (unless (functionp symbol-completion-completions-function)
  101. (error "symbol-completion-completions-function not defined"))
  102. (let* ((pattern (or (funcall symbol-completion-symbol-function)
  103. (error "No preceding symbol to complete")))
  104. ;; FIXME: We assume below that `pattern' holds the text just
  105. ;; before point. This is a problem in the way
  106. ;; symbol-completion-symbol-function was defined.
  107. (predicate (or predicate
  108. (if symbol-completion-predicate-function
  109. (funcall symbol-completion-predicate-function
  110. (- (point) (length pattern))
  111. (point)))))
  112. (completions (funcall symbol-completion-completions-function
  113. pattern))
  114. ;; In case the transform needs to access it.
  115. (symbol-completion-predicate predicate)
  116. (completion-annotate-function
  117. (if (functionp symbol-completion-transform-function)
  118. (lambda (str)
  119. (car-safe (cdr-safe
  120. (funcall symbol-completion-transform-function
  121. str)))))))
  122. (completion-in-region (- (point) (length pattern)) (point)
  123. completions predicate)))
  124. (eval-when-compile (require 'hippie-exp))
  125. ;;;###autoload
  126. (defun symbol-completion-try-complete (old)
  127. "Completion function for use with `hippie-expand'.
  128. Uses `symbol-completion-symbol-function' and
  129. `symbol-completion-completions-function'. It is intended to be
  130. used something like this in a major mode which provides symbol
  131. completion:
  132. (if (featurep 'hippie-exp)
  133. (set (make-local-variable 'hippie-expand-try-functions-list)
  134. (cons 'symbol-completion-try-complete
  135. hippie-expand-try-functions-list)))"
  136. (when (and symbol-completion-symbol-function
  137. symbol-completion-completions-function)
  138. (unless old
  139. (let ((symbol (funcall symbol-completion-symbol-function)))
  140. (he-init-string (- (point) (length symbol)) (point))
  141. (if (not (he-string-member he-search-string he-tried-table))
  142. (push he-search-string he-tried-table))
  143. (setq he-expand-list
  144. (and symbol
  145. (funcall symbol-completion-completions-function symbol)))))
  146. (while (and he-expand-list
  147. (he-string-member (car he-expand-list) he-tried-table))
  148. (pop he-expand-list))
  149. (if he-expand-list
  150. (progn
  151. (he-substitute-string (pop he-expand-list))
  152. t)
  153. (if old (he-reset-string))
  154. nil)))
  155. ;;; Emacs Lisp symbol completion.
  156. (defun lisp-completion-symbol ()
  157. "`symbol-completion-symbol-function' for Lisp."
  158. (let ((end (point))
  159. (beg (with-syntax-table emacs-lisp-mode-syntax-table
  160. (save-excursion
  161. (backward-sexp 1)
  162. (while (= (char-syntax (following-char)) ?\')
  163. (forward-char 1))
  164. (point)))))
  165. (buffer-substring-no-properties beg end)))
  166. (defun lisp-completion-predicate (beg end)
  167. "`symbol-completion-predicate-function' for Lisp."
  168. (save-excursion
  169. (goto-char beg)
  170. (if (not (eq (char-before) ?\())
  171. (lambda (sym) ;why not just nil ? -sm
  172. ;To avoid interned symbols with
  173. ;no slots. -- fx
  174. (or (boundp sym) (fboundp sym)
  175. (symbol-plist sym)))
  176. ;; Looks like a funcall position. Let's double check.
  177. (if (condition-case nil
  178. (progn (up-list -2) (forward-char 1)
  179. (eq (char-after) ?\())
  180. (error nil))
  181. ;; If the first element of the parent list is an open
  182. ;; parenthesis we are probably not in a funcall position.
  183. ;; Maybe a `let' varlist or something.
  184. nil
  185. ;; Else, we assume that a function name is expected.
  186. 'fboundp))))
  187. (defun lisp-symbol-completion-transform ()
  188. "`symbol-completion-transform-function' for Lisp."
  189. (lambda (elt)
  190. (if (and (not (eq 'fboundp symbol-completion-predicate))
  191. (fboundp (intern elt)))
  192. (list elt " <f>")
  193. elt)))
  194. (provide 'sym-comp)
  195. ;;; sym-comp.el ends here