func()

in cli/completer.go [277:435]


func (t *autoCompleter) Do(line []rune, pos int) (options [][]rune, offset int) {
	apiMap := buildAPICacheMap(t.Config.GetAPIVerbMap())

	var verbs []string
	for verb := range apiMap {
		verbs = append(verbs, verb)
		sort.Slice(apiMap[verb], func(i, j int) bool {
			return apiMap[verb][i].Name < apiMap[verb][j].Name
		})
	}
	sort.Strings(verbs)

	line = trimSpaceLeft(line[:pos])

	// Auto-complete verb
	var verbFound string
	for _, verb := range verbs {
		search := verb + " "
		if !hasPrefix(line, []rune(search)) {
			sLine, sOffset := doInternal(line, pos, len(line), []rune(search))
			options = append(options, sLine...)
			offset = sOffset
		} else {
			verbFound = verb
			break
		}
	}
	if len(verbFound) == 0 {
		return
	}

	// Auto-complete noun
	var nounFound string
	line = trimSpaceLeft(line[len(verbFound):])
	for _, api := range apiMap[verbFound] {
		search := api.Noun + " "
		if !hasPrefix(line, []rune(search)) {
			sLine, sOffset := doInternal(line, pos, len(line), []rune(search))
			options = append(options, sLine...)
			offset = sOffset
		} else {
			nounFound = api.Noun
			break
		}
	}
	if len(nounFound) == 0 {
		return
	}

	// Find API
	var apiFound *config.API
	for _, api := range apiMap[verbFound] {
		if api.Noun == nounFound {
			apiFound = api
			break
		}
	}
	if apiFound == nil {
		return
	}

	// Auto-complete API arg
	splitLine := strings.Split(string(line), " ")
	line = trimSpaceLeft([]rune(splitLine[len(splitLine)-1]))
	for _, arg := range apiFound.Args {
		search := arg.Name
		if !hasPrefix(line, []rune(search)) {
			sLine, sOffset := doInternal(line, pos, len(line), []rune(search))
			options = append(options, sLine...)
			offset = sOffset
		} else {
			words := strings.Split(string(line), "=")
			argInput := lastString(words)
			if arg.Type == "boolean" {
				for _, search := range []string{"true ", "false "} {
					offset = 0
					if strings.HasPrefix(search, argInput) {
						options = append(options, []rune(search[len(argInput):]))
						offset = len(argInput)
					}
				}
				return
			}
			if arg.Type == config.FAKE && arg.Name == "filter=" {
				offset = 0
				filterInputs := strings.Split(strings.Replace(argInput, ",", ",|", -1), "|")
				lastFilterInput := lastString(filterInputs)
				for _, key := range apiFound.ResponseKeys {
					if inArray(key, filterInputs) {
						continue
					}
					if strings.HasPrefix(key, lastFilterInput) {
						options = append(options, []rune(key[len(lastFilterInput):]))
						offset = len(lastFilterInput)
					}
				}
				return
			}

			autocompleteAPI := findAutocompleteAPI(arg, apiFound, apiMap)
			if autocompleteAPI == nil {
				return nil, 0
			}

			completeArgs := t.Config.Core.AutoComplete
			autocompleteAPIArgs := []string{}
			argOptions := []argOption{}
			if completeArgs {
				autocompleteAPIArgs = []string{"listall=true"}
				if autocompleteAPI.Noun == "templates" {
					autocompleteAPIArgs = append(autocompleteAPIArgs, "templatefilter=executable")
				}

				if apiFound.Name != "provisionCertificate" && autocompleteAPI.Name == "listHosts" {
					autocompleteAPIArgs = append(autocompleteAPIArgs, "type=Routing")
				} else if apiFound.Name == "migrateSystemVm" {
					autocompleteAPI.Name = "listSystemVms"
				}

				spinner := t.Config.StartSpinner("fetching options, please wait...")
				request := cmd.NewRequest(nil, completer.Config, nil)
				response, _ := cmd.NewAPIRequest(request, autocompleteAPI.Name, autocompleteAPIArgs, false)
				t.Config.StopSpinner(spinner)

				hasID := strings.HasSuffix(arg.Name, "id=") || strings.HasSuffix(arg.Name, "ids=")
				argOptions = buildArgOptions(response, hasID)
			}

			filteredOptions := []argOption{}
			if len(argOptions) > 0 {
				sort.Slice(argOptions, func(i, j int) bool {
					return argOptions[i].Value < argOptions[j].Value
				})
				for _, item := range argOptions {
					if strings.HasPrefix(item.Value, argInput) {
						filteredOptions = append(filteredOptions, item)
					}
				}
			}
			offset = 0
			if len(filteredOptions) == 0 {
				options = [][]rune{[]rune("")}
			}
			for _, item := range filteredOptions {
				option := item.Value + " "
				if len(filteredOptions) > 1 && len(item.Detail) > 0 {
					option += fmt.Sprintf("(%v)", item.Detail)
				}
				if strings.HasPrefix(option, argInput) {
					options = append(options, []rune(option[len(argInput):]))
					offset = len(argInput)
				}
			}
			return
		}
	}

	return options, offset
}