Mercurial > emacs
annotate lisp/progmodes/sym-comp.el @ 94659:b631bc2a3818
Fix last fix.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Tue, 06 May 2008 03:31:55 +0000 |
parents | bae32624018f |
children | 52b7a8c22af5 |
rev | line source |
---|---|
92054 | 1 ;;; sym-comp.el --- mode-dependent symbol completion |
2 | |
92250
a2c5eb229cdf
Change copyright to FSF, per the author's statement:
Glenn Morris <rgm@gnu.org>
parents:
92229
diff
changeset
|
3 ;; Copyright (C) 2004, 2008 Free Software Foundation, Inc. |
92054 | 4 |
5 ;; Author: Dave Love <fx@gnu.org> | |
6 ;; Keywords: extensions | |
7 ;; URL: http://www.loveshack.ukfsn.org/emacs | |
8 | |
92256 | 9 ;; This file is part of GNU Emacs. |
10 | |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
92054 | 12 ;; it under the terms of the GNU General Public License as published by |
92229 | 13 ;; the Free Software Foundation; either version 3, or (at your option) |
92054 | 14 ;; any later version. |
15 | |
92256 | 16 ;; GNU Emacs is distributed in the hope that it will be useful, |
92054 | 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 ;; GNU General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
92256 | 22 ;; along with GNU Emacs; see the file COPYING. If not, write to the |
92250
a2c5eb229cdf
Change copyright to FSF, per the author's statement:
Glenn Morris <rgm@gnu.org>
parents:
92229
diff
changeset
|
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
a2c5eb229cdf
Change copyright to FSF, per the author's statement:
Glenn Morris <rgm@gnu.org>
parents:
92229
diff
changeset
|
24 ;; Boston, MA 02110-1301, USA. |
92054 | 25 |
26 ;;; Commentary: | |
27 | |
28 ;; This defines `symbol-complete', which is a generalization of the | |
29 ;; old `lisp-complete-symbol'. It provides the following hooks to | |
30 ;; allow major modes to set up completion appropriate for the mode: | |
31 ;; `symbol-completion-symbol-function', | |
32 ;; `symbol-completion-completions-function', | |
33 ;; `symbol-completion-predicate-function', | |
34 ;; `symbol-completion-transform-function'. Typically it is only | |
35 ;; necessary for a mode to set | |
36 ;; `symbol-completion-completions-function' locally and to bind | |
37 ;; `symbol-complete' appropriately. | |
38 | |
39 ;; It's unfortunate that there doesn't seem to be a good way of | |
40 ;; combining this with `complete-symbol'. | |
41 | |
42 ;; There is also `symbol-completion-try-complete', for use with | |
43 ;; Hippie-exp. | |
44 | |
45 ;;; Code: | |
46 | |
47 ;;;; Mode-dependent symbol completion. | |
48 | |
49 (defun symbol-completion-symbol () | |
50 "Default `symbol-completion-symbol-function'. | |
51 Uses `current-word' with the buffer narrowed to the part before | |
52 point." | |
53 (save-restriction | |
54 ;; Narrow in case point is in the middle of a symbol -- we want | |
55 ;; just the preceeding part. | |
56 (narrow-to-region (point-min) (point)) | |
57 (current-word))) | |
58 | |
59 (defvar symbol-completion-symbol-function 'symbol-completion-symbol | |
60 "Function to return a partial symbol before point for completion. | |
61 The value it returns should be a string (or nil). | |
62 Major modes may set this locally if the default isn't appropriate.") | |
63 | |
64 (defvar symbol-completion-completions-function nil | |
65 "Function to return possible symbol completions. | |
66 It takes an argument which is the string to be completed and | |
67 returns a value suitable for the second argument of | |
68 `try-completion'. This value need not use the argument, i.e. it | |
69 may be all possible completions, such as `obarray' in the case of | |
70 Emacs Lisp. | |
71 | |
72 Major modes may set this locally to allow them to support | |
73 `symbol-complete'. See also `symbol-completion-symbol-function', | |
74 `symbol-completion-predicate-function' and | |
75 `symbol-completion-transform-function'.") | |
76 | |
77 (defvar symbol-completion-predicate-function nil | |
78 "If non-nil, function to return a predicate for selecting symbol completions. | |
79 The function gets two args, the positions of the beginning and | |
80 end of the symbol to be completed. | |
81 | |
82 Major modes may set this locally if the default isn't | |
83 appropriate. This is a function returning a predicate so that | |
84 the predicate can be context-dependent, e.g. to select only | |
85 function names if point is at a function call position. The | |
86 function's args may be useful for determining the context.") | |
87 | |
88 (defvar symbol-completion-transform-function nil | |
89 "If non-nil, function to transform symbols in the symbol-completion buffer. | |
90 E.g., for Lisp, it may annotate the symbol as being a function, | |
91 not a variable. | |
92 | |
93 The function takes the symbol name as argument. If it needs to | |
94 annotate this, it should return a value suitable as an element of | |
95 the list passed to `display-completion-list'. | |
96 | |
97 The predicate being used for selecting completions (from | |
98 `symbol-completion-predicate-function') is available | |
99 dynamically-bound as `symbol-completion-predicate' in case the | |
100 transform needs it.") | |
101 | |
102 (defvar displayed-completions) | |
103 | |
104 ;;;###autoload | |
105 (defun symbol-complete (&optional predicate) | |
106 "Perform completion of the symbol preceding point. | |
107 This is done in a way appropriate to the current major mode, | |
108 perhaps by interrogating an inferior interpreter. Compare | |
109 `complete-symbol'. | |
110 If no characters can be completed, display a list of possible completions. | |
111 Repeating the command at that point scrolls the list. | |
112 | |
113 When called from a program, optional arg PREDICATE is a predicate | |
114 determining which symbols are considered. | |
115 | |
116 This function requires `symbol-completion-completions-function' | |
117 to be set buffer-locally. Variables `symbol-completion-symbol-function', | |
118 `symbol-completion-predicate-function' and | |
119 `symbol-completion-transform-function' are also consulted." | |
120 (interactive) | |
121 ;; Fixme: Punt to `complete-symbol' in this case? | |
122 (unless (functionp symbol-completion-completions-function) | |
123 (error "symbol-completion-completions-function not defined")) | |
124 (let ((window (get-buffer-window "*Completions*"))) | |
125 (let* ((pattern (or (funcall symbol-completion-symbol-function) | |
126 (error "No preceding symbol to complete"))) | |
127 (predicate (or predicate | |
128 (if symbol-completion-predicate-function | |
129 (funcall symbol-completion-predicate-function | |
130 (- (point) (length pattern)) | |
131 (point))))) | |
132 (completions (funcall symbol-completion-completions-function | |
133 pattern)) | |
134 (completion (try-completion pattern completions predicate))) | |
135 ;; If this command was repeated, and there's a fresh completion | |
136 ;; window with a live buffer and a displayed completion list | |
137 ;; matching the current completions, then scroll the window. | |
138 (unless (and (eq last-command this-command) | |
139 window (window-live-p window) (window-buffer window) | |
140 (buffer-name (window-buffer window)) | |
141 (with-current-buffer (window-buffer window) | |
142 (if (equal displayed-completions | |
143 (all-completions pattern completions predicate)) | |
144 (progn | |
145 (if (pos-visible-in-window-p (point-max) window) | |
146 (set-window-start window (point-min)) | |
147 (save-selected-window | |
148 (select-window window) | |
149 (scroll-up))) | |
150 t)))) | |
151 ;; Otherwise, do completion. | |
152 (cond ((eq completion t)) | |
153 ((null completion) | |
154 (message "Can't find completion for \"%s\"" pattern) | |
155 (ding)) | |
156 ((not (string= pattern completion)) | |
157 (delete-region (- (point) (length pattern)) (point)) | |
158 (insert completion)) | |
159 (t | |
160 (message "Making completion list...") | |
161 (let* ((list (all-completions pattern completions predicate)) | |
162 ;; In case the transform needs to access it. | |
163 (symbol-completion-predicate predicate) | |
164 ;; Copy since list is side-effected by sorting. | |
165 (copy (copy-sequence list))) | |
166 (setq list (sort list 'string<)) | |
167 (if (functionp symbol-completion-transform-function) | |
168 (setq list | |
169 (mapcar (funcall | |
170 symbol-completion-transform-function) | |
171 list))) | |
172 (with-output-to-temp-buffer "*Completions*" | |
173 (condition-case () | |
174 (display-completion-list list pattern) ; Emacs 22 | |
175 (error (display-completion-list list)))) | |
176 ;; Record the list for determining whether to scroll | |
177 ;; (above). | |
178 (with-current-buffer "*Completions*" | |
179 (set (make-local-variable 'displayed-completions) copy))) | |
180 (message "Making completion list...%s" "done"))))))) | |
181 | |
182 (eval-when-compile (require 'hippie-exp)) | |
183 | |
184 ;;;###autoload | |
185 (defun symbol-completion-try-complete (old) | |
186 "Completion function for use with `hippie-expand'. | |
187 Uses `symbol-completion-symbol-function' and | |
188 `symbol-completion-completions-function'. It is intended to be | |
189 used something like this in a major mode which provides symbol | |
190 completion: | |
191 | |
192 (if (featurep 'hippie-exp) | |
193 (set (make-local-variable 'hippie-expand-try-functions-list) | |
194 (cons 'symbol-completion-try-complete | |
195 hippie-expand-try-functions-list)))" | |
196 (when (and symbol-completion-symbol-function | |
197 symbol-completion-completions-function) | |
198 (unless old | |
199 (let ((symbol (funcall symbol-completion-symbol-function))) | |
200 (he-init-string (- (point) (length symbol)) (point)) | |
201 (if (not (he-string-member he-search-string he-tried-table)) | |
202 (push he-search-string he-tried-table)) | |
203 (setq he-expand-list | |
204 (and symbol | |
205 (funcall symbol-completion-completions-function symbol))))) | |
206 (while (and he-expand-list | |
207 (he-string-member (car he-expand-list) he-tried-table)) | |
208 (pop he-expand-list)) | |
209 (if he-expand-list | |
210 (progn | |
211 (he-substitute-string (pop he-expand-list)) | |
212 t) | |
213 (if old (he-reset-string)) | |
214 nil))) | |
215 | |
216 ;;; Emacs Lisp symbol completion. | |
217 | |
218 (defun lisp-completion-symbol () | |
219 "`symbol-completion-symbol-function' for Lisp." | |
220 (let ((end (point)) | |
221 (beg (with-syntax-table emacs-lisp-mode-syntax-table | |
222 (save-excursion | |
223 (backward-sexp 1) | |
224 (while (= (char-syntax (following-char)) ?\') | |
225 (forward-char 1)) | |
226 (point))))) | |
227 (buffer-substring-no-properties beg end))) | |
228 | |
229 (defun lisp-completion-predicate (beg end) | |
230 "`symbol-completion-predicate-function' for Lisp." | |
231 (save-excursion | |
232 (goto-char beg) | |
233 (if (not (eq (char-before) ?\()) | |
234 (lambda (sym) ;why not just nil ? -sm | |
235 ;To avoid interned symbols with | |
236 ;no slots. -- fx | |
237 (or (boundp sym) (fboundp sym) | |
238 (symbol-plist sym))) | |
239 ;; Looks like a funcall position. Let's double check. | |
240 (if (condition-case nil | |
241 (progn (up-list -2) (forward-char 1) | |
242 (eq (char-after) ?\()) | |
243 (error nil)) | |
244 ;; If the first element of the parent list is an open | |
245 ;; parenthesis we are probably not in a funcall position. | |
246 ;; Maybe a `let' varlist or something. | |
247 nil | |
248 ;; Else, we assume that a function name is expected. | |
249 'fboundp)))) | |
250 | |
251 (defvar symbol-completion-predicate) | |
252 | |
253 (defun lisp-symbol-completion-transform () | |
254 "`symbol-completion-transform-function' for Lisp." | |
255 (lambda (elt) | |
256 (if (and (not (eq 'fboundp symbol-completion-predicate)) | |
257 (fboundp (intern elt))) | |
258 (list elt " <f>") | |
259 elt))) | |
260 | |
261 (provide 'sym-comp) | |
92123 | 262 |
263 ;; arch-tag: 6fcce616-f3c4-4751-94b4-710e83144124 | |
92054 | 264 ;;; sym-comp.el ends here |