fix: flush held text-run carry on a 16ms timer so shell prompts render immediately
The highlight stream holds a trailing text run for cross-chunk anchor consistency; a bare shell prompt (plain text, no follow-up data) stayed held until the next keypress. Now the carry auto-flushes within one frame.
This commit is contained in:
1 parent
551723c2d4
commit
db0eae5efd
2 files changed
+20
No files matched your search
@@ -319,9 +319,23 @@ export const TerminalView: ForwardRefExoticComponent<TerminalViewProps & { ref?:
|
|||||||
// across a sessionId rebind (e.g. template apply).
|
// across a sessionId rebind (e.g. template apply).
|
||||||
const stream = new HighlightStream(compiledRules)
|
const stream = new HighlightStream(compiledRules)
|
||||||
streamRef.current = stream
|
streamRef.current = stream
|
||||||
|
// The stream holds a trailing text run for cross-chunk anchor consistency.
|
||||||
|
// A shell prompt is exactly such a run with no follow-up data, so flush the
|
||||||
|
// carry on a short timer — prompts render within a frame, anchors survive.
|
||||||
|
let carryTimer: number | undefined
|
||||||
|
const scheduleCarryFlush = (): void => {
|
||||||
|
if (carryTimer !== undefined || !stream.hasPending()) return
|
||||||
|
carryTimer = window.setTimeout(() => {
|
||||||
|
carryTimer = undefined
|
||||||
|
if (deadRef.current) return
|
||||||
|
const rest = stream.flush()
|
||||||
|
if (rest) term.write(rest)
|
||||||
|
}, 16)
|
||||||
|
}
|
||||||
const writeHighlighted = (data: string) => {
|
const writeHighlighted = (data: string) => {
|
||||||
const out = stream.push(data)
|
const out = stream.push(data)
|
||||||
if (out) term.write(out)
|
if (out) term.write(out)
|
||||||
|
scheduleCarryFlush()
|
||||||
}
|
}
|
||||||
const disposables: { dispose(): void }[] = [
|
const disposables: { dispose(): void }[] = [
|
||||||
term.onData((data) => {
|
term.onData((data) => {
|
||||||
@@ -375,6 +389,7 @@ export const TerminalView: ForwardRefExoticComponent<TerminalViewProps & { ref?:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
if (carryTimer !== undefined) window.clearTimeout(carryTimer)
|
||||||
for (const unsubscribe of unsubscribes) unsubscribe()
|
for (const unsubscribe of unsubscribes) unsubscribe()
|
||||||
for (const disposable of disposables) disposable.dispose()
|
for (const disposable of disposables) disposable.dispose()
|
||||||
observer?.disconnect()
|
observer?.disconnect()
|
||||||
|
|||||||
@@ -240,6 +240,11 @@ export class HighlightStream {
|
|||||||
this.rules = rules
|
this.rules = rules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** True while content is held back (a pending flush will release it). */
|
||||||
|
hasPending(): boolean {
|
||||||
|
return this.buffer.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
/** Join held bytes with `chunk`, return content safe to hand to xterm. */
|
/** Join held bytes with `chunk`, return content safe to hand to xterm. */
|
||||||
push(chunk: string): string {
|
push(chunk: string): string {
|
||||||
this.buffer += chunk
|
this.buffer += chunk
|
||||||
|
|||||||
Reference in new issue
Block a user