emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 13e1fb4c3f7 2/2: Merge remote-tracking branch 'origin/ma


From: Po Lu
Subject: feature/android 13e1fb4c3f7 2/2: Merge remote-tracking branch 'origin/master' into feature/android
Date: Tue, 28 Mar 2023 20:42:38 -0400 (EDT)

branch: feature/android
commit 13e1fb4c3f7f969f45ccbec1cfc001d76690d680
Merge: af6af86d08e 2002ac376c9
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/android
---
 lisp/eshell/em-cmpl.el            | 60 ++++++++++++++++---------
 lisp/eshell/em-dirs.el            | 11 ++++-
 lisp/eshell/em-glob.el            | 10 -----
 lisp/eshell/esh-cmd.el            | 31 +++++++++----
 lisp/eshell/esh-var.el            | 95 ++++++++++++++++++++-------------------
 lisp/progmodes/ruby-ts-mode.el    | 41 ++++++++++-------
 test/lisp/eshell/em-cmpl-tests.el | 86 ++++++++++++++++++++++++++++++-----
 test/lisp/eshell/esh-var-tests.el |  2 +-
 8 files changed, 224 insertions(+), 112 deletions(-)

diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index b65652019d4..732bbb3f1fa 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -306,9 +306,24 @@ to writing a completion function."
 
 (defun eshell-complete--eval-argument-form (arg)
   "Evaluate a single Eshell argument form ARG for the purposes of completion."
-  (let ((result (eshell-do-eval `(eshell-commands ,arg) t)))
-    (cl-assert (eq (car result) 'quote))
-    (cadr result)))
+  (condition-case err
+      (let* (;; Don't allow running commands; they could have
+             ;; arbitrary side effects, which we don't want when we're
+             ;; just performing completions!
+             (eshell-allow-commands)
+             ;; Handle errors ourselves so that we can properly catch
+             ;; `eshell-commands-forbidden'.
+             (eshell-handle-errors)
+             (result (eshell-do-eval `(eshell-commands ,arg) t)))
+        (cl-assert (eq (car result) 'quote))
+        (cadr result))
+    (eshell-commands-forbidden
+     (propertize "\0" 'eshell-argument-stub
+                 (intern (format "%s-command" (cadr err)))))
+    (error
+     (lwarn 'eshell :error
+            "Failed to evaluate argument form during completion: %S" arg)
+     (propertize "\0" 'eshell-argument-stub 'error))))
 
 (defun eshell-complete-parse-arguments ()
   "Parse the command line arguments for `pcomplete-argument'."
@@ -325,23 +340,28 @@ to writing a completion function."
       (if (= begin end)
          (end-of-line))
       (setq end (point-marker)))
-    (if (setq delim
-             (catch 'eshell-incomplete
-               (ignore
-                (setq args (eshell-parse-arguments begin end)))))
-        (cond ((member (car delim) '("{" "${" "$<"))
-              (setq begin (1+ (cadr delim))
-                    args (eshell-parse-arguments begin end)))
-              ((member (car delim) '("$'" "$\"" "#<"))
-               ;; Add the (incomplete) argument to our arguments, and
-               ;; note its position.
-               (setq args (append (nth 2 delim) (list (car delim)))
-                     incomplete-arg t)
-               (push (- (nth 1 delim) 2) posns))
-              ((member (car delim) '("(" "$("))
-              (throw 'pcompleted (elisp-completion-at-point)))
-             (t
-              (eshell--pcomplete-insert-tab))))
+    ;; Don't expand globs when parsing arguments; we want to pass any
+    ;; globs to Pcomplete unaltered.
+    (declare-function eshell-parse-glob-chars "em-glob" ())
+    (let ((eshell-parse-argument-hook (remq #'eshell-parse-glob-chars
+                                            eshell-parse-argument-hook)))
+      (if (setq delim
+               (catch 'eshell-incomplete
+                 (ignore
+                  (setq args (eshell-parse-arguments begin end)))))
+          (cond ((member (car delim) '("{" "${" "$<"))
+                (setq begin (1+ (cadr delim))
+                      args (eshell-parse-arguments begin end)))
+                ((member (car delim) '("$'" "$\"" "#<"))
+                 ;; Add the (incomplete) argument to our arguments, and
+                 ;; note its position.
+                 (setq args (append (nth 2 delim) (list (car delim)))
+                       incomplete-arg t)
+                 (push (- (nth 1 delim) 2) posns))
+                ((member (car delim) '("(" "$("))
+                (throw 'pcompleted (elisp-completion-at-point)))
+               (t
+                (eshell--pcomplete-insert-tab)))))
     (when (get-text-property (1- end) 'comment)
       (eshell--pcomplete-insert-tab))
     (let ((pos (1- end)))
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 4bc6342d422..5284df9ab59 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -253,12 +253,21 @@ Thus, this does not include the current directory.")
     (throw 'eshell-replace-command
           (eshell-parse-command "cd" (flatten-tree args)))))
 
-(defun eshell-expand-user-reference (file)
+(defun eshell-expand-user-reference-1 (file)
   "Expand a user reference in FILE to its real directory name."
   (replace-regexp-in-string
    (rx bos (group "~" (*? anychar)) (or "/" eos))
    #'expand-file-name file))
 
+(defun eshell-expand-user-reference (file)
+  "Expand a user reference in FILE to its real directory name.
+FILE can be either a string or a list of strings to expand."
+  ;; If the argument was a glob pattern, then FILE is a list, so
+  ;; expand each element of the glob's resulting list.
+  (if (listp file)
+      (mapcar #'eshell-expand-user-reference-1 file)
+    (eshell-expand-user-reference-1 file)))
+
 (defun eshell-parse-user-reference ()
   "An argument beginning with ~ is a filename to be expanded."
   (when (and (not eshell-current-argument)
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 8a2ba13b2ad..9402df43065 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -145,16 +145,6 @@ This mimics the behavior of zsh if non-nil, but bash if 
nil."
 
 (defun eshell-add-glob-modifier ()
   "Add `eshell-extended-glob' to the argument modifier list."
-  (when (memq 'expand-file-name eshell-current-modifiers)
-    (setq eshell-current-modifiers
-         (delq 'expand-file-name eshell-current-modifiers))
-    ;; if this is a glob pattern than needs to be expanded, then it
-    ;; will need to expand each member of the resulting glob list
-    (add-to-list 'eshell-current-modifiers
-                (lambda (list)
-                   (if (listp list)
-                       (mapcar 'expand-file-name list)
-                     (expand-file-name list)))))
   (add-to-list 'eshell-current-modifiers 'eshell-extended-glob))
 
 (defun eshell-parse-glob-chars ()
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 93f2616020c..d5237ee1f04 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -293,6 +293,17 @@ CDR are the same process.
 
 When the process in the CDR completes, resume command evaluation.")
 
+(defvar eshell-allow-commands t
+  "If non-nil, allow evaluating command forms (including Lisp forms).
+If you want to forbid command forms, you can let-bind this to a
+non-nil value before calling `eshell-do-eval'.  Then, any command
+forms will signal `eshell-commands-forbidden'.  This is useful
+if, for example, you want to evaluate simple expressions like
+variable expansions, but not fully-evaluate the command.  See
+also `eshell-complete-parse-arguments'.")
+
+(define-error 'eshell-commands-forbidden "Commands forbidden")
+
 ;;; Functions:
 
 (defsubst eshell-interactive-process-p ()
@@ -675,13 +686,13 @@ This means an exit code of 0."
           (or (= (point-max) (1+ (point)))
               (not (eq (char-after (1+ (point))) ?\}))))
       (let ((end (eshell-find-delimiter ?\{ ?\})))
-       (if (not end)
-            (throw 'eshell-incomplete "{")
-         (when (eshell-arg-delimiter (1+ end))
-           (prog1
-               `(eshell-as-subcommand
-                  ,(eshell-parse-command (cons (1+ (point)) end)))
-             (goto-char (1+ end))))))))
+        (unless end
+          (throw 'eshell-incomplete "{"))
+        (when (eshell-arg-delimiter (1+ end))
+          (prog1
+              `(eshell-as-subcommand
+                ,(eshell-parse-command (cons (1+ (point)) end)))
+            (goto-char (1+ end)))))))
 
 (defun eshell-parse-lisp-argument ()
   "Parse a Lisp expression which is specified as an argument."
@@ -1168,7 +1179,7 @@ have been replaced by constants."
        (setcar (cdr args) (eshell-do-eval (cadr args) synchronous-p))
        (eval form))
        ((eq (car form) 'let)
-        (when (not (eq (car (cadr args)) 'eshell-do-eval))
+        (unless (eq (car-safe (cadr args)) 'eshell-do-eval)
           (eshell-manipulate "evaluating let args"
             (dolist (letarg (car args))
               (when (and (listp letarg)
@@ -1328,6 +1339,8 @@ have been replaced by constants."
 (defun eshell-named-command (command &optional args)
   "Insert output from a plain COMMAND, using ARGS.
 COMMAND may result in an alias being executed, or a plain command."
+  (unless eshell-allow-commands
+    (signal 'eshell-commands-forbidden '(named)))
   (setq eshell-last-arguments args
        eshell-last-command-name (eshell-stringify command))
   (run-hook-with-args 'eshell-prepare-command-hook)
@@ -1465,6 +1478,8 @@ via `eshell-errorn'."
 
 (defun eshell-lisp-command (object &optional args)
   "Insert Lisp OBJECT, using ARGS if a function."
+  (unless eshell-allow-commands
+    (signal 'eshell-commands-forbidden '(lisp)))
   (catch 'eshell-external               ; deferred to an external command
     (setq eshell-last-command-status 0
           eshell-last-arguments args)
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 5d6299af564..7dcaff1e24f 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -507,55 +507,56 @@ Possible variable references are:
   (cond
    ((eq (char-after) ?{)
     (let ((end (eshell-find-delimiter ?\{ ?\})))
-      (if (not end)
-          (throw 'eshell-incomplete "${")
-        (forward-char)
-        (prog1
-            `(eshell-apply-indices
-              (eshell-convert
-               (eshell-command-to-value
-                (eshell-as-subcommand
-                 ,(let ((subcmd (or (eshell-unescape-inner-double-quote end)
-                                    (cons (point) end)))
-                        (eshell-current-quoted nil))
-                    (eshell-parse-command subcmd))))
-               ;; If this is a simple double-quoted form like
-               ;; "${COMMAND}" (i.e. no indices after the subcommand
-               ;; and no `#' modifier before), ensure we convert to a
-               ;; single string.  This avoids unnecessary work
-               ;; (e.g. splitting the output by lines) when it would
-               ;; just be joined back together afterwards.
-               ,(when (and (not modifier-p) eshell-current-quoted)
-                  '(not indices)))
-              indices ,eshell-current-quoted)
-          (goto-char (1+ end))))))
+      (unless end
+        (throw 'eshell-incomplete "${"))
+      (forward-char)
+      (prog1
+          `(eshell-apply-indices
+            (eshell-convert
+             (eshell-command-to-value
+              (eshell-as-subcommand
+               ,(let ((subcmd (or (eshell-unescape-inner-double-quote end)
+                                  (cons (point) end)))
+                      (eshell-current-quoted nil))
+                  (eshell-parse-command subcmd))))
+             ;; If this is a simple double-quoted form like
+             ;; "${COMMAND}" (i.e. no indices after the subcommand and
+             ;; no `#' modifier before), ensure we convert to a single
+             ;; string.  This avoids unnecessary work (e.g. splitting
+             ;; the output by lines) when it would just be joined back
+             ;; together afterwards.
+             ,(when (and (not modifier-p) eshell-current-quoted)
+                '(not indices)))
+            indices ,eshell-current-quoted)
+        (goto-char (1+ end)))))
    ((eq (char-after) ?\<)
     (let ((end (eshell-find-delimiter ?\< ?\>)))
-      (if (not end)
-          (throw 'eshell-incomplete "$<")
-        (let* ((temp (make-temp-file temporary-file-directory))
-               (cmd (concat (buffer-substring (1+ (point)) end)
-                            " > " temp)))
-          (prog1
-              `(let ((eshell-current-handles
-                      (eshell-create-handles ,temp 'overwrite)))
-                 (progn
-                   (eshell-as-subcommand
-                    ,(let ((eshell-current-quoted nil))
-                       (eshell-parse-command cmd)))
-                   (ignore
-                    (nconc eshell-this-command-hook
-                           ;; Quote this lambda; it will be evaluated
-                           ;; by `eshell-do-eval', which requires very
-                           ;; particular forms in order to work
-                           ;; properly.  See bug#54190.
-                           (list (function
-                                  (lambda ()
-                                    (delete-file ,temp)
-                                    (when-let ((buffer (get-file-buffer 
,temp)))
-                                      (kill-buffer buffer)))))))
-                   (eshell-apply-indices ,temp indices 
,eshell-current-quoted)))
-            (goto-char (1+ end)))))))
+      (unless end
+        (throw 'eshell-incomplete "$<"))
+      (forward-char)
+      (let* ((temp (make-temp-file temporary-file-directory))
+             (subcmd (or (eshell-unescape-inner-double-quote end)
+                         (cons (point) end))))
+        (prog1
+            `(let ((eshell-current-handles
+                    (eshell-create-handles ,temp 'overwrite)))
+               (progn
+                 (eshell-as-subcommand
+                  ,(let ((eshell-current-quoted nil))
+                     (eshell-parse-command subcmd)))
+                 (ignore
+                  (nconc eshell-this-command-hook
+                         ;; Quote this lambda; it will be evaluated by
+                         ;; `eshell-do-eval', which requires very
+                         ;; particular forms in order to work
+                         ;; properly.  See bug#54190.
+                         (list (function
+                                (lambda ()
+                                  (delete-file ,temp)
+                                  (when-let ((buffer (get-file-buffer ,temp)))
+                                    (kill-buffer buffer)))))))
+                 (eshell-apply-indices ,temp indices ,eshell-current-quoted)))
+          (goto-char (1+ end))))))
    ((eq (char-after) ?\()
     (condition-case nil
         `(eshell-apply-indices
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 97c7cf6480c..1a085b669ee 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -1114,21 +1114,32 @@ leading double colon is not added."
   (setq-local treesit-defun-type-regexp ruby-ts--method-regex)
 
   (setq-local treesit-sexp-type-regexp
-              (regexp-opt '("class"
-                            "module"
-                            "method"
-                            "argument_list"
-                            "array"
-                            "hash"
-                            "parenthesized_statements"
-                            "if"
-                            "case"
-                            "when"
-                            "block"
-                            "do_block"
-                            "begin"
-                            "binary"
-                            "assignment")))
+              (rx bol
+                  (or "class"
+                      "module"
+                      "method"
+                      "array"
+                      "hash"
+                      "parenthesized_statements"
+                      "if"
+                      "case"
+                      "when"
+                      "block"
+                      "do_block"
+                      "begin"
+                      "integer"
+                      "identifier"
+                      "constant"
+                      "simple_symbol"
+                      "symbol_array"
+                      "hash_key_symbol"
+                      "string"
+                      "string_array"
+                      "heredoc_body"
+                      "regex"
+                      "argument_list"
+                      )
+                  eol))
 
   ;; AFAIK, Ruby can not nest methods
   (setq-local treesit-defun-prefer-top-level nil)
diff --git a/test/lisp/eshell/em-cmpl-tests.el 
b/test/lisp/eshell/em-cmpl-tests.el
index ea907f1945d..29a41625d5e 100644
--- a/test/lisp/eshell/em-cmpl-tests.el
+++ b/test/lisp/eshell/em-cmpl-tests.el
@@ -69,11 +69,10 @@ ACTUAL and EXPECTED should both be lists of strings."
 (ert-deftest em-cmpl-test/parse-arguments/pipeline ()
   "Test that parsing arguments for completion discards earlier commands."
   (with-temp-eshell
-   (let ((eshell-test-value '("foo" "bar")))
-     (insert "echo hi | cat")
-     (should (eshell-arguments-equal
-              (car (eshell-complete-parse-arguments))
-              '("cat"))))))
+   (insert "echo hi | cat")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            '("cat")))))
 
 (ert-deftest em-cmpl-test/parse-arguments/multiple-dots ()
   "Test parsing arguments with multiple dots like \".../\"."
@@ -123,6 +122,45 @@ ACTUAL and EXPECTED should both be lists of strings."
               (car (eshell-complete-parse-arguments))
               '("echo" "foo" "bar"))))))
 
+(ert-deftest em-cmpl-test/parse-arguments/unevaluated-subcommand ()
+  "Test that subcommands return a stub when parsing for completion."
+  (with-temp-eshell
+   (insert "echo {echo hi}")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            `("echo" ,(propertize
+                       "\0" 'eshell-argument-stub 'named-command)))))
+  (with-temp-eshell
+   (insert "echo ${echo hi}")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            `("echo" ,(propertize
+                       "\0" 'eshell-argument-stub 'named-command))))))
+
+(ert-deftest em-cmpl-test/parse-arguments/unevaluated-lisp-form ()
+  "Test that Lisp forms return a stub when parsing for completion."
+  (with-temp-eshell
+   (insert "echo (concat \"hi\")")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            `("echo" ,(propertize
+                       "\0" 'eshell-argument-stub 'lisp-command)))))
+  (with-temp-eshell
+   (insert "echo $(concat \"hi\")")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            `("echo" ,(propertize
+                       "\0" 'eshell-argument-stub 'lisp-command))))))
+
+(ert-deftest em-cmpl-test/parse-arguments/unevaluated-inner-subcommand ()
+  "Test that nested subcommands return a stub when parsing for completion."
+  (with-temp-eshell
+   (insert "echo $exec-path[${echo 0}]")
+   (should (eshell-arguments-equal
+            (car (eshell-complete-parse-arguments))
+            `("echo" ,(propertize
+                       "\0" 'eshell-argument-stub 'named-command))))))
+
 (ert-deftest em-cmpl-test/file-completion/unique ()
   "Test completion of file names when there's a unique result."
   (with-temp-eshell
@@ -150,14 +188,39 @@ ACTUAL and EXPECTED should both be lists of strings."
          (forward-line -1)
          (should (looking-at "Complete, but not unique")))))))
 
+(ert-deftest em-cmpl-test/file-completion/glob ()
+  "Test completion of file names using a glob."
+  (with-temp-eshell
+   (ert-with-temp-directory default-directory
+     (write-region nil nil (expand-file-name "file.txt"))
+     (write-region nil nil (expand-file-name "file.el"))
+     (should (equal (eshell-insert-and-complete "echo fi*.el")
+                    "echo file.el ")))))
+
 (ert-deftest em-cmpl-test/file-completion/after-list ()
   "Test completion of file names after previous list arguments.
 See bug#59956."
   (with-temp-eshell
-   (ert-with-temp-directory default-directory
-     (write-region nil nil (expand-file-name "file.txt"))
-     (should (equal (eshell-insert-and-complete "echo (list 1 2) fi")
-                    "echo (list 1 2) file.txt ")))))
+   (let ((eshell-test-value '("foo" "bar")))
+     (ert-with-temp-directory default-directory
+       (write-region nil nil (expand-file-name "file.txt"))
+       (should (equal (eshell-insert-and-complete "echo $eshell-test-value fi")
+                      "echo $eshell-test-value file.txt "))))))
+
+(ert-deftest em-cmpl-test/command-completion ()
+  "Test completion of command names like \"command\"."
+  (with-temp-eshell
+   (should (equal (eshell-insert-and-complete "listif")
+                  "listify "))))
+
+(ert-deftest em-cmpl-test/subcommand-completion ()
+  "Test completion of command names like \"{command}\"."
+  (with-temp-eshell
+   (should (equal (eshell-insert-and-complete "{ listif")
+                  "{ listify ")))
+  (with-temp-eshell
+   (should (equal (eshell-insert-and-complete "echo ${ listif")
+                  "echo ${ listify "))))
 
 (ert-deftest em-cmpl-test/lisp-symbol-completion ()
   "Test completion of Lisp forms like \"#'symbol\" and \"`symbol\".
@@ -174,7 +237,10 @@ See <lisp/eshell/esh-cmd.el>."
 See <lisp/eshell/esh-cmd.el>."
   (with-temp-eshell
    (should (equal (eshell-insert-and-complete "echo (eshell/ech")
-                  "echo (eshell/echo"))))
+                  "echo (eshell/echo")))
+  (with-temp-eshell
+   (should (equal (eshell-insert-and-complete "echo $(eshell/ech")
+                  "echo $(eshell/echo"))))
 
 (ert-deftest em-cmpl-test/special-ref-completion/type ()
   "Test completion of the start of special references like \"#<buffer\".
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 6767d9289f9..771bd5a419c 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -454,7 +454,7 @@ nil, use FUNCTION instead."
   (let ((temporary-file-directory
          (file-name-as-directory (make-temp-file "esh-vars-tests" t))))
     (unwind-protect
-        (eshell-command-result-equal "cat \"$<echo hi>\"" "hi")
+        (eshell-command-result-equal "cat \"$<echo \\\"hi\\\">\"" "hi")
       (delete-directory temporary-file-directory t))))
 
 (ert-deftest esh-var-test/quoted-interp-concat-cmd ()



reply via email to

[Prev in Thread] Current Thread [Next in Thread]