root/trunk/lisp/eshell/em-term.el
| Revision 4220, 10.8 kB (checked in by miyoshi, 9 months ago) | |
|---|---|
| |
| Line | |
|---|---|
| 1 | ;;; em-term.el --- running visual commands |
| 2 | |
| 3 | ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, |
| 4 | ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc. |
| 5 | |
| 6 | ;; Author: John Wiegley <johnw@gnu.org> |
| 7 | |
| 8 | ;; This file is part of GNU Emacs. |
| 9 | |
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
| 11 | ;; it under the terms of the GNU General Public License as published by |
| 12 | ;; the Free Software Foundation; either version 3, or (at your option) |
| 13 | ;; any later version. |
| 14 | |
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | ;; GNU General Public License for more details. |
| 19 | |
| 20 | ;; You should have received a copy of the GNU General Public License |
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
| 22 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 23 | ;; Boston, MA 02110-1301, USA. |
| 24 | |
| 25 | (provide 'em-term) |
| 26 | |
| 27 | (eval-when-compile (require 'esh-maint)) |
| 28 | |
| 29 | (defgroup eshell-term nil |
| 30 | "This module causes visual commands (e.g., 'vi') to be executed by |
| 31 | the `term' package, which comes with Emacs. This package handles most |
| 32 | of the ANSI control codes, allowing curses-based applications to run |
| 33 | within an Emacs window. The variable `eshell-visual-commands' defines |
| 34 | which commands are considered visual in nature." |
| 35 | :tag "Running visual commands" |
| 36 | :group 'eshell-module) |
| 37 | |
| 38 | ;;; Commentary: |
| 39 | |
| 40 | ;; At the moment, eshell is stream-based in its interactive input and |
| 41 | ;; output. This means that full-screen commands, such as "vi" or |
| 42 | ;; "lynx", will not display correctly. These are therefore thought of |
| 43 | ;; as "visual" programs. In order to run these progrem under Emacs, |
| 44 | ;; Eshell uses the term.el package, and invokes them in a separate |
| 45 | ;; buffer, giving the illusion that Eshell itself is allowing these |
| 46 | ;; visual processes to execute. |
| 47 | |
| 48 | (require 'term) |
| 49 | |
| 50 | ;;; User Variables: |
| 51 | |
| 52 | (defcustom eshell-term-load-hook '(eshell-term-initialize) |
| 53 | "*A list of functions to call when loading `eshell-term'." |
| 54 | :type 'hook |
| 55 | :group 'eshell-term) |
| 56 | |
| 57 | (defcustom eshell-visual-commands |
| 58 | '("vi" ; what is going on?? |
| 59 | "screen" "top" ; ok, a valid program... |
| 60 | "less" "more" ; M-x view-file |
| 61 | "lynx" "ncftp" ; w3.el, ange-ftp |
| 62 | "pine" "tin" "trn" "elm") ; GNUS!! |
| 63 | "*A list of commands that present their output in a visual fashion." |
| 64 | :type '(repeat string) |
| 65 | :group 'eshell-term) |
| 66 | |
| 67 | (defcustom eshell-term-name "eterm" |
| 68 | "*Name to use for the TERM variable when running visual commands. |
| 69 | See `term-term-name' in term.el for more information on how this is |
| 70 | used." |
| 71 | :type 'string |
| 72 | :group 'eshell-term) |
| 73 | |
| 74 | (defcustom eshell-escape-control-x t |
| 75 | "*If non-nil, allow <C-x> to be handled by Emacs key in visual buffers. |
| 76 | See the variable `eshell-visual-commands'. If this variable is set to |
| 77 | nil, <C-x> will send that control character to the invoked process." |
| 78 | :type 'boolean |
| 79 | :group 'eshell-term) |
| 80 | |
| 81 | ;;; Internal Variables: |
| 82 | |
| 83 | (defvar eshell-parent-buffer) |
| 84 | |
| 85 | ;;; Functions: |
| 86 | |
| 87 | (defun eshell-term-initialize () |
| 88 | "Initialize the `term' interface code." |
| 89 | (make-local-variable 'eshell-interpreter-alist) |
| 90 | (setq eshell-interpreter-alist |
| 91 | (cons (cons (function |
| 92 | (lambda (command) |
| 93 | (member (file-name-nondirectory command) |
| 94 | eshell-visual-commands))) |
| 95 | 'eshell-exec-visual) |
| 96 | eshell-interpreter-alist))) |
| 97 | |
| 98 | (defun eshell-exec-visual (&rest args) |
| 99 | "Run the specified PROGRAM in a terminal emulation buffer. |
| 100 | ARGS are passed to the program. At the moment, no piping of input is |
| 101 | allowed." |
| 102 | (let* (eshell-interpreter-alist |
| 103 | (interp (eshell-find-interpreter (car args))) |
| 104 | (program (car interp)) |
| 105 | (args (eshell-flatten-list |
| 106 | (eshell-stringify-list (append (cdr interp) |
| 107 | (cdr args))))) |
| 108 | (term-buf |
| 109 | (generate-new-buffer |
| 110 | (concat "*" (file-name-nondirectory program) "*"))) |
| 111 | (eshell-buf (current-buffer))) |
| 112 | (save-current-buffer |
| 113 | (switch-to-buffer term-buf) |
| 114 | (term-mode) |
| 115 | (set (make-local-variable 'term-term-name) eshell-term-name) |
| 116 | (make-local-variable 'eshell-parent-buffer) |
| 117 | (setq eshell-parent-buffer eshell-buf) |
| 118 | (term-exec term-buf program program nil args) |
| 119 | (let ((proc (get-buffer-process term-buf))) |
| 120 | (if (and proc (eq 'run (process-status proc))) |
| 121 | (set-process-sentinel proc 'eshell-term-sentinel) |
| 122 | (error "Failed to invoke visual command"))) |
| 123 | (term-char-mode) |
| 124 | (if eshell-escape-control-x |
| 125 | (term-set-escape-char ?\C-x)))) |
| 126 | nil) |
| 127 | |
| 128 | (defun eshell-term-sentinel (proc string) |
| 129 | "Destroy the buffer visiting PROC." |
| 130 | (let ((proc-buf (process-buffer proc))) |
| 131 | (when (and proc-buf (buffer-live-p proc-buf) |
| 132 | (not (eq 'run (process-status proc))) |
| 133 | (= (process-exit-status proc) 0)) |
| 134 | (if (eq (current-buffer) proc-buf) |
| 135 | (let ((buf (and (boundp 'eshell-parent-buffer) |
| 136 | eshell-parent-buffer |
| 137 | (buffer-live-p eshell-parent-buffer) |
| 138 | eshell-parent-buffer))) |
| 139 | (if buf |
| 140 | (switch-to-buffer buf)))) |
| 141 | (kill-buffer proc-buf)))) |
| 142 | |
| 143 | ;; jww (1999-09-17): The code below will allow Eshell to send input |
| 144 | ;; characters directly to the currently running interactive process. |
| 145 | ;; However, since this would introduce other problems that would need |
| 146 | ;; solutions, I'm going to let it wait until after 2.1. |
| 147 | |
| 148 | ; (defvar eshell-term-raw-map nil |
| 149 | ; "Keyboard map for sending characters directly to the inferior process.") |
| 150 | ; (defvar eshell-term-escape-char nil |
| 151 | ; "Escape character for char-sub-mode of term mode. |
| 152 | ; Do not change it directly; use term-set-escape-char instead.") |
| 153 | ; (defvar eshell-term-raw-escape-map nil) |
| 154 | |
| 155 | ; (defun eshell-term-send-raw-string (chars) |
| 156 | ; (goto-char eshell-last-output-end) |
| 157 | ; (process-send-string (eshell-interactive-process) chars)) |
| 158 | |
| 159 | ; (defun eshell-term-send-raw () |
| 160 | ; "Send the last character typed through the terminal-emulator |
| 161 | ; without any interpretation." |
| 162 | ; (interactive) |
| 163 | ; ;; Convert `return' to C-m, etc. |
| 164 | ; (if (and (symbolp last-input-char) |
| 165 | ; (get last-input-char 'ascii-character)) |
| 166 | ; (setq last-input-char (get last-input-char 'ascii-character))) |
| 167 | ; (eshell-term-send-raw-string (make-string 1 last-input-char))) |
| 168 | |
| 169 | ; (defun eshell-term-send-raw-meta () |
| 170 | ; (interactive) |
| 171 | ; (if (symbolp last-input-char) |
| 172 | ; ;; Convert `return' to C-m, etc. |
| 173 | ; (let ((tmp (get last-input-char 'event-symbol-elements))) |
| 174 | ; (if tmp |
| 175 | ; (setq last-input-char (car tmp))) |
| 176 | ; (if (symbolp last-input-char) |
| 177 | ; (progn |
| 178 | ; (setq tmp (get last-input-char 'ascii-character)) |
| 179 | ; (if tmp (setq last-input-char tmp)))))) |
| 180 | ; (eshell-term-send-raw-string (if (and (numberp last-input-char) |
| 181 | ; (> last-input-char 127) |
| 182 | ; (< last-input-char 256)) |
| 183 | ; (make-string 1 last-input-char) |
| 184 | ; (format "\e%c" last-input-char)))) |
| 185 | |
| 186 | ; (defun eshell-term-mouse-paste (click arg) |
| 187 | ; "Insert the last stretch of killed text at the position clicked on." |
| 188 | ; (interactive "e\nP") |
| 189 | ; (if (boundp 'xemacs-logo) |
| 190 | ; (eshell-term-send-raw-string |
| 191 | ; (or (condition-case () (x-get-selection) (error ())) |
| 192 | ; (x-get-cutbuffer) |
| 193 | ; (error "No selection or cut buffer available"))) |
| 194 | ; ;; Give temporary modes such as isearch a chance to turn off. |
| 195 | ; (run-hooks 'mouse-leave-buffer-hook) |
| 196 | ; (setq this-command 'yank) |
| 197 | ; (eshell-term-send-raw-string |
| 198 | ; (current-kill (cond ((listp arg) 0) |
| 199 | ; ((eq arg '-) -1) |
| 200 | ; (t (1- arg))))))) |
| 201 | |
| 202 | ; ;; Which would be better: "\e[A" or "\eOA"? readline accepts either. |
| 203 | ; ;; For my configuration it's definitely better \eOA but YMMV. -mm |
| 204 | ; ;; For example: vi works with \eOA while elm wants \e[A ... |
| 205 | ; (defun eshell-term-send-up () (interactive) (eshell-term-send-raw-string "\eOA")) |
| 206 | ; (defun eshell-term-send-down () (interactive) (eshell-term-send-raw-string "\eOB")) |
| 207 | ; (defun eshell-term-send-right () (interactive) (eshell-term-send-raw-string "\eOC")) |
| 208 | ; (defun eshell-term-send-left () (interactive) (eshell-term-send-raw-string "\eOD")) |
| 209 | ; (defun eshell-term-send-home () (interactive) (eshell-term-send-raw-string "\e[1~")) |
| 210 | ; (defun eshell-term-send-end () (interactive) (eshell-term-send-raw-string "\e[4~")) |
| 211 | ; (defun eshell-term-send-prior () (interactive) (eshell-term-send-raw-string "\e[5~")) |
| 212 | ; (defun eshell-term-send-next () (interactive) (eshell-term-send-raw-string "\e[6~")) |
| 213 | ; (defun eshell-term-send-del () (interactive) (eshell-term-send-raw-string "\C-?")) |
| 214 | ; (defun eshell-term-send-backspace () (interactive) (eshell-term-send-raw-string "\C-H")) |
| 215 | |
| 216 | ; (defun eshell-term-set-escape-char (c) |
| 217 | ; "Change term-escape-char and keymaps that depend on it." |
| 218 | ; (if eshell-term-escape-char |
| 219 | ; (define-key eshell-term-raw-map eshell-term-escape-char 'eshell-term-send-raw)) |
| 220 | ; (setq c (make-string 1 c)) |
| 221 | ; (define-key eshell-term-raw-map c eshell-term-raw-escape-map) |
| 222 | ; ;; Define standard bindings in eshell-term-raw-escape-map |
| 223 | ; (define-key eshell-term-raw-escape-map "\C-x" |
| 224 | ; (lookup-key (current-global-map) "\C-x")) |
| 225 | ; (define-key eshell-term-raw-escape-map "\C-v" |
| 226 | ; (lookup-key (current-global-map) "\C-v")) |
| 227 | ; (define-key eshell-term-raw-escape-map "\C-u" |
| 228 | ; (lookup-key (current-global-map) "\C-u")) |
| 229 | ; (define-key eshell-term-raw-escape-map c 'eshell-term-send-raw)) |
| 230 | |
| 231 | ; (defun eshell-term-char-mode () |
| 232 | ; "Switch to char (\"raw\") sub-mode of term mode. |
| 233 | ; Each character you type is sent directly to the inferior without |
| 234 | ; intervention from Emacs, except for the escape character (usually C-c)." |
| 235 | ; (interactive) |
| 236 | ; (if (not eshell-term-raw-map) |
| 237 | ; (let* ((map (make-keymap)) |
| 238 | ; (esc-map (make-keymap)) |
| 239 | ; (i 0)) |
| 240 | ; (while (< i 128) |
| 241 | ; (define-key map (make-string 1 i) 'eshell-term-send-raw) |
| 242 | ; (define-key esc-map (make-string 1 i) 'eshell-term-send-raw-meta) |
| 243 | ; (setq i (1+ i))) |
| 244 | ; (define-key map "\e" esc-map) |
| 245 | ; (setq eshell-term-raw-map map) |
| 246 | ; (setq eshell-term-raw-escape-map |
| 247 | ; (copy-keymap (lookup-key (current-global-map) "\C-x"))) |
| 248 | ; (if (boundp 'xemacs-logo) |
| 249 | ; (define-key eshell-term-raw-map [button2] 'eshell-term-mouse-paste) |
| 250 | ; (define-key eshell-term-raw-map [mouse-2] 'eshell-term-mouse-paste)) |
| 251 | ; (define-key eshell-term-raw-map [up] 'eshell-term-send-up) |
| 252 | ; (define-key eshell-term-raw-map [down] 'eshell-term-send-down) |
| 253 | ; (define-key eshell-term-raw-map [right] 'eshell-term-send-right) |
| 254 | ; (define-key eshell-term-raw-map [left] 'eshell-term-send-left) |
| 255 | ; (define-key eshell-term-raw-map [delete] 'eshell-term-send-del) |
| 256 | ; (define-key eshell-term-raw-map [backspace] 'eshell-term-send-backspace) |
| 257 | ; (define-key eshell-term-raw-map [home] 'eshell-term-send-home) |
| 258 | ; (define-key eshell-term-raw-map [end] 'eshell-term-send-end) |
| 259 | ; (define-key eshell-term-raw-map [prior] 'eshell-term-send-prior) |
| 260 | ; (define-key eshell-term-raw-map [next] 'eshell-term-send-next) |
| 261 | ; (eshell-term-set-escape-char ?\C-c)))) |
| 262 | |
| 263 | ; (defun eshell-term-line-mode () |
| 264 | ; "Switch to line (\"cooked\") sub-mode of eshell-term mode." |
| 265 | ; (use-local-map term-old-mode-map)) |
| 266 | |
| 267 | ;;; Code: |
| 268 | |
| 269 | ;;; arch-tag: ab7c8fe4-3101-4257-925b-1354c6b2fe9d |
| 270 | ;;; em-term.el ends here |
| 271 |
Note: See TracBrowser for help on using the browser.
