-;;; esh-arg.el --- argument processing
+;;; esh-arg.el --- argument processing -*- lexical-binding:t -*-
-;; Copyright (C) 1999-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
;; Author: John Wiegley <johnw@gnu.org>
(provide 'esh-arg)
-(eval-when-compile (require 'eshell))
+(require 'esh-mode)
(defgroup eshell-arg nil
"Argument parsing involves transforming the arguments passed on the
(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
;;; User Variables:
-(defcustom eshell-arg-load-hook '(eshell-arg-initialize)
+(defcustom eshell-arg-load-hook nil
"A hook that gets run when `eshell-arg' is loaded."
+ :version "24.1" ; removed eshell-arg-initialize
:type 'hook
:group 'eshell-arg)
(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)
(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)
(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"))
(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!"
(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."