package arg import ( "strings" "github.com/posener/complete/v2/internal/tokener" ) // Arg is typed a command line argument. type Arg struct { Text string Completed bool Parsed } // Parsed contains information about the argument. type Parsed struct { Flag string HasFlag bool Value string Dashes string HasValue bool } // Parse parses a typed command line argument list, and returns a list of arguments. func Parse(line string) []Arg { var args []Arg for { arg, after := next(line) if arg.Text != "" { args = append(args, arg) } line = after if line == "" { break } } return args } // next returns the first argument in the line and the rest of the line. func next(line string) (arg Arg, after string) { defer arg.parse() // Start and end of the argument term. var start, end int // Stack of quote marks met during the paring of the argument. var token tokener.Tokener // Skip prefix spaces. for start = 0; start < len(line); start++ { token.Visit(line[start]) if !token.LastSpace() { break } } // If line is only spaces, return empty argument and empty leftovers. if start == len(line) { return } for end = start + 1; end < len(line); end++ { token.Visit(line[end]) if token.LastSpace() { arg.Completed = true break } } arg.Text = line[start:end] if !arg.Completed { return } start2 := end // Skip space after word. for start2 < len(line) { token.Visit(line[start2]) if !token.LastSpace() { break } start2++ } after = line[start2:] return } // parse a flag from an argument. The flag can have value attached when it is given in the // `-key=value` format. func (a *Arg) parse() { if len(a.Text) == 0 { return } // A pure value, no flag. if a.Text[0] != '-' { a.Value = a.Text a.HasValue = true return } // Seprate the dashes from the flag name. dahsI := 1 if len(a.Text) > 1 && a.Text[1] == '-' { dahsI = 2 } a.Dashes = a.Text[:dahsI] a.HasFlag = true a.Flag = a.Text[dahsI:] // Empty flag if a.Flag == "" { return } // Third dash or empty flag with equal is forbidden. if a.Flag[0] == '-' || a.Flag[0] == '=' { a.Parsed = Parsed{} return } // The flag is valid. // Check if flag has a value. if equal := strings.IndexRune(a.Flag, '='); equal != -1 { a.Flag, a.Value = a.Flag[:equal], a.Flag[equal+1:] a.HasValue = true return } }