From: Stefan Monnier Date: Mon, 16 Sep 2013 18:23:30 +0000 (-0400) Subject: * lisp/eshell/esh-opt.el: Fix last change to set lexical-vars properly. X-Git-Tag: emacs-24.3.90~173^2^2~42^2~45^2~387^2~1604 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=70568a90a17f4ea136d99f0c8eed5088322fb5ed;p=emacs.git * 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 --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 44a81ee32fc..f5710d85e16 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,19 @@ +2013-09-16 Stefan Monnier + + * 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 * progmodes/ruby-mode.el (ruby-operator-re): Consider line diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el index e9252cb540e..3f5bcb641ac 100644 --- a/lisp/eshell/esh-opt.el +++ b/lisp/eshell/esh-opt.el @@ -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))))) - -(defun eshell-process-option (name switch kind ai 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) + (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 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 diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 5fa591a3082..5e0aad8345f 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -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))