summaryrefslogtreecommitdiff
path: root/lisp/eshell/esh-opt.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/eshell/esh-opt.el')
-rw-r--r--lisp/eshell/esh-opt.el109
1 files changed, 71 insertions, 38 deletions
diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el
index d96b77ddd37..f52b70fe7a6 100644
--- a/lisp/eshell/esh-opt.el
+++ b/lisp/eshell/esh-opt.el
@@ -97,10 +97,10 @@ let-bound variable `args'."
(declare (debug (form form sexp body)))
`(let* ((temp-args
,(if (memq ':preserve-args (cadr options))
- macro-args
+ (list 'copy-tree macro-args)
(list 'eshell-stringify-list
(list 'flatten-tree macro-args))))
- (processed-args (eshell--do-opts ,name ,options temp-args))
+ (processed-args (eshell--do-opts ,name ,options temp-args ,macro-args))
,@(delete-dups
(delq nil (mapcar (lambda (opt)
(and (listp opt) (nth 3 opt)
@@ -117,7 +117,7 @@ let-bound variable `args'."
;; Documented part of the interface; see eshell-eval-using-options.
(defvar eshell--args)
-(defun eshell--do-opts (name options args)
+(defun eshell--do-opts (name options args orig-args)
"Helper function for `eshell-eval-using-options'.
This code doesn't really need to be macro expanded everywhere."
(require 'esh-ext)
@@ -135,7 +135,7 @@ This code doesn't really need to be macro expanded everywhere."
(error "%s" usage-msg))))))
(if ext-command
(throw 'eshell-external
- (eshell-external-command ext-command args))
+ (eshell-external-command ext-command orig-args))
args)))
(defun eshell-show-usage (name options)
@@ -187,49 +187,82 @@ passed to this command, the external version `%s'
will be called instead." extcmd)))))
(throw 'eshell-usage usage)))
-(defun eshell--set-option (name ai opt options opt-vals)
+(defun eshell--split-switch (switch kind)
+ "Split SWITCH into its option name and potential value, if any.
+KIND should be the integer 0 if SWITCH is a short option, or 1 if it's
+a long option."
+ (if (eq kind 0)
+ ;; Short option
+ (cons (aref switch 0)
+ (and (> (length switch) 1) (substring switch 1)))
+ ;; Long option
+ (save-match-data
+ (string-match "\\([^=]*\\)\\(?:=\\(.*\\)\\)?" switch)
+ (cons (match-string 1 switch) (match-string 2 switch)))))
+
+(defun eshell--set-option (name ai opt value options opt-vals)
"Using NAME's remaining args (index AI), set the OPT within OPTIONS.
-If the option consumes an argument for its value, the argument list
-will be modified."
+VALUE is the potential value of the OPT, coming from args like
+\"-fVALUE\" or \"--foo=VALUE\", or nil if no value was supplied. If
+OPT doesn't consume a value, return VALUE unchanged so that it can be
+processed later; otherwise, return nil.
+
+If the OPT consumes an argument for its value and VALUE is nil, the
+argument list will be modified."
(if (not (nth 3 opt))
(eshell-show-usage name options)
- (setcdr (assq (nth 3 opt) opt-vals)
- (if (eq (nth 2 opt) t)
- (if (> ai (length eshell--args))
- (error "%s: missing option argument" name)
- (pop (nthcdr ai eshell--args)))
- (or (nth 2 opt) t)))))
+ (if (eq (nth 2 opt) t)
+ (progn
+ (setcdr (assq (nth 3 opt) opt-vals)
+ (or value
+ (if (> ai (length eshell--args))
+ (error "%s: missing option argument" name)
+ (pop (nthcdr ai eshell--args)))))
+ nil)
+ (setcdr (assq (nth 3 opt) opt-vals)
+ (or (nth 2 opt) t))
+ value)))
(defun eshell--process-option (name switch kind ai options opt-vals)
"For NAME, process SWITCH (of type KIND), from args at index AI.
The SWITCH will be looked up in the set of OPTIONS.
-SWITCH should be either a string or character. KIND should be the
-integer 0 if it's a character, or 1 if it's a string.
-
-The SWITCH is then be matched against OPTIONS. If no matching handler
-is found, and an :external command is defined (and available), it will
-be called; otherwise, an error will be triggered to say that the
-switch is unrecognized."
- (let* ((opts options)
- found)
+SWITCH should be a string starting with the option to process,
+possibly followed by its value, e.g. \"u\" or \"uUSER\". KIND should
+be the integer 0 if it's a short option, or 1 if it's a long option.
+
+The SWITCH is then be matched against OPTIONS. If KIND is 0 and the
+SWITCH matches an option that doesn't take a value, return the
+remaining characters in SWITCH to be processed later as further short
+options.
+
+If no matching handler is found, and an :external command is defined
+(and available), it will be called; otherwise, an error will be
+triggered to say that the switch is unrecognized."
+ (let ((switch (eshell--split-switch switch kind))
+ (opts options)
+ found remaining)
(while opts
(if (and (listp (car opts))
- (nth kind (car opts))
- (equal switch (nth kind (car opts))))
+ (equal (car switch) (nth kind (car opts))))
(progn
- (eshell--set-option name ai (car opts) options opt-vals)
+ (setq remaining (eshell--set-option name ai (car opts)
+ (cdr switch) options opt-vals))
+ (when (and remaining (eq kind 1))
+ (error "%s: option --%s doesn't allow an argument"
+ name (car switch)))
(setq found t opts nil))
(setq opts (cdr opts))))
- (unless found
+ (if found
+ remaining
(let ((extcmd (memq ':external options)))
(when extcmd
- (setq extcmd (eshell-search-path (cadr extcmd)))
- (if extcmd
- (throw 'eshell-ext-command extcmd)
- (error (if (characterp switch) "%s: unrecognized option -%c"
- "%s: unrecognized option --%s")
- name switch)))))))
+ (setq extcmd (eshell-search-path (cadr extcmd))))
+ (if extcmd
+ (throw 'eshell-ext-command extcmd)
+ (error (if (characterp (car switch)) "%s: unrecognized option -%c"
+ "%s: unrecognized option --%s")
+ name (car switch)))))))
(defun eshell--process-args (name args options)
"Process the given ARGS using OPTIONS."
@@ -250,6 +283,9 @@ switch is unrecognized."
(memq :parse-leading-options-only options))))
(setq arg (nth ai eshell--args))
(if (not (and (stringp arg)
+ ;; A string of length 1 can't be an option; (if
+ ;; it's "-", that generally means stdin).
+ (> (length arg) 1)
(string-match "^-\\(-\\)?\\(.*\\)" arg)))
;; Positional argument found, skip
(setq ai (1+ ai)
@@ -262,12 +298,9 @@ switch is unrecognized."
(if (> (length switch) 0)
(eshell--process-option name switch 1 ai options opt-vals)
(setq ai (length eshell--args)))
- (let ((len (length switch))
- (index 0))
- (while (< index len)
- (eshell--process-option name (aref switch index)
- 0 ai options opt-vals)
- (setq index (1+ index))))))))
+ (while (> (length switch) 0)
+ (setq switch (eshell--process-option name switch 0
+ ai options opt-vals)))))))
(nconc (mapcar #'cdr opt-vals) eshell--args)))
(provide 'esh-opt)