From 7dbf7a39dc545c2ef0a0a49759f9e79c8529272a Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Mon, 21 Oct 2024 14:21:50 -0700 Subject: [PATCH] Fix a race condition when running Eshell startup scripts Previously, these scripts could run before all the Eshell modules had fully-initialized. * lisp/eshell/esh-mode.el (eshell-after-initialize-hook): New hook... (eshell-mode): ... run it. * lisp/eshell/em-script.el (eshell-run-startup-scripts): New function... (eshell-script-initialize): ... add it to 'eshell-after-initialize-hook'. * etc/NEWS: Announce 'eshell-after-initialize-hook'. (cherry picked from commit 605f26cf70ab3d7c5ea635c19cd2a280812a4ddc) --- etc/NEWS | 6 ++++++ lisp/eshell/em-script.el | 34 ++++++++++++++++++---------------- lisp/eshell/esh-mode.el | 6 +++++- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index bda55a049ae..47e01ebb1d2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -226,6 +226,12 @@ By passing '-t' or '--timeout', you can specify a maximum time to wait for the processes to exit. Additionally, you can now wait for external processes by passing their PIDs. +--- +*** New hook 'eshell-after-initialize-hook'. +This hook runs after an Eshell session has been fully initialized, +immediately before running 'eshell-post-command-hook' for the first +time. + ** SHR +++ diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el index 03d9a88e32e..f426afb5d28 100644 --- a/lisp/eshell/em-script.el +++ b/lisp/eshell/em-script.el @@ -68,22 +68,24 @@ This includes when running `eshell-command'." 'eshell/source) eshell-interpreter-alist)) (setq-local eshell-complex-commands - (append '("source" ".") eshell-complex-commands)) - ;; these two variables are changed through usage, but we don't want - ;; to ruin it for other modules - (let (eshell-inside-quote-regexp - eshell-outside-quote-regexp) - (and (not (bound-and-true-p eshell-non-interactive-p)) - eshell-login-script - (file-readable-p eshell-login-script) - (eshell-do-eval - `(eshell-commands ,(eshell--source-file eshell-login-script)) - t)) - (and eshell-rc-script - (file-readable-p eshell-rc-script) - (eshell-do-eval - `(eshell-commands ,(eshell--source-file eshell-rc-script)) - t)))) + (append '("source" ".") eshell-complex-commands)) + ;; Run our startup scripts once this Eshell session has finished + ;; initialization. + (add-hook 'eshell-after-initialize-hook #'eshell-run-startup-scripts 90 t)) + +(defun eshell-run-startup-scripts () + "Run any necessary startup scripts for the current Eshell session." + (when (and (not (bound-and-true-p eshell-non-interactive-p)) + eshell-login-script + (file-readable-p eshell-login-script)) + (eshell-do-eval + `(eshell-commands ,(eshell--source-file eshell-login-script)) + t)) + (when (and eshell-rc-script + (file-readable-p eshell-rc-script)) + (eshell-do-eval + `(eshell-commands ,(eshell--source-file eshell-rc-script)) + t))) (defun eshell--source-file (file &optional args subcommand-p) "Return a Lisp form for executing the Eshell commands in FILE, passing ARGS. diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index ead5a20bec8..37a88fce790 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -90,6 +90,10 @@ That is to say, the first time during an Emacs session." :type 'hook) +(defcustom eshell-after-initialize-hook nil + "A hook that gets run after an Eshell session has been fully initialized." + :type 'hook) + (defcustom eshell-exit-hook nil "A hook that is run whenever `eshell' is exited. This hook is only run if exiting actually kills the buffer." @@ -406,7 +410,7 @@ and the hook `eshell-exit-hook'." (when eshell-first-time-p (setq eshell-first-time-p nil) (run-hooks 'eshell-first-time-mode-hook)) - + (run-hooks 'eshell-after-initialize-hook) (run-hooks 'eshell-post-command-hook)) (put 'eshell-mode 'mode-class 'special) -- 2.39.2