* lisp/eshell/esh-opt.el: Fix last change to set lexical-vars properly.

(eshell--do-opts): Rename from eshell-do-opt, remove arg `body-fun',
return args and options.
(eshell-eval-using-options): Use the new return value of
eshell--do-opts to set the options's vars in their scope.
(eshell--set-option): Rename from eshell-set-option.
Add arg `opt-vals'.
(eshell--process-option): Rename from eshell-process-option.
Add arg `opt-vals'.
(eshell--process-args): Use an `opt-vals' alist to store the options's
values during their processing and return them additionally to the
remaining args.

Fixes: debbugs:15379
This commit is contained in:
Stefan Monnier 2013-09-16 14:23:30 -04:00
parent 3f386383dc
commit 70568a90a1
3 changed files with 76 additions and 52 deletions

View file

@ -1,3 +1,19 @@
2013-09-16 Stefan Monnier <monnier@iro.umontreal.ca>
* eshell/esh-opt.el: Fix last change to set lexical-vars properly
(bug#15379).
(eshell--do-opts): Rename from eshell-do-opt, remove arg `body-fun',
return args and options.
(eshell-eval-using-options): Use the new return value of
eshell--do-opts to set the options's vars in their scope.
(eshell--set-option): Rename from eshell-set-option.
Add arg `opt-vals'.
(eshell--process-option): Rename from eshell-process-option.
Add arg `opt-vals'.
(eshell--process-args): Use an `opt-vals' alist to store the options's
values during their processing and return them additionally to the
remaining args.
2013-09-15 Dmitry Gutov <dgutov@yandex.ru>
* progmodes/ruby-mode.el (ruby-operator-re): Consider line

View file

@ -98,45 +98,44 @@ the new process for its value.
Lastly, any remaining arguments will be available in a locally
interned variable `args' (created using a `let' form)."
(declare (debug (form form sexp body)))
`(let ((temp-args
,(if (memq ':preserve-args (cadr options))
macro-args
(list 'eshell-stringify-list
(list 'eshell-flatten-list macro-args)))))
(let ,(delq nil (mapcar (lambda (opt)
(and (listp opt) (nth 3 opt)))
(cadr options)))
;; FIXME: `options' ends up hiding some variable names under `quote',
;; which is incompatible with lexical scoping!!
(eshell-do-opt ,name ,options (lambda (args) ,@body-forms) temp-args))))
`(let* ((temp-args
,(if (memq ':preserve-args (cadr options))
macro-args
(list 'eshell-stringify-list
(list 'eshell-flatten-list macro-args))))
(processed-args (eshell--do-opts ,name ,options temp-args))
,@(delete-dups
(delq nil (mapcar (lambda (opt)
(and (listp opt) (nth 3 opt)
`(,(nth 3 opt) (pop processed-args))))
;; `options' is of the form (quote OPTS).
(cadr options))))
(args processed-args))
,@body-forms))
;;; Internal Functions:
;; Documented part of the interface; see eshell-eval-using-options.
(defvar eshell--args)
(defun eshell-do-opt (name options body-fun args)
(defun eshell--do-opts (name options args)
"Helper function for `eshell-eval-using-options'.
This code doesn't really need to be macro expanded everywhere."
(let* (last-value
(ext-command
(catch 'eshell-ext-command
(let ((usage-msg
(catch 'eshell-usage
(setq last-value nil)
(if (and (= (length args) 0)
(memq ':show-usage options))
(throw 'eshell-usage
(eshell-show-usage name options)))
(setq args (eshell-process-args name args options)
last-value (funcall body-fun args))
nil)))
(when usage-msg
(error "%s" usage-msg))))))
(let ((ext-command
(catch 'eshell-ext-command
(let ((usage-msg
(catch 'eshell-usage
(if (and (= (length args) 0)
(memq ':show-usage options))
(eshell-show-usage name options)
(setq args (eshell--process-args name args options))
nil))))
(when usage-msg
(error "%s" usage-msg))))))
(if ext-command
(throw 'eshell-external
(eshell-external-command ext-command args))
last-value)))
(throw 'eshell-external
(eshell-external-command ext-command args))
args)))
(defun eshell-show-usage (name options)
"Display the usage message for NAME, using OPTIONS."
@ -185,23 +184,24 @@ 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)
(defun eshell--set-option (name ai opt 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."
(if (not (nth 3 opt))
(eshell-show-usage name options)
(if (eq (nth 2 opt) t)
(if (> ai (length eshell--args))
(error "%s: missing option argument" name)
(set (nth 3 opt) (nth ai eshell--args))
(if (> ai 0)
(setcdr (nthcdr (1- ai) eshell--args)
(nthcdr (1+ ai) eshell--args))
(setq eshell--args (cdr eshell--args))))
(set (nth 3 opt) (or (nth 2 opt) t)))))
(setcdr (assq (nth 3 opt) opt-vals)
(if (eq (nth 2 opt) t)
(if (> ai (length eshell--args))
(error "%s: missing option argument" name)
(prog1 (nth ai eshell--args)
(if (> ai 0)
(setcdr (nthcdr (1- ai) eshell--args)
(nthcdr (1+ ai) eshell--args))
(setq eshell--args (cdr eshell--args)))))
(or (nth 2 opt) t)))))
(defun eshell-process-option (name switch kind ai options)
(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.
@ -219,7 +219,7 @@ switch is unrecognized."
(nth kind (car opts))
(equal switch (nth kind (car opts))))
(progn
(eshell-set-option name ai (car opts) options)
(eshell--set-option name ai (car opts) options opt-vals)
(setq found t opts nil))
(setq opts (cdr opts))))
(unless found
@ -232,11 +232,18 @@ switch is unrecognized."
"%s: unrecognized option --%s")
name switch)))))))
(defun eshell-process-args (name args options)
"Process the given ARGS using OPTIONS.
This assumes that symbols have been intern'd by `eshell-eval-using-options'."
(let ((ai 0) arg
(eshell--args args))
(defun eshell--process-args (name args options)
"Process the given ARGS using OPTIONS."
(let* ((seen ())
(opt-vals (delq nil (mapcar (lambda (opt)
(when (listp opt)
(let ((sym (nth 3 opt)))
(when (and sym (not (memq sym seen)))
(push sym seen)
(list sym)))))
options)))
(ai 0) arg
(eshell--args args))
(while (< ai (length args))
(setq arg (nth ai args))
(if (not (and (stringp arg)
@ -249,13 +256,14 @@ This assumes that symbols have been intern'd by `eshell-eval-using-options'."
(setcdr (nthcdr (1- ai) args) (nthcdr (1+ ai) args)))
(if dash
(if (> (length switch) 0)
(eshell-process-option name switch 1 ai options)
(eshell--process-option name switch 1 ai options opt-vals)
(setq ai (length args)))
(let ((len (length switch))
(index 0))
(while (< index len)
(eshell-process-option name (aref switch index) 0 ai options)
(setq index (1+ index)))))))))
args)
(eshell--process-option name (aref switch index)
0 ai options opt-vals)
(setq index (1+ index))))))))
(nconc (mapcar #'cdr opt-vals) args)))
;;; esh-opt.el ends here

View file

@ -144,7 +144,7 @@ function `string-to-number'."
Otherwise, evaluates FORM with no error handling."
(declare (indent 2))
(if eshell-handle-errors
`(condition-case ,tag
`(condition-case-unless-debug ,tag
,form
,@handlers)
form))