@@ -27,7 +27,6 @@ import (
27 "github.com/charmbracelet/crush/internal/version"
27 "github.com/charmbracelet/crush/internal/version"
28 uv "github.com/charmbracelet/ultraviolet"
28 uv "github.com/charmbracelet/ultraviolet"
29 "github.com/charmbracelet/ultraviolet/screen"
29 "github.com/charmbracelet/ultraviolet/screen"
30− "github.com/charmbracelet/x/ansi"
33// uiFocusState represents the current focus state of the UI.
32// uiFocusState represents the current focus state of the UI.
@@ -114,9 +113,6 @@ type UI struct {
115 // sidebarLogo keeps a cached version of the sidebar sidebarLogo.
114 // sidebarLogo keeps a cached version of the sidebar sidebarLogo.
116 sidebarLogo string
115 sidebarLogo string
118− // Canvas for rendering
119− canvas *uv.ScreenBuffer
122// New creates a new instance of the [UI] model.
118// New creates a new instance of the [UI] model.
@@ -131,10 +127,6 @@ func New(com *common.Common) *UI {
132 ch := NewChat(com)
128 ch := NewChat(com)
134− // TODO: Switch to lipgloss.Canvas when available
135− canvas := uv.NewScreenBuffer(0, 0)
136− canvas.Method = ansi.GraphemeWidth
138 ui := &UI{
130 ui := &UI{
139 com: com,
131 com: com,
140 dialog: dialog.NewOverlay(),
132 dialog: dialog.NewOverlay(),
@@ -144,7 +136,6 @@ func New(com *common.Common) *UI {
144 state: uiConfigure,
136 state: uiConfigure,
145 textarea: ta,
137 textarea: ta,
146 chat: ch,
138 chat: ch,
150 // set onboarding state defaults
141 // set onboarding state defaults
@@ -222,7 +213,6 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
222 case tea.WindowSizeMsg:
213 case tea.WindowSizeMsg:
223 m.width, m.height = msg.Width, msg.Height
214 m.width, m.height = msg.Width, msg.Height
224 m.updateLayoutAndSize()
215 m.updateLayoutAndSize()
225− m.canvas.Resize(msg.Width, msg.Height)
226 case tea.KeyboardEnhancementsMsg:
216 case tea.KeyboardEnhancementsMsg:
227 m.keyenh = msg
217 m.keyenh = msg
228 if msg.SupportsKeyDisambiguation() {
218 if msg.SupportsKeyDisambiguation() {
@@ -499,9 +489,10 @@ func (m *UI) View() tea.View {
499 v.Cursor = m.Cursor()
489 v.Cursor = m.Cursor()
500 v.MouseMode = tea.MouseModeCellMotion
490 v.MouseMode = tea.MouseModeCellMotion
492+ canvas := uv.NewScreenBuffer(m.width, m.height)
502− m.Draw(m.canvas, m.canvas.Bounds())
493+ m.Draw(canvas, canvas.Bounds())
504− content := strings.ReplaceAll(m.canvas.Render(), "\r\n", "\n") // normalize newlines
495+ content := strings.ReplaceAll(canvas.Render(), "\r\n", "\n") // normalize newlines
505 contentLines := strings.Split(content, "\n")
496 contentLines := strings.Split(content, "\n")
506 for i, line := range contentLines {
497 for i, line := range contentLines {
507 // Trim trailing spaces for concise rendering
498 // Trim trailing spaces for concise rendering
@@ -509,6 +500,7 @@ func (m *UI) View() tea.View {
511 content = strings.Join(contentLines, "\n")
502 content = strings.Join(contentLines, "\n")
512 v.Content = content
504 v.Content = content
513 if m.sendProgressBar && m.com.App != nil && m.com.App.AgentCoordinator != nil && m.com.App.AgentCoordinator.IsBusy() {
505 if m.sendProgressBar && m.com.App != nil && m.com.App.AgentCoordinator != nil && m.com.App.AgentCoordinator.IsBusy() {
514 // HACK: use a random percentage to prevent ghostty from hiding it
506 // HACK: use a random percentage to prevent ghostty from hiding it
@@ -658,27 +650,21 @@ func (m *UI) updateSize() {
658 // Set help width
650 // Set help width
659 m.help.SetWidth(m.layout.help.Dx())
651 m.help.SetWidth(m.layout.help.Dx())
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())
661 // Handle different app states
657 // Handle different app states
662 switch m.state {
658 switch m.state {
663− case uiConfigure, uiInitialize:
659+ case uiConfigure, uiInitialize, uiLanding:
664− m.renderHeader(false, m.layout.header.Dx())
667 m.renderHeader(false, m.layout.header.Dx())
660 m.renderHeader(false, m.layout.header.Dx())
668− m.textarea.SetWidth(m.layout.editor.Dx())
669− m.textarea.SetHeight(m.layout.editor.Dy())
671 case uiChat:
662 case uiChat:
672 m.renderSidebarLogo(m.layout.sidebar.Dx())
663 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())
677 case uiChatCompact:
665 case uiChatCompact:
678 // TODO: set the width and heigh of the chat component
666 // TODO: set the width and heigh of the chat component
679 m.renderHeader(true, m.layout.header.Dx())
667 m.renderHeader(true, m.layout.header.Dx())
680− m.textarea.SetWidth(m.layout.editor.Dx())
681− m.textarea.SetHeight(m.layout.editor.Dy())