Mercurial > emacs
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 |