aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1994-03-03 23:37:27 +0000
committerRichard M. Stallman1994-03-03 23:37:27 +0000
commit988a4d60ceddc04f86a5d691b165f257e17a8633 (patch)
tree41f104c7214c9588560bd13e951255227cae27b0
parent1b4218268dcde0a1311dca7870884fc787717597 (diff)
downloademacs-988a4d60ceddc04f86a5d691b165f257e17a8633.tar.gz
emacs-988a4d60ceddc04f86a5d691b165f257e17a8633.zip
(shell-dynamic-complete-functions): New variable.
(shell-mode): Use it to set comint-dynamic-complete-functions. (shell-mode-map): Define menu-bars for command, variable and directory completion/expansion. (shell-get-current-command, shell-after-partial-filename): Functions deleted. (shell-dynamic-complete-environment-variable, shell-replace-by-expanded-directory): New commands. (shell-match-partial-variable, shell-dynamic-complete-as-environment-variable): New functions.
-rw-r--r--lisp/shell.el245
1 files changed, 172 insertions, 73 deletions
diff --git a/lisp/shell.el b/lisp/shell.el
index 45107e67f67..3a6a9c03818 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -160,6 +160,18 @@ shell buffer. The default is (?\\| ?& ?< ?> ?\\( ?\\) ?\\;).
160 160
161This is a fine thing to set in your `.emacs' file.") 161This is a fine thing to set in your `.emacs' file.")
162 162
163(defvar shell-dynamic-complete-functions
164 '(comint-replace-by-expanded-history
165 shell-dynamic-complete-environment-variable
166 shell-dynamic-complete-command
167 shell-replace-by-expanded-directory
168 comint-dynamic-complete-filename)
169 "List of functions called to perform completion.
170This variable is used to initialise `comint-dynamic-complete-functions' in the
171shell buffer.
172
173This is a fine thing to set in your `.emacs' file.")
174
163(defvar shell-command-regexp "\\((.*)\\|[^;&|]\\)+" 175(defvar shell-command-regexp "\\((.*)\\|[^;&|]\\)+"
164 "*Regexp to match shell commands. 176 "*Regexp to match shell commands.
165Elements of pipes are considered as separate commands, forks and redirections 177Elements of pipes are considered as separate commands, forks and redirections
@@ -236,7 +248,20 @@ Thus, this does not include the shell's current directory.")
236 (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command) 248 (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command)
237 (define-key shell-mode-map "\t" 'comint-dynamic-complete) 249 (define-key shell-mode-map "\t" 'comint-dynamic-complete)
238 (define-key shell-mode-map "\M-?" 250 (define-key shell-mode-map "\M-?"
239 'comint-dynamic-list-filename-completions))) 251 'comint-dynamic-list-filename-completions)
252 ;; Undefine the general completion first.
253 (define-key shell-mode-map [menu-bar completion complete] nil)
254 (define-key shell-mode-map [menu-bar completion expand-directory]
255 '("Expand Directory Reference" . shell-replace-by-expanded-directory))
256 (define-key shell-mode-map [menu-bar completion complete-env-variable]
257 '("Complete Env. Variable Name" .
258 shell-dynamic-complete-environment-variable))
259 (define-key shell-mode-map [menu-bar completion complete-command]
260 '("Complete Command Name" . shell-dynamic-complete-command))
261 ;; Redefine (requires a new key) so that it is at the top.
262 (define-key shell-mode-map [menu-bar completion complete-shell]
263 '("Complete Before Point" . comint-dynamic-complete))
264 ))
240 265
241(defvar shell-mode-hook '() 266(defvar shell-mode-hook '()
242 "*Hook for customising Shell mode.") 267 "*Hook for customising Shell mode.")
@@ -266,8 +291,9 @@ M-x dirtrack-toggle turns directory tracking on and off.
266 291
267\\{shell-mode-map} 292\\{shell-mode-map}
268Customization: Entry to this mode runs the hooks on `comint-mode-hook' and 293Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
269`shell-mode-hook' (in that order). After each shell output, the hooks on 294`shell-mode-hook' (in that order). Before each input, the hooks on
270`comint-output-filter-functions' are run. 295`comint-input-sentinel-functions' are run. After each shell output, the hooks
296on `comint-output-sentinel-functions' are run.
271 297
272Variables `shell-cd-regexp', `shell-pushd-regexp' and `shell-popd-regexp' 298Variables `shell-cd-regexp', `shell-pushd-regexp' and `shell-popd-regexp'
273are used to match their respective commands, while `shell-pushd-tohome', 299are used to match their respective commands, while `shell-pushd-tohome',
@@ -282,9 +308,10 @@ the behavior of command name completion.
282Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control 308Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control
283the initialisation of the input ring history, and history expansion. 309the initialisation of the input ring history, and history expansion.
284 310
285Variables `comint-output-filter-functions', `comint-scroll-to-bottom-on-input', 311Variables `comint-output-sentinel-functions', a hook, and
286and `comint-scroll-to-bottom-on-output' control whether input and output 312`comint-scroll-to-bottom-on-input',and `comint-scroll-to-bottom-on-output'
287cause the window to scroll to the end of the buffer." 313control whether input and output cause the window to scroll to the end of the
314buffer."
288 (interactive) 315 (interactive)
289 (comint-mode) 316 (comint-mode)
290 (setq major-mode 'shell-mode) 317 (setq major-mode 'shell-mode)
@@ -292,9 +319,7 @@ cause the window to scroll to the end of the buffer."
292 (use-local-map shell-mode-map) 319 (use-local-map shell-mode-map)
293 (setq comint-prompt-regexp shell-prompt-pattern) 320 (setq comint-prompt-regexp shell-prompt-pattern)
294 (setq comint-delimiter-argument-list shell-delimiter-argument-list) 321 (setq comint-delimiter-argument-list shell-delimiter-argument-list)
295 (setq comint-after-partial-filename-command 'shell-after-partial-filename) 322 (setq comint-dynamic-complete-functions shell-dynamic-complete-functions)
296 (setq comint-get-current-command 'shell-get-current-command)
297 (setq comint-dynamic-complete-command-command 'shell-dynamic-complete-command)
298 (make-local-variable 'paragraph-start) 323 (make-local-variable 'paragraph-start)
299 (setq paragraph-start comint-prompt-regexp) 324 (setq paragraph-start comint-prompt-regexp)
300 (make-local-variable 'shell-dirstack) 325 (make-local-variable 'shell-dirstack)
@@ -302,7 +327,7 @@ cause the window to scroll to the end of the buffer."
302 (setq shell-last-dir nil) 327 (setq shell-last-dir nil)
303 (make-local-variable 'shell-dirtrackp) 328 (make-local-variable 'shell-dirtrackp)
304 (setq shell-dirtrackp t) 329 (setq shell-dirtrackp t)
305 (setq comint-input-sentinel 'shell-directory-tracker) 330 (add-hook 'comint-output-sentinel-functions 'shell-directory-tracker)
306 (setq comint-input-autoexpand shell-input-autoexpand) 331 (setq comint-input-autoexpand shell-input-autoexpand)
307 ;; shell-dependent assignments. 332 ;; shell-dependent assignments.
308 (let ((shell (car (process-command (get-buffer-process (current-buffer)))))) 333 (let ((shell (car (process-command (get-buffer-process (current-buffer))))))
@@ -621,27 +646,6 @@ See `shell-command-regexp'."
621 (skip-chars-forward ";&|"))))) 646 (skip-chars-forward ";&|")))))
622 647
623 648
624(defun shell-get-current-command ()
625 "Function that returns the current command including arguments."
626 (save-excursion
627 (if (looking-at "[\t ]*[^;&|\n]")
628 (goto-char (match-end 0)))
629 (buffer-substring
630 (progn (shell-backward-command 1) (point))
631 (progn (shell-forward-command 1) (if (eolp) (point) (match-end 1))))))
632
633
634(defun shell-after-partial-filename ()
635 "Returns t if point is after a file name.
636File names are assumed to contain `/'s or not be the first item in the command.
637
638See also `shell-backward-command'."
639 (let ((filename (comint-match-partial-filename)))
640 (or (save-match-data (string-match "/" filename))
641 (not (eq (match-beginning 0)
642 (save-excursion (shell-backward-command 1) (point)))))))
643
644
645(defun shell-dynamic-complete-command () 649(defun shell-dynamic-complete-command ()
646 "Dynamically complete the command at point. 650 "Dynamically complete the command at point.
647This function is similar to `comint-dynamic-complete-filename', except that it 651This function is similar to `comint-dynamic-complete-filename', except that it
@@ -650,10 +654,25 @@ candidates. Note that this may not be the same as the shell's idea of the
650path. 654path.
651 655
652Completion is dependent on the value of `shell-completion-execonly', plus 656Completion is dependent on the value of `shell-completion-execonly', plus
653those that effect file completion. See `comint-dynamic-complete-filename'." 657those that effect file completion. See `shell-dynamic-complete-as-command'.
658
659Returns t if successful."
654 (interactive) 660 (interactive)
661 (let ((filename (comint-match-partial-filename)))
662 (if (and filename
663 (save-match-data (not (string-match "[~/]" filename)))
664 (eq (match-beginning 0)
665 (save-excursion (shell-backward-command 1) (point))))
666 (prog2 (message "Completing command name...")
667 (shell-dynamic-complete-as-command)))))
668
669
670(defun shell-dynamic-complete-as-command ()
671 "Dynamically complete at point as a command.
672See `shell-dynamic-complete-filename'. Returns t if successful."
655 (let* ((completion-ignore-case nil) 673 (let* ((completion-ignore-case nil)
656 (filename (comint-match-partial-filename)) 674 (success t)
675 (filename (or (comint-match-partial-filename) ""))
657 (pathnondir (file-name-nondirectory filename)) 676 (pathnondir (file-name-nondirectory filename))
658 (paths (cdr (reverse exec-path))) 677 (paths (cdr (reverse exec-path)))
659 (cwd (file-name-as-directory (expand-file-name default-directory))) 678 (cwd (file-name-as-directory (expand-file-name default-directory)))
@@ -681,47 +700,127 @@ those that effect file completion. See `comint-dynamic-complete-filename'."
681 (setq paths (cdr paths))) 700 (setq paths (cdr paths)))
682 ;; OK, we've got a list of completions. 701 ;; OK, we've got a list of completions.
683 (cond ((null completions) 702 (cond ((null completions)
684 (message "No completions of %s" filename) 703 (message "No completions of %s" filename)
685 (ding)) 704 (setq success nil))
686 ((= 1 (length completions)) ; Gotcha! 705 ((= 1 (length completions)) ; Gotcha!
687 (let ((completion (car completions))) 706 (let ((completion (car completions)))
688 (if (string-equal completion pathnondir) 707 (if (string-equal completion pathnondir)
689 (message "Sole completion") 708 (message "Sole completion")
690 (insert (substring (directory-file-name completion) 709 (insert (substring (directory-file-name completion)
691 (length pathnondir))) 710 (length pathnondir)))
692 (message "Completed")) 711 (message "Completed"))
693 (if comint-completion-addsuffix 712 (if comint-completion-addsuffix
694 (insert (if (file-directory-p completion) "/" " "))))) 713 (insert (if (file-directory-p completion) "/" " ")))))
695 (t ; There's no unique completion. 714 (t ; There's no unique completion.
696 (let ((completion 715 (let ((completion
697 (try-completion pathnondir (mapcar (function (lambda (x) 716 (try-completion pathnondir (mapcar (function (lambda (x)
698 (list x))) 717 (list x)))
699 completions)))) 718 completions))))
700 ;; Insert the longest substring. 719 ;; Insert the longest substring.
701 (insert (substring (directory-file-name completion) 720 (insert (substring (directory-file-name completion)
702 (length pathnondir))) 721 (length pathnondir)))
703 (cond ((and comint-completion-recexact comint-completion-addsuffix 722 (cond ((and comint-completion-recexact comint-completion-addsuffix
704 (string-equal pathnondir completion) 723 (string-equal pathnondir completion)
705 (member completion completions)) 724 (member completion completions))
706 ;; It's not unique, but user wants shortest match. 725 ;; It's not unique, but user wants shortest match.
707 (insert (if (file-directory-p completion) "/" " ")) 726 (insert (if (file-directory-p completion) "/" " "))
708 (message "Completed shortest")) 727 (message "Completed shortest"))
709 ((or comint-completion-autolist 728 ((or comint-completion-autolist
710 (string-equal pathnondir completion)) 729 (string-equal pathnondir completion))
711 ;; It's not unique, list possible completions. 730 ;; It's not unique, list possible completions.
712 (comint-dynamic-list-completions completions)) 731 (comint-dynamic-list-completions completions))
713 (t 732 (t
714 (message "Partially completed")))))))) 733 (message "Partially completed"))))))
715 734 success))
716;;; Do the user's customization... 735
717;;; 736
718;;; Isn't this what eval-after-load is for? 737(defun shell-match-partial-variable ()
719;;;(defvar shell-load-hook nil 738 "Return the variable at point, or nil if non is found."
720;;; "This hook is run when shell is loaded in. 739 (save-excursion
721;;;This is a good place to put keybindings.") 740 (let ((limit (point)))
722;;; 741 (if (re-search-backward "[^A-Za-z0-9_{}]" nil 'move)
723;;;(run-hooks 'shell-load-hook) 742 (or (looking-at "\\$") (forward-char 1)))
743 ;; Anchor the search forwards.
744 (if (or (eolp) (looking-at "[^A-Za-z0-9_{}$]"))
745 nil
746 (re-search-forward "\\$?{?[A-Za-z0-9_]*}?" limit)
747 (buffer-substring (match-beginning 0) (match-end 0))))))
724 748
749
750(defun shell-dynamic-complete-environment-variable ()
751 "Dynamically complete the environment variable at point.
752Completes if after a variable, i.e., if it starts with a \"$\".
753See `shell-dynamic-complete-as-environment-variable'.
754
755This function is similar to `comint-dynamic-complete-filename', except that it
756searches `process-environment' for completion candidates. Note that this may
757not be the same as the interpreter's idea of variable names. The main problem
758with this type of completion is that `process-environment' is the environment
759which Emacs started with. Emacs does not track changes to the environment made
760by the interpreter. Perhaps it would be more accurate if this function was
761called `shell-dynamic-complete-process-environment-variable'.
762
763Returns non-nil if successful."
764 (interactive)
765 (let ((variable (shell-match-partial-variable)))
766 (if (and variable (string-match "^\\$" variable))
767 (prog2 (message "Completing variable name...")
768 (shell-dynamic-complete-as-environment-variable)))))
769
770
771(defun shell-dynamic-complete-as-environment-variable ()
772 "Dynamically complete at point as an environment variable.
773Used by `shell-dynamic-complete-environment-variable'.
774Uses `comint-dynamic-simple-complete'."
775 (let* ((var (or (shell-match-partial-variable) ""))
776 (variable (substring var (or (string-match "[^$({]\\|$" var) 0)))
777 (variables (mapcar (function (lambda (x)
778 (substring x 0 (string-match "=" x))))
779 process-environment))
780 (addsuffix comint-completion-addsuffix)
781 (comint-completion-addsuffix nil)
782 (success (comint-dynamic-simple-complete variable variables)))
783 (if (memq success '(sole shortest))
784 (let* ((var (shell-match-partial-variable))
785 (variable (substring var (string-match "[^$({]" var)))
786 (protection (cond ((string-match "{" var) "}")
787 ((string-match "(" var) ")")
788 (t "")))
789 (suffix (cond ((null addsuffix) "")
790 ((file-directory-p
791 (comint-directory (getenv variable))) "/")
792 (t " "))))
793 (insert protection suffix)))
794 success))
795
796
797(defun shell-replace-by-expanded-directory ()
798 "Expand directory stack reference before point.
799Directory stack references are of the form \"=digit\" or \"=-\".
800See `default-directory' and `shell-dirstack'.
801
802Returns t if successful."
803 (interactive)
804 (if (comint-match-partial-filename)
805 (save-excursion
806 (message "Expanding directory references...")
807 (goto-char (match-beginning 0))
808 (let ((stack (cons default-directory shell-dirstack))
809 (index (cond ((looking-at "=-/?")
810 (length shell-dirstack))
811 ((looking-at "=\\([0-9]+\\)")
812 (string-to-number
813 (buffer-substring
814 (match-beginning 1) (match-end 1)))))))
815 (cond ((null index)
816 nil)
817 ((>= index (length stack))
818 (error "Directory stack not that deep."))
819 (t
820 (replace-match (file-name-as-directory (nth index stack)) t t)
821 (message "Directory item: %d" index)
822 t))))))
823
725(provide 'shell) 824(provide 'shell)
726 825
727;;; shell.el ends here 826;;; shell.el ends here