diff options
| author | Jim Porter | 2022-01-04 12:58:38 -0800 |
|---|---|---|
| committer | Eli Zaretskii | 2022-01-12 16:58:37 +0200 |
| commit | db745f37aec2adc44ec4b2eae0720e0365ed0ca9 (patch) | |
| tree | 1c2b405ad2bc81d34fd2ae140c18855d78460665 /lisp | |
| parent | 7ebcb4b6f2f4531ebc893bb3b2f74d6298bf9b41 (diff) | |
| download | emacs-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.el | 90 |
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' | |||
| 187 | will be called instead." extcmd))))) | 187 | will 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. | ||
| 192 | KIND should be the integer 0 if SWITCH is a short option, or 1 if it's | ||
| 193 | a 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. |
| 192 | If the option consumes an argument for its value, the argument list | 205 | VALUE is the potential value of the OPT, coming from args like |
| 193 | will be modified." | 206 | \"-fVALUE\" or \"--foo=VALUE\", or nil if no value was supplied. If |
| 207 | OPT doesn't consume a value, return VALUE unchanged so that it can be | ||
| 208 | processed later; otherwsie, return nil. | ||
| 209 | |||
| 210 | If the OPT consumes an argument for its value and VALUE is nil, the | ||
| 211 | argument 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. |
| 205 | The SWITCH will be looked up in the set of OPTIONS. | 228 | The SWITCH will be looked up in the set of OPTIONS. |
| 206 | 229 | ||
| 207 | SWITCH should be either a string or character. KIND should be the | 230 | SWITCH should be a string starting with the option to process, |
| 208 | integer 0 if it's a character, or 1 if it's a string. | 231 | possibly followed by its value, e.g. \"u\" or \"uUSER\". KIND should |
| 209 | 232 | be the integer 0 if it's a short option, or 1 if it's a long option. | |
| 210 | The SWITCH is then be matched against OPTIONS. If no matching handler | 233 | |
| 211 | is found, and an :external command is defined (and available), it will | 234 | The SWITCH is then be matched against OPTIONS. If KIND is 0 and the |
| 212 | be called; otherwise, an error will be triggered to say that the | 235 | SWITCH matches an option that doesn't take a value, return the |
| 213 | switch is unrecognized." | 236 | remaining characters in SWITCH to be processed later as further short |
| 214 | (let* ((opts options) | 237 | options. |
| 215 | found) | 238 | |
| 239 | If no matching handler is found, and an :external command is defined | ||
| 240 | (and available), it will be called; otherwise, an error will be | ||
| 241 | triggered 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) |