@@ -27,7 +27,6 @@ import (
2727 "github.com/charmbracelet/crush/internal/version"
2828 uv "github.com/charmbracelet/ultraviolet"
2929 "github.com/charmbracelet/ultraviolet/screen"
30− "github.com/charmbracelet/x/ansi"
3130)
3231
3332// uiFocusState represents the current focus state of the UI.
@@ -114,9 +113,6 @@ type UI struct {
114113
115114 // sidebarLogo keeps a cached version of the sidebar sidebarLogo.
116115 sidebarLogo string
117−
118− // Canvas for rendering
119− canvas *uv.ScreenBuffer
120116}
121117
122118// New creates a new instance of the [UI] model.
@@ -131,10 +127,6 @@ func New(com *common.Common) *UI {
131127
132128 ch := NewChat(com)
133129
134− // TODO: Switch to lipgloss.Canvas when available
135− canvas := uv.NewScreenBuffer(0, 0)
136− canvas.Method = ansi.GraphemeWidth
137−
138130 ui := &UI{
139131 com: com,
140132 dialog: dialog.NewOverlay(),
@@ -144,7 +136,6 @@ func New(com *common.Common) *UI {
144136 state: uiConfigure,
145137 textarea: ta,
146138 chat: ch,
147− canvas: &canvas,
148139 }
149140
150141 // set onboarding state defaults
@@ -222,7 +213,6 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
222213 case tea.WindowSizeMsg:
223214 m.width, m.height = msg.Width, msg.Height
224215 m.updateLayoutAndSize()
225− m.canvas.Resize(msg.Width, msg.Height)
226216 case tea.KeyboardEnhancementsMsg:
227217 m.keyenh = msg
228218 if msg.SupportsKeyDisambiguation() {
@@ -499,9 +489,10 @@ func (m *UI) View() tea.View {
499489 v.Cursor = m.Cursor()
500490 v.MouseMode = tea.MouseModeCellMotion
501491
502− m.Draw(m.canvas, m.canvas.Bounds())
492+ canvas := uv.NewScreenBuffer(m.width, m.height)
493+ m.Draw(canvas, canvas.Bounds())
503494
504− content := strings.ReplaceAll(m.canvas.Render(), "\r\n", "\n") // normalize newlines
495+ content := strings.ReplaceAll(canvas.Render(), "\r\n", "\n") // normalize newlines
505496 contentLines := strings.Split(content, "\n")
506497 for i, line := range contentLines {
507498 // Trim trailing spaces for concise rendering
@@ -509,6 +500,7 @@ func (m *UI) View() tea.View {
509500 }
510501
511502 content = strings.Join(contentLines, "\n")
503+
512504 v.Content = content
513505 if m.sendProgressBar && m.com.App != nil && m.com.App.AgentCoordinator != nil && m.com.App.AgentCoordinator.IsBusy() {
514506 // HACK: use a random percentage to prevent ghostty from hiding it
@@ -658,27 +650,21 @@ func (m *UI) updateSize() {
658650 // Set help width
659651 m.help.SetWidth(m.layout.help.Dx())
660652
653+ m.chat.SetSize(m.layout.main.Dx(), m.layout.main.Dy())
654+ m.textarea.SetWidth(m.layout.editor.Dx())
655+ m.textarea.SetHeight(m.layout.editor.Dy())
656+
661657 // Handle different app states
662658 switch m.state {
663− case uiConfigure, uiInitialize:
664− m.renderHeader(false, m.layout.header.Dx())
665−
666− case uiLanding:
659+ case uiConfigure, uiInitialize, uiLanding:
667660 m.renderHeader(false, m.layout.header.Dx())
668− m.textarea.SetWidth(m.layout.editor.Dx())
669− m.textarea.SetHeight(m.layout.editor.Dy())
670661
671662 case uiChat:
672663 m.renderSidebarLogo(m.layout.sidebar.Dx())
673− m.textarea.SetWidth(m.layout.editor.Dx())
674− m.textarea.SetHeight(m.layout.editor.Dy())
675− m.chat.SetSize(m.layout.main.Dx(), m.layout.main.Dy())
676664
677665 case uiChatCompact:
678666 // TODO: set the width and heigh of the chat component
679667 m.renderHeader(true, m.layout.header.Dx())
680− m.textarea.SetWidth(m.layout.editor.Dx())
681− m.textarea.SetHeight(m.layout.editor.Dy())
682668 }
683669}
684670