mirror of
https://github.com/agresdominik/cheat_sheet.git
synced 2026-04-21 18:05:51 +00:00
Merge pull request #1 from agresdominik/ui_optimisation
UI optimisation
This commit is contained in:
+3
-3
@@ -45,7 +45,6 @@
|
|||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
# Kernel Module Compile Results
|
# Kernel Module Compile Results
|
||||||
*.mod*
|
|
||||||
*.cmd
|
*.cmd
|
||||||
.tmp_versions/
|
.tmp_versions/
|
||||||
modules.order
|
modules.order
|
||||||
@@ -57,6 +56,7 @@ dkms.conf
|
|||||||
*.dwo
|
*.dwo
|
||||||
|
|
||||||
# Go
|
# Go
|
||||||
*.sum
|
|
||||||
*.mod
|
|
||||||
bin/*
|
bin/*
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
log/
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
FROM golang:1.24-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN apk add --no-cache make
|
||||||
|
RUN make install
|
||||||
|
CMD ["cheatsh"]
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
EXECUTABLE = cheatsh
|
||||||
|
PACKAGES = ./src/.
|
||||||
|
BINDIR = bin
|
||||||
|
SYSCONFDIR = /etc/cheatsh
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
@mkdir -p bin
|
||||||
|
go build -o bin/$(EXECUTABLE) $(PACKAGES)
|
||||||
|
|
||||||
|
install: build
|
||||||
|
|
||||||
|
@echo "Installing binary in $(PREFIX)"
|
||||||
|
install -Dm755 bin/$(EXECUTABLE) $(PREFIX)/bin/$(EXECUTABLE)
|
||||||
|
|
||||||
|
@echo "Copying config files to $(SYSCONFDIR)"
|
||||||
|
install -Dm644 data/commands.json $(SYSCONFDIR)/commands.json
|
||||||
|
install -Dm644 data/commands_template.json $(SYSCONFDIR)/commands_template.json
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(PREFIX)/bin/$(EXECUTABLE)
|
||||||
|
rm -rf $(SYSCONFDIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf bin/
|
||||||
|
|
||||||
|
docker:
|
||||||
|
docker build -t cheatsh-test .
|
||||||
|
docker run -it --rm cheatsh-test /bin/sh
|
||||||
|
|
||||||
|
local: build
|
||||||
|
./bin/cheatsh --config ./data/commands.json
|
||||||
@@ -68,5 +68,11 @@
|
|||||||
"command": "GOOS=linux GOARCH=amd64 go build -o bin/myprogram.exe main.go",
|
"command": "GOOS=linux GOARCH=amd64 go build -o bin/myprogram.exe main.go",
|
||||||
"desc": "Cross-compile for Linux (alt. windows, darwin (arm64 / amd64))"
|
"desc": "Cross-compile for Linux (alt. windows, darwin (arm64 / amd64))"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"git": [
|
||||||
|
{
|
||||||
|
"command": "git checkout -b branch_name",
|
||||||
|
"desc": "Create and checkout a new branch"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"language/system": [
|
||||||
|
{
|
||||||
|
"command": "the actual command",
|
||||||
|
"desc": "Describe the command here"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "and add any amount of commands below",
|
||||||
|
"desc": "Describe them"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"different language/system": [
|
||||||
|
{
|
||||||
|
"command": "the command for a different language",
|
||||||
|
"desc": "Describe it"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
module github.com/dominikagres/cheat_sheet
|
||||||
|
|
||||||
|
go 1.24.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
|
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
|
golang.org/x/text v0.21.0 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
|
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
|
||||||
|
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||||
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||||
|
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
|
||||||
|
func HandleInput() {
|
||||||
|
|
||||||
|
}
|
||||||
+84
-68
@@ -1,96 +1,112 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
"flag"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
|
||||||
"github.com/rivo/tview"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Individual Command Items Later Extracted
|
type CmdGroup struct {
|
||||||
|
Category string
|
||||||
|
Commands []CmdItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type CmdList []CmdGroup
|
||||||
|
|
||||||
type CmdItem struct {
|
type CmdItem struct {
|
||||||
CommandName string `json:"command"`
|
CommandName string `json:"command"`
|
||||||
CommandDescription string `json:"desc"`
|
CommandDescription string `json:"desc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// All commands
|
func (list CmdList) Get(category string) []CmdItem {
|
||||||
type CmdMap map[string][]CmdItem
|
for _, group := range list {
|
||||||
|
if group.Category == category {
|
||||||
|
return group.Commands
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Read Json-File and return it
|
|
||||||
func loadCommands(path string) (CmdMap, error) {
|
func main() {
|
||||||
|
|
||||||
|
configFlag := flag.String("config", "", "Specify a config file")
|
||||||
|
helpFlag := flag.Bool("help", false, "Show help")
|
||||||
|
newFlag := flag.Bool("new", false, "Add new command to config")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
configFile := "/etc/cheatsh/commands.json"
|
||||||
|
|
||||||
|
var commands CmdList
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if *configFlag != "" {
|
||||||
|
commands, err = loadCommands(*configFlag)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot load commands file: %v", err)
|
||||||
|
}
|
||||||
|
StartTui(commands)
|
||||||
|
return
|
||||||
|
} else if len(os.Args) == 1 {
|
||||||
|
commands, err = loadCommands(configFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot load commands file: %v", err)
|
||||||
|
}
|
||||||
|
StartTui(commands)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
|
||||||
|
case *helpFlag:
|
||||||
|
printHelp()
|
||||||
|
|
||||||
|
case *newFlag:
|
||||||
|
HandleInput()
|
||||||
|
|
||||||
|
default:
|
||||||
|
printHelp()
|
||||||
|
os.Exit(1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHelp() {
|
||||||
|
fmt.Println(`Usage: cheatsh [options]
|
||||||
|
Options:
|
||||||
|
--config <file> Specify a config file
|
||||||
|
--help Show this help message
|
||||||
|
--new Add a new command to the config file`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCommands(path string) (CmdList, error) {
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var m CmdMap
|
var raw map[string][]CmdItem
|
||||||
if err := json.Unmarshal(data, &m); err != nil {
|
err = json.Unmarshal(data, &raw)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function Called when a subset of functions has been selected
|
cmdList := make(CmdList, 0, len(raw))
|
||||||
func showCommandList(app *tview.Application, lang string, cmds []CmdItem, langList *tview.List) {
|
for category, commands := range raw {
|
||||||
cmdList := tview.NewList()
|
cmdList = append(cmdList, CmdGroup{
|
||||||
cmdList.SetBorder(true).SetTitle(fmt.Sprintf("%s commands", lang))
|
Category: category,
|
||||||
|
Commands: commands,
|
||||||
for _, c := range cmds {
|
|
||||||
c := c
|
|
||||||
cmdList.AddItem(c.CommandName, c.CommandDescription, 0, func() {
|
|
||||||
//fmt.Println(c.CommandName)
|
|
||||||
app.Suspend(func() {
|
|
||||||
fmt.Println(c.CommandName) // this now prints visibly
|
|
||||||
})
|
|
||||||
app.Stop()
|
|
||||||
os.Exit(0)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdList.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
sort.Slice(cmdList, func(i, j int) bool {
|
||||||
if event.Rune() == 'b' || event.Key() == tcell.KeyEscape {
|
return cmdList[i].Category < cmdList[j].Category
|
||||||
// Restore the language list
|
|
||||||
app.SetRoot(langList, true)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return event
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.SetRoot(cmdList, true)
|
return cmdList, nil
|
||||||
}
|
|
||||||
|
|
||||||
// Main Function
|
|
||||||
// Initialises the first page and starts app
|
|
||||||
func main() {
|
|
||||||
commands, err := loadCommands("data/commands.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cannot load commands file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
app := tview.NewApplication()
|
|
||||||
|
|
||||||
// Sort alphabetically
|
|
||||||
langs := make([]string, 0, len(commands))
|
|
||||||
for lang := range commands {
|
|
||||||
langs = append(langs, lang)
|
|
||||||
}
|
|
||||||
sort.Strings(langs)
|
|
||||||
|
|
||||||
langList := tview.NewList()
|
|
||||||
langList.SetBorder(true).SetTitle("Select a topic")
|
|
||||||
|
|
||||||
for _, lang := range langs {
|
|
||||||
lang := lang // capture loop variable
|
|
||||||
langList.AddItem(lang, "", 0, func() {
|
|
||||||
showCommandList(app, lang, commands[lang], langList)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := app.SetRoot(langList, true).Run(); err != nil {
|
|
||||||
log.Fatalf("Error initialising TUI: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+158
@@ -0,0 +1,158 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
//"sort"
|
||||||
|
//"strings"
|
||||||
|
|
||||||
|
|
||||||
|
"github.com/charmbracelet/bubbles/key"
|
||||||
|
"github.com/charmbracelet/bubbles/list"
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
title string
|
||||||
|
description string
|
||||||
|
}
|
||||||
|
func (i item) Title() string { return i.title }
|
||||||
|
func (i item) Description() string { return i.description }
|
||||||
|
func (i item) FilterValue() string { return i.title }
|
||||||
|
|
||||||
|
type view int
|
||||||
|
|
||||||
|
type model struct {
|
||||||
|
list list.Model
|
||||||
|
commands CmdList
|
||||||
|
currentView view
|
||||||
|
currentKey string
|
||||||
|
selectedCmd string
|
||||||
|
}
|
||||||
|
func (m model) Init() tea.Cmd { return nil }
|
||||||
|
|
||||||
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
|
||||||
|
case tea.KeyMsg:
|
||||||
|
|
||||||
|
switch msg.String() {
|
||||||
|
|
||||||
|
case "ctrl+c", "q":
|
||||||
|
return m, tea.Quit
|
||||||
|
|
||||||
|
case "enter":
|
||||||
|
selected, ok := m.list.SelectedItem().(item)
|
||||||
|
if ok {
|
||||||
|
if m.currentView == viewCategories {
|
||||||
|
m.currentKey = selected.title
|
||||||
|
m.currentView = viewCommands
|
||||||
|
m.list.Title = m.currentKey
|
||||||
|
m.list.SetItems(cmdItemsToList(m.commands.Get(m.currentKey)))
|
||||||
|
} else if m.currentView == viewCommands {
|
||||||
|
m.selectedCmd = selected.title
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "b":
|
||||||
|
|
||||||
|
if m.currentView == viewCommands {
|
||||||
|
m.currentView = viewCategories
|
||||||
|
m.list.Title = "Choose a list of commands"
|
||||||
|
m.list.SetItems(cmdListKeysToList(m.commands))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case tea.WindowSizeMsg:
|
||||||
|
h, v := docStyle.GetFrameSize()
|
||||||
|
m.list.SetSize(msg.Width-h, msg.Height-v)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd tea.Cmd
|
||||||
|
m.list, cmd = m.list.Update(msg)
|
||||||
|
return m, cmd
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m model) View() string {
|
||||||
|
return docStyle.Render(m.list.View())
|
||||||
|
}
|
||||||
|
|
||||||
|
var docStyle = lipgloss.NewStyle().Margin(1, 2)
|
||||||
|
|
||||||
|
const (
|
||||||
|
viewCategories view = iota
|
||||||
|
viewCommands
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartTui(commands CmdList) {
|
||||||
|
|
||||||
|
delegate := list.NewDefaultDelegate()
|
||||||
|
backKey := key.NewBinding(
|
||||||
|
key.WithKeys("b"),
|
||||||
|
key.WithHelp("b", "back"),
|
||||||
|
)
|
||||||
|
delegate.ShortHelpFunc = func() []key.Binding{
|
||||||
|
return []key.Binding{
|
||||||
|
backKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate.FullHelpFunc = func() [][]key.Binding{
|
||||||
|
return [][]key.Binding{
|
||||||
|
{backKey},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items := cmdListKeysToList(commands)
|
||||||
|
l := list.New(items, delegate, 0, 0)
|
||||||
|
l.Title = "Choose a list of commands"
|
||||||
|
|
||||||
|
m := model{
|
||||||
|
list: l,
|
||||||
|
commands: commands,
|
||||||
|
currentView: viewCategories,
|
||||||
|
}
|
||||||
|
|
||||||
|
p := tea.NewProgram(m, tea.WithAltScreen())
|
||||||
|
finalModel, err := p.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error running program:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := finalModel.(model); ok && m.selectedCmd != "" {
|
||||||
|
fmt.Println(m.selectedCmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdListKeysToList(cmds CmdList) []list.Item {
|
||||||
|
items := []list.Item{}
|
||||||
|
for _, group := range cmds {
|
||||||
|
listItem := item{
|
||||||
|
title: group.Category,
|
||||||
|
description: "",
|
||||||
|
}
|
||||||
|
items = append(items, listItem)
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdItemsToList(cmds []CmdItem) []list.Item {
|
||||||
|
|
||||||
|
items := []list.Item{}
|
||||||
|
|
||||||
|
for _, command := range cmds {
|
||||||
|
listItem := item{
|
||||||
|
title: command.CommandName,
|
||||||
|
description: command.CommandDescription,
|
||||||
|
}
|
||||||
|
items = append(items, listItem)
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user