A novel experience for building application entrypoint.
- POSIX & GNU style flag parsing, typed and customizable. (
flag*.go) - Commands and sub-commands, nothing hidden. (
cmd*.go) - Shell completions made straightforward. (
comp*.go,scripts/*)- Use
CompCmdShellsto provide shell completion support forbash,zshandpwsh(powershell).
- Use
- From mostly static to highly dynamic, choices available for zero-allocation* and productivity preferences.
- Choose
ReflectIndexerfor productivity, chooseFuncIndexerfor zero-allocation. (see Core Concepts and module document)
- Choose
- Solid & decoupled utilities comes with sane abstractions. (
vp*.go,rules*.go)VPimplementations for both concrete types and reflection types.
*zero-allocation can be achieved by adding proper buffering in ParseOptions and CmdOptions.
see package examples
-
Flags having implicit value cannot be followed by value prefixed with hyphen (
-) if the flag accepts that value (e.g.--IntSum -1). To workaround, choose any of following methods:- (Method 1) use
=to assign flag value explicitly (e.g.--IntSum=-1) - (Method 2) set
ParseOptions.HandleParseErrorto handle error of type*ErrAmbiguousArgs.
- (Method 1) use
-
Limitations to standalone dash (
--)- Cannot be a flag value (e.g. given
--sep --, then--sepgets nothing). To wrokaround, use=to assign dash value (e.g.--sep=--) - Can never be a positional arg. To workaround, check if
dashArgs == nilis true, and if it is ture, then there is no standalone dash. - Due to limitations mentioned above, you cannot use a hyphen (
-) as a flag shorthand.
- Cannot be a flag value (e.g. given
- A
FlagFinderimplementation is capable of searching flags known to it by flag name or shorthand, so it represents a set of flags. FlagIndexerextends the ability ofFlagFinderwith iteration support (FlagIter).MapIndexer: register flags just like old days. (see Motivation)FuncIndexer: provide ad-hoc flag indexing logic.LevelIndexer: build flag hierarchies.ReflectIndexer: lazily produce flags on request.MultiIndexer: collect indexers as one.- ... or implement your own
FlagIndexer/FlagFinderfor you own use cases.
- A root command is the receiver of a
(*Cmd).Exec(...)function call. - A
Routeis a collection of all*Cmds from the root command to the target command.
Illustration without sub-commands:
dash
|
posArg flag name |
| | |
$ ./foo xxx -i --join bar -- other args
| | [ all args after the dash are dashArgs]
| |
| flag value
|
flag shorthand, with implicit valueargs: all strings provided to a cmd.- For a root command in real world, it usually is
os.Args[1:]
- For a root command in real world, it usually is
flags: before the first dash, strings interpreted as flag names and flag values.- flag (long) name: a string consists of more than one unicode characters.
- flag shorthand: a string consists of exactly one unicode character and not a hyphen (
-).
subcmds(sub-commands): before the first dash, ignore flag names and their values, consecutive args matching a serial ofCmd.Pattern.- In the above illustration, if there is a
Cmdin root command'sChildrenwhose.Patternisxxx, then the posArgxxxbecomes subcmdxxx.
- In the above illustration, if there is a
posArgs(positional args): before the first dash, strings that are not flags and subcmds.dashArgs: all strings after the first dash.
Most existing command-line libraies forces you to register your flags to some central registries to get things going, these registrations happen at runtime and often involves dynamic memory allocation, even the often highly praised Rust crate clap works this way, but under the guise of procedural macros.
While we acknowledge the fact flag registration works fine in most cases, it is obvious to us that larger applications with a fair amount of sub-commands and flags often suffer from such method due to the central builder forcing the application to write a lot of boilerplate code just to work around its own workflow and restrictions, and we definitely want something more flexible.
Hint: You may obtain (almost) the same experience of traditional flag registration from this module by using MapIndexer and predefined flag types.
We are building a no-GC, zero-allocation, FFI-friendly, well-structured std module (inside primecitizens/pcz) for Golang, exposing all lower bits of the runtime, and compatible with the official go1.21+ toolchain (go tool compile/link/asm).
This cli module serves as a showcase how we redesign fundamental components in a standard library.
- Completion support for
fish - Add more Helper interfaces in addition to
HelperTerminal.-
HelperMarkdown -
HelperMandoc -
HelperYAML
-
- Define a new interface (
Command) as abstraction ofCmdto allow custom implementation. - Add cli tool
cligento generate flag indexer implementations for struct types.
Copyright 2023 The Prime Citizens
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.