]> git.eshelyaron.com Git - emacs.git/commitdiff
Use 'eshell-with-temp-command' (indirectly) to parse Eshell script files
authorJim Porter <jporterbugs@gmail.com>
Mon, 18 Sep 2023 04:06:46 +0000 (21:06 -0700)
committerJim Porter <jporterbugs@gmail.com>
Mon, 18 Sep 2023 04:10:28 +0000 (21:10 -0700)
* 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.

lisp/eshell/em-script.el
lisp/eshell/esh-cmd.el

index 55a05076342e8472c9aa98ec112a49e2f6b87654..9f6f720b8b0ba559c0eb327e5057c4e5b965f706 100644 (file)
@@ -89,26 +89,13 @@ This includes when running `eshell-command'."
 (defun eshell-source-file (file &optional args subcommand-p)
   "Execute a series of Eshell commands in FILE, passing ARGS.
 Comments begin with `#'."
-  (let ((orig (point))
-       (here (point-max)))
-    (goto-char (point-max))
-    (with-silent-modifications
-      ;; FIXME: Why not use a temporary buffer and avoid this
-      ;; "insert&delete" business?  --Stef
-      (insert-file-contents file)
-      (goto-char (point-max))
-      (throw 'eshell-replace-command
-             (prog1
-                 (list 'let
-                       (list (list 'eshell-command-name (list 'quote file))
-                             (list 'eshell-command-arguments
-                                   (list 'quote args)))
-                       (let ((cmd (eshell-parse-command (cons here (point)))))
-                         (if subcommand-p
-                             (setq cmd (list 'eshell-as-subcommand cmd)))
-                         cmd))
-               (delete-region here (point))
-               (goto-char orig))))))
+  (let ((cmd (eshell-parse-command `(:file . ,file))))
+    (when subcommand-p
+      (setq cmd `(eshell-as-subcommand ,cmd)))
+    (throw 'eshell-replace-command
+           `(let ((eshell-command-name ',file)
+                  (eshell-command-arguments ',args))
+              ,cmd))))
 
 (defun eshell/source (&rest args)
   "Source a file in a subshell environment."
index a4542dd917d80f1c01bb7da121a66011675a6c90..0d73b2d6e693b1305021ddf656157e39224d6ae4 100644 (file)
@@ -350,48 +350,62 @@ This only returns external (non-Lisp) processes."
 
 ;; Command parsing
 
-(defmacro eshell-with-temp-command (region &rest body)
-  "Narrow the buffer to REGION and execute the forms in BODY.
+(defsubst eshell--region-p (object)
+  "Return non-nil if OBJECT is a pair of numbers or markers."
+  (and (consp object)
+       (number-or-marker-p (car object))
+       (number-or-marker-p (cdr object))))
 
-REGION is a cons cell (START . END) that specifies the region to
-which to narrow the buffer.  REGION can also be a string, in
-which case the macro temporarily inserts it into the buffer at
-point, and narrows the buffer to the inserted string.  Before
-executing BODY, point is set to the beginning of the narrowed
-REGION.
+(defmacro eshell-with-temp-command (command &rest body)
+  "Temporarily insert COMMAND into the buffer and execute the forms in BODY.
+
+COMMAND can be a string to insert, a cons cell (START . END)
+specifying a region in the current buffer, or (:file . FILENAME)
+to temporarily insert the contents of FILENAME.
+
+Before executing BODY, narrow the buffer to the text for COMMAND
+and and set point to the beginning of the narrowed region.
 
 The value returned is the last form in BODY."
   (declare (indent 1))
-  `(let ((reg ,region))
-     (if (stringp reg)
+  (let ((command-sym (make-symbol "command"))
+        (begin-sym (make-symbol "begin"))
+        (end-sym (make-symbol "end")))
+    `(let ((,command-sym ,command))
+       (if (eshell--region-p ,command-sym)
+           (save-restriction
+             (narrow-to-region (car ,command-sym) (cdr ,command-sym))
+             (goto-char (car ,command-sym))
+             ,@body)
          ;; Since parsing relies partly on buffer-local state
          ;; (e.g. that of `eshell-parse-argument-hook'), we need to
          ;; perform the parsing in the Eshell buffer.
-         (let ((begin (point)) end)
+         (let ((,begin-sym (point)) ,end-sym)
            (with-silent-modifications
-             (insert reg)
-             (setq end (point))
+             (if (stringp ,command-sym)
+                 (insert ,command-sym)
+               (forward-char (cadr (insert-file-contents (cdr ,command-sym)))))
+             (setq ,end-sym (point))
              (unwind-protect
                  (save-restriction
-                   (narrow-to-region begin end)
-                   (goto-char begin)
+                   (narrow-to-region ,begin-sym ,end-sym)
+                   (goto-char ,begin-sym)
                    ,@body)
-               (delete-region begin end))))
-       (save-restriction
-         (narrow-to-region (car reg) (cdr reg))
-         (goto-char (car reg))
-         ,@body))))
+               (delete-region ,begin-sym ,end-sym))))))))
 
 (defun eshell-parse-command (command &optional args toplevel)
   "Parse the COMMAND, adding ARGS if given.
-COMMAND can either be a string, or a cons cell demarcating a buffer
-region.  TOPLEVEL, if non-nil, means that the outermost command (the
-user's input command) is being parsed, and that pre and post command
-hooks should be run before and after the command."
+COMMAND can be a string, a cons cell (START . END) demarcating a
+buffer region, or (:file . FILENAME) to parse the contents of
+FILENAME.
+
+TOPLEVEL, if non-nil, means that the outermost command (the
+user's input command) is being parsed, and that pre and post
+command hooks should be run before and after the command."
   (pcase-let*
     ((terms
       (append
-       (if (consp command)
+       (if (eshell--region-p command)
            (eshell-parse-arguments (car command) (cdr command))
          (eshell-with-temp-command command
            (goto-char (point-max))