From 3c6984445e85d5c1c86b1a311fd9e37402dcc489 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Tue, 16 Dec 2025 09:33:18 +0100 Subject: [PATCH] chore: some small ux improvements --- .../components/dialogs/commands/commands.go | 5 ++-- .../tui/components/dialogs/lazygit/lazygit.go | 1 + .../dialogs/termdialog/termdialog.go | 30 +++++++++++++++---- internal/tui/tui.go | 5 ++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 0b7bd6cd342600bf6611079a7d3cbc091a3cfb19..12abda44ebcafbb1f9c85a0ff6412532d14bd591 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "os/exec" "slices" "strings" @@ -18,7 +19,6 @@ import ( "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/pubsub" - "github.com/charmbracelet/crush/internal/shell" "github.com/charmbracelet/crush/internal/tui/components/chat" "github.com/charmbracelet/crush/internal/tui/components/core" "github.com/charmbracelet/crush/internal/tui/components/dialogs" @@ -440,8 +440,7 @@ func (c *commandDialogCmp) defaultCommands() []Command { } // Add lazygit command if lazygit is installed. - sh := shell.NewShell(nil) - if _, _, err := sh.Exec(c.ctx, "which lazygit"); err == nil { + if _, err := exec.LookPath("lazygit"); err == nil { commands = append(commands, Command{ ID: "lazygit", Title: "Open Lazygit", diff --git a/internal/tui/components/dialogs/lazygit/lazygit.go b/internal/tui/components/dialogs/lazygit/lazygit.go index f2a9257508f6db6ea7f76cf7cba16b1d8824985e..ce88aed8029eedf0810810ed12f2098e73f18560 100644 --- a/internal/tui/components/dialogs/lazygit/lazygit.go +++ b/internal/tui/components/dialogs/lazygit/lazygit.go @@ -37,6 +37,7 @@ func NewDialog(ctx context.Context, workingDir string) *termdialog.Dialog { Title: "Lazygit", LoadingMsg: "Starting lazygit...", Term: terminal.New(terminal.Config{Context: ctx, Cmd: cmd}), + QuitHint: "q to close", OnClose: func() { if themeConfig != "" { if err := os.Remove(themeConfig); err != nil { diff --git a/internal/tui/components/dialogs/termdialog/termdialog.go b/internal/tui/components/dialogs/termdialog/termdialog.go index 88f3091e1f5b4c083016107b19f22a35d013db07..83e5eb1232af7bb47f848c299f05e6d3710e24f4 100644 --- a/internal/tui/components/dialogs/termdialog/termdialog.go +++ b/internal/tui/components/dialogs/termdialog/termdialog.go @@ -17,8 +17,11 @@ const ( // headerHeight is the height of the dialog header (title + padding). headerHeight = 2 // fullscreenWidthBreakpoint is the width below which the dialog goes - // fullscreen. Matches CompactModeWidthBreakpoint in chat.go. - fullscreenWidthBreakpoint = 120 + // fullscreen. + fullscreenWidthBreakpoint = 125 + // fullscreenHeightBreakpoint is the height below which the dialog goes + // fullscreen. Lazygit degrades significantly below 40 rows. + fullscreenHeightBreakpoint = 40 ) // Config holds configuration for a terminal dialog. @@ -33,6 +36,8 @@ type Config struct { Term *terminal.Terminal // OnClose is called when the dialog is closed (optional). OnClose func() + // QuitHint is shown in the header (e.g., "q to close"). If empty, no hint is shown. + QuitHint string } // Dialog is a dialog that embeds a terminal application. @@ -42,6 +47,7 @@ type Dialog struct { loadingMsg string term *terminal.Terminal onClose func() + quitHint string wWidth int wHeight int @@ -63,6 +69,7 @@ func New(cfg Config) *Dialog { loadingMsg: loadingMsg, term: cfg.Term, onClose: cfg.OnClose, + quitHint: cfg.QuitHint, } } @@ -102,8 +109,8 @@ func (d *Dialog) handleResize(msg tea.WindowSizeMsg) (util.Model, tea.Cmd) { d.wWidth = msg.Width d.wHeight = msg.Height - // Go fullscreen when window is below compact mode breakpoint. - d.fullscreen = msg.Width < fullscreenWidthBreakpoint + // Go fullscreen when window is below size breakpoints. + d.fullscreen = msg.Width < fullscreenWidthBreakpoint || msg.Height < fullscreenHeightBreakpoint var outerWidth, outerHeight int if d.fullscreen { @@ -192,7 +199,20 @@ func (d *Dialog) View() string { termContent = d.loadingMsg } - header := t.S().Base.Padding(0, 1, 1, 1).Render(core.Title(d.title, d.width-2)) + // Build header with title and optional quit hint on the right. + var header string + if d.quitHint != "" { + hintStyle := t.S().Base.Foreground(t.Secondary) + hint := hintStyle.Render(d.quitHint) + hintWidth := lipgloss.Width(hint) + titleWidth := d.width - 2 - hintWidth - 1 // -1 for space between title and hint + title := core.Title(d.title, titleWidth) + headerContent := title + " " + hint + header = t.S().Base.Padding(0, 1, 1, 1).Render(headerContent) + } else { + header = t.S().Base.Padding(0, 1, 1, 1).Render(core.Title(d.title, d.width-2)) + } + content := lipgloss.JoinVertical(lipgloss.Left, header, termContent) dialogStyle := t.S().Base. diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 3a3ae553695223498ca09e12c91c64017fd46974..be29d545fc8a93c4baf7101006f08b659cffbf75 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -458,8 +458,9 @@ func (a *appModel) handleWindowResize(width, height int) tea.Cmd { cmds = append(cmds, pageCmd) } - // Update the dialogs - dialog, cmd := a.dialog.Update(tea.WindowSizeMsg{Width: width, Height: height}) + // Update the dialogs with full window dimensions so they can overlay + // everything including the status bar. + dialog, cmd := a.dialog.Update(tea.WindowSizeMsg{Width: a.wWidth, Height: a.wHeight}) if model, ok := dialog.(dialogs.DialogCmp); ok { a.dialog = model }