infinite
:art: infinite
的目标是成为一个易于使用、定制能力强的 tui 组件库
TOC
Install
go get github.com/fzdwx/infinite
Components
这里是infinite
提供的一些组件,你可以把它们变成你的形状.
Autocomplete
这个一个自动补全的组件

Selection
选择器,可更改的选项:
- 一些提示符的自定义,比如说光标的形状,选中/未选中符号...
- 键盘映射
- 每一行输出结果
- Filter
比如说自定义2和3,我们就可以实现一个multi select
-> single select
.
文本输入框
- 支持修改光标的形状
- 输入模式(正常,密码框)
- 一个
Quit key
,默认是关闭的
- 一些提示符自定义
Spinner
微调控制项,什么翻译,就是可以根据定义的一系列的服务,周期性的变换.
除了这个基本功能外,它还可以在刷新提示文字.
Progress
进度条
How to use
这里是infinite
提供的一些开箱即用的组件,它们都是基于上面的基础组件封装而来.
Progress
这是一个进度条组件的使用案例
代码
package main
import (
"fmt"
"github.com/fzdwx/infinite/components"
"time"
)
func main() {
var total = 10
progress := components.NewProgress().
WithTotal(int64(total)).
WithDefaultGradient().
WithPercentAgeFunc(func(total int64, current int64, percent float64) string {
return fmt.Sprintf(" %d/%d", current, total)
})
startUp := components.NewStartUp(progress)
go func() {
sleep()
for i := 0; i < total+1; i++ {
progress.IncrOne()
sleep()
}
for i := 0; i < total; i++ {
progress.DecrOne()
sleep()
}
for i := 0; i < total+1; i++ {
progress.IncrOne()
sleep()
}
startUp.Kill()
}()
startUp.Start()
}
func sleep() {
time.Sleep(time.Millisecond * 100)
}

Progress group
这是一个progress group,它可以管理多个progress.当所有的progress运行完了之后它会自动停止.具体原理可以查看progressUpdater
这个结构体和Group
的done
参数.
代码
package main
import (
"fmt"
"github.com/fzdwx/infinite/components"
"github.com/fzdwx/infinite/components/progress"
"time"
)
func main() {
cnt := 10
group := progress.NewGroupWithCount(10).AppendRunner(func(progress *components.Progress) func() {
total := cnt
cnt += 1
progress.WithTotal(int64(total)).
WithDefaultGradient().
WithPercentAgeFunc(func(total int64, current int64, percent float64) string {
return fmt.Sprintf(" %d/%d", current, total)
})
return func() {
for i := 0; i < total+1; i++ {
progress.IncrOne()
sleep()
}
for i := 0; i < total; i++ {
progress.DecrOne()
sleep()
}
for i := 0; i < total+1; i++ {
progress.IncrOne()
sleep()
}
}
})
group.Display()
}
func sleep() {
time.Sleep(time.Millisecond * 100)
}

Multi select
基于Selection
而来的,基本没有做什么改动.
代码
package main
import (
inf "github.com/fzdwx/infinite"
"github.com/fzdwx/infinite/color"
"github.com/fzdwx/infinite/components"
"github.com/fzdwx/infinite/components/selection/multiselect"
"github.com/fzdwx/infinite/style"
)
func main() {
input := components.NewInput()
input.Prompt = "Filtering: "
input.PromptStyle = style.New().Bold().Italic().Fg(color.LightBlue)
_, _ = inf.NewMultiSelect([]string{
"Buy carrots",
"Buy celery",
"Buy kohlrabi",
"Buy computer",
"Buy something",
"Buy car",
"Buy subway",
},
multiselect.WithHintSymbol("x"),
multiselect.WithUnHintSymbol("√"),
multiselect.WithFilterInput(input),
).Display("select your items!")
}

Single select
基于Multi select
而来的,它减少了一些不要的option
,以及修改了一些key mapping
.
具体可以看singleselect#mapMultiToSingle
这个方法
代码
package main
import (
"fmt"
inf "github.com/fzdwx/infinite"
"github.com/fzdwx/infinite/components/selection/singleselect"
"github.com/rotisserie/eris"
)
func main() {
options := []string{
"1 Buy carrots",
"2 Buy celery",
"3 Buy kohlrabi",
"4 Buy computer",
"5 Buy something",
"6 Buy car",
"7 Buy subway",
}
selected, err := inf.NewSingleSelect(
options,
singleselect.WithDisableFilter(),
).Display("Hello world")
if err != nil {
fmt.Println(eris.ToString(err, true))
return
}
fmt.Printf("you selection %s\n", options[selected])
}

Spinner
基于Spinner
而来的,基本没有做什么改动.
代码
package main
import (
inf "github.com/fzdwx/infinite"
"github.com/fzdwx/infinite/components"
"github.com/fzdwx/infinite/components/spinner"
"time"
)
func main() {
_ = inf.NewSpinner(
spinner.WithShape(components.Dot),
//spinner.WithDisableOutputResult(),
spinner.WithFunc(func(spinner *spinner.Spinner) {
for i := 0; i < 10; i++ {
time.Sleep(time.Millisecond * 100)
spinner.Refreshf("hello world %d", i)
}
spinner.Finish("finish")
spinner.Refresh("is finish?")
}),
).Display()
time.Sleep(time.Millisecond * 100 * 15)
}

Input text
基于Input
而来的,基本没有做什么改动.
代码
package main
import (
"fmt"
inf "github.com/fzdwx/infinite"
"github.com/fzdwx/infinite/components/input/text"
"github.com/fzdwx/infinite/theme"
)
func main() {
i := inf.NewText(
text.WithPrompt("what's your name? "),
text.WithPromptStyle(theme.DefaultTheme.PromptStyle),
text.WithPlaceholder(" fzdwx (maybe)"),
)
_ = i.Display()
fmt.Printf("you input: %s\n", i.Value())
}

Confirm
基于Input
而来的,根据Confirm
的使用场景做了一些适配,它只关注Quit
,Yes
,No
这3个事件.
代码
package main
import (
"fmt"
inf "github.com/fzdwx/infinite"
"github.com/fzdwx/infinite/components/input/confirm"
)
func main() {
c := inf.NewConfirm(
confirm.WithDefaultYes(),
confirm.WithDisplayHelp(),
)
c.Display()
if c.Value() {
fmt.Println("yes, you are.")
} else {
fmt.Println("no,you are not.")
}
}

Build with
License
MIT