From: Jim Porter <jporterbugs@gmail.com>
To: Christopher Howard <christopher@librehacker.com>, 70847@debbugs.gnu.org
Subject: bug#70847: 29.3; eshell scripts "from anywhere"
Date: Thu, 23 May 2024 13:30:09 -0700 [thread overview]
Message-ID: <ee947e44-72e8-bc6f-57b3-8e4127f8199f@gmail.com> (raw)
In-Reply-To: <87h6f6c1hk.fsf@librehacker.com>
[-- Attachment #1: Type: text/plain, Size: 622 bytes --]
On 5/9/2024 10:57 AM, Christopher Howard wrote:
> ``` ~/Scratch/script.esh
> echo hello world
> ```
>
> M-: (eshell-source-file "~/Scratch/script.esh")
>
> gives
>
> eval-expression: No catch for tag: eshell-replace-command, (let ((eshell-command-name '"~/Scratch/script.esh") (eshell-command-arguments 'nil)) (eshell-trap-errors (eshell-named-command "echo" (list "hello" "world"))))
Looking at this code, I doubt 'eshell-source-file' ever worked, so the
documentation is probably just wrong.
Do the attached patches help you? They also add support for running
Eshell scripts from the command line using a shebang.
[-- Attachment #2: 0001-Consolidate-Eshell-module-loading-unloading-code.patch --]
[-- Type: text/plain, Size: 9917 bytes --]
From 201f8b1329d88985d29ca682b070b21ce7462f1e Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Fri, 10 Mar 2023 19:02:26 -0800
Subject: [PATCH 1/4] Consolidate Eshell module loading/unloading code
This also adds the ability to suppress module loading/unloading
messages, which will be necessary to support running Eshell scripts as
batch scripts.
* lisp/eshell/esh-mode.el (eshell-mode): Move module
loading/initialization to...
* lisp/eshell/esh-module.el (eshell-load-modules)
(eshell-initialize-modules): ... here.
(eshell-module-loading-messages): New option.
(eshell-module--feature-name): Improve docstring.
(eshell-unload-modules): Display a real warning if unable to unload a
module.
* test/lisp/eshell/eshell-tests-helpers.el (with-temp-eshell)
(eshell-command-result-equal):
* test/lisp/eshell/eshell-tests-unload.el (load-eshell): Silence Eshell
loading messages.
---
lisp/eshell/esh-mode.el | 31 ++---------
lisp/eshell/esh-module.el | 70 ++++++++++++++++++++----
test/lisp/eshell/eshell-tests-helpers.el | 10 ++--
test/lisp/eshell/eshell-tests-unload.el | 2 +
4 files changed, 72 insertions(+), 41 deletions(-)
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 78a448a41a5..31a9216be33 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -372,36 +372,15 @@ eshell-mode
;; strong R2L character.
(setq bidi-paragraph-direction 'left-to-right)
- ;; load extension modules into memory. This will cause any global
- ;; variables they define to be visible, since some of the core
- ;; modules sometimes take advantage of their functionality if used.
- (dolist (module eshell-modules-list)
- (let ((module-fullname (symbol-name module))
- module-shortname)
- (if (string-match "^eshell-\\(.*\\)" module-fullname)
- (setq module-shortname
- (concat "em-" (match-string 1 module-fullname))))
- (unless module-shortname
- (error "Invalid Eshell module name: %s" module-fullname))
- (unless (featurep (intern module-shortname))
- (condition-case nil
- (load module-shortname)
- (error (lwarn 'eshell :error
- "Unable to load module `%s' (defined in `eshell-modules-list')"
- module-fullname))))))
+ ;; Load extension modules into memory.
+ (eshell-load-modules eshell-modules-list)
(unless (file-exists-p eshell-directory-name)
(eshell-make-private-directory eshell-directory-name t))
- ;; Load core Eshell modules, then extension modules, for this session.
- (dolist (module (append (eshell-subgroups 'eshell) eshell-modules-list))
- (let ((load-hook (intern-soft (format "%s-load-hook" module)))
- (initfunc (intern-soft (format "%s-initialize" module))))
- (when (and load-hook (boundp load-hook))
- (if (memq initfunc (symbol-value load-hook)) (setq initfunc nil))
- (run-hooks load-hook))
- ;; So we don't need the -initialize functions on the hooks (bug#5375).
- (and initfunc (fboundp initfunc) (funcall initfunc))))
+ ;; Initialize core Eshell modules, then extension modules, for this session.
+ (eshell-initialize-modules (eshell-subgroups 'eshell))
+ (eshell-initialize-modules eshell-modules-list)
(if eshell-send-direct-to-subprocesses
(add-hook 'pre-command-hook #'eshell-intercept-commands t t))
diff --git a/lisp/eshell/esh-module.el b/lisp/eshell/esh-module.el
index fbd5ae4b9b8..88221638e16 100644
--- a/lisp/eshell/esh-module.el
+++ b/lisp/eshell/esh-module.el
@@ -49,6 +49,12 @@ eshell-module-unload-hook
:group 'eshell-module)
(make-obsolete-variable 'eshell-module-unload-hook nil "30.1")
+(defcustom eshell-module-loading-messages t
+ "If non-nil, display messages when loading/unloading Eshell modules."
+ :type 'boolean
+ :group 'eshell-module
+ :version "30.1")
+
(defcustom eshell-modules-list
'(eshell-alias
eshell-banner
@@ -87,7 +93,9 @@ eshell-modules-list
;;; Code:
(defsubst eshell-module--feature-name (module &optional kind)
- "Get the feature name for the specified Eshell MODULE."
+ "Get the feature name for the specified Eshell MODULE.
+KIND can be either `core' for a core module or `extension' for an
+extension module; if nil, KIND defaults to `extension'."
(let ((module-name (symbol-name module))
(prefix (cond ((eq kind 'core) "esh-")
((memq kind '(extension nil)) "em-")
@@ -102,17 +110,57 @@ eshell-using-module
customization group. Example: `eshell-cmpl' for that module."
(memq module eshell-modules-list))
-(defun eshell-unload-modules (modules &optional kind)
- "Try to unload the specified Eshell MODULES."
+(defun eshell-load-modules (modules)
+ "Load Eshell MODULES into memory.
+This will cause any global variables they define to be visible so
+that other modules can take advantage of their functionality if
+desired."
+ (let ((verbose eshell-module-loading-messages))
+ (dolist (module modules)
+ (let ((module-feature-name (eshell-module--feature-name module)))
+ (unless (featurep (intern module-feature-name))
+ (when verbose (message "Loading %s..." module))
+ (condition-case-unless-debug nil
+ (progn
+ (load module-feature-name nil t)
+ (when verbose (message "Loading %s...done" module)))
+ (error (when verbose (message "Loading %s...failed" module))
+ (lwarn 'eshell :error
+ "Unable to load Eshell module `%s'"
+ module))))))))
+
+(defun eshell-initialize-modules (modules)
+ "Initialize Eshell MODULES.
+This calls `MODULE-load-hook' and `MODULE-initialize' for each
+MODULE, if they're defined."
(dolist (module modules)
- (let ((module-feature (intern (eshell-module--feature-name module kind))))
- (when (featurep module-feature)
- (message "Unloading %s..." (symbol-name module))
- (condition-case-unless-debug _
- (progn
- (unload-feature module-feature)
- (message "Unloading %s...done" (symbol-name module)))
- (error (message "Unloading %s...failed" (symbol-name module))))))))
+ (let ((load-hook (intern-soft (format "%s-load-hook" module)))
+ (initfunc (intern-soft (format "%s-initialize" module))))
+ (when (and load-hook (boundp load-hook))
+ (if (memq initfunc (symbol-value load-hook)) (setq initfunc nil))
+ (run-hooks load-hook))
+ ;; So we don't need the -initialize functions on the hooks (bug#5375).
+ (and initfunc (fboundp initfunc) (funcall initfunc)))))
+
+(defun eshell-unload-modules (modules &optional kind)
+ "Try to unload the specified Eshell MODULES.
+KIND can be either `core' for core modules or `extension' for
+extension modules; if nil, KIND defaults to `extension'."
+ ;; We're about to unload this module, but we need to remember whether
+ ;; to print messages.
+ (let ((verbose eshell-module-loading-messages))
+ (dolist (module modules)
+ (let ((module-feature (intern (eshell-module--feature-name module kind))))
+ (when (featurep module-feature)
+ (when verbose (message "Unloading %s..." module))
+ (condition-case-unless-debug nil
+ (progn
+ (unload-feature module-feature)
+ (when verbose (message "Unloading %s...done" module)))
+ (error (when verbose (message "Unloading %s...failed" module))
+ (lwarn 'eshell :error
+ "Unable to unload Eshell module `%s'"
+ module))))))))
(defun eshell-unload-extension-modules ()
"Try to unload all currently-loaded Eshell extension modules."
diff --git a/test/lisp/eshell/eshell-tests-helpers.el b/test/lisp/eshell/eshell-tests-helpers.el
index 652146fefcc..3f1c55f420d 100644
--- a/test/lisp/eshell/eshell-tests-helpers.el
+++ b/test/lisp/eshell/eshell-tests-helpers.el
@@ -63,6 +63,7 @@ with-temp-eshell
(eshell-debug-command (cons 'process eshell-debug-command))
(eshell-history-file-name nil)
(eshell-last-dir-ring-file-name nil)
+ (eshell-module-loading-messages nil)
(eshell-buffer (eshell t)))
(unwind-protect
(with-current-buffer eshell-buffer
@@ -183,10 +184,11 @@ eshell-command-result--equal-explainer
(defun eshell-command-result-equal (command result)
"Execute COMMAND non-interactively and compare it to RESULT."
(ert-info (#'eshell-get-debug-logs :prefix "Command logs: ")
- (should (eshell-command-result--equal
- command
- (eshell-test-command-result command)
- result))))
+ (let ((eshell-module-loading-messages nil))
+ (should (eshell-command-result--equal
+ command
+ (eshell-test-command-result command)
+ result)))))
(provide 'eshell-tests-helpers)
diff --git a/test/lisp/eshell/eshell-tests-unload.el b/test/lisp/eshell/eshell-tests-unload.el
index bf8291ba47a..479090e8f8c 100644
--- a/test/lisp/eshell/eshell-tests-unload.el
+++ b/test/lisp/eshell/eshell-tests-unload.el
@@ -33,6 +33,7 @@ eshell-directory-name
(defvar eshell-history-file-name)
(defvar eshell-last-dir-ring-file-name)
(defvar eshell-modules-list)
+(defvar eshell-module-loading-messages)
(declare-function eshell-module--feature-name "esh-module"
(module &optional kind))
@@ -51,6 +52,7 @@ load-eshell
(process-environment (cons "HISTFILE" process-environment))
(eshell-history-file-name nil)
(eshell-last-dir-ring-file-name nil)
+ (eshell-module-loading-messages nil)
(eshell-buffer (eshell t)))
(let (kill-buffer-query-functions)
(kill-buffer eshell-buffer))))))
--
2.25.1
[-- Attachment #3: 0002-Use-esh-module-autoload-for-Eshell-modules-defgroups.patch --]
[-- Type: text/plain, Size: 13971 bytes --]
From bc1828265c226fa3b5267eca2c3d3f08bedfe627 Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Sun, 19 May 2024 22:01:31 -0700
Subject: [PATCH 2/4] Use 'esh-module-autoload' for Eshell modules' defgroups
This will let modules define their own, regular autoloads, independent
of the core Eshell machinery for defining modules.
* lisp/eshell/em-alias.el (em-alias):
* lisp/eshell/em-banner.el (em-banner):
* lisp/eshell/em-basic.el (em-basic):
* lisp/eshell/em-cmpl.el (em-cmpl):
* lisp/eshell/em-dirs.el (em-dirs):
* lisp/eshell/em-elecslash.el (em-elecslash):
* lisp/eshell/em-extpipe.el:
* lisp/eshell/em-glob.el (em-glob):
* lisp/eshell/em-hist.el (em-hist):
* lisp/eshell/em-ls.el (em-ls):
* lisp/eshell/em-pred.el (em-pred):
* lisp/eshell/em-prompt.el (em-prompt):
* lisp/eshell/em-rebind.el (em-rebind):
* lisp/eshell/em-script.el (em-script):
* lisp/eshell/em-smart.el (em-smart):
* lisp/eshell/em-term.el (em-term):
* lisp/eshell/em-tramp.el (em-tramp):
* lisp/eshell/em-unix.el (em-unix):
* lisp/eshell/em-xtra.el (em-xtra): Use 'esh-module-autoload'.
* lisp/eshell/esh-module.el ("esh-module-loaddefs"): Load this instead
of "esh-groups".
* .gitignore: Change esh-groups.el to esh-module-loaddefs.el
---
.gitignore | 2 +-
lisp/eshell/em-alias.el | 7 +------
lisp/eshell/em-banner.el | 7 +------
lisp/eshell/em-basic.el | 7 +------
lisp/eshell/em-cmpl.el | 7 +------
lisp/eshell/em-dirs.el | 7 +------
lisp/eshell/em-elecslash.el | 7 +------
lisp/eshell/em-extpipe.el | 2 +-
lisp/eshell/em-glob.el | 7 +------
lisp/eshell/em-hist.el | 7 +------
lisp/eshell/em-ls.el | 7 +------
lisp/eshell/em-pred.el | 7 +------
lisp/eshell/em-prompt.el | 7 +------
lisp/eshell/em-rebind.el | 7 +------
lisp/eshell/em-script.el | 7 +------
lisp/eshell/em-smart.el | 7 +------
lisp/eshell/em-term.el | 7 +------
lisp/eshell/em-tramp.el | 7 +------
lisp/eshell/em-unix.el | 7 +------
lisp/eshell/em-xtra.el | 7 +------
lisp/eshell/esh-module.el | 2 +-
21 files changed, 21 insertions(+), 111 deletions(-)
diff --git a/.gitignore b/.gitignore
index 1557c085fad..52d328a9357 100644
--- a/.gitignore
+++ b/.gitignore
@@ -128,7 +128,7 @@ lisp/cedet/semantic/wisent/js-wy.el
lisp/cedet/semantic/wisent/python-wy.el
lisp/cedet/srecode/srt-wy.el
lisp/cedet/semantic/grammar-wy.el
-lisp/eshell/esh-groups.el
+lisp/eshell/esh-module-loaddefs.el
lisp/finder-inf.el
lisp/leim/ja-dic/
leim/small-ja-dic-option
diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el
index 832e14418d0..d12b382d885 100644
--- a/lisp/eshell/em-alias.el
+++ b/lisp/eshell/em-alias.el
@@ -92,7 +92,7 @@
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-alias nil
"Command aliases allow for easy definition of alternate commands."
@@ -268,9 +268,4 @@ eshell-fix-bad-commands
(eshell-parse-command alias))))))))))
(provide 'em-alias)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-alias.el ends here
diff --git a/lisp/eshell/em-banner.el b/lisp/eshell/em-banner.el
index e6dcbb24475..626624c7bfe 100644
--- a/lisp/eshell/em-banner.el
+++ b/lisp/eshell/em-banner.el
@@ -44,7 +44,7 @@
(require 'esh-util)
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-banner nil
"This sample module displays a welcome banner at login.
@@ -82,9 +82,4 @@ eshell-banner-initialize
(eshell-interactive-print msg))))
(provide 'em-banner)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-banner.el ends here
diff --git a/lisp/eshell/em-basic.el b/lisp/eshell/em-basic.el
index 6ec53ef9412..82cddd7385f 100644
--- a/lisp/eshell/em-basic.el
+++ b/lisp/eshell/em-basic.el
@@ -58,7 +58,7 @@
(require 'esh-opt)
(require 'esh-util)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-basic nil
"The \"basic\" code provides a set of convenience functions which
@@ -225,9 +225,4 @@ pcomplete/eshell-mode/eshell-debug
(while (pcomplete-here '("error" "form" "process"))))
(provide 'em-basic)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-basic.el ends here
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index 201beb5071d..4c79f7b187a 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -76,7 +76,7 @@
(eval-when-compile (require 'cl-lib))
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-cmpl nil
"This module provides a programmable completion function bound to
@@ -518,9 +518,4 @@ eshell--complete-commands-list
(define-obsolete-function-alias 'eshell-pcomplete #'completion-at-point "27.1")
(provide 'em-cmpl)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-cmpl.el ends here
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 07063afc286..a3d1a349540 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -47,7 +47,7 @@
(require 'ring)
(require 'esh-opt)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-dirs nil
"Directory navigation involves changing directories, examining the
@@ -599,9 +599,4 @@ eshell-write-last-dir-ring
'no-message))))))))
(provide 'em-dirs)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-dirs.el ends here
diff --git a/lisp/eshell/em-elecslash.el b/lisp/eshell/em-elecslash.el
index 93eadcfe1ff..60f2c6e4039 100644
--- a/lisp/eshell/em-elecslash.el
+++ b/lisp/eshell/em-elecslash.el
@@ -32,7 +32,7 @@
(require 'esh-mode)
;; This makes us an option when customizing `eshell-modules-list'.
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-elecslash nil
"Electric forward slash in remote Eshells.
@@ -108,9 +108,4 @@ eshell-electric-forward-slash
(insert "/")))))
(provide 'em-elecslash)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; esh-elecslash.el ends here
diff --git a/lisp/eshell/em-extpipe.el b/lisp/eshell/em-extpipe.el
index 057eead9297..4c92653a3a3 100644
--- a/lisp/eshell/em-extpipe.el
+++ b/lisp/eshell/em-extpipe.el
@@ -36,7 +36,7 @@
(eval-when-compile (require 'files-x))
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-extpipe nil
"Native shell pipelines.
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 89a40151d00..36e4f90aed2 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -53,7 +53,7 @@
(require 'esh-module)
(require 'esh-util)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-glob nil
"This module provides extended globbing syntax, similar what is used
@@ -417,9 +417,4 @@ eshell-glob-entries
(eshell-glob-entries rdir globs only-dirs)))))
(provide 'em-glob)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-glob.el ends here
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index 21029eae1bc..22d7723943a 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -60,7 +60,7 @@
(require 'esh-opt)
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-hist nil
"This module provides command history management."
@@ -1068,9 +1068,4 @@ em-hist-unload-function
(remove-hook 'kill-emacs-hook 'eshell-save-some-history))
(provide 'em-hist)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-hist.el ends here
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 62ad7ff72a1..82d4b01393f 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -32,7 +32,7 @@
(require 'esh-proc)
(require 'esh-cmd)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-ls nil
"This module implements the \"ls\" utility fully in Lisp.
@@ -956,9 +956,4 @@ em-ls-unload-function
(eshell-ls-disable-in-dired))
(provide 'em-ls)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-ls.el ends here
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index c3997dc72c3..0be262641ea 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -48,7 +48,7 @@
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-pred nil
"This module allows for predicates to be applied to globbing
@@ -576,9 +576,4 @@ eshell-split-members
lst))))
(provide 'em-pred)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-pred.el ends here
diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el
index 3662c1fa895..b6556d29544 100644
--- a/lisp/eshell/em-prompt.el
+++ b/lisp/eshell/em-prompt.el
@@ -29,7 +29,7 @@
(require 'esh-mode)
(require 'text-property-search)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-prompt nil
"This module provides command prompts, and navigation between them,
@@ -231,9 +231,4 @@ eshell-bol-ignoring-prompt
(move-beginning-of-line arg)))
(provide 'em-prompt)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-prompt.el ends here
diff --git a/lisp/eshell/em-rebind.el b/lisp/eshell/em-rebind.el
index c6ee1a329b6..aad65f66f41 100644
--- a/lisp/eshell/em-rebind.el
+++ b/lisp/eshell/em-rebind.el
@@ -25,7 +25,7 @@
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-rebind nil
"This module allows for special keybindings that only take effect
@@ -250,9 +250,4 @@ eshell-delchar-or-maybe-eof
(eshell-delete-backward-char (- arg)))))
(provide 'em-rebind)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-rebind.el ends here
diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el
index 066063c4cc2..254a11ea114 100644
--- a/lisp/eshell/em-script.el
+++ b/lisp/eshell/em-script.el
@@ -25,7 +25,7 @@
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-script nil
"This module allows for the execution of files containing Eshell
@@ -115,9 +115,4 @@ eshell/.
(put 'eshell/. 'eshell-no-numeric-conversions t)
(provide 'em-script)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-script.el ends here
diff --git a/lisp/eshell/em-smart.el b/lisp/eshell/em-smart.el
index 91fe02e5545..670b956476d 100644
--- a/lisp/eshell/em-smart.el
+++ b/lisp/eshell/em-smart.el
@@ -70,7 +70,7 @@
(require 'esh-mode)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-smart nil
"This module combines the facility of normal, modern shells with
@@ -303,9 +303,4 @@ em-smart-unload-hook
(remove-hook 'window-configuration-change-hook #'eshell-smart-scroll))
(provide 'em-smart)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-smart.el ends here
diff --git a/lisp/eshell/em-term.el b/lisp/eshell/em-term.el
index 8f29e2d8509..2f8c06a0baa 100644
--- a/lisp/eshell/em-term.el
+++ b/lisp/eshell/em-term.el
@@ -36,7 +36,7 @@
(require 'esh-ext)
(require 'term)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-term nil
"This module causes visual commands (e.g., `vi') to be executed by
@@ -330,9 +330,4 @@ eshell-term-sentinel
; (use-local-map term-old-mode-map))
(provide 'em-term)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-term.el ends here
diff --git a/lisp/eshell/em-tramp.el b/lisp/eshell/em-tramp.el
index efb37225651..cfc8a47327e 100644
--- a/lisp/eshell/em-tramp.el
+++ b/lisp/eshell/em-tramp.el
@@ -35,7 +35,7 @@
;; There are no items in this custom group, but eshell modules (ab)use
;; custom groups.
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-tramp nil
"This module defines commands that use Tramp in a way that is
@@ -152,9 +152,4 @@ eshell/doas
(put 'eshell/doas 'eshell-no-numeric-conversions t)
(provide 'em-tramp)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-tramp.el ends here
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 855efa26033..7f976d22681 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -38,7 +38,7 @@
(require 'esh-mode)
(require 'pcomplete)
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-unix nil
"This module defines many of the more common UNIX utilities as
@@ -1096,9 +1096,4 @@ eshell-diff-window-config
(define-obsolete-function-alias 'eshell-diff-quit #'ignore "30.1")
(provide 'em-unix)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-unix.el ends here
diff --git a/lisp/eshell/em-xtra.el b/lisp/eshell/em-xtra.el
index a62073e2183..0a032395fd3 100644
--- a/lisp/eshell/em-xtra.el
+++ b/lisp/eshell/em-xtra.el
@@ -28,7 +28,7 @@
;; There are no items in this custom group, but eshell modules (ab)use
;; custom groups.
-;;;###autoload
+;;;###esh-module-autoload
(progn
(defgroup eshell-xtra nil
"This module defines some extra alias functions which are entirely
@@ -85,9 +85,4 @@ 'eshell/ff
(defalias 'eshell/gf #'find-grep-dired)
(provide 'em-xtra)
-
-;; Local Variables:
-;; generated-autoload-file: "esh-groups.el"
-;; End:
-
;;; em-xtra.el ends here
diff --git a/lisp/eshell/esh-module.el b/lisp/eshell/esh-module.el
index 88221638e16..db808f8597a 100644
--- a/lisp/eshell/esh-module.el
+++ b/lisp/eshell/esh-module.el
@@ -38,7 +38,7 @@ eshell-module
;; `eshell-modules-list'. We use "(progn (defgroup ..." in each file
;; to force the autoloader into including the entire defgroup, rather
;; than an abbreviated version.
-(load "esh-groups" nil 'nomessage)
+(load "esh-module-loaddefs" nil 'nomessage)
;;; User Variables:
--
2.25.1
[-- Attachment #4: 0003-Rework-how-eshell-ensure-newline-p-adds-newlines.patch --]
[-- Type: text/plain, Size: 10856 bytes --]
From 7d385585f48c9c7093ca1a4ff0448028f9fade46 Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Wed, 22 May 2024 21:58:34 -0700
Subject: [PATCH 3/4] Rework how 'eshell-ensure-newline-p' adds newlines
This allows for other output targets (see the following commit) to be
"line-oriented".
* lisp/eshell/esh-io.el (eshell-virtual-targets): Update docstring.
(eshell-ensure-newline-p): Move from esh-cmd.el.
(eshell-generic-target): New struct...
(eshell-function-target): ... use it, and rename from
'eshell-virtual-target'.
(eshell-target-line-oriented-p, eshell--output-maybe-n)
(eshell-print-maybe-n, eshell-error-maybe-n)
(eshell-maybe-output-newline): New functions.
* lisp/eshell/esh-cmd.el (eshell-lisp-command): Don't print a newline
in this function directly; instead, use 'eshell-print-maybe-n' and
'eshell-error-maybe-n'.
(eshell-ensure-newline-p): Move to esh-io.el.
* lisp/eshell/em-unix.el (eshell/cat): Remove now-unnecessary override
of 'eshell-ensure-newline-p'.
* doc/misc/eshell.texi (Redirection): Correct documentation about
virtual targets.
---
doc/misc/eshell.texi | 4 +-
lisp/eshell/em-unix.el | 4 +-
lisp/eshell/esh-cmd.el | 20 +++------
lisp/eshell/esh-io.el | 100 ++++++++++++++++++++++++++++++++---------
4 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 57ee3bf3e9f..bdf19bb6bd9 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -2402,8 +2402,8 @@ Redirection
@code{append} for @code{>>}, or @code{insert} for @code{>>>}--and the
function is expected to return the output function.
-The output function is called once on each line of output until
-@code{nil} is passed, indicating end of output.
+When using the virtual target, Eshell will call the output function with
+each object to output in turn.
@node Pipelines
@section Pipelines
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 7f976d22681..4137c05fa41 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -683,9 +683,7 @@ eshell/cat
(with-current-buffer curbuf
(eshell-buffered-print str)))
(forward-line)))))
- (eshell-flush)
- ;; if the file does not end in a newline, do not emit one
- (setq eshell-ensure-newline-p nil))))
+ (eshell-flush))))
(put 'eshell/cat 'eshell-no-numeric-conversions t)
(put 'eshell/cat 'eshell-filename-arguments t)
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index dae1a77552f..f77f910e63f 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -254,11 +254,6 @@ eshell-subcommand-bindings
:type 'sexp
:risky t)
-(defvar eshell-ensure-newline-p nil
- "If non-nil, ensure that a newline is emitted after a Lisp form.
-This can be changed by Lisp forms that are evaluated from the Eshell
-command line.")
-
;;; Internal Variables:
;; These variables have been merged into `eshell-foreground-command'.
@@ -1497,7 +1492,7 @@ eshell-lisp-command
(catch 'eshell-external ; deferred to an external command
(setq eshell-last-command-status 0
eshell-last-arguments args)
- (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
+ (let* ((eshell-ensure-newline-p t)
(command-form-p (functionp object))
(result
(if command-form-p
@@ -1524,14 +1519,13 @@ eshell-lisp-command
(setq args (cdr args))))
(setq eshell-last-command-name
(concat "#<function " (symbol-name object) ">"))
- (eshell-apply object eshell-last-arguments))
+ (eshell-apply* #'eshell-print-maybe-n
+ #'eshell-error-maybe-n
+ object eshell-last-arguments))
(setq eshell-last-command-name "#<Lisp object>")
- (eshell-eval object))))
- (if (and eshell-ensure-newline-p
- (save-excursion
- (goto-char eshell-last-output-end)
- (not (bolp))))
- (eshell-print "\n"))
+ (eshell-eval* #'eshell-print-maybe-n
+ #'eshell-error-maybe-n
+ object))))
(eshell-close-handles
;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms
;; that succeeded but have a nil result should have an exit
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index 4487389bf26..83b869e307b 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -144,9 +144,8 @@ eshell-virtual-targets
output function. Otherwise, the second element itself is the output
function.
-The output function is then called repeatedly with single strings,
-which represents successive pieces of the output of the command, until nil
-is passed, meaning EOF."
+When using the virtual target, Eshell calls the output function
+repeatedly with each object to output."
:version "30.1"
:type '(repeat
(list (string :tag "Target")
@@ -158,6 +157,12 @@ eshell-virtual-targets
(define-error 'eshell-pipe-broken "Pipe broken")
+(defvar eshell-ensure-newline-p nil
+ "If non-nil, ensure that a newline is emitted after a Lisp form.
+This can be changed by Lisp forms that are evaluated from the
+Eshell command line. This behavior only applies to line-oriented
+output targets (see `eshell-target-line-oriented-p'.")
+
;;; Internal Variables:
(defconst eshell-redirection-operators-alist
@@ -489,20 +494,48 @@ eshell-error
"Output OBJECT to the standard error handle."
(eshell-output-object object eshell-error-handle))
-(defsubst eshell-errorn (object)
- "Output OBJECT followed by a newline to the standard error handle."
- (eshell-error object)
- (eshell-error "\n"))
-
(defsubst eshell-printn (object)
"Output OBJECT followed by a newline to the standard output handle."
(eshell-print object)
(eshell-print "\n"))
-(cl-defstruct (eshell-virtual-target
+(defsubst eshell-errorn (object)
+ "Output OBJECT followed by a newline to the standard error handle."
+ (eshell-error object)
+ (eshell-error "\n"))
+
+(defun eshell--output-maybe-n (object handle)
+ "Output OBJECT to HANDLE.
+For any line-oriented output targets on HANDLE, ensure the output
+ends in a newline."
+ (eshell-output-object object handle)
+ (when (and eshell-ensure-newline-p
+ (not (and (stringp object)
+ (string-suffix-p object "\n"))))
+ (eshell-maybe-output-newline handle)))
+
+(defsubst eshell-print-maybe-n (object)
+ "Output OBJECT to the standard output handle.
+For any line-oriented output targets, ensure the output ends in a
+newline."
+ (eshell--output-maybe-n object eshell-output-handle))
+
+(defsubst eshell-error-maybe-n (object)
+ "Output OBJECT to the standard error handle.
+For any line-oriented output targets, ensure the output ends in a
+newline."
+ (eshell--output-maybe-n object eshell-error-handle))
+
+(cl-defstruct (eshell-generic-target (:constructor nil))
+ "An Eshell target.
+This is mainly useful for creating virtual targets (see
+`eshell-virtual-targets').")
+
+(cl-defstruct (eshell-function-target
+ (:include eshell-generic-target)
(:constructor nil)
- (:constructor eshell-virtual-target-create (output-function)))
- "A virtual target (see `eshell-virtual-targets')."
+ (:constructor eshell-function-target-create (output-function)))
+ "An Eshell target that calls an output function."
output-function)
(cl-defgeneric eshell-get-target (raw-target &optional _mode)
@@ -514,14 +547,16 @@ eshell-get-target
(cl-defmethod eshell-get-target ((raw-target string) &optional mode)
"Convert a string RAW-TARGET into a valid output target using MODE.
If TARGET is a virtual target (see `eshell-virtual-targets'),
-return an `eshell-virtual-target' instance; otherwise, return a
+return an `eshell-generic-target' instance; otherwise, return a
marker for a file named TARGET."
(setq mode (or mode 'insert))
(if-let ((redir (assoc raw-target eshell-virtual-targets)))
- (eshell-virtual-target-create
- (if (nth 2 redir)
- (funcall (nth 1 redir) mode)
- (nth 1 redir)))
+ (let ((target (if (nth 2 redir)
+ (funcall (nth 1 redir) mode)
+ (nth 1 redir))))
+ (unless (eshell-generic-target-p target)
+ (setq target (eshell-function-target-create target)))
+ target)
(let ((exists (get-file-buffer raw-target))
(buf (find-file-noselect raw-target t)))
(with-current-buffer buf
@@ -602,8 +637,8 @@ eshell-close-target
(throw 'done nil))
(process-send-eof target))))
-(cl-defmethod eshell-close-target ((_target eshell-virtual-target) _status)
- "Close a virtual TARGET."
+(cl-defmethod eshell-close-target ((_target eshell-function-target) _status)
+ "Close an Eshell function TARGET."
nil)
(cl-defgeneric eshell-output-object-to-target (object target)
@@ -660,9 +695,19 @@ eshell-output-object-to-target
object)
(cl-defmethod eshell-output-object-to-target (object
- (target eshell-virtual-target))
- "Output OBJECT to the virtual TARGET."
- (funcall (eshell-virtual-target-output-function target) object))
+ (target eshell-function-target))
+ "Output OBJECT to the Eshell function TARGET."
+ (funcall (eshell-function-target-output-function target) object))
+
+(cl-defgeneric eshell-target-line-oriented-p (_target)
+ "Return non-nil if the specified TARGET is line-oriented.
+Line-oriented targets are those that expect a newline after
+command output when `eshell-ensure-newline-p' is non-nil."
+ nil)
+
+(cl-defmethod eshell-target-line-oriented-p ((_target (eql t)))
+ "Return non-nil to indicate that the display is line-oriented."
+ t)
(defun eshell-output-object (object &optional handle-index handles)
"Insert OBJECT, using HANDLE-INDEX specifically.
@@ -674,5 +719,18 @@ eshell-output-object
(dolist (target targets)
(eshell-output-object-to-target object target))))
+(defun eshell-maybe-output-newline (&optional handle-index handles)
+ "Maybe insert a newline, using HANDLE-INDEX specifically.
+This inserts a newline for all line-oriented output targets.
+
+If HANDLE-INDEX is nil, output to `eshell-output-handle'.
+HANDLES is the set of file handles to use; if nil, use
+`eshell-current-handles'."
+ (let ((targets (caar (aref (or handles eshell-current-handles)
+ (or handle-index eshell-output-handle)))))
+ (dolist (target targets)
+ (when (eshell-target-line-oriented-p target)
+ (eshell-output-object-to-target "\n" target)))))
+
(provide 'esh-io)
;;; esh-io.el ends here
--
2.25.1
[-- Attachment #5: 0004-Fix-calling-Eshell-scripts-outside-of-Eshell.patch --]
[-- Type: text/plain, Size: 12891 bytes --]
From 3cb8cf0229fc154e439a0a27c047d42ce8452a3b Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Mon, 20 May 2024 08:59:02 -0700
Subject: [PATCH 4/4] Fix calling Eshell scripts outside of Eshell
* lisp/eshell/em-script.el (eshell-source-file): Make obsolete.
(eshell--source-file): Adapt from 'eshell-source-file'...
(eshell-script-initialize, eshell/source, eshell/.): ... use it.
(eshell-princ-target): New struct.
(eshell-output-object-to-target, eshell-target-line-oriented-p): New
implementations for 'eshell-princ-target'.
(eshell-execute-file, eshell-batch-file): New functions.
* lisp/eshell/esh-mode.el (eshell-mode): Just warn if we can't create
the Eshell directory.
* test/lisp/eshell/em-script-tests.el (em-script-test/execute-file):
(em-script-test/execute-file/args), em-script-test/batch-file): New
tests.
* test/lisp/eshell/eshell-tests-helpers.el (with-temp-eshell-settings):
New function...
(with-temp-eshell): ... use it.
* doc/misc/eshell.texi (Control Flow): Update documentation.
---
doc/misc/eshell.texi | 15 ++-
lisp/eshell/em-script.el | 115 ++++++++++++++++++-----
lisp/eshell/esh-mode.el | 3 +-
test/lisp/eshell/em-script-tests.el | 31 ++++++
test/lisp/eshell/eshell-tests-helpers.el | 36 ++++---
5 files changed, 155 insertions(+), 45 deletions(-)
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index bdf19bb6bd9..ae76546c52f 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -1686,13 +1686,20 @@ Control Flow
@node Scripts
@section Scripts
@cmindex source
-@fnindex eshell-source-file
+@fnindex eshell-execute-file
+@fnindex eshell-batch-file
You can run Eshell scripts much like scripts for other shells; the main
difference is that since Eshell is not a system command, you have to run
it from within Emacs. An Eshell script is simply a file containing a
-sequence of commands, as with almost any other shell script. Scripts
-are invoked from Eshell with @command{source}, or from anywhere in Emacs
-with @code{eshell-source-file}.
+sequence of commands, as with almost any other shell script. You can
+invoke scripts from within Eshell with @command{source}, or from
+anywhere in Emacs with @code{eshell-execute-file}. Additionally, you
+can make an Eshell script file executable by calling
+@code{eshell-batch-file} in the interpreter directive:
+
+@example
+#!/usr/bin/env -S emacs --batch -f eshell-batch-file
+@end example
Like with aliases (@pxref{Aliases}), Eshell scripts can accept any
number of arguments. Within the script, you can refer to these with
diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el
index 254a11ea114..6e2ca7ca781 100644
--- a/lisp/eshell/em-script.el
+++ b/lisp/eshell/em-script.el
@@ -24,6 +24,7 @@
;;; Code:
(require 'esh-mode)
+(require 'esh-io)
;;;###esh-module-autoload
(progn
@@ -75,42 +76,106 @@ eshell-script-initialize
eshell-login-script
(file-readable-p eshell-login-script)
(eshell-do-eval
- (list 'eshell-commands
- (catch 'eshell-replace-command
- (eshell-source-file eshell-login-script)))
+ `(eshell-commands ,(eshell--source-file eshell-login-script))
t))
(and eshell-rc-script
(file-readable-p eshell-rc-script)
(eshell-do-eval
- (list 'eshell-commands
- (catch 'eshell-replace-command
- (eshell-source-file eshell-rc-script))) t))))
+ `(eshell-commands ,(eshell--source-file eshell-rc-script))
+ t))))
-(defun eshell-source-file (file &optional args subcommand-p)
- "Execute a series of Eshell commands in FILE, passing ARGS.
-Comments begin with `#'."
+(defun eshell--source-file (file &optional args subcommand-p)
+ "Return a Lisp form for executig the Eshell commands in FILE, passing ARGS.
+If SUBCOMMAND-P is non-nil, execute this as a subcommand."
(let ((cmd (eshell-parse-command `(:file . ,file))))
(when subcommand-p
(setq cmd `(eshell-as-subcommand ,cmd)))
- (throw 'eshell-replace-command
- `(let ((eshell-command-name ',file)
- (eshell-command-arguments ',args)
- ;; Don't print subjob messages by default.
- ;; Otherwise, if this function was called as a
- ;; subjob, then *all* commands in the script would
- ;; print start/stop messages.
- (eshell-subjob-messages nil))
- ,cmd))))
-
-(defun eshell/source (&rest args)
- "Source a file in a subshell environment."
- (eshell-source-file (car args) (cdr args) t))
+ `(let ((eshell-command-name ',file)
+ (eshell-command-arguments ',args)
+ ;; Don't print subjob messages by default. Otherwise, if
+ ;; this function was called as a subjob, then *all* commands
+ ;; in the script would print start/stop messages.
+ (eshell-subjob-messages nil))
+ ,cmd)))
+
+(defun eshell-source-file (file &optional args subcommand-p)
+ "Execute a series of Eshell commands in FILE, passing ARGS.
+Comments begin with `#'."
+ (declare (obsolete nil "30.1"))
+ (throw 'eshell-replace-command
+ (eshell--source-file file args subcommand-p)))
+
+;;;###autoload
+(defun eshell-execute-file (file &optional args destination)
+ "Execute a series of Eshell commands in FILE, passing ARGS.
+Comments begin with `#'."
+ (let ((eshell-non-interactive-p t)
+ (stdout (if (eq destination t) (current-buffer) destination)))
+ (with-temp-buffer
+ (eshell-mode)
+ (eshell-do-eval
+ `(let ((eshell-current-handles
+ (eshell-create-handles ,stdout 'insert))
+ (eshell-current-subjob-p))
+ ,(eshell--source-file file args))
+ t))))
+
+(cl-defstruct (eshell-princ-target
+ (:include eshell-generic-target)
+ (:constructor nil)
+ (:constructor eshell-princ-target-create
+ (&optional printcharfun)))
+ "A virtual target calling `princ' (see `eshell-virtual-targets')."
+ printcharfun)
+
+(cl-defmethod eshell-output-object-to-target (object
+ (target eshell-princ-target))
+ "Output OBJECT to the `princ' function TARGET."
+ (princ object (eshell-princ-target-printcharfun target)))
+
+(cl-defmethod eshell-target-line-oriented-p ((_target eshell-princ-target))
+ "Return non-nil to indicate that the display is line-oriented."
+ t)
+
+;;;###autoload
+(defun eshell-batch-file ()
+ "Execute an Eshell script as a batch script from the command line.
+Inside your Eshell script file, you can add the following at the
+top in order to make it into an executable script:
+
+ #!/usr/bin/env -S emacs --batch -f eshell-batch-file"
+ (let ((file (pop command-line-args-left))
+ (args command-line-args-left)
+ (eshell-non-interactive-p t)
+ (eshell-module-loading-messages nil)
+ (eshell-virtual-targets
+ (append `(("/dev/stdout" ,(eshell-princ-target-create) nil)
+ ("/dev/stderr" ,(eshell-princ-target-create
+ #'external-debugging-output)
+ nil))
+ eshell-virtual-targets)))
+ (setq command-line-args-left nil)
+ (with-temp-buffer
+ (eshell-mode)
+ (eshell-do-eval
+ `(let ((eshell-current-handles
+ (eshell-create-handles "/dev/stdout" 'append
+ "/dev/stderr" 'append))
+ (eshell-current-subjob-p))
+ ,(eshell--source-file file args))
+ t))))
+
+(defun eshell/source (file &rest args)
+ "Source a FILE in a subshell environment."
+ (throw 'eshell-replace-command
+ (eshell--source-file file args t)))
(put 'eshell/source 'eshell-no-numeric-conversions t)
-(defun eshell/. (&rest args)
- "Source a file in the current environment."
- (eshell-source-file (car args) (cdr args)))
+(defun eshell/. (file &rest args)
+ "Source a FILE in the current environment."
+ (throw 'eshell-replace-command
+ (eshell--source-file file args)))
(put 'eshell/. 'eshell-no-numeric-conversions t)
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 31a9216be33..488ff58352e 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -376,7 +376,8 @@ eshell-mode
(eshell-load-modules eshell-modules-list)
(unless (file-exists-p eshell-directory-name)
- (eshell-make-private-directory eshell-directory-name t))
+ (with-demoted-errors "Error creating Eshell directory: %s"
+ (eshell-make-private-directory eshell-directory-name t)))
;; Initialize core Eshell modules, then extension modules, for this session.
(eshell-initialize-modules (eshell-subgroups 'eshell))
diff --git a/test/lisp/eshell/em-script-tests.el b/test/lisp/eshell/em-script-tests.el
index f77c4568ea8..5ec64ebe089 100644
--- a/test/lisp/eshell/em-script-tests.el
+++ b/test/lisp/eshell/em-script-tests.el
@@ -24,6 +24,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'esh-mode)
(require 'eshell)
(require 'em-script)
@@ -94,4 +95,34 @@ em-script-test/source-script/all-args-var
(eshell-match-command-output (format "source %s a b c" temp-file)
"a\nb\nc\n"))))
+(ert-deftest em-script-test/execute-file ()
+ "FIXME"
+ (ert-with-temp-file temp-file
+ :text "echo hi\necho bye"
+ (with-temp-buffer
+ (with-temp-eshell-settings
+ (eshell-execute-file temp-file nil t))
+ (should (equal (buffer-string) "hibye")))))
+
+(ert-deftest em-script-test/execute-file/args ()
+ "FIXME"
+ (ert-with-temp-file temp-file
+ :text "+ $@*"
+ (with-temp-buffer
+ (with-temp-eshell-settings
+ (eshell-execute-file temp-file '(1 2 3) t))
+ (should (equal (buffer-string) "6")))))
+
+(ert-deftest em-script-test/batch-file ()
+ "FIXME"
+ (ert-with-temp-file temp-file
+ :text (format
+ "#!/usr/bin/env -S %s -Q --batch -f eshell-batch-file\necho hi"
+ (expand-file-name invocation-name invocation-directory))
+ (set-file-modes temp-file #o744)
+ (with-temp-buffer
+ (with-temp-eshell-settings
+ (call-process temp-file nil '(t nil)))
+ (should (equal (buffer-string) "hi\n")))))
+
;; em-script-tests.el ends here
diff --git a/test/lisp/eshell/eshell-tests-helpers.el b/test/lisp/eshell/eshell-tests-helpers.el
index 3f1c55f420d..a15fe611676 100644
--- a/test/lisp/eshell/eshell-tests-helpers.el
+++ b/test/lisp/eshell/eshell-tests-helpers.el
@@ -47,24 +47,30 @@ eshell-tests-remote-accessible-p
(file-directory-p ert-remote-temporary-file-directory)
(file-writable-p ert-remote-temporary-file-directory))))
+(defmacro with-temp-eshell-settings (&rest body)
+ "Configure Eshell to leave no trace behind, and then evaluate BODY."
+ (declare (indent 0))
+ `(ert-with-temp-directory eshell-directory-name
+ (let (;; We want no history file, so prevent Eshell from falling
+ ;; back on $HISTFILE.
+ (process-environment (cons "HISTFILE" process-environment))
+ ;; Enable process debug instrumentation. We may be able to
+ ;; remove this eventually once we're confident that all the
+ ;; process bugs have been worked out. (At that point, we can
+ ;; just enable this selectively when needed.) See also
+ ;; `eshell-test-command-result' below.
+ (eshell-debug-command (cons 'process eshell-debug-command))
+ (eshell-history-file-name nil)
+ (eshell-last-dir-ring-file-name nil)
+ (eshell-module-loading-messages nil))
+ ,@body)))
+
(defmacro with-temp-eshell (&rest body)
"Evaluate BODY in a temporary Eshell buffer."
+ (declare (indent 0))
`(save-current-buffer
- (ert-with-temp-directory eshell-directory-name
- (let* (;; We want no history file, so prevent Eshell from falling
- ;; back on $HISTFILE.
- (process-environment (cons "HISTFILE" process-environment))
- ;; Enable process debug instrumentation. We may be able
- ;; to remove this eventually once we're confident that
- ;; all the process bugs have been worked out. (At that
- ;; point, we can just enable this selectively when
- ;; needed.) See also `eshell-test-command-result'
- ;; below.
- (eshell-debug-command (cons 'process eshell-debug-command))
- (eshell-history-file-name nil)
- (eshell-last-dir-ring-file-name nil)
- (eshell-module-loading-messages nil)
- (eshell-buffer (eshell t)))
+ (with-temp-eshell-settings
+ (let ((eshell-buffer (eshell t)))
(unwind-protect
(with-current-buffer eshell-buffer
,@body)
--
2.25.1
next prev parent reply other threads:[~2024-05-23 20:30 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-09 17:57 bug#70847: 29.3; eshell scripts "from anywhere" Christopher Howard
2024-05-23 20:30 ` Jim Porter [this message]
2024-05-24 14:27 ` Christopher Howard
2024-05-25 2:17 ` Jim Porter
2024-05-28 19:42 ` Christopher Howard
2024-05-28 21:51 ` Jim Porter
2024-05-28 19:46 ` Christopher Howard
2024-05-28 22:49 ` Christopher Howard
2024-05-29 0:31 ` Jim Porter
2024-05-29 14:16 ` Christopher Howard
2024-05-29 19:22 ` Jim Porter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ee947e44-72e8-bc6f-57b3-8e4127f8199f@gmail.com \
--to=jporterbugs@gmail.com \
--cc=70847@debbugs.gnu.org \
--cc=christopher@librehacker.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).