]> code.delx.au - gnu-emacs/blobdiff - lisp/eshell/esh-arg.el
Don’t create unnecessary marker in ‘delete-trailing-whitespace’
[gnu-emacs] / lisp / eshell / esh-arg.el
index 1fb8b7f4c3245d57c463998c5bab1e89a2046d1b..2f34c36d26b032cbde5221829041db516c3f3bd2 100644 (file)
@@ -1,6 +1,6 @@
-;;; esh-arg.el --- argument processing
+;;; esh-arg.el --- argument processing  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1999-201 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@gnu.org>
 
@@ -27,7 +27,7 @@
 
 (provide 'esh-arg)
 
-(eval-when-compile (require 'eshell))
+(require 'esh-mode)
 
 (defgroup eshell-arg nil
   "Argument parsing involves transforming the arguments passed on the
@@ -89,7 +89,7 @@ yield the values intended."
          (goto-char (match-end 0))
          (eshell-finish-arg)))))
 
-   ;; backslash before a special character means escape it
+   ;; parse backslash and the character after
    'eshell-parse-backslash
 
    ;; text beginning with ' is a literally quoted
@@ -202,6 +202,18 @@ If POS is nil, the location of point is checked."
     (or (= pos (point-max))
        (memq (char-after pos) eshell-delimiter-argument-list))))
 
+(defun eshell-quote-argument (string)
+  "Return STRING with magic characters quoted.
+Magic characters are those in `eshell-special-chars-outside-quoting'."
+  (let ((index 0))
+    (mapconcat (lambda (c)
+                (prog1
+                    (or (eshell-quote-backslash string index)
+                        (char-to-string c))
+                  (setq index (1+ index))))
+              string
+              "")))
+
 ;; Argument parsing
 
 (defun eshell-parse-arguments (beg end)
@@ -225,7 +237,7 @@ Point is left at the end of the arguments."
                    (let* ((here (point))
                           (arg (eshell-parse-argument)))
                      (if (= (point) here)
-                         (error "Failed to parse argument '%s'"
+                         (error "Failed to parse argument `%s'"
                                 (buffer-substring here (point-max))))
                      (and arg (nconc args (list arg)))))))
               (throw 'eshell-incomplete (if (listp delim)
@@ -266,7 +278,7 @@ Point is left at the end of the arguments."
     (eshell-resolve-current-argument)
     eshell-current-argument))
 
-(defsubst eshell-operator (&rest args)
+(defsubst eshell-operator (&rest _args)
   "A stub function that generates an error if a floating operator is found."
   (error "Unhandled operator in input text"))
 
@@ -293,34 +305,27 @@ If the character is itself a backslash, it needs no escaping."
          (string ?\\ char)))))
 
 (defun eshell-parse-backslash ()
-  "Parse a single backslash (\) character, which might mean escape.
-It only means escape if the character immediately following is a
-special character that is not itself a backslash."
+  "Parse a single backslash (\\) character and the character after.
+If the character after the backslash is special, always ignore
+the backslash and return the escaped character.
+
+Otherwise, if the backslash is not in quoted string, the
+backslash is ignored and the character after is returned.  If the
+backslash is in a quoted string, the backslash and the character
+after are both returned."
   (when (eq (char-after) ?\\)
-    (if (eshell-looking-at-backslash-return (point))
-       (throw 'eshell-incomplete ?\\)
-      (if (and (not (eq (char-after (1+ (point))) ?\\))
-              (if eshell-current-quoted
-                  (memq (char-after (1+ (point)))
-                        eshell-special-chars-inside-quoting)
-                (memq (char-after (1+ (point)))
-                      eshell-special-chars-outside-quoting)))
-         (progn
-           (forward-char 2)
-           (list 'eshell-escape-arg
-                 (char-to-string (char-before))))
-       ;; allow \\<RET> to mean a literal "\" character followed by a
-       ;; normal return, rather than a backslash followed by a line
-       ;; continuator (i.e., "\\ + \n" rather than "\ + \\n").  This
-       ;; is necessary because backslashes in Eshell are not special
-       ;; unless they either precede something special, or precede a
-       ;; backslash that precedes something special.  (Mainly this is
-       ;; done to make using backslash on Windows systems more
-       ;; natural-feeling).
-       (if (eshell-looking-at-backslash-return (1+ (point)))
-           (forward-char))
-       (forward-char)
-       "\\"))))
+    (when (eshell-looking-at-backslash-return (point))
+       (throw 'eshell-incomplete ?\\))
+    (forward-char 2) ; Move one char past the backslash.
+    ;; If the char is in a quote, backslash only has special meaning
+    ;; if it is escaping a special char.
+    (if eshell-current-quoted
+        (if (memq (char-before) eshell-special-chars-inside-quoting)
+            (list 'eshell-escape-arg (char-to-string (char-before)))
+          (concat "\\" (char-to-string (char-before))))
+      (if (memq (char-before) eshell-special-chars-outside-quoting)
+          (list 'eshell-escape-arg (char-to-string (char-before)))
+        (char-to-string (char-before))))))
 
 (defun eshell-parse-literal-quote ()
   "Parse a literally quoted string.  Nothing has special meaning!"
@@ -352,22 +357,31 @@ special character that is not itself a backslash."
          (goto-char (1+ end)))))))
 
 (defun eshell-parse-special-reference ()
-  "Parse a special syntax reference, of the form '#<type arg>'."
-  (if (and (not eshell-current-argument)
-          (not eshell-current-quoted)
-          (looking-at "#<\\(buffer\\|process\\)\\s-"))
-      (let ((here (point)))
-       (goto-char (match-end 0))
-       (let* ((buffer-p (string= (match-string 1) "buffer"))
-              (end (eshell-find-delimiter ?\< ?\>)))
-         (if (not end)
-             (throw 'eshell-incomplete ?\<)
-           (if (eshell-arg-delimiter (1+ end))
-               (prog1
-                   (list (if buffer-p 'get-buffer-create 'get-process)
-                         (buffer-substring-no-properties (point) end))
-                 (goto-char (1+ end)))
-             (ignore (goto-char here))))))))
+  "Parse a special syntax reference, of the form `#<args>'.
+
+args           := `type' `whitespace' `arbitrary-args' | `arbitrary-args'
+type           := \"buffer\" or \"process\"
+arbitrary-args := any string of characters.
+
+If the form has no `type', the syntax is parsed as if `type' were
+\"buffer\"."
+  (when (and (not eshell-current-argument)
+             (not eshell-current-quoted)
+             (looking-at "#<\\(\\(buffer\\|process\\)\\s-\\)?"))
+    (let ((here (point)))
+      (goto-char (match-end 0)) ;; Go to the end of the match.
+      (let ((buffer-p (if (match-string 1)
+                          (string= (match-string 2) "buffer")
+                        t)) ;; buffer-p is non-nil by default.
+            (end (eshell-find-delimiter ?\< ?\>)))
+        (when (not end)
+          (throw 'eshell-incomplete ?\<))
+        (if (eshell-arg-delimiter (1+ end))
+            (prog1
+                (list (if buffer-p 'get-buffer-create 'get-process)
+                      (buffer-substring-no-properties (point) end))
+              (goto-char (1+ end)))
+          (ignore (goto-char here)))))))
 
 (defun eshell-parse-delimiter ()
   "Parse an argument delimiter, which is essentially a command operator."