Documentation
¶
Index ¶
- Variables
- func ArgInt(option *Option) error
- func ArgNonEmpty(option *Option) error
- func ArgNone(option *Option) error
- func ArgOptional(option *Option) error
- func ArgRequired(option *Option) error
- func ArgUnimpl(option *Option) error
- func ArgUnknown(option *Option) error
- func Parse(args []string, usage Usage, flags string) (options []*Option, nonoptions []string, err error, alloptions []*Option)
- type ARG_NONE
- type ArgChecker
- type ColumnWrapper
- type LinePartIterator
- func (l *LinePartIterator) Column() int
- func (l *LinePartIterator) Data() string
- func (l *LinePartIterator) NextPart() bool
- func (l *LinePartIterator) NextRow() bool
- func (l *LinePartIterator) NextTable() bool
- func (l *LinePartIterator) PartTerminator() byte
- func (l *LinePartIterator) RestartRow() bool
- func (l *LinePartIterator) RestartTable() bool
- func (l *LinePartIterator) ScreenLength() int
- func (l *LinePartIterator) Subrow() int
- type Option
- type OptionInfo
- type Usage
Constants ¶
This section is empty.
Variables ¶
var ARG_OK error = nil
var Columns = 0
Number of screen columns for formatting usage in function Usage.String(). If Columns I<= 0, then the environment variable COLUMNS is used. If COLUMNS is empty or cannot be parsed as an integer, 80 is used. NOTE: Asian wide characters are supported by Usage.String() and count as 2 screen columns.
var LastColumnMinPercent = 50
An integer in the range 0-100. The minimum percentage of screen columns (as specified by Columns above) that should be available for the last column (which typically contains the textual explanation of an option) when formatting usage with Usage.String(). If less space is available, the last column will be printed on its own line, indented according to LastColumnOwnLineMaxPercent (see below).
var LastColumnOwnLineMaxPercent = 75
An integer in the range 0-100. If String.Usage() formats the last column on its own line due to less than LastColumnMinPercent (see above) of screen columns being available, then only LastColumnOwnLineMaxPercent of the extra line(s) will be used for the last column's text. This ensures an indentation. E.g.:
Columns=20, LastColumnMinPercent=50 (i.e. last column's minimum size=20 * 50% = 10)
--3456789 1234567890
1234567890
Columns=20, LastColumnMinPercent=75 (i.e. last column's minimum size=20 * 75% = 15),
LastColumnOwnLineMaxPercent=75 (i.e. maximum size = 20 * 75% = 15)
--3456789
123456789012345
67890
Columns=20, LastColumnMinPercent=75 (i.e. last column's minimum size=20 * 75% = 15)
LastColumnOwnLineMaxPercent=25 (i.e. maximum size = 20 * 25% = 5)
--3456789
12345
67890
12345
67890
Functions ¶
func ArgNonEmpty ¶
ArgChecker that accepts any argument as long as it is not the empty string. E.g. --file="" would be rejected by this ArgChecker.
func ArgOptional ¶
ArgChecker for options that may or may not have an argument. This ArgChecker accepts only attached arguments, because of the ambiguities that would otherwise arise (e.g. What does "-f -g" mean if -f takes an optional argument?)
func ArgRequired ¶
ArgChecker that accepts any argument as long as there is one. Note that the empty string is a valid argument for this ArgChecker (e.g. --title= ).
func ArgUnimpl ¶
ArgChecker that always fails with an error that says the option is unimplemented. Useful as placeholder in Usage.
func ArgUnknown ¶
ArgChecker for unknown options. Usage should contain at least one OptionInfo with Long==Short=="" and ArgChecker ArgUnknown. When Parse() encounters a word on the argument vector that starts with a "-", is not "-" or "--", and does not match any known option, Parse() will call the ArgChecker for the first dummy entry in Usage (a dummy entry is one with Long==Short==""). If you use ArgUnknown for this dummy entry, Parse() will abort. If there is no dummy entry in usage, unknown arguments will be silently ignored. Of course you can also use an ArgChecker that accepts unknown options to serve as a catch-all. This ArgChecker evaluates option.Value which Parse() uses to communicate additional information in the following manner:
- if option.Value is a 2-element []string, then the option is an ambiguous abbreviation of (at least) the 2 option names in the []string ArgUnknown will report the 2 names in the returned error message.
func Parse ¶
func Parse(args []string, usage Usage, flags string) (options []*Option, nonoptions []string, err error, alloptions []*Option)
Takes an argument vector (typically os.Args[1:]) and parses it according to usage and flags.
flags contains zero or more words separated by space. The following words
are understood:
"gnu": By default Parse() uses the behavior specified by POSIX for getopt()
which is to treat every word in the argument vector after the
first non-option word as a non-option even if it starts with "-".
The "gnu" flag changes Parse() behavior to that of GNU getopt() which
continues parsing for options even after a non-option until the
special "--" separator is encountered (after which definitely every
word is a non-option no matter what it looks like).
"-perl": This makes Parse() accept Perl-style single-minus long options.
The double minus form will still be recognized. Note that
single minus long options take precedence over short options and
short option groups. E.g. "-file" would be interpreted as "--file"
and not as "-f -i -l -e" (assuming a long option named "file" exists).
"--a", "--ab", "--abb", "--abbr", ... "--abbreviated":
Any word starting with "--a" will tell Parse() to recognize abbreviated
long options as long as the abbreviated form has at least as many characters
as the "-a..." word. Parse() will match a prefix of a long option as if it was
the full long option (e.g. "--foob=10" will be interpreted as if it was
"--foobar=10" ), as long as the prefix has the required length AND IS UNAMBIGUOUS.
Be careful if combining "-perl" and "--a" (i.e. abbreviations with only a 1 character
prefix) because the ambiguity check does not consider short options and abbreviated
single minus long options will take precedence over short options.
The returned values are
options: a slice with one entry for each non-negative OptionInfo.Id in usage.
options[id] is nil if none of the arguments described in usage with that id
is found in the argument vector. Otherwise it's a pointer to the parsed
Option corresponding to the first option in the argument vector with that id.
From that entry you can follow the Next() chain to iterate over all
options with the same OptionInfo.Id.
nonoptions: a list of all non-option words in the argument vector (excluding the "--"
separator if present). Note that in POSIX mode (the default, see flags)
the first argument that doesn't start with '-' or '--' and does not belong to
a preceding argument-taking option, will terminate the option list and is the
first non-option argument. All following words in the argument vector
are treated as non-option arguments, even if they start with '-' .
err: if non-nil something went wrong and the other return values have unspecified values.
alloptions: contains all the parsed options from the argument vector in order, i.e.
alloptions[i] corresponds to the i-th option in the argument vector.
Note the difference to the returned options slice which is indexed
by the OptionInfo.Id values. The alloptions slice is used to iterate
over all options found in the argument vector. The options slice is used
to access specific options directly.
NOTE: Each option from the argument vector produces only one Option
structure. The same Option structures are referenced in the
returned options and alloptions slices.
Types ¶
type ARG_NONE ¶
type ARG_NONE struct {
// contains filtered or unexported fields
}
func ARG_NONE_Err ¶
type ArgChecker ¶
A function that Parse() calls to check if opt.HasArg and opt.Arg are valid for the kind of option the ArgChecker is for. The return value is one of the following:
ARG_OK (which is nil but should be used for readability) if HasArg==true and Arg is valid; or if HasArg==false and the option does not take an argument.
An error of type ARG_NONE (Tip: use the ARG_NONE_Err() function) if the option does not take an argument or if the argument that is provided is not acceptable but that's okay because the argument is optional. This may be returned regardless of the values of HasArg and Arg. In situations where the interpretation of a word in the argument vector is ambiguous (e.g. "-f -g" where "-g" could be e.g. a filename argument for the "-f" option or could be a "-g" option) , the Parse() function will first try to interpret it as an option argument passing opt.HasArg==true to the ArgChecker. If the ArgChecker returns ARG_NONE, Parse() will set HasArg to false and try to interpret the word as an option instead (which may result in an error if it is not a valid option). If the situation is unambiguous (e.g. "--foo=-g") and ARG_NONE is returned, the ARG_NONE error will abort Parse() with that ARG_NONE error being returned. If HasArg==false and ArgChecker returns an ARG_NONE error, it will be ignored (i.e. treated as if it was ARG_OK).
Any other kind of error will be returned from Parse() immediately.
type ColumnWrapper ¶
type ColumnWrapper struct {
// contains filtered or unexported fields
}
A buffer for formatting output to fit into a column. Text can be pushed into the buffer in arbitrary sized chunks and will be broken up into appropriate chunks for writing a column of a given width one line at a time, so that the writing can be interleaved with data from other colums.
The following example makes this clearer:
Column 1,1 Column 2,1 This is a long text
Column 1,2 Column 2,2 that does not fit into
a single line.
The difficulty in producing this output is that the whole string "This is a long text that does not fit into a single line" is the 1st and only part of column 3. In order to produce the above output the 3rd column's data must be output piecemeal, interleaved with the data from the other 2 columns. This is where the ColumnWrapper comes in. The 3rd column's text can be written into the ColumnWrapper and the ColumnWrapper will wrap it for the width of the column and chunk the output for interleaving with the other columns.
When flushing the final part of 3rd column's data ("a single line.") the ColumnWrapper will produce indendation to substitute for the other 2 columns which do not have content for a 3rd line of output.
func NewColumnWrapper ¶
func NewColumnWrapper(x1, x2 int) *ColumnWrapper
Creates a new ColumnWrapper that wraps a column whose first character has x coordinate x1 and whose last character has x coordinate x2-1.
func (*ColumnWrapper) Flush ¶
func (w *ColumnWrapper) Flush(write io.Writer)
Writes out all remaining data from the ColumnWrapper using write. Unlike Process() this method indents all lines including the first and will output a '\n' at the end (but only if something has been written).
func (*ColumnWrapper) Process ¶
func (w *ColumnWrapper) Process(write io.Writer, data string)
Process, wrap and output the next piece of data.
Process() will output exactly one line of output. This is not necessarily the data passed in. It may be data queued from a prior call to Process().
Process() assumes that the a proper amount of indentation has already been output. It won't write any further indentation.
NOTE: No '\n' is written by this method after the last line that is written.
type LinePartIterator ¶
type LinePartIterator struct {
// contains filtered or unexported fields
}
A multi-level iterator over the OptionInfo.Help texts of a Usage. The general idea is that LinePartIterator will return substrings of the Help texts in the order in which they need to be written to the screen to achieve a table layout as described in String.Usage(). The formatting aspects LinePartIterator is not concerned with are line wrapping and inserting spaces to achieve column alignment.
The top-level organizational unit is the TABLE.
A table begins at an OptionInfo with Help != "\f" and extends up to a Descriptor with Help == "\f".
A table consists of ROWS.
Each OptionInfo.Help (except for the special string "\f" which is a table separator) starts a new row. Every '\n' character inside Help also starts a new row, even if it is the last character. This means that the number of rows defined by an OptionInfo.Help string is equal to the number of '\n' contained in the string PLUS ONE.
A row consists of CELLS.
Cells within a row are separated by '\t'.
The word COLUMN refers to the index of a cell within its row. E.g. column 0 contains the very first cell of a row. If that sounds confusing simply consider "column" as a synonym for "cell".
A cell consists of PARTS.
Parts within a cell are separated by '\v'. Usage.String() stacks parts vertically, so this is essentially a line break within a cell. ('\n' would start a new row in the table which is NOT equivalent unless your table has only 1 row)
Rows within a table need not have the same number of cells and cells need not have the same number of parts.
LinePartIterator iterates through the Help texts at 3 levels: table, row and part. Tables and rows are visited in their natural order. Parts are visited in the following way: Within the current row, it will visit the 1st part of the 1st cell, then the 1st part of the 2nd cell, and so on until the 1st part of the last cell of the current row has been visited. Then the 2nd part of the 1st cell is visited, followed by the 2nd part of the 2nd cell, and so on.
Example: The row "1 \v 3 \t 2 \v 4" has 2 cells and 4 parts. The parts will be returned in the order 1, 2, 3, 4.
It is possible that some cells have fewer parts than others. In this case LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator always returns the same number of parts for each cell within the same row (but not for cells in different rows).
func (*LinePartIterator) Column ¶
func (l *LinePartIterator) Column() int
Returns the index (counting from 0) of the column in which the part returned by Data() is located.
func (*LinePartIterator) Data ¶
func (l *LinePartIterator) Data() string
Returns the current part of the iteration.
func (*LinePartIterator) NextPart ¶
func (l *LinePartIterator) NextPart() bool
*
- Moves iteration to the next part (if any). Has to be called once after each call to
- NextRow() to move to the 1st part of the row.
- Returns false if moving to next part failed because no further part exists. *
- See LinePartIterator for details about the iteration.
func (*LinePartIterator) NextRow ¶
func (l *LinePartIterator) NextRow() bool
Moves iteration to the next row (if any). Has to be called once after each call to NextTable() to move to the 1st row of the table. Returns false if moving to next row failed because no further row exists within the current table. Note that NextRow() will not enter the next table. You need to use NextTable() for that.
func (*LinePartIterator) NextTable ¶
func (l *LinePartIterator) NextTable() bool
Moves iteration to the next table (if any). Has to be called once on a new LinePartIterator to move to the 1st table. Returns false if moving to next table failed because no further table exists. E.g.
for iter := usage.Iterate(); iter.NextTable() {
...
}
func (*LinePartIterator) PartTerminator ¶
func (l *LinePartIterator) PartTerminator() byte
Returns the byte that terminates the current part within the Help text. If the part is terminated by the end of the string, the returned byte is 0.
func (*LinePartIterator) RestartRow ¶
func (l *LinePartIterator) RestartRow() bool
Reset iteration to the beginning of the current row. Returns false if there is no current row (because iteration has already passed the last row of the current table).
func (*LinePartIterator) RestartTable ¶
func (l *LinePartIterator) RestartTable() bool
Reset iteration to the beginning of the current table. Returns false if there is no current table (because the iteration has finished). After calling this function, you must call NextRow() to move to the 1st row.
func (*LinePartIterator) ScreenLength ¶
func (l *LinePartIterator) ScreenLength() int
Returns the width in screen columns of the part returned by Data(). Takes multi-byte UTF-8 sequences and wide characters into account.
func (*LinePartIterator) Subrow ¶
func (l *LinePartIterator) Subrow() int
Returns the index (counting from 0) of the current part within the current cell. When iterating over a row, indexes change like this: Column()==0/Subrow()==0, Column()==1/Subrow()==0, Column()==2/Subrow()==0,..., Column()==0/Subrow()==1, Column()==1/Subrow()==1, Column()==2/Subrow()==1,..., Column()==0/Subrow()==2, Column()==1/Subrow()==2, Column()==2/Subrow()==2,...
type Option ¶
type Option struct {
/*
Useful mostly for inclusion in error messages, this is the name of the
option as used in the actual argument vector, including leading "-" character(s).
If the option is part of a single-letter option group in the actual argument vector,
Name will still only contain the name of the one option represented by
the Option object (e.g. Name=="-b" even if the option group is "-abc").
*/
Name string
/*
If the option has an argument (e.g. in "-f filename" the argument would be filename)
this is true.
*/
HasArg bool
/*
true if the option has an argument that is part of the same word in the
argument vector (e.g. "--numeric=10" or "-n10", but not "-n 10").
*/
ArgAttached bool
/*
If HasArg == true, this is the option's argument. Otherwise this is "".
Note that "" is a valid argument, so you must check HasArg.
*/
Arg string
/*
The element of the Usage that defines this option.
*/
Info *OptionInfo
/*
The ArgChecker function used to validate Arg may store information in this
field, typically a cooked form of the argument. E.g. ArgInt stores the argument
converted to int in this field.
*/
Value interface{}
// contains filtered or unexported fields
}
Parse() parses an argument vector into Option structures.
func (*Option) Count ¶
Returns the number of times options with the same Id() as this option occur in the argument vector. Use this to implement cumulative options, such as -v, -vv, -vvv for different verbosity levels. If o == nil or *o is uninitialized, returns 0.
func (*Option) Id ¶
Returns the OptionInfo.Id of o or -1 if o is nil or *o is uninitialized. You should use this function instead of accessing o.Info.Id directly because it handles nil.
func (*Option) Is ¶
This function is the most common way to test if an option is set. It returns true iff o is non-nil and o.Last().Info.State == value. If called on an undefined option (i.e. nil), it will return false no matter what value is passed. For readability purposes, however, it is usually best to write something like option.Is(ENABLED) even for options that can only be present or absent in the argument vector. A common use case for this function are option pairs like "--enable-foo" and "--disable-foo". In the Usage you would define the respective OptionInfos with the same Id==FOO but State==ENABLED vs State==DISABLED. With these definitions in place you can write tests like option.Is(ENABLED). This assumes that disabled is the default state. Because Is() returns false if none of the options from the pair is present in the argument vector, if the default state is enabled, you need to write the test as option.Is(DISABLED).
func (*Option) Last ¶
Returns the last option in the argument vector with the same Info.Id as o. When multiple contradictory options are used in the same argument vector, it is customary that the last one wins. E.g. if you have options --quiet and --verbose you would use the same OptionInfo.Id for both options and starting from any of them Last() would give you the option that actually matters. Most of the time, however, you would not use Last() directly but instead use the Is() method.
type OptionInfo ¶
type OptionInfo struct {
/* An identifier. Most options have a unique identifier, but related
options may have the same identifier with different values for
State (see below). The Parse() function creates one entry in the
returned options slice for each non-negative Id, so you should
use consecutive non-negative numbers as Id. */
Id int
/* Used to differentiate related options with the same Id value.
The typical example would be --enable-foo and --disable-foo which
would both use the same Id==FOO but have State==ENABLED vs
State==DISABLED.
*/
State int
/*
Each character in this string is accepted as a short option character.
E.g.
if this string is "abc", then "-a", "-b" and "-c" will be accepted.
If Short is "", there are no short options.
NOTE: Don't include the "-" character here or stuff will break!
*/
Short string
/*
The long option name without any leading "-".
E.g. if Long is "foo", then "--foo" (and "-foo" if single-minus long options
are enabled) will be accepted.
If Long is "", there is no long option name.
*/
Long string
/*
Checks a potential argument (or lack thereof) for validity with respect to
the option described by this OptionInfo.
*/
CheckArg ArgChecker
/*
String for use by Usage.String(). See there for formatting details.
*/
Help string
}
Describes a command line option. OptionInfos provide the information for Parse() to parse an argument vector.
type Usage ¶
type Usage []OptionInfo
The set of all possible command line options. The order of entries is important only in case of overlapping definitions (e.g. 2 options with the same long name) which you should avoid, and for Usage.String() which processes the Help strings in order.
func (Usage) Iterate ¶
func (usage Usage) Iterate() *LinePartIterator
Creates an iterator for usage.
func (Usage) String ¶
Converts the OptionInfo.Help texts from usage into a nicely formatted "manpage" with support for multi-column layout and line-wrapping. The following explains how to write your OptionInfo.Help texts to make use of these features.
TABLE FORMATTING ¶
Table formatting is the most essential tool for making your usage look nice. Without table formatting your output will look like this:
-c, --create |Creates something. -k, --kill |Destroys something.
With table formatting you can align the texts:
-c, --create |Creates something. -k, --kill |Destroys something.
Often programmers achieve alignment by manual padding with spaces. However this does not play nice with gettext translation and can not take different terminal widths into account.
Table formatting removes the need to pad help texts manually. To create a table, simply insert '\t' (tab) characters to separate the cells within a row. E.g.:
var usage = argv.Usage{
{..., "-c, --create \tCreates something." },
{..., "-k, --kill \tDestroys something." }, ...
Note that you must include the minimum amount of space desired between cells yourself. Table formatting will insert further spaces as needed to achieve alignment.
MULTIPLE ROWS PER Help TEXT ¶
The same OptionInfo.Help text may contain multiple rows. These are separated by '\n' (line feed). E.g.:
var usage = argv.Usage{
{..., "-c, --create \tCreates something." +
"\n" +
"-k, --kill \tDestroys something." }, ...
results in the same output as the previous example.
MULTI-LINE CELLS ¶
You can insert line breaks within cells by using '\v' (vertical tab). Do not confuse this with the multiple-rows-per Help text feature described in the previous section. E.g.:
var usage = argv.Usage{
{..., "-c,\v--create \tCreates\vsomething." },
{..., "-k,\v--kill \tDestroys\vsomething." }, ...
results in
-c, Creates
--create something.
-k, Destroys
--kill something.
PLAIN LINE INSERTIONS ¶
It is possible to mix Help strings that use table formatting characters '\t' and '\v' with plain strings that don't any table formatting characters. The plain lines will not mess up the table layout. Alignment of the table columns will continue after the plain line insertion. E.g.
var usage = argv.Usage{
{..., "-c, --create \tCreates something." },
{..., "----------------------------------" },
{..., "-k, --kill \tDestroys something." }, ...
results in
-c, --create Creates something.
----------------------------------
-k, --kill Destroys something.
MULTIPLE TABLES ¶
The same Usage may contain multiple tables whose columns are aligned independently. To start a new table, insert a dummy OptionInfo with Help=="\f" (form feed).
var usage = argv.Usage{
{..., "Long options:" },
{..., "--very-long-option \tDoes something long." },
{..., "--ultra-super-mega-long-option \tTakes forever to complete." },
{..., "\f" }, // ---------- table break -----------
{..., "Short options:" },
{..., "-s \tShort." },
{..., "-q \tQuick." }, ...
results in
Long options:
--very-long-option Does something long.
--ultra-super-mega-long-option Takes forever to complete.
Short options:
-s Short.
-q Quick.
Without the table break it would be
Long options:
--very-long-option Does something long.
--ultra-super-mega-long-option Takes forever to complete.
Short options:
-s Short.
-q Quick.
LINE-WRAPPING ¶
Lines will be wrapped according to the global parameters Columns, LastColumnMinPercent and LastColumnOwnLineMaxPercent. See their documentation for details.