Mercurial > hg > xemacs-beta
comparison lisp/ilisp/completer.no-fun.el @ 4:b82b59fe008d r19-15b3
Import from CVS: tag r19-15b3
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:46:56 +0200 |
parents | |
children | ec9a17fef872 |
comparison
equal
deleted
inserted
replaced
3:30df88044ec6 | 4:b82b59fe008d |
---|---|
1 ;;; -*-Emacs-Lisp-*- | |
2 ;;;%Header | |
3 ;;; | |
4 ;;; Rcs_Info: completer.el,v 3.23 1993/09/03 02:05:07 ivan Rel $ | |
5 ;;; | |
6 ;;; Partial completion mechanism for GNU Emacs. Version 3.03 | |
7 ;;; Copyright (C) 1990, 1991, 1992 Chris McConnell, ccm@cs.cmu.edu. | |
8 ;;; Thanks to Bjorn Victor for suggestions, testing, and patches for | |
9 ;;; file completion. | |
10 | |
11 ;;; This file is part of GNU Emacs. | |
12 | |
13 ;;; GNU Emacs is distributed in the hope that it will be useful, | |
14 ;;; but WITHOUT ANY WARRANTY. No author or distributor | |
15 ;;; accepts responsibility to anyone for the consequences of using it | |
16 ;;; or for whether it serves any particular purpose or works at all, | |
17 ;;; unless he says so in writing. Refer to the GNU Emacs General Public | |
18 ;;; License for full details. | |
19 ;;; Everyone is granted permission to copy, modify and redistribute | |
20 ;;; GNU Emacs, but only under the conditions described in the | |
21 ;;; GNU Emacs General Public License. A copy of this license is | |
22 ;;; supposed to have been given to you along with GNU Emacs so you | |
23 ;;; can know your rights and responsibilities. It should be in a | |
24 ;;; file named COPYING. Among other things, the copyright notice | |
25 ;;; and this notice must be preserved on all copies. | |
26 | |
27 ;;; When loaded, this file extends the standard completion mechanisms | |
28 ;;; so that they perform pattern matching completions. There is also | |
29 ;;; an interface that allows it to be used by other programs. The | |
30 ;;; completion rules are: | |
31 ;;; | |
32 ;;; 1) If what has been typed matches any possibility, do normal | |
33 ;;; completion. | |
34 ;;; | |
35 ;;; 2) Otherwise, generate a regular expression such that | |
36 ;;; completer-words delimit words and generate all possible matches. | |
37 ;;; The variable completer-any-delimiter can be set to a character | |
38 ;;; that matches any delimiter. If it were " ", then "by d" would be | |
39 ;;; byte-recompile-directory. If completer-use-words is T, a match is | |
40 ;;; unique if it is the only one with the same number of words. If | |
41 ;;; completer-use-words is NIL, a match is unique if it is the only | |
42 ;;; possibility. If you ask the completer to use its best guess, it | |
43 ;;; will be the shortest match of the possibilities unless | |
44 ;;; completer-exact is T. | |
45 ;;; | |
46 ;;; 3) For filenames, if completer-complete-filenames is T, each | |
47 ;;; pathname component will be individually completed, otherwise only | |
48 ;;; the final component will be completed. If you are using a | |
49 ;;; distributed file system like afs, you may want to set up a | |
50 ;;; symbolic link in your home directory or add pathname components to | |
51 ;;; completer-file-skip so that the pathname components that go across | |
52 ;;; machines do not get expanded. | |
53 ;;; | |
54 ;;; SPACE, TAB, LFD, RET, and ? do normal completion if possible | |
55 ;;; otherwise they do partial completion. In addition, C-DEL will | |
56 ;;; undo the last partial expansion or contraction. M-RET will always | |
57 ;;; complete to the current match before returning. This is useful | |
58 ;;; when any string is possible, but you want to complete to a string | |
59 ;;; as when calling find-file. The bindings can be changed by using | |
60 ;;; completer-load-hook. | |
61 ;;; | |
62 ;;; Modes that use comint-dynamic-complete (like cmushell and ilisp) | |
63 ;;; will also do partial completion as will M-tab in Emacs LISP. | |
64 ;;; | |
65 ;;; Examples: | |
66 ;;; a-f auto-fill-mode | |
67 ;;; b--d *beginning-of-defun or byte-recompile-directory | |
68 ;;; by d *byte-recompile-directory if completer-any-delimiter is " " | |
69 ;;; ~/i.e *~/ilisp.el or ~/il-el.el or ~/ilisp.elc | |
70 ;;; /u/mi/ /usr/misc/ | |
71 ;;; | |
72 | |
73 ;;;%Globals | |
74 ;;;%%Switches | |
75 (defvar completer-load-hook nil | |
76 "Hook called when minibuffer partial completion is loaded.") | |
77 | |
78 (defvar completer-disable nil | |
79 "*If T, turn off partial completion. Use the command | |
80 \\[completer-toggle] to set this.") | |
81 | |
82 (defvar completer-complete-filenames t | |
83 "*If T, then each component of a filename will be completed, | |
84 otherwise just the final component will be completed.") | |
85 | |
86 (defvar completer-use-words nil ; jwz: this is HATEFUL! | |
87 "*If T, then prefer completions with the same number of words as the | |
88 pattern.") | |
89 | |
90 (defvar completer-words "---. <" | |
91 "*Delimiters used in partial completions. It should be a set of | |
92 characters suitable for inclusion in a [] regular expression.") | |
93 | |
94 (defvar completer-any-delimiter nil | |
95 "*If a character, then a delimiter in the pattern that matches the | |
96 character will match any delimiter in completer-words.") | |
97 | |
98 (defvar completer-file-skip "^cs/$\\|@sys\\|.edu/$\\|.gov/$\\|.com/$\\|:/$" | |
99 "*Regular expression for pathname components to not complete.") | |
100 | |
101 (defvar completer-exact nil | |
102 "*If T, then you must have an exact match. Otherwise, the shortest | |
103 string that matches the pattern will be used.") | |
104 | |
105 (defvar completer-cache-size 100 | |
106 "*Size of cache to use for partially completed pathnames.") | |
107 | |
108 (defvar completer-use-cache t | |
109 "*Set to nil to disable the partially completed pathname cache.") | |
110 | |
111 ;;;%%Internal | |
112 (defvar completer-last-pattern "" | |
113 "The last pattern expanded.") | |
114 | |
115 (defvar completer-message nil | |
116 "T if temporary message was just displayed.") | |
117 | |
118 (defvar completer-path-cache nil | |
119 "Cache of (path . choices) for completer.") | |
120 | |
121 (defvar completer-string nil "Last completer string.") | |
122 (defvar completer-table nil "Last completer table.") | |
123 (defvar completer-pred nil "Last completer pred.") | |
124 (defvar completer-mode nil "Last completer mode.") | |
125 (defvar completer-result nil "Last completer result.") | |
126 | |
127 ;;;%Utilities | |
128 (defun completer-message (message &optional point) | |
129 "Display MESSAGE at optional POINT for two seconds." | |
130 (setq point (or point (point-max)) | |
131 completer-message t) | |
132 (let ((end | |
133 (save-excursion | |
134 (goto-char point) | |
135 (insert message) | |
136 (point))) | |
137 (inhibit-quit t)) | |
138 (sit-for 2) | |
139 (delete-region point end) | |
140 (if (and quit-flag | |
141 ;;(not (eq 'lucid-19 ilisp-emacs-version-id)) | |
142 (not (string-match "Lucid" emacs-version)) | |
143 ) | |
144 (setq quit-flag nil | |
145 unread-command-char 7)))) | |
146 | |
147 ;;; | |
148 (defun completer-deleter (regexp choices &optional keep) | |
149 "Destructively remove strings that match REGEXP in CHOICES and | |
150 return the modified list. If optional KEEP, then keep entries that | |
151 match regexp." | |
152 (let* ((choiceb choices) | |
153 choicep) | |
154 (if keep | |
155 (progn | |
156 (while (and choiceb (not (string-match regexp (car choiceb)))) | |
157 (setq choiceb (cdr choiceb))) | |
158 (setq choicep choiceb) | |
159 (while (cdr choicep) | |
160 (if (string-match regexp (car (cdr choicep))) | |
161 (setq choicep (cdr choicep)) | |
162 (rplacd choicep (cdr (cdr choicep)))))) | |
163 (while (and choiceb (string-match regexp (car choiceb))) | |
164 (setq choiceb (cdr choiceb))) | |
165 (setq choicep choiceb) | |
166 (while (cdr choicep) | |
167 (if (string-match regexp (car (cdr choicep))) | |
168 (rplacd choicep (cdr (cdr choicep))) | |
169 (setq choicep (cdr choicep))))) | |
170 choiceb)) | |
171 | |
172 ;;;%%Regexp | |
173 (defun completer-regexp (string delimiters any) | |
174 "Convert STRING into a regexp with words delimited by characters in | |
175 DELIMITERS. Any delimiter in STRING that is the same as ANY will | |
176 match any delimiter." | |
177 (let* ((delimiter-reg (concat "[" delimiters "]")) | |
178 (limit (length string)) | |
179 (pos 0) | |
180 (regexp "^")) | |
181 (while (and (< pos limit) (string-match delimiter-reg string pos)) | |
182 (let* ((begin (match-beginning 0)) | |
183 (end (match-end 0)) | |
184 (delimiter (substring string begin end)) | |
185 (anyp (eq (elt string begin) any))) | |
186 (setq regexp | |
187 (format "%s%s[^%s]*%s" | |
188 regexp | |
189 (regexp-quote (substring string pos begin)) | |
190 (if anyp delimiters delimiter) | |
191 (if anyp delimiter-reg delimiter)) | |
192 pos end))) | |
193 (if (<= pos limit) | |
194 (setq regexp (concat regexp | |
195 (regexp-quote (substring string pos limit))))))) | |
196 | |
197 ;;; | |
198 (defun completer-words (regexp string &optional limit) | |
199 "Return the number of words matching REGEXP in STRING up to LIMIT." | |
200 (setq limit (or limit 1000)) | |
201 (let ((count 1) | |
202 (pos 0)) | |
203 (while (and (string-match regexp string pos) (<= count limit)) | |
204 (setq count (1+ count) | |
205 pos (match-end 0))) | |
206 count)) | |
207 | |
208 ;;;%Matcher | |
209 (defun completer-matches (string choices delimiters any) | |
210 "Return STRING's matches in CHOICES using DELIMITERS and wildcard | |
211 ANY to segment the strings." | |
212 (let* ((regexp (concat "[" delimiters "]")) | |
213 (from nil) | |
214 (to 0) | |
215 (pattern nil) | |
216 (len (length string)) | |
217 (matches nil) | |
218 sub sublen choice word wordlen pat) | |
219 ;; Segment pattern | |
220 (while (< (or from 0) len) | |
221 (setq to (or (string-match regexp string (if from (1+ from))) len)) | |
222 (if (eq (elt string (or from 0)) completer-any-delimiter) | |
223 (setq sub (substring string (if from (1+ from) 0) to) | |
224 sublen (- (length sub))) | |
225 (setq sub (substring string (or from 0) to) | |
226 sublen (length sub))) | |
227 (setq pattern (cons (cons sub sublen) pattern) | |
228 from to)) | |
229 (setq pattern (reverse pattern)) | |
230 ;; Find choices that match patterns | |
231 (setq regexp (concat "[" delimiters "]")) | |
232 (while choices | |
233 (setq choice (car choices) | |
234 word pattern | |
235 from 0) | |
236 (while (and word from | |
237 (let* (begin end) | |
238 (if (< (setq wordlen (cdr (setq pat (car word)))) 0) | |
239 (setq begin (1+ from) | |
240 end (+ begin (- wordlen))) | |
241 (setq begin from | |
242 end (+ begin wordlen))) | |
243 (and (<= end (length choice)) | |
244 (or (zerop wordlen) | |
245 (string-equal | |
246 (car pat) | |
247 (substring choice begin end)))))) | |
248 (setq from (string-match regexp choice | |
249 (if (and (zerop from) (zerop wordlen)) | |
250 from | |
251 (1+ from))) | |
252 word (cdr word))) | |
253 (if (not word) (setq matches (cons choice matches))) | |
254 (setq choices (cdr choices))) | |
255 matches)) | |
256 | |
257 ;;; | |
258 (defun completer-choice (string choices delimiters use-words) | |
259 "Return the best match of STRING in CHOICES with DELIMITERS between | |
260 words and T if it is unique. A match is unique if it is the only | |
261 possibility or when USE-WORDS the only possibility with the same | |
262 number of words. The shortest string of multiple possiblities will be | |
263 the best match." | |
264 (or (if (null (cdr choices)) (cons (car choices) t)) | |
265 (let* ((regexp (concat "[^" delimiters "]*[" delimiters "]")) | |
266 (words (if use-words (completer-words regexp string))) | |
267 (choice choices) | |
268 (unique-p nil) | |
269 (match nil) | |
270 (match-count nil) | |
271 (match-len 1000)) | |
272 (while choice | |
273 (let* ((current (car choice)) | |
274 (length (length current))) | |
275 (if match-count | |
276 (if (= (completer-words regexp current words) words) | |
277 (progn | |
278 (setq unique-p nil) | |
279 (if (< length match-len) | |
280 (setq match current | |
281 match-len length)))) | |
282 (if (and use-words | |
283 (= (completer-words regexp current words) words)) | |
284 (setq match current | |
285 match-len length | |
286 match-count t | |
287 unique-p t) | |
288 (if (< length match-len) | |
289 (setq match current | |
290 match-len length))))) | |
291 (setq choice (cdr choice))) | |
292 (cons match unique-p)))) | |
293 | |
294 ;;;%Completer | |
295 ;;;%%Utilities | |
296 (defun completer-region (delimiters) | |
297 "Return the completion region bounded by characters in DELIMITERS | |
298 for the current buffer assuming that point is in it." | |
299 (cons (save-excursion (skip-chars-backward delimiters) (point)) | |
300 (save-excursion (skip-chars-forward delimiters) (point)))) | |
301 | |
302 ;;; | |
303 (defun completer-last-component (string) | |
304 "Return the start of the last filename component in STRING." | |
305 (let ((last (1- (length string)) ) | |
306 (match 0) | |
307 (end 0)) | |
308 (while (and (setq match (string-match "/" string end)) (< match last)) | |
309 (setq end (1+ match))) | |
310 end)) | |
311 | |
312 ;;; | |
313 (defun completer-match-record (string matches delimiters any dir mode) | |
314 "Return (match lcs choices unique) for STRING in MATCHES with | |
315 DELIMITERS or ANY wildcards and DIR if a filename when in MODE." | |
316 (let ((pattern (if dir | |
317 (substring string (completer-last-component string)) | |
318 string))) | |
319 (setq matches (completer-matches pattern matches delimiters any)) | |
320 (if (cdr matches) | |
321 (let ((match | |
322 (if (not completer-exact) | |
323 (completer-choice | |
324 pattern matches delimiters completer-use-words))) | |
325 (lcs (concat dir (try-completion "" (mapcar 'list matches))))) | |
326 (list (if match (concat dir (car match))) | |
327 lcs | |
328 matches (cdr match))) | |
329 (if matches | |
330 (let ((match (concat dir (car matches)))) | |
331 (list match match matches t)) | |
332 (list nil nil nil nil))))) | |
333 | |
334 ;;;%%Complete file | |
335 (defun completer-extension-regexp (extensions) | |
336 "Return a regexp that matches any of EXTENSIONS." | |
337 (let ((regexp "\\(")) | |
338 (while extensions | |
339 (setq regexp (concat regexp (car extensions) | |
340 (if (cdr extensions) "\\|")) | |
341 extensions (cdr extensions))) | |
342 (concat regexp "\\)$"))) | |
343 | |
344 ;;; | |
345 (defun completer-flush () | |
346 "Flush completer's pathname cache." | |
347 (interactive) | |
348 (setq completer-path-cache nil)) | |
349 | |
350 ;;; | |
351 (defun completer-cache (path pred words any mode) | |
352 "Check to see if PATH is in path cache with PRED, WORDS, ANY and | |
353 MODE." | |
354 (let* ((last nil) | |
355 (ptr completer-path-cache) | |
356 (size 0) | |
357 (result nil)) | |
358 (if completer-use-cache | |
359 (while ptr | |
360 (let ((current (car (car ptr)))) | |
361 (if (string-equal current path) | |
362 (progn | |
363 (if last | |
364 (progn | |
365 (rplacd last (cdr ptr)) | |
366 (rplacd ptr completer-path-cache) | |
367 (setq completer-path-cache ptr))) | |
368 (setq result (cdr (car ptr)) | |
369 ptr nil)) | |
370 (if (cdr ptr) (setq last ptr)) | |
371 (setq size (1+ size) | |
372 ptr (cdr ptr)))))) | |
373 (or result | |
374 (let* ((choices | |
375 (completer path 'read-file-name-internal pred words any | |
376 mode t))) | |
377 (if (and (or (car (cdr (cdr (cdr choices)))) | |
378 (string= path (car choices))) | |
379 (eq (elt (car choices) (1- (length (car choices)))) ?/)) | |
380 (progn | |
381 (if (>= size completer-cache-size) (rplacd last nil)) | |
382 (setq completer-path-cache | |
383 (cons (cons path choices) completer-path-cache)))) | |
384 choices)))) | |
385 | |
386 ;;; | |
387 (defun completer-file (string pred words any mode) | |
388 "Return (match common-substring matches unique-p) for STRING using | |
389 read-file-name-internal for choices that pass PRED using WORDS to | |
390 delimit words. Optional ANY is a delimiter that matches any of the | |
391 delimiters in WORD. If optional MODE is nil or 'help then possible | |
392 matches will always be returned." | |
393 (let* ((case-fold-search completion-ignore-case) | |
394 (last (and (eq mode 'exit-ok) (completer-last-component string))) | |
395 (position | |
396 ;; Special hack for CMU RFS filenames | |
397 (if (string-match "^/\\.\\./[^/]*/" string) | |
398 (match-end 0) | |
399 (string-match "[^~/]" string))) | |
400 (new (substring string 0 position)) | |
401 (user (if (string= new "~") | |
402 (setq new (file-name-directory (expand-file-name new))))) | |
403 (words (concat words "/")) | |
404 (len (length string)) | |
405 (choices nil) | |
406 end | |
407 (old-choices (list nil nil nil nil))) | |
408 (while position | |
409 (let* ((begin (string-match "/" string position)) | |
410 (exact-p nil)) | |
411 (setq end (if begin (match-end 0)) | |
412 choices | |
413 ;; Ends with a /, so check files in directory | |
414 (if (and (memq mode '(nil help)) (= position len)) | |
415 (completer-match-record | |
416 "" | |
417 ;; This assumes that .. and . come at the end | |
418 (let* ((choices | |
419 (all-completions new 'read-file-name-internal)) | |
420 (choicep choices)) | |
421 (if (string= (car choicep) "../") | |
422 (cdr (cdr choicep)) | |
423 (while (cdr choicep) | |
424 (if (string= (car (cdr choicep)) "../") | |
425 (rplacd choicep nil)) | |
426 (setq choicep (cdr choicep))) | |
427 choices)) | |
428 words any new mode) | |
429 (if (eq position last) | |
430 (let ((new (concat new (substring string position)))) | |
431 (list new new nil t)) | |
432 (let ((component (substring string position end))) | |
433 (if (and end | |
434 (string-match completer-file-skip component)) | |
435 ;; Assume component is complete | |
436 (list (concat new component) | |
437 (concat new component) | |
438 nil t) | |
439 (completer-cache | |
440 (concat new component) | |
441 pred words any mode)))))) | |
442 ;; Keep going if unique or we match exactly | |
443 (if (or (car (cdr (cdr (cdr choices)))) | |
444 (setq exact-p | |
445 (string= (concat new (substring string position end)) | |
446 (car choices)))) | |
447 (setq old-choices | |
448 (let* ((lcs (car (cdr choices))) | |
449 (matches (car (cdr (cdr choices)))) | |
450 (slash (and lcs (string-match "/$" lcs)))) | |
451 (list nil | |
452 (if slash (substring lcs 0 slash) lcs) | |
453 (if (and (cdr matches) | |
454 (or (eq mode 'help) (not exact-p))) | |
455 matches) | |
456 nil)) | |
457 new (car choices) | |
458 position end) | |
459 ;; Its ok to not match user names because they may be in | |
460 ;; different root directories | |
461 (if (and (= position 1) (= (elt string 0) ?~)) | |
462 (setq new (substring string 0 end) | |
463 choices (list new new (list new) t) | |
464 user nil | |
465 position end) | |
466 (setq position nil))))) | |
467 (if (not (car choices)) | |
468 (setq choices old-choices)) | |
469 (if (and (car choices) | |
470 (not (eq mode 'help)) | |
471 (not (car (cdr (cdr (cdr choices)))))) | |
472 ;; Try removing completion ignored extensions | |
473 (let* ((extensions | |
474 (completer-extension-regexp completion-ignored-extensions)) | |
475 (choiceb (car (cdr (cdr choices)))) | |
476 (choicep choiceb) | |
477 (isext nil) | |
478 (noext nil)) | |
479 (while choicep | |
480 (if (string-match extensions (car choicep)) | |
481 (setq isext t) | |
482 (setq noext t)) | |
483 (if (and isext noext) | |
484 ;; There are matches besides extensions | |
485 (setq choiceb (completer-deleter extensions choiceb) | |
486 choicep nil) | |
487 (setq choicep (cdr choicep)))) | |
488 (if (and isext noext) | |
489 (setq choices | |
490 (completer-match-record | |
491 (if end (substring string end) "") | |
492 choiceb words any | |
493 (file-name-directory (car (cdr choices))) | |
494 mode))))) | |
495 (if user | |
496 (let ((match (car choices)) | |
497 (lcs (car (cdr choices))) | |
498 (len (length user))) | |
499 (setq choices | |
500 (cons (if match (concat "~" (substring match len))) | |
501 (cons (if lcs (concat "~" (substring lcs len))) | |
502 (cdr (cdr choices))))))) | |
503 choices)) | |
504 | |
505 ;;;%Exported program interface | |
506 ;;;%%Completer | |
507 (defun completer (string table pred words | |
508 &optional any mode file-p) | |
509 "Return (match common-substring matches unique-p) for STRING in | |
510 TABLE for choices that pass PRED using WORDS to delimit words. If the | |
511 flag completer-complete-filenames is T and the table is | |
512 read-file-name-internal, then filename components will be individually | |
513 expanded. Optional ANY is a delimiter that can match any delimiter in | |
514 WORDS. Optional MODE is nil for complete, 'help for help and 'exit | |
515 for exit." | |
516 (if (and (stringp completer-string) | |
517 (string= string completer-string) | |
518 (eq table completer-table) | |
519 (eq pred completer-pred) | |
520 (not file-p) | |
521 (or (eq mode completer-mode) | |
522 (not (memq table '(read-file-name-internal | |
523 read-directory-name-internal))))) | |
524 completer-result | |
525 (setq | |
526 completer-string "" | |
527 completer-table table | |
528 completer-pred pred | |
529 completer-mode mode | |
530 completer-result | |
531 (if (and completer-complete-filenames | |
532 (not file-p) (eq table 'read-file-name-internal)) | |
533 (completer-file string pred words any mode) | |
534 (let* ((file-p (or file-p (eq table 'read-file-name-internal))) | |
535 (case-fold-search completion-ignore-case) | |
536 (pattern (concat "[" words "]")) | |
537 (component (if file-p (completer-last-component string))) | |
538 (dir (if component (substring string 0 component))) | |
539 (string (if dir (substring string component) string)) | |
540 (has-words (or (string-match pattern string) | |
541 (length string)))) | |
542 (if (and file-p (string-match "^\\$" string)) | |
543 ;; Handle environment variables | |
544 (let ((match | |
545 (getenv (substring string 1 | |
546 (string-match "/" string))))) | |
547 (if match (setq match (concat match "/"))) | |
548 (list match match (list match) match)) | |
549 (let* ((choices | |
550 (all-completions | |
551 (concat dir (substring string 0 has-words)) | |
552 table pred)) | |
553 (regexp (completer-regexp string words any))) | |
554 (if choices | |
555 (completer-match-record | |
556 string | |
557 (completer-deleter regexp choices t) | |
558 words any dir mode) | |
559 (list nil nil nil nil)))))) | |
560 completer-string string) | |
561 completer-result)) | |
562 | |
563 ;;;%%Display choices | |
564 (defun completer-display-choices (choices &optional match message end | |
565 display) | |
566 "Display the list of possible CHOICES with optional MATCH, MESSAGE, | |
567 END and DISPLAY. If MATCH is non-nil, it will be flagged as the best | |
568 guess. If there are no choices, display MESSAGE. END is where to put | |
569 temporary messages. If DISPLAY is present then it will be called on | |
570 each possible completion and should return a string." | |
571 (if choices | |
572 (with-output-to-temp-buffer " *Completions*" | |
573 (if (cdr choices) | |
574 (display-completion-list | |
575 (sort | |
576 (if display | |
577 (let ((old choices) | |
578 (new nil)) | |
579 (while old | |
580 (setq new (cons (funcall display (car old)) new) | |
581 old (cdr old))) | |
582 new) | |
583 (copy-sequence choices)) | |
584 (function (lambda (x y) | |
585 (string-lessp (or (car-safe x) x) | |
586 (or (car-safe y) y))))))) | |
587 (if match | |
588 (save-excursion | |
589 (set-buffer " *Completions*") | |
590 (goto-char (point-min)) | |
591 (insert "Guess = " match (if (cdr choices) ", " ""))))) | |
592 (beep) | |
593 (completer-message (or message " (No completions)") end))) | |
594 | |
595 ;;;%%Goto | |
596 (defun completer-goto (match lcs choices unique delimiters words | |
597 &optional mode display) | |
598 "MATCH is the best match, LCS is the longest common substring of all | |
599 of the matches. CHOICES is a list of the possibilities, UNIQUE | |
600 indicates if MATCH is unique. DELIMITERS are possible bounding | |
601 characters for the completion region. WORDS are the characters that | |
602 delimit the words for partial matches. Replace the region bounded by | |
603 delimiters with the match if unique and the lcs otherwise unless | |
604 optional MODE is 'help. Then go to the part of the string that | |
605 disambiguates choices using WORDS to separate words and display the | |
606 possibilities if the string was not extended. If optional DISPLAY is | |
607 present then it will be called on each possible completion and should | |
608 return a string." | |
609 (setq completer-message nil) | |
610 (let* ((region (completer-region delimiters)) | |
611 (start (car region)) | |
612 (end (cdr region)) | |
613 (string (buffer-substring start end)) | |
614 (file-p (string-match "[^ ]*\\(~\\|/\\|$\\)" string)) | |
615 (no-insert (eq mode 'help)) | |
616 (message t) | |
617 (new (not (string= (buffer-substring start (point)) lcs)))) | |
618 (if unique | |
619 (if no-insert | |
620 (progn | |
621 (goto-char end) | |
622 (completer-display-choices choices match nil end display)) | |
623 (if (string= string match) | |
624 (if (not file-p) | |
625 (progn (goto-char end) | |
626 (completer-message " (Sole completion)" end))) | |
627 (completer-insert match delimiters))) | |
628 ;;Not unique | |
629 (if lcs | |
630 (let* ((regexp | |
631 (concat "[" words (if file-p "/") "]")) | |
632 (words (completer-words regexp lcs)) | |
633 point) | |
634 ;; Go to where its ambiguous | |
635 (goto-char start) | |
636 (if (not no-insert) | |
637 (progn | |
638 (insert lcs) | |
639 (setq completer-last-pattern | |
640 (list string delimiters (current-buffer) start) | |
641 start (point) | |
642 end (+ end (length lcs))))) | |
643 ;; Skip to the first delimiter in the original string | |
644 ;; beyond the ambiguous point and keep from there on | |
645 (if (re-search-forward regexp end 'move words) | |
646 (progn | |
647 (if (and (not no-insert) match) | |
648 (let ((delimiter | |
649 (progn | |
650 (string-match lcs match) | |
651 (substring match (match-end 0) | |
652 (1+ (match-end 0)))))) | |
653 (if (string-match regexp delimiter) | |
654 (insert delimiter)))) | |
655 (forward-char -1))) | |
656 (if (not no-insert) | |
657 (progn | |
658 (setq end (- end (- (point) start))) | |
659 (delete-region start (point)))))) | |
660 (if choices | |
661 (if (or no-insert (not new)) | |
662 (completer-display-choices choices match nil end display)) | |
663 (if file-p | |
664 (progn | |
665 (if (not (= (point) end)) (forward-char 1)) | |
666 (if (not (save-excursion (re-search-forward "/" end t))) | |
667 (goto-char end)))) | |
668 (if message | |
669 (progn | |
670 (beep) | |
671 (completer-message (if no-insert | |
672 " (No completions)" | |
673 " (No match)") | |
674 end))))))) | |
675 | |
676 ;;;%Exported buffer interface | |
677 ;;;%%Complete and go | |
678 (defun completer-complete-goto (delimiters words table pred | |
679 &optional no-insert display) | |
680 "Complete the string bound by DELIMITERS using WORDS to bound words | |
681 for partial matches in TABLE with PRED and then insert the longest | |
682 common substring unless optional NO-INSERT and go to the point of | |
683 ambiguity. If optional DISPLAY, it will be called on each match when | |
684 possible completions are shown and should return a string." | |
685 (let* ((region (completer-region delimiters))) | |
686 (apply 'completer-goto | |
687 (append (completer (buffer-substring (car region) (cdr region)) | |
688 table pred words completer-any-delimiter | |
689 no-insert) | |
690 (list delimiters words no-insert display))))) | |
691 | |
692 ;;;%%Undo | |
693 (defun completer-insert (match delimiters &optional buffer undo) | |
694 "Replace the region bounded with characters in DELIMITERS by MATCH | |
695 and save it so that it can be restored by completer-undo." | |
696 (let* ((region (completer-region delimiters)) | |
697 (start (car region)) | |
698 (end (cdr region))) | |
699 (if (and undo (or (not (= start undo)) | |
700 (not (eq (current-buffer) buffer)))) | |
701 (error "No previous pattern") | |
702 (setq completer-last-pattern (list (buffer-substring start end) | |
703 delimiters | |
704 (current-buffer) | |
705 start)) | |
706 (delete-region start end) | |
707 (goto-char start) | |
708 (insert match)))) | |
709 | |
710 ;;; | |
711 (defun completer-undo () | |
712 "Swap the last expansion and the last match pattern." | |
713 (interactive) | |
714 (if completer-last-pattern | |
715 (apply 'completer-insert completer-last-pattern) | |
716 (error "No previous pattern"))) | |
717 | |
718 ;;;%Minibuffer specific code | |
719 ;;;%%Utilities | |
720 (defun completer-minibuf-string () | |
721 "Remove dead filename specs from the minibuffer as delimited by // | |
722 or ~ or $ and return the resulting string." | |
723 (save-excursion | |
724 (goto-char (point-max)) | |
725 (if (and (eq minibuffer-completion-table 'read-file-name-internal) | |
726 (re-search-backward "//\\|/~\\|.\\$" nil t)) | |
727 (delete-region (point-min) (1+ (point)))) | |
728 (buffer-substring (point-min) (point-max)))) | |
729 | |
730 ;;; | |
731 (defun completer-minibuf-exit () | |
732 "Exit and clear pattern." | |
733 (interactive) | |
734 (setq completer-last-pattern nil) | |
735 (exit-minibuffer)) | |
736 | |
737 ;;; | |
738 (defun completer-new-cmd (cmd) | |
739 "Return T if we can't execute the old minibuffer version of CMD." | |
740 (if (or completer-disable | |
741 (let ((string (completer-minibuf-string))) | |
742 (or | |
743 (not (string-match | |
744 (concat "[" completer-words "/~]") | |
745 string)) | |
746 (condition-case () | |
747 (let ((completion | |
748 (try-completion string | |
749 minibuffer-completion-table | |
750 minibuffer-completion-predicate))) | |
751 (if (eq minibuffer-completion-table | |
752 'read-file-name-internal) | |
753 ;; Directories complete as themselves | |
754 (and completion | |
755 (or (not (string= string completion)) | |
756 (file-exists-p completion))) | |
757 completion)) | |
758 (error nil))))) | |
759 (progn | |
760 (funcall cmd) | |
761 nil) | |
762 t)) | |
763 | |
764 ;;; | |
765 (defun completer-minibuf (&optional mode) | |
766 "Partial completion of minibuffer expressions. Optional MODE is | |
767 'help for help and 'exit for exit. | |
768 | |
769 If what has been typed so far matches any possibility normal | |
770 completion will be done. Otherwise, the string is considered to be a | |
771 pattern with words delimited by the characters in | |
772 completer-words. If completer-exact is T, the best match will be | |
773 the shortest one with the same number of words as the pattern if | |
774 possible and otherwise the shortest matching expression. If called | |
775 with a prefix, caching will be temporarily disabled. | |
776 | |
777 Examples: | |
778 a-f auto-fill-mode | |
779 r-e rmail-expunge | |
780 b--d *begining-of-defun or byte-recompile-directory | |
781 by d *byte-recompile-directory if completer-any-delimiter is \" \" | |
782 ~/i.e *~/ilisp.el or ~/il-el.el or ~/ilisp.elc | |
783 /u/mi/ /usr/misc/" | |
784 (interactive) | |
785 (append | |
786 (let ((completer-use-cache (not (or (not completer-use-cache) | |
787 current-prefix-arg)))) | |
788 (completer (completer-minibuf-string) | |
789 minibuffer-completion-table | |
790 minibuffer-completion-predicate | |
791 completer-words | |
792 completer-any-delimiter | |
793 mode)) | |
794 (list "^" completer-words mode))) | |
795 | |
796 ;;;%%Commands | |
797 (defun completer-toggle () | |
798 "Turn partial completion on or off." | |
799 (interactive) | |
800 (setq completer-disable (not completer-disable)) | |
801 (message (if completer-disable | |
802 "Partial completion OFF" | |
803 "Partial completion ON"))) | |
804 | |
805 ;;; | |
806 (defvar completer-old-help | |
807 (lookup-key minibuffer-local-must-match-map "?") | |
808 "Old binding of ? in minibuffer completion map.") | |
809 (defun completer-help () | |
810 "Partial completion minibuffer-completion-help. | |
811 See completer-minibuf for more information." | |
812 (interactive) | |
813 (if (completer-new-cmd completer-old-help) | |
814 (apply 'completer-goto (completer-minibuf 'help)))) | |
815 | |
816 ;;; | |
817 (defvar completer-old-completer | |
818 (lookup-key minibuffer-local-must-match-map "\t") | |
819 "Old binding of TAB in minibuffer completion map.") | |
820 (defun completer-complete () | |
821 "Partial completion minibuffer-complete. | |
822 See completer-minibuf for more information." | |
823 (interactive) | |
824 (if (completer-new-cmd completer-old-completer) | |
825 (apply 'completer-goto (completer-minibuf)))) | |
826 | |
827 ;;; | |
828 (defvar completer-old-word | |
829 (lookup-key minibuffer-local-must-match-map " ") | |
830 "Old binding of SPACE in minibuffer completion map.") | |
831 (defun completer-word () | |
832 "Partial completion minibuffer-complete. | |
833 See completer-minibuf for more information." | |
834 (interactive) | |
835 (if (eq completer-any-delimiter ?\ ) | |
836 (insert ?\ ) | |
837 (if (completer-new-cmd completer-old-word) | |
838 (apply 'completer-goto (completer-minibuf))))) | |
839 | |
840 ;;; | |
841 (defvar completer-old-exit | |
842 (lookup-key minibuffer-local-must-match-map "\n") | |
843 "Old binding of RET in minibuffer completion map.") | |
844 (defun completer-exit () | |
845 "Partial completion minibuffer-complete-and-exit. | |
846 See completer-minibuf for more information." | |
847 (interactive) | |
848 (if (completer-new-cmd completer-old-exit) | |
849 (let* ((completions (completer-minibuf 'exit)) | |
850 (match (car completions)) | |
851 (unique-p (car (cdr (cdr (cdr completions)))))) | |
852 (apply 'completer-goto completions) | |
853 (if unique-p | |
854 (completer-minibuf-exit) | |
855 (if match | |
856 (progn (completer-insert match "^") | |
857 (if minibuffer-completion-confirm | |
858 (completer-message " (Confirm)") | |
859 (completer-minibuf-exit))) | |
860 (if (not completer-message) (beep))))))) | |
861 | |
862 ;;; | |
863 (defun completer-match-exit () | |
864 "Exit the minibuffer with the current best match." | |
865 (interactive) | |
866 (let* ((completions (completer-minibuf 'exit)) | |
867 (guess (car completions))) | |
868 (if (not guess) | |
869 ;; OK if last filename component doesn't match | |
870 (setq completions (completer-minibuf 'exit-ok) | |
871 guess (car completions))) | |
872 (if guess | |
873 (progn | |
874 (goto-char (point-min)) | |
875 (insert guess) | |
876 (delete-region (point) (point-max)) | |
877 (exit-minibuffer)) | |
878 (apply 'completer-goto completions)))) | |
879 | |
880 ;;;%%Keymaps | |
881 (define-key minibuffer-local-completion-map "\C-_" 'completer-undo) | |
882 (define-key minibuffer-local-completion-map "\t" 'completer-complete) | |
883 (define-key minibuffer-local-completion-map " " 'completer-word) | |
884 (define-key minibuffer-local-completion-map "?" 'completer-help) | |
885 (define-key minibuffer-local-completion-map "\n" 'completer-minibuf-exit) | |
886 (define-key minibuffer-local-completion-map "\r" 'completer-minibuf-exit) | |
887 (define-key minibuffer-local-completion-map "\M-\n" 'completer-match-exit) | |
888 (define-key minibuffer-local-completion-map "\M-\r" 'completer-match-exit) | |
889 | |
890 (define-key minibuffer-local-must-match-map "\C-_" 'completer-undo) | |
891 (define-key minibuffer-local-must-match-map "\t" 'completer-complete) | |
892 (define-key minibuffer-local-must-match-map " " 'completer-word) | |
893 (define-key minibuffer-local-must-match-map "\n" 'completer-exit) | |
894 (define-key minibuffer-local-must-match-map "\r" 'completer-exit) | |
895 (define-key minibuffer-local-must-match-map "?" 'completer-help) | |
896 (define-key minibuffer-local-must-match-map "\M-\n" 'completer-match-exit) | |
897 (define-key minibuffer-local-must-match-map "\M-\r" 'completer-match-exit) | |
898 | |
899 ;;;%comint | |
900 (defun completer-comint-dynamic-list-completions (completions) | |
901 "List in help buffer sorted COMPLETIONS. | |
902 Typing SPC flushes the help buffer." | |
903 (completer-comint-dynamic-complete-1 nil 'help)) | |
904 | |
905 (defun completer-comint-dynamic-complete-filename () | |
906 "Dynamically complete the filename at point." | |
907 (completer-comint-dynamic-complete-1 nil t)) | |
908 | |
909 ;;; | |
910 (defun completer-comint-dynamic-complete-1 (&optional undo mode) | |
911 "Complete the previous filename or display possibilities if done | |
912 twice in a row. If called with a prefix, undo the last completion." | |
913 (interactive "P") | |
914 (if undo | |
915 (completer-undo) | |
916 ;; added by jwz: don't cache completions in shell buffer! | |
917 (setq completer-string nil) | |
918 (let ((conf (current-window-configuration)));; lemacs change | |
919 (completer-complete-goto | |
920 "^ \t\n\"" | |
921 completer-words | |
922 'read-file-name-internal | |
923 default-directory | |
924 mode) | |
925 ;; lemacs change | |
926 (if (eq mode 'help) (comint-restore-window-config conf)) | |
927 ))) | |
928 ;(fset 'comint-dynamic-complete 'completer-comint-dynamic-complete) | |
929 (fset 'comint-dynamic-complete-filename | |
930 'completer-comint-dynamic-complete-filename) | |
931 (fset 'comint-dynamic-list-completions | |
932 'completer-comint-dynamic-list-completions) | |
933 | |
934 ;;; Set the functions again if comint is loaded | |
935 (setq comint-load-hook | |
936 (cons (function (lambda () | |
937 ;; (fset 'comint-dynamic-complete | |
938 ;; 'completer-comint-dynamic-complete) | |
939 (fset 'comint-dynamic-complete-filename | |
940 'completer-comint-dynamic-complete-filename) | |
941 (fset 'comint-dynamic-list-completions | |
942 'completer-comint-dynamic-list-completions))) | |
943 (if (and (boundp 'comint-load-hook) comint-load-hook) | |
944 (if (consp comint-load-hook) | |
945 (if (eq (car comint-load-hook) 'lambda) | |
946 (list comint-load-hook) | |
947 comint-load-hook) | |
948 (list comint-load-hook))))) | |
949 | |
950 ;;;%lisp-complete-symbol | |
951 (defun lisp-complete-symbol (&optional mode) | |
952 "Perform partial completion on Lisp symbol preceding point. That | |
953 symbol is compared against the symbols that exist and any additional | |
954 characters determined by what is there are inserted. If the symbol | |
955 starts just after an open-parenthesis, only symbols with function | |
956 definitions are considered. Otherwise, all symbols with function | |
957 definitions, values or properties are considered. If called with a | |
958 negative prefix, the last completion will be undone." | |
959 (interactive "P") | |
960 (if (< (prefix-numeric-value mode) 0) | |
961 (completer-undo) | |
962 (let* ((end (save-excursion (skip-chars-forward "^ \t\n)]}\"") (point))) | |
963 (beg (save-excursion | |
964 (backward-sexp 1) | |
965 (while (= (char-syntax (following-char)) ?\') | |
966 (forward-char 1)) | |
967 (point))) | |
968 (pattern (buffer-substring beg end)) | |
969 (predicate | |
970 (if (eq (char-after (1- beg)) ?\() | |
971 'fboundp | |
972 (function (lambda (sym) | |
973 (or (boundp sym) (fboundp sym) | |
974 (symbol-plist sym)))))) | |
975 (completion (try-completion pattern obarray predicate))) | |
976 (cond ((eq completion t)) | |
977 ((null completion) | |
978 (completer-complete-goto | |
979 "^ \t\n\(\)[]{}'`" completer-words | |
980 obarray predicate | |
981 nil | |
982 (if (not (eq predicate 'fboundp)) | |
983 (function (lambda (choice) | |
984 (if (fboundp (intern choice)) | |
985 (list choice " <f>") | |
986 choice)))))) | |
987 ((not (string= pattern completion)) | |
988 (delete-region beg end) | |
989 (insert completion)) | |
990 (t | |
991 (message "Making completion list...") | |
992 (let ((list (all-completions pattern obarray predicate))) | |
993 (or (eq predicate 'fboundp) | |
994 (let (new) | |
995 (while list | |
996 (setq new (cons (if (fboundp (intern (car list))) | |
997 (list (car list) " <f>") | |
998 (car list)) | |
999 new)) | |
1000 (setq list (cdr list))) | |
1001 (setq list (nreverse new)))) | |
1002 (with-output-to-temp-buffer "*Help*" | |
1003 (display-completion-list | |
1004 (sort list (function (lambda (x y) | |
1005 (string-lessp | |
1006 (or (car-safe x) x) | |
1007 (or (car-safe y) y)))))))) | |
1008 (message "Making completion list...%s" "done")))))) | |
1009 | |
1010 ;;;%Hooks | |
1011 (provide 'completer) | |
1012 (run-hooks 'completer-load-hook) | |
1013 |