update of packages
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
;;; ess-inf.el --- Support for running S as an inferior Emacs process -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 1989-2022 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 1989-2023 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: David Smith <dsmith@stats.adelaide.edu.au>
|
||||
;; Created: 7 Jan 1994
|
||||
@@ -103,7 +103,8 @@ been initialized."
|
||||
(progn
|
||||
(setq-local inferior-ess-mode-syntax-table
|
||||
(eval (or (alist-get 'inferior-ess-mode-syntax-table ess-local-customize-alist)
|
||||
(alist-get 'ess-mode-syntax-table ess-local-customize-alist))))
|
||||
(alist-get 'ess-mode-syntax-table ess-local-customize-alist))
|
||||
t))
|
||||
(inferior-ess-mode)))))
|
||||
|
||||
;;*;; Process handling
|
||||
@@ -129,6 +130,11 @@ If `ess-plain-first-buffername', then initial process is number-free."
|
||||
(defvar-local inferior-ess--local-data nil
|
||||
"Program name and arguments used to start the inferior process.")
|
||||
|
||||
(defvar inferior-ess--last-started-process-buffer nil
|
||||
"Useful in unit tests to check initialisation errors.
|
||||
In that case the command fails before it can return the process
|
||||
buffer to us. This global variable can be checked instead.")
|
||||
|
||||
(defun inferior-ess (start-args customize-alist &optional no-wait)
|
||||
"Start inferior ESS process.
|
||||
Without a prefix argument, starts a new ESS process, or switches
|
||||
@@ -160,7 +166,7 @@ This may be useful for debugging."
|
||||
;; This function is primarily used to figure out the Process and
|
||||
;; buffer names to use for inferior-ess.
|
||||
(run-hooks 'ess-pre-run-hook)
|
||||
(let* ((dialect (eval (cdr (assoc 'ess-dialect customize-alist))))
|
||||
(let* ((dialect (eval (cdr (assoc 'ess-dialect customize-alist)) t))
|
||||
(process-environment process-environment)
|
||||
;; Use dialect if not R, R program name otherwise
|
||||
(temp-dialect (if ess-use-inferior-program-in-buffer-name ;VS[23-02-2013]: FIXME: this should not be here
|
||||
@@ -202,15 +208,14 @@ This may be useful for debugging."
|
||||
(ess-wait-for-process proc nil 0.01 t))
|
||||
(unless (and proc (eq (process-status proc) 'run))
|
||||
(error "Process %s failed to start" proc-name))
|
||||
(when ess-setwd-command
|
||||
(ess-set-working-directory default-directory))
|
||||
(setq-local font-lock-fontify-region-function #'inferior-ess-fontify-region)
|
||||
(setq-local ess-sl-modtime-alist nil)
|
||||
(run-hooks 'ess-post-run-hook)
|
||||
;; User initialization can take some time ...
|
||||
(unless no-wait
|
||||
(ess-write-to-dribble-buffer "(inferior-ess 3): waiting for process after hook")
|
||||
(ess-write-to-dribble-buffer "(inferior-ess): waiting for process (after hook)\n")
|
||||
(ess-wait-for-process proc)))
|
||||
(setq inferior-ess--last-started-process-buffer inf-buf)
|
||||
inf-buf)))
|
||||
|
||||
(defun inferior-ess--get-proc-buffer-create (name)
|
||||
@@ -288,7 +293,6 @@ Default depends on the ESS language/dialect and hence made buffer local")
|
||||
BEG and END signify the bounds, VERBOSE gets passed to
|
||||
`font-lock-default-fontify-region'."
|
||||
(let* ((buffer-undo-list t)
|
||||
(inhibit-point-motion-hooks t)
|
||||
(font-lock-dont-widen t)
|
||||
(font-lock-extend-region-functions nil)
|
||||
(pos1 beg)
|
||||
@@ -356,14 +360,13 @@ defined. If no project directory has been found, use
|
||||
;; This ensures that people who have this set in their init file don't
|
||||
;; get errors about undefined functions after upgrading ESS:
|
||||
(define-obsolete-function-alias 'ess-gen-proc-buffer-name:projectile-or-simple
|
||||
'ess-gen-proc-buffer-name:project-or-simple "ESS 19.04")
|
||||
#'ess-gen-proc-buffer-name:project-or-simple "ESS 19.04")
|
||||
(define-obsolete-function-alias 'ess-gen-proc-buffer-name:projectile-or-directory
|
||||
'ess-gen-proc-buffer-name:project-or-directory "ESS 19.04")
|
||||
#'ess-gen-proc-buffer-name:project-or-directory "ESS 19.04")
|
||||
|
||||
(defun inferior-ess-available-p (&optional proc)
|
||||
"Return non-nil if PROC is not busy."
|
||||
(when-let ((proc (or proc (and ess-local-process-name
|
||||
(get-process ess-local-process-name)))))
|
||||
(when-let ((proc (or proc (ess-get-current-process))))
|
||||
(unless (process-get proc 'busy)
|
||||
(or (ess-debug-active-p proc) ; don't send empty lines in debugger
|
||||
(when-let ((last-check (process-get proc 'last-availability-check)))
|
||||
@@ -478,10 +481,16 @@ inserted in the process buffer instead of the command buffer."
|
||||
(process-put proc 'busy nil))))
|
||||
|
||||
(defun ess--delimiter-start-re (delim)
|
||||
(concat "\\(" delim "-START$\\)"))
|
||||
(concat "\\(" delim "-START\r*$\\)"))
|
||||
|
||||
(defun ess--delimiter-end-re (delim)
|
||||
(concat "\\(" delim "-END\\)"))
|
||||
(concat "\\(" delim "-END\r*\\)"))
|
||||
|
||||
(defun ess--delimiter-error-start-re ()
|
||||
"ESSR::ERROR \\(\"\\)")
|
||||
|
||||
(defun ess--delimiter-error-end-re ()
|
||||
"\\(\"\\)")
|
||||
|
||||
(defun inferior-ess-mark-as-busy (proc)
|
||||
"Put PROC's busy value to t."
|
||||
@@ -518,8 +527,9 @@ inserted in the process buffer instead of the command buffer."
|
||||
--> busy:%s busy-end:%s sec-prompt:%s interruptable:%s <--
|
||||
--> running-async:%s callback:%s suppress-next-output:%s <--
|
||||
--> dbg-active:%s is-recover:%s <--
|
||||
--> string:%s\n"
|
||||
(or filter "NORMAL-FILTER")
|
||||
--> cmd-buffer:%s cmd-output-delimiter:%s <--
|
||||
--> string:%s<--\n"
|
||||
(upcase (or filter "normal-filter"))
|
||||
(process-get proc 'busy)
|
||||
(process-get proc 'busy-end?)
|
||||
(process-get proc 'sec-prompt)
|
||||
@@ -529,6 +539,8 @@ inserted in the process buffer instead of the command buffer."
|
||||
(process-get proc 'suppress-next-output?)
|
||||
(process-get proc 'dbg-active)
|
||||
(process-get proc 'is-recover)
|
||||
(process-get proc 'cmd-buffer)
|
||||
(process-get proc 'cmd-output-delimiter)
|
||||
(if (> (length string) 150)
|
||||
(format "%s .... %s" (substring string 0 50) (substring string -50))
|
||||
string))))
|
||||
@@ -608,8 +620,8 @@ process-less buffer because it was created with
|
||||
(split-string switches))))
|
||||
(let ((proc (get-buffer-process buf)))
|
||||
;; Set the process hooks
|
||||
(set-process-sentinel proc 'ess-process-sentinel)
|
||||
(set-process-filter proc 'inferior-ess-output-filter)
|
||||
(set-process-sentinel proc #'ess-process-sentinel)
|
||||
(set-process-filter proc #'inferior-ess-output-filter)
|
||||
(inferior-ess-mark-as-busy proc)
|
||||
;; Add this process to ess-process-name-list, if needed
|
||||
(let ((conselt (assoc proc-name ess-process-name-list)))
|
||||
@@ -640,7 +652,9 @@ the name of the inferior process (e.g. \"R:1\"), and DIALECT is
|
||||
the language dialect (e.g. \"R\")."
|
||||
(let ((default-dir (inferior-ess--get-startup-directory)))
|
||||
(if ess-ask-for-ess-directory
|
||||
(let ((prompt (format "%s starting project directory? " procname)))
|
||||
(let ((prompt (format "%s starting project directory? " procname))
|
||||
(display-buffer-overriding-action nil) ; hack to let helm display a buffer
|
||||
)
|
||||
(ess-prompt-for-directory default-dir prompt))
|
||||
default-dir)))
|
||||
|
||||
@@ -668,7 +682,7 @@ local ESS vars like `ess-local-process-name'."
|
||||
(,dialect ess-dialect)
|
||||
(,alist ess-local-customize-alist))
|
||||
(with-current-buffer ,buffer
|
||||
(ess-setq-vars-local (eval ,alist))
|
||||
(ess-setq-vars-local (eval ,alist t))
|
||||
(setq ess-local-process-name ,lpn)
|
||||
(setq ess-dialect ,dialect)
|
||||
,@body))))
|
||||
@@ -754,10 +768,8 @@ Returns the name of the process, or nil if the current buffer has none."
|
||||
"Check if the local ess process is alive.
|
||||
Return nil if current buffer has no associated process, or
|
||||
process was killed. PROC defaults to `ess-local-process-name'"
|
||||
(and (or proc ess-local-process-name)
|
||||
(let ((proc (or proc (get-process ess-local-process-name))))
|
||||
(and (processp proc)
|
||||
(process-live-p proc)))))
|
||||
(when-let ((proc (or proc (ess-get-current-process))))
|
||||
(process-live-p proc)))
|
||||
|
||||
(defun ess-process-get (propname &optional proc)
|
||||
"Return the variable PROPNAME (symbol) of the current ESS process.
|
||||
@@ -830,8 +842,10 @@ to `ess-completing-read'."
|
||||
'ess-dialect
|
||||
(process-buffer (get-process
|
||||
(car pname-list))))))))
|
||||
;; try to start "the appropriate" process, don't show the buffer
|
||||
;; Try to start "the appropriate" process, don't show the buffer
|
||||
;; since we handle that explicitly with no-switch
|
||||
(ess-if-verbose-write
|
||||
"ess-request-a-process: Can't find a process, starting a new one\n")
|
||||
(ess--with-no-pop-to-buffer
|
||||
(ess-start-process-specific ess-language ess-dialect))
|
||||
(setq num-processes 1
|
||||
@@ -857,6 +871,8 @@ to `ess-completing-read'."
|
||||
;; Prevent new process buffer from being popped
|
||||
;; because we handle display depending on the value
|
||||
;; of `no-switch`
|
||||
(ess-if-verbose-write
|
||||
"ess-request-a-process: User requested a new process\n")
|
||||
(ess--with-no-pop-to-buffer
|
||||
(ess-start-process-specific ess-language ess-dialect))
|
||||
(caar ess-process-name-list))))))
|
||||
@@ -866,7 +882,12 @@ to `ess-completing-read'."
|
||||
(let ((proc-buf (ess-get-process-buffer proc)))
|
||||
(if noswitch
|
||||
(display-buffer proc-buf)
|
||||
(pop-to-buffer proc-buf))))
|
||||
(pop-to-buffer proc-buf))
|
||||
;; If inferior startup has already finished, set screen
|
||||
;; options again in case the post-run hook ran before a new
|
||||
;; screen config was created by `pop-to-buffer' (#1243).
|
||||
(with-current-buffer proc-buf
|
||||
(ess--execute-screen-options-bg))))
|
||||
proc))
|
||||
|
||||
(defun ess-force-buffer-current (&optional prompt force no-autostart ask-if-1)
|
||||
@@ -900,26 +921,50 @@ it was successfully forced, throws an error otherwise."
|
||||
(interactive)
|
||||
(ess-force-buffer-current "Process to use: " 'force nil 'ask-if-1))
|
||||
|
||||
(defun ess-get-next-available-process (&optional dialect ignore-busy)
|
||||
(defun ess-get-current-process ()
|
||||
(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
|
||||
no such process has been found."
|
||||
no such process has been found. If BACKGROUND is non-nil, only
|
||||
processes that are allowed to evaluate in the background are
|
||||
matched."
|
||||
(setq dialect (or dialect ess-dialect))
|
||||
(when dialect
|
||||
(when (and dialect (or (not background)
|
||||
ess-can-eval-in-background))
|
||||
(let (proc)
|
||||
(catch 'found
|
||||
(dolist (p (cons ess-local-process-name
|
||||
(mapcar 'car ess-process-name-list)))
|
||||
(mapcar #'car ess-process-name-list)))
|
||||
(when p
|
||||
(setq proc (get-process p))
|
||||
(when (and proc
|
||||
(process-live-p proc)
|
||||
(equal dialect
|
||||
(buffer-local-value 'ess-dialect (process-buffer proc)))
|
||||
;; Check that we can evaluate in background
|
||||
;; before checking for availability to
|
||||
;; avoid issues with newline handshakes
|
||||
(or (not background)
|
||||
(ess-can-eval-in-background proc))
|
||||
(or ignore-busy
|
||||
(inferior-ess-available-p proc)))
|
||||
(throw 'found proc))))))))
|
||||
|
||||
(defun ess-get-next-available-bg-process (&optional proc dialect ignore-busy)
|
||||
"Returns first avaiable process only if background evaluations are allowed.
|
||||
Same as `ess-get-next-available-process' but checks for
|
||||
`ess-can-eval-in-background'."
|
||||
(if proc
|
||||
(ess-can-eval-in-background proc)
|
||||
(ess-get-next-available-process dialect ignore-busy 'background)))
|
||||
|
||||
|
||||
;;*;;; Commands for switching to the process buffer
|
||||
|
||||
@@ -1049,38 +1094,42 @@ Returns nil if TIMEOUT was reached, non-nil otherwise."
|
||||
(setq wait .3))))
|
||||
(< elapsed timeout)))
|
||||
|
||||
;; This filter is active under `ess-command`
|
||||
(defun inferior-ess-ordinary-filter (proc string)
|
||||
(ess--if-verbose-write-process-state proc string "ordinary-filter")
|
||||
(let* ((cmd-buf (process-get proc 'cmd-buffer))
|
||||
(cmd-delim (process-get proc 'cmd-output-delimiter))
|
||||
(early-exit t))
|
||||
(cmd-delim (process-get proc 'cmd-output-delimiter)))
|
||||
(when (buffer-live-p cmd-buf)
|
||||
(unwind-protect
|
||||
(ess--exit-protect
|
||||
(progn
|
||||
(with-current-buffer cmd-buf
|
||||
(goto-char (point-max))
|
||||
(insert string))
|
||||
(when-let ((info (if cmd-delim
|
||||
(ess--command-delimited-output-info cmd-buf cmd-delim)
|
||||
(ess--command-output-info cmd-buf))))
|
||||
(let ((new-output (ess--command-set-status proc cmd-buf info)))
|
||||
(when (not (process-get proc 'busy))
|
||||
;; Store new output until restoration
|
||||
(when new-output
|
||||
(process-put proc 'pending-output new-output))
|
||||
;; Restore the user's process filter as soon as process is
|
||||
;; available
|
||||
(funcall (process-get proc 'cmd-restore-function))
|
||||
;; Run callback with command output
|
||||
(when (process-get proc 'callbacks)
|
||||
(inferior-ess-run-callback proc (with-current-buffer cmd-buf
|
||||
(buffer-string)))))))
|
||||
(setq early-exit nil))
|
||||
(if-let ((info (if cmd-delim
|
||||
(ess--command-delimited-output-info cmd-buf cmd-delim)
|
||||
(ess--command-output-info cmd-buf))))
|
||||
(let ((new-output (ess--command-set-status proc cmd-buf info)))
|
||||
(ess-if-verbose-write
|
||||
"ess-command (filter): Found prompt\n")
|
||||
(when (not (process-get proc 'busy))
|
||||
;; Store new output until restoration
|
||||
(when new-output
|
||||
(process-put proc 'pending-output new-output))
|
||||
;; Restore the user's process filter as soon as process is
|
||||
;; available
|
||||
(funcall (process-get proc 'cmd-restore-function))
|
||||
;; Run callback with command output
|
||||
(when (process-get proc 'callbacks)
|
||||
(inferior-ess-run-callback proc (with-current-buffer cmd-buf
|
||||
(buffer-string))))))
|
||||
(ess-if-verbose-write
|
||||
"ess-command (filter): Accumulating output\n")))
|
||||
;; Be defensive when something goes wrong. Restore process to a
|
||||
;; usable state.
|
||||
(when early-exit
|
||||
(process-put proc 'busy nil)
|
||||
(funcall (process-get proc 'cmd-restore-function)))))))
|
||||
(ess-if-verbose-write
|
||||
"ess-command (filter): Early exit\n")
|
||||
(process-put proc 'busy nil)
|
||||
(funcall (process-get proc 'cmd-restore-function))))))
|
||||
|
||||
(defvar ess-presend-filter-functions nil
|
||||
"List of functions to call before sending the input string to the process.
|
||||
@@ -1154,7 +1203,7 @@ Hide all the junk output in temporary buffer."
|
||||
;; this is to avoid putting junk in user's buffer on process
|
||||
;; interruption
|
||||
(set-process-buffer proc buf)
|
||||
(set-process-filter proc 'inferior-ess-ordinary-filter)
|
||||
(set-process-filter proc #'inferior-ess-ordinary-filter)
|
||||
(interrupt-process proc)
|
||||
(when cb
|
||||
(ess-if-verbose-write "executing interruption callback ... ")
|
||||
@@ -1286,19 +1335,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))
|
||||
@@ -1345,71 +1381,112 @@ 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))
|
||||
(ess-if-verbose-write (format "(ess-command %s ..)" cmd))
|
||||
(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
|
||||
(unwind-protect
|
||||
(progn
|
||||
;; The process is restored from the filter once it's
|
||||
;; available again (i.e. a prompt or delimiter is
|
||||
;; detected). This handles the synchronous case when the
|
||||
;; command runs to completion, as well as the
|
||||
;; asynchronous case when an early exit occurs. The most
|
||||
;; common cause of early exits are interrupts sent by
|
||||
;; Emacs when the user types (see `when-no-input'). In
|
||||
;; these cases we forward the interrupt to the process
|
||||
;; and return to the caller right away. We can't restore
|
||||
;; synchronously after an interrupt because the output
|
||||
;; of the background command would spill into the
|
||||
;; process buffer of the user when the process doesn't
|
||||
;; interrupt in time.
|
||||
(process-put proc 'cmd-restore-function
|
||||
(ess--command-make-restore-function proc))
|
||||
(when use-delimiter
|
||||
(process-put proc 'cmd-output-delimiter delim))
|
||||
(process-put proc 'cmd-buffer out-buffer)
|
||||
(set-process-filter proc 'inferior-ess-ordinary-filter)
|
||||
(with-current-buffer out-buffer
|
||||
(ess-setq-vars-local proc-forward-alist)
|
||||
(setq buffer-read-only nil)
|
||||
(erase-buffer)
|
||||
(inferior-ess-mark-as-busy proc)
|
||||
(process-send-string proc rich-cmd)
|
||||
;; Need time for ess-create-object-name-db on PC
|
||||
(if no-prompt-check
|
||||
(sleep-for 0.02) ; 0.1 is noticeable!
|
||||
(unless (ess-wait-for-process proc nil wait force-redisplay timeout)
|
||||
(error "Timeout during background ESS command `%s'"
|
||||
(ess--strip-final-newlines cmd)))))
|
||||
(setq early-exit nil))
|
||||
(when early-exit
|
||||
;; Protect process interruption from further quits
|
||||
(let ((inhibit-quit t))
|
||||
;; In case of early exit send an interrupt to the
|
||||
;; process to abort the command
|
||||
(with-current-buffer out-buffer
|
||||
(goto-char (point-min))
|
||||
(when (and use-delimiter
|
||||
(not (re-search-forward (ess--delimiter-start-re delim) nil t)))
|
||||
;; CMD probably failed to parse if the start delimiter
|
||||
;; can't be found in the output. Disable the delimiter
|
||||
;; before interrupt to avoid a freeze.
|
||||
(ess-write-to-dribble-buffer
|
||||
"Disabling output delimiter because CMD failed to parse")
|
||||
(process-put proc 'cmd-output-delimiter nil))
|
||||
(goto-char (point-max))
|
||||
(ess--interrupt proc)))))))
|
||||
(condition-case err
|
||||
(progn
|
||||
;; The process is restored from the filter once it's
|
||||
;; available again (i.e. a prompt or delimiter is
|
||||
;; detected). This handles the synchronous case when the
|
||||
;; command runs to completion, as well as the
|
||||
;; asynchronous case when an early exit occurs. The most
|
||||
;; common cause of early exits are interrupts sent by
|
||||
;; Emacs when the user types (see `when-no-input'). In
|
||||
;; these cases we forward the interrupt to the process
|
||||
;; and return to the caller right away. We can't restore
|
||||
;; synchronously after an interrupt because the output
|
||||
;; of the background command would spill into the
|
||||
;; process buffer of the user when the process doesn't
|
||||
;; interrupt in time.
|
||||
(process-put proc 'cmd-restore-function
|
||||
(ess--command-make-restore-function proc))
|
||||
(when use-delimiter
|
||||
(process-put proc 'cmd-output-delimiter delim))
|
||||
(process-put proc 'cmd-buffer out-buffer)
|
||||
(set-process-filter proc #'inferior-ess-ordinary-filter)
|
||||
(with-current-buffer out-buffer
|
||||
(ess-setq-vars-local proc-forward-alist)
|
||||
(setq buffer-read-only nil)
|
||||
(erase-buffer)
|
||||
(inferior-ess-mark-as-busy proc)
|
||||
(process-send-string proc rich-cmd)
|
||||
;; Need time for ess-create-object-name-db on PC
|
||||
(if no-prompt-check
|
||||
(sleep-for 0.02) ; 0.1 is noticeable!
|
||||
(unless (ess-wait-for-process proc nil wait force-redisplay timeout)
|
||||
(error "Timeout during background ESS command `%s'"
|
||||
(ess--strip-final-newlines cmd))))
|
||||
(setq early-exit nil)))
|
||||
(error (setq early-exit err))
|
||||
(quit (setq early-exit err)))
|
||||
(if early-exit
|
||||
(ess--command-error-handler proc out-buffer use-delimiter delim early-exit)
|
||||
(with-current-buffer out-buffer
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward (ess--delimiter-error-start-re) nil t)
|
||||
(let ((start (1+ (match-beginning 1))))
|
||||
(when (re-search-forward (ess--delimiter-error-end-re) nil t)
|
||||
(let ((end (match-beginning 1)))
|
||||
(error "R error during background ESS command `%s'\nError: %s"
|
||||
(ess--strip-final-newlines cmd)
|
||||
(buffer-substring start end)))))))))))
|
||||
out-buffer))
|
||||
|
||||
(defun ess--command-error-handler (proc
|
||||
out-buffer
|
||||
use-delimiter
|
||||
delim
|
||||
early-exit)
|
||||
(let ((inhibit-quit t))
|
||||
;; In case of early exit send an interrupt to the
|
||||
;; process to abort the command
|
||||
(with-current-buffer out-buffer
|
||||
(goto-char (point-min))
|
||||
(when (and use-delimiter
|
||||
(not (re-search-forward (ess--delimiter-start-re delim) nil t)))
|
||||
;; CMD probably failed to parse if the start delimiter
|
||||
;; can't be found in the output. Disable the delimiter
|
||||
;; before interrupt to avoid a freeze.
|
||||
(ess-write-to-dribble-buffer
|
||||
"Disabling output delimiter because CMD failed to parse\n")
|
||||
(process-put proc 'cmd-output-delimiter nil))
|
||||
(goto-char (point-max))
|
||||
(ess--interrupt proc)))
|
||||
;; Can be `t` when early exit is caused e.g. by a throw instead of
|
||||
;; an error or a quit. This happens in tests and within
|
||||
;; `while-no-input'.
|
||||
(unless (eq early-exit t)
|
||||
(when (and (eq (car early-exit) 'quit)
|
||||
(y-or-n-p (concat "Background background command interrupted with a user quit.\n"
|
||||
"Would you like to disable background evaluations in this process?")))
|
||||
(process-put proc 'bg-eval-disabled t))
|
||||
(signal (car early-exit) (cdr early-exit))))
|
||||
|
||||
;; (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 ()
|
||||
@@ -1680,7 +1757,7 @@ Prefix arg VIS toggles visibility of ess-code as for
|
||||
(setq msg (format "Eval function: %s"
|
||||
(if (looking-at add-log-current-defun-header-regexp)
|
||||
(match-string 1)
|
||||
(buffer-substring (point) (point-at-eol)))))
|
||||
(buffer-substring (point) (line-end-position)))))
|
||||
(setq beg (point))
|
||||
(end-of-defun)
|
||||
(setq end (point))
|
||||
@@ -1696,7 +1773,7 @@ Prefix arg VIS toggles visibility of ess-code as for
|
||||
Prefix arg VIS toggles visibility of ess-code as for `ess-eval-region'."
|
||||
(interactive "P")
|
||||
(let ((start-pos (point)))
|
||||
(if (= (point-at-bol) (point-min))
|
||||
(if (= (line-beginning-position) (point-min))
|
||||
(ess-next-code-line 0)
|
||||
;; Evaluation is forward oriented
|
||||
(forward-line -1)
|
||||
@@ -1787,8 +1864,8 @@ input will fail."
|
||||
"Send the current line to the inferior ESS process.
|
||||
VIS has same meaning as for `ess-eval-region'."
|
||||
(interactive "P")
|
||||
(let* ((beg (point-at-bol))
|
||||
(end (point-at-eol))
|
||||
(let* ((beg (line-beginning-position))
|
||||
(end (line-end-position))
|
||||
(msg (format "Loading line: %s" (buffer-substring beg end))))
|
||||
(ess-eval-region beg end vis msg)))
|
||||
|
||||
@@ -1832,7 +1909,8 @@ Evaluate all comments and empty lines."
|
||||
(interactive)
|
||||
(let ((ess-eval-visibly nil))
|
||||
(ess-eval-line-and-step)))
|
||||
(define-obsolete-function-alias 'ess-eval-line-and-step-invisibly 'ess-eval-line-invisibly-and-step "18.10")
|
||||
(define-obsolete-function-alias 'ess-eval-line-and-step-invisibly
|
||||
#'ess-eval-line-invisibly-and-step "18.10")
|
||||
|
||||
|
||||
;;;*;;; Evaluate and switch to S
|
||||
@@ -2013,9 +2091,10 @@ node `(ess)Top'. If you accidentally suspend your process, use
|
||||
"]: %s"))
|
||||
|
||||
;;; Completion support ----------------
|
||||
(remove-hook 'completion-at-point-functions 'comint-completion-at-point t) ;; reset the hook
|
||||
(add-hook 'completion-at-point-functions 'comint-c-a-p-replace-by-expanded-history nil 'local)
|
||||
(add-hook 'completion-at-point-functions 'ess-filename-completion nil 'local)
|
||||
(remove-hook 'completion-at-point-functions #'comint-completion-at-point t) ;; reset the hook
|
||||
(add-hook 'completion-at-point-functions
|
||||
#'comint-c-a-p-replace-by-expanded-history nil 'local)
|
||||
(add-hook 'completion-at-point-functions #'ess-filename-completion nil 'local)
|
||||
|
||||
;; hyperlinks support
|
||||
(goto-address-mode t)
|
||||
@@ -2149,13 +2228,13 @@ If in the output field, goes to the beginning of previous input."
|
||||
(if (looking-at inferior-ess-prompt) ; cust.var, might not include sec-prompt
|
||||
(progn
|
||||
(comint-skip-prompt)
|
||||
(setq command (buffer-substring-no-properties (point) (point-at-eol)))
|
||||
(setq command (buffer-substring-no-properties (point) (line-end-position)))
|
||||
(when inferior-ess-secondary-prompt
|
||||
(while (progn (forward-line 1)
|
||||
(looking-at inferior-ess-secondary-prompt))
|
||||
(re-search-forward inferior-ess-secondary-prompt (point-at-eol) t)
|
||||
(re-search-forward inferior-ess-secondary-prompt (line-end-position) t)
|
||||
(setq command (concat command "\n"
|
||||
(buffer-substring-no-properties (point) (point-at-eol))))))
|
||||
(buffer-substring-no-properties (point) (line-end-position))))))
|
||||
(forward-line -1)
|
||||
command)
|
||||
(message "No command at this point")
|
||||
@@ -2167,6 +2246,17 @@ If in the output field, goes to the beginning of previous input."
|
||||
(inferior-ess--get-old-input:regexp)
|
||||
(inferior-ess--get-old-input:field)))
|
||||
|
||||
(defun ess-can-eval-in-background (&optional proc)
|
||||
"Can the current process be used for background commands.
|
||||
Inspects the `ess-can-eval-in-background' variable as well as the
|
||||
`bg-eval-disabled' property of PROC or of the current process, if
|
||||
any. This makes it possible to disable background evals for a
|
||||
specific process, for instance in case it was not initialized
|
||||
properly."
|
||||
(when ess-can-eval-in-background
|
||||
(when-let ((proc (or proc (ess-get-current-process))))
|
||||
(not (process-get proc 'bg-eval-disabled)))))
|
||||
|
||||
|
||||
;;;*;;; Hot key commands
|
||||
|
||||
@@ -2220,6 +2310,8 @@ Also sets the \"length\" option to 99999. When INVISIBLY is
|
||||
non-nil, don't echo to R subprocess. This is a good thing to put
|
||||
in `ess-r-post-run-hook' or `ess-S+-post-run-hook'."
|
||||
(interactive)
|
||||
(ess-if-verbose-write
|
||||
(format "ess-execute-screen-options: invisibly=%s\n" invisibly))
|
||||
(if (null ess-execute-screen-options-command)
|
||||
(message "Not implemented for '%s'" ess-dialect)
|
||||
(let ((command (ess-calculate-width 'window)))
|
||||
@@ -2227,6 +2319,12 @@ in `ess-r-post-run-hook' or `ess-S+-post-run-hook'."
|
||||
(ess-command command)
|
||||
(ess-eval-linewise command nil nil nil 'wait-prompt)))))
|
||||
|
||||
;; Runs in background if inferior is not busy
|
||||
(defun ess--execute-screen-options-bg ()
|
||||
(when (and ess-execute-screen-options-command
|
||||
(inferior-ess-available-p))
|
||||
(ess-execute-screen-options t)))
|
||||
|
||||
(defun ess-calculate-width (opt)
|
||||
"Calculate width command given OPT.
|
||||
OPT can be \\='window, \\='frame, or an integer. Return a command
|
||||
@@ -2650,7 +2748,7 @@ name that contains :,$ or @."
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "(list" nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
(setq args (ignore-errors (eval (read (current-buffer)))))
|
||||
(setq args (ignore-errors (eval (read (current-buffer)) t)))
|
||||
(when args
|
||||
(setcar args (cons (car args) (current-time)))))
|
||||
;; push even if nil
|
||||
@@ -2911,8 +3009,8 @@ P-STRING is the prompt string."
|
||||
(car ess--handy-history))))
|
||||
(call-interactively
|
||||
(cdr (assoc (ess-completing-read "Execute"
|
||||
(sort (mapcar 'car commands)
|
||||
'string-lessp)
|
||||
(sort (mapcar #'car commands)
|
||||
#'string-lessp)
|
||||
nil t nil 'ess--handy-history hist)
|
||||
commands)))))
|
||||
|
||||
@@ -2955,9 +3053,9 @@ NO-ERROR prevents errors when this has not been implemented for
|
||||
(unless no-error
|
||||
(error "Not implemented for dialect %s" ess-dialect))))
|
||||
|
||||
(defalias 'ess-change-directory 'ess-set-working-directory)
|
||||
(defalias 'ess-change-directory #'ess-set-working-directory)
|
||||
(define-obsolete-function-alias
|
||||
'ess-use-dir 'ess-set-working-directory "ESS 18.10")
|
||||
'ess-use-dir #'ess-set-working-directory "ESS 18.10")
|
||||
|
||||
(defun ess-use-this-dir (&rest _ignore)
|
||||
"Set the current process directory to the directory of this file.
|
||||
@@ -2978,7 +3076,7 @@ NO-ERROR prevents errors when this has not been implemented for
|
||||
(defun ess-synchronize-dirs ()
|
||||
"Set Emacs' current directory to be the same as the subprocess directory.
|
||||
To be used in `ess-idle-timer-functions'."
|
||||
(when (and ess-can-eval-in-background
|
||||
(when (and (ess-can-eval-in-background)
|
||||
ess-getwd-command
|
||||
(inferior-ess-available-p))
|
||||
(ess-when-new-input last-sync-dirs
|
||||
@@ -3018,7 +3116,7 @@ path, and can be a remote path"
|
||||
|
||||
(defun ess-cache-search-list ()
|
||||
"To be used in `ess-idle-timer-functions', to set search path related variables."
|
||||
(when (and ess-can-eval-in-background
|
||||
(when (and (ess-can-eval-in-background)
|
||||
inferior-ess-search-list-command)
|
||||
(ess-when-new-input last-cache-search-list
|
||||
(let ((path (ess-search-list 'force))
|
||||
|
||||
Reference in New Issue
Block a user