branch: externals/ess commit 19724bbe35f21a0a14be86ed436d28702813c055 Author: Lionel Henry <lionel....@gmail.com> Commit: Lionel Henry <lionel....@gmail.com>
Qualify ESSR commands with namespace --- doc/newfeat.texi | 4 ++++ lisp/ess-r-mode.el | 35 +++++++++++++++++++++++------------ test/ess-test-inf.el | 25 +++++++++++++++++++++++++ test/ess-test-r.el | 12 ++++++------ 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/doc/newfeat.texi b/doc/newfeat.texi index f53df308a9..54315c7580 100644 --- a/doc/newfeat.texi +++ b/doc/newfeat.texi @@ -4,6 +4,10 @@ Changes and New Features in 19.04 (unreleased): @itemize @bullet +@item ESS[R]: ESSR commands are now more robust when ESSR is +not in scope. This can happen when using @code{browser()} in +an environment that doesn't inherit from the search path. + @item ESS[R]: Unexpected exits are now detected during startup. In that case an error is thrown with advice about how to recover. diff --git a/lisp/ess-r-mode.el b/lisp/ess-r-mode.el index 244daa044a..6a638328b4 100644 --- a/lisp/ess-r-mode.el +++ b/lisp/ess-r-mode.el @@ -480,7 +480,7 @@ fill=TRUE); try(traceback(), silent=TRUE)})\n") (defun ess-r-format-command (cmd &rest args) (let ((sentinel (alist-get 'output-delimiter args))) - (format ".ess.command(local(%s), '%s')\n" cmd sentinel))) + (ess-r--format-call ".ess.command(local(%s), '%s')\n" cmd sentinel))) (defvar ess-r-format-command-alist '((fun . ess-r-format-command) @@ -1093,7 +1093,8 @@ returned." (defun ess-current-R-version () "Get the version of R currently running in the ESS buffer as a string." (ess-make-buffer-current) - (car (ess-get-words-from-vector "as.character(.ess.Rversion)\n"))) + (car (ess-get-words-from-vector (format "base::as.character(%s)\n" + (ess-r--format-call ".ess.Rversion"))))) (defun ess-current-R-at-least (version) "Is the version of R (in the ESS buffer) at least (\">=\") VERSION ? @@ -1102,7 +1103,9 @@ Examples: (ess-current-R-at-least '2.7.0) (ess-make-buffer-current) (string= "TRUE" (car (ess-get-words-from-vector - (format "as.character(.ess.Rversion >= \"%s\")\n" version))))) + (format "base::as.character(%s >= \"%s\")\n" + (ess-r--format-call ".ess.Rversion") + version))))) (defun ess-find-newest-date (rvers) "Find the newest version of R given in the a-list RVERS. Each element of RVERS is a dotted pair (date . R-version), where @@ -1306,13 +1309,19 @@ Placed into `ess-presend-filter-functions' for R dialects." (ess-r-arg "verbose" "TRUE")))) (concat visibly output pkg verbose))) +(defun ess-r--format-call (cmd &rest objects) + "Prefix an ESSR command with a namespace qualifier. +CMD is formatted with OBJECTS using `format'." + (concat "base::as.environment('ESSR')$" + (apply #'format cmd objects))) + (cl-defmethod ess-build-eval-command--override (string &context (ess-dialect "R") &optional visibly output file &rest args) "R method to build eval command." (let* ((namespace (caar args)) (namespace (unless ess-debug-minor-mode (or namespace (ess-r-get-evaluation-env)))) - (cmd (if namespace ".ess.ns_eval" ".ess.eval")) + (cmd (ess-r--format-call (if namespace ".ess.ns_eval" ".ess.eval"))) (file (when file (ess-r-arg "file" file t))) (rargs (ess-r-build-args visibly output namespace))) (concat cmd "(\"" string "\"" rargs file ")\n"))) @@ -1320,7 +1329,7 @@ Placed into `ess-presend-filter-functions' for R dialects." (cl-defmethod ess-build-load-command (string &context (ess-dialect "R") &optional visibly output file &rest _args) (let* ((namespace (or file (ess-r-get-evaluation-env))) - (cmd (if namespace ".ess.ns_source" ".ess.source")) + (cmd (ess-r--format-call (if namespace ".ess.ns_source" ".ess.source"))) (rargs (ess-r-build-args visibly output namespace))) (concat cmd "('" string "'" rargs ")\n"))) @@ -1443,7 +1452,7 @@ selected (see `ess-r-set-evaluation-env')." (setq ess-r-help--local-object obj) (let ((obj-arg (concat "'" obj "'")) (pkg-arg (ess-r-arg "package" pkg t))) - (concat ".ess.help(" obj-arg pkg-arg ")\n"))) + (ess-r--format-call ".ess.help(%s%s)\n" obj-arg pkg-arg))) (defun ess-r-help--build-help-command--unqualified (obj) (if (eq ess-help-type 'index) @@ -1572,11 +1581,12 @@ Source the etc/ESSR/.load.R file into the R process. The etc/ESSR/R directory into the ESSR environment and attaches the environment to the search path." (let* ((src-dir (expand-file-name "ESSR/R" ess-etc-directory)) - (cmd (format "local({ - source('%s/.load.R', local=TRUE) #define load.ESSR + (cmd (format "base::local({ + base::source('%s/.load.R', local=TRUE) #define load.ESSR .ess.ESSR.load('%s') })\n" - src-dir src-dir))) + src-dir + src-dir))) (with-current-buffer (ess-command cmd) (let ((msg (buffer-string))) (when (> (length msg) 1) @@ -2566,9 +2576,10 @@ state.") "Add links to the help buffer." (let ((links (when (ess-process-live-p) (ess-get-words-from-vector - (format ".ess.helpLinks('%s' %s)\n" - ess-r-help--local-object - (ess-r-arg "package" ess-r-help--local-package t))))) + (ess-r--format-call + ".ess.helpLinks('%s' %s)\n" + ess-r-help--local-object + (ess-r-arg "package" ess-r-help--local-package t))))) (inhibit-read-only t)) (save-excursion ;; Search for fancy quotes only. If users have diff --git a/test/ess-test-inf.el b/test/ess-test-inf.el index 54a28fcbe8..22f4800680 100644 --- a/test/ess-test-inf.el +++ b/test/ess-test-inf.el @@ -163,6 +163,31 @@ Browse[1]> " :inf-result "NULL Browse[1]> ") +(etest-deftest ess--command-browser-unscoped-essr () + "`ess-command' when ESSR is not in scope." + :cleanup (ess-test--browser-cleanup) + (ess-send-string (ess-get-process) "evalq({ browser(); NULL }, baseenv())\n") + (ess-test--browser) + :inf-result "Called from: evalq({ + browser() + NULL +}, baseenv()) +Browse[1]> debug at #1: browser() +Browse[3]> Browse[3]> " + + (should (equal (ess-get-words-from-vector "'foo'\n") + '("foo"))) + + ;; No impact on inferior + :inf-result "" + (should (inferior-ess-available-p)) + + ;; We're still in the browser + (ess-send-string (ess-get-process) "NULL\n") + (ess-wait-for-process) + :inf-result "NULL +Browse[3]> ") + (etest-deftest ess-command-browser-curly-braces () "`{` expressions when debugger is active do not interrupt command." :cleanup (ess-test--browser-cleanup) diff --git a/test/ess-test-r.el b/test/ess-test-r.el index 04ddc6b700..cb5896c0a3 100644 --- a/test/ess-test-r.el +++ b/test/ess-test-r.el @@ -49,20 +49,20 @@ (let ((command "command(\"string\")") (ess-dialect "R")) (should (string= (ess-build-eval-command command) - ".ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = FALSE)\n")) + "base::as.environment('ESSR')$.ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = FALSE)\n")) (should (string= (ess-build-eval-command command nil t) - ".ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = TRUE)\n")) + "base::as.environment('ESSR')$.ess.eval(\"command(\\\"string\\\")\", visibly = FALSE, output = TRUE)\n")) (should (string= (ess-build-eval-command command t t "file.ext" "foo") - ".ess.ns_eval(\"command(\\\"string\\\")\", visibly = TRUE, output = TRUE, package = 'foo', verbose = TRUE, file = 'file.ext')\n")))) + "base::as.environment('ESSR')$.ess.ns_eval(\"command(\\\"string\\\")\", visibly = TRUE, output = TRUE, package = 'foo', verbose = TRUE, file = 'file.ext')\n")))) (ert-deftest ess-build-load-command-R-test () (let ((ess-dialect "R")) (should (string= (ess-build-load-command "file.ext") - ".ess.source('file.ext', visibly = FALSE, output = FALSE)\n")) + "base::as.environment('ESSR')$.ess.source('file.ext', visibly = FALSE, output = FALSE)\n")) (should (string= (ess-build-load-command "file.ext" t t) - ".ess.source('file.ext', visibly = TRUE, output = TRUE)\n")) + "base::as.environment('ESSR')$.ess.source('file.ext', visibly = TRUE, output = TRUE)\n")) (should (string= (ess-build-load-command "file.ext" nil t "foo") - ".ess.ns_source('file.ext', visibly = FALSE, output = TRUE, package = 'foo', verbose = TRUE)\n")))) + "base::as.environment('ESSR')$.ess.ns_source('file.ext', visibly = FALSE, output = TRUE, package = 'foo', verbose = TRUE)\n")))) (ert-deftest inferior-ess-inherits-from-comint-test () (let ((inhibit-message ess-inhibit-message-in-tests))