1 ;;; esh-opt.el --- command options processing
3 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4 ;; 2008 Free Software Foundation, Inc.
6 ;; Author: John Wiegley <johnw@gnu.org>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27 (eval-when-compile (require 'esh-ext
))
29 (defgroup eshell-opt nil
30 "The options processing code handles command argument parsing for
31 Eshell commands implemented in Lisp."
32 :tag
"Command options processing"
37 (defmacro eshell-eval-using-options
(name macro-args
38 options
&rest body-forms
)
39 "Process NAME's MACRO-ARGS using a set of command line OPTIONS.
40 After doing so, settings will be stored in local symbols as declared
41 by OPTIONS; FORMS will then be evaluated -- assuming all was OK.
43 The syntax of OPTIONS is:
45 '((?C nil nil multi-column \"multi-column display\")
46 (nil \"help\" nil nil \"show this usage display\")
47 (?r \"reverse\" nil reverse-list \"reverse order while sorting\")
49 :usage \"[OPTION]... [FILE]...
50 List information about the FILEs (the current directory by default).
51 Sort entries alphabetically across.\")
53 `eshell-eval-using-options' returns the value of the last form in
54 BODY-FORMS. If instead an external command is run, the tag
55 `eshell-external' will be thrown with the new process for its value.
57 Lastly, any remaining arguments will be available in a locally
58 interned variable `args' (created using a `let' form)."
59 (declare (debug (form form sexp body
)))
61 ,(if (memq ':preserve-args
(cadr options
))
63 (list 'eshell-stringify-list
64 (list 'eshell-flatten-list macro-args
)))))
65 (let ,(append (mapcar (function
67 (or (and (listp opt
) (nth 3 opt
))
68 'eshell-option-stub
)))
70 '(usage-msg last-value ext-command args
))
71 (eshell-do-opt ,name
,options
(quote ,body-forms
)))))
73 ;;; Internal Functions:
81 (defun eshell-do-opt (name options body-forms
)
82 "Helper function for `eshell-eval-using-options'.
83 This code doesn't really need to be macro expanded everywhere."
87 (catch 'eshell-ext-command
92 (if (and (= (length args
) 0)
93 (memq ':show-usage options
))
95 (eshell-show-usage name options
)))
96 (setq args
(eshell-process-args name args options
)
97 last-value
(eval (append (list 'progn
)
100 (error "%s" usage-msg
))))
101 (throw 'eshell-external
102 (eshell-external-command ext-command args
))
105 (defun eshell-show-usage (name options
)
106 "Display the usage message for NAME, using OPTIONS."
107 (let ((usage (format "usage: %s %s\n\n" name
108 (cadr (memq ':usage options
))))
109 (extcmd (memq ':external options
))
110 (post-usage (memq ':post-usage options
))
113 (when (listp (car options
))
114 (let ((opt (car options
)))
116 (cond ((and (nth 0 opt
)
120 (format " %-20s %s\n"
121 (format "-%c, --%s" (nth 0 opt
)
127 (format " %-20s %s\n"
128 (format "-%c" (nth 0 opt
))
133 (format " %-20s %s\n"
134 (format " --%s" (nth 1 opt
))
136 (t (setq had-option nil
)))))
137 (setq options
(cdr options
)))
139 (setq usage
(concat usage
(and had-option
"\n")
142 (setq extcmd
(eshell-search-path (cadr extcmd
)))
147 This command is implemented in Lisp. If an unrecognized option is
148 passed to this command, the external version '%s'
149 will be called instead." extcmd
)))))
150 (throw 'eshell-usage usage
)))
152 (defun eshell-set-option (name ai opt options
)
153 "Using NAME's remaining args (index AI), set the OPT within OPTIONS.
154 If the option consumes an argument for its value, the argument list
156 (if (not (nth 3 opt
))
157 (eshell-show-usage name options
)
158 (if (eq (nth 2 opt
) t
)
159 (if (> ai
(length args
))
160 (error "%s: missing option argument" name
)
161 (set (nth 3 opt
) (nth ai args
))
163 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
))
164 (setq args
(cdr args
))))
165 (set (nth 3 opt
) (or (nth 2 opt
) t
)))))
167 (defun eshell-process-option (name switch kind ai options
)
168 "For NAME, process SWITCH (of type KIND), from args at index AI.
169 The SWITCH will be looked up in the set of OPTIONS.
171 SWITCH should be either a string or character. KIND should be the
172 integer 0 if it's a character, or 1 if it's a string.
174 The SWITCH is then be matched against OPTIONS. If no matching handler
175 is found, and an :external command is defined (and available), it will
176 be called; otherwise, an error will be triggered to say that the
177 switch is unrecognized."
178 (let* ((opts options
)
181 (if (and (listp (car opts
))
182 (nth kind
(car opts
))
184 (eq switch
(nth kind
(car opts
)))
185 (string= switch
(nth kind
(car opts
)))))
187 (eshell-set-option name ai
(car opts
) options
)
188 (setq found t opts nil
))
189 (setq opts
(cdr opts
))))
191 (let ((extcmd (memq ':external options
)))
193 (setq extcmd
(eshell-search-path (cadr extcmd
)))
195 (throw 'eshell-ext-command extcmd
)
196 (if (characterp switch
)
197 (error "%s: unrecognized option -%c" name switch
)
198 (error "%s: unrecognized option --%s" name switch
))))))))
200 (defun eshell-process-args (name args options
)
201 "Process the given ARGS using OPTIONS.
202 This assumes that symbols have been intern'd by `eshell-with-options'."
204 (while (< ai
(length args
))
205 (setq arg
(nth ai args
))
206 (if (not (and (stringp arg
)
207 (string-match "^-\\(-\\)?\\(.*\\)" arg
)))
209 (let* ((dash (match-string 1 arg
))
210 (switch (match-string 2 arg
)))
212 (setq args
(cdr args
))
213 (setcdr (nthcdr (1- ai
) args
) (nthcdr (1+ ai
) args
)))
215 (if (> (length switch
) 0)
216 (eshell-process-option name switch
1 ai options
)
217 (setq ai
(length args
)))
218 (let ((len (length switch
))
221 (eshell-process-option name
(aref switch index
) 0 ai options
)
222 (setq index
(1+ index
)))))))))
227 ;; arch-tag: 45c6c2d0-8091-46a1-a205-2f4bafd8230c
228 ;;; esh-opt.el ends here