From bc87da9e56c3631c70e4b946ba3b60d3753c4d98 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 10 Jul 2025 13:15:16 -0400 Subject: [PATCH 1/3] chore: update vendors --- go.mod | 2 +- .../ultraviolet/screen/screen.go | 109 ++++++++++++++++++ vendor/modules.txt | 1 + 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/charmbracelet/ultraviolet/screen/screen.go diff --git a/go.mod b/go.mod index c68c8f02f9b68d8d3dfe94aec40da7e588a15939..128e04842feca31ebb4a7f8529149e13e4578f06 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/colorprofile v0.3.1 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa // indirect github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef github.com/charmbracelet/x/term v0.2.1 diff --git a/vendor/github.com/charmbracelet/ultraviolet/screen/screen.go b/vendor/github.com/charmbracelet/ultraviolet/screen/screen.go new file mode 100644 index 0000000000000000000000000000000000000000..fd54788456a999d1e0593b3bee9050005f7ceee2 --- /dev/null +++ b/vendor/github.com/charmbracelet/ultraviolet/screen/screen.go @@ -0,0 +1,109 @@ +// Package screen provides functions and helpers to manipulate a [uv.Screen]. +package screen + +import uv "github.com/charmbracelet/ultraviolet" + +// Clear clears the screen with empty cells. This is equivalent to filling the +// screen with empty cells. +// +// If the screen implements a [Clear] method, it will be called instead of +// filling the screen with empty cells. +func Clear(scr uv.Screen) { + if c, ok := scr.(interface { + Clear() + }); ok { + c.Clear() + return + } + Fill(scr, nil) +} + +// ClearArea clears the given area of the screen with empty cells. This is +// equivalent to filling the area with empty cells. +// +// If the screen implements a [ClearArea] method, it will be called instead of +// filling the area with empty cells. +func ClearArea(scr uv.Screen, area uv.Rectangle) { + if c, ok := scr.(interface { + ClearArea(area uv.Rectangle) + }); ok { + c.ClearArea(area) + return + } + FillArea(scr, nil, area) +} + +// Fill fills the screen with the given cell. If the cell is nil, it fills the +// screen with empty cells. +// +// If the screen implements a [Fill] method, it will be called instead of +// filling the screen with empty cells. +func Fill(scr uv.Screen, cell *uv.Cell) { + if f, ok := scr.(interface { + Fill(cell *uv.Cell) + }); ok { + f.Fill(cell) + return + } + FillArea(scr, cell, scr.Bounds()) +} + +// FillArea fills the given area of the screen with the given cell. If the cell +// is nil, it fills the area with empty cells. +// +// If the screen implements a [FillArea] method, it will be called instead of +// filling the area with empty cells. +func FillArea(scr uv.Screen, cell *uv.Cell, area uv.Rectangle) { + if f, ok := scr.(interface { + FillArea(cell *uv.Cell, area uv.Rectangle) + }); ok { + f.FillArea(cell, area) + return + } + for y := area.Min.Y; y < area.Max.Y; y++ { + for x := area.Min.X; x < area.Max.X; x++ { + scr.SetCell(x, y, cell) + } + } +} + +// CloneArea clones the given area of the screen and returns a new buffer +// with the same size as the area. The new buffer will contain the same cells +// as the area in the screen. +// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again. +// +// If the screen implements a [CloneArea] method, it will be called instead of +// cloning the area manually. +func CloneArea(scr uv.Screen, area uv.Rectangle) *uv.Buffer { + if c, ok := scr.(interface { + CloneArea(area uv.Rectangle) *uv.Buffer + }); ok { + return c.CloneArea(area) + } + buf := uv.NewBuffer(area.Dx(), area.Dy()) + for y := area.Min.Y; y < area.Max.Y; y++ { + for x := area.Min.X; x < area.Max.X; x++ { + cell := scr.CellAt(x, y) + if cell == nil || cell.IsZero() { + continue + } + buf.SetCell(x-area.Min.X, y-area.Min.Y, cell.Clone()) + } + } + return buf +} + +// Clone creates a new [uv.Buffer] clone of the given screen. The new buffer will +// have the same size as the screen and will contain the same cells. +// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again. +// +// If the screen implements a [Clone] method, it will be called instead of +// cloning the entire screen manually. +func Clone(scr uv.Screen) *uv.Buffer { + if c, ok := scr.(interface { + Clone() *uv.Buffer + }); ok { + return c.Clone() + } + return CloneArea(scr, scr.Bounds()) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e256e639e4098adadaf25a32fa4a05937e2066d7..743324d3515946ef7be8dce0230ee691f92e680b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -280,6 +280,7 @@ github.com/charmbracelet/log/v2 # github.com/charmbracelet/ultraviolet v0.0.0-20250708152637-0fe0235c8db9 ## explicit; go 1.24.0 github.com/charmbracelet/ultraviolet +github.com/charmbracelet/ultraviolet/screen # github.com/charmbracelet/x/ansi v0.9.3 ## explicit; go 1.23.0 github.com/charmbracelet/x/ansi From 653c6a56fc15ce076e97e85240205e5670c08342 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 10 Jul 2025 13:15:29 -0400 Subject: [PATCH 2/3] fix(tui): permission: make sure the fetch content has the correct background color --- .../dialogs/permissions/permissions.go | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/tui/components/dialogs/permissions/permissions.go b/internal/tui/components/dialogs/permissions/permissions.go index e7f6dd517b1504e2f938c9310e95b8a7086cbbf0..0e26cc063ad826c2306428b0f12cbc29abc02199 100644 --- a/internal/tui/components/dialogs/permissions/permissions.go +++ b/internal/tui/components/dialogs/permissions/permissions.go @@ -16,6 +16,7 @@ import ( "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" + uv "github.com/charmbracelet/ultraviolet" "github.com/charmbracelet/x/ansi" ) @@ -395,7 +396,22 @@ func (p *permissionDialogCmp) generateFetchContent() string { Width(p.contentViewPort.Width()). Render(renderedContent) - return finalContent + // We render the content into a buffer with the size of the viewport + // width and height of the content. Then we make sure each cell has the + // appropriate background color. + ss := uv.NewStyledString(finalContent) + scr := uv.NewScreenBuffer(p.contentViewPort.Width(), lipgloss.Height(finalContent)) + ss.Draw(scr, scr.Bounds()) + for y := 0; y < scr.Height(); y++ { + for x := 0; x < scr.Width(); x++ { + cell := scr.CellAt(x, y) + if cell != nil { + cell.Style.Bg = t.BgSubtle + } + } + } + + return scr.Render() } return "" } @@ -452,8 +468,8 @@ func (p *permissionDialogCmp) render() string { if p.supportsDiffView() { contentHelp = help.New().View(p.keyMap) } - // Calculate content height dynamically based on window size + // Calculate content height dynamically based on window size strs := []string{ title, "", From 006b3a1da1640e4d4be38c84ff6c08f725f1ff86 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Thu, 10 Jul 2025 20:22:24 +0200 Subject: [PATCH 3/3] simplify fetch url --- .../dialogs/permissions/permissions.go | 31 ++----------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/internal/tui/components/dialogs/permissions/permissions.go b/internal/tui/components/dialogs/permissions/permissions.go index 0e26cc063ad826c2306428b0f12cbc29abc02199..c43d50aa6233a2acb26e5b57c0b0f60b4ee143d3 100644 --- a/internal/tui/components/dialogs/permissions/permissions.go +++ b/internal/tui/components/dialogs/permissions/permissions.go @@ -16,7 +16,6 @@ import ( "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" - uv "github.com/charmbracelet/ultraviolet" "github.com/charmbracelet/x/ansi" ) @@ -383,35 +382,11 @@ func (p *permissionDialogCmp) generateFetchContent() string { t := styles.CurrentTheme() baseStyle := t.S().Base.Background(t.BgSubtle) if pr, ok := p.permission.Params.(tools.FetchPermissionsParams); ok { - content := fmt.Sprintf("```bash\n%s\n```", pr.URL) - - // Use the cache for markdown rendering - renderedContent := p.GetOrSetMarkdown(p.permission.ID, func() (string, error) { - r := styles.GetMarkdownRenderer(p.width - 4) - s, err := r.Render(content) - return s, err - }) - finalContent := baseStyle. + Padding(1, 1). Width(p.contentViewPort.Width()). - Render(renderedContent) - - // We render the content into a buffer with the size of the viewport - // width and height of the content. Then we make sure each cell has the - // appropriate background color. - ss := uv.NewStyledString(finalContent) - scr := uv.NewScreenBuffer(p.contentViewPort.Width(), lipgloss.Height(finalContent)) - ss.Draw(scr, scr.Bounds()) - for y := 0; y < scr.Height(); y++ { - for x := 0; x < scr.Width(); x++ { - cell := scr.CellAt(x, y) - if cell != nil { - cell.Style.Bg = t.BgSubtle - } - } - } - - return scr.Render() + Render(pr.URL) + return finalContent } return "" }