127 lines
2.3 KiB
Go
127 lines
2.3 KiB
Go
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
|
|
}
|
|
|
|
}
|