comparison lisp/ilisp/completer.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children b82b59fe008d
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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 (regexp-quote 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 match)
320 (setq matches (completer-matches pattern matches delimiters any)
321 match (try-completion pattern (mapcar 'list matches)))
322 ;; If try-completion produced an exact match for an element in 'matches',
323 ;; then remove any partial matches from 'matches' and set the unique
324 ;; match flag.
325 (and (stringp match) (member match matches) (setq matches (list match)))
326 (if (cdr matches)
327 (let ((lcs (concat dir (try-completion "" (mapcar 'list matches)))))
328 (setq match (if (not completer-exact)
329 (completer-choice
330 pattern matches delimiters completer-use-words)))
331 (list (if match (concat dir (car match)))
332 lcs
333 matches
334 (cdr match)))
335 (if matches
336 (progn (setq match (concat dir (car matches)))
337 (list match match matches t))
338 (list nil nil nil nil)))))
339
340 ;;;%%Complete file
341 (defun completer-extension-regexp (extensions)
342 "Return a regexp that matches to a string that ends with any string from EXTENSIONS list."
343 (concat "\\(" (mapconcat 'regexp-quote extensions "\\|") "\\)\\'"))
344
345 ;;;
346 (defun completer-flush ()
347 "Flush completer's pathname cache."
348 (interactive)
349 (setq completer-path-cache nil))
350
351 ;;;
352 (defun completer-cache (path pred words any mode)
353 "Check to see if PATH is in path cache with PRED, WORDS, ANY and
354 MODE."
355 (let* ((last nil)
356 (ptr completer-path-cache)
357 (size 0)
358 (result nil))
359 (if completer-use-cache
360 (while ptr
361 (let ((current (car (car ptr))))
362 (if (string-equal current path)
363 (progn
364 (if last
365 (progn
366 (rplacd last (cdr ptr))
367 (rplacd ptr completer-path-cache)
368 (setq completer-path-cache ptr)))
369 (setq result (cdr (car ptr))
370 ptr nil))
371 (if (cdr ptr) (setq last ptr))
372 (setq size (1+ size)
373 ptr (cdr ptr))))))
374 (or result
375 (let* ((choices
376 (completer path 'read-file-name-internal pred words any
377 mode t)))
378 (if (and (or (car (cdr (cdr (cdr choices))))
379 (string= path (car choices)))
380 (eq (elt (car choices) (1- (length (car choices)))) ?/))
381 (progn
382 (if (>= size completer-cache-size) (rplacd last nil))
383 (setq completer-path-cache
384 (cons (cons path choices) completer-path-cache))))
385 choices))))
386
387 ;;;
388 (defun completer-file (string pred words any mode)
389 "Return (match common-substring matches unique-p) for STRING using
390 read-file-name-internal for choices that pass PRED using WORDS to
391 delimit words. Optional ANY is a delimiter that matches any of the
392 delimiters in WORD. If optional MODE is nil or 'help then possible
393 matches will always be returned."
394 (let* ((case-fold-search completion-ignore-case)
395 (last (and (eq mode 'exit-ok) (completer-last-component string)))
396 (position
397 ;; Special hack for CMU RFS filenames
398 (if (string-match "^/\\.\\./[^/]*/" string)
399 (match-end 0)
400 (string-match "[^~/]" string)))
401 (new (substring string 0 position))
402 (user (if (string= new "~")
403 (setq new (file-name-directory (expand-file-name new)))))
404 (words (concat words "/"))
405 (len (length string))
406 (choices nil)
407 end
408 (old-choices (list nil nil nil nil)))
409 (while position
410 (let* ((begin (string-match "/" string position))
411 (exact-p nil))
412 (setq end (if begin (match-end 0))
413 choices
414 ;; Ends with a /, so check files in directory
415 (if (and (memq mode '(nil help)) (= position len))
416 (completer-match-record
417 ""
418 ;; This assumes that .. and . come at the end
419 (let* ((choices
420 (all-completions new 'read-file-name-internal))
421 (choicep choices))
422 (if (string= (car choicep) "../")
423 (cdr (cdr choicep))
424 (while (cdr choicep)
425 (if (string= (car (cdr choicep)) "../")
426 (rplacd choicep nil))
427 (setq choicep (cdr choicep)))
428 choices))
429 words any new mode)
430 (if (eq position last)
431 (let ((new (concat new (substring string position))))
432 (list new new nil t))
433 (let ((component (substring string position end)))
434 (if (and end
435 (string-match completer-file-skip component))
436 ;; Assume component is complete
437 (list (concat new component)
438 (concat new component)
439 nil t)
440 (completer-cache
441 (concat new component)
442 pred words any mode))))))
443 ;; Keep going if unique or we match exactly
444 (if (or (car (cdr (cdr (cdr choices))))
445 (setq exact-p
446 (string= (concat new (substring string position end))
447 (car choices))))
448 (setq old-choices
449 (let* ((lcs (car (cdr choices)))
450 (matches (car (cdr (cdr choices))))
451 (slash (and lcs (string-match "/$" lcs))))
452 (list nil
453 (if slash (substring lcs 0 slash) lcs)
454 (if (and (cdr matches)
455 (or (eq mode 'help) (not exact-p)))
456 matches)
457 nil))
458 new (car choices)
459 position end)
460 ;; Its ok to not match user names because they may be in
461 ;; different root directories
462 (if (and (= position 1) (= (elt string 0) ?~))
463 (setq new (substring string 0 end)
464 choices (list new new (list new) t)
465 user nil
466 position end)
467 (setq position nil)))))
468 (if (not (car choices))
469 (setq choices old-choices))
470 (if (and (car choices)
471 (not (eq mode 'help))
472 (not (car (cdr (cdr (cdr choices))))))
473 ;; Try removing completion ignored extensions
474 (let* ((extensions
475 (completer-extension-regexp completion-ignored-extensions))
476 (choiceb (car (cdr (cdr choices))))
477 (choicep choiceb)
478 (isext nil)
479 (noext nil))
480 (while choicep
481 (if (string-match extensions (car choicep))
482 (setq isext t)
483 (setq noext t))
484 (if (and isext noext)
485 ;; There are matches besides extensions
486 (setq choiceb (completer-deleter extensions choiceb)
487 choicep nil)
488 (setq choicep (cdr choicep))))
489 (if (and isext noext)
490 (setq choices
491 (completer-match-record
492 (if end (substring string end) "")
493 choiceb words any
494 (file-name-directory (car (cdr choices)))
495 mode)))))
496 (if user
497 (let ((match (car choices))
498 (lcs (car (cdr choices)))
499 (len (length user)))
500 (setq choices
501 (cons (if match (concat "~" (substring match len)))
502 (cons (if lcs (concat "~" (substring lcs len)))
503 (cdr (cdr choices)))))))
504 choices))
505
506 ;;;%Exported program interface
507 ;;;%%Completer
508 (defun completer (string table pred words
509 &optional any mode file-p)
510 "Return (match common-substring matches unique-p) for STRING in
511 TABLE for choices that pass PRED using WORDS to delimit words. If the
512 flag completer-complete-filenames is T and the table is
513 read-file-name-internal, then filename components will be individually
514 expanded. Optional ANY is a delimiter that can match any delimiter in
515 WORDS. Optional MODE is nil for complete, 'help for help and 'exit
516 for exit."
517 (if (and (stringp completer-string)
518 (string= string completer-string)
519 (eq table completer-table)
520 (eq pred completer-pred)
521 (not file-p)
522 (or (eq mode completer-mode)
523 (not (memq table '(read-file-name-internal
524 read-directory-name-internal)))))
525 completer-result
526 (setq
527 completer-string ""
528 completer-table table
529 completer-pred pred
530 completer-mode mode
531 completer-result
532 (if (and completer-complete-filenames
533 (not file-p) (eq table 'read-file-name-internal))
534 (completer-file string pred words any mode)
535 (let* ((file-p (or file-p (eq table 'read-file-name-internal)))
536 (case-fold-search completion-ignore-case)
537 (pattern (concat "[" words "]"))
538 (component (if file-p (completer-last-component string)))
539 (dir (if component (substring string 0 component)))
540 (string (if dir (substring string component) string))
541 (has-words (or (string-match pattern string)
542 (length string))))
543 (if (and file-p (string-match "^\\$" string))
544 ;; Handle environment variables
545 (let ((match
546 (getenv (substring string 1
547 (string-match "/" string)))))
548 (if match (setq match (concat match "/")))
549 (list match match (list match) match))
550 (let* ((choices
551 (all-completions
552 (concat dir (substring string 0 has-words))
553 table pred))
554 (regexp (completer-regexp string words any)))
555 (if choices
556 (completer-match-record
557 string
558 (completer-deleter regexp choices t)
559 words any dir mode)
560 (list nil nil nil nil))))))
561 completer-string string)
562 completer-result))
563
564 ;;;%%Display choices
565 (defun completer-display-choices (choices &optional match message end
566 display)
567 "Display the list of possible CHOICES with optional MATCH, MESSAGE,
568 END and DISPLAY. If MATCH is non-nil, it will be flagged as the best
569 guess. If there are no choices, display MESSAGE. END is where to put
570 temporary messages. If DISPLAY is present then it will be called on
571 each possible completion and should return a string."
572 (if choices
573 (with-output-to-temp-buffer "*Completions*"
574 (if (cdr choices)
575 (funcall completion-display-completion-list-function
576 (sort
577 (if display
578 (let ((old choices)
579 (new nil))
580 (while old
581 (setq new (cons (funcall display (car old)) new)
582 old (cdr old)))
583 new)
584 (copy-sequence choices))
585 (function (lambda (x y)
586 (string-lessp (or (car-safe x) x)
587 (or (car-safe y) y)))))))
588 (if match
589 (save-excursion
590 (set-buffer "*Completions*")
591 (goto-char (point-min))
592 (let ((buffer-read-only nil))
593 (insert "Guess = " match (if (cdr choices) ", " "") "\n")))))
594 (beep)
595 (completer-message (or message " (No completions)") end)))
596
597 ;;;%%Goto
598 (defun completer-goto (match lcs choices unique delimiters words
599 &optional mode display)
600 "MATCH is the best match, LCS is the longest common substring of all
601 of the matches. CHOICES is a list of the possibilities, UNIQUE
602 indicates if MATCH is unique. DELIMITERS are possible bounding
603 characters for the completion region. WORDS are the characters that
604 delimit the words for partial matches. Replace the region bounded by
605 delimiters with the match if unique and the lcs otherwise unless
606 optional MODE is 'help. Then go to the part of the string that
607 disambiguates choices using WORDS to separate words and display the
608 possibilities if the string was not extended. If optional DISPLAY is
609 present then it will be called on each possible completion and should
610 return a string."
611 (setq completer-message nil)
612 (let* ((region (completer-region delimiters))
613 (start (car region))
614 (end (cdr region))
615 (string (buffer-substring start end))
616 (file-p (string-match "[^ ]*\\(~\\|/\\|$\\)" string))
617 (no-insert (eq mode 'help))
618 (message t)
619 (new (not (string= (buffer-substring start (point)) lcs))))
620 (if unique
621 (if no-insert
622 (progn
623 (goto-char end)
624 (completer-display-choices choices match nil end display))
625 (if (string= string match)
626 (if (not file-p)
627 (progn (goto-char end)
628 (completer-message " (Sole completion)" end)))
629 (completer-insert match delimiters)))
630 ;;Not unique
631 (if lcs
632 (let* ((regexp
633 (concat "[" words (if file-p "/") "]"))
634 (words (completer-words regexp lcs))
635 point)
636 ;; Go to where its ambiguous
637 (goto-char start)
638 (if (not no-insert)
639 (progn
640 (insert lcs)
641 (setq completer-last-pattern
642 (list string delimiters (current-buffer) start)
643 start (point)
644 end (+ end (length lcs)))))
645 ;; Skip to the first delimiter in the original string
646 ;; beyond the ambiguous point and keep from there on
647 (if (re-search-forward regexp end 'move words)
648 (progn
649 (if (and (not no-insert) match)
650 (let ((delimiter
651 (progn
652 (string-match (regexp-quote lcs) match)
653 (substring match (match-end 0)
654 (1+ (match-end 0))))))
655 (if (string-match regexp delimiter)
656 (insert delimiter))))
657 (forward-char -1)))
658 (if (not no-insert)
659 (progn
660 (setq end (- end (- (point) start)))
661 (delete-region start (point))))))
662 (if choices
663 (if (or no-insert (not new))
664 (completer-display-choices choices match nil end display))
665 (if file-p
666 (progn
667 (if (not (= (point) end)) (forward-char 1))
668 (if (not (save-excursion (re-search-forward "/" end t)))
669 (goto-char end))))
670 (if message
671 (progn
672 (beep)
673 (completer-message (if no-insert
674 " (No completions)"
675 " (No match)")
676 end)))))))
677
678 ;;;%Exported buffer interface
679 ;;;%%Complete and go
680 (defun completer-complete-goto (delimiters words table pred
681 &optional no-insert display)
682 "Complete the string bound by DELIMITERS using WORDS to bound words
683 for partial matches in TABLE with PRED and then insert the longest
684 common substring unless optional NO-INSERT and go to the point of
685 ambiguity. If optional DISPLAY, it will be called on each match when
686 possible completions are shown and should return a string."
687 (let* ((region (completer-region delimiters)))
688 (apply 'completer-goto
689 (append (completer (buffer-substring (car region) (cdr region))
690 table pred words completer-any-delimiter
691 no-insert)
692 (list delimiters words no-insert display)))))
693
694 ;;;%%Undo
695 (defun completer-insert (match delimiters &optional buffer undo)
696 "Replace the region bounded with characters in DELIMITERS by MATCH
697 and save it so that it can be restored by completer-undo."
698 (let* ((region (completer-region delimiters))
699 (start (car region))
700 (end (cdr region)))
701 (if (and undo (or (not (= start undo))
702 (not (eq (current-buffer) buffer))))
703 (error "No previous pattern")
704 (setq completer-last-pattern (list (buffer-substring start end)
705 delimiters
706 (current-buffer)
707 start))
708 (delete-region start end)
709 (goto-char start)
710 (insert match))))
711
712 ;;;
713 (defun completer-undo ()
714 "Swap the last expansion and the last match pattern."
715 (interactive)
716 (if completer-last-pattern
717 (apply 'completer-insert completer-last-pattern)
718 (error "No previous pattern")))
719
720 ;;;%Minibuffer specific code
721 ;;;%%Utilities
722 (defun completer-minibuf-string ()
723 "Remove dead filename specs from the minibuffer as delimited by //
724 or ~ or $ and return the resulting string."
725 (save-excursion
726 (goto-char (point-max))
727 (if (and (eq minibuffer-completion-table 'read-file-name-internal)
728 (re-search-backward "//\\|/~\\|.\\$" nil t))
729 (delete-region (point-min) (1+ (point))))
730 (buffer-substring (point-min) (point-max))))
731
732 ;;;
733 (defun completer-minibuf-exit ()
734 "Exit the minibuffer and clear completer-last-pattern."
735 (interactive)
736 (setq completer-last-pattern nil)
737 (exit-minibuffer))
738
739 ;;;
740 (defun completer-new-cmd (cmd)
741 "Return t if we can't execute the old minibuffer version of CMD."
742 (if (or completer-disable
743 (let ((string (completer-minibuf-string)))
744 (or
745 (not (string-match
746 (concat "[" completer-words "/~]")
747 string))
748 (condition-case ()
749 (let ((completion
750 (try-completion string
751 minibuffer-completion-table
752 minibuffer-completion-predicate)))
753 (if (eq minibuffer-completion-table
754 'read-file-name-internal)
755 ;; Directories complete as themselves
756 (and completion
757 (or (not (string= string completion))
758 (file-exists-p completion)))
759 completion))
760 (error nil)))))
761 (progn
762 (funcall cmd)
763 nil)
764 t))
765
766 ;;;
767 (defun completer-minibuf (&optional mode)
768 "Partial completion of minibuffer expressions. Optional MODE is
769 'help for help and 'exit for exit.
770
771 If what has been typed so far matches any possibility normal
772 completion will be done. Otherwise, the string is considered to be a
773 pattern with words delimited by the characters in
774 completer-words. If completer-exact is T, the best match will be
775 the shortest one with the same number of words as the pattern if
776 possible and otherwise the shortest matching expression. If called
777 with a prefix, caching will be temporarily disabled.
778
779 Examples:
780 a-f auto-fill-mode
781 r-e rmail-expunge
782 b--d *begining-of-defun or byte-recompile-directory
783 by d *byte-recompile-directory if completer-any-delimiter is \" \"
784 ~/i.e *~/ilisp.el or ~/il-el.el or ~/ilisp.elc
785 /u/mi/ /usr/misc/"
786 (interactive)
787 (append
788 (let ((completer-use-cache (not (or (not completer-use-cache)
789 current-prefix-arg))))
790 (completer (completer-minibuf-string)
791 minibuffer-completion-table
792 minibuffer-completion-predicate
793 completer-words
794 completer-any-delimiter
795 mode))
796 (list "^" completer-words mode)))
797
798 ;;;%%Commands
799 (defun completer-toggle ()
800 "Turn partial completion on or off."
801 (interactive)
802 (setq completer-disable (not completer-disable))
803 (message (if completer-disable
804 "Partial completion OFF"
805 "Partial completion ON")))
806
807 ;;;
808 (defvar completer-old-help
809 (lookup-key minibuffer-local-must-match-map "?")
810 "Old binding of ? in minibuffer completion map.")
811 (defun completer-help ()
812 "Partial completion minibuffer-completion-help.
813 See completer-minibuf for more information."
814 (interactive)
815 (if (completer-new-cmd completer-old-help)
816 (apply 'completer-goto (completer-minibuf 'help))))
817
818 ;;;
819 (defvar completer-old-completer
820 (lookup-key minibuffer-local-must-match-map "\t")
821 "Old binding of TAB in minibuffer completion map.")
822 (defun completer-complete ()
823 "Partial completion minibuffer-complete.
824 See completer-minibuf for more information."
825 (interactive)
826 (if (completer-new-cmd completer-old-completer)
827 (apply 'completer-goto (completer-minibuf))))
828
829 ;;;
830 (defvar completer-old-word
831 (lookup-key minibuffer-local-must-match-map " ")
832 "Old binding of SPACE in minibuffer completion map.")
833 (defun completer-word ()
834 "Partial completion minibuffer-complete.
835 See completer-minibuf for more information."
836 (interactive)
837 (if (eq completer-any-delimiter ?\ )
838 (insert ?\ )
839 (if (completer-new-cmd completer-old-word)
840 (apply 'completer-goto (completer-minibuf)))))
841
842 ;;;
843 (defvar completer-old-exit
844 (lookup-key minibuffer-local-must-match-map "\n")
845 "Old binding of RET in minibuffer completion map.")
846 (defun completer-exit ()
847 "Partial completion minibuffer-complete-and-exit.
848 See completer-minibuf for more information."
849 (interactive)
850 (if (completer-new-cmd completer-old-exit)
851 (let* ((completions (completer-minibuf 'exit))
852 (match (car completions))
853 (unique-p (car (cdr (cdr (cdr completions))))))
854 (apply 'completer-goto completions)
855 (if unique-p
856 (completer-minibuf-exit)
857 (if match
858 (progn (completer-insert match "^")
859 (if minibuffer-completion-confirm
860 (completer-message " (Confirm)")
861 (completer-minibuf-exit)))
862 (if (not completer-message) (beep)))))))
863
864 ;;;
865 (defun completer-match-exit ()
866 "Exit the minibuffer with the current best match."
867 (interactive)
868 (let* ((completions (completer-minibuf 'exit))
869 (guess (car completions)))
870 (if (not guess)
871 ;; OK if last filename component doesn't match
872 (setq completions (completer-minibuf 'exit-ok)
873 guess (car completions)))
874 (if guess
875 (progn
876 (goto-char (point-min))
877 (insert guess)
878 (delete-region (point) (point-max))
879 (exit-minibuffer))
880 (apply 'completer-goto completions))))
881
882 ;;;%%Keymaps
883 ;this interferes with normal undo.
884 ;(define-key minibuffer-local-completion-map "\C-_" 'completer-undo)
885 (define-key minibuffer-local-completion-map "\t" 'completer-complete)
886 (define-key minibuffer-local-completion-map " " 'completer-word)
887 (define-key minibuffer-local-completion-map "?" 'completer-help)
888 (define-key minibuffer-local-completion-map "\n" 'completer-minibuf-exit)
889 (define-key minibuffer-local-completion-map "\r" 'completer-minibuf-exit)
890 (define-key minibuffer-local-completion-map "\M-\n" 'completer-match-exit)
891 (define-key minibuffer-local-completion-map "\M-\r" 'completer-match-exit)
892
893 ;this interferes with normal undo.
894 ;(define-key minibuffer-local-must-match-map "\C-_" 'completer-undo)
895 (define-key minibuffer-local-must-match-map "\t" 'completer-complete)
896 (define-key minibuffer-local-must-match-map " " 'completer-word)
897 (define-key minibuffer-local-must-match-map "\n" 'completer-exit)
898 (define-key minibuffer-local-must-match-map "\r" 'completer-exit)
899 (define-key minibuffer-local-must-match-map "?" 'completer-help)
900 (define-key minibuffer-local-must-match-map "\M-\n" 'completer-match-exit)
901 (define-key minibuffer-local-must-match-map "\M-\r" 'completer-match-exit)
902
903 ;;;%comint
904 (defun completer-comint-dynamic-list-completions (completions)
905 "List in help buffer sorted COMPLETIONS.
906 Typing SPC flushes the help buffer."
907 (completer-comint-dynamic-complete-1 nil 'help))
908
909 (defun completer-comint-dynamic-complete-filename ()
910 "Dynamically complete the filename at point."
911 (interactive)
912 (completer-comint-dynamic-complete-1 nil t))
913
914 ;;;
915 (defun completer-comint-dynamic-complete-1 (&optional undo mode)
916 "Complete the previous filename or display possibilities if done
917 twice in a row. If called with a prefix, undo the last completion."
918 (interactive "P")
919 (if undo
920 (completer-undo)
921 ;; added by jwz: don't cache completions in shell buffer!
922 (setq completer-string nil)
923 (let ((conf (current-window-configuration)));; lemacs change
924 (completer-complete-goto
925 "^ \t\n\""
926 completer-words
927 'read-file-name-internal
928 default-directory
929 mode)
930 ;; lemacs change
931 (if (eq mode 'help) (comint-restore-window-config conf))
932 )))
933 ;(fset 'comint-dynamic-complete 'completer-comint-dynamic-complete)
934 (fset 'comint-dynamic-complete-filename
935 'completer-comint-dynamic-complete-filename)
936 (fset 'comint-dynamic-list-completions
937 'completer-comint-dynamic-list-completions)
938
939 ;;; Set the functions again if comint is loaded
940 (setq comint-load-hook
941 (cons (function (lambda ()
942 ;; (fset 'comint-dynamic-complete
943 ;; 'completer-comint-dynamic-complete)
944 (fset 'comint-dynamic-complete-filename
945 'completer-comint-dynamic-complete-filename)
946 (fset 'comint-dynamic-list-completions
947 'completer-comint-dynamic-list-completions)))
948 (if (and (boundp 'comint-load-hook) comint-load-hook)
949 (if (consp comint-load-hook)
950 (if (eq (car comint-load-hook) 'lambda)
951 (list comint-load-hook)
952 comint-load-hook)
953 (list comint-load-hook)))))
954
955 ;;;%lisp-complete-symbol
956 (defun lisp-complete-symbol (&optional mode)
957 "Perform partial completion on Lisp symbol preceding point. That
958 symbol is compared against the symbols that exist and any additional
959 characters determined by what is there are inserted. If the symbol
960 starts just after an open-parenthesis, only symbols with function
961 definitions are considered. Otherwise, all symbols with function
962 definitions, values or properties are considered. If called with a
963 negative prefix, the last completion will be undone."
964 (interactive "P")
965 (if (< (prefix-numeric-value mode) 0)
966 (completer-undo)
967 (let* ((end (save-excursion (skip-chars-forward "^ \t\n)]}\"") (point)))
968 (beg (save-excursion
969 (backward-sexp 1)
970 (while (= (char-syntax (following-char)) ?\')
971 (forward-char 1))
972 (point)))
973 (pattern (buffer-substring beg end))
974 (predicate
975 (if (eq (char-after (1- beg)) ?\()
976 'fboundp
977 (function (lambda (sym)
978 (or (boundp sym) (fboundp sym)
979 (symbol-plist sym))))))
980 (completion (try-completion pattern obarray predicate)))
981 (cond ((eq completion t))
982 ((null completion)
983 (completer-complete-goto
984 "^ \t\n\(\)[]{}'`" completer-words
985 obarray predicate
986 nil
987 (if (not (eq predicate 'fboundp))
988 (function (lambda (choice)
989 (if (fboundp (intern choice))
990 (list choice " <f>")
991 choice))))))
992 ((not (string= pattern completion))
993 (delete-region beg end)
994 (insert completion))
995 (t
996 (message "Making completion list...")
997 (let ((list (all-completions pattern obarray predicate)))
998 (or (eq predicate 'fboundp)
999 (let (new)
1000 (while list
1001 (setq new (cons (if (fboundp (intern (car list)))
1002 (list (car list) " <f>")
1003 (car list))
1004 new))
1005 (setq list (cdr list)))
1006 (setq list (nreverse new))))
1007 (with-output-to-temp-buffer "*Help*"
1008 (funcall completion-display-completion-list-function
1009 (sort list (function (lambda (x y)
1010 (string-lessp
1011 (or (car-safe x) x)
1012 (or (car-safe y) y))))))))
1013 (message "Making completion list...%s" "done"))))))
1014
1015 ;;;%Hooks
1016 (provide 'completer)
1017 (run-hooks 'completer-load-hook)