Просмотр исходного кода

fix: use real cursor instead of virtual cursor

adamdotdevin 6 месяцев назад
Родитель
Сommit
b2f2c9ac37
2 измененных файлов с 41 добавлено и 13 удалено
  1. 6 0
      packages/tui/internal/components/chat/editor.go
  2. 35 13
      packages/tui/internal/tui/tui.go

+ 6 - 0
packages/tui/internal/components/chat/editor.go

@@ -31,6 +31,7 @@ type EditorComponent interface {
 	tea.Model
 	tea.ViewModel
 	Content() string
+	Cursor() *tea.Cursor
 	Lines() int
 	Value() string
 	Length() int
@@ -407,6 +408,10 @@ func (m *editorComponent) Content() string {
 	return content
 }
 
+func (m *editorComponent) Cursor() *tea.Cursor {
+	return m.textarea.Cursor()
+}
+
 func (m *editorComponent) View() string {
 	width := m.width
 	if m.app.Session.ID == "" {
@@ -694,6 +699,7 @@ func NewEditorComponent(app *app.App) EditorComponent {
 	ta.Prompt = " "
 	ta.ShowLineNumbers = false
 	ta.CharLimit = -1
+	ta.VirtualCursor = false
 	ta = updateTextareaStyles(ta)
 
 	m := &editorComponent{

+ 35 - 13
packages/tui/internal/tui/tui.go

@@ -59,6 +59,8 @@ const interruptDebounceTimeout = 1 * time.Second
 const exitDebounceTimeout = 1 * time.Second
 
 type Model struct {
+	tea.Model
+	tea.CursorModel
 	width, height        int
 	app                  *app.App
 	modal                layout.Modal
@@ -748,15 +750,17 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return a, tea.Batch(cmds...)
 }
 
-func (a Model) View() string {
+func (a Model) View() (string, *tea.Cursor) {
 	t := theme.CurrentTheme()
 
 	var mainLayout string
 
+	var editorX int
+	var editorY int
 	if a.app.Session.ID == "" {
-		mainLayout = a.home()
+		mainLayout, editorX, editorY = a.home()
 	} else {
-		mainLayout = a.chat()
+		mainLayout, editorX, editorY = a.chat()
 	}
 	mainLayout = styles.NewStyle().
 		Background(t.Background()).
@@ -780,7 +784,12 @@ func (a Model) View() string {
 	if theme.CurrentThemeUsesAnsiColors() {
 		mainLayout = util.ConvertRGBToAnsi16Colors(mainLayout)
 	}
-	return mainLayout + "\n" + a.status.View()
+
+	cursor := a.editor.Cursor()
+	cursor.Position.X += editorX
+	cursor.Position.Y += editorY
+
+	return mainLayout + "\n" + a.status.View(), cursor
 }
 
 func (a Model) Cleanup() {
@@ -807,7 +816,7 @@ func (a Model) openFile(filepath string) (tea.Model, tea.Cmd) {
 	return a, cmd
 }
 
-func (a Model) home() string {
+func (a Model) home() (string, int, int) {
 	t := theme.CurrentTheme()
 	effectiveWidth := a.width - 4
 	baseStyle := styles.NewStyle().Background(t.Background())
@@ -899,14 +908,21 @@ func (a Model) home() string {
 		styles.WhitespaceStyle(t.Background()),
 	)
 
-	editorX := (effectiveWidth - editorWidth) / 2
+	editorX := max(0, (effectiveWidth-editorWidth)/2)
 	editorY := (a.height / 2) + (mainHeight / 2) - 2
 
 	if editorLines > 1 {
+		content := a.editor.Content()
+		editorHeight := lipgloss.Height(content)
+
+		if editorY+editorHeight > a.height {
+			difference := (editorY + editorHeight) - a.height
+			editorY -= difference
+		}
 		mainLayout = layout.PlaceOverlay(
 			editorX,
 			editorY,
-			a.editor.Content(),
+			content,
 			mainLayout,
 		)
 	}
@@ -924,10 +940,10 @@ func (a Model) home() string {
 		)
 	}
 
-	return mainLayout
+	return mainLayout, editorX + 5, editorY + 2
 }
 
-func (a Model) chat() string {
+func (a Model) chat() (string, int, int) {
 	effectiveWidth := a.width - 4
 	t := theme.CurrentTheme()
 	editorView := a.editor.View()
@@ -944,14 +960,20 @@ func (a Model) chat() string {
 	)
 
 	mainLayout := messagesView + "\n" + editorView
-	editorX := (effectiveWidth - editorWidth) / 2
+	editorX := max(0, (effectiveWidth-editorWidth)/2)
+	editorY := a.height - editorHeight
 
 	if lines > 1 {
-		editorY := a.height - editorHeight
+		content := a.editor.Content()
+		editorHeight := lipgloss.Height(content)
+		if editorY+editorHeight > a.height {
+			difference := (editorY + editorHeight) - a.height
+			editorY -= difference
+		}
 		mainLayout = layout.PlaceOverlay(
 			editorX,
 			editorY,
-			a.editor.Content(),
+			content,
 			mainLayout,
 		)
 	}
@@ -970,7 +992,7 @@ func (a Model) chat() string {
 		)
 	}
 
-	return mainLayout
+	return mainLayout, editorX + 5, editorY + 2
 }
 
 func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {