From 1dccc979c7e2d5c7d5e6de20b76cfbbb62d11ce4 Mon Sep 17 00:00:00 2001 From: Raphael Amorim Date: Mon, 16 Jun 2025 14:25:18 +0200 Subject: [PATCH 1/4] perf: drop reflection usage and use string builder --- internal/llm/tools/diagnostics.go | 32 +++++++++---------- internal/llm/tools/grep.go | 18 +++++------ internal/llm/tools/ls.go | 2 +- internal/tui/components/chat/editor/keys.go | 11 +++++-- internal/tui/components/completions/keys.go | 13 ++++++-- internal/tui/components/core/layout/layout.go | 15 ++------- internal/tui/components/core/list/keys.go | 19 +++++++++-- internal/tui/components/core/status/keys.go | 13 ++++++-- .../tui/components/dialogs/commands/keys.go | 25 +++++++++++++-- .../tui/components/dialogs/compact/keys.go | 14 ++++++-- .../tui/components/dialogs/filepicker/keys.go | 15 +++++++-- internal/tui/components/dialogs/init/keys.go | 14 ++++++-- internal/tui/components/dialogs/keys.go | 10 ++++-- .../tui/components/dialogs/models/keys.go | 13 ++++++-- .../components/dialogs/permissions/keys.go | 16 ++++++++-- internal/tui/components/dialogs/quit/keys.go | 15 +++++++-- .../tui/components/dialogs/sessions/keys.go | 13 ++++++-- internal/tui/keys.go | 14 ++++++-- internal/tui/page/chat/keys.go | 13 ++++++-- internal/tui/page/logs/keys.go | 10 ++++-- 20 files changed, 224 insertions(+), 71 deletions(-) diff --git a/internal/llm/tools/diagnostics.go b/internal/llm/tools/diagnostics.go index 89ad484c134a30fa4b18526e64a25e37cc0912eb..e48132414ad338635ada6294134e3d7f2d938c7d 100644 --- a/internal/llm/tools/diagnostics.go +++ b/internal/llm/tools/diagnostics.go @@ -245,28 +245,28 @@ func getDiagnostics(filePath string, lsps map[string]*lsp.Client) string { return projectDiagnostics[i] < projectDiagnostics[j] }) - output := "" + var output strings.Builder if len(fileDiagnostics) > 0 { - output += "\n\n" + output.WriteString("\n\n") if len(fileDiagnostics) > 10 { - output += strings.Join(fileDiagnostics[:10], "\n") - output += fmt.Sprintf("\n... and %d more diagnostics", len(fileDiagnostics)-10) + output.WriteString(strings.Join(fileDiagnostics[:10], "\n")) + fmt.Fprintf(&output, "\n... and %d more diagnostics", len(fileDiagnostics)-10) } else { - output += strings.Join(fileDiagnostics, "\n") + output.WriteString(strings.Join(fileDiagnostics, "\n")) } - output += "\n\n" + output.WriteString("\n\n") } if len(projectDiagnostics) > 0 { - output += "\n\n" + output.WriteString("\n\n") if len(projectDiagnostics) > 10 { - output += strings.Join(projectDiagnostics[:10], "\n") - output += fmt.Sprintf("\n... and %d more diagnostics", len(projectDiagnostics)-10) + output.WriteString(strings.Join(projectDiagnostics[:10], "\n")) + fmt.Fprintf(&output, "\n... and %d more diagnostics", len(projectDiagnostics)-10) } else { - output += strings.Join(projectDiagnostics, "\n") + output.WriteString(strings.Join(projectDiagnostics, "\n")) } - output += "\n\n" + output.WriteString("\n\n") } if len(fileDiagnostics) > 0 || len(projectDiagnostics) > 0 { @@ -275,13 +275,13 @@ func getDiagnostics(filePath string, lsps map[string]*lsp.Client) string { projectErrors := countSeverity(projectDiagnostics, "Error") projectWarnings := countSeverity(projectDiagnostics, "Warn") - output += "\n\n" - output += fmt.Sprintf("Current file: %d errors, %d warnings\n", fileErrors, fileWarnings) - output += fmt.Sprintf("Project: %d errors, %d warnings\n", projectErrors, projectWarnings) - output += "\n" + output.WriteString("\n\n") + fmt.Fprintf(&output, "Current file: %d errors, %d warnings\n", fileErrors, fileWarnings) + fmt.Fprintf(&output, "Project: %d errors, %d warnings\n", projectErrors, projectWarnings) + output.WriteString("\n") } - return output + return output.String() } func countSeverity(diagnostics []string, severity string) int { diff --git a/internal/llm/tools/grep.go b/internal/llm/tools/grep.go index e043a71e0bafc77050bf444a02f50c2462018e8d..e6992a4f8c23dc440898298d8f0e5d880b2fdc53 100644 --- a/internal/llm/tools/grep.go +++ b/internal/llm/tools/grep.go @@ -198,35 +198,35 @@ func (g *grepTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) return ToolResponse{}, fmt.Errorf("error searching files: %w", err) } - var output string + var output strings.Builder if len(matches) == 0 { - output = "No files found" + output.WriteString("No files found") } else { - output = fmt.Sprintf("Found %d matches\n", len(matches)) + fmt.Fprintf(&output, "Found %d matches\n", len(matches)) currentFile := "" for _, match := range matches { if currentFile != match.path { if currentFile != "" { - output += "\n" + output.WriteString("\n") } currentFile = match.path - output += fmt.Sprintf("%s:\n", match.path) + fmt.Fprintf(&output, "%s:\n", match.path) } if match.lineNum > 0 { - output += fmt.Sprintf(" Line %d: %s\n", match.lineNum, match.lineText) + fmt.Fprintf(&output, " Line %d: %s\n", match.lineNum, match.lineText) } else { - output += fmt.Sprintf(" %s\n", match.path) + fmt.Fprintf(&output, " %s\n", match.path) } } if truncated { - output += "\n(Results are truncated. Consider using a more specific path or pattern.)" + output.WriteString("\n(Results are truncated. Consider using a more specific path or pattern.)") } } return WithResponseMetadata( - NewTextResponse(output), + NewTextResponse(output.String()), GrepResponseMetadata{ NumberOfMatches: len(matches), Truncated: truncated, diff --git a/internal/llm/tools/ls.go b/internal/llm/tools/ls.go index 81539abe8db1ce2ccde5b8261d34474ab77ea076..a0426b1393f42bc4729db558641e0c178a680d27 100644 --- a/internal/llm/tools/ls.go +++ b/internal/llm/tools/ls.go @@ -209,7 +209,7 @@ func printNode(builder *strings.Builder, node *TreeNode, level int) { nodeName := node.Name if node.Type == "directory" { - nodeName += string(filepath.Separator) + nodeName = nodeName + string(filepath.Separator) } fmt.Fprintf(builder, "%s- %s\n", indent, nodeName) diff --git a/internal/tui/components/chat/editor/keys.go b/internal/tui/components/chat/editor/keys.go index 51c521244ec8e060333ff3e89328f73252ce5369..0f85249645b976e861a6e9bdff61b7fbebcdbd50 100644 --- a/internal/tui/components/chat/editor/keys.go +++ b/internal/tui/components/chat/editor/keys.go @@ -2,7 +2,6 @@ package editor import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type EditorKeyMap struct { @@ -23,10 +22,18 @@ func DefaultEditorKeyMap() EditorKeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k EditorKeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Send, + k.OpenEditor, + } +} + // FullHelp implements help.KeyMap. func (k EditorKeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/completions/keys.go b/internal/tui/components/completions/keys.go index c2f7a10d77b12439f18d6bf110c11debaa8b4ba7..fee3a0e574ab926cb4e80d02c0d9d19c0e614edd 100644 --- a/internal/tui/components/completions/keys.go +++ b/internal/tui/components/completions/keys.go @@ -2,7 +2,6 @@ package completions import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -33,10 +32,20 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Down, + k.Up, + k.Select, + k.Cancel, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/core/layout/layout.go b/internal/tui/components/core/layout/layout.go index ae43c51bf685134f859bf99ac9cef3d6328cb1e1..a0d0b9c0326de3d6a263eb1707f99b8f61a72b95 100644 --- a/internal/tui/components/core/layout/layout.go +++ b/internal/tui/components/core/layout/layout.go @@ -1,8 +1,6 @@ package layout import ( - "reflect" - "github.com/charmbracelet/bubbles/v2/help" "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" @@ -27,14 +25,7 @@ type Positionable interface { SetPosition(x, y int) tea.Cmd } -func KeyMapToSlice(t any) (bindings []key.Binding) { - typ := reflect.TypeOf(t) - if typ.Kind() != reflect.Struct { - return nil - } - for i := range typ.NumField() { - v := reflect.ValueOf(t).Field(i) - bindings = append(bindings, v.Interface().(key.Binding)) - } - return +// KeyMapProvider defines an interface for types that can provide their key bindings as a slice +type KeyMapProvider interface { + KeyBindings() []key.Binding } diff --git a/internal/tui/components/core/list/keys.go b/internal/tui/components/core/list/keys.go index 92201cebdcc503ea621c75e851381c8ffad3a6ad..9cc628ab912d43aadde09a863d389cdb5dc618ba 100644 --- a/internal/tui/components/core/list/keys.go +++ b/internal/tui/components/core/list/keys.go @@ -2,7 +2,6 @@ package list import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -53,10 +52,26 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Down, + k.Up, + k.NDown, + k.NUp, + k.DownOneItem, + k.UpOneItem, + k.HalfPageDown, + k.HalfPageUp, + k.Home, + k.End, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/core/status/keys.go b/internal/tui/components/core/status/keys.go index b16d035bfd0154ff0e8a82af87a67e2d2bd58053..d33abe2d2102ef88bfba6ce8c2d89ea66bd95282 100644 --- a/internal/tui/components/core/status/keys.go +++ b/internal/tui/components/core/status/keys.go @@ -2,7 +2,6 @@ package status import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -33,10 +32,20 @@ func DefaultKeyMap(tabHelp string) KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Tab, + k.Commands, + k.Sessions, + k.Help, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/commands/keys.go b/internal/tui/components/dialogs/commands/keys.go index 08420f56fd2b57aeaa407a4908bba2e83fc0e569..9685216817c02cdfaab682f94e0f89aa64af365f 100644 --- a/internal/tui/components/dialogs/commands/keys.go +++ b/internal/tui/components/dialogs/commands/keys.go @@ -2,7 +2,6 @@ package commands import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type CommandsDialogKeyMap struct { @@ -38,10 +37,21 @@ func DefaultCommandsDialogKeyMap() CommandsDialogKeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k CommandsDialogKeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Select, + k.Next, + k.Previous, + k.Tab, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k CommandsDialogKeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) @@ -86,10 +96,19 @@ func DefaultArgumentsDialogKeyMap() ArgumentsDialogKeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k ArgumentsDialogKeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Confirm, + k.Next, + k.Previous, + } +} + // FullHelp implements help.KeyMap. func (k ArgumentsDialogKeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/compact/keys.go b/internal/tui/components/dialogs/compact/keys.go index 491b582388593ec33ef2584e503aa3677679c59d..c3dd98e13035085b7d46e7a2e94450b25a7f0d59 100644 --- a/internal/tui/components/dialogs/compact/keys.go +++ b/internal/tui/components/dialogs/compact/keys.go @@ -2,7 +2,6 @@ package compact import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) // KeyMap defines the key bindings for the compact dialog. @@ -40,10 +39,21 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.ChangeSelection, + k.Select, + k.Y, + k.N, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/filepicker/keys.go b/internal/tui/components/dialogs/filepicker/keys.go index cc95915c675058e3728d2bd5d1228b638204b093..9f3b706e3cf677b66cbc3136a7b98a466470d949 100644 --- a/internal/tui/components/dialogs/filepicker/keys.go +++ b/internal/tui/components/dialogs/filepicker/keys.go @@ -2,7 +2,6 @@ package filepicker import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) // KeyMap defines keyboard bindings for dialog management. @@ -45,10 +44,22 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Select, + k.Down, + k.Up, + k.Forward, + k.Backward, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/init/keys.go b/internal/tui/components/dialogs/init/keys.go index 163b4869fb477ae34545ef169725b551cd05c6fd..afd82d45ea8b47630c2d5ed1450419ae8d4b4c19 100644 --- a/internal/tui/components/dialogs/init/keys.go +++ b/internal/tui/components/dialogs/init/keys.go @@ -2,7 +2,6 @@ package init import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -38,10 +37,21 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.ChangeSelection, + k.Select, + k.Y, + k.N, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/keys.go b/internal/tui/components/dialogs/keys.go index 027ed6e3a8ad86d2587061085623117a44016d01..c382b7e09e15de04efb5b2520bc490ef9d57b985 100644 --- a/internal/tui/components/dialogs/keys.go +++ b/internal/tui/components/dialogs/keys.go @@ -2,7 +2,6 @@ package dialogs import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) // KeyMap defines keyboard bindings for dialog management. @@ -18,10 +17,17 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/models/keys.go b/internal/tui/components/dialogs/models/keys.go index f17fdb95e366275660287a17a0df2ffc8e375355..f9c3c549c30c6d95282e88818c247ec80a2f0e4c 100644 --- a/internal/tui/components/dialogs/models/keys.go +++ b/internal/tui/components/dialogs/models/keys.go @@ -2,7 +2,6 @@ package models import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -33,10 +32,20 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Select, + k.Next, + k.Previous, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/permissions/keys.go b/internal/tui/components/dialogs/permissions/keys.go index de4e595ac273e31be661cccec9d8053bf3c7a379..d626eecf9a819cfb209823f922f96dfb58ea3ca4 100644 --- a/internal/tui/components/dialogs/permissions/keys.go +++ b/internal/tui/components/dialogs/permissions/keys.go @@ -2,7 +2,6 @@ package permissions import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -48,10 +47,23 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Left, + k.Right, + k.Tab, + k.Select, + k.Allow, + k.AllowSession, + k.Deny, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/quit/keys.go b/internal/tui/components/dialogs/quit/keys.go index 20421fb1c2709f515b31b57b2e984e76f02eb071..3268749b20c703ae1faf7640e253ce557f051c65 100644 --- a/internal/tui/components/dialogs/quit/keys.go +++ b/internal/tui/components/dialogs/quit/keys.go @@ -2,7 +2,6 @@ package quit import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) // KeyMap defines the keyboard bindings for the quit dialog. @@ -44,10 +43,22 @@ func DefaultKeymap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.LeftRight, + k.EnterSpace, + k.Yes, + k.No, + k.Tab, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/components/dialogs/sessions/keys.go b/internal/tui/components/dialogs/sessions/keys.go index 1dfdf43f9e841f45cc4ec6d854117bad63a738ba..a3ca4b31f0c04c491fa7990f7e69ac546f608a7d 100644 --- a/internal/tui/components/dialogs/sessions/keys.go +++ b/internal/tui/components/dialogs/sessions/keys.go @@ -2,7 +2,6 @@ package sessions import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -33,10 +32,20 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Select, + k.Next, + k.Previous, + k.Close, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/keys.go b/internal/tui/keys.go index 2c1d0d038b220d3bc97e78b105caea15f7699149..e36e264f36ca720f717874632e2607006140fbb8 100644 --- a/internal/tui/keys.go +++ b/internal/tui/keys.go @@ -2,7 +2,6 @@ package tui import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -42,7 +41,7 @@ func DefaultKeyMap() KeyMap { // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) @@ -50,6 +49,17 @@ func (k KeyMap) FullHelp() [][]key.Binding { return m } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Logs, + k.Quit, + k.Help, + k.Commands, + k.Sessions, + } +} + // ShortHelp implements help.KeyMap. func (k KeyMap) ShortHelp() []key.Binding { return []key.Binding{} diff --git a/internal/tui/page/chat/keys.go b/internal/tui/page/chat/keys.go index 9858a9d5821704334cac75dcdbb1d4ca228234bb..61e8023145262fed2c0a6455dd11ba2b228405d7 100644 --- a/internal/tui/page/chat/keys.go +++ b/internal/tui/page/chat/keys.go @@ -2,7 +2,6 @@ package chat import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -33,10 +32,20 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.NewSession, + k.FilePicker, + k.Cancel, + k.Tab, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) diff --git a/internal/tui/page/logs/keys.go b/internal/tui/page/logs/keys.go index 7fc25bf4d399bd30946406bb9a7c7bc5b2747fd1..3c612b949183b4180494bdbb8224dd8eedbbb156 100644 --- a/internal/tui/page/logs/keys.go +++ b/internal/tui/page/logs/keys.go @@ -2,7 +2,6 @@ package logs import ( "github.com/charmbracelet/bubbles/v2/key" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" ) type KeyMap struct { @@ -18,10 +17,17 @@ func DefaultKeyMap() KeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Back, + } +} + // FullHelp implements help.KeyMap. func (k KeyMap) FullHelp() [][]key.Binding { m := [][]key.Binding{} - slice := layout.KeyMapToSlice(k) + slice := k.KeyBindings() for i := 0; i < len(slice); i += 4 { end := min(i+4, len(slice)) m = append(m, slice[i:end]) From 1e4459876b6136746b9f3efcdb6149b16d8d5141 Mon Sep 17 00:00:00 2001 From: Raphael Amorim Date: Mon, 16 Jun 2025 14:31:00 +0200 Subject: [PATCH 2/4] fix: update code with gofmt --- internal/llm/tools/grep_test.go | 18 +++++++++--------- internal/tui/components/chat/chat.go | 2 +- .../tui/components/dialogs/commands/item.go | 2 +- internal/tui/page/chat/chat.go | 2 +- internal/tui/page/logs/logs.go | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/llm/tools/grep_test.go b/internal/llm/tools/grep_test.go index de4e6afb225075df34e14d54fb1e5db76955625b..22680fd0980213ea9943959367d3d987620695df 100644 --- a/internal/llm/tools/grep_test.go +++ b/internal/llm/tools/grep_test.go @@ -7,24 +7,24 @@ import ( func TestRegexCache(t *testing.T) { cache := newRegexCache() - + // Test basic caching pattern := "test.*pattern" regex1, err := cache.get(pattern) if err != nil { t.Fatalf("Failed to compile regex: %v", err) } - + regex2, err := cache.get(pattern) if err != nil { t.Fatalf("Failed to get cached regex: %v", err) } - + // Should be the same instance (cached) if regex1 != regex2 { t.Error("Expected cached regex to be the same instance") } - + // Test that it actually works if !regex1.MatchString("test123pattern") { t.Error("Regex should match test string") @@ -34,13 +34,13 @@ func TestRegexCache(t *testing.T) { func TestGlobToRegexCaching(t *testing.T) { // Test that globToRegex uses pre-compiled regex pattern1 := globToRegex("*.{js,ts}") - + // Should not panic and should work correctly regex1, err := regexp.Compile(pattern1) if err != nil { t.Fatalf("Failed to compile glob regex: %v", err) } - + if !regex1.MatchString("test.js") { t.Error("Glob regex should match .js files") } @@ -56,7 +56,7 @@ func TestGlobToRegexCaching(t *testing.T) { func BenchmarkRegexCacheVsCompile(b *testing.B) { cache := newRegexCache() pattern := "test.*pattern.*[0-9]+" - + b.Run("WithCache", func(b *testing.B) { for b.Loop() { _, err := cache.get(pattern) @@ -65,7 +65,7 @@ func BenchmarkRegexCacheVsCompile(b *testing.B) { } } }) - + b.Run("WithoutCache", func(b *testing.B) { for b.Loop() { _, err := regexp.Compile(pattern) @@ -74,4 +74,4 @@ func BenchmarkRegexCacheVsCompile(b *testing.B) { } } }) -} \ No newline at end of file +} diff --git a/internal/tui/components/chat/chat.go b/internal/tui/components/chat/chat.go index bd449123a886d5c88a5834e2dbe73a855451babd..9aa7ef1037b2b99f23e15ce903a4f4b264fd35c1 100644 --- a/internal/tui/components/chat/chat.go +++ b/internal/tui/components/chat/chat.go @@ -11,8 +11,8 @@ import ( "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/components/chat/messages" - "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" ) diff --git a/internal/tui/components/dialogs/commands/item.go b/internal/tui/components/dialogs/commands/item.go index 09c97e16ed930c21e81246573b453b061d12d78e..a89a884472cff75a0051d89b637ae4f55feba527 100644 --- a/internal/tui/components/dialogs/commands/item.go +++ b/internal/tui/components/dialogs/commands/item.go @@ -3,8 +3,8 @@ package commands import ( tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/tui/components/core" - "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/x/ansi" diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index ff769f9fee40545e003167d91ff29fcbee83b906..e02996b1ff4ba0e97ddda05d469ec9f8fca4ab5c 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -13,8 +13,8 @@ import ( "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/chat/editor" "github.com/charmbracelet/crush/internal/tui/components/chat/sidebar" - "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands" "github.com/charmbracelet/crush/internal/tui/page" "github.com/charmbracelet/crush/internal/tui/util" ) diff --git a/internal/tui/page/logs/logs.go b/internal/tui/page/logs/logs.go index 39f7137178bb9fe0a58d798ac32434402c0d133c..228875a196434d0f8dfb8cfe15783c4d2b1fd618 100644 --- a/internal/tui/page/logs/logs.go +++ b/internal/tui/page/logs/logs.go @@ -4,8 +4,8 @@ import ( "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/tui/components/core" - logsComponents "github.com/charmbracelet/crush/internal/tui/components/logs" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + logsComponents "github.com/charmbracelet/crush/internal/tui/components/logs" "github.com/charmbracelet/crush/internal/tui/page" "github.com/charmbracelet/crush/internal/tui/page/chat" "github.com/charmbracelet/crush/internal/tui/styles" From c31760be64e67dc946b09750219d3ae711402ab2 Mon Sep 17 00:00:00 2001 From: Raphael Amorim Date: Mon, 16 Jun 2025 15:02:53 +0200 Subject: [PATCH 3/4] feat: update implementation to main --- internal/tui/components/chat/chat.go | 2 +- internal/tui/components/chat/editor/editor.go | 9 +-------- internal/tui/components/chat/editor/keys.go | 9 +++++++++ internal/tui/components/core/layout/layout.go | 2 -- internal/tui/components/core/list/keys.go | 16 ++++++++++++++++ 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/internal/tui/components/chat/chat.go b/internal/tui/components/chat/chat.go index d0c83857e5ea95ee582371d14c9ea1724669c60d..332d0ff5070290377342e75b0af6c2f4a59d70e5 100644 --- a/internal/tui/components/chat/chat.go +++ b/internal/tui/components/chat/chat.go @@ -500,6 +500,6 @@ func (m *messageListCmp) IsFocused() bool { } func (m *messageListCmp) Bindings() []key.Binding { - bindings := layout.KeyMapToSlice(m.defaultListKeyMap) + bindings := m.defaultListKeyMap.KeyBindings() return bindings } diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 2f7e02b676512a226f8da5f25329a937c13c64dc..97493a00508e765baedb35c7df2239fb24b3075a 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -18,7 +18,6 @@ import ( "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/completions" - "github.com/charmbracelet/crush/internal/tui/components/core/layout" "github.com/charmbracelet/crush/internal/tui/components/dialogs" "github.com/charmbracelet/crush/internal/tui/components/dialogs/filepicker" "github.com/charmbracelet/crush/internal/tui/components/dialogs/quit" @@ -49,12 +48,6 @@ type editorCmp struct { isCompletionsOpen bool } -type DeleteAttachmentKeyMaps struct { - AttachmentDeleteMode key.Binding - Escape key.Binding - DeleteAllAttachments key.Binding -} - var DeleteKeyMaps = DeleteAttachmentKeyMaps{ AttachmentDeleteMode: key.NewBinding( key.WithKeys("ctrl+r"), @@ -372,7 +365,7 @@ func (c *editorCmp) IsFocused() bool { } func (c *editorCmp) Bindings() []key.Binding { - return layout.KeyMapToSlice(c.keyMap) + return c.keyMap.KeyBindings() } func NewEditorCmp(app *app.App) util.Model { diff --git a/internal/tui/components/chat/editor/keys.go b/internal/tui/components/chat/editor/keys.go index 07a8597db73c997b32b20ee1094a7b8ed12987d4..f7521e1ccaa74a4679a89f2c06c61ab30d204016 100644 --- a/internal/tui/components/chat/editor/keys.go +++ b/internal/tui/components/chat/editor/keys.go @@ -27,6 +27,15 @@ func DefaultEditorKeyMap() EditorKeyMap { } } +// KeyBindings implements layout.KeyMapProvider +func (k EditorKeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.AddFile, + k.SendMessage, + k.OpenEditor, + } +} + type DeleteAttachmentKeyMaps struct { AttachmentDeleteMode key.Binding Escape key.Binding diff --git a/internal/tui/components/core/layout/layout.go b/internal/tui/components/core/layout/layout.go index ba691e5df6ad84c5b0bc0f32cbad7d5611268b25..30bc97391aefc2437093b94786504b2b98606e6e 100644 --- a/internal/tui/components/core/layout/layout.go +++ b/internal/tui/components/core/layout/layout.go @@ -1,8 +1,6 @@ package layout import ( - "reflect" - "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" ) diff --git a/internal/tui/components/core/list/keys.go b/internal/tui/components/core/list/keys.go index da7c1661a40cb1f6284b0da1fd32c53a0c004d25..4b4e8f9691f87c02db6226ae87c5931db27509b4 100644 --- a/internal/tui/components/core/list/keys.go +++ b/internal/tui/components/core/list/keys.go @@ -50,4 +50,20 @@ func DefaultKeyMap() KeyMap { key.WithKeys("shift+g", "end"), ), } +} + +// KeyBindings implements layout.KeyMapProvider +func (k KeyMap) KeyBindings() []key.Binding { + return []key.Binding{ + k.Down, + k.Up, + k.NDown, + k.NUp, + k.DownOneItem, + k.UpOneItem, + k.HalfPageDown, + k.HalfPageUp, + k.Home, + k.End, + } } \ No newline at end of file From 032e738f630a6f7597b7b7cd3cb4a2ff671fc1d3 Mon Sep 17 00:00:00 2001 From: Raphael Amorim Date: Mon, 16 Jun 2025 15:05:37 +0200 Subject: [PATCH 4/4] fix: format files --- internal/tui/components/chat/editor/keys.go | 2 +- internal/tui/components/chat/sidebar/sidebar.go | 2 +- internal/tui/components/completions/item.go | 2 +- internal/tui/components/core/layout/layout.go | 2 +- internal/tui/components/core/list/keys.go | 2 +- internal/tui/keys.go | 2 +- internal/tui/page/chat/keys.go | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/tui/components/chat/editor/keys.go b/internal/tui/components/chat/editor/keys.go index f7521e1ccaa74a4679a89f2c06c61ab30d204016..c64a92d526a1a81e558909fe5500b2bf1d4e3990 100644 --- a/internal/tui/components/chat/editor/keys.go +++ b/internal/tui/components/chat/editor/keys.go @@ -56,4 +56,4 @@ var AttachmentsKeyMaps = DeleteAttachmentKeyMaps{ key.WithKeys("r"), key.WithHelp("ctrl+r+r", "delete all attachments"), ), -} \ No newline at end of file +} diff --git a/internal/tui/components/chat/sidebar/sidebar.go b/internal/tui/components/chat/sidebar/sidebar.go index ad0531e2e16c673dad7003cba5a2416d4506e7b3..2e86f6a9750f858a10cbdba02cfcbaf439a1cdfa 100644 --- a/internal/tui/components/chat/sidebar/sidebar.go +++ b/internal/tui/components/chat/sidebar/sidebar.go @@ -10,8 +10,8 @@ import ( "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/core" - "github.com/charmbracelet/crush/internal/tui/components/logo" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/logo" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/crush/internal/version" diff --git a/internal/tui/components/completions/item.go b/internal/tui/components/completions/item.go index e26ef7f92dce616a25236379b17d9a8f18fc4c12..12e14b48edffddb2043c03da61c956bdac2ab242 100644 --- a/internal/tui/components/completions/item.go +++ b/internal/tui/components/completions/item.go @@ -4,8 +4,8 @@ import ( "image/color" tea "github.com/charmbracelet/bubbletea/v2" - "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/components/core/layout" + "github.com/charmbracelet/crush/internal/tui/components/core/list" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" diff --git a/internal/tui/components/core/layout/layout.go b/internal/tui/components/core/layout/layout.go index 30bc97391aefc2437093b94786504b2b98606e6e..6af2d5fa87776716a2d96446cd060adccbe83654 100644 --- a/internal/tui/components/core/layout/layout.go +++ b/internal/tui/components/core/layout/layout.go @@ -27,4 +27,4 @@ type Positionable interface { // KeyMapProvider defines an interface for types that can provide their key bindings as a slice type KeyMapProvider interface { KeyBindings() []key.Binding -} \ No newline at end of file +} diff --git a/internal/tui/components/core/list/keys.go b/internal/tui/components/core/list/keys.go index 4b4e8f9691f87c02db6226ae87c5931db27509b4..4ad2a9e27807063609215f1f6c834872ceff2aac 100644 --- a/internal/tui/components/core/list/keys.go +++ b/internal/tui/components/core/list/keys.go @@ -66,4 +66,4 @@ func (k KeyMap) KeyBindings() []key.Binding { k.Home, k.End, } -} \ No newline at end of file +} diff --git a/internal/tui/keys.go b/internal/tui/keys.go index 34f40e88c9a083e528496105945ab550b5bb10f2..dda3ad4dba02192626adf74540d2c62aad44a5a1 100644 --- a/internal/tui/keys.go +++ b/internal/tui/keys.go @@ -97,4 +97,4 @@ func (k KeyMap) ShortHelp() []key.Binding { k.Help, } return k.prependEscAndTab(bindings) -} \ No newline at end of file +} diff --git a/internal/tui/page/chat/keys.go b/internal/tui/page/chat/keys.go index 899ff1d77f25373bfc5421b9652926f0eb2731bf..87167ee2c47162bb9c7c4111d100bd80283e5bbe 100644 --- a/internal/tui/page/chat/keys.go +++ b/internal/tui/page/chat/keys.go @@ -30,4 +30,4 @@ func DefaultKeyMap() KeyMap { key.WithHelp("tab", "change focus"), ), } -} \ No newline at end of file +}