github.com/skyzyx/posener-complete@v1.1.2/command.go (about)

     1  package complete
     2  
     3  // Command represents a command line
     4  // It holds the data that enables auto completion of command line
     5  // Command can also be a sub command.
     6  type Command struct {
     7  	// Sub is map of sub commands of the current command
     8  	// The key refer to the sub command name, and the value is it's
     9  	// Command descriptive struct.
    10  	Sub Commands
    11  
    12  	// Flags is a map of flags that the command accepts.
    13  	// The key is the flag name, and the value is it's predictions.
    14  	Flags Flags
    15  
    16  	// GlobalFlags is a map of flags that the command accepts.
    17  	// Global flags that can appear also after a sub command.
    18  	GlobalFlags Flags
    19  
    20  	// Args are extra arguments that the command accepts, those who are
    21  	// given without any flag before.
    22  	Args Predictor
    23  }
    24  
    25  // Predict returns all possible predictions for args according to the command struct
    26  func (c *Command) Predict(a Args) []string {
    27  	options, _ := c.predict(a)
    28  	return options
    29  }
    30  
    31  // Commands is the type of Sub member, it maps a command name to a command struct
    32  type Commands map[string]Command
    33  
    34  // Predict completion of sub command names names according to command line arguments
    35  func (c Commands) Predict(a Args) (prediction []string) {
    36  	for sub := range c {
    37  		prediction = append(prediction, sub)
    38  	}
    39  	return
    40  }
    41  
    42  // Flags is the type Flags of the Flags member, it maps a flag name to the flag predictions.
    43  type Flags map[string]Predictor
    44  
    45  // Predict completion of flags names according to command line arguments
    46  func (f Flags) Predict(a Args) (prediction []string) {
    47  	for flag := range f {
    48  		// If the flag starts with a hyphen, we avoid emitting the prediction
    49  		// unless the last typed arg contains a hyphen as well.
    50  		flagHyphenStart := len(flag) != 0 && flag[0] == '-'
    51  		lastHyphenStart := len(a.Last) != 0 && a.Last[0] == '-'
    52  		if flagHyphenStart && !lastHyphenStart {
    53  			continue
    54  		}
    55  		prediction = append(prediction, flag)
    56  	}
    57  	return
    58  }
    59  
    60  // predict options
    61  // only is set to true if no more options are allowed to be returned
    62  // those are in cases of special flag that has specific completion arguments,
    63  // and other flags or sub commands can't come after it.
    64  func (c *Command) predict(a Args) (options []string, only bool) {
    65  
    66  	// search sub commands for predictions first
    67  	subCommandFound := false
    68  	for i, arg := range a.Completed {
    69  		if cmd, ok := c.Sub[arg]; ok {
    70  			subCommandFound = true
    71  
    72  			// recursive call for sub command
    73  			options, only = cmd.predict(a.from(i))
    74  			if only {
    75  				return
    76  			}
    77  
    78  			// We matched so stop searching. Continuing to search can accidentally
    79  			// match a subcommand with current set of commands, see issue #46.
    80  			break
    81  		}
    82  	}
    83  
    84  	// if last completed word is a global flag that we need to complete
    85  	if predictor, ok := c.GlobalFlags[a.LastCompleted]; ok && predictor != nil {
    86  		Log("Predicting according to global flag %s", a.LastCompleted)
    87  		return predictor.Predict(a), true
    88  	}
    89  
    90  	options = append(options, c.GlobalFlags.Predict(a)...)
    91  
    92  	// if a sub command was entered, we won't add the parent command
    93  	// completions and we return here.
    94  	if subCommandFound {
    95  		return
    96  	}
    97  
    98  	// if last completed word is a command flag that we need to complete
    99  	if predictor, ok := c.Flags[a.LastCompleted]; ok && predictor != nil {
   100  		Log("Predicting according to flag %s", a.LastCompleted)
   101  		return predictor.Predict(a), true
   102  	}
   103  
   104  	options = append(options, c.Sub.Predict(a)...)
   105  	options = append(options, c.Flags.Predict(a)...)
   106  	if c.Args != nil {
   107  		options = append(options, c.Args.Predict(a)...)
   108  	}
   109  
   110  	return
   111  }