argv

package
v0.0.0-...-782cc26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2018 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ARG_OK error = nil
View Source
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.

View Source
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).

View Source
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 ArgInt

func ArgInt(option *Option) error

ArgChecker that accepts base-10 integers and stores them as int in option.Value.

func ArgNonEmpty

func ArgNonEmpty(option *Option) error

ArgChecker that accepts any argument as long as it is not the empty string. E.g. --file="" would be rejected by this ArgChecker.

func ArgNone

func ArgNone(option *Option) error

ArgChecker for options that do not have an argument.

func ArgOptional

func ArgOptional(option *Option) error

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

func ArgRequired(option *Option) error

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

func ArgUnimpl(option *Option) error

ArgChecker that always fails with an error that says the option is unimplemented. Useful as placeholder in Usage.

func ArgUnknown

func ArgUnknown(option *Option) error

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

func ARG_NONE_Err(optionname string) ARG_NONE

type ArgChecker

type ArgChecker func(opt *Option) error

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

func (o *Option) Count() int

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

func (o *Option) Id() int

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

func (o *Option) Is(value int) bool

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

func (o *Option) Last() *Option

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.

func (*Option) Next

func (o *Option) Next() *Option

If the option in the argument vector that produced o was followed by another option with the same OptionInfo.Id, then Next() returns a pointer to the parsed Option for that other option. Otherwise this function returns nil. Also returns nil if o is undefined.

func (*Option) String

func (o *Option) String() string

Returns the name of the option, so that Option objects can be used with *printf().

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

func (usage Usage) String() 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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL