aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Porter2023-09-17 21:06:46 -0700
committerJim Porter2023-09-17 21:10:28 -0700
commit9ab8b968d63d9287639bbc574873bf8fde769fea (patch)
tree9d70e6ef15be15f1c1771c85218cbe1d8c916c9d
parent4e46df96510335c086a3764e002c99348e0e9624 (diff)
downloademacs-9ab8b968d63d9287639bbc574873bf8fde769fea.tar.gz
emacs-9ab8b968d63d9287639bbc574873bf8fde769fea.zip
Use 'eshell-with-temp-command' (indirectly) to parse Eshell script files
* lisp/eshell/esh-cmd.el (eshell--region-p): New function. (eshell-with-temp-command, eshell-parse-command): Support '(:file . FILENAME)' to use the contents of FILENAME. * lisp/eshell/em-script.el (eshell-source-file): Call 'eshell-parse-command' and use backticks.
-rw-r--r--lisp/eshell/em-script.el27
-rw-r--r--lisp/eshell/esh-cmd.el64
2 files changed, 46 insertions, 45 deletions
diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el
index 55a05076342..9f6f720b8b0 100644
--- a/lisp/eshell/em-script.el
+++ b/lisp/eshell/em-script.el
@@ -89,26 +89,13 @@ This includes when running `eshell-command'."
89(defun eshell-source-file (file &optional args subcommand-p) 89(defun eshell-source-file (file &optional args subcommand-p)
90 "Execute a series of Eshell commands in FILE, passing ARGS. 90 "Execute a series of Eshell commands in FILE, passing ARGS.
91Comments begin with `#'." 91Comments begin with `#'."
92 (let ((orig (point)) 92 (let ((cmd (eshell-parse-command `(:file . ,file))))
93 (here (point-max))) 93 (when subcommand-p
94 (goto-char (point-max)) 94 (setq cmd `(eshell-as-subcommand ,cmd)))
95 (with-silent-modifications 95 (throw 'eshell-replace-command
96 ;; FIXME: Why not use a temporary buffer and avoid this 96 `(let ((eshell-command-name ',file)
97 ;; "insert&delete" business? --Stef 97 (eshell-command-arguments ',args))
98 (insert-file-contents file) 98 ,cmd))))
99 (goto-char (point-max))
100 (throw 'eshell-replace-command
101 (prog1
102 (list 'let
103 (list (list 'eshell-command-name (list 'quote file))
104 (list 'eshell-command-arguments
105 (list 'quote args)))
106 (let ((cmd (eshell-parse-command (cons here (point)))))
107 (if subcommand-p
108 (setq cmd (list 'eshell-as-subcommand cmd)))
109 cmd))
110 (delete-region here (point))
111 (goto-char orig))))))
112 99
113(defun eshell/source (&rest args) 100(defun eshell/source (&rest args)
114 "Source a file in a subshell environment." 101 "Source a file in a subshell environment."
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index a4542dd917d..0d73b2d6e69 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -350,48 +350,62 @@ This only returns external (non-Lisp) processes."
350 350
351;; Command parsing 351;; Command parsing
352 352
353(defmacro eshell-with-temp-command (region &rest body) 353(defsubst eshell--region-p (object)
354 "Narrow the buffer to REGION and execute the forms in BODY. 354 "Return non-nil if OBJECT is a pair of numbers or markers."
355 (and (consp object)
356 (number-or-marker-p (car object))
357 (number-or-marker-p (cdr object))))
355 358
356REGION is a cons cell (START . END) that specifies the region to 359(defmacro eshell-with-temp-command (command &rest body)
357which to narrow the buffer. REGION can also be a string, in 360 "Temporarily insert COMMAND into the buffer and execute the forms in BODY.
358which case the macro temporarily inserts it into the buffer at 361
359point, and narrows the buffer to the inserted string. Before 362COMMAND can be a string to insert, a cons cell (START . END)
360executing BODY, point is set to the beginning of the narrowed 363specifying a region in the current buffer, or (:file . FILENAME)
361REGION. 364to temporarily insert the contents of FILENAME.
365
366Before executing BODY, narrow the buffer to the text for COMMAND
367and and set point to the beginning of the narrowed region.
362 368
363The value returned is the last form in BODY." 369The value returned is the last form in BODY."
364 (declare (indent 1)) 370 (declare (indent 1))
365 `(let ((reg ,region)) 371 (let ((command-sym (make-symbol "command"))
366 (if (stringp reg) 372 (begin-sym (make-symbol "begin"))
373 (end-sym (make-symbol "end")))
374 `(let ((,command-sym ,command))
375 (if (eshell--region-p ,command-sym)
376 (save-restriction
377 (narrow-to-region (car ,command-sym) (cdr ,command-sym))
378 (goto-char (car ,command-sym))
379 ,@body)
367 ;; Since parsing relies partly on buffer-local state 380 ;; Since parsing relies partly on buffer-local state
368 ;; (e.g. that of `eshell-parse-argument-hook'), we need to 381 ;; (e.g. that of `eshell-parse-argument-hook'), we need to
369 ;; perform the parsing in the Eshell buffer. 382 ;; perform the parsing in the Eshell buffer.
370 (let ((begin (point)) end) 383 (let ((,begin-sym (point)) ,end-sym)
371 (with-silent-modifications 384 (with-silent-modifications
372 (insert reg) 385 (if (stringp ,command-sym)
373 (setq end (point)) 386 (insert ,command-sym)
387 (forward-char (cadr (insert-file-contents (cdr ,command-sym)))))
388 (setq ,end-sym (point))
374 (unwind-protect 389 (unwind-protect
375 (save-restriction 390 (save-restriction
376 (narrow-to-region begin end) 391 (narrow-to-region ,begin-sym ,end-sym)
377 (goto-char begin) 392 (goto-char ,begin-sym)
378 ,@body) 393 ,@body)
379 (delete-region begin end)))) 394 (delete-region ,begin-sym ,end-sym))))))))
380 (save-restriction
381 (narrow-to-region (car reg) (cdr reg))
382 (goto-char (car reg))
383 ,@body))))
384 395
385(defun eshell-parse-command (command &optional args toplevel) 396(defun eshell-parse-command (command &optional args toplevel)
386 "Parse the COMMAND, adding ARGS if given. 397 "Parse the COMMAND, adding ARGS if given.
387COMMAND can either be a string, or a cons cell demarcating a buffer 398COMMAND can be a string, a cons cell (START . END) demarcating a
388region. TOPLEVEL, if non-nil, means that the outermost command (the 399buffer region, or (:file . FILENAME) to parse the contents of
389user's input command) is being parsed, and that pre and post command 400FILENAME.
390hooks should be run before and after the command." 401
402TOPLEVEL, if non-nil, means that the outermost command (the
403user's input command) is being parsed, and that pre and post
404command hooks should be run before and after the command."
391 (pcase-let* 405 (pcase-let*
392 ((terms 406 ((terms
393 (append 407 (append
394 (if (consp command) 408 (if (eshell--region-p command)
395 (eshell-parse-arguments (car command) (cdr command)) 409 (eshell-parse-arguments (car command) (cdr command))
396 (eshell-with-temp-command command 410 (eshell-with-temp-command command
397 (goto-char (point-max)) 411 (goto-char (point-max))