【问题标题】:Implementing auto autocomplete for CLI application为 CLI 应用程序实现自动自动完成
【发布时间】:2017-01-27 13:36:36
【问题描述】:

我正在考虑用 Go 编写一个 CLI 应用程序。

其中一个要求是自动完成。不是命令本身,而是可能的选项。

假设我想使用 CLI 添加一个新条目。每个条目都可以有一个类别。 这些类别在一个切片中可用。我现在要做的是让用户在输入add 时能够通过可用类别进行选项卡。

我知道像 https://github.com/chzyer/readlinehttps://github.com/spf13/cobra 这样的库,但找不到它们是否支持或如何支持。

【问题讨论】:

  • “CLI”是什么意思?即用户将启动您的程序,然后在其中的“交互式外壳”中工作,还是用户将在系统外壳中输入完整的命令,您的程序执行它并退出?
  • @ain 好问题。我没有想过这个。这与用例无关。因此:无论实施哪个更好。
  • 你指出的两个例子非常不同,一个 readline实现,一个使用bash的自动完成功能(它使用不同的readline实现)。跨度>
  • @JimB 你能进一步解释 readline 的含义吗?它是否读取实际行(在 CLI 上输入/输入的意义上)还是我可以提供它应该通过的值?
  • readline 是交互式 CLI 使用的标准库:en.wikipedia.org/wiki/GNU_Readline

标签: go command-line-interface


【解决方案1】:

感谢@ain 和@JimB 为我指明了正确的方向。

根据https://github.com/chzyer/readline/tree/master/example/readline-demo 提供的示例,我能够实现所需的功能。

以下代码必须对主要命令newEntrynewCategory。如果用户键入newEntry 然后按TAB,他可以从可用类别中进行选择。 newCategory 命令允许添加一个新的自定义类别,该类别在下次执行 newEntry 时立即可用。

package main

import (
    "io"
    "log"
    "strconv"
    "strings"

    "github.com/chzyer/readline"
)

// completer defines which commands the user can use
var completer = readline.NewPrefixCompleter()

// categories holding the initial default categories. The user can  add categories.
var categories = []string{"Category A", "Category B", "Category C"}

var l *readline.Instance

func main() {

// Initialize config
config := readline.Config{
    Prompt:          "\033[31m»\033[0m ",
    HistoryFile:     "/tmp/readline.tmp",
    AutoComplete:    completer,
    InterruptPrompt: "^C",
    EOFPrompt:       "exit",

    HistorySearchFold: true,
}

var err error
// Create instance
l, err = readline.NewEx(&config)
if err != nil {
    panic(err)
}
defer l.Close()

// Initial initialization of the completer
updateCompleter(categories)

log.SetOutput(l.Stderr())
// This loop watches for user input and process it
for {
    line, err := l.Readline()
    if err == readline.ErrInterrupt {
        if len(line) == 0 {
            break
        } else {
            continue
        }
    } else if err == io.EOF {
        break
    }

    line = strings.TrimSpace(line)
    // Checking which command the user typed
    switch {
    // Add new category
    case strings.HasPrefix(line, "newCategory"):
        // Remove the "newCategory " prefix (including space)
        if len(line) <= 12 {
            log.Println("newCategory <NameOfCategory>")
            break
        }
        // Append everything that comes behind the command as the name of the new category
        categories = append(categories, line[12:])
        // Update the completer to make the new category available in the cmd
        updateCompleter(categories)
    // Program is closed when user types "exit"
    case line == "exit":
        goto exit
    // Log all commands we don't know
    default:
        log.Println("Unknown command:", strconv.Quote(line))
    }
}
exit:
}

// updateCompleter is updates the completer allowing to add new command during runtime. The completer is recreated
// and the configuration of the instance update.
func updateCompleter(categories []string) {

var items []readline.PrefixCompleterInterface

for _, category := range categories {
    items = append(items, readline.PcItem(category))
}

completer = readline.NewPrefixCompleter(
    readline.PcItem("newEntry",
        items...,
    ),
    readline.PcItem("newCategory"),
)

l.Config.AutoComplete = completer
}

【讨论】:

    猜你喜欢
    • 2016-06-23
    • 2018-04-23
    • 2020-09-10
    • 2022-11-02
    • 2013-02-24
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    相关资源
    最近更新 更多