github.com/jmigpin/editor@v1.6.0/util/flagutil/parsedargs.go (about)

     1  package flagutil
     2  
     3  import "strings"
     4  
     5  // NOTE: alternative to flag.flagset (more premitive, lacks documentation utility)
     6  
     7  func ParseParsedArgs(args []string, isBool map[string]bool) ParsedArgs {
     8  	pa := ParsedArgs{}
     9  	for i := 0; i < len(args); i++ {
    10  		name, value, k := parseArg(args, i, isBool)
    11  		arg := &Arg{Name: name, Value: value}
    12  		i = k
    13  		pa = append(pa, arg)
    14  	}
    15  	return pa
    16  }
    17  
    18  //----------
    19  
    20  type ParsedArgs []*Arg
    21  
    22  func (pa ParsedArgs) Get(name string) (*Arg, bool) {
    23  	for _, a := range pa {
    24  		if a.Name == name {
    25  			return a, true
    26  		}
    27  	}
    28  	return nil, false
    29  }
    30  
    31  func (pa *ParsedArgs) Remove(arg *Arg) {
    32  	for i, a := range *pa {
    33  		if a == arg {
    34  			*pa = append((*pa)[:i], (*pa)[i+1:]...)
    35  			break
    36  		}
    37  	}
    38  }
    39  
    40  func (pa ParsedArgs) Join() []string {
    41  	u := []string{}
    42  	for _, a := range pa {
    43  		u = append(u, a.String())
    44  	}
    45  	return u
    46  }
    47  
    48  //----------
    49  
    50  func (pa ParsedArgs) CommonSplit() (ParsedArgs, ParsedArgs, ParsedArgs) {
    51  	pa, binaryPa := pa.SplitAtDoubleDashExclude()
    52  	pa, unnamedPa := pa.SplitAtFirstUnnamed()
    53  	unnamedPa, namedPa := unnamedPa.SplitAtFirstNamed()
    54  	binaryPa = append(namedPa, binaryPa...)
    55  	return pa, unnamedPa, binaryPa
    56  }
    57  
    58  func (pa ParsedArgs) SplitAtFirstUnnamed() (ParsedArgs, ParsedArgs) {
    59  	for i, a := range pa {
    60  		if a.Name == "" { // name is empty if no dash was used
    61  			return pa[:i], pa[i:]
    62  		}
    63  	}
    64  	return pa, nil
    65  }
    66  
    67  func (pa ParsedArgs) SplitAtFirstNamed() (ParsedArgs, ParsedArgs) {
    68  	for i, a := range pa {
    69  		if a.Name != "" { // name is not empty if a dash was used
    70  			return pa[:i], pa[i:]
    71  		}
    72  	}
    73  	return pa, nil
    74  }
    75  
    76  func (pa ParsedArgs) SplitAtDoubleDashExclude() (ParsedArgs, ParsedArgs) {
    77  	return pa.SplitAtNameExclude("--")
    78  }
    79  
    80  func (pa ParsedArgs) SplitAtNameExclude(name string) (ParsedArgs, ParsedArgs) {
    81  	for i, a := range pa {
    82  		if a.Name == name {
    83  			return pa[:i], pa[i+1:]
    84  		}
    85  	}
    86  	return pa, nil
    87  }
    88  
    89  //----------
    90  
    91  type Arg struct {
    92  	Name  string // can be empty if just a value
    93  	Value string // can be empty if just a name
    94  }
    95  
    96  func (a *Arg) String() string {
    97  	s := ""
    98  	if a.Name != "" {
    99  		s += "-" + a.Name
   100  	}
   101  	if a.Value != "" {
   102  		if a.Name != "" {
   103  			s += "="
   104  		}
   105  		s += a.Value
   106  	}
   107  	return s
   108  }
   109  
   110  //----------
   111  
   112  func parseArg(args []string, i int, isBool map[string]bool) (name string, value string, curI int) {
   113  	curI = i
   114  	arg := args[curI]
   115  
   116  	dash := "-"
   117  	dashed := strings.HasPrefix(arg, dash)
   118  	if !dashed {
   119  		value = arg
   120  		return
   121  	}
   122  
   123  	// TODO: cut only 2?
   124  	noDashArg := strings.TrimLeft(arg, dash)
   125  
   126  	// an arg full of dashes (ex: "--")
   127  	if noDashArg == "" {
   128  		name = arg
   129  		return
   130  	}
   131  
   132  	name = noDashArg
   133  	if k := strings.Index(noDashArg, "="); k >= 0 {
   134  		name = noDashArg[:k]
   135  		value = noDashArg[k+1:]
   136  
   137  		// simplify bool values
   138  		if isBool != nil && isBool[name] {
   139  			if s, ok := simplifyBoolValue(value); ok {
   140  				value = s
   141  			}
   142  		}
   143  
   144  		return
   145  	}
   146  
   147  	// value after a space from here
   148  
   149  	if isBool != nil && isBool[name] {
   150  		return // no spaced value
   151  	}
   152  
   153  	if i+1 >= len(args) {
   154  		return // missing spaced value
   155  	}
   156  
   157  	// take next arg as value
   158  	curI = i + 1
   159  	arg = args[curI]
   160  	value = arg
   161  	return
   162  }