diff options
Diffstat (limited to 'lisp/shell.el')
-rw-r--r-- | lisp/shell.el | 82 |
1 files changed, 58 insertions, 24 deletions
diff --git a/lisp/shell.el b/lisp/shell.el index 100bbc40376..57cc11f9d4f 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -70,7 +70,7 @@ ;; c-c c-c comint-interrupt-subjob ^c ;; c-c c-z comint-stop-subjob ^z ;; c-c c-\ comint-quit-subjob ^\ -;; c-c c-o comint-kill-output Delete last batch of process output +;; c-c c-o comint-delete-output Delete last batch of process output ;; c-c c-r comint-show-output Show last batch of process output ;; c-c c-l comint-dynamic-list-input-ring List input history ;; send-invisible Read line w/o echo & send to proc @@ -334,25 +334,25 @@ Thus, this does not include the shell's current directory.") (defvar shell-dirstack-query nil "Command used by `shell-resync-dirs' to query the shell.") -(defvar shell-mode-map nil) -(cond ((not shell-mode-map) - (setq shell-mode-map (nconc (make-sparse-keymap) comint-mode-map)) - (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command) - (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command) - (define-key shell-mode-map "\t" 'comint-dynamic-complete) - (define-key shell-mode-map "\M-?" - 'comint-dynamic-list-filename-completions) - (define-key shell-mode-map [menu-bar completion] - (cons "Complete" - (copy-keymap (lookup-key comint-mode-map [menu-bar completion])))) - (define-key-after (lookup-key shell-mode-map [menu-bar completion]) - [complete-env-variable] '("Complete Env. Variable Name" . - shell-dynamic-complete-environment-variable) - 'complete-file) - (define-key-after (lookup-key shell-mode-map [menu-bar completion]) - [expand-directory] '("Expand Directory Reference" . - shell-replace-by-expanded-directory) - 'complete-expand))) +(defvar shell-mode-map + (let ((map (nconc (make-sparse-keymap) comint-mode-map))) + (define-key map "\C-c\C-f" 'shell-forward-command) + (define-key map "\C-c\C-b" 'shell-backward-command) + (define-key map "\t" 'comint-dynamic-complete) + (define-key map (kbd "M-RET") 'shell-resync-dirs) + (define-key map "\M-?" 'comint-dynamic-list-filename-completions) + (define-key map [menu-bar completion] + (cons "Complete" + (copy-keymap (lookup-key comint-mode-map [menu-bar completion])))) + (define-key-after (lookup-key map [menu-bar completion]) + [complete-env-variable] '("Complete Env. Variable Name" . + shell-dynamic-complete-environment-variable) + 'complete-file) + (define-key-after (lookup-key map [menu-bar completion]) + [expand-directory] '("Expand Directory Reference" . + shell-replace-by-expanded-directory) + 'complete-expand) + map)) (defcustom shell-mode-hook '() "Hook for customizing Shell mode." @@ -367,6 +367,17 @@ Thus, this does not include the shell's current directory.") ;;; Basic Procedures +(defcustom shell-dir-cookie-re nil + "Regexp matching your prompt, including some part of the current directory. +If your prompt includes the current directory or the last few elements of it, +set this to a pattern that matches your prompt and whose subgroup 1 matches +the directory part of it. +This is used by `shell-dir-cookie-watcher' to try and use this info +to track your current directory. It can be used instead of or in addition +to `dirtrack-mode'." + :group 'shell + :type '(choice (const nil) regexp)) + (put 'shell-mode 'mode-class 'special) (define-derived-mode shell-mode comint-mode "Shell" @@ -471,6 +482,10 @@ buffer." (when (string-equal shell "bash") (add-hook 'comint-output-filter-functions 'shell-filter-ctrl-a-ctrl-b nil t))) + (when shell-dir-cookie-re + ;; Watch for magic cookies in the output to track the current dir. + (add-hook 'comint-output-filter-functions + 'shell-dir-cookie-watcher nil t)) (comint-read-input-ring t))) (defun shell-filter-ctrl-a-ctrl-b (string) @@ -549,13 +564,19 @@ Otherwise, one argument `-i' is passed to the shell. (generate-new-buffer-name "*shell*")) (if (file-remote-p default-directory) ;; It must be possible to declare a local default-directory. + ;; FIXME: This can't be right: it changes the default-directory + ;; of the current-buffer rather than of the *shell* buffer. (setq default-directory (expand-file-name (read-file-name "Default directory: " default-directory default-directory t nil 'file-directory-p)))))))) (require 'ansi-color) - (setq buffer (get-buffer-create (or buffer "*shell*"))) + (setq buffer (if (or buffer (not (derived-mode-p 'shell-mode)) + (comint-check-proc (current-buffer))) + (get-buffer-create (or buffer "*shell*")) + ;; If the current buffer is a dead shell buffer, use it. + (current-buffer))) ;; Pop to buffer, so that the buffer's window will be correctly set ;; when we call comint (so that comint sets the COLUMNS env var properly). (pop-to-buffer buffer) @@ -618,6 +639,20 @@ Otherwise, one argument `-i' is passed to the shell. ;; replace it with a process filter that watches for and strips out ;; these messages. +(defun shell-dir-cookie-watcher (text) + ;; This is fragile: the TEXT could be split into several chunks and we'd + ;; miss it. Oh well. It's a best effort anyway. I'd expect that it's + ;; rather unusual to have the prompt split into several packets, but + ;; I'm sure Murphy will prove me wrong. + (when (and shell-dir-cookie-re (string-match shell-dir-cookie-re text)) + (let ((dir (match-string 1 text))) + (cond + ((file-name-absolute-p dir) (shell-cd dir)) + ;; Let's try and see if it seems to be up or down from where we were. + ((string-match "\\`\\(.*\\)\\(?:/.*\\)?\n\\(.*/\\)\\1\\(?:/.*\\)?\\'" + (setq text (concat dir "\n" default-directory))) + (shell-cd (concat (match-string 2 text) dir))))))) + (defun shell-directory-tracker (str) "Tracks cd, pushd and popd commands issued to the shell. This function is called on each input passed to the shell. @@ -700,7 +735,7 @@ Environment variables are expanded, see function `substitute-in-file-name'." (defun shell-process-popd (arg) (let ((num (or (shell-extract-num arg) 0))) (cond ((and num (= num 0) shell-dirstack) - (shell-cd (car shell-dirstack)) + (shell-cd (shell-prefixed-directory-name (car shell-dirstack))) (setq shell-dirstack (cdr shell-dirstack)) (shell-dirstack-message)) ((and num (> num 0) (<= num (length shell-dirstack))) @@ -928,7 +963,7 @@ Copy Shell environment variable to Emacs: "))) "Move forward across ARG shell command(s). Does not cross lines. See `shell-command-regexp'." (interactive "p") - (let ((limit (save-excursion (end-of-line nil) (point)))) + (let ((limit (line-end-position))) (if (re-search-forward (concat shell-command-regexp "\\([;&|][\t ]*\\)+") limit 'move arg) (skip-syntax-backward " ")))) @@ -1111,5 +1146,4 @@ Returns t if successful." (provide 'shell) -;; arch-tag: bcb5f12a-c1f4-4aea-a809-2504bd5bd797 ;;; shell.el ends here |