1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-31 21:01:23 -08:00

Fix handling of Eshell debug modes

Previously, these were enabled/disabled at byte-compilation time, but
we want to control them at runtime.

* lisp/eshell/esh-cmd.el (eshell-eval-command): Call
'eshell-debug-command-start'.
(eshell-manipulate): Check 'eshell-debug-command' at runtime.  Update
callers.
(eshell-debug-command): Move to "esh-util.el".
(eshell/eshell-debug, pcomplate/eshell-mode/eshell-debug): Move to
"em-basic.el".
(eshell-debug-show-parsed-args): Update implementation.

* lisp/eshell/esh-util.el (eshell-debug-command): Move from
"esh-cmd.el" and convert to a list.
(eshell-debug-command-buffer): New variable.
(eshell-condition-case): Check 'eshell-handle-errors' at runtime.
(eshell-debug-command-start): New function.
(eshell-debug-command): Move from "esh-cmd.el" and convert to a macro.

* lisp/eshell/em-basic.el (eshell/eshell-debug)
(pcomplete/eshell-mode/eshell-debug): Move from "esh-cmd.el" and
reimplement.

* lisp/eshell/eshell.el (eshell-command): Pass the original input to
'eshell-eval-command'.

* doc/misc/eshell.texi (Built-ins): Update documentation for
'eshell-debug'.
This commit is contained in:
Jim Porter 2023-08-29 17:02:40 -07:00
parent 17188e07ab
commit ccb62321d2
5 changed files with 108 additions and 92 deletions

View file

@ -619,10 +619,19 @@ environment.
@item eshell-debug
@cmindex eshell-debug
Toggle debugging information for Eshell itself. You can pass this
command the argument @code{errors} to enable/disable Eshell trapping
errors when evaluating commands, or the argument @code{commands} to
show/hide command execution progress in the buffer @code{*eshell last
cmd*}.
command one or more of the following arguments:
@itemize @bullet
@item
@code{error}, to enable/disable Eshell trapping errors when
evaluating commands; or
@item
@code{form}, to show/hide Eshell command form manipulation in the
buffer @code{*eshell last cmd*}.
@end itemize
@item exit
@cmindex exit

View file

@ -188,6 +188,37 @@ or `eshell-printn' for display."
(put 'eshell/umask 'eshell-no-numeric-conversions t)
(defun eshell/eshell-debug (&rest args)
"A command for toggling certain debug variables."
(eshell-eval-using-options
"eshell-debug" args
'((?h "help" nil nil "display this usage message")
:usage "[KIND]...
This command is used to aid in debugging problems related to Eshell
itself. It is not useful for anything else. The recognized `kinds'
are:
error stops Eshell from trapping errors
form shows command form manipulation in `*eshell last cmd*'")
(if args
(dolist (kind args)
(if (equal kind "error")
(setq eshell-handle-errors (not eshell-handle-errors))
(let ((kind-sym (intern kind)))
(if (memq kind-sym eshell-debug-command)
(setq eshell-debug-command
(delq kind-sym eshell-debug-command))
(push kind-sym eshell-debug-command)))))
;; Output the currently-enabled debug kinds.
(unless eshell-handle-errors
(eshell-print "errors\n"))
(dolist (kind eshell-debug-command)
(eshell-printn (symbol-name kind))))))
(defun pcomplete/eshell-mode/eshell-debug ()
"Completion for the `debug' command."
(while (pcomplete-here '("error" "form"))))
(provide 'em-basic)
;; Local Variables:

View file

@ -237,17 +237,6 @@ return non-nil if the command is complex."
:version "24.1" ; removed eshell-cmd-initialize
:type 'hook)
(defcustom eshell-debug-command nil
"If non-nil, enable Eshell debugging code.
This is slow, and only useful for debugging problems with Eshell.
If you change this without using customize after Eshell has loaded,
you must re-load `esh-cmd.el'."
:initialize 'custom-initialize-default
:set (lambda (symbol value)
(set symbol value)
(load "esh-cmd"))
:type 'boolean)
(defcustom eshell-deferrable-commands
'(eshell-named-command
eshell-lisp-command
@ -436,22 +425,9 @@ hooks should be run before and after the command."
(run-hooks 'eshell-post-command-hook)))
(macroexp-progn commands))))
(defun eshell-debug-command (tag subform)
"Output a debugging message to `*eshell last cmd*'."
(let ((buf (get-buffer-create "*eshell last cmd*"))
(text (eshell-stringify eshell-current-command)))
(with-current-buffer buf
(if (not tag)
(erase-buffer)
(insert "\n\C-l\n" tag "\n\n" text
(if subform
(concat "\n\n" (eshell-stringify subform)) ""))))))
(defun eshell-debug-show-parsed-args (terms)
"Display parsed arguments in the debug buffer."
(ignore
(if eshell-debug-command
(eshell-debug-command "parsed arguments" terms))))
(ignore (eshell-debug-command 'form "parsed arguments" terms)))
(defun eshell-no-command-conversion (terms)
"Don't convert the command argument."
@ -942,38 +918,6 @@ This avoids the need to use `let*'."
;; finishes, it will resume the evaluation using the remainder of the
;; command tree.
(defun eshell/eshell-debug (&rest args)
"A command for toggling certain debug variables."
(ignore
(cond
((not args)
(if eshell-handle-errors
(eshell-print "errors\n"))
(if eshell-debug-command
(eshell-print "commands\n")))
((member (car args) '("-h" "--help"))
(eshell-print "usage: eshell-debug [kinds]
This command is used to aid in debugging problems related to Eshell
itself. It is not useful for anything else. The recognized `kinds'
at the moment are:
errors stops Eshell from trapping errors
commands shows command execution progress in `*eshell last cmd*'
"))
(t
(while args
(cond
((string= (car args) "errors")
(setq eshell-handle-errors (not eshell-handle-errors)))
((string= (car args) "commands")
(setq eshell-debug-command (not eshell-debug-command))))
(setq args (cdr args)))))))
(defun pcomplete/eshell-mode/eshell-debug ()
"Completion for the `debug' command."
(while (pcomplete-here '("errors" "commands"))))
(iter-defun eshell--find-subcommands (haystack)
"Recursively search for subcommand forms in HAYSTACK.
This yields the SUBCOMMANDs when found in forms like
@ -1049,10 +993,7 @@ process(es) in a cons cell like:
(if here
(eshell-update-markers here))
(eshell-do-eval ',command))))
(and eshell-debug-command
(with-current-buffer (get-buffer-create "*eshell last cmd*")
(erase-buffer)
(insert "command: \"" input "\"\n")))
(eshell-debug-command-start input)
(setq eshell-current-command command)
(let* (result
(delim (catch 'eshell-incomplete
@ -1088,17 +1029,17 @@ process(es) in a cons cell like:
(error
(error (error-message-string err)))))
(defmacro eshell-manipulate (tag &rest commands)
"Manipulate a COMMAND form, with TAG as a debug identifier."
(declare (indent 1))
;; Check `bound'ness since at compile time the code until here has not
;; executed yet.
(if (not (and (boundp 'eshell-debug-command) eshell-debug-command))
`(progn ,@commands)
`(progn
(eshell-debug-command ,(eval tag) form)
,@commands
(eshell-debug-command ,(concat "done " (eval tag)) form))))
(defmacro eshell-manipulate (form tag &rest body)
"Manipulate a command FORM with BODY, using TAG as a debug identifier."
(declare (indent 2))
(let ((tag-symbol (make-symbol "tag")))
`(if (not (memq 'form eshell-debug-command))
(progn ,@body)
(let ((,tag-symbol ,tag))
(eshell-debug-command 'form ,tag-symbol ,form 'always)
,@body
(eshell-debug-command 'form (concat "done " ,tag-symbol) ,form
'always)))))
(defun eshell-do-eval (form &optional synchronous-p)
"Evaluate FORM, simplifying it as we go.
@ -1125,8 +1066,8 @@ have been replaced by constants."
;; we can modify any `let' forms to evaluate only once.
(if (macrop (car form))
(let ((exp (copy-tree (macroexpand form))))
(eshell-manipulate (format-message "expanding macro `%s'"
(symbol-name (car form)))
(eshell-manipulate form
(format-message "expanding macro `%s'" (symbol-name (car form)))
(setcar form (car exp))
(setcdr form (cdr exp)))))
(let ((args (cdr form)))
@ -1138,7 +1079,7 @@ have been replaced by constants."
(let ((new-form (copy-tree `(let ((eshell--command-body nil)
(eshell--test-body nil))
(eshell--wrapped-while ,@args)))))
(eshell-manipulate "modifying while form"
(eshell-manipulate form "modifying while form"
(setcar form (car new-form))
(setcdr form (cdr new-form)))
(eshell-do-eval form synchronous-p)))
@ -1161,7 +1102,7 @@ have been replaced by constants."
(setq eshell--command-body nil
eshell--test-body (copy-tree (car args)))))
((eq (car form) 'if)
(eshell-manipulate "evaluating if condition"
(eshell-manipulate form "evaluating if condition"
(setcar args (eshell-do-eval (car args) synchronous-p)))
(eshell-do-eval
(cond
@ -1180,7 +1121,7 @@ have been replaced by constants."
(eval form))
((eq (car form) 'let)
(unless (eq (car-safe (cadr args)) 'eshell-do-eval)
(eshell-manipulate "evaluating let args"
(eshell-manipulate form "evaluating let args"
(dolist (letarg (car args))
(when (and (listp letarg)
(not (eq (cadr letarg) 'quote)))
@ -1207,7 +1148,7 @@ have been replaced by constants."
;; the let-bindings' values so that those values are
;; correct when we resume evaluation of this form.
(when deferred
(eshell-manipulate "rebinding let args after `eshell-defer'"
(eshell-manipulate form "rebinding let args after `eshell-defer'"
(let ((bindings (car args)))
(while bindings
(let ((binding (if (consp (car bindings))
@ -1232,7 +1173,7 @@ have been replaced by constants."
(unless (eq (car form) 'unwind-protect)
(setq args (cdr args)))
(unless (eq (caar args) 'eshell-do-eval)
(eshell-manipulate "handling special form"
(eshell-manipulate form "handling special form"
(setcar args `(eshell-do-eval ',(car args) ,synchronous-p))))
(eval form))
((eq (car form) 'setq)
@ -1242,7 +1183,7 @@ have been replaced by constants."
(list 'quote (eval form)))
(t
(if (and args (not (memq (car form) '(run-hooks))))
(eshell-manipulate
(eshell-manipulate form
(format-message "evaluating arguments to `%s'"
(symbol-name (car form)))
(while args
@ -1283,7 +1224,7 @@ have been replaced by constants."
(setq result (eval form))))))
(if new-form
(progn
(eshell-manipulate "substituting replacement form"
(eshell-manipulate form "substituting replacement form"
(setcar form (car new-form))
(setcdr form (cdr new-form)))
(eshell-do-eval form synchronous-p))
@ -1292,7 +1233,7 @@ have been replaced by constants."
(procs (eshell-make-process-pair result)))
(if synchronous-p
(eshell/wait (cdr procs))
(eshell-manipulate "inserting ignore form"
(eshell-manipulate form "inserting ignore form"
(setcar form 'ignore)
(setcdr form nil))
(throw 'eshell-defer procs))

View file

@ -102,6 +102,15 @@ argument matches `eshell-number-regexp'."
(string :tag "Username")
(repeat :tag "UIDs" string))))))
(defcustom eshell-debug-command nil
"A list of debug features to enable when running Eshell commands.
Possible entries are `form', to log the manipulation of Eshell
command forms.
If nil, don't debug commands at all."
:version "30.1"
:type '(set (const :tag "Form manipulation" form)))
;;; Internal Variables:
(defvar eshell-number-regexp
@ -145,6 +154,9 @@ function `string-to-number'.")
,#'eshell--mark-yanked-as-output))
"A list of text properties to apply to command output.")
(defvar eshell-debug-command-buffer "*eshell last cmd*"
"The name of the buffer to log debug messages about command invocation.")
;;; Obsolete variables:
(define-obsolete-variable-alias 'eshell-host-names
@ -164,11 +176,33 @@ function `string-to-number'.")
"If `eshell-handle-errors' is non-nil, this is `condition-case'.
Otherwise, evaluates FORM with no error handling."
(declare (indent 2) (debug (sexp form &rest form)))
(if eshell-handle-errors
`(condition-case-unless-debug ,tag
,form
,@handlers)
form))
`(if eshell-handle-errors
(condition-case-unless-debug ,tag
,form
,@handlers)
,form))
(defun eshell-debug-command-start (command)
"Start debugging output for the command string COMMAND.
If debugging is enabled (see `eshell-debug-command'), this will
start logging to `*eshell last cmd*'."
(when eshell-debug-command
(with-current-buffer (get-buffer-create eshell-debug-command-buffer)
(erase-buffer)
(insert "command: \"" command "\"\n"))))
(defmacro eshell-debug-command (kind message &optional form always)
"Output a debugging message to `*eshell last cmd*' if debugging is enabled.
KIND is the kind of message to log (either `form' or `io'). If
present in `eshell-debug-command' (or if ALWAYS is non-nil),
output this message; otherwise, ignore it."
(let ((kind-sym (make-symbol "kind")))
`(let ((,kind-sym ,kind))
(when ,(or always `(memq ,kind-sym eshell-debug-command))
(with-current-buffer (get-buffer-create eshell-debug-command-buffer)
(insert "\n\C-l\n[" (symbol-name ,kind-sym) "] " ,message)
(when-let ((form ,form))
(insert "\n\n" (eshell-stringify form))))))))
(defun eshell--mark-as-output (start end &optional object)
"Mark the text from START to END as Eshell output.

View file

@ -301,7 +301,8 @@ argument), then insert output into the current buffer at point."
`(let ((eshell-current-handles
(eshell-create-handles ,stdout 'insert))
(eshell-current-subjob-p))
,(eshell-parse-command command))))
,(eshell-parse-command command))
command))
intr
(bufname (if (eq (car-safe proc) :eshell-background)
"*Eshell Async Command Output*"