diff --git a/go.mod b/go.mod index 7b36182d401f2d5df0f9126fc204558755db82df..63eddd631ee5cbaf30b4d796d2e430490ceb513c 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.26.1 require ( charm.land/bubbles/v2 v2.1.0 - charm.land/bubbletea/v2 v2.0.2 + charm.land/bubbletea/v2 v2.0.3 charm.land/catwalk v0.35.3 charm.land/fang/v2 v2.0.1 charm.land/fantasy v0.17.1 @@ -24,7 +24,7 @@ require ( github.com/charlievieth/fastwalk v1.0.14 github.com/charmbracelet/colorprofile v0.4.3 github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266 - github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 + github.com/charmbracelet/ultraviolet v0.0.0-20260413133134-73592393e1ad github.com/charmbracelet/x/ansi v0.11.6 github.com/charmbracelet/x/editor v0.2.0 github.com/charmbracelet/x/etag v0.2.0 diff --git a/go.sum b/go.sum index 5b77409c2dbd61faaa25a836db9a6d8587f2b1f6..c03e66b37bffc22d5a16e8d7581f160a120d3810 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g= charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY= -charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0= -charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= +charm.land/bubbletea/v2 v2.0.3 h1:l+n6zlO+WW/Jj9QV+od9ZmeOK4ITh0NuH1xP4VPEyeA= +charm.land/bubbletea/v2 v2.0.3/go.mod h1:yzdemvvo7UJrtPl//9g7/JdILzYw1oYH2FOrJfN/TXc= charm.land/catwalk v0.35.3 h1:tg3Vnz9V4kOQw9t+tQQFJyWxH4pZy2nblhSUaD9jH5o= charm.land/catwalk v0.35.3/go.mod h1:IvMXm7qMKvYuWWlN5A4dA0bTgYg4clG1GAeU9/NlY0w= charm.land/fang/v2 v2.0.1 h1:zQCM8JQJ1JnQX/66B5jlCYBUxL2as5JXQZ2KJ6EL0mY= @@ -108,8 +108,8 @@ github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266 h1:BW/sZtyd1JyYy0h5adMm3tzpNyL857LWjuTRET6OhpY= github.com/charmbracelet/openai-go v0.0.0-20260319145158-d0740cc34266/go.mod h1:1DahUaExbUZx/jD+FNT2PKP4L9rLE5+ZBRuI8mZjd/E= -github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA= -github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98= +github.com/charmbracelet/ultraviolet v0.0.0-20260413133134-73592393e1ad h1:kxhuAdAdSGSiAadbEjP7v06nCb17jXjjqF2QOX+0QiE= +github.com/charmbracelet/ultraviolet v0.0.0-20260413133134-73592393e1ad/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= github.com/charmbracelet/x/editor v0.2.0 h1:7XLUKtaRaB8jN7bWU2p2UChiySyaAuIfYiIRg8gGWwk= diff --git a/internal/ui/model/landing.go b/internal/ui/model/landing.go index e78d03e2afb5bd826e7d5ffd5c4d571575fcf949..0f3fc8d4d4012b953d2da0a3eb6b8a34d33fd535 100644 --- a/internal/ui/model/landing.go +++ b/internal/ui/model/landing.go @@ -1,6 +1,8 @@ package model import ( + "image" + "charm.land/lipgloss/v2" "github.com/charmbracelet/crush/internal/ui/common" "github.com/charmbracelet/crush/internal/workspace" @@ -31,7 +33,11 @@ func (m *UI) landingView() string { parts = append(parts, "", m.modelInfo(width)) infoSection := lipgloss.JoinVertical(lipgloss.Left, parts...) - _, remainingHeightArea := layout.SplitVertical(m.layout.main, layout.Fixed(lipgloss.Height(infoSection)+1)) + var remainingHeightArea image.Rectangle + layout.Vertical( + layout.Len(lipgloss.Height(infoSection)+1), + layout.Fill(1), + ).Split(m.layout.main).Assign(new(image.Rectangle), &remainingHeightArea) mcpLspSectionWidth := min(30, (width-1)/2) diff --git a/internal/ui/model/sidebar.go b/internal/ui/model/sidebar.go index 13e1797f3f2f7155a17d93bbe01ae7bb14e8246f..2b8db441a14495f9367963677bba4891a7fdd740 100644 --- a/internal/ui/model/sidebar.go +++ b/internal/ui/model/sidebar.go @@ -3,6 +3,7 @@ package model import ( "cmp" "fmt" + "image" "charm.land/lipgloss/v2" "github.com/charmbracelet/crush/internal/ui/common" @@ -136,7 +137,11 @@ func (m *UI) drawSidebar(scr uv.Screen, area uv.Rectangle) { blocks..., ) - _, remainingHeightArea := layout.SplitVertical(m.layout.sidebar, layout.Fixed(lipgloss.Height(sidebarHeader))) + var remainingHeightArea image.Rectangle + layout.Vertical( + layout.Len(lipgloss.Height(sidebarHeader)), + layout.Fill(1), + ).Split(m.layout.sidebar).Assign(new(image.Rectangle), &remainingHeightArea) remainingHeight := remainingHeightArea.Dy() - 10 maxFiles, maxLSPs, maxMCPs := getDynamicHeightLimits(remainingHeight) diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index f63131752397c2d83de3bc47c23f7501ab197e93..8f49776c8775d6b4ed38e5aaef0f875d23d15517 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -2481,7 +2481,11 @@ func (m *UI) generateLayout(w, h int) uiLayout { } // Add app margins - appRect, helpRect := layout.SplitVertical(area, layout.Fixed(area.Dy()-helpHeight)) + var appRect, helpRect image.Rectangle + layout.Vertical( + layout.Len(area.Dy()-helpHeight), + layout.Fill(1), + ).Split(area).Assign(&appRect, &helpRect) appRect.Min.Y += 1 appRect.Max.Y -= 1 helpRect.Min.Y -= 1 @@ -2510,7 +2514,11 @@ func (m *UI) generateLayout(w, h int) uiLayout { // ------ // help - headerRect, mainRect := layout.SplitVertical(appRect, layout.Fixed(landingHeaderHeight)) + var headerRect, mainRect image.Rectangle + layout.Vertical( + layout.Len(landingHeaderHeight), + layout.Fill(1), + ).Split(appRect).Assign(&headerRect, &mainRect) uiLayout.header = headerRect uiLayout.main = mainRect @@ -2524,8 +2532,16 @@ func (m *UI) generateLayout(w, h int) uiLayout { // editor // ------ // help - headerRect, mainRect := layout.SplitVertical(appRect, layout.Fixed(landingHeaderHeight)) - mainRect, editorRect := layout.SplitVertical(mainRect, layout.Fixed(mainRect.Dy()-editorHeight)) + var headerRect, mainRect image.Rectangle + layout.Vertical( + layout.Len(landingHeaderHeight), + layout.Fill(1), + ).Split(appRect).Assign(&headerRect, &mainRect) + var editorRect image.Rectangle + layout.Vertical( + layout.Len(mainRect.Dy()-editorHeight), + layout.Fill(1), + ).Split(mainRect).Assign(&mainRect, &editorRect) // Remove extra padding from editor (but keep it for header and main) editorRect.Min.X -= 1 editorRect.Max.X += 1 @@ -2545,20 +2561,36 @@ func (m *UI) generateLayout(w, h int) uiLayout { // ------ // help const compactHeaderHeight = 1 - headerRect, mainRect := layout.SplitVertical(appRect, layout.Fixed(compactHeaderHeight)) - detailsHeight := min(sessionDetailsMaxHeight, area.Dy()-1) // One row for the header - sessionDetailsArea, _ := layout.SplitVertical(appRect, layout.Fixed(detailsHeight)) + var headerRect, mainRect image.Rectangle + layout.Vertical( + layout.Len(compactHeaderHeight), + layout.Fill(1), + ).Split(appRect).Assign(&headerRect, &mainRect) + detailsHeight := min(sessionDetailsMaxHeight, area.Dy()-1) // One row for the header + var sessionDetailsArea image.Rectangle + layout.Vertical( + layout.Len(detailsHeight), + layout.Fill(1), + ).Split(appRect).Assign(&sessionDetailsArea, new(image.Rectangle)) uiLayout.sessionDetails = sessionDetailsArea uiLayout.sessionDetails.Min.Y += compactHeaderHeight // adjust for header // Add one line gap between header and main content mainRect.Min.Y += 1 - mainRect, editorRect := layout.SplitVertical(mainRect, layout.Fixed(mainRect.Dy()-editorHeight)) + var editorRect image.Rectangle + layout.Vertical( + layout.Len(mainRect.Dy()-editorHeight), + layout.Fill(1), + ).Split(mainRect).Assign(&mainRect, &editorRect) mainRect.Max.X -= 1 // Add padding right uiLayout.header = headerRect pillsHeight := m.pillsAreaHeight() if pillsHeight > 0 { pillsHeight = min(pillsHeight, mainRect.Dy()) - chatRect, pillsRect := layout.SplitVertical(mainRect, layout.Fixed(mainRect.Dy()-pillsHeight)) + var chatRect, pillsRect image.Rectangle + layout.Vertical( + layout.Len(mainRect.Dy()-pillsHeight), + layout.Fill(1), + ).Split(mainRect).Assign(&chatRect, &pillsRect) uiLayout.main = chatRect uiLayout.pills = pillsRect } else { @@ -2577,16 +2609,28 @@ func (m *UI) generateLayout(w, h int) uiLayout { // ---------- // help - mainRect, sideRect := layout.SplitHorizontal(appRect, layout.Fixed(appRect.Dx()-sidebarWidth)) + var mainRect, sideRect image.Rectangle + layout.Horizontal( + layout.Len(appRect.Dx()-sidebarWidth), + layout.Fill(1), + ).Split(appRect).Assign(&mainRect, &sideRect) // Add padding left sideRect.Min.X += 1 - mainRect, editorRect := layout.SplitVertical(mainRect, layout.Fixed(mainRect.Dy()-editorHeight)) + var editorRect image.Rectangle + layout.Vertical( + layout.Len(mainRect.Dy()-editorHeight), + layout.Fill(1), + ).Split(mainRect).Assign(&mainRect, &editorRect) mainRect.Max.X -= 1 // Add padding right uiLayout.sidebar = sideRect pillsHeight := m.pillsAreaHeight() if pillsHeight > 0 { pillsHeight = min(pillsHeight, mainRect.Dy()) - chatRect, pillsRect := layout.SplitVertical(mainRect, layout.Fixed(mainRect.Dy()-pillsHeight)) + var chatRect, pillsRect image.Rectangle + layout.Vertical( + layout.Len(mainRect.Dy()-pillsHeight), + layout.Fill(1), + ).Split(mainRect).Assign(&chatRect, &pillsRect) uiLayout.main = chatRect uiLayout.pills = pillsRect } else {