aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorJim Porter2022-01-04 12:58:38 -0800
committerEli Zaretskii2022-01-12 16:58:37 +0200
commitdb745f37aec2adc44ec4b2eae0720e0365ed0ca9 (patch)
tree1c2b405ad2bc81d34fd2ae140c18855d78460665 /lisp
parent7ebcb4b6f2f4531ebc893bb3b2f74d6298bf9b41 (diff)
downloademacs-db745f37aec2adc44ec4b2eae0720e0365ed0ca9.tar.gz
emacs-db745f37aec2adc44ec4b2eae0720e0365ed0ca9.zip
Follow POSIX/GNU argument conventions for 'eshell-eval-using-options'
* lisp/eshell/esh-opt.el (eshell--split-switch): New function. (eshell-set-option): Allow setting a supplied value instead of always consuming from 'eshell--args'. (eshell--process-option): Support consuming option values specified as a single token. (eshell--process-args): For short options, pass full switch token to 'eshell--process-option'. * test/lisp/eshell/esh-opt-tests.el (esh-opt-process-args-test): Fix test. (test-eshell-eval-using-options): Add tests for various types of options. * doc/misc/eshell.texi (Defining new built-in commands): New subsection, describe how to use 'eshell-eval-using-options'. * etc/NEWS: Announce the change.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/eshell/esh-opt.el90
1 files changed, 60 insertions, 30 deletions
diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el
index d96b77ddd37..bba1c4ad25d 100644
--- a/lisp/eshell/esh-opt.el
+++ b/lisp/eshell/esh-opt.el
@@ -187,49 +187,82 @@ passed to this command, the external version `%s'
187will be called instead." extcmd))))) 187will be called instead." extcmd)))))
188 (throw 'eshell-usage usage))) 188 (throw 'eshell-usage usage)))
189 189
190(defun eshell--set-option (name ai opt options opt-vals) 190(defun eshell--split-switch (switch kind)
191 "Split SWITCH into its option name and potential value, if any.
192KIND should be the integer 0 if SWITCH is a short option, or 1 if it's
193a long option."
194 (if (eq kind 0)
195 ;; Short option
196 (cons (aref switch 0)
197 (and (> (length switch) 1) (substring switch 1)))
198 ;; Long option
199 (save-match-data
200 (string-match "\\([^=]*\\)\\(?:=\\(.*\\)\\)?" switch)
201 (cons (match-string 1 switch) (match-string 2 switch)))))
202
203(defun eshell--set-option (name ai opt value options opt-vals)
191 "Using NAME's remaining args (index AI), set the OPT within OPTIONS. 204 "Using NAME's remaining args (index AI), set the OPT within OPTIONS.
192If the option consumes an argument for its value, the argument list 205VALUE is the potential value of the OPT, coming from args like
193will be modified." 206\"-fVALUE\" or \"--foo=VALUE\", or nil if no value was supplied. If
207OPT doesn't consume a value, return VALUE unchanged so that it can be
208processed later; otherwsie, return nil.
209
210If the OPT consumes an argument for its value and VALUE is nil, the
211argument list will be modified."
194 (if (not (nth 3 opt)) 212 (if (not (nth 3 opt))
195 (eshell-show-usage name options) 213 (eshell-show-usage name options)
196 (setcdr (assq (nth 3 opt) opt-vals) 214 (if (eq (nth 2 opt) t)
197 (if (eq (nth 2 opt) t) 215 (progn
198 (if (> ai (length eshell--args)) 216 (setcdr (assq (nth 3 opt) opt-vals)
199 (error "%s: missing option argument" name) 217 (or value
200 (pop (nthcdr ai eshell--args))) 218 (if (> ai (length eshell--args))
201 (or (nth 2 opt) t))))) 219 (error "%s: missing option argument" name)
220 (pop (nthcdr ai eshell--args)))))
221 nil)
222 (setcdr (assq (nth 3 opt) opt-vals)
223 (or (nth 2 opt) t))
224 value)))
202 225
203(defun eshell--process-option (name switch kind ai options opt-vals) 226(defun eshell--process-option (name switch kind ai options opt-vals)
204 "For NAME, process SWITCH (of type KIND), from args at index AI. 227 "For NAME, process SWITCH (of type KIND), from args at index AI.
205The SWITCH will be looked up in the set of OPTIONS. 228The SWITCH will be looked up in the set of OPTIONS.
206 229
207SWITCH should be either a string or character. KIND should be the 230SWITCH should be a string starting with the option to process,
208integer 0 if it's a character, or 1 if it's a string. 231possibly followed by its value, e.g. \"u\" or \"uUSER\". KIND should
209 232be the integer 0 if it's a short option, or 1 if it's a long option.
210The SWITCH is then be matched against OPTIONS. If no matching handler 233
211is found, and an :external command is defined (and available), it will 234The SWITCH is then be matched against OPTIONS. If KIND is 0 and the
212be called; otherwise, an error will be triggered to say that the 235SWITCH matches an option that doesn't take a value, return the
213switch is unrecognized." 236remaining characters in SWITCH to be processed later as further short
214 (let* ((opts options) 237options.
215 found) 238
239If no matching handler is found, and an :external command is defined
240(and available), it will be called; otherwise, an error will be
241triggered to say that the switch is unrecognized."
242 (let ((switch (eshell--split-switch switch kind))
243 (opts options)
244 found remaining)
216 (while opts 245 (while opts
217 (if (and (listp (car opts)) 246 (if (and (listp (car opts))
218 (nth kind (car opts)) 247 (equal (car switch) (nth kind (car opts))))
219 (equal switch (nth kind (car opts))))
220 (progn 248 (progn
221 (eshell--set-option name ai (car opts) options opt-vals) 249 (setq remaining (eshell--set-option name ai (car opts)
250 (cdr switch) options opt-vals))
251 (when (and remaining (eq kind 1))
252 (error "%s: option --%s doesn't allow an argument"
253 name (car switch)))
222 (setq found t opts nil)) 254 (setq found t opts nil))
223 (setq opts (cdr opts)))) 255 (setq opts (cdr opts))))
224 (unless found 256 (if found
257 remaining
225 (let ((extcmd (memq ':external options))) 258 (let ((extcmd (memq ':external options)))
226 (when extcmd 259 (when extcmd
227 (setq extcmd (eshell-search-path (cadr extcmd))) 260 (setq extcmd (eshell-search-path (cadr extcmd)))
228 (if extcmd 261 (if extcmd
229 (throw 'eshell-ext-command extcmd) 262 (throw 'eshell-ext-command extcmd)
230 (error (if (characterp switch) "%s: unrecognized option -%c" 263 (error (if (characterp (car switch)) "%s: unrecognized option -%c"
231 "%s: unrecognized option --%s") 264 "%s: unrecognized option --%s")
232 name switch))))))) 265 name (car switch))))))))
233 266
234(defun eshell--process-args (name args options) 267(defun eshell--process-args (name args options)
235 "Process the given ARGS using OPTIONS." 268 "Process the given ARGS using OPTIONS."
@@ -262,12 +295,9 @@ switch is unrecognized."
262 (if (> (length switch) 0) 295 (if (> (length switch) 0)
263 (eshell--process-option name switch 1 ai options opt-vals) 296 (eshell--process-option name switch 1 ai options opt-vals)
264 (setq ai (length eshell--args))) 297 (setq ai (length eshell--args)))
265 (let ((len (length switch)) 298 (while (> (length switch) 0)
266 (index 0)) 299 (setq switch (eshell--process-option name switch 0
267 (while (< index len) 300 ai options opt-vals)))))))
268 (eshell--process-option name (aref switch index)
269 0 ai options opt-vals)
270 (setq index (1+ index))))))))
271 (nconc (mapcar #'cdr opt-vals) eshell--args))) 301 (nconc (mapcar #'cdr opt-vals) eshell--args)))
272 302
273(provide 'esh-opt) 303(provide 'esh-opt)