diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ad19971..82754bd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,4 +18,4 @@ jobs: with: go-version: "1.24" - name: golangci-lint - uses: golangci/golangci-lint-action@f08454af877ea2a5246a58683951857b61853eab + uses: golangci/golangci-lint-action@b68d21b131098f33ec55c11c242113b4a10dc30a diff --git a/cmd/ari/input.go b/cmd/ari/input.go deleted file mode 100644 index 1ad9a30..0000000 --- a/cmd/ari/input.go +++ /dev/null @@ -1,487 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "regexp" - "sort" - "strings" - - "codeberg.org/anaseto/goal" - "github.com/knz/bubbline" - "github.com/knz/bubbline/complete" - "github.com/knz/bubbline/computil" - "github.com/knz/bubbline/editline" - "github.com/semperos/ari" - "github.com/spf13/viper" -) - -type AutoCompleter struct { - ariContext *ari.Context - sqlKeywords []string - goalKeywordsKeys []string - goalSyntaxAliases map[string]string - goalSyntaxKeys []string - systemCommandsHelp map[string]string - systemCommandsKeys []string -} - -func matchesSystemCommand(s string) bool { - return strings.HasPrefix(s, ")") -} - -// CheckInputComplete handler for Goal. -// -// This detects whether a SQL statement is complete from the CLI editor's perspective, -// it does not provide autocomplete functionality. -func modeGoalCheckInputComplete(v [][]rune, line, _ int) bool { - if len(v) == 1 && matchesSystemCommand(string(v[0])) { - return true - } - if line == len(v)-1 { // Enter on final line of input to allow inserting newlines. - s := stringFromSliceOfRuneSlices(v) - sc := &scanner{r: bufio.NewReader(strings.NewReader(s))} - _, err := sc.readLine() - // No error means it parsed completely as a Goal expression. - return err == nil - } - return false -} - -func stringFromSliceOfRuneSlices(v [][]rune) string { - sb := strings.Builder{} - for _, runeSlice := range v { - sb.WriteString(string(runeSlice)) - sb.WriteByte('\n') - } - return sb.String() -} - -// scanner represents the state of a readline scanner for the Goal REPL. It -// handles multi-line expressions. -type scanner struct { - r *bufio.Reader - depth []byte // (){}[] depth stack - state scanState - done bool - escape bool -} - -type scanState int - -const ( - scanNormal scanState = iota - scanComment - scanCommentBlock - scanString - scanQuote - scanRawQuote -) - -const delimchars = ":+-*%!&|=~,^#_?@/`" - -// readLine reads until the first end of line that also ends a Goal expression. -// -// Adapated from Goal's implementation. -// -//nolint:cyclop,funlen,gocognit,gocyclo // Vendored code -func (sc *scanner) readLine() (string, error) { - *sc = scanner{r: sc.r, depth: sc.depth[:0]} - sb := strings.Builder{} - var qr byte = '/' - nl := true // at newline - cs := true // at possible start of comment - cbdelim := false // after possible comment block start/end delimiter - for { - c, err := sc.r.ReadByte() - if err != nil { - return sb.String(), err - } - switch c { - case '\r': - continue - default: - sb.WriteByte(c) - } - switch sc.state { - case scanNormal: - switch c { - case '\n': - if len(sc.depth) == 0 || sc.done { - return sb.String(), nil - } - cs = true - case ' ', '\t': - cs = true - case '"': - sc.state = scanString - cs = false - case '{', '(', '[': - sc.depth = append(sc.depth, c) - cs = true - case '}', ')', ']': - if len(sc.depth) > 0 && sc.depth[len(sc.depth)-1] == opening(c) { - sc.depth = sc.depth[:len(sc.depth)-1] - } else { - // error, so return on next \n - sc.done = true - } - cs = false - default: - if strings.IndexByte(delimchars, c) != -1 { - acc := sb.String() - switch { - case strings.HasSuffix(acc[:len(acc)-1], "rx"): - qr = c - sc.state = scanQuote - case strings.HasSuffix(acc[:len(acc)-1], "rq"): - qr = c - sc.state = scanRawQuote - case strings.HasSuffix(acc[:len(acc)-1], "qq"): - qr = c - sc.state = scanQuote - default: - if c == '/' && cs { - sc.state = scanComment - cbdelim = nl - } - } - } - cs = false - } - case scanComment: - if c == '\n' { - //nolint:gocritic // vendored code - if cbdelim { - sc.state = scanCommentBlock - } else if len(sc.depth) == 0 || sc.done { - return sb.String(), nil - } else { - cs = true - sc.state = scanNormal - } - } - cbdelim = false - case scanCommentBlock: - if cbdelim && c == '\n' { - if len(sc.depth) == 0 || sc.done { - return sb.String(), nil - } - cs = true - sc.state = scanNormal - } else { - cbdelim = nl && c == '\\' - } - case scanQuote: - switch c { - case '\\': - sc.escape = !sc.escape - case qr: - if !sc.escape { - sc.state = scanNormal - } - sc.escape = false - default: - sc.escape = false - } - case scanString: - switch c { - case '\\': - sc.escape = !sc.escape - case '"': - if !sc.escape { - sc.state = scanNormal - } - sc.escape = false - default: - sc.escape = false - } - case scanRawQuote: - if c == qr { - //nolint:govet // vendored code - c, err := sc.r.ReadByte() - if err != nil { - return sb.String(), err - } - if c == qr { - sb.WriteByte(c) - } else { - //nolint:errcheck // Goal impl says cannot error - sc.r.UnreadByte() // cannot error - sc.state = scanNormal - } - } - } - nl = c == '\n' - } -} - -// opening returns matching opening delimiter for a given closing delimiter. -// -// Adapted from Goal's implementation. -func opening(r byte) byte { - switch r { - case ')': - return '(' - case ']': - return '[' - case '}': - return '{' - default: - return r - } -} - -// CheckInputComplete handler for SQL. -// -// This detects whether a SQL statement is complete from the CLI editor's perspective, -// it does not provide autocomplete functionality. -func modeSQLCheckInputComplete(v [][]rune, line, _ int) bool { - if len(v) == 1 && matchesSystemCommand(string(v[0])) { - return true - } - if line == len(v)-1 && // Enter on last row. - strings.HasSuffix(string(v[len(v)-1]), ";") { // Semicolon at end of last row.; - return true - } - return false -} - -// Autocompletion - -//nolint:lll -func (autoCompleter *AutoCompleter) systemCommandsAutoComplete() func(v [][]rune, line, col int) (string, editline.Completions) { - // Cache system commands, few though they be. - if autoCompleter.systemCommandsKeys == nil { - autoCompleter.cacheSystemCommands() - } - return func(v [][]rune, line, col int) (string, editline.Completions) { - perCategory := map[string][]acEntry{} - word, start, end := computil.FindWord(v, line, col) - lword := strings.ToLower(word) - if matchesSystemCommand(lword) { - for _, mode := range autoCompleter.systemCommandsKeys { - if len(lword) == 0 || strings.HasPrefix(strings.ToLower(mode), lword) { - perCategory["mode"] = append(perCategory["mode"], acEntry{mode, autoCompleter.systemCommandsHelp[mode]}) - } - } - } - - completions := &multiComplete{ - Values: complete.MapValues(perCategory, nil), - moveRight: end - col, - deleteLeft: end - start, - } - msg := "" - return msg, completions - } -} - -//nolint:lll -func (autoCompleter *AutoCompleter) goalAutoCompleteFn() func(v [][]rune, line, col int) (string, editline.Completions) { - goalNameRe := regexp.MustCompile(`[a-zA-Z\.]+`) - // Cache Goal syntax autocompletion keys. - if autoCompleter.goalSyntaxKeys == nil { - autoCompleter.cacheGoalSyntax() - } - return func(v [][]rune, line, col int) (string, editline.Completions) { - perCategory := map[string][]acEntry{} - word, start, end := computil.FindWord(v, line, col) - // N.B. Matching system commands must come first. - if matchesSystemCommand(word) { - return autoCompleter.systemCommandsAutoComplete()(v, line, col) - } - locs := goalNameRe.FindStringIndex(word) - if locs != nil { - word = word[locs[0]:locs[1]] - start = locs[0] // Preserve non-word prefix - end = locs[1] // Preserve non-word suffix - } - // msg := fmt.Sprintf("Matching %v", word) - lword := strings.ToLower(word) - autoCompleteGoalGlobals(autoCompleter, lword, perCategory) - autoCompleteGoalKeywords(autoCompleter, lword, perCategory) - autoCompleteGoalSyntax(autoCompleter, lword, perCategory) - // msg = fmt.Sprintf("Type is %v") - completions := &multiComplete{ - Values: complete.MapValues(perCategory, nil), - moveRight: end - col, - deleteLeft: end - start, - } - msg := "" - return msg, completions - } -} - -func autoCompleteGoalSyntax(autoCompleter *AutoCompleter, lword string, perCategory map[string][]acEntry) { - helpFunc := autoCompleter.ariContext.Help.Func - category := "Syntax" - syntaxSet := make(map[string]bool, 0) - for _, name := range autoCompleter.goalSyntaxKeys { - chstr := autoCompleter.goalSyntaxAliases[name] - if strings.HasPrefix(strings.ToLower(name), lword) { - if _, ok := syntaxSet[chstr]; !ok { - syntaxSet[chstr] = true - help := helpFunc(chstr) - perCategory[category] = append(perCategory[category], acEntry{chstr, help}) - } - } - } -} - -func autoCompleteGoalKeywords(autoCompleter *AutoCompleter, lword string, perCategory map[string][]acEntry) { - // Keywords can be user-defined via Go, but they are all present once Goal is initialized. - if autoCompleter.goalKeywordsKeys == nil { - autoCompleter.cacheGoalKeywords(autoCompleter.ariContext.GoalContext) - } - helpFunc := autoCompleter.ariContext.Help.Func - category := "Keyword" - for _, goalKeyword := range autoCompleter.goalKeywordsKeys { - if strings.HasPrefix(strings.ToLower(goalKeyword), lword) { - help := helpFunc(goalKeyword) - perCategory[category] = append(perCategory[category], acEntry{goalKeyword, help}) - } - } -} - -func autoCompleteGoalGlobals(autoCompleter *AutoCompleter, lword string, perCategory map[string][]acEntry) { - goalContext := autoCompleter.ariContext.GoalContext - helpFunc := autoCompleter.ariContext.Help.Func - // Globals cannot be cached; this is what assignment in Goal creates. - goalGlobals := goalContext.GlobalNames(nil) - sort.Strings(goalGlobals) - category := "Global" - for _, goalGlobal := range goalGlobals { - if strings.HasPrefix(strings.ToLower(goalGlobal), lword) { - help := helpFunc(goalGlobal) - perCategory[category] = append(perCategory[category], acEntry{goalGlobal, help}) - } - } -} - -func (autoCompleter *AutoCompleter) sqlAutoCompleteFn() func(v [][]rune, line, col int) (string, editline.Completions) { - // Cache sorted slice of SQL keywords - if autoCompleter.sqlKeywords == nil { - autoCompleter.cacheSQL() - } - return func(v [][]rune, line, col int) (string, editline.Completions) { - word, wstart, wend := computil.FindWord(v, line, col) - // msg = fmt.Sprintf("Matching '%v'", word) - perCategory := map[string][]acEntry{} - lword := strings.ToLower(word) - // N.B. Matching system commands must come first. - if matchesSystemCommand(word) { - return autoCompleter.systemCommandsAutoComplete()(v, line, col) - } - for _, sqlWord := range autoCompleter.sqlKeywords { - if strings.HasPrefix(strings.ToLower(sqlWord), lword) { - perCategory["sql"] = append(perCategory["sql"], acEntry{sqlWord, "A SQL keyword"}) - } - } - completions := &multiComplete{ - Values: complete.MapValues(perCategory, nil), - moveRight: wend - col, - deleteLeft: wend - wstart, - } - msg := "" - return msg, completions - } -} - -func (autoCompleter *AutoCompleter) cacheGoalKeywords(goalContext *goal.Context) { - goalKeywords := goalContext.Keywords(nil) - sort.Strings(goalKeywords) - autoCompleter.goalKeywordsKeys = goalKeywords -} - -func (autoCompleter *AutoCompleter) cacheGoalSyntax() { - goalSyntax := ari.GoalSyntax() - keys := make([]string, 0) - for k := range goalSyntax { - keys = append(keys, k) - } - sort.Strings(keys) - autoCompleter.goalSyntaxKeys = keys - autoCompleter.goalSyntaxAliases = goalSyntax -} - -func (autoCompleter *AutoCompleter) cacheSQL() { - autoCompleter.sqlKeywords = ari.SQLKeywords() -} - -func (autoCompleter *AutoCompleter) cacheSystemCommands() { - m, ks := systemCommands() - autoCompleter.systemCommandsKeys = ks - autoCompleter.systemCommandsHelp = m -} - -func systemCommands() (map[string]string, []string) { - m := map[string]string{ - ")goal": "Goal array language mode", - ")goal.invoke": "Goal array language mode, auto-invocation of functions", - // TODO Output formats: https://duckdb.org/docs/api/cli/output_formats.html - // In particular csv, json, markdown, latex, and one of the boxed ones - ")output.csv": "Print results as CSV", - ")output.goal": "Print results as Goal values (default)", - ")output.json": "Print results as JSON", - ")output.json+pretty": "Print results as JSON with indentation", - ")output.latex": "Print results as LaTeX", - ")output.markdown": "Print results as Markdown", - ")output.tsv": "Print results as TSV", - ")sql": "Read-only SQL mode (querying)", - ")sql!": "Read/write SQL mode", - } - // Prepare sorted keys ahead of time - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - return m, keys -} - -type acEntry struct { - name, description string -} - -func (e acEntry) Title() string { - return e.name -} - -func (e acEntry) Description() string { - return "\n" + e.description -} - -type multiComplete struct { - complete.Values - moveRight, deleteLeft int -} - -func (m *multiComplete) Candidate(e complete.Entry) editline.Candidate { - return candidate{e.Title(), m.moveRight, m.deleteLeft} -} - -type candidate struct { - repl string - moveRight, deleteLeft int -} - -func (m candidate) Replacement() string { return m.repl } -func (m candidate) MoveRight() int { return m.moveRight } -func (m candidate) DeleteLeft() int { return m.deleteLeft } - -// Bubbline - -func cliEditorInitialize() *bubbline.Editor { - editor := bubbline.New() - editor.Placeholder = "" - historyFile := viper.GetString("history") - if err := editor.LoadHistory(historyFile); err != nil { - fmt.Fprintf(os.Stderr, "Failed to load history, error: %v\n", err) - } - editor.SetAutoSaveHistory(historyFile, true) - editor.SetDebugEnabled(false) - editor.SetExternalEditorEnabled(true, "goal") - return editor -} diff --git a/cmd/ari/main.go b/cmd/ari/main.go index a8b115d..074e589 100644 --- a/cmd/ari/main.go +++ b/cmd/ari/main.go @@ -4,7 +4,6 @@ import ( "bufio" "errors" "fmt" - "io" "log" "os" "path" @@ -16,7 +15,6 @@ import ( "unsafe" "codeberg.org/anaseto/goal" - "github.com/knz/bubbline" _ "github.com/marcboeker/go-duckdb" "github.com/semperos/ari" "github.com/spf13/cobra" @@ -57,15 +55,12 @@ const ( ) type CliSystem struct { - ariContext *ari.Context - autoCompleter *AutoCompleter - cliEditor *bubbline.Editor - cliMode cliMode - debug bool - outputFormat outputFormat - programName string - prompt string - rawREPL bool + ariContext *ari.Context + cliMode cliMode + debug bool + outputFormat outputFormat + programName string + prompt string } func (cliSystem *CliSystem) switchMode(cliMode cliMode, args []string) error { @@ -90,13 +85,6 @@ func (cliSystem *CliSystem) switchMode(cliMode cliMode, args []string) error { func (cliSystem *CliSystem) switchModeToGoal() error { cliSystem.cliMode = cliModeGoal cliSystem.prompt = cliModeGoalPrompt - if !cliSystem.rawREPL { - cliSystem.cliEditor.Prompt = cliModeGoalPrompt - cliSystem.cliEditor.NextPrompt = cliModeGoalNextPrompt - cliSystem.cliEditor.AutoComplete = cliSystem.autoCompleter.goalAutoCompleteFn() - cliSystem.cliEditor.CheckInputComplete = modeGoalCheckInputComplete - cliSystem.cliEditor.SetExternalEditorEnabled(true, "goal") - } cliSystem.detectPrompt() return nil } @@ -124,13 +112,6 @@ func (cliSystem *CliSystem) switchModeToSQLReadOnly(args []string) error { } cliSystem.cliMode = cliModeSQLReadOnly cliSystem.prompt = cliModeSQLReadOnlyPrompt - if !cliSystem.rawREPL { - cliSystem.cliEditor.CheckInputComplete = modeSQLCheckInputComplete - cliSystem.cliEditor.AutoComplete = cliSystem.autoCompleter.sqlAutoCompleteFn() - cliSystem.cliEditor.SetExternalEditorEnabled(true, "sql") - cliSystem.cliEditor.Prompt = cliModeSQLReadOnlyPrompt - cliSystem.cliEditor.NextPrompt = cliModeSQLReadOnlyNextPrompt - } return nil } @@ -152,13 +133,6 @@ func (cliSystem *CliSystem) switchModeToSQLReadWrite(args []string) error { } cliSystem.cliMode = cliModeSQLReadOnly cliSystem.prompt = cliModeSQLReadWritePrompt - if !cliSystem.rawREPL { - cliSystem.cliEditor.CheckInputComplete = modeSQLCheckInputComplete - cliSystem.cliEditor.AutoComplete = cliSystem.autoCompleter.sqlAutoCompleteFn() - cliSystem.cliEditor.SetExternalEditorEnabled(true, "sql") - cliSystem.cliEditor.Prompt = cliModeSQLReadWritePrompt - cliSystem.cliEditor.NextPrompt = cliModeSQLReadWriteNextPrompt - } return nil } @@ -209,13 +183,11 @@ func ariMain(cmd *cobra.Command, args []string) int { return 1 } programName := os.Args[0] - // Delay initializing CLI editor and friends until needed mainCliSystem := CliSystem{ ariContext: ariContext, debug: viper.GetBool("debug"), programName: programName, prompt: cliModeGoalPrompt, - rawREPL: viper.GetBool("raw"), } // MUST COME FIRST @@ -323,13 +295,6 @@ func ariMain(cmd *cobra.Command, args []string) int { return 0 } - // With files loaded (which might adjust the prompt via Goal code) - // and knowing we're not executing and exiting immediately, - // set up the CLI REPL. - if !mainCliSystem.rawREPL { - mainCliSystem.cliEditor = cliEditorInitialize() - mainCliSystem.autoCompleter = &AutoCompleter{ariContext: ariContext} - } startupCliModeString := viper.GetString("mode") startupCliMode, err := cliModeFromString(startupCliModeString) if err != nil { @@ -344,68 +309,202 @@ func ariMain(cmd *cobra.Command, args []string) int { } // REPL - if mainCliSystem.rawREPL { - rawREPL(&mainCliSystem) - } else { - editorREPL(&mainCliSystem) - } + rawREPL(&mainCliSystem) return 0 } func registerCliGoalBindings(ariContext *ari.Context) { - goalContext := ariContext.GoalContext - goalContext.RegisterMonad("tui.color", vfTuiColor) - goalContext.RegisterMonad("tui.style", vfTuiStyle) - goalContext.RegisterDyad("tui.render", vfTuiRender) + // Previously registered TUI bindings, now removed } -func rawREPL(cliSystem *CliSystem) { - sc := &scanner{r: bufio.NewReader(os.Stdin)} - for { - fmt.Fprint(os.Stdout, cliSystem.prompt) - line, err := sc.readLine() - line = strings.TrimRight(line, "\n\r") - if err != nil && line == "" { - return - } - if matchesSystemCommand(line) { - err = cliSystem.replEvalSystemCommand(line) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to execute system command %q with error: %v\n", line, err) - } - continue - } +func matchesSystemCommand(s string) bool { + return strings.HasPrefix(s, ")") +} - replHandleLine(cliSystem, line) - } +// scanner represents the state of a readline scanner for the Goal REPL. It +// handles multi-line expressions. +type scanner struct { + r *bufio.Reader + depth []byte // (){}[] depth stack + state scanState + done bool + escape bool } -func editorREPL(cliSystem *CliSystem) { - cliEditor := cliSystem.cliEditor +type scanState int + +const ( + scanNormal scanState = iota + scanComment + scanCommentBlock + scanString + scanQuote + scanRawQuote +) + +const delimchars = ":+-*%!&|=~,^#_?@/`" + +// readLine reads until the first end of line that also ends a Goal expression. +// +// Adapated from Goal's implementation. +// +//nolint:cyclop,funlen,gocognit,gocyclo // Vendored code +func (sc *scanner) readLine() (string, error) { + *sc = scanner{r: sc.r, depth: sc.depth[:0]} + sb := strings.Builder{} + var qr byte = '/' + nl := true // at newline + cs := true // at possible start of comment + cbdelim := false // after possible comment block start/end delimiter for { - line, err := cliEditor.GetLine() + c, err := sc.r.ReadByte() if err != nil { - if errors.Is(err, io.EOF) { - cliSystem.shutdown() - break + return sb.String(), err + } + switch c { + case '\r': + continue + default: + sb.WriteByte(c) + } + switch sc.state { + case scanNormal: + switch c { + case '\n': + if len(sc.depth) == 0 || sc.done { + return sb.String(), nil + } + cs = true + case ' ', '\t': + cs = true + case '"': + sc.state = scanString + cs = false + case '{', '(', '[': + sc.depth = append(sc.depth, c) + cs = true + case '}', ')', ']': + if len(sc.depth) > 0 && sc.depth[len(sc.depth)-1] == opening(c) { + sc.depth = sc.depth[:len(sc.depth)-1] + } else { + // error, so return on next \n + sc.done = true + } + cs = false + default: + if strings.IndexByte(delimchars, c) != -1 { + acc := sb.String() + switch { + case strings.HasSuffix(acc[:len(acc)-1], "rx"): + qr = c + sc.state = scanQuote + case strings.HasSuffix(acc[:len(acc)-1], "rq"): + qr = c + sc.state = scanRawQuote + case strings.HasSuffix(acc[:len(acc)-1], "qq"): + qr = c + sc.state = scanQuote + default: + if c == '/' && cs { + sc.state = scanComment + cbdelim = nl + } + } + } + cs = false + } + case scanComment: + if c == '\n' { + //nolint:gocritic // vendored code + if cbdelim { + sc.state = scanCommentBlock + } else if len(sc.depth) == 0 || sc.done { + return sb.String(), nil + } else { + cs = true + sc.state = scanNormal + } } - if errors.Is(err, bubbline.ErrInterrupted) { - // Entered Ctrl+C to cancel input. - fmt.Fprintln(os.Stdout, "^C") + cbdelim = false + case scanCommentBlock: + if cbdelim && c == '\n' { + if len(sc.depth) == 0 || sc.done { + return sb.String(), nil + } + cs = true + sc.state = scanNormal } else { - fmt.Fprintln(os.Stderr, "error:", err) + cbdelim = nl && c == '\\' + } + case scanQuote: + switch c { + case '\\': + sc.escape = !sc.escape + case qr: + if !sc.escape { + sc.state = scanNormal + } + sc.escape = false + default: + sc.escape = false + } + case scanString: + switch c { + case '\\': + sc.escape = !sc.escape + case '"': + if !sc.escape { + sc.state = scanNormal + } + sc.escape = false + default: + sc.escape = false + } + case scanRawQuote: + if c == qr { + //nolint:govet // vendored code + c, err := sc.r.ReadByte() + if err != nil { + return sb.String(), err + } + if c == qr { + sb.WriteByte(c) + } else { + //nolint:errcheck // Goal impl says cannot error + sc.r.UnreadByte() // cannot error + sc.state = scanNormal + } } - continue } + nl = c == '\n' + } +} - // Add line to REPL history, even if not a legal expression (thus before we try to evaluate) - err = cliEditor.AddHistory(line) - if err != nil { - // NB: Not exiting if history file fails to load, just printing. - fmt.Fprintf(os.Stderr, "Failed to write REPL history with error: %v\n", err) - } +// opening returns matching opening delimiter for a given closing delimiter. +// +// Adapted from Goal's implementation. +func opening(r byte) byte { + switch r { + case ')': + return '(' + case ']': + return '[' + case '}': + return '{' + default: + return r + } +} - // Future: Consider user commands with ] +func rawREPL(cliSystem *CliSystem) { + sc := &scanner{r: bufio.NewReader(os.Stdin)} + for { + fmt.Fprint(os.Stdout, cliSystem.prompt) + line, err := sc.readLine() + line = strings.TrimRight(line, "\n\r") + if err != nil && line == "" { + return + } if matchesSystemCommand(line) { err = cliSystem.replEvalSystemCommand(line) if err != nil { @@ -418,6 +517,7 @@ func editorREPL(cliSystem *CliSystem) { } } + func replHandleLine(cliSystem *CliSystem, line string) { switch cliSystem.cliMode { case cliModeGoal: @@ -550,7 +650,7 @@ func newExitError(ctx *goal.Context, e *goal.Error) *ExitError { return ee } -// detectPrompt interrogates Goal globals ari.prompt and ari.nextprompt +// detectPrompt interrogates Goal global ari.prompt // to determine the prompt shown at the CLI REPL. func (cliSystem *CliSystem) detectPrompt() { goalContext := cliSystem.ariContext.GoalContext @@ -564,34 +664,11 @@ func (cliSystem *CliSystem) detectPrompt() { fmt.Fprintf(os.Stderr, "ari.prompt must be a string, but found %q\n", prompt) } } - - if !cliSystem.rawREPL { - nextPrompt, found := goalContext.GetGlobal("ari.nextprompt") - if found { - nextPromptS, ok := nextPrompt.BV().(goal.S) - if ok { - setNextPrompt(cliSystem, string(nextPromptS)) - } else { - fmt.Fprintf(os.Stderr, "ari.nextprompt must be a string, but found %q\n", nextPrompt) - } - } - } } -// setPrompt updates the REPL prompt, handling raw vs. rich REPL. +// setPrompt updates the REPL prompt. func setPrompt(cliSystem *CliSystem, prompt string) { - if cliSystem.rawREPL { - cliSystem.prompt = prompt - } else { - cliSystem.cliEditor.Prompt = prompt - } -} - -// setNextPrompt update the REPL prompt that appears on subsequent lines for multi-line entries. No effect for raw REPL. -func setNextPrompt(cliSystem *CliSystem, nextPrompt string) { - if !cliSystem.rawREPL { - cliSystem.cliEditor.Prompt = nextPrompt - } + cliSystem.prompt = prompt } // detectAriPrint returns a function for printing values at the REPL in goal mode. @@ -863,7 +940,6 @@ working with SQL and HTTP APIs.`, home, err := os.UserHomeDir() cobra.CheckErr(err) cfgDir := path.Join(home, ".config", "ari") - defaultHistFile := path.Join(cfgDir, "ari-history.txt") defaultCfgFile := path.Join(cfgDir, "ari-config.yaml") // Config file has processing in initConfigFn outside of viper lifecycle, so it's a separate variable. @@ -871,14 +947,10 @@ working with SQL and HTTP APIs.`, pFlags := rootCmd.PersistentFlags() - flagNameHistory := "history" flagNameDatabase := "database" - pFlags.String(flagNameHistory, defaultHistFile, "history of REPL entries") pFlags.StringP(flagNameDatabase, "d", "", "DuckDB database (default: in-memory)") - err = viper.BindPFlag(flagNameHistory, pFlags.Lookup(flagNameHistory)) - cobra.CheckErr(err) err = viper.BindPFlag(flagNameDatabase, pFlags.Lookup(flagNameDatabase)) cobra.CheckErr(err) @@ -897,9 +969,6 @@ working with SQL and HTTP APIs.`, rootCmd.Flags().BoolP("println", "p", false, "print final value of the script + newline") err = viper.BindPFlag("println", rootCmd.Flags().Lookup("println")) cobra.CheckErr(err) - rootCmd.Flags().BoolP("raw", "r", false, "raw REPL w/out history or auto-complete") - err = viper.BindPFlag("raw", rootCmd.Flags().Lookup("raw")) - cobra.CheckErr(err) rootCmd.Flags().BoolP("version", "v", false, "print version info and exit") // NB: MUST be last in this method. diff --git a/cmd/ari/tui.go b/cmd/ari/tui.go deleted file mode 100644 index ab1c872..0000000 --- a/cmd/ari/tui.go +++ /dev/null @@ -1,378 +0,0 @@ -package main - -import ( - "fmt" - - "codeberg.org/anaseto/goal" - "github.com/charmbracelet/lipgloss" -) - -type TuiStyle struct { - style lipgloss.Style -} - -// LessT implements goal.BV. -func (tuiStyle *TuiStyle) LessT(y goal.BV) bool { - // Goal falls back to ordering by type name, - // and there is no other reasonable way to order - // these HTTPClient structs. - return tuiStyle.Type() < y.Type() -} - -// Matches implements goal.BV. -func (tuiStyle *TuiStyle) Matches(_ goal.BV) bool { - // lipgloss.Style has no public fields - return false -} - -// Type implements goal.BV. -func (tuiStyle *TuiStyle) Type() string { - return "tui.TuiStyle" -} - -// Append implements goal.BV. -func (tuiStyle *TuiStyle) Append(_ *goal.Context, dst []byte, _ bool) []byte { - // Go prints nil as `` so following suit. - return append(dst, fmt.Sprintf("<%v %#v>", tuiStyle.Type(), tuiStyle.style)...) -} - -// TuiColor is a Goal value that abstracts over lipgloss color types. Currently only lipgloss.Color is supported, -// but this allows adding support for lipgloss.AdaptiveColor later without needing to change calling code. -type TuiColor struct { - color lipgloss.Color -} - -// LessT implements goal.BV. -func (tuiColor *TuiColor) LessT(y goal.BV) bool { - // Goal falls back to ordering by type name, - // and there is no other reasonable way to order - // these HTTPClient structs. - return tuiColor.Type() < y.Type() -} - -// Matches implements goal.BV. -func (tuiColor *TuiColor) Matches(_ goal.BV) bool { - // TODO This is just a string alias - return false -} - -// Type implements goal.BV. -func (tuiColor *TuiColor) Type() string { - return "tui.TuiColor" -} - -// Append implements goal.BV. -func (tuiColor *TuiColor) Append(_ *goal.Context, dst []byte, _ bool) []byte { - // Go prints nil as `` so following suit. - return append(dst, fmt.Sprintf("<%v %#v>", tuiColor.Type(), tuiColor.color)...) -} - -const ( - monadic = 1 - dyadic = 2 - triadic = 3 -) - -func vfTuiColor(_ *goal.Context, args []goal.V) goal.V { - x := args[len(args)-1] - colorS, ok := x.BV().(goal.S) - switch len(args) { - case monadic: - if !ok { - return panicType("tui.color s", "s", x) - } - color := lipgloss.Color(string(colorS)) - tuiColor := TuiColor{color} - return goal.NewV(&tuiColor) - default: - return goal.Panicf("tui.color : too many arguments (%d), expects 1 argument", len(args)) - } -} - -const quadrilateral = 4 - -// Implements tui.style monad. -// -//nolint:cyclop,funlen,gocognit,gocyclo // These dictionary translators are best kept together -func vfTuiStyle(_ *goal.Context, args []goal.V) goal.V { - x := args[len(args)-1] - styleD, okD := x.BV().(*goal.D) - switch len(args) { - case monadic: - style := lipgloss.NewStyle() - if !okD { - return panicType("tui.style d", "d", x) - } - // TODO START HERE Process dictionary entries as in augmentRequestWithOptions - styleKeys := styleD.KeyArray() - styleValues := styleD.ValueArray() - switch kas := styleKeys.(type) { - case (*goal.AS): - for i, k := range kas.Slice { - value := styleValues.At(i) - switch k { - case "Align": - switch { - case value.IsF(): - style = style.Align(lipgloss.Position(value.F())) - case value.IsI(): - style = style.Align(lipgloss.Position(value.I())) - default: - s, ok := value.BV().(goal.S) - if !ok { - return goal.Panicf(`field Align supports either floats or one of "t", "r", "b", "l", or "c", `+ - "but received a %v: %v", value.Type(), value) - } - switch string(s) { - case "t": - style = style.Align(lipgloss.Top) - case "r": - style = style.Align(lipgloss.Right) - case "b": - style = style.Align(lipgloss.Bottom) - case "l": - style = style.Align(lipgloss.Left) - case "c": - style = style.Align(lipgloss.Center) - default: - return goal.Panicf(`field Align supports either floats or one of "t", "r", "b", "l", or "c", `+ - "but received: %v", s) - } - } - case "Background": - tuiColor, ok := value.BV().(*TuiColor) - if !ok { - return goal.Panicf("field Background must be a tui.color value, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.Background(tuiColor.color) - case "Blink": - if value.IsTrue() { - style = style.Blink(true) - } - case "Bold": - if value.IsTrue() { - style = style.Bold(true) - } - case "Border": - //nolint:nestif // keep Border handling in one place - if value.IsI() { - style = style.Border(lipgloss.NormalBorder()) - } else { - switch v := value.BV().(type) { - case (goal.S): - switch v { - case "double": - style = style.Border(lipgloss.DoubleBorder()) - case "hidden": - style = style.Border(lipgloss.HiddenBorder()) - case "normal": - style = style.Border(lipgloss.NormalBorder()) - case "rounded": - style = style.Border(lipgloss.RoundedBorder()) - case "thick": - style = style.Border(lipgloss.ThickBorder()) - default: - return goal.Panicf("field Border supports one of "+ - `"double", "hidden", "normal", "rounded", or "thick" border names, but `+ - "received %v", v) - } - case (*goal.AV): - //nolint: mnd // Argument is a 5-element list of: border-type, top, right, bottom, left - if v.Len() != 5 { - return goal.Panicf("field Border expects either a 0 or 1, or "+ - `a list of where the first item is one of "double", "hidden", "normal", "rounded", or "thick" `+ - "and the remainder are 0 or 1 for top, right, bottom, and left borders. "+ - "Received a list with %d items: %v", v.Len(), v) - } - borderS := v.Slice[0] - s, ok := borderS.BV().(goal.S) - if !ok { - return goal.Panicf("field Border expects either a 0 or 1, or "+ - `a list of where the first item is one of "double", "hidden", "normal", "rounded", or "thick" `+ - "and the remainder are 0 or 1 for top, right, bottom, and left borders. "+ - "Instead of s, received a %v: %v", borderS.Type(), borderS) - } - borderSidesAB := v.Slice[1:] - bools := make([]bool, v.Len()-1) - for i, v := range borderSidesAB { - if v.IsI() { - if v.I() == 0 { - bools[i] = false - } else { - bools[i] = true - } - } else { - return goal.Panicf("field Border expects either a 0 or 1, or "+ - `a list of where the first item is one of "double", "hidden", "normal", "rounded", or "thick" `+ - "and the remainder are 0 or 1 for top, right, bottom, and left borders. "+ - "For the number in position %d, received a %v: %v", i, v.Type(), v) - } - } - switch s { - case "double": - style = style.Border(lipgloss.DoubleBorder(), bools...) - case "hidden": - style = style.Border(lipgloss.HiddenBorder(), bools...) - case "normal": - style = style.Border(lipgloss.NormalBorder(), bools...) - case "rounded": - style = style.Border(lipgloss.RoundedBorder(), bools...) - case "thick": - style = style.Border(lipgloss.ThickBorder(), bools...) - default: - return goal.Panicf("field Border supports one of "+ - `"double", "hidden", "normal", "rounded", or "thick" border names, but `+ - "received %v", s) - } - default: - return goal.Panicf("field Border expects either a 0 or 1, or "+ - `a list of where the first item is one of "double", "hidden", "normal", "rounded", or "thick" `+ - "and the remainder are 0 or 1 for top, right, bottom, and left borders. "+ - "Received a %v: %v", value.Type(), value) - } - } - case "BorderBackground": - tuiColor, ok := value.BV().(*TuiColor) - if !ok { - return goal.Panicf("field BorderBackground must be a tui.color value, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.BorderBackground(tuiColor.color) - case "BorderForeground": - tuiColor, ok := value.BV().(*TuiColor) - if !ok { - return goal.Panicf("field BorderForeground must be a tui.color value, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.BorderForeground(tuiColor.color) - - case "Faint": - if value.IsTrue() { - style = style.Faint(true) - } - case "Foreground": - tuiColor, ok := value.BV().(*TuiColor) - if !ok { - return goal.Panicf("field Foreground must be a tui.color value, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.Foreground(tuiColor.color) - case "Height": - switch { - case value.IsI(): - style = style.Height(int(value.I())) - default: - return goal.Panicf("field Height expects an integer, "+ - "but received a %v: %v", value.Type(), value) - } - case "Italic": - if value.IsTrue() { - style = style.Italic(true) - } - case "Margin": - marginArgs := make([]int, quadrilateral) - switch v := value.BV().(type) { - case *goal.AB: - if v.Len() > quadrilateral { - return goal.Panicf("field Margin must be an array of 4 integers, "+ - "but received %v: %v", v.Len(), value) - } - for i, x := range v.Slice { - marginArgs[i] = int(x) - } - case *goal.AI: - if v.Len() > quadrilateral { - return goal.Panicf("field Margin must be an array of 4 integers, "+ - "but received %v: %v", v.Len(), value) - } - for i, x := range v.Slice { - marginArgs[i] = int(x) - } - default: - return goal.Panicf("field Margin must be an array of 4 numbers, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.Margin(marginArgs...) - case "Padding": - paddingArgs := make([]int, quadrilateral) - switch v := value.BV().(type) { - case *goal.AB: - if v.Len() > quadrilateral { - return goal.Panicf("field Padding must be an array of 4 integers, "+ - "but received %v: %v", v.Len(), value) - } - for i, x := range v.Slice { - paddingArgs[i] = int(x) - } - case *goal.AI: - if v.Len() > quadrilateral { - return goal.Panicf("field Padding must be an array of 4 integers, "+ - "but received %v: %v", v.Len(), value) - } - for i, x := range v.Slice { - paddingArgs[i] = int(x) - } - default: - return goal.Panicf("field Padding must be an array of 4 numbers, "+ - "but received a %v: %v", value.Type(), value) - } - style = style.Padding(paddingArgs...) - case "Reverse": - if value.IsTrue() { - style = style.Reverse(true) - } - case "Strikethrough": - if value.IsTrue() { - style = style.Strikethrough(true) - } - case "Underline": - if value.IsTrue() { - style = style.Underline(true) - } - case "Width": - switch { - case value.IsI(): - style = style.Width(int(value.I())) - default: - return goal.Panicf("field Width expects an integer, "+ - "but received a %v: %v", value.Type(), value) - } - } - } - default: - return goal.Panicf("tui.style expects a Goal dictionary with string keys, but received a %v: %v", - kas.Type(), - kas) - } - tuiStyle := TuiStyle{style} - return goal.NewV(&tuiStyle) - default: - return goal.Panicf("tui.style : too many arguments (%d), expects 1 argument", len(args)) - } -} - -func vfTuiRender(_ *goal.Context, args []goal.V) goal.V { - x := args[len(args)-1] - tuiStyle, ok := x.BV().(*TuiStyle) - switch len(args) { - case dyadic: - if !ok { - return panicType("tui.render style s", "style", x) - } - y := args[0] - s, ok := y.BV().(goal.S) - if !ok { - return panicType("tui.render style s", "s", y) - } - rendered := tuiStyle.style.Render(string(s)) - return goal.NewS(rendered) - default: - return goal.Panicf("tui.color : too many arguments (%d), expects 1 argument", len(args)) - } -} - -// Copied from Goal's implementation, a panic value for type mismatches. -func panicType(op, sym string, x goal.V) goal.V { - return goal.Panicf("%s : bad type %q in %s", op, x.Type(), sym) -} diff --git a/context.go b/context.go index 8aa53e1..3810240 100644 --- a/context.go +++ b/context.go @@ -29,26 +29,21 @@ // // ## CLI ari // -// The CLI application at `github.com/semperos/ari/cmd/ari` provides a rich REPL with -// multi-line editing, history, and auto-complete functionality. This interface is ideal when -// first learning Goal, using Goal as an ad hoc calculator, or when building a REPL- -// based user experience. +// The CLI application at `github.com/semperos/ari/cmd/ari` provides a REPL for interactive +// programming. This interface is ideal when first learning Goal, using Goal as an ad hoc +// calculator, or when building a REPL-based user experience. // -// To drive ari's Goal REPL from an editor, you should prefer the `--raw` REPL, -// which does not have line editing, history, or auto-complete features, but which has -// better performance. You can use the Goal `ac` function with a string argument for glob matching +// You can use the Goal `ac` function with a string argument for glob matching // or a regular expression argument for loose regex matching of all bindings in your Goal // environment, optionally passing those results to `help` to view their help strings. // // Concretely, the CLI app adds the following on top of the base ari library: // -// - A rich REPL using `github.com/knz/bubbline` (built on `github.com/charmbracelet/bubbletea`) -// with dedicated Goal and SQL modes, system commands starting with `)`, multiple output +// - A REPL with dedicated Goal and SQL modes, system commands starting with `)`, multiple output // formats, basic profiling and debugging capabilities, and ability to programmatically // change the REPL prompt. // - A `help` Goal verb that allows (re)defining help strings for globals/keywords in Goal // - A dependency on `github.com/marcboeker/go-duckdb` to use DuckDB as the SQL database -// - TUI functions for basic terminal styling // - Common configuration options can be saved to a `$HOME/.config/ari/ari-config.yaml` file // for reuse, which are overridden when CLI arguments are provided. package ari diff --git a/go.mod b/go.mod index 0485ea4..d5c3e3b 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,8 @@ go 1.24 require ( codeberg.org/anaseto/goal v1.4.0 - github.com/charmbracelet/lipgloss v1.1.0 github.com/go-resty/resty/v2 v2.16.5 github.com/jarcoal/httpmock v1.4.1 - github.com/knz/bubbline v0.0.0-20230717192058-486954f9953f github.com/marcboeker/go-duckdb v1.8.5 github.com/spf13/cobra v1.10.1 github.com/spf13/viper v1.21.0 @@ -16,16 +14,7 @@ require ( require ( github.com/apache/arrow-go/v18 v18.1.0 // indirect - github.com/atotto/clipboard v0.1.4 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/benbjohnson/clock v1.3.0 // indirect - github.com/charmbracelet/bubbles v0.15.1-0.20230123181021-a6a12c4a31eb // indirect - github.com/charmbracelet/bubbletea v0.23.1 // indirect - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect - github.com/charmbracelet/x/ansi v0.8.0 // indirect - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect - github.com/charmbracelet/x/term v0.2.1 // indirect - github.com/containerd/console v1.0.3 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect @@ -34,25 +23,14 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // 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/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.16.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.uber.org/atomic v1.9.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect @@ -61,7 +39,6 @@ require ( golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/term v0.33.0 // indirect golang.org/x/text v0.28.0 // indirect golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect diff --git a/go.sum b/go.sum index 03c2551..c75d68d 100644 --- a/go.sum +++ b/go.sum @@ -6,39 +6,9 @@ github.com/apache/arrow-go/v18 v18.1.0 h1:agLwJUiVuwXZdwPYVrlITfx7bndULJ/dggbnLF github.com/apache/arrow-go/v18 v18.1.0/go.mod h1:tigU/sIgKNXaesf5d7Y95jBBKS5KsxTqYBKXFsvKzo0= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= -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 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= -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/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/charmbracelet/bubbles v0.13.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc= -github.com/charmbracelet/bubbles v0.15.1-0.20230123181021-a6a12c4a31eb h1:OYmHuDqyuzWwiurw7eeYJ2482BENoX3hScpzamwF5K8= -github.com/charmbracelet/bubbles v0.15.1-0.20230123181021-a6a12c4a31eb/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= -github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= -github.com/charmbracelet/bubbletea v0.22.2-0.20220830200705-989d49f3e69f/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0= -github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck= -github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= -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/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= -github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= -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.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= -github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= -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/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= -github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -70,77 +40,29 @@ github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IX github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= -github.com/knz/bubbline v0.0.0-20230717192058-486954f9953f h1:Jjq9RwAsihYCm5fudPBj5CwsLDNd6r1ee3M2mfKFYdI= -github.com/knz/bubbline v0.0.0-20230717192058-486954f9953f/go.mod h1:ucXvyrucVy4jp/4afdKWNW1TVO73GMI72VNINzyT678= -github.com/knz/catwalk v0.1.4 h1:GgCxHbPp+nzyZBJcNL/CJd1aba4ACoeuI1lnsshAPkY= -github.com/knz/catwalk v0.1.4/go.mod h1:Q+Yj4ny4AXgrOOyWyDGY/HJzmbGH8MFnsUqvCAiUT5s= -github.com/knz/lipgloss-convert v0.1.0 h1:qUPUt6r8mqvi9DIV3nBPu3kEmFyHrZtXzv0BlPBPLNQ= -github.com/knz/lipgloss-convert v0.1.0/go.mod h1:S14GmtoiW/VAHqB7xEzuZOt0/G6GQ2dfjJN0fHpm30Q= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/marcboeker/go-duckdb v1.8.5 h1:tkYp+TANippy0DaIOP5OEfBEwbUINqiFqgwMQ44jME0= github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -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.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/maxatome/go-testdeep v1.14.0 h1:rRlLv1+kI8eOI3OaBXZwb3O7xY3exRzdW5QyX48g9wI= github.com/maxatome/go-testdeep v1.14.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -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.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -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/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= -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/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y= -github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -160,8 +82,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -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= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= @@ -180,24 +100,12 @@ golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= @@ -205,9 +113,7 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6f gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/goal.go b/goal.go index 16da5e9..a7b7f07 100644 --- a/goal.go +++ b/goal.go @@ -471,32 +471,6 @@ func GoalKeywordsHelp() map[string]string { }, "\n") sqlopen := `sql.open s Open DuckDB database with data source name s` sqlq := `sql.q s Run SQL query, results as table.` - tuiColor := strings.Join([]string{ - `tui.color s Color string accepted by lipgloss.Color`, - }, "\n") - tuiRender := strings.Join([]string{ - `tui.render style s Return s marked up according to style (see tui.style)`, - }, "\n") - tuiStyle := strings.Join([]string{ - `tui.style d Return a style based on entries in d: - - Align (floats or one of "t", "r", "b", "l", or "c") - - Background (tui.color) - - Blink (bool) - - Bold (bool) - - Border (list of name + top, right, bottom, left bools) - - BorderBackground (tui.color) - - BorderForeground (tui.color) - - Faint (bool) - - Foreground (tui.color) - - Height (int) - - Italic (bool) - - Margin (top, right, bottom, left ints) - - Padding (top, right, bottom, left ints) - - Reverse (bool) - - Strikethrough (bool) - - Underline (bool) - - Width (int)`, - }, "\n") vendoredGoalHelp := help.Map() ariGoalHelp := map[string]string{ "http.client": httpclient, @@ -509,9 +483,6 @@ func GoalKeywordsHelp() map[string]string { "http.put": helpForHTTPFn("put"), "sql.open": sqlopen, "sql.q": sqlq, - "tui.color": tuiColor, - "tui.render": tuiRender, - "tui.style": tuiStyle, } for k, v := range ariGoalHelp { vendoredGoalHelp[k] = v