branch: externals/ess commit 2a8c385d20b61c4329b83fac96f30bf85950af58 Author: Lionel Henry <lionel....@gmail.com> Commit: Lionel Henry <lionel....@gmail.com>
Don't enable enriched `ess-command` too early In case initialization fails. Also simplifies things, we no longer need to disable the format command during init. The format command config is now stored in a process property instead of a mode-local variable. --- lisp/ess-inf.el | 49 ++++++++++++++++++++++++++--------------------- lisp/ess-r-mode.el | 50 +++++++++++++++++------------------------------- test/ess-test-r-utils.el | 3 ++- test/ess-test-r.el | 8 +++++++- 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/lisp/ess-inf.el b/lisp/ess-inf.el index 89253037f4..0a07ca744f 100644 --- a/lisp/ess-inf.el +++ b/lisp/ess-inf.el @@ -923,6 +923,10 @@ it was successfully forced, throws an error otherwise." (when ess-local-process-name (get-process ess-local-process-name))) +(defun ess-get-current-process-buffer () + (when-let ((proc (ess-get-current-process))) + (process-buffer proc))) + (defun ess-get-next-available-process (&optional dialect ignore-busy background) "Return first available (aka not busy) process of dialect DIALECT. DIALECT defaults to the local value of ess-dialect. Return nil if @@ -1329,19 +1333,6 @@ This handles Tramp when working on a remote." (user-error "ESS process not ready. Finish your command before trying again"))) proc) -(defvar-local ess-format-command-alist nil - "Alist of mode-specific parameters for formatting a command. -All elements are optional. - -- `fun': A formatting function for running a command. First - argument is the background command to run. Must include a - catch-all `&rest` parameter for extensibility. - -- `use-delimiter' : Whether to wait for an output sentinel. If - non-nil, `fun' should get the `cmd-output-delimiter' element of the - alist of parameters and ensure the sentinel is written to the - process output at the end of the command.") - (defvar inferior-ess--output-delimiter-count 0) (defun inferior-ess--output-delimiter () (setq inferior-ess--output-delimiter-count (1+ inferior-ess--output-delimiter-count)) @@ -1388,15 +1379,16 @@ wrapping the code into: (delim (inferior-ess--output-delimiter)) (timeout (or timeout ess--command-default-timeout))) (with-current-buffer (process-buffer proc) - (let ((proc-forward-alist (ess--alist (ess-local-process-name - inferior-ess-primary-prompt))) - (use-delimiter (alist-get 'use-delimiter ess-format-command-alist)) - (rich-cmd (if-let ((cmd-fun (alist-get 'fun ess-format-command-alist))) - (funcall cmd-fun - (ess--strip-final-newlines cmd) - (cons 'output-delimiter delim)) - cmd)) - (early-exit t)) + (let* ((proc-forward-alist (ess--alist (ess-local-process-name + inferior-ess-primary-prompt))) + (format-command-alist (ess-process-get 'format-command-alist)) + (use-delimiter (alist-get 'use-delimiter format-command-alist)) + (rich-cmd (if-let ((cmd-fun (alist-get 'fun format-command-alist))) + (funcall cmd-fun + (ess--strip-final-newlines cmd) + (cons 'output-delimiter delim)) + cmd)) + (early-exit t)) (ess-if-verbose-write (format "(ess-command '%s' ..)\n" cmd)) ;; Swap the process buffer with the output buffer before ;; sending the command @@ -1462,6 +1454,19 @@ wrapping the code into: (buffer-substring start end))))))))))) out-buffer)) +;; (ess-process-get 'ess-format-command-alist) +;; "Alist of mode-specific parameters for formatting a command. +;; All elements are optional. +;; +;; - `fun': A formatting function for running a command. First +;; argument is the background command to run. Must include a +;; catch-all `&rest` parameter for extensibility. +;; +;; - `use-delimiter' : Whether to wait for an output sentinel. If +;; non-nil, `fun' should get the `cmd-output-delimiter' element of the +;; alist of parameters and ensure the sentinel is written to the +;; process output at the end of the command." + (defun ess--command-make-restore-function (proc) (let ((old-pf (process-filter proc))) (lambda () diff --git a/lisp/ess-r-mode.el b/lisp/ess-r-mode.el index e3648c780e..305fc36b89 100644 --- a/lisp/ess-r-mode.el +++ b/lisp/ess-r-mode.el @@ -442,7 +442,6 @@ To be used as part of `font-lock-defaults' keywords." '((ess-local-customize-alist . 'ess-r-customize-alist) (ess-dialect . "R") (ess-suffix . "R") - (ess-format-command-alist . ess-r-format-command-alist) (ess-traceback-command . ess-r-traceback-command) (ess-call-stack-command . ess-r-call-stack-command) (ess-mode-completion-syntax-table . ess-r-completion-syntax-table) @@ -629,17 +628,6 @@ will be prompted to enter arguments interactively." (defun inferior-ess-r--init-callback (_proc _name) (ess-r-initialize)) -(defmacro ess-r--without-format-command (&rest body) - (declare (indent 0) - (debug (&rest form))) - `(with-current-buffer (process-buffer (ess-command--get-proc nil nil)) - (let ((old-alist ess-format-command-alist)) - (unwind-protect - (progn - (setq ess-format-command-alist nil) - ,@body) - (setq ess-format-command-alist old-alist))))) - (defvar ess-r--init-timeout 5 "Maximum time for R to become available on startup. If the timeout is reached, an error is thrown advising the user @@ -654,13 +642,12 @@ Executed in process buffer." (progn (unless (ess-wait-for-process nil nil nil nil ess-r--init-timeout) (error "Process is busy")) - (ess-r--without-format-command - (ess-command (ess-r--init-options-command)) - ;; TODO: Detect early exits on the R side and communicate - ;; them to lisp - (ess-r-load-ESSR))) + (ess-command (ess-r--init-options-command)) + (ess-r-load-ESSR)) (error (ess-r--init-error-handler err)) (quit (ess-r--init-error-handler))) + (ess-process-put 'format-command-alist ess-r-format-command-alist) + (ess-process-put 'bg-eval-disabled nil) (ess-execute-screen-options t) (ess-set-working-directory default-directory) (when ess-use-tracebug @@ -1559,21 +1546,20 @@ process." ;; `.ess.command()` is not defined until ESSR is loaded so disable ;; it temporarily. Would be helpful to implement an `inferior-ess-let' ;; macro . - (ess-r--without-format-command - (cond - ((file-remote-p (ess-get-process-variable 'default-directory)) - (if (eq ess-r-fetch-ESSR-on-remotes t) - (or (ess-r--fetch-ESSR-remote) - (ess-r--load-ESSR-remote)) - (ess-r--load-ESSR-remote))) - ((and (bound-and-true-p ess-remote)) - ;; NB: With ess-remote we send by chunks because sending large sources is - ;; fragile - (if ess-r-fetch-ESSR-on-remotes - (or (ess-r--fetch-ESSR-remote) - (ess-r--load-ESSR-remote t)) - (ess-r--load-ESSR-remote t))) - (t (ess-r--load-ESSR-local))))) + (cond + ((file-remote-p (ess-get-process-variable 'default-directory)) + (if (eq ess-r-fetch-ESSR-on-remotes t) + (or (ess-r--fetch-ESSR-remote) + (ess-r--load-ESSR-remote)) + (ess-r--load-ESSR-remote))) + ((and (bound-and-true-p ess-remote)) + ;; NB: With ess-remote we send by chunks because sending large sources is + ;; fragile + (if ess-r-fetch-ESSR-on-remotes + (or (ess-r--fetch-ESSR-remote) + (ess-r--load-ESSR-remote t)) + (ess-r--load-ESSR-remote t))) + (t (ess-r--load-ESSR-local)))) (defun ess-r--load-ESSR-local () "Load ESSR into a local process. diff --git a/test/ess-test-r-utils.el b/test/ess-test-r-utils.el index 48fbb8328e..432796300e 100644 --- a/test/ess-test-r-utils.el +++ b/test/ess-test-r-utils.el @@ -335,6 +335,7 @@ Note that if `ess--essr-detach' is successful then it is critical that we don't run `ess--essr-remove-global-objs' because .ess.command doesn't exist in the R runtime environment (and which is relied upon by `ess-command')." + (ess-process-put 'format-command-alist nil) (or (ess--essr-detach) (ess--essr-remove-global-objs))) @@ -372,7 +373,7 @@ Throws an error if unsuccesful." ;; global environment (ess--essr-remove) ;; inject environment and attach - (ess-r--without-format-command (funcall ess-r--load-ESSR-fcn)) + (funcall ess-r--load-ESSR-fcn) ;; check for successful ESSR injection (should (not (ess--essr-check-if-in-globalenv))) (should (ess--essr-check-if-attached)) diff --git a/test/ess-test-r.el b/test/ess-test-r.el index e138771347..62dd414219 100644 --- a/test/ess-test-r.el +++ b/test/ess-test-r.el @@ -919,7 +919,13 @@ https://github.com/emacs-ess/ESS/issues/725#issuecomment-431781558" (with-current-buffer inferior-ess--last-started-process-buffer (should (string-match-p "Loading failed with a nice message." (caddr err))) - (should (not (ess-can-eval-in-background)))))) + (should (not (ess-can-eval-in-background))) + (should (not (ess-process-get 'format-command-alist))) + (ess-send-string (ess-get-current-process) "Sys.unsetenv('ESSR_TEST_LOAD_ERROR')\n") + ;; Can recover manually + (ess-r-initialize) + (should (ess-can-eval-in-background)) + (should (ess-process-get 'format-command-alist))))) (setenv "ESSR_TEST_LOAD_ERROR" nil))) (etest-deftest ess-r-command-error-test ()