diff options
| author | Jim Porter | 2023-09-17 21:06:46 -0700 |
|---|---|---|
| committer | Jim Porter | 2023-09-17 21:10:28 -0700 |
| commit | 9ab8b968d63d9287639bbc574873bf8fde769fea (patch) | |
| tree | 9d70e6ef15be15f1c1771c85218cbe1d8c916c9d | |
| parent | 4e46df96510335c086a3764e002c99348e0e9624 (diff) | |
| download | emacs-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.el | 27 | ||||
| -rw-r--r-- | lisp/eshell/esh-cmd.el | 64 |
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. |
| 91 | Comments begin with `#'." | 91 | Comments 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 | ||
| 356 | REGION is a cons cell (START . END) that specifies the region to | 359 | (defmacro eshell-with-temp-command (command &rest body) |
| 357 | which to narrow the buffer. REGION can also be a string, in | 360 | "Temporarily insert COMMAND into the buffer and execute the forms in BODY. |
| 358 | which case the macro temporarily inserts it into the buffer at | 361 | |
| 359 | point, and narrows the buffer to the inserted string. Before | 362 | COMMAND can be a string to insert, a cons cell (START . END) |
| 360 | executing BODY, point is set to the beginning of the narrowed | 363 | specifying a region in the current buffer, or (:file . FILENAME) |
| 361 | REGION. | 364 | to temporarily insert the contents of FILENAME. |
| 365 | |||
| 366 | Before executing BODY, narrow the buffer to the text for COMMAND | ||
| 367 | and and set point to the beginning of the narrowed region. | ||
| 362 | 368 | ||
| 363 | The value returned is the last form in BODY." | 369 | The 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. |
| 387 | COMMAND can either be a string, or a cons cell demarcating a buffer | 398 | COMMAND can be a string, a cons cell (START . END) demarcating a |
| 388 | region. TOPLEVEL, if non-nil, means that the outermost command (the | 399 | buffer region, or (:file . FILENAME) to parse the contents of |
| 389 | user's input command) is being parsed, and that pre and post command | 400 | FILENAME. |
| 390 | hooks should be run before and after the command." | 401 | |
| 402 | TOPLEVEL, if non-nil, means that the outermost command (the | ||
| 403 | user's input command) is being parsed, and that pre and post | ||
| 404 | command 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)) |