initial commit
This commit is contained in:
parent
1ed7ad39d0
commit
68d9e387c9
16 changed files with 1072 additions and 0 deletions
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
9
.idea/TUI.iml
Normal file
9
.idea/TUI.iml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
14
.idea/discord.xml
Normal file
14
.idea/discord.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="ASK" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
<option name="applicationTheme" value="default" />
|
||||||
|
<option name="iconsTheme" value="default" />
|
||||||
|
<option name="button1Title" value="" />
|
||||||
|
<option name="button1Url" value="" />
|
||||||
|
<option name="button2Title" value="" />
|
||||||
|
<option name="button2Url" value="" />
|
||||||
|
<option name="customApplicationId" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/TUI.iml" filepath="$PROJECT_DIR$/.idea/TUI.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
64
ansi.go
Normal file
64
ansi.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package tui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/term"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Colors = string
|
||||||
|
type Fmt = string
|
||||||
|
|
||||||
|
// Formatting
|
||||||
|
const (
|
||||||
|
FmtReset Colors = "\033[0m"
|
||||||
|
FmtBold = "\033[1m"
|
||||||
|
FmtBoldReset = "\033[22m"
|
||||||
|
FmtDim = "\033[2m"
|
||||||
|
FmtDimReset = FmtBoldReset
|
||||||
|
FmtItalic = "\033[3m"
|
||||||
|
FmtItalicReset = "\033[23m"
|
||||||
|
FmtUnderline = "\033[4m"
|
||||||
|
FmtUnderlineReset = "\033[24m"
|
||||||
|
FmtBlink = "\033[5m"
|
||||||
|
FmtBlinkReset = "\033[25m"
|
||||||
|
FmtReverse = "\033[7m"
|
||||||
|
FmtReverseReset = "\033[27m"
|
||||||
|
FmtHidden = "\033[8m"
|
||||||
|
FmtHiddenReset = "\033[28m"
|
||||||
|
FmtStrikethrough = "\033[9m"
|
||||||
|
FmtStrikethroughReset = "\033[29m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Foreground Colors
|
||||||
|
const (
|
||||||
|
FgColorGrey Fmt = "\033[38;5;247m"
|
||||||
|
FgColorGold = "\033[38;5;214m"
|
||||||
|
FgColorGreen = "\033[38;5;34m"
|
||||||
|
FgColorRed = "\033[38;5;167m"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BlankLine() {
|
||||||
|
|
||||||
|
width, _, _ := term.GetSize(int(os.Stdin.Fd()))
|
||||||
|
|
||||||
|
// Assume ptero terminal if no width.
|
||||||
|
if width == 0 {
|
||||||
|
fmt.Print("\033[1B")
|
||||||
|
} else {
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Format(codes ...string) string {
|
||||||
|
|
||||||
|
var str strings.Builder
|
||||||
|
|
||||||
|
for _, code := range codes {
|
||||||
|
str.WriteString(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.String()
|
||||||
|
}
|
113
confirmation/confirmation.go
Normal file
113
confirmation/confirmation.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package confirmation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gitlab.com/omnibill/tui"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InputData struct {
|
||||||
|
Notice string
|
||||||
|
Question string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(data InputData) (*bool, error) {
|
||||||
|
|
||||||
|
if data.Notice != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Notice + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m!\033[38;5;247m]\033[22m \033[3m%s\033[0m\n", data.Notice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Question != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
data.Question + " " +
|
||||||
|
"(" + tui.FgColorGreen + "y" + tui.FmtReset + "/" + tui.FgColorRed + "n" + tui.FmtReset + ") " +
|
||||||
|
tui.FgColorGrey + ">>" + tui.Format(tui.FmtItalic, tui.FgColorGold) + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m?\033[38;5;247m]\033[0m %s (\033[38;5;34my\033[0m/\033[38;5;167mn\033[0m) \033[38;5;247m>>\033[3m\033[38;5;214m\n", data.Question)
|
||||||
|
}
|
||||||
|
|
||||||
|
var input string
|
||||||
|
var chosen bool
|
||||||
|
|
||||||
|
inputLoop:
|
||||||
|
for {
|
||||||
|
if _, err := fmt.Scanln(&input); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
width, _, err := term.GetSize(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch strings.ToLower(input) {
|
||||||
|
case "y", "yes":
|
||||||
|
chosen = true
|
||||||
|
break inputLoop
|
||||||
|
case "n", "no":
|
||||||
|
chosen = false
|
||||||
|
break inputLoop
|
||||||
|
default:
|
||||||
|
var lineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
if data.Notice != "" {
|
||||||
|
lineNum++
|
||||||
|
}
|
||||||
|
lineNum += 2
|
||||||
|
} else {
|
||||||
|
if data.Notice == "" {
|
||||||
|
lineNum = ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
} else {
|
||||||
|
lineNum = ((len(data.Notice) + 5 + width) / width) + ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < lineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
"Invalid input, please try again!\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;167m!\033[38;5;247m]\033[0m Invalid input, please try again!\n")
|
||||||
|
|
||||||
|
if data.Notice != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Notice + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m!\033[38;5;247m]\033[22m \033[3m%s\033[0m\n", data.Notice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Question != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
data.Question + " " +
|
||||||
|
"(" + tui.FgColorGreen + "y" + tui.FmtReset + "/" + tui.FgColorRed + "n" + tui.FmtReset + ") " +
|
||||||
|
tui.FgColorGrey + ">>" + tui.Format(tui.FmtItalic, tui.FgColorGold) + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m?\033[38;5;247m]\033[0m %s (\033[38;5;34my\033[0m/\033[38;5;167mn\033[0m) \033[38;5;247m>>\033[3m\033[38;5;214m\n", data.Question)
|
||||||
|
}
|
||||||
|
continue inputLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\033[0m")
|
||||||
|
|
||||||
|
return &chosen, nil
|
||||||
|
|
||||||
|
}
|
31
displaylist/displaylist.go
Normal file
31
displaylist/displaylist.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package displaylist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.eggactyl.cloud/Eggactyl/tui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListOptions struct {
|
||||||
|
Title string
|
||||||
|
Items []Item
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(opts ListOptions) {
|
||||||
|
|
||||||
|
fmt.Println(tui.FgColorGrey + "[ " + tui.Format(tui.FgColorGold, tui.FmtUnderline) + opts.Title + tui.Format(tui.FmtUnderlineReset, tui.FgColorGrey) + " ]" + tui.FmtReset)
|
||||||
|
|
||||||
|
for _, item := range opts.Items {
|
||||||
|
fmt.Println(itemString(item.Key, item.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func itemString(key string, value string) string {
|
||||||
|
return tui.FgColorGrey + "[ " + tui.FgColorGold + key + " " + tui.FgColorGrey + value + tui.FgColorGrey + " ]" + tui.FmtReset
|
||||||
|
}
|
13
go.mod
Normal file
13
go.mod
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module gitlab.com/omnibill/tui
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.4.1
|
||||||
|
golang.org/x/term v0.25.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
|
golang.org/x/text v0.19.0 // indirect
|
||||||
|
)
|
14
go.sum
Normal file
14
go.sum
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
git.eggactyl.cloud/Eggactyl/tui v0.0.0-20240808144724-4c617ba4b5e2 h1:Moamm0JZr2J+DnkxNonZMmTjIC6lZxMMKQ93sPs4OfU=
|
||||||
|
git.eggactyl.cloud/Eggactyl/tui v0.0.0-20240808144724-4c617ba4b5e2/go.mod h1:nDnIAL3nj3ZRfJIjESD752RtHbInjn2ASxBeeRgSv1g=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk=
|
||||||
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||||
|
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||||
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
345
list/list.go
Normal file
345
list/list.go
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
package list
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"gitlab.com/omnibill/tui"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regex = regexp.MustCompile("\033\\[[0-9;]+m")
|
||||||
|
|
||||||
|
func removeANSIEscapeCodes(input string) string {
|
||||||
|
return regex.ReplaceAllString(input, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListData struct {
|
||||||
|
pages []ListPage
|
||||||
|
history []int
|
||||||
|
currentPage int
|
||||||
|
strLengths []int
|
||||||
|
localizer *i18n.Localizer
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListPage struct {
|
||||||
|
Title string
|
||||||
|
Items []ListItem
|
||||||
|
Render func() []ListItem
|
||||||
|
Cache []ListItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListItem struct {
|
||||||
|
Label string
|
||||||
|
Notice string
|
||||||
|
Order int
|
||||||
|
Render func() ListItem
|
||||||
|
LinkTo int
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(localizer *i18n.Localizer) ListData {
|
||||||
|
return ListData{
|
||||||
|
pages: []ListPage{},
|
||||||
|
history: []int{},
|
||||||
|
localizer: localizer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListData) Execute() interface{} {
|
||||||
|
return l.listRunner()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListData) AddPage(page ListPage) {
|
||||||
|
l.pages = append(l.pages, page)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListData) listRunner() interface{} {
|
||||||
|
|
||||||
|
var option interface{}
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
var tempItemStore []ListItem
|
||||||
|
|
||||||
|
for _, item := range l.pages[l.currentPage].Items {
|
||||||
|
|
||||||
|
if len(l.pages[l.currentPage].Cache) == 0 {
|
||||||
|
if item.Render != nil {
|
||||||
|
renderedItem := item.Render()
|
||||||
|
renderedItem.Value = item.Value
|
||||||
|
tempItemStore = append(tempItemStore, renderedItem)
|
||||||
|
} else {
|
||||||
|
tempItemStore = append(tempItemStore, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(tempItemStore, func(i, j int) bool {
|
||||||
|
return tempItemStore[i].Order < tempItemStore[j].Order
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tempItemStore) != 0 {
|
||||||
|
l.pages[l.currentPage].Cache = append(l.pages[l.currentPage].Cache, tempItemStore...)
|
||||||
|
|
||||||
|
if l.currentPage != 0 {
|
||||||
|
l.pages[l.currentPage].Cache = append(
|
||||||
|
l.pages[l.currentPage].Cache,
|
||||||
|
[]ListItem{
|
||||||
|
{
|
||||||
|
Label: "Back",
|
||||||
|
Value: "action_back",
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
l.renderList()
|
||||||
|
|
||||||
|
chosen := l.inputHandler(l.pages[l.currentPage].Cache)
|
||||||
|
|
||||||
|
if chosen.LinkTo != 0 {
|
||||||
|
|
||||||
|
width, _, _ := term.GetSize(0)
|
||||||
|
|
||||||
|
var totalLineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
totalLineNum = len(l.strLengths)
|
||||||
|
} else {
|
||||||
|
for _, strLength := range l.strLengths {
|
||||||
|
totalLineNum += ((strLength) / width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalLineNum++ //User input line
|
||||||
|
|
||||||
|
for i := 0; i < totalLineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
l.history = append(l.history, l.currentPage)
|
||||||
|
l.currentPage = chosen.LinkTo
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if chosen.Value != nil {
|
||||||
|
|
||||||
|
if _, ok := chosen.Value.(string); ok {
|
||||||
|
if chosen.Value == "action_home" {
|
||||||
|
|
||||||
|
l.currentPage = 0
|
||||||
|
l.history = []int{}
|
||||||
|
|
||||||
|
width, _, _ := term.GetSize(0)
|
||||||
|
|
||||||
|
var totalLineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
totalLineNum = len(l.strLengths)
|
||||||
|
} else {
|
||||||
|
for _, strLength := range l.strLengths {
|
||||||
|
totalLineNum += ((strLength) / width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalLineNum++ //User input line
|
||||||
|
|
||||||
|
for i := 0; i < totalLineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if chosen.Value == "action_back" {
|
||||||
|
|
||||||
|
l.currentPage = l.history[len(l.history)-1]
|
||||||
|
|
||||||
|
if len(l.history) == 1 {
|
||||||
|
l.history = []int{}
|
||||||
|
} else {
|
||||||
|
l.history = l.history[0 : len(l.history)-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
width, _, _ := term.GetSize(0)
|
||||||
|
|
||||||
|
var totalLineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
totalLineNum = len(l.strLengths)
|
||||||
|
} else {
|
||||||
|
for _, strLength := range l.strLengths {
|
||||||
|
totalLineNum += ((strLength) / width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalLineNum++ //User input line
|
||||||
|
|
||||||
|
for i := 0; i < totalLineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option = chosen.Value
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return option
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListData) renderList() {
|
||||||
|
|
||||||
|
l.strLengths = []int{}
|
||||||
|
|
||||||
|
currentPage := l.pages[l.currentPage]
|
||||||
|
|
||||||
|
listNotice := tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + fmt.Sprintf("Please choose an option from 1 - %d", len(currentPage.Cache)) + "\n"
|
||||||
|
|
||||||
|
//listNotice := fmt.Sprintf("\033[1m\033[38;5;247m[\033[38;5;214m!\033[38;5;247m]\033[22m \033[3mPlease choose an option from 1 - %d\033[0m\n", len(currentPage.Cache))
|
||||||
|
l.strLengths = append(l.strLengths, len(removeANSIEscapeCodes(listNotice)))
|
||||||
|
fmt.Print(listNotice)
|
||||||
|
|
||||||
|
listTitle := tui.FgColorGrey + "[ " + tui.Format(tui.FgColorGold, tui.FmtUnderline) + currentPage.Title + ":" + tui.Format(tui.FmtUnderlineReset, tui.FgColorGrey) + " ]" + tui.FmtReset + "\n"
|
||||||
|
l.strLengths = append(l.strLengths, len(removeANSIEscapeCodes(listTitle)))
|
||||||
|
fmt.Print(listTitle)
|
||||||
|
|
||||||
|
longestStrLength := 0
|
||||||
|
|
||||||
|
for _, item := range currentPage.Cache {
|
||||||
|
formattedLabel := removeANSIEscapeCodes(item.Label)
|
||||||
|
if len([]rune(formattedLabel)) > longestStrLength {
|
||||||
|
longestStrLength = len([]rune(formattedLabel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index, item := range currentPage.Cache {
|
||||||
|
var listItem string
|
||||||
|
|
||||||
|
var userInputColor string
|
||||||
|
if index == len(currentPage.Cache)-1 {
|
||||||
|
userInputColor = tui.Format(tui.FmtItalic, tui.FgColorGrey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := item.Value.(string); ok {
|
||||||
|
if item.Value == "action_back" {
|
||||||
|
listItem = " " + tui.FgColorGrey + "[" + tui.Format(tui.FmtBold, tui.FgColorRed) + strconv.Itoa(index+1) + tui.Format(tui.FmtBoldReset, tui.FgColorGrey) + "]" + tui.FmtReset +
|
||||||
|
fmt.Sprintf(" %-*s ", longestStrLength, item.Label) + tui.Format(tui.FmtItalic, tui.FgColorGrey) + item.Notice + tui.FmtReset + userInputColor + "\n"
|
||||||
|
//listItem = fmt.Sprintf(" \033[38;5;247m[\033[1m\033[38;5;167m%d\033[22m\033[38;5;247m]\033[0m %-*s \033[3m\033[38;5;247m%s\033[0m%s\n", index+1, longestStrLength, item.Label, item.Notice, userInputColor)
|
||||||
|
} else {
|
||||||
|
listItem = " " + tui.FgColorGrey + "[" + tui.Format(tui.FmtBold, tui.FgColorGold) + strconv.Itoa(index+1) + tui.Format(tui.FmtBoldReset, tui.FgColorGrey) + "]" + tui.FmtReset +
|
||||||
|
fmt.Sprintf(" %-*s ", longestStrLength, item.Label) + tui.Format(tui.FmtItalic, tui.FgColorGrey) + item.Notice + tui.FmtReset + userInputColor + "\n"
|
||||||
|
//listItem = fmt.Sprintf(" \033[38;5;247m[\033[1m\033[38;5;214m%d\033[22m\033[38;5;247m]\033[0m %-*s \033[3m\033[38;5;247m%s\033[0m%s\n", index+1, longestStrLength, item.Label, item.Notice, userInputColor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listItem = " " + tui.FgColorGrey + "[" + tui.Format(tui.FmtBold, tui.FgColorGold) + strconv.Itoa(index+1) + tui.Format(tui.FmtBoldReset, tui.FgColorGrey) + "]" + tui.FmtReset +
|
||||||
|
fmt.Sprintf(" %-*s ", longestStrLength, item.Label) + tui.Format(tui.FmtItalic, tui.FgColorGrey) + item.Notice + tui.FmtReset + userInputColor + "\n"
|
||||||
|
//listItem = fmt.Sprintf(" \033[38;5;247m[\033[1m\033[38;5;214m%d\033[22m\033[38;5;247m]\033[0m %-*s \033[3m\033[38;5;247m%s\033[0m%s\n", index+1, longestStrLength, item.Label, item.Notice, userInputColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.strLengths = append(l.strLengths, len(removeANSIEscapeCodes(listItem)))
|
||||||
|
fmt.Print(listItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListData) inputHandler(items []ListItem) ListItem {
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
|
var input int
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
|
||||||
|
text := scanner.Text()
|
||||||
|
|
||||||
|
inputAnswer, err := strconv.Atoi(text)
|
||||||
|
if err != nil {
|
||||||
|
width, _, _ := term.GetSize(0)
|
||||||
|
|
||||||
|
var totalLineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
totalLineNum = len(l.strLengths)
|
||||||
|
} else {
|
||||||
|
for _, strLength := range l.strLengths {
|
||||||
|
totalLineNum += (strLength) / width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalLineNum++ //User input line
|
||||||
|
|
||||||
|
for i := 0; i < totalLineNum; i++ {
|
||||||
|
fmt.Printf("\033[0m\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorRed + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
" Invalid input, please try again!\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;167m!\033[38;5;247m]\033[0m Invalid input, please try again!\n")
|
||||||
|
l.strLengths = []int{}
|
||||||
|
|
||||||
|
l.renderList()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if inputAnswer < 1 || inputAnswer > len(items) {
|
||||||
|
width, _, _ := term.GetSize(0)
|
||||||
|
|
||||||
|
var totalLineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
totalLineNum = len(l.strLengths)
|
||||||
|
} else {
|
||||||
|
for _, strLength := range l.strLengths {
|
||||||
|
totalLineNum += (strLength) / width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalLineNum++ //User input line
|
||||||
|
|
||||||
|
for i := 0; i < totalLineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorRed + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
" Invalid input, please try again!\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;167m!\033[38;5;247m]\033[0m Invalid input, please try again!\n")
|
||||||
|
l.strLengths = []int{}
|
||||||
|
|
||||||
|
l.renderList()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
input = inputAnswer
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
chosenItem := items[input-1]
|
||||||
|
|
||||||
|
return chosenItem
|
||||||
|
}
|
190
progress/progress.go
Normal file
190
progress/progress.go
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
package progress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.eggactyl.cloud/Eggactyl/tui"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regex = regexp.MustCompile("\033\\[[0-9;]+m")
|
||||||
|
|
||||||
|
//║░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░║ 40 characters
|
||||||
|
|
||||||
|
type ProgressInfo struct {
|
||||||
|
Size int64
|
||||||
|
Desc string
|
||||||
|
ClearOnFinish bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProgressBar struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
maxBytes int64
|
||||||
|
currentBytes int64
|
||||||
|
hasStarted bool
|
||||||
|
currentPercent int
|
||||||
|
desc string
|
||||||
|
clearFinish bool
|
||||||
|
textWidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(info ProgressInfo) *ProgressBar {
|
||||||
|
return &ProgressBar{
|
||||||
|
maxBytes: info.Size,
|
||||||
|
desc: info.Desc,
|
||||||
|
clearFinish: info.ClearOnFinish,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProgressBar) render(final bool) {
|
||||||
|
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
numFilled := math.Round((float64(p.currentBytes) / float64(p.maxBytes)) * 40)
|
||||||
|
numBlank := 40 - numFilled
|
||||||
|
donePercent := math.Round(float64(p.currentBytes) / float64(p.maxBytes) * 100)
|
||||||
|
|
||||||
|
if int(donePercent) == p.currentPercent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var blockColor string
|
||||||
|
|
||||||
|
if final {
|
||||||
|
blockColor = tui.FgColorGreen
|
||||||
|
} else {
|
||||||
|
blockColor = tui.FgColorGold
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(p.desc)
|
||||||
|
sb.WriteString(" ")
|
||||||
|
|
||||||
|
percentString := strconv.Itoa(int(donePercent)) + "%"
|
||||||
|
blankPercent := 4 - len(percentString)
|
||||||
|
|
||||||
|
for i := 0; i < blankPercent; i++ {
|
||||||
|
sb.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(percentString)
|
||||||
|
|
||||||
|
sb.WriteString(tui.Format(tui.FmtBold, tui.FgColorGrey) + " [" + tui.FmtReset)
|
||||||
|
//sb.WriteString("\033[1m\033[38;5;247m [\033[0m")
|
||||||
|
|
||||||
|
for i := 0; i < int(numFilled); i++ {
|
||||||
|
|
||||||
|
sb.WriteString(blockColor + "█" + tui.FmtReset)
|
||||||
|
//sb.WriteString(fmt.Sprintf("%sm█\033[0m", blockColor))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if numFilled < 40 {
|
||||||
|
|
||||||
|
numBlank = numBlank - 1
|
||||||
|
|
||||||
|
sb.WriteString(tui.FgColorGold + "▒" + tui.FmtReset)
|
||||||
|
//sb.WriteString("\033[38;5;214m▒\033[0m")
|
||||||
|
|
||||||
|
for i := 0; i < int(numBlank); i++ {
|
||||||
|
sb.WriteString(tui.FgColorGrey + "░" + tui.FmtReset)
|
||||||
|
//sb.WriteString("\033[38;5;247m░\033[0m")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for i := 0; i < int(numBlank); i++ {
|
||||||
|
sb.WriteString(tui.FgColorGrey + "░" + tui.FmtReset)
|
||||||
|
//sb.WriteString("\033[38;5;247m░\033[0m")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(tui.Format(tui.FmtBold, tui.FgColorGrey) + "]" + tui.FmtReset)
|
||||||
|
//sb.WriteString("\033[1m\033[38;5;247m]\033[0m")
|
||||||
|
|
||||||
|
width, _, err := term.GetSize(0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
lineNum = 1
|
||||||
|
} else {
|
||||||
|
lineNum = ((len(removeANSIEscapeCodes(sb.String())) + width - 1) / width)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.hasStarted {
|
||||||
|
for i := 0; i < lineNum; i++ {
|
||||||
|
if i == lineNum-1 {
|
||||||
|
fmt.Println("\033[A\033[0G\033[K" + sb.String())
|
||||||
|
} else {
|
||||||
|
fmt.Println("\033[A\033[0G\033[K")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(sb.String())
|
||||||
|
p.hasStarted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
p.textWidth = len(removeANSIEscapeCodes(sb.String()))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProgressBar) Add(num int64) {
|
||||||
|
p.currentBytes = p.currentBytes + num
|
||||||
|
|
||||||
|
p.render(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProgressBar) Close() (err error) {
|
||||||
|
|
||||||
|
if p.clearFinish {
|
||||||
|
|
||||||
|
width, _, err := term.GetSize(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
lineNum = 1
|
||||||
|
} else {
|
||||||
|
lineNum = ((p.textWidth + width - 1) / width)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < lineNum; i++ {
|
||||||
|
fmt.Println("\033[A\033[0G\033[K")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
p.render(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (p *ProgressBar) Write(b []byte) (n int, err error) {
|
||||||
|
n = len(b)
|
||||||
|
p.Add(int64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProgressBar) Read(b []byte) (n int, err error) {
|
||||||
|
p.Add(int64(n))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeANSIEscapeCodes(input string) string {
|
||||||
|
return regex.ReplaceAllString(input, "")
|
||||||
|
}
|
172
textinput/text.go
Normal file
172
textinput/text.go
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
package textinput
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.eggactyl.cloud/Eggactyl/tui"
|
||||||
|
"git.eggactyl.cloud/Eggactyl/tui/validators"
|
||||||
|
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InputData struct {
|
||||||
|
Notice string
|
||||||
|
Question string
|
||||||
|
Validator validators.TextInputValidator
|
||||||
|
ValidationFunc func(input string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(data InputData) (*string, error) {
|
||||||
|
|
||||||
|
if data.Notice != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Notice + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
} else if data.Validator != nil && data.Validator.Notice() != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Validator.Notice() + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m!\033[38;5;247m]\033[22m \033[3m%s\033[0m\n", data.Validator.Notice())
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Question != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "?" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
data.Question + " " + tui.FgColorGrey + ">>" + tui.Format(tui.FmtItalic, tui.FgColorGold) + "\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var input string
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
if _, err := fmt.Scanln(&input); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
width, _, err := term.GetSize(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.ValidationFunc != nil {
|
||||||
|
if !data.ValidationFunc(input) {
|
||||||
|
var lineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
if data.Notice != "" {
|
||||||
|
lineNum++
|
||||||
|
}
|
||||||
|
lineNum += 2
|
||||||
|
} else {
|
||||||
|
if data.Notice == "" {
|
||||||
|
lineNum = ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
} else {
|
||||||
|
lineNum = ((len(data.Notice) + 5 + width) / width) + ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < lineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorRed + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
" Invalid input, please try again!\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.Notice != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Notice + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
} else if data.Validator != nil {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Validator.Notice() + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Question != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "?" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
data.Question + " " + tui.FgColorGrey + ">>" + tui.Format(tui.FmtItalic, tui.FgColorGold) + "\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if data.Validator != nil {
|
||||||
|
if !data.Validator.ValidationFunc(input) {
|
||||||
|
var lineNum int
|
||||||
|
|
||||||
|
if width == 0 {
|
||||||
|
if data.Notice != "" || data.Validator.Notice() != "" {
|
||||||
|
lineNum++
|
||||||
|
}
|
||||||
|
lineNum += 2
|
||||||
|
} else {
|
||||||
|
if data.Notice == "" && data.Validator.Notice() == "" {
|
||||||
|
lineNum = ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
} else {
|
||||||
|
if data.Notice != "" {
|
||||||
|
lineNum = ((len(data.Notice) + 5 + width) / width) + ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
} else if data.Validator.Notice() != "" {
|
||||||
|
lineNum = ((len(data.Validator.Notice()) + 5 + width - 1) / width) + ((len(data.Question) + 5 + width - 1) / width) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < lineNum; i++ {
|
||||||
|
fmt.Printf("\033[A\033[K\033[0G")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorRed + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
" Invalid input, please try again!\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.Notice != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Notice + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m!\033[38;5;247m]\033[22m \033[3m%s\033[0m\n", data.Notice)
|
||||||
|
} else if data.Validator.Notice() != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "!" + tui.FgColorGrey + "]" + tui.FmtBoldReset + " " +
|
||||||
|
tui.FmtItalic + data.Validator.Notice() + tui.FmtReset + "\n",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Question != "" {
|
||||||
|
fmt.Printf(
|
||||||
|
tui.Format(tui.FmtBold, tui.FgColorGrey) +
|
||||||
|
"[" + tui.FgColorGold + "?" + tui.FgColorGrey + "]" + tui.FmtReset + " " +
|
||||||
|
data.Question + " " + tui.FgColorGrey + ">>" + tui.Format(tui.FmtItalic, tui.FgColorGold) + "\n",
|
||||||
|
)
|
||||||
|
//fmt.Printf("\033[1m\033[38;5;247m[\033[38;5;214m?\033[38;5;247m]\033[0m %s \033[38;5;247m>>\033[3m\033[38;5;214m\n", data.Question)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\033[0m")
|
||||||
|
|
||||||
|
return &input, nil
|
||||||
|
|
||||||
|
}
|
6
validators/interface.go
Normal file
6
validators/interface.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package validators
|
||||||
|
|
||||||
|
type TextInputValidator interface {
|
||||||
|
Notice() string
|
||||||
|
ValidationFunc(input string) bool
|
||||||
|
}
|
46
validators/mc_version.go
Normal file
46
validators/mc_version.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func McVersion(versions []string) TextInputValidator {
|
||||||
|
return TextInputMCVersion{
|
||||||
|
versions: versions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextInputMCVersion struct {
|
||||||
|
versions []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d TextInputMCVersion) Notice() string {
|
||||||
|
var versionString string
|
||||||
|
|
||||||
|
for index, version := range d.versions {
|
||||||
|
if index == (len(d.versions) - 1) {
|
||||||
|
versionString = versionString + version
|
||||||
|
} else {
|
||||||
|
versionString = versionString + version + ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Available Versions: %s", versionString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d TextInputMCVersion) ValidationFunc(input string) bool {
|
||||||
|
|
||||||
|
isFound := false
|
||||||
|
|
||||||
|
for _, ver := range d.versions {
|
||||||
|
|
||||||
|
if ver == input {
|
||||||
|
isFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFound
|
||||||
|
|
||||||
|
}
|
33
validators/range.go
Normal file
33
validators/range.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package validators
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Range(min int, max int) TextInputValidator {
|
||||||
|
return TextInputRange{
|
||||||
|
min: min,
|
||||||
|
max: max,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextInputRange struct {
|
||||||
|
min int
|
||||||
|
max int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d TextInputRange) Notice() string {
|
||||||
|
return fmt.Sprintf("Valid values: (%d - %d)", d.min, d.max)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d TextInputRange) ValidationFunc(input string) bool {
|
||||||
|
portNum, err := strconv.Atoi(input)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if portNum > 65535 || portNum < 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
Loading…
Reference in a new issue