X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/73b0cd50031a714347109169ceb8bacae338612a..bf5ddded70c11edaf3514b25da27fc71cfb8e965:/lisp/eshell/esh-ext.el diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el index f0b9a5eb08..ca62d0cf8b 100644 --- a/lisp/eshell/esh-ext.el +++ b/lisp/eshell/esh-ext.el @@ -1,6 +1,6 @@ -;;; esh-ext.el --- commands external to Eshell +;;; esh-ext.el --- commands external to Eshell -*- lexical-binding:t -*- -;; Copyright (C) 1999-2011 Free Software Foundation, Inc. +;; Copyright (C) 1999-2016 Free Software Foundation, Inc. ;; Author: John Wiegley @@ -33,10 +33,13 @@ (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 @@ -46,8 +49,9 @@ loaded into memory, thus beginning a new process." ;;; User Variables: -(defcustom eshell-ext-load-hook '(eshell-ext-initialize) +(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) @@ -56,14 +60,15 @@ loaded into memory, thus beginning a new process." :type '(repeat string) :group 'eshell-ext) -(defcustom eshell-force-execution nil - "If non-nil, try to execute binary files regardless of permissions. +(defcustom eshell-force-execution + (not (null (memq system-type '(windows-nt ms-dos)))) + "If non-nil, try to execute files regardless of execute 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 -kind of script file, but the language won't let you but a '#!' -interpreter line in the file, and you don't want to make it executable -since nothing else but Eshell will be able to understand +doesn't support the execution bit for shell scripts; or in cases where +you want to associate an interpreter with a particular kind of script +file, but the language won't let you but a `#!' interpreter line in +the file, and you don't want to make it executable since nothing else +but Eshell will be able to understand `eshell-interpreter-alist'." :type 'boolean :group 'eshell-ext) @@ -74,6 +79,8 @@ since nothing else but Eshell will be able to understand name (let ((list (eshell-parse-colon-path eshell-path-env)) suffixes n1 n2 file) + (if (eshell-under-windows-p) + (push "." list)) (while list (setq n1 (concat (car list) name)) (setq suffixes eshell-binary-suffixes) @@ -88,9 +95,13 @@ since nothing else but Eshell will be able to understand (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")) @@ -101,13 +112,17 @@ 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) @@ -117,9 +132,10 @@ 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 @@ -175,6 +191,8 @@ This bypasses all Lisp functions and aliases." (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. @@ -185,6 +203,7 @@ all the output from the remote command, and sends it all at once, 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 @@ -202,10 +221,16 @@ causing the user to wonder if anything's really going on..." (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 @@ -221,20 +246,15 @@ causing the user to wonder if anything's really going on..." 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) @@ -256,18 +276,19 @@ Return nil, or a list of the form: (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 #!." (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)))) @@ -278,6 +299,11 @@ line of the form #!." (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 @@ -301,7 +327,7 @@ line of the form #!." (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)))))))