golang命令行界面readline式交互插件库liner的使用
Golang命令行界面readline式交互插件库liner的使用
Liner是一个带有历史记录功能的命令行编辑器,它受到linenoise的启发。它适用于类Unix系统和Windows平台,旨在为跨平台应用程序提供统一的命令行编辑体验。
功能特点
Liner支持以下命令行编辑功能(在支持的平台和终端上):
快捷键 | 功能描述 |
---|---|
Ctrl-A, Home | 移动光标到行首 |
Ctrl-E, End | 移动光标到行尾 |
Ctrl-B, Left | 向左移动一个字符 |
Ctrl-F, Right | 向右移动一个字符 |
Ctrl-Left, Alt-B | 移动到前一个单词 |
Ctrl-Right, Alt-F | 移动到下一个单词 |
Ctrl-D, Del | 删除光标下的字符(如果行不为空) |
Ctrl-D | 文件结束(如果行为空)通常退出应用程序 |
Ctrl-C | 重置输入(创建新的空提示) |
Ctrl-L | 清屏(行内容不变) |
Ctrl-T | 交换前一个字符和当前字符 |
Ctrl-H, BackSpace | 删除光标前的字符 |
Ctrl-W, Alt-BackSpace | 删除光标前的单词 |
Alt-D | 删除光标后的单词 |
Ctrl-K | 删除从光标到行尾的内容 |
Ctrl-U | 删除从行首到光标的内容 |
Ctrl-P, Up | 历史记录中的上一条匹配 |
Ctrl-N, Down | 历史记录中的下一条匹配 |
Ctrl-R | 反向搜索历史记录 |
Ctrl-Y | 从Yank缓冲区粘贴 |
Tab | 下一个补全选项 |
Shift-Tab | 上一个补全选项 |
使用示例
下面是一个完整的Liner使用示例,展示了如何创建一个简单的交互式命令行界面:
package main
import (
"log"
"os"
"path/filepath"
"strings"
"github.com/peterh/liner"
)
var (
// 历史记录文件路径
history_fn = filepath.Join(os.TempDir(), ".liner_example_history")
// 自动补全的示例名称列表
names = []string{"john", "james", "mary", "nancy"}
)
func main() {
// 创建一个新的Liner实例
line := liner.NewLiner()
// 确保在程序结束时关闭Liner
defer line.Close()
// 设置Ctrl+C可以中止输入
line.SetCtrlCAborts(true)
// 设置自动补全函数
line.SetCompleter(func(line string) (c []string) {
for _, n := range names {
if strings.HasPrefix(n, strings.ToLower(line)) {
c = append(c, n)
}
}
return
})
// 尝试读取历史记录文件
if f, err := os.Open(history_fn); err == nil {
line.ReadHistory(f)
f.Close()
}
// 显示提示并获取用户输入
if name, err := line.Prompt("What is your name? "); err == nil {
log.Print("Got: ", name)
// 将输入添加到历史记录
line.AppendHistory(name)
} else if err == liner.ErrPromptAborted {
log.Print("Aborted")
} else {
log.Print("Error reading line: ", err)
}
// 将历史记录写入文件
if f, err := os.Create(history_fn); err != nil {
log.Print("Error writing history file: ", err)
} else {
line.WriteHistory(f)
f.Close()
}
}
代码说明
- 首先创建一个
liner.NewLiner()
实例,并在程序结束时调用Close()
SetCtrlCAborts(true)
设置Ctrl+C可以中止输入SetCompleter()
函数用于设置自动补全逻辑ReadHistory()
和WriteHistory()
用于读取和保存历史记录Prompt()
显示提示并等待用户输入AppendHistory()
将用户输入添加到历史记录
这个示例展示了Liner的基本用法,包括历史记录管理、自动补全和基本的用户交互功能。
更多关于golang命令行界面readline式交互插件库liner的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang命令行界面readline式交互插件库liner的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang命令行交互库Liner使用指南
Liner是一个轻量级的Go库,用于创建具有readline功能的命令行交互界面。它提供了行编辑、历史记录、自动补全等功能,非常适合构建交互式命令行工具。
安装Liner
go get github.com/peterh/liner
基础使用示例
package main
import (
"fmt"
"log"
"strings"
"github.com/peterh/liner"
)
func main() {
line := liner.NewLiner()
defer line.Close()
line.SetCtrlCAborts(true) // 允许Ctrl+C终止程序
// 设置自动补全函数
line.SetCompleter(func(line string) (c []string) {
commands := []string{"help", "exit", "show", "list", "add"}
for _, cmd := range commands {
if strings.HasPrefix(cmd, strings.ToLower(line)) {
c = append(c, cmd)
}
}
return
})
// 加载历史记录
if f, err := liner.NewHistoryFromFile("history.txt"); err == nil {
line.ReadHistory(f)
}
for {
// 读取用户输入
if input, err := line.Prompt("> "); err == nil {
input = strings.TrimSpace(input)
if input == "" {
continue
}
// 添加到历史记录
line.AppendHistory(input)
// 处理命令
switch input {
case "exit":
return
case "help":
fmt.Println("Available commands: help, exit, show, list, add")
default:
fmt.Printf("You entered: %q\n", input)
}
} else if err == liner.ErrPromptAborted {
fmt.Println("Aborted")
break
} else {
log.Print("Error reading line: ", err)
break
}
}
// 保存历史记录
if f, err := liner.NewHistoryFile("history.txt", 0644); err == nil {
line.WriteHistory(f)
f.Close()
} else {
log.Print("Error writing history file: ", err)
}
}
主要功能特性
1. 行编辑功能
Liner提供了类似readline的行编辑功能:
- 左右箭头移动光标
- Home/End键跳转到行首/行尾
- Backspace/Delete删除字符
- Ctrl+U删除整行
- Ctrl+K删除光标到行尾
2. 历史记录
// 添加历史记录
line.AppendHistory("command")
// 保存历史记录到文件
if f, err := liner.NewHistoryFile("history.txt", 0644); err == nil {
line.WriteHistory(f)
f.Close()
}
// 从文件加载历史记录
if f, err := liner.NewHistoryFromFile("history.txt"); err == nil {
line.ReadHistory(f)
}
3. 自动补全
line.SetCompleter(func(line string) (c []string) {
// 返回匹配的补全选项
if strings.HasPrefix("hello", strings.ToLower(line)) {
c = append(c, "hello")
}
if strings.HasPrefix("world", strings.ToLower(line)) {
c = append(c, "world")
}
return
})
4. 密码输入
password, err := line.PasswordPrompt("Enter password: ")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Your password is %d characters long\n", len(password))
5. 多行模式
line.SetMultiLineMode(true) // 启用多行模式
input, err := line.Prompt("multiline> ")
高级配置
// 自定义Tab键行为
line.SetTabCompletionStyle(liner.TabPrints)
// 设置最大历史记录数
line.SetHistoryLimit(1000)
// 自定义Ctrl+C行为
line.SetCtrlCAborts(true)
// 设置自定义提示符
prompt := func() string {
return fmt.Sprintf("[%s] > ", time.Now().Format("15:04:05"))
}
input, err := line.PromptWithSuggestion(prompt(), "default", -1)
实际应用示例 - 简单的数据库CLI
package main
import (
"fmt"
"log"
"strings"
"github.com/peterh/liner"
)
type Database struct {
data map[string]string
}
func NewDatabase() *Database {
return &Database{
data: make(map[string]string),
}
}
func (db *Database) Set(key, value string) {
db.data[key] = value
}
func (db *Database) Get(key string) (string, bool) {
val, ok := db.data[key]
return val, ok
}
func (db *Database) Delete(key string) {
delete(db.data, key)
}
func (db *Database) Keys() []string {
keys := make([]string, 0, len(db.data))
for k := range db.data {
keys = append(keys, k)
}
return keys
}
func main() {
db := NewDatabase()
line := liner.NewLiner()
defer line.Close()
line.SetCompleter(func(line string) (c []string) {
commands := []string{"set", "get", "delete", "keys", "exit"}
for _, cmd := range commands {
if strings.HasPrefix(cmd, strings.ToLower(line)) {
c = append(c, cmd)
}
}
return
})
for {
input, err := line.Prompt("db> ")
if err != nil {
if err == liner.ErrPromptAborted {
fmt.Println("Bye!")
} else {
log.Printf("Error: %v", err)
}
break
}
input = strings.TrimSpace(input)
parts := strings.Fields(input)
if len(parts) == 0 {
continue
}
cmd := strings.ToLower(parts[0])
switch cmd {
case "set":
if len(parts) != 3 {
fmt.Println("Usage: set <key> <value>")
continue
}
db.Set(parts[1], parts[2])
fmt.Println("OK")
case "get":
if len(parts) != 2 {
fmt.Println("Usage: get <key>")
continue
}
if val, ok := db.Get(parts[1]); ok {
fmt.Println(val)
} else {
fmt.Println("(nil)")
}
case "delete":
if len(parts) != 2 {
fmt.Println("Usage: delete <key>")
continue
}
db.Delete(parts[1])
fmt.Println("OK")
case "keys":
keys := db.Keys()
for _, k := range keys {
fmt.Println(k)
}
case "exit":
fmt.Println("Bye!")
return
default:
fmt.Println("Unknown command. Available: set, get, delete, keys, exit")
}
line.AppendHistory(input)
}
}
Liner是一个简单但功能强大的库,适合需要基本命令行交互功能的Go应用程序。它轻量级、易于使用,并且提供了足够的功能来构建复杂的CLI工具。