-;;; esh-ext.el --- commands external to Eshell
+;;; esh-ext.el --- commands external to Eshell -*- lexical-binding:t -*-
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2015 Free Software Foundation, Inc.
;; Author: John Wiegley <johnw@gnu.org>
(provide 'esh-ext)
+(require 'esh-util)
+
(eval-when-compile
- (require 'cl)
+ (require 'cl-lib)
+ (require 'esh-io)
(require 'esh-cmd))
-(require 'esh-util)
+(require 'esh-opt)
(defgroup eshell-ext nil
"External commands are invoked when operating system executables are
;;; User Variables:
-(defcustom eshell-ext-load-hook '(eshell-ext-initialize)
- "*A hook that gets run when `eshell-ext' is loaded."
+(defcustom eshell-ext-load-hook nil
+ "A hook that gets run when `eshell-ext' is loaded."
+ :version "24.1" ; removed eshell-ext-initialize
:type 'hook
:group 'eshell-ext)
(defcustom eshell-binary-suffixes exec-suffixes
- "*A list of suffixes used when searching for executable files."
+ "A list of suffixes used when searching for executable files."
:type '(repeat string)
:group 'eshell-ext)
(defcustom eshell-force-execution nil
- "*If non-nil, try to execute binary files regardless of permissions.
+ "If non-nil, try to execute binary files regardless of permissions.
This can be useful on systems like Windows, where the operating system
doesn't happen to honor the permission bits in certain cases; or in
cases where you want to associate an interpreter with a particular
(setq list (cdr list)))
file)))
+;; This file provides itself then eval-when-compile loads files that require it.
+;; This causes spurious "might not be defined at runtime" warnings.
+(declare-function eshell-search-path "esh-ext" (name))
+
(defcustom eshell-windows-shell-file
(if (eshell-under-windows-p)
- (if (string-match "\\(\\`cmdproxy\\|sh\\)\\.\\(com\\|exe\\)"
+ (if (string-match "\\(cmdproxy\\|sh\\)\\.\\(com\\|exe\\)"
shell-file-name)
(or (eshell-search-path "cmd.exe")
(eshell-search-path "command.com"))
shell-file-name))
- "*The name of the shell command to use for DOS/Windows batch files.
+ "The name of the shell command to use for DOS/Windows batch files.
This defaults to nil on non-Windows systems, where this variable is
wholly ignored."
:type '(choice file (const nil))
:group 'eshell-ext)
+(autoload 'eshell-parse-command "esh-cmd")
+
(defsubst eshell-invoke-batch-file (&rest args)
"Invoke a .BAT or .CMD file on DOS/Windows systems."
;; since CMD.EXE can't handle forward slashes in the initial
;; argument...
(setcar args (subst-char-in-string ?/ ?\\ (car args)))
(throw 'eshell-replace-command
- (eshell-parse-command eshell-windows-shell-file (cons "/c" args))))
+ (eshell-parse-command
+ (eshell-quote-argument eshell-windows-shell-file)
+ (cons "/c" args))))
(defcustom eshell-interpreter-alist
(if (eshell-under-windows-p)
'(("\\.\\(bat\\|cmd\\)\\'" . eshell-invoke-batch-file)))
- "*An alist defining interpreter substitutions.
+ "An alist defining interpreter substitutions.
Each member is a cons cell of the form:
(MATCH . INTERPRETER)
-MATCH should be a regexp, which is matched against the command name,
-or a function. If either returns a non-nil value, then INTERPRETER
-will be used for that command.
+MATCH should be a regexp, which is matched against the command
+name, or a function of arity 2 receiving the COMMAND and its
+ARGS (a list). If either returns a non-nil value, then
+INTERPRETER will be used for that command.
If INTERPRETER is a string, it will be called as the command name,
with the original command name passed as the first argument, with all
:group 'eshell-ext)
(defcustom eshell-alternate-command-hook nil
- "*A hook run whenever external command lookup fails.
+ "A hook run whenever external command lookup fails.
If a functions wishes to provide an alternate command, they must throw
it using the tag `eshell-replace-command'. This is done because the
substituted command need not be external at all, and therefore must be
:group 'eshell-ext)
(defcustom eshell-command-interpreter-max-length 256
- "*The maximum length of any command interpreter string, plus args."
+ "The maximum length of any command interpreter string, plus args."
:type 'integer
:group 'eshell-ext)
(defcustom eshell-explicit-command-char ?*
- "*If this char occurs before a command name, call it externally.
+ "If this char occurs before a command name, call it externally.
That is, although `vi' may be an alias, `\vi' will always call the
external version."
:type 'character
(error "%s: external command not found"
(substring command 1))))))
+(autoload 'eshell-close-handles "esh-io")
+
(defun eshell-remote-command (command args)
"Insert output from a remote COMMAND, using ARGS.
A remote command is something that executes on a different machine.
causing the user to wonder if anything's really going on..."
(let ((outbuf (generate-new-buffer " *eshell remote output*"))
(errbuf (generate-new-buffer " *eshell remote error*"))
+ (command (or (file-remote-p command 'localname) command))
(exitcode 1))
(unwind-protect
(progn
(defun eshell-external-command (command args)
"Insert output from an external COMMAND, using ARGS."
(setq args (eshell-stringify-list (eshell-flatten-list args)))
- (if (string-equal (file-remote-p default-directory 'method) "ftp")
- (eshell-remote-command command args))
- (let ((interp (eshell-find-interpreter command)))
- (assert interp)
+ (let ((interp (eshell-find-interpreter
+ command
+ args
+ ;; `eshell-find-interpreter' does not work correctly
+ ;; for Tramp file name syntax. But we don't need to
+ ;; know the interpreter in that case, therefore the
+ ;; check is suppressed.
+ (or (and (stringp command) (file-remote-p command))
+ (file-remote-p default-directory)))))
+ (cl-assert interp)
(if (functionp (car interp))
(apply (car interp) (append (cdr interp) args))
(eshell-gather-process-output
Adds the given PATH to $PATH.")
(if args
(progn
- (if prepend
- (setq args (nreverse args)))
- (while args
- (setenv "PATH"
- (if prepend
- (concat (car args) path-separator
- (getenv "PATH"))
- (concat (getenv "PATH") path-separator
- (car args))))
- (setq args (cdr args))))
- (let ((paths (parse-colon-path (getenv "PATH"))))
- (while paths
- (eshell-printn (car paths))
- (setq paths (cdr paths)))))))
+ (setq eshell-path-env (getenv "PATH")
+ args (mapconcat 'identity args path-separator)
+ eshell-path-env
+ (if prepend
+ (concat args path-separator eshell-path-env)
+ (concat eshell-path-env path-separator args)))
+ (setenv "PATH" eshell-path-env))
+ (dolist (dir (parse-colon-path (getenv "PATH")))
+ (eshell-printn dir)))))
(put 'eshell/addpath 'eshell-no-numeric-conversions t)
(list (match-string 1)
file)))))))
-(defun eshell-find-interpreter (file &optional no-examine-p)
+(defun eshell-find-interpreter (file args &optional no-examine-p)
"Find the command interpreter with which to execute FILE.
If NO-EXAMINE-P is non-nil, FILE will not be inspected for a script
line of the form #!<interp>."
(let ((finterp
(catch 'found
(ignore
- (eshell-for possible eshell-interpreter-alist
+ (dolist (possible eshell-interpreter-alist)
(cond
((functionp (car possible))
- (and (funcall (car possible) file)
- (throw 'found (cdr possible))))
+ (let ((fn (car possible)))
+ (and (funcall fn file args)
+ (throw 'found (cdr possible)))))
((stringp (car possible))
(and (string-match (car possible) file)
(throw 'found (cdr possible))))
(let ((fullname (if (file-name-directory file) file
(eshell-search-path file)))
(suffixes eshell-binary-suffixes))
+ (if (and fullname
+ (not (file-remote-p fullname))
+ (file-remote-p default-directory))
+ (setq fullname (expand-file-name
+ (concat "./" fullname) default-directory)))
(if (and fullname (not (or eshell-force-execution
(file-executable-p fullname))))
(while suffixes
(setq interp (eshell-script-interpreter fullname))
(if interp
(setq interp
- (cons (car (eshell-find-interpreter (car interp) t))
+ (cons (car (eshell-find-interpreter (car interp) args t))
(cdr interp)))))
(or interp (list fullname)))))))
-;; arch-tag: 178d4064-7e60-4745-b81f-bab5d8d7c40f
;;; esh-ext.el ends here