Skip to content

Optionally treat first top-level argument as an implicit terminator - #7

Open
mistekko wants to merge 3 commits into
sjl:masterfrom
mistekko:master
Open

Optionally treat first top-level argument as an implicit terminator#7
mistekko wants to merge 3 commits into
sjl:masterfrom
mistekko:master

Conversation

@mistekko

Copy link
Copy Markdown

Some commands, time and watch for example, treat their first non-hyphenated arguments as names of commands and their remaining arguments as to be passed to those commands. Currently this is not possible in Adopt, but this commit, by simply adding another optional argument to parse-options, makes it possible .
Perhaps there is a more elegant way of doing this. This commit will force the user to pass a value for the arguments parameter in parse-options (and thus parse-options-or-exit) if they wish to parse options in the time/watch style.

Standard POSIX commands like `time' and `watch' treat their first non-
hyphenated arguments as the name of a command and the remaining
arguments as to be passed to that command. This was not possible in
Adopt, but by adding another optional argument to `parse-options' this
commit makes it possible.
@sjl

sjl commented Mar 20, 2026

Copy link
Copy Markdown
Owner

Interesting, I can see the use case here. A couple of thoughts:

  • Formatting looks weird, probably a tabs-vs-spaces thing.
  • This should probably be defined as an option on the interface object rather than a special argument to the parsing functions.
  • Is there ever a case where you'd want to stop at something other than the first toplevel? If so, we could take a terminatorp predicate instead, which would get called on the toplevel options as they're detected. Then you could do :terminatorp (constantly t) to stop at the first, or something like :terminatorp (let ((n 0)) (lambda (arg) (declare (ignore arg) (= (incf n) 2))) to stop at the second, etc. But maybe that's getting too far into the weeds and the simpler stop-at-first is better, I dunno.
  • I haven't tried running it, but thinking through it in my mind I think this implementation looks like it will interact sanely with a real -- arg, e.g. if you do ./watch -- --command-that-starts-with-two-dashes-lol.sh --foo bar you should get ("--command-that-starts-with-two-dashes-lol.sh" "--foo" "bar") as the toplevel args, which makes sense. Is that right?

Previously this feature was accessed by passing an optional argument
to adopt:parse-options and could only trigger when processing the
first toplevel argument in a list; now it's accessed by a slot in the
interface class, and any argument may trigger it so long as it satis-
fies the predicate stored in that slot.
@mistekko

Copy link
Copy Markdown
Author
  • Right you are, seems I lapsed in my quality control.

  • Definitely. That's loads better than my way.

  • I can think of some cases where one might stop argument processing at an arbitrary string, possibly processing the remaining arguments using a second interface. The sbcl command is an example of this: it has two distinct --script options. If we were making this command with Adopt, we might have one interface called runtime-options with :terminatorp (lambda (arg) (string= arg "--end-runtime-options")) and another interface named toplevel-options with :terminatorp (lambda (arg) (string= arg "--end-toplevel-options")). Another example is the -exec SHELL-COMMAND ; option of find, where `-exec' should be treated as a terminator. So I think having a terminator defined by a custom predicate could be a useful feature.

  • Yep.

I've updated the code to use the predicate strategy rather than the parse-options strategy. I'll write some tests and update the documentation sometime soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants