comparison lisp/shell.el @ 6186:84df7a6f6240

(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.
author Richard M. Stallman <rms@gnu.org>
date Thu, 03 Mar 1994 23:37:27 +0000
parents 2b445a954b0b
children 4ff931c18e4b
comparison
equal deleted inserted replaced
6185:82a92cf44059 6186:84df7a6f6240
158 This variable is used to initialize `comint-delimiter-argument-list' in the 158 This variable is used to initialize `comint-delimiter-argument-list' in the
159 shell buffer. The default is (?\\| ?& ?< ?> ?\\( ?\\) ?\\;). 159 shell buffer. The default is (?\\| ?& ?< ?> ?\\( ?\\) ?\\;).
160 160
161 This is a fine thing to set in your `.emacs' file.") 161 This 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.
170 This variable is used to initialise `comint-dynamic-complete-functions' in the
171 shell buffer.
172
173 This 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.
165 Elements of pipes are considered as separate commands, forks and redirections 177 Elements of pipes are considered as separate commands, forks and redirections
166 as part of one command.") 178 as part of one command.")
167 179
234 (setq shell-mode-map (copy-keymap comint-mode-map)) 246 (setq shell-mode-map (copy-keymap comint-mode-map))
235 (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command) 247 (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command)
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.")
243 268
244 269
264 directory stack is. 289 directory stack is.
265 M-x dirtrack-toggle turns directory tracking on and off. 290 M-x dirtrack-toggle turns directory tracking on and off.
266 291
267 \\{shell-mode-map} 292 \\{shell-mode-map}
268 Customization: Entry to this mode runs the hooks on `comint-mode-hook' and 293 Customization: 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
296 on `comint-output-sentinel-functions' are run.
271 297
272 Variables `shell-cd-regexp', `shell-pushd-regexp' and `shell-popd-regexp' 298 Variables `shell-cd-regexp', `shell-pushd-regexp' and `shell-popd-regexp'
273 are used to match their respective commands, while `shell-pushd-tohome', 299 are used to match their respective commands, while `shell-pushd-tohome',
274 `shell-pushd-dextract' and `shell-pushd-dunique' control the behavior of the 300 `shell-pushd-dextract' and `shell-pushd-dunique' control the behavior of the
275 relevant command. 301 relevant command.
280 the behavior of command name completion. 306 the behavior of command name completion.
281 307
282 Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control 308 Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control
283 the initialisation of the input ring history, and history expansion. 309 the initialisation of the input ring history, and history expansion.
284 310
285 Variables `comint-output-filter-functions', `comint-scroll-to-bottom-on-input', 311 Variables `comint-output-sentinel-functions', a hook, and
286 and `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'
287 cause the window to scroll to the end of the buffer." 313 control whether input and output cause the window to scroll to the end of the
314 buffer."
288 (interactive) 315 (interactive)
289 (comint-mode) 316 (comint-mode)
290 (setq major-mode 'shell-mode) 317 (setq major-mode 'shell-mode)
291 (setq mode-name "Shell") 318 (setq mode-name "Shell")
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)
301 (setq shell-dirstack nil) 326 (setq shell-dirstack nil)
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))))))
309 (setq comint-input-ring-file-name 334 (setq comint-input-ring-file-name
310 (or (getenv "HISTFILE") 335 (or (getenv "HISTFILE")
619 (format "[;&|]+[\\s ]*\\(%s\\)" shell-command-regexp) limit 'move arg) 644 (format "[;&|]+[\\s ]*\\(%s\\)" shell-command-regexp) limit 'move arg)
620 (progn (goto-char (match-beginning 1)) 645 (progn (goto-char (match-beginning 1))
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.
636 File names are assumed to contain `/'s or not be the first item in the command.
637
638 See 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.
647 This function is similar to `comint-dynamic-complete-filename', except that it 651 This function is similar to `comint-dynamic-complete-filename', except that it
648 searches `exec-path' (minus the trailing emacs library path) for completion 652 searches `exec-path' (minus the trailing emacs library path) for completion
649 candidates. Note that this may not be the same as the shell's idea of the 653 candidates. Note that this may not be the same as the shell's idea of the
650 path. 654 path.
651 655
652 Completion is dependent on the value of `shell-completion-execonly', plus 656 Completion is dependent on the value of `shell-completion-execonly', plus
653 those that effect file completion. See `comint-dynamic-complete-filename'." 657 those that effect file completion. See `shell-dynamic-complete-as-command'.
658
659 Returns 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.
672 See `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)))
660 (ignored-extensions 679 (ignored-extensions
661 (mapconcat (function (lambda (x) (concat (regexp-quote x) "$"))) 680 (mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
679 (setq completions (cons file completions))) 698 (setq completions (cons file completions)))
680 (setq comps-in-path (cdr comps-in-path))) 699 (setq comps-in-path (cdr comps-in-path)))
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"))))))
734 success))
735
736
737 (defun shell-match-partial-variable ()
738 "Return the variable at point, or nil if non is found."
739 (save-excursion
740 (let ((limit (point)))
741 (if (re-search-backward "[^A-Za-z0-9_{}]" nil 'move)
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))))))
748
749
750 (defun shell-dynamic-complete-environment-variable ()
751 "Dynamically complete the environment variable at point.
752 Completes if after a variable, i.e., if it starts with a \"$\".
753 See `shell-dynamic-complete-as-environment-variable'.
754
755 This function is similar to `comint-dynamic-complete-filename', except that it
756 searches `process-environment' for completion candidates. Note that this may
757 not be the same as the interpreter's idea of variable names. The main problem
758 with this type of completion is that `process-environment' is the environment
759 which Emacs started with. Emacs does not track changes to the environment made
760 by the interpreter. Perhaps it would be more accurate if this function was
761 called `shell-dynamic-complete-process-environment-variable'.
762
763 Returns 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.
773 Used by `shell-dynamic-complete-environment-variable'.
774 Uses `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.
799 Directory stack references are of the form \"=digit\" or \"=-\".
800 See `default-directory' and `shell-dirstack'.
801
802 Returns 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))))))
715 823
716 ;;; Do the user's customization...
717 ;;;
718 ;;; Isn't this what eval-after-load is for?
719 ;;;(defvar shell-load-hook nil
720 ;;; "This hook is run when shell is loaded in.
721 ;;;This is a good place to put keybindings.")
722 ;;;
723 ;;;(run-hooks 'shell-load-hook)
724
725 (provide 'shell) 824 (provide 'shell)
726 825
727 ;;; shell.el ends here 826 ;;; shell.el ends here