From 1fbee269ce851f0d9052dcbd26f050ab4aded8d9 Mon Sep 17 00:00:00 2001 From: Nick Goodall Date: Tue, 13 Jan 2026 14:45:36 +0000 Subject: [PATCH] colour setup --- main.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 3900906..8d5bfc7 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( "strings" "time" "unicode" + "unicode/utf8" tea "github.com/charmbracelet/bubbletea" "github.com/pelletier/go-toml/v2" @@ -314,11 +315,12 @@ func generateServiceName() string { func promptServiceName(defaultName string) (string, error) { reader := bufio.NewReader(os.Stdin) - fmt.Printf("Service name [%s]: ", defaultName) + fmt.Printf("%sService name%s [%s]: ", headerColor, remoteColorReset, defaultName) input, err := reader.ReadString('\n') if err != nil { return "", err } + input = normalizePromptInput(input) input = strings.TrimSpace(input) if input == "" { return defaultName, nil @@ -365,7 +367,7 @@ func confirmServerConfig(pbPath string) error { return err } - fmt.Println("Confirm remote server settings (press Enter to keep the current value):") + fmt.Printf("Confirm remote server settings (press Enter to keep the current value):\n") reader := bufio.NewReader(os.Stdin) ipDefault := cfg.Server.IP @@ -406,16 +408,18 @@ func confirmServerConfig(pbPath string) error { } func promptWithDefault(reader *bufio.Reader, label, defaultValue string) (string, error) { + fmt.Printf("%s%s%s", headerColor, label, remoteColorReset) if defaultValue != "" { - fmt.Printf("%s [%s]: ", label, defaultValue) + fmt.Printf(" [%s]: ", defaultValue) } else { - fmt.Printf("%s: ", label) + fmt.Print(": ") } input, err := reader.ReadString('\n') if err != nil { return "", err } + input = normalizePromptInput(input) input = strings.TrimSpace(input) if input == "" { return defaultValue, nil @@ -429,11 +433,12 @@ func promptPort(reader *bufio.Reader, label string, defaultValue int) (int, erro } for { - fmt.Printf("%s [%d]: ", label, defaultValue) + fmt.Printf("%s%s%s [%d]: ", headerColor, label, remoteColorReset, defaultValue) input, err := reader.ReadString('\n') if err != nil { return 0, err } + input = normalizePromptInput(input) value := strings.TrimSpace(input) if value == "" { return defaultValue, nil @@ -447,6 +452,68 @@ func promptPort(reader *bufio.Reader, label string, defaultValue int) (int, erro } } +func normalizePromptInput(raw string) string { + var buf []rune + for i := 0; i < len(raw); { + r, size := utf8.DecodeRuneInString(raw[i:]) + if size == 0 { + break + } + if r == '\r' || r == '\n' { + break + } + if r == 0x1b { + nextIndex := i + size + if nextIndex >= len(raw) { + break + } + next, nextSize := utf8.DecodeRuneInString(raw[nextIndex:]) + if next == 0x7f || next == 0x08 { + buf = deletePreviousWord(buf) + i = nextIndex + nextSize + continue + } + if next == '[' || next == 'O' { + i = nextIndex + nextSize + for i < len(raw) { + code, codeSize := utf8.DecodeRuneInString(raw[i:]) + if codeSize == 0 { + break + } + i += codeSize + if ('A' <= code && code <= 'Z') || ('a' <= code && code <= 'z') { + break + } + } + continue + } + i = nextIndex + nextSize + continue + } + if r == 0x7f || r == 0x08 { + if len(buf) > 0 { + buf = buf[:len(buf)-1] + } + i += size + continue + } + buf = append(buf, r) + i += size + } + return string(buf) +} + +func deletePreviousWord(buf []rune) []rune { + i := len(buf) + for i > 0 && unicode.IsSpace(buf[i-1]) { + i-- + } + for i > 0 && !unicode.IsSpace(buf[i-1]) { + i-- + } + return buf[:i] +} + func pocketbaseBinaryName(goos string) string { if goos == "windows" { return "pocketbase.exe"