package main import ( "fmt" "strings" "github.com/chzyer/readline" "github.com/fatih/color" ) // Color helpers var ( cyan = color.New(color.FgCyan).SprintFunc() green = color.New(color.FgGreen).SprintFunc() yellow = color.New(color.FgYellow).SprintFunc() red = color.New(color.FgRed).SprintFunc() magenta = color.New(color.FgMagenta).SprintFunc() ) // parseCommand parses command line respecting quotes func parseCommand(line string) []string { var parts []string var current strings.Builder var quoteChar rune = 0 // Use a rune to store the active quote character (' or ") for _, ch := range line { switch { // If we see a quote character case ch == '\'' || ch == '"': if quoteChar == 0 { // Not currently inside a quoted string, so start one quoteChar = ch } else if quoteChar == ch { // Inside a quoted string and found the matching quote, so end it quoteChar = 0 } else { // Inside a quoted string but found the *other* type of quote, treat it as a literal character current.WriteRune(ch) } // If we see a space or tab and are NOT inside a quoted string case (ch == ' ' || ch == '\t') && quoteChar == 0: if current.Len() > 0 { parts = append(parts, current.String()) current.Reset() } // Any other character default: current.WriteRune(ch) } } // Add the last part if it exists if current.Len() > 0 { parts = append(parts, current.String()) } return parts } // printJSONError displays a user-friendly JSON parsing error with helpful hints func printJSONError(input string, err error) { fmt.Println(red("❌ Invalid JSON:"), err) fmt.Println() // Show what was received if len(input) > 100 { fmt.Println(yellow("Received:"), input[:100]+"...") } else { fmt.Println(yellow("Received:"), input) } fmt.Println() // Provide helpful hints based on common errors errMsg := err.Error() if strings.Contains(errMsg, "looking for beginning of") || strings.Contains(errMsg, "invalid character") { fmt.Println(cyan("💡 Tip:"), "JSON with spaces needs quotes:") fmt.Println(green(" ✓ Correct:"), "put key '{\"hello\":\"world\"}'") fmt.Println(green(" ✓ Correct:"), "put key '{\"a\":1,\"b\":2}'") fmt.Println(green(" ✓ Compact:"), "put key {\"a\":1,\"b\":2} (no spaces)") fmt.Println(red(" ✗ Wrong: "), "put key {\"a\": 1, \"b\": 2} (spaces without quotes)") } else if strings.Contains(errMsg, "unexpected end of JSON") { fmt.Println(cyan("💡 Tip:"), "JSON appears incomplete or cut off") fmt.Println(green(" Check:"), "Are all brackets/braces matched? {}, []") fmt.Println(green(" Check:"), "Did spaces split your JSON into multiple arguments?") } else { fmt.Println(cyan("💡 Tip:"), "Wrap JSON in quotes for complex values:") fmt.Println(green(" Single quotes:"), "put key '{\"your\":\"json\"}'") fmt.Println(green(" Double quotes:"), "put key \"{\\\"your\\\":\\\"json\\\"}\"") } } // Auto-completion setup var completer = readline.NewPrefixCompleter( readline.PcItem("connect"), readline.PcItem("auth"), readline.PcItem("profile", readline.PcItem("add"), readline.PcItem("use"), readline.PcItem("remove"), ), readline.PcItem("get"), readline.PcItem("put"), readline.PcItem("delete"), readline.PcItem("meta", readline.PcItem("get"), readline.PcItem("set", readline.PcItem("--owner"), readline.PcItem("--group"), readline.PcItem("--permissions"), ), ), readline.PcItem("members"), readline.PcItem("health"), readline.PcItem("user", readline.PcItem("get"), readline.PcItem("create"), ), readline.PcItem("help"), readline.PcItem("exit"), readline.PcItem("quit"), readline.PcItem("clear"), )