Revert "Opentui textarea (#3310)"

This reverts commit 4c2d0cf181.
This commit is contained in:
Dax 2025-10-23 21:03:32 -04:00 committed by GitHub
parent 4c2d0cf181
commit d136411e86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 53 deletions

View file

@ -1,4 +1,4 @@
import type { BoxRenderable, TextareaRenderable, KeyEvent } from "@opentui/core"
import type { ParsedKey, BoxRenderable, InputRenderable } from "@opentui/core"
import fuzzysort from "fuzzysort"
import { firstBy } from "remeda"
import { createMemo, createResource, createEffect, onMount, For, Show } from "solid-js"
@ -12,7 +12,7 @@ import type { PromptInfo } from "./history"
export type AutocompleteRef = {
onInput: (value: string) => void
onKeyDown: (e: KeyEvent) => void
onKeyDown: (e: ParsedKey) => void
visible: false | "@" | "/"
}
@ -28,7 +28,7 @@ export function Autocomplete(props: {
sessionID?: string
setPrompt: (input: (prompt: PromptInfo) => void) => void
anchor: () => BoxRenderable
input: () => TextareaRenderable
input: () => InputRenderable
ref: (ref: AutocompleteRef) => void
}) {
const sdk = useSDK()
@ -138,9 +138,8 @@ export function Autocomplete(props: {
display: "/" + command.name,
description: command.description,
onSelect: () => {
console.log("commands.onSelect", command.name, Bun.stringWidth(props.input().value))
props.input().value = "/" + command.name + " "
props.input().cursorOffset = Bun.stringWidth(props.input().value)
props.input().cursorPosition = props.input().value.length
},
})
}
@ -239,10 +238,9 @@ export function Autocomplete(props: {
}
function show(mode: "@" | "/") {
console.log("show", mode, props.input().visualCursor.offset)
setStore({
visible: mode,
index: props.input().visualCursor.offset,
index: props.input().cursorPosition,
position: {
x: props.anchor().x,
y: props.anchor().y,
@ -264,7 +262,7 @@ export function Autocomplete(props: {
onInput(value: string) {
if (store.visible && value.length <= store.index) hide()
},
onKeyDown(e: KeyEvent) {
onKeyDown(e: ParsedKey) {
if (store.visible) {
if (e.name === "up") move(-1)
if (e.name === "down") move(1)
@ -280,7 +278,7 @@ export function Autocomplete(props: {
}
if (e.name === "/") {
if (props.input().visualCursor.offset === 0) show("/")
if (props.input().cursorPosition === 0) show("/")
}
}
},

View file

@ -1,4 +1,4 @@
import { TextAttributes, BoxRenderable, TextareaRenderable, MouseEvent, KeyEvent } from "@opentui/core"
import { InputRenderable, TextAttributes, BoxRenderable } from "@opentui/core"
import { createEffect, createMemo, Match, Switch, type JSX } from "solid-js"
import { useLocal } from "@tui/context/local"
import { Theme } from "@tui/context/theme"
@ -34,7 +34,7 @@ export type PromptRef = {
}
export function Prompt(props: PromptProps) {
let input: TextareaRenderable
let input: InputRenderable
let anchor: BoxRenderable
let autocomplete: AutocompleteRef
@ -69,8 +69,7 @@ export function Prompt(props: PromptProps) {
input: content,
parts: [],
})
console.log("editor.open", content, Bun.stringWidth(content))
input.cursorOffset = Bun.stringWidth(content)
input.cursorPosition = content.length
}
},
},
@ -142,8 +141,7 @@ export function Prompt(props: PromptProps) {
},
set(prompt) {
setStore("prompt", prompt)
console.log("prompt.set", prompt.input, Bun.stringWidth(prompt.input))
input.cursorOffset = Bun.stringWidth(prompt.input)
input.cursorPosition = prompt.input.length
},
reset() {
setStore("prompt", {
@ -241,8 +239,7 @@ export function Prompt(props: PromptProps) {
input={() => input}
setPrompt={(cb) => {
setStore("prompt", produce(cb))
console.log("setPrompt", store.prompt.input, Bun.stringWidth(store.prompt.input))
input.cursorOffset = Bun.stringWidth(store.prompt.input)
input.cursorPosition = store.prompt.input.length
}}
value={store.prompt.input}
/>
@ -251,23 +248,18 @@ export function Prompt(props: PromptProps) {
flexDirection="row"
{...SplitBorder}
borderColor={keybind.leader ? Theme.accent : store.mode === "shell" ? Theme.secondary : undefined}
justifyContent="space-evenly"
>
<box
backgroundColor={Theme.backgroundElement}
width={3}
height="100%"
justifyContent="center"
alignItems="center"
>
<box backgroundColor={Theme.backgroundElement} width={3} justifyContent="center" alignItems="center">
<text attributes={TextAttributes.BOLD} fg={Theme.primary}>
{store.mode === "normal" ? ">" : "!"}
</text>
</box>
<box paddingTop={1} paddingBottom={1} backgroundColor={Theme.backgroundElement} flexGrow={1}>
<textarea
onContentChange={() => {
const value = input.value
<box paddingTop={1} paddingBottom={2} backgroundColor={Theme.backgroundElement} flexGrow={1}>
<input
onPaste={async function (text) {
this.insertText(text)
}}
onInput={(value) => {
let diff = value.length - store.prompt.input.length
setStore(
produce((draft) => {
@ -276,7 +268,7 @@ export function Prompt(props: PromptProps) {
const part = draft.prompt.parts[i]
if (!part.source) continue
const source = part.type === "agent" ? part.source : part.source.text
if (source.start >= input.visualCursor.offset) {
if (source.start >= input.cursorPosition) {
source.start += diff
source.end += diff
}
@ -286,14 +278,7 @@ export function Prompt(props: PromptProps) {
draft.prompt.input =
draft.prompt.input.slice(0, source.start) + draft.prompt.input.slice(source.end)
draft.prompt.parts.splice(i, 1)
console.log(
"onContentChange setting cursor offset",
value,
input.visualCursor.offset,
source.start,
source.end,
)
input.cursorOffset = Math.max(0, source.start - 1)
input.cursorPosition = Math.max(0, source.start - 1)
i--
}
}
@ -302,7 +287,7 @@ export function Prompt(props: PromptProps) {
autocomplete.onInput(value)
}}
value={store.prompt.input}
onKeyDown={async (e: KeyEvent) => {
onKeyDown={async (e) => {
if (props.disabled) {
e.preventDefault()
return
@ -318,32 +303,29 @@ export function Prompt(props: PromptProps) {
await exit()
return
}
if (e.name === "!" && input.visualCursor.offset === 0) {
if (e.name === "!" && input.cursorPosition === 0) {
setStore("mode", "shell")
e.preventDefault()
return
}
if (store.mode === "shell") {
if ((e.name === "backspace" && input.visualCursor.offset === 0) || e.name === "escape") {
if ((e.name === "backspace" && input.cursorPosition === 0) || e.name === "escape") {
setStore("mode", "normal")
e.preventDefault()
return
}
}
if (store.mode === "normal") autocomplete.onKeyDown(e)
if (!autocomplete.visible && input.visualCursor.offset === 0) {
if (!autocomplete.visible) {
if (e.name === "up" || e.name === "down") {
const direction = e.name === "up" ? -1 : 1
const item = history.move(direction, input.value)
if (item) {
setStore("prompt", item)
input.cursorPosition = item.input.length
e.preventDefault()
}
return
}
}
if (!autocomplete.visible) {
if (e.name === "escape" && props.sessionID) {
sdk.client.session.abort({
path: {
@ -353,9 +335,9 @@ export function Prompt(props: PromptProps) {
return
}
}
const old = input.visualCursor.offset
const old = input.cursorPosition
setTimeout(() => {
const position = input.visualCursor.offset
const position = input.cursorPosition
const direction = Math.sign(old - position)
for (const part of store.prompt.parts) {
const source = iife(() => {
@ -366,12 +348,10 @@ export function Prompt(props: PromptProps) {
if (source) {
if (position >= source.start && position < source.end) {
if (direction === 1) {
console.log("onKeyDown setting cursor offset", source.start - 1)
input.cursorOffset = Math.max(0, source.start - 1)
input.cursorPosition = Math.max(0, source.start - 1)
}
if (direction === -1) {
console.log("onKeyDown setting cursor offset", source.end)
input.cursorOffset = source.end
input.cursorPosition = source.end
}
}
}
@ -379,8 +359,8 @@ export function Prompt(props: PromptProps) {
}, 0)
}}
onSubmit={submit}
ref={(r: TextareaRenderable) => (input = r)}
onMouseDown={(r: MouseEvent) => r.target?.focus()}
ref={(r) => (input = r)}
onMouseDown={(r) => r.target?.focus()}
focusedBackgroundColor={Theme.backgroundElement}
cursorColor={Theme.primary}
backgroundColor={Theme.backgroundElement}