aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2009-10-25 20:38:06 +0000
committerStefan Monnier2009-10-25 20:38:06 +0000
commit2d0853070d1353348e6ef067b138d971cf52f341 (patch)
tree9b9eebeab34943bb08b42832f2165025885408ee /lisp
parent955ef4309a441a2d53605631d1346a238bba43ea (diff)
downloademacs-2d0853070d1353348e6ef067b138d971cf52f341.tar.gz
emacs-2d0853070d1353348e6ef067b138d971cf52f341.zip
(pcomplete-unquote-argument-function): New var.
(pcomplete-unquote-argument): New function. (pcomplete--common-suffix): Always pay attention to case. (pcomplete--table-subvert): Quote and unquote the text. (pcomplete--common-quoted-suffix): New function. (pcomplete-std-complete): Use it and pcomplete-begin.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog7
-rw-r--r--lisp/pcomplete.el330
2 files changed, 189 insertions, 148 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index c6a8287942c..0ff59e4ef35 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,12 @@
12009-10-25 Stefan Monnier <monnier@iro.umontreal.ca> 12009-10-25 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * pcomplete.el (pcomplete-unquote-argument-function): New var.
4 (pcomplete-unquote-argument): New function.
5 (pcomplete--common-suffix): Always pay attention to case.
6 (pcomplete--table-subvert): Quote and unquote the text.
7 (pcomplete--common-quoted-suffix): New function.
8 (pcomplete-std-complete): Use it and pcomplete-begin.
9
3 * bookmark.el (bookmark-bmenu-list): Don't use switch-to-buffer if 10 * bookmark.el (bookmark-bmenu-list): Don't use switch-to-buffer if
4 we're inside a dedicated or minibuffer window. 11 we're inside a dedicated or minibuffer window.
5 12
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el
index f23b219e1e1..371b61eea1b 100644
--- a/lisp/pcomplete.el
+++ b/lisp/pcomplete.el
@@ -351,65 +351,69 @@ modified to be an empty string, or the desired separation string."
351 351
352;;; User Functions: 352;;; User Functions:
353 353
354;;;###autoload 354;;; Alternative front-end using the standard completion facilities.
355(defun pcomplete (&optional interactively) 355
356 "Support extensible programmable completion. 356;; The way pcomplete-parse-arguments, pcomplete-stub, and
357To use this function, just bind the TAB key to it, or add it to your 357;; pcomplete-quote-argument work only works because of some deep
358completion functions list (it should occur fairly early in the list)." 358;; hypothesis about the way the completion work. Basically, it makes
359 (interactive "p") 359;; it pretty much impossible to have completion other than
360 (if (and interactively 360;; prefix-completion.
361 pcomplete-cycle-completions 361;;
362 pcomplete-current-completions 362;; pcomplete--common-quoted-suffix and pcomplete--table-subvert try to
363 (memq last-command '(pcomplete 363;; work around this difficulty with heuristics, but it's
364 pcomplete-expand-and-complete 364;; really a hack.
365 pcomplete-reverse))) 365
366 (progn 366(defvar pcomplete-unquote-argument-function nil)
367 (delete-backward-char pcomplete-last-completion-length) 367
368 (if (eq this-command 'pcomplete-reverse) 368(defun pcomplete-unquote-argument (s)
369 (progn 369 (cond
370 (setq pcomplete-current-completions 370 (pcomplete-unquote-argument-function
371 (cons (car (last pcomplete-current-completions)) 371 (funcall pcomplete-unquote-argument-function s))
372 pcomplete-current-completions)) 372 ((null pcomplete-arg-quote-list) s)
373 (setcdr (last pcomplete-current-completions 2) nil)) 373 (t
374 (nconc pcomplete-current-completions 374 (replace-regexp-in-string "\\\\\\(.\\)" "\\1" s t))))
375 (list (car pcomplete-current-completions)))
376 (setq pcomplete-current-completions
377 (cdr pcomplete-current-completions)))
378 (pcomplete-insert-entry pcomplete-last-completion-stub
379 (car pcomplete-current-completions)
380 nil pcomplete-last-completion-raw))
381 (setq pcomplete-current-completions nil
382 pcomplete-last-completion-raw nil)
383 (catch 'pcompleted
384 (let* ((pcomplete-stub)
385 pcomplete-seen pcomplete-norm-func
386 pcomplete-args pcomplete-last pcomplete-index
387 (pcomplete-autolist pcomplete-autolist)
388 (pcomplete-suffix-list pcomplete-suffix-list)
389 (completions (pcomplete-completions))
390 (result (pcomplete-do-complete pcomplete-stub completions)))
391 (and result
392 (not (eq (car result) 'listed))
393 (cdr result)
394 (pcomplete-insert-entry pcomplete-stub (cdr result)
395 (memq (car result)
396 '(sole shortest))
397 pcomplete-last-completion-raw))))))
398 375
399(defun pcomplete-common-suffix (s1 s2) 376(defun pcomplete--common-suffix (s1 s2)
400 (assert (not (or (string-match "\n" s1) (string-match "\n" s2)))) 377 (assert (not (or (string-match "\n" s1) (string-match "\n" s2))))
401 (let ((case-fold-search pcomplete-ignore-case)) 378 ;; Since S2 is expected to be the "unquoted/expanded" version of S1,
379 ;; there shouldn't be any case difference, even if the completion is
380 ;; case-insensitive.
381 (let ((case-fold-search nil)) ;; pcomplete-ignore-case
402 (string-match ".*?\\(.*\\)\n.*\\1\\'" (concat s1 "\n" s2)) 382 (string-match ".*?\\(.*\\)\n.*\\1\\'" (concat s1 "\n" s2))
403 (- (match-end 1) (match-beginning 1)))) 383 (- (match-end 1) (match-beginning 1))))
404 384
405(defun pcomplete-table-subvert (table s1 s2 string pred action) 385(defun pcomplete--common-quoted-suffix (s1 s2)
386 "Find the common suffix between S1 and S2 where S1 is the expanded S2.
387S1 is expected to be the unquoted and expanded version of S1.
388Returns (PS1 . PS2), i.e. the shortest prefixes of S1 and S2, such that
389S1 = (concat PS1 SS1) and S2 = (concat PS2 SS2) and
390SS1 = (unquote SS2)."
391 (let* ((cs (pcomplete--common-suffix s1 s2))
392 (ss1 (substring s1 (- (length s1) cs)))
393 (qss1 (pcomplete-quote-argument ss1))
394 qc)
395 (if (and (not (equal ss1 qss1))
396 (setq qc (pcomplete-quote-argument (substring ss1 0 1)))
397 (eq t (compare-strings s2 (- (length s2) cs (length qc) -1)
398 (- (length s2) cs -1)
399 qc nil nil)))
400 ;; The difference found is just that one char is quoted in S2
401 ;; but not in S1, keep looking before this difference.
402 (pcomplete--common-quoted-suffix
403 (substring s1 0 (- (length s1) cs))
404 (substring s2 0 (- (length s2) cs (length qc) -1)))
405 (cons (substring s1 0 (- (length s1) cs))
406 (substring s2 0 (- (length s2) cs))))))
407
408(defun pcomplete--table-subvert (table s1 s2 string pred action)
406 "Completion table that replaces the prefix S1 with S2 in STRING. 409 "Completion table that replaces the prefix S1 with S2 in STRING.
407When TABLE, S1 and S2 are provided by `apply-partially', the result 410When TABLE, S1 and S2 are provided by `apply-partially', the result
408is a completion table which completes strings of the form (concat S1 S) 411is a completion table which completes strings of the form (concat S1 S)
409in the same way as TABLE completes strings of the form (concat S2 S)." 412in the same way as TABLE completes strings of the form (concat S2 S)."
410 (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil 413 (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil
411 completion-ignore-case)) 414 completion-ignore-case))
412 (concat s2 (substring string (length s1))))) 415 (concat s2 (pcomplete-unquote-argument
416 (substring string (length s1))))))
413 (res (if str (complete-with-action action table str pred)))) 417 (res (if str (complete-with-action action table str pred))))
414 (when res 418 (when res
415 (cond 419 (cond
@@ -417,12 +421,14 @@ in the same way as TABLE completes strings of the form (concat S2 S)."
417 (let ((beg (or (and (eq (car-safe res) 'boundaries) (cadr res)) 0))) 421 (let ((beg (or (and (eq (car-safe res) 'boundaries) (cadr res)) 0)))
418 (list* 'boundaries 422 (list* 'boundaries
419 (max (length s1) 423 (max (length s1)
424 ;; FIXME: Adjust because of quoting/unquoting.
420 (+ beg (- (length s1) (length s2)))) 425 (+ beg (- (length s1) (length s2))))
421 (and (eq (car-safe res) 'boundaries) (cddr res))))) 426 (and (eq (car-safe res) 'boundaries) (cddr res)))))
422 ((stringp res) 427 ((stringp res)
423 (if (eq t (compare-strings res 0 (length s2) s2 nil nil 428 (if (eq t (compare-strings res 0 (length s2) s2 nil nil
424 completion-ignore-case)) 429 completion-ignore-case))
425 (concat s1 (substring res (length s2))))) 430 (concat s1 (pcomplete-quote-argument
431 (substring res (length s2))))))
426 ((eq action t) 432 ((eq action t)
427 (let ((bounds (completion-boundaries str table pred ""))) 433 (let ((bounds (completion-boundaries str table pred "")))
428 (if (>= (car bounds) (length s2)) 434 (if (>= (car bounds) (length s2))
@@ -435,14 +441,14 @@ in the same way as TABLE completes strings of the form (concat S2 S)."
435 (substring c (match-end 0)))) 441 (substring c (match-end 0))))
436 res)))))))))) 442 res))))))))))
437 443
438 444;; I don't think such commands are usable before first setting up buffer-local
445;; variables to parse args, so there's no point autoloading it.
446;; ;;;###autoload
439(defun pcomplete-std-complete () 447(defun pcomplete-std-complete ()
440 "Provide standard completion using pcomplete's completion tables. 448 "Provide standard completion using pcomplete's completion tables.
441Same as `pcomplete' but using the standard completion UI." 449Same as `pcomplete' but using the standard completion UI."
442 (interactive) 450 (interactive)
443 ;; FIXME: it fails to unquote/requote the arguments.
444 ;; FIXME: it doesn't implement paring. 451 ;; FIXME: it doesn't implement paring.
445 ;; FIXME: when we bring up *Completions* we never bring it back down.
446 (catch 'pcompleted 452 (catch 'pcompleted
447 (let* ((pcomplete-stub) 453 (let* ((pcomplete-stub)
448 pcomplete-seen pcomplete-norm-func 454 pcomplete-seen pcomplete-norm-func
@@ -465,46 +471,98 @@ Same as `pcomplete' but using the standard completion UI."
465 ;; pcomplete-stub and works from the buffer's text instead, 471 ;; pcomplete-stub and works from the buffer's text instead,
466 ;; we need to trick minibuffer-complete, into using 472 ;; we need to trick minibuffer-complete, into using
467 ;; pcomplete-stub without its knowledge. To that end, we 473 ;; pcomplete-stub without its knowledge. To that end, we
468 ;; use pcomplete-table-subvert to construct a completion 474 ;; use pcomplete--table-subvert to construct a completion
469 ;; table which expects strings using a prefix from the 475 ;; table which expects strings using a prefix from the
470 ;; buffer's text but internally uses the corresponding 476 ;; buffer's text but internally uses the corresponding
471 ;; prefix from pcomplete-stub. 477 ;; prefix from pcomplete-stub.
472 (beg (max (- (point) (length pcomplete-stub)) 478 (beg (max (- (point) (length pcomplete-stub))
473 ;; Rather than `point-min' we should use the 479 (pcomplete-begin)))
474 ;; beginning position of the current arg.
475 (point-min)))
476 (buftext (buffer-substring beg (point))) 480 (buftext (buffer-substring beg (point)))
477 ;; This isn't always strictly right (e.g. if 481 (table
478 ;; FOO="toto/$FOO", then completion of /$FOO/bar may 482 (if (not (equal pcomplete-stub buftext))
479 ;; result in something incorrect), but given the lack of 483 ;; This isn't always strictly right (e.g. if
480 ;; any other info, it's about as good as it gets, and in 484 ;; FOO="toto/$FOO", then completion of /$FOO/bar may
481 ;; practice it should work just fine (fingers crossed). 485 ;; result in something incorrect), but given the lack of
482 (suflen (pcomplete-common-suffix pcomplete-stub buftext))) 486 ;; any other info, it's about as good as it gets, and in
483 (unless (= suflen (length pcomplete-stub)) 487 ;; practice it should work just fine (fingers crossed).
484 (setq completions 488 (let ((prefixes (pcomplete--common-quoted-suffix
485 (apply-partially 489 pcomplete-stub buftext)))
486 'pcomplete-table-subvert 490 (apply-partially
487 completions 491 'pcomplete--table-subvert
488 (substring buftext 0 (- (length buftext) suflen)) 492 completions
489 (substring pcomplete-stub 493 (cdr prefixes) (car prefixes)))
490 0 (- (length pcomplete-stub) suflen))))) 494 (lexical-let ((completions completions))
495 (lambda (string pred action)
496 (let ((res (complete-with-action
497 action completions string pred)))
498 (if (stringp res)
499 (pcomplete-quote-argument res)
500 res)))))))
501
491 (let ((ol (make-overlay beg (point) nil nil t)) 502 (let ((ol (make-overlay beg (point) nil nil t))
492 (minibuffer-completion-table 503 (minibuffer-completion-table
493 ;; Add a space at the end of completion. Use a terminator-regexp 504 ;; Add a space at the end of completion. Use a terminator-regexp
494 ;; that never matches since the terminator cannot appear 505 ;; that never matches since the terminator cannot appear
495 ;; within the completion field anyway. 506 ;; within the completion field anyway.
496 (if (zerop (length pcomplete-termination-string)) 507 (if (zerop (length pcomplete-termination-string))
497 completions 508 table
498 (apply-partially 'completion-table-with-terminator 509 (apply-partially 'completion-table-with-terminator
499 (cons pcomplete-termination-string 510 (cons pcomplete-termination-string
500 "\\`a\\`") 511 "\\`a\\`")
501 completions))) 512 table)))
502 (minibuffer-completion-predicate nil)) 513 (minibuffer-completion-predicate nil))
503 (overlay-put ol 'field 'pcomplete) 514 (overlay-put ol 'field 'pcomplete)
504 (unwind-protect 515 (unwind-protect
505 (call-interactively 'minibuffer-complete) 516 (call-interactively 'minibuffer-complete)
506 (delete-overlay ol)))))) 517 (delete-overlay ol))))))
507 518
519;;; Pcomplete's native UI.
520
521;;;###autoload
522(defun pcomplete (&optional interactively)
523 "Support extensible programmable completion.
524To use this function, just bind the TAB key to it, or add it to your
525completion functions list (it should occur fairly early in the list)."
526 (interactive "p")
527 (if (and interactively
528 pcomplete-cycle-completions
529 pcomplete-current-completions
530 (memq last-command '(pcomplete
531 pcomplete-expand-and-complete
532 pcomplete-reverse)))
533 (progn
534 (delete-backward-char pcomplete-last-completion-length)
535 (if (eq this-command 'pcomplete-reverse)
536 (progn
537 (setq pcomplete-current-completions
538 (cons (car (last pcomplete-current-completions))
539 pcomplete-current-completions))
540 (setcdr (last pcomplete-current-completions 2) nil))
541 (nconc pcomplete-current-completions
542 (list (car pcomplete-current-completions)))
543 (setq pcomplete-current-completions
544 (cdr pcomplete-current-completions)))
545 (pcomplete-insert-entry pcomplete-last-completion-stub
546 (car pcomplete-current-completions)
547 nil pcomplete-last-completion-raw))
548 (setq pcomplete-current-completions nil
549 pcomplete-last-completion-raw nil)
550 (catch 'pcompleted
551 (let* ((pcomplete-stub)
552 pcomplete-seen pcomplete-norm-func
553 pcomplete-args pcomplete-last pcomplete-index
554 (pcomplete-autolist pcomplete-autolist)
555 (pcomplete-suffix-list pcomplete-suffix-list)
556 (completions (pcomplete-completions))
557 (result (pcomplete-do-complete pcomplete-stub completions)))
558 (and result
559 (not (eq (car result) 'listed))
560 (cdr result)
561 (pcomplete-insert-entry pcomplete-stub (cdr result)
562 (memq (car result)
563 '(sole shortest))
564 pcomplete-last-completion-raw))))))
565
508;;;###autoload 566;;;###autoload
509(defun pcomplete-reverse () 567(defun pcomplete-reverse ()
510 "If cycling completion is in use, cycle backwards." 568 "If cycling completion is in use, cycle backwards."
@@ -713,6 +771,7 @@ this is `comint-dynamic-complete-functions'."
713;;;###autoload 771;;;###autoload
714(defun pcomplete-shell-setup () 772(defun pcomplete-shell-setup ()
715 "Setup `shell-mode' to use pcomplete." 773 "Setup `shell-mode' to use pcomplete."
774 ;; FIXME: insufficient
716 (pcomplete-comint-setup 'comint-dynamic-complete-functions)) 775 (pcomplete-comint-setup 'comint-dynamic-complete-functions))
717 776
718(declare-function comint-bol "comint" (&optional arg)) 777(declare-function comint-bol "comint" (&optional arg))
@@ -789,23 +848,17 @@ this is `comint-dynamic-complete-functions'."
789Magic characters are those in `pcomplete-arg-quote-list'." 848Magic characters are those in `pcomplete-arg-quote-list'."
790 (if (null pcomplete-arg-quote-list) 849 (if (null pcomplete-arg-quote-list)
791 filename 850 filename
792 (let ((len (length filename)) 851 (let ((index 0))
793 (index 0) 852 (mapconcat (lambda (c)
794 (result "") 853 (prog1
795 replacement char) 854 (or (run-hook-with-args-until-success
796 (while (< index len) 855 'pcomplete-quote-arg-hook filename index)
797 (setq replacement (run-hook-with-args-until-success 856 (when (memq c pcomplete-arg-quote-list)
798 'pcomplete-quote-arg-hook filename index)) 857 (string "\\" c))
799 (cond 858 (char-to-string c))
800 (replacement 859 (setq index (1+ index))))
801 (setq result (concat result replacement))) 860 filename
802 ((memq (setq char (aref filename index)) 861 ""))))
803 pcomplete-arg-quote-list)
804 (setq result (concat result (string "\\" char))))
805 (t
806 (setq result (concat result (char-to-string char)))))
807 (setq index (1+ index)))
808 result)))
809 862
810;; file-system completion lists 863;; file-system completion lists
811 864
@@ -829,65 +882,46 @@ If PREDICATE is non-nil, it will also be used to refine the match
829\(files for which the PREDICATE returns nil will be excluded). 882\(files for which the PREDICATE returns nil will be excluded).
830If no directory information can be extracted from the completed 883If no directory information can be extracted from the completed
831component, `default-directory' is used as the basis for completion." 884component, `default-directory' is used as the basis for completion."
832 (let* ((name (substitute-env-vars pcomplete-stub)) 885 ;; FIXME: obey pcomplete-file-ignore and pcomplete-dir-ignore.
833 (completion-ignore-case pcomplete-ignore-case) 886 ;; FIXME: obey pcomplete-compare-entry-function (tho only if there
834 (default-directory (expand-file-name 887 ;; are less than pcomplete-cycle-cutoff-length completions).
835 (or (file-name-directory name) 888 ;; FIXME: expand envvars? shouldn't this be done globally instead?
836 default-directory))) 889 (let* ((reg-pred (when regexp
837 above-cutoff) 890 (lexical-let ((re regexp))
838 (setq name (file-name-nondirectory name) 891 (lambda (f)
839 pcomplete-stub name) 892 ;; (let ((name (file-name-nondirectory f)))
840 (let ((completions 893 ;; (if (zerop (length name))
841 (file-name-all-completions name default-directory))) 894 ;; (setq name (file-name-as-directory
842 (if regexp 895 ;; (file-name-nondirectory
843 (setq completions 896 ;; (directory-file-name f)))))
844 (pcomplete-pare-list 897 ;; (string-match re name))
845 completions nil 898 (string-match re f)))))
846 (function 899 (pred (cond
847 (lambda (file) 900 ((null predicate) reg-pred)
848 (not (string-match regexp file))))))) 901 ((null reg-pred) predicate)
849 (if predicate 902 (t (lexical-let ((predicate predicate)
850 (setq completions 903 (reg-pred reg-pred))
851 (pcomplete-pare-list 904 (lambda (f)
852 completions nil 905 (and (funcall predicate f)
853 (function 906 (funcall reg-pred f)))))))
854 (lambda (file) 907 (fun
855 (not (funcall predicate file))))))) 908 (lexical-let ((pred pred)
856 (if (or pcomplete-file-ignore pcomplete-dir-ignore) 909 (dir default-directory))
857 (setq completions 910 (lambda (s p a)
858 (pcomplete-pare-list 911 ;; Remember the default-directory that was active when we built
859 completions nil 912 ;; the completion table.
860 (function 913 (let ((default-directory dir)
861 (lambda (file) 914 ;; The old code used only file-name-all-completions
862 (if (eq (aref file (1- (length file))) 915 ;; which ignores completion-ignored-extensions.
863 ?/) 916 (completion-ignored-extensions nil))
864 (and pcomplete-dir-ignore 917 (completion-table-with-predicate
865 (string-match pcomplete-dir-ignore file)) 918 'completion-file-name-table pred 'strict s p a)))))
866 (and pcomplete-file-ignore 919 ;; Indirect through a symbol rather than returning a lambda
867 (string-match pcomplete-file-ignore file)))))))) 920 ;; expression, so as to help catch bugs where the caller
868 (setq above-cutoff (and pcomplete-cycle-cutoff-length 921 ;; might treat the lambda expression as a list of completions.
869 (> (length completions) 922 (sym (make-symbol "pcomplete-read-file-name-internal")))
870 pcomplete-cycle-cutoff-length))) 923 (fset sym fun)
871 (sort completions 924 sym))
872 (function
873 (lambda (l r)
874 ;; for the purposes of comparison, remove the
875 ;; trailing slash from directory names.
876 ;; Otherwise, "foo.old/" will come before "foo/",
877 ;; since . is earlier in the ASCII alphabet than
878 ;; /
879 (let ((left (if (eq (aref l (1- (length l)))
880 ?/)
881 (substring l 0 (1- (length l)))
882 l))
883 (right (if (eq (aref r (1- (length r)))
884 ?/)
885 (substring r 0 (1- (length r)))
886 r)))
887 (if above-cutoff
888 (string-lessp left right)
889 (funcall pcomplete-compare-entry-function
890 left right)))))))))
891 925
892(defsubst pcomplete-all-entries (&optional regexp predicate) 926(defsubst pcomplete-all-entries (&optional regexp predicate)
893 "Like `pcomplete-entries', but doesn't ignore any entries." 927 "Like `pcomplete-entries', but doesn't ignore any entries."