mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 08:13:11 +03:00
fix(tui): clear stale composer placeholder
This commit is contained in:
@@ -137,6 +137,30 @@ describe("NanobotTui layout", () => {
|
|||||||
expect(sent).toEqual(["你好"])
|
expect(sent).toEqual(["你好"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("clears the placeholder on the first typed character", async () => {
|
||||||
|
setup = await createRenderer({ width: 72, height: 20, screenMode: "alternate-screen" })
|
||||||
|
const app = mount(setup)
|
||||||
|
const composer = (app as unknown as { composer: TextareaRenderable }).composer
|
||||||
|
await setup.renderOnce()
|
||||||
|
expect(setup.captureCharFrame()).toContain("Ask nanobot anything")
|
||||||
|
|
||||||
|
setup.mockInput.typeText("bu")
|
||||||
|
await setup.flush()
|
||||||
|
const frame = setup.captureCharFrame()
|
||||||
|
|
||||||
|
expect(composer.plainText).toBe("bu")
|
||||||
|
expect(composer.placeholder).toBeNull()
|
||||||
|
expect(frame).toContain("bu")
|
||||||
|
expect(frame).not.toContain("Ask nanobot anything")
|
||||||
|
expect(frame).not.toContain("buAsk nanobot anything")
|
||||||
|
|
||||||
|
setup.mockInput.pressBackspace()
|
||||||
|
setup.mockInput.pressBackspace()
|
||||||
|
await setup.flush()
|
||||||
|
expect(composer.placeholder).toBe("Ask nanobot anything")
|
||||||
|
expect(setup.captureCharFrame()).toContain("Ask nanobot anything")
|
||||||
|
})
|
||||||
|
|
||||||
test("recalls submitted prompts without stealing multiline cursor movement", async () => {
|
test("recalls submitted prompts without stealing multiline cursor movement", async () => {
|
||||||
const sent: string[] = []
|
const sent: string[] = []
|
||||||
setup = await createRenderer({ width: 72, height: 20, screenMode: "alternate-screen" })
|
setup = await createRenderer({ width: 72, height: 20, screenMode: "alternate-screen" })
|
||||||
|
|||||||
+15
-2
@@ -82,6 +82,8 @@ const LIGHT: Palette = {
|
|||||||
cool: "#0F766E",
|
cool: "#0F766E",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const COMPOSER_PLACEHOLDER = "Ask nanobot anything"
|
||||||
|
|
||||||
function syntaxStyle(palette: Palette): SyntaxStyle {
|
function syntaxStyle(palette: Palette): SyntaxStyle {
|
||||||
const color = (value: string) => {
|
const color = (value: string) => {
|
||||||
const parsed = RGBA.fromHex(value)
|
const parsed = RGBA.fromHex(value)
|
||||||
@@ -231,7 +233,7 @@ export class NanobotTui {
|
|||||||
minHeight: 1,
|
minHeight: 1,
|
||||||
maxHeight: 8,
|
maxHeight: 8,
|
||||||
wrapMode: "word",
|
wrapMode: "word",
|
||||||
placeholder: "Ask nanobot anything",
|
placeholder: COMPOSER_PLACEHOLDER,
|
||||||
placeholderColor: this.palette.faint,
|
placeholderColor: this.palette.faint,
|
||||||
textColor: this.palette.text,
|
textColor: this.palette.text,
|
||||||
focusedTextColor: this.palette.text,
|
focusedTextColor: this.palette.text,
|
||||||
@@ -243,7 +245,10 @@ export class NanobotTui {
|
|||||||
{ name: "return", action: "submit" },
|
{ name: "return", action: "submit" },
|
||||||
{ name: "return", meta: true, action: "newline" },
|
{ name: "return", meta: true, action: "newline" },
|
||||||
],
|
],
|
||||||
onContentChange: () => this.resizeComposer(),
|
onContentChange: () => {
|
||||||
|
this.syncComposerPlaceholder()
|
||||||
|
this.resizeComposer()
|
||||||
|
},
|
||||||
// IMEs may commit their final composed glyph after Enter. Matching the
|
// IMEs may commit their final composed glyph after Enter. Matching the
|
||||||
// OpenCode/OpenTUI integration, defer twice before reading plainText.
|
// OpenCode/OpenTUI integration, defer twice before reading plainText.
|
||||||
onSubmit: () => this.deferSubmit(),
|
onSubmit: () => this.deferSubmit(),
|
||||||
@@ -673,6 +678,14 @@ export class NanobotTui {
|
|||||||
this.composerFrame.maxHeight = maxHeight + 2
|
this.composerFrame.maxHeight = maxHeight + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private syncComposerPlaceholder(): void {
|
||||||
|
// OpenTUI normally suppresses placeholder glyphs while the editor is not
|
||||||
|
// empty. Explicitly removing them also invalidates their old cells, which
|
||||||
|
// prevents stale placeholder text in differential/embedded terminals.
|
||||||
|
const placeholder = this.composer.plainText ? null : COMPOSER_PLACEHOLDER
|
||||||
|
if (this.composer.placeholder !== placeholder) this.composer.placeholder = placeholder
|
||||||
|
}
|
||||||
|
|
||||||
private async copySelection(text: string): Promise<void> {
|
private async copySelection(text: string): Promise<void> {
|
||||||
if (!text) return
|
if (!text) return
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user