|
|
1.1 ! root 1: ;; Run subshell under Emacs ! 2: ;; Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: ;; This file is part of GNU Emacs. ! 5: ! 6: ;; GNU Emacs is free software; you can redistribute it and/or modify ! 7: ;; it under the terms of the GNU General Public License as published by ! 8: ;; the Free Software Foundation; either version 1, or (at your option) ! 9: ;; any later version. ! 10: ! 11: ;; GNU Emacs is distributed in the hope that it will be useful, ! 12: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: ;; GNU General Public License for more details. ! 15: ! 16: ;; You should have received a copy of the GNU General Public License ! 17: ;; along with GNU Emacs; see the file COPYING. If not, write to ! 18: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: ! 20: ! 21: (provide 'shell) ! 22: ! 23: (defvar last-input-start nil ! 24: "In a shell-mode buffer, marker for start of last unit of input.") ! 25: (defvar last-input-end nil ! 26: "In a shell-mode buffer, marker for end of last unit of input.") ! 27: ! 28: (defvar shell-mode-map nil) ! 29: ! 30: (defvar shell-directory-stack nil ! 31: "List of directories saved by pushd in this buffer's shell.") ! 32: ! 33: (defvar shell-popd-regexp "popd" ! 34: "*Regexp to match subshell commands equivalent to popd.") ! 35: ! 36: (defvar shell-pushd-regexp "pushd" ! 37: "*Regexp to match subshell commands equivalent to pushd.") ! 38: ! 39: (defvar shell-cd-regexp "cd" ! 40: "*Regexp to match subshell commands equivalent to cd.") ! 41: ! 42: (defvar explicit-shell-file-name nil ! 43: "*If non-nil, is file name to use for explicitly requested inferior shell.") ! 44: ! 45: ;In loaddefs.el now. ! 46: ;(defconst shell-prompt-pattern ! 47: ; "^[^#$%>]*[#$%>] *" ! 48: ; "*Regexp used by Newline command to match subshell prompts. ! 49: ;Anything from beginning of line up to the end of what this pattern matches ! 50: ;is deemed to be prompt, and is not reexecuted.") ! 51: ! 52: (defun shell-mode () ! 53: "Major mode for interacting with an inferior shell. ! 54: Shell name is same as buffer name, sans the asterisks. ! 55: Return at end of buffer sends line as input. ! 56: Return not at end copies rest of line to end and sends it. ! 57: ! 58: The following commands imitate the usual Unix interrupt and ! 59: editing control characters: ! 60: \\{shell-mode-map} ! 61: ! 62: Entry to this mode calls the value of shell-mode-hook with no args, ! 63: if that value is non-nil. ! 64: ! 65: cd, pushd and popd commands given to the shell are watched ! 66: by Emacs to keep this buffer's default directory ! 67: the same as the shell's working directory. ! 68: Variables shell-cd-regexp, shell-pushd-regexp and shell-popd-regexp ! 69: are used to match these command names. ! 70: ! 71: You can send text to the shell (or its subjobs) from other buffers ! 72: using the commands process-send-region, process-send-string ! 73: and lisp-send-defun." ! 74: (interactive) ! 75: (kill-all-local-variables) ! 76: (setq major-mode 'shell-mode) ! 77: (setq mode-name "Shell") ! 78: (setq mode-line-process '(": %s")) ! 79: (use-local-map shell-mode-map) ! 80: (make-local-variable 'shell-directory-stack) ! 81: (setq shell-directory-stack nil) ! 82: (make-local-variable 'last-input-start) ! 83: (setq last-input-start (make-marker)) ! 84: (make-local-variable 'last-input-end) ! 85: (setq last-input-end (make-marker)) ! 86: (run-hooks 'shell-mode-hook)) ! 87: ! 88: (if shell-mode-map ! 89: nil ! 90: (setq shell-mode-map (make-sparse-keymap)) ! 91: (define-key shell-mode-map "\C-m" 'shell-send-input) ! 92: (define-key shell-mode-map "\C-c\C-d" 'shell-send-eof) ! 93: (define-key shell-mode-map "\C-c\C-u" 'kill-shell-input) ! 94: (define-key shell-mode-map "\C-c\C-w" 'backward-kill-word) ! 95: (define-key shell-mode-map "\C-c\C-c" 'interrupt-shell-subjob) ! 96: (define-key shell-mode-map "\C-c\C-z" 'stop-shell-subjob) ! 97: (define-key shell-mode-map "\C-c\C-\\" 'quit-shell-subjob) ! 98: (define-key shell-mode-map "\C-c\C-o" 'kill-output-from-shell) ! 99: (define-key shell-mode-map "\C-c\C-r" 'show-output-from-shell) ! 100: (define-key shell-mode-map "\C-c\C-y" 'copy-last-shell-input)) ! 101: ! 102: (defvar explicit-csh-args ! 103: (if (eq system-type 'hpux) ! 104: ;; -T persuades HP's csh not to think it is smarter ! 105: ;; than us about what terminal modes to use. ! 106: '("-i" "-T") ! 107: '("-i")) ! 108: "Args passed to inferior shell by M-x shell, if the shell is csh. ! 109: Value is a list of strings, which may be nil.") ! 110: ! 111: (defun shell () ! 112: "Run an inferior shell, with I/O through buffer *shell*. ! 113: If buffer exists but shell process is not running, make new shell. ! 114: Program used comes from variable explicit-shell-file-name, ! 115: or (if that is nil) from the ESHELL environment variable, ! 116: or else from SHELL if there is no ESHELL. ! 117: If a file ~/.emacs_SHELLNAME exists, it is given as initial input ! 118: (Note that this may lose due to a timing error if the shell ! 119: discards input when it starts up.) ! 120: The buffer is put in shell-mode, giving commands for sending input ! 121: and controlling the subjobs of the shell. See shell-mode. ! 122: See also variable shell-prompt-pattern. ! 123: ! 124: The shell file name (sans directories) is used to make a symbol name ! 125: such as `explicit-csh-arguments'. If that symbol is a variable, ! 126: its value is used as a list of arguments when invoking the shell. ! 127: Otherwise, one argument `-i' is passed to the shell. ! 128: ! 129: Note that many people's .cshrc files unconditionally clear the prompt. ! 130: If yours does, you will probably want to change it." ! 131: (interactive) ! 132: (let* ((prog (or explicit-shell-file-name ! 133: (getenv "ESHELL") ! 134: (getenv "SHELL") ! 135: "/bin/sh")) ! 136: (name (file-name-nondirectory prog))) ! 137: (switch-to-buffer ! 138: (apply 'make-shell "shell" prog ! 139: (if (file-exists-p (concat "~/.emacs_" name)) ! 140: (concat "~/.emacs_" name)) ! 141: (let ((symbol (intern-soft (concat "explicit-" name "-args")))) ! 142: (if (and symbol (boundp symbol)) ! 143: (symbol-value symbol) ! 144: '("-i"))))))) ! 145: ! 146: (defun make-shell (name program &optional startfile &rest switches) ! 147: (let ((buffer (get-buffer-create (concat "*" name "*"))) ! 148: proc status size) ! 149: (setq proc (get-buffer-process buffer)) ! 150: (if proc (setq status (process-status proc))) ! 151: (save-excursion ! 152: (set-buffer buffer) ! 153: ;; (setq size (buffer-size)) ! 154: (if (memq status '(run stop)) ! 155: nil ! 156: (if proc (delete-process proc)) ! 157: (setq proc (apply 'start-process name buffer ! 158: (concat exec-directory "env") ! 159: (format "TERMCAP=emacs:co#%d:tc=unknown:" ! 160: (screen-width)) ! 161: "TERM=emacs" ! 162: "EMACS=t" ! 163: "-" ! 164: (or program explicit-shell-file-name ! 165: (getenv "ESHELL") ! 166: (getenv "SHELL") ! 167: "/bin/sh") ! 168: switches)) ! 169: (cond (startfile ! 170: ;;This is guaranteed to wait long enough ! 171: ;;but has bad results if the shell does not prompt at all ! 172: ;; (while (= size (buffer-size)) ! 173: ;; (sleep-for 1)) ! 174: ;;I hope 1 second is enough! ! 175: (sleep-for 1) ! 176: (goto-char (point-max)) ! 177: (insert-file-contents startfile) ! 178: (setq startfile (buffer-substring (point) (point-max))) ! 179: (delete-region (point) (point-max)) ! 180: (process-send-string proc startfile))) ! 181: (setq name (process-name proc))) ! 182: (goto-char (point-max)) ! 183: (set-marker (process-mark proc) (point)) ! 184: (or (eq major-mode 'shell-mode) (shell-mode))) ! 185: buffer)) ! 186: ! 187: (defvar shell-set-directory-error-hook 'ignore ! 188: "Function called with no arguments when shell-send-input ! 189: recognizes a change-directory command but gets an error ! 190: trying to change Emacs's default directory.") ! 191: ! 192: (defun shell-send-input () ! 193: "Send input to subshell. ! 194: At end of buffer, sends all text after last output ! 195: as input to the subshell, including a newline inserted at the end. ! 196: When not at end, copies current line to the end of the buffer and sends it, ! 197: after first attempting to discard any prompt at the beginning of the line ! 198: by matching the regexp that is the value of shell-prompt-pattern if possible. ! 199: This regexp should start with \"^\"." ! 200: (interactive) ! 201: (or (get-buffer-process (current-buffer)) ! 202: (error "Current buffer has no process")) ! 203: (end-of-line) ! 204: (if (eobp) ! 205: (progn ! 206: (move-marker last-input-start ! 207: (process-mark (get-buffer-process (current-buffer)))) ! 208: (insert ?\n) ! 209: (move-marker last-input-end (point))) ! 210: (beginning-of-line) ! 211: ;; Exclude the shell prompt, if any. ! 212: (re-search-forward shell-prompt-pattern ! 213: (save-excursion (end-of-line) (point)) ! 214: t) ! 215: (let ((copy (buffer-substring (point) ! 216: (progn (forward-line 1) (point))))) ! 217: (goto-char (point-max)) ! 218: (move-marker last-input-start (point)) ! 219: (insert copy) ! 220: (move-marker last-input-end (point)))) ! 221: ;; Even if we get an error trying to hack the working directory, ! 222: ;; still send the input to the subshell. ! 223: (condition-case () ! 224: (save-excursion ! 225: (goto-char last-input-start) ! 226: (shell-set-directory)) ! 227: (error (funcall shell-set-directory-error-hook))) ! 228: (let ((process (get-buffer-process (current-buffer)))) ! 229: (process-send-region process last-input-start last-input-end) ! 230: (set-marker (process-mark process) (point)))) ! 231: ! 232: ;;; If this code changes (shell-send-input and shell-set-directory), ! 233: ;;; the customization tutorial in ! 234: ;;; info/customizing-tutorial must also change, since it explains this ! 235: ;;; code. Please let [email protected] know of any changes you ! 236: ;;; make. ! 237: ! 238: (defun shell-set-directory () ! 239: (cond ((and (looking-at shell-popd-regexp) ! 240: (memq (char-after (match-end 0)) '(?\; ?\n))) ! 241: (if shell-directory-stack ! 242: (progn ! 243: (cd (car shell-directory-stack)) ! 244: (setq shell-directory-stack (cdr shell-directory-stack))))) ! 245: ((looking-at shell-pushd-regexp) ! 246: (cond ((memq (char-after (match-end 0)) '(?\; ?\n)) ! 247: (if shell-directory-stack ! 248: (let ((old default-directory)) ! 249: (cd (car shell-directory-stack)) ! 250: (setq shell-directory-stack ! 251: (cons old (cdr shell-directory-stack)))))) ! 252: ((memq (char-after (match-end 0)) '(?\ ?\t)) ! 253: (let (dir) ! 254: (skip-chars-forward "^ ") ! 255: (skip-chars-forward " \t") ! 256: (if (file-directory-p ! 257: (setq dir ! 258: (expand-file-name ! 259: (substitute-in-file-name ! 260: (buffer-substring ! 261: (point) ! 262: (progn ! 263: (skip-chars-forward "^\n \t;") ! 264: (point))))))) ! 265: (progn ! 266: (setq shell-directory-stack ! 267: (cons default-directory shell-directory-stack)) ! 268: (cd dir))))))) ! 269: ((looking-at shell-cd-regexp) ! 270: (cond ((memq (char-after (match-end 0)) '(?\; ?\n)) ! 271: (cd (getenv "HOME"))) ! 272: ((memq (char-after (match-end 0)) '(?\ ?\t)) ! 273: (let (dir) ! 274: (forward-char 3) ! 275: (skip-chars-forward " \t") ! 276: (if (file-directory-p ! 277: (setq dir ! 278: (expand-file-name ! 279: (substitute-in-file-name ! 280: (buffer-substring ! 281: (point) ! 282: (progn ! 283: (skip-chars-forward "^\n \t;") ! 284: (point))))))) ! 285: (cd dir)))))))) ! 286: ! 287: (defun shell-send-eof () ! 288: "Send eof to subshell (or to the program running under it)." ! 289: (interactive) ! 290: (process-send-eof)) ! 291: ! 292: (defun kill-output-from-shell () ! 293: "Kill all output from shell since last input." ! 294: (interactive) ! 295: (goto-char (point-max)) ! 296: (beginning-of-line) ! 297: (kill-region last-input-end (point)) ! 298: (insert "*** output flushed ***\n") ! 299: (goto-char (point-max))) ! 300: ! 301: (defun show-output-from-shell () ! 302: "Display start of this batch of shell output at top of window. ! 303: Also put cursor there." ! 304: (interactive) ! 305: (set-window-start (selected-window) last-input-end) ! 306: (goto-char last-input-end)) ! 307: ! 308: (defun copy-last-shell-input () ! 309: "Copy previous shell input, sans newline, and insert before point." ! 310: (interactive) ! 311: (insert (buffer-substring last-input-end last-input-start)) ! 312: (delete-char -1)) ! 313: ! 314: (defun interrupt-shell-subjob () ! 315: "Interrupt this shell's current subjob." ! 316: (interactive) ! 317: (interrupt-process nil t)) ! 318: ! 319: (defun kill-shell-subjob () ! 320: "Send kill signal to this shell's current subjob." ! 321: (interactive) ! 322: (kill-process nil t)) ! 323: ! 324: (defun quit-shell-subjob () ! 325: "Send quit signal to this shell's current subjob." ! 326: (interactive) ! 327: (quit-process nil t)) ! 328: ! 329: (defun stop-shell-subjob () ! 330: "Stop this shell's current subjob." ! 331: (interactive) ! 332: (stop-process nil t)) ! 333: ! 334: (defun kill-shell-input () ! 335: "Kill all text since last stuff output by the shell or its subjobs." ! 336: (interactive) ! 337: (kill-region (process-mark (get-buffer-process (current-buffer))) ! 338: (point))) ! 339: ! 340: (defvar inferior-lisp-mode-map nil) ! 341: (if inferior-lisp-mode-map ! 342: nil ! 343: (setq inferior-lisp-mode-map (copy-alist shell-mode-map)) ! 344: (lisp-mode-commands inferior-lisp-mode-map) ! 345: (define-key inferior-lisp-mode-map "\e\C-x" 'lisp-send-defun)) ! 346: ! 347: (defvar inferior-lisp-program "lisp" ! 348: "*Program name for invoking an inferior Lisp with `run-lisp'.") ! 349: ! 350: (defvar inferior-lisp-load-command "(load \"%s\")\n" ! 351: "*Format-string for building a Lisp expression to load a file. ! 352: This format string should use %s to substitute a file name ! 353: and should result in a Lisp expression that will command the inferior Lisp ! 354: to load that file. The default works acceptably on most Lisps. ! 355: The string \"(progn (load \\\"%s\\\" :verbose nil :print t) (values))\\\n\" ! 356: produces cosmetically superior output for this application, ! 357: but it works only in Common Lisp.") ! 358: ! 359: (defvar inferior-lisp-prompt "^.*>:? *$" ! 360: "*Regexp to recognize prompts from the inferior Lisp. ! 361: Default is right for Franz Lisp and kcl.") ! 362: ! 363: (defun inferior-lisp-mode () ! 364: "Major mode for interacting with an inferior Lisp process. ! 365: Runs a Lisp interpreter as a subprocess of Emacs, with Lisp I/O ! 366: through an Emacs buffer. Variable inferior-lisp-program controls ! 367: which Lisp interpreter is run. Variables inferior-lisp-prompt ! 368: and inferior-lisp-load-command can customize this mode for different ! 369: Lisp interpreters. ! 370: ! 371: Commands: ! 372: DELETE converts tabs to spaces as it moves back. ! 373: TAB indents for Lisp; with argument, shifts rest ! 374: of expression rigidly with the current line. ! 375: Meta-Control-Q does TAB on each line starting within following expression. ! 376: Paragraphs are separated only by blank lines. Semicolons start comments. ! 377: ! 378: Return at end of buffer sends line as input. ! 379: Return not at end copies rest of line to end and sends it. ! 380: ! 381: The following commands imitate the usual Unix interrupt and ! 382: editing control characters: ! 383: \\{shell-mode-map} ! 384: ! 385: Entry to this mode calls the value of lisp-mode-hook with no arguments, ! 386: if that value is non-nil. Likewise with the value of shell-mode-hook. ! 387: lisp-mode-hook is called after shell-mode-hook. ! 388: ! 389: You can send text to the inferior Lisp from other buffers ! 390: using the commands process-send-region, process-send-string ! 391: and \\[lisp-send-defun]." ! 392: (interactive) ! 393: (kill-all-local-variables) ! 394: (setq major-mode 'inferior-lisp-mode) ! 395: (setq mode-name "Inferior Lisp") ! 396: (setq mode-line-process '(": %s")) ! 397: (lisp-mode-variables t) ! 398: (use-local-map inferior-lisp-mode-map) ! 399: (make-local-variable 'last-input-start) ! 400: (setq last-input-start (make-marker)) ! 401: (make-local-variable 'last-input-end) ! 402: (setq last-input-end (make-marker)) ! 403: (run-hooks 'shell-mode-hook 'lisp-mode-hook)) ! 404: ! 405: (defun run-lisp () ! 406: "Run an inferior Lisp process, input and output via buffer *lisp*." ! 407: (interactive) ! 408: (switch-to-buffer (make-shell "lisp" inferior-lisp-program)) ! 409: (inferior-lisp-mode)) ! 410: ! 411: (defun lisp-send-defun (display-flag) ! 412: "Send the current defun to the Lisp process made by M-x run-lisp. ! 413: With argument, force redisplay and scrolling of the *lisp* buffer. ! 414: Variable `inferior-lisp-load-command' controls formatting of ! 415: the `load' form that is set to the Lisp process." ! 416: (interactive "P") ! 417: (or (get-process "lisp") ! 418: (error "No current lisp process")) ! 419: (save-excursion ! 420: (end-of-defun) ! 421: (let ((end (point)) ! 422: (filename (format "/tmp/emlisp%d" (process-id (get-process "lisp"))))) ! 423: (beginning-of-defun) ! 424: (write-region (point) end filename nil 'nomessage) ! 425: (process-send-string "lisp" (format inferior-lisp-load-command filename))) ! 426: (if display-flag ! 427: (let* ((process (get-process "lisp")) ! 428: (buffer (process-buffer process)) ! 429: (w (or (get-buffer-window buffer) (display-buffer buffer))) ! 430: (height (window-height w)) ! 431: (end)) ! 432: (save-excursion ! 433: (set-buffer buffer) ! 434: (setq end (point-max)) ! 435: (while (progn ! 436: (accept-process-output process) ! 437: (goto-char (point-max)) ! 438: (beginning-of-line) ! 439: (or (= (point-max) end) ! 440: (not (looking-at inferior-lisp-prompt))))) ! 441: (setq end (point-max)) ! 442: (vertical-motion (- 4 height)) ! 443: (set-window-start w (point))) ! 444: (set-window-point w end))))) ! 445: ! 446: (defun lisp-send-defun-and-go () ! 447: "Send the current defun to the inferior Lisp, and switch to *lisp* buffer." ! 448: (interactive) ! 449: (lisp-send-defun nil) ! 450: (switch-to-buffer "*lisp*"))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.