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