-;;; em-term.el --- running visual commands
+;;; em-term.el --- running visual commands -*- lexical-binding:t -*-
-;; Copyright (C) 1999-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2015 Free Software Foundation, Inc.
;; Author: John Wiegley <johnw@gnu.org>
;;; Code:
+(require 'cl-lib)
(require 'esh-util)
(require 'esh-ext)
(eval-when-compile (require 'eshell))
"less" "more" ; M-x view-file
"lynx" "ncftp" ; w3.el, ange-ftp
"pine" "tin" "trn" "elm") ; GNUS!!
- "A list of commands that present their output in a visual fashion."
+ "A list of commands that present their output in a visual fashion.
+
+Commands listed here are run in a term buffer.
+
+See also `eshell-visual-subcommands' and `eshell-visual-options'."
:type '(repeat string)
:group 'eshell-term)
+(defcustom eshell-visual-subcommands
+ nil
+ "An alist of subcommands that present their output in a visual fashion.
+
+An alist of the form
+
+ ((COMMAND1 SUBCOMMAND1 SUBCOMMAND2...)
+ (COMMAND2 SUBCOMMAND1 ...))
+
+of commands with subcommands that present their output in a
+visual fashion. A likely entry is
+
+ (\"git\" \"log\" \"diff\" \"show\")
+
+because git shows logs and diffs using a pager by default.
+
+See also `eshell-visual-commands' and `eshell-visual-options'."
+ :type '(repeat (cons (string :tag "Command")
+ (repeat (string :tag "Subcommand"))))
+ :version "24.4"
+ :group 'eshell-term)
+
+(defcustom eshell-visual-options
+ nil
+ "An alist of the form
+
+ ((COMMAND1 OPTION1 OPTION2...)
+ (COMMAND2 OPTION1 ...))
+
+of commands with options that present their output in a visual
+fashion. For example, a sensible entry would be
+
+ (\"git\" \"--help\")
+
+because \"git <command> --help\" shows the command's
+documentation with a pager.
+
+See also `eshell-visual-commands' and `eshell-visual-subcommands'."
+ :type '(repeat (cons (string :tag "Command")
+ (repeat (string :tag "Option"))))
+ :version "24.4"
+ :group 'eshell-term)
+
;; If you change this from term-term-name, you need to ensure that the
;; value you choose exists in the system's terminfo database. (Bug#12485)
(defcustom eshell-term-name term-term-name
(defcustom eshell-escape-control-x t
"If non-nil, allow <C-x> to be handled by Emacs key in visual buffers.
-See the variable `eshell-visual-commands'. If this variable is set to
-nil, <C-x> will send that control character to the invoked process."
+See the variables `eshell-visual-commands',
+`eshell-visual-subcommands', and `eshell-visual-options'. If
+this variable is set to nil, <C-x> will send that control
+character to the invoked process."
+ :type 'boolean
+ :group 'eshell-term)
+
+(defcustom eshell-destroy-buffer-when-process-dies nil
+ "If non-nil, term buffers are destroyed after their processes die.
+WARNING: Setting this to non-nil may result in unexpected
+behavior for short-lived processes, see bug#18108."
:type 'boolean
:group 'eshell-term)
"Initialize the `term' interface code."
(make-local-variable 'eshell-interpreter-alist)
(setq eshell-interpreter-alist
- (cons (cons (function
- (lambda (command)
- (member (file-name-nondirectory command)
- eshell-visual-commands)))
+ (cons (cons #'eshell-visual-command-p
'eshell-exec-visual)
eshell-interpreter-alist)))
+(defun eshell-visual-command-p (command args)
+ "Returns non-nil when given a visual command.
+If either COMMAND or a subcommand in ARGS (e.g. git log) is a
+visual command, returns non-nil."
+ (let ((command (file-name-nondirectory command)))
+ (and (eshell-interactive-output-p)
+ (or (member command eshell-visual-commands)
+ (member (car args)
+ (cdr (assoc command eshell-visual-subcommands)))
+ (cl-intersection args
+ (cdr (assoc command eshell-visual-options))
+ :test 'string=)))))
+
(defun eshell-exec-visual (&rest args)
"Run the specified PROGRAM in a terminal emulation buffer.
ARGS are passed to the program. At the moment, no piping of input is
allowed."
(let* (eshell-interpreter-alist
- (interp (eshell-find-interpreter (car args)))
+ (interp (eshell-find-interpreter (car args) (cdr args)))
(program (car interp))
(args (eshell-flatten-list
(eshell-stringify-list (append (cdr interp)
(term-set-escape-char ?\C-x))))
nil)
-(defun eshell-term-sentinel (proc string)
- "Destroy the buffer visiting PROC."
- (let ((proc-buf (process-buffer proc)))
- (when (and proc-buf (buffer-live-p proc-buf)
- (not (eq 'run (process-status proc)))
- (= (process-exit-status proc) 0))
- (if (eq (current-buffer) proc-buf)
- (let ((buf (and (boundp 'eshell-parent-buffer)
- eshell-parent-buffer
- (buffer-live-p eshell-parent-buffer)
- eshell-parent-buffer)))
- (if buf
- (switch-to-buffer buf))))
- (kill-buffer proc-buf))))
+;; Process sentinels receive two arguments.
+(defun eshell-term-sentinel (proc msg)
+ "Clean up the buffer visiting PROC.
+If `eshell-destroy-buffer-when-process-dies' is non-nil, destroy
+the buffer."
+ (term-sentinel proc msg) ;; First call the normal term sentinel.
+ (when eshell-destroy-buffer-when-process-dies
+ (let ((proc-buf (process-buffer proc)))
+ (when (and proc-buf (buffer-live-p proc-buf)
+ (not (eq 'run (process-status proc)))
+ (= (process-exit-status proc) 0))
+ (if (eq (current-buffer) proc-buf)
+ (let ((buf (and (boundp 'eshell-parent-buffer)
+ eshell-parent-buffer
+ (buffer-live-p eshell-parent-buffer)
+ eshell-parent-buffer)))
+ (if buf
+ (switch-to-buffer buf))))
+ (kill-buffer proc-buf)))))
;; jww (1999-09-17): The code below will allow Eshell to send input
;; characters directly to the currently running interactive process.