mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 19:04:37 +00:00
fix(tui): reduce unnecessary full redraws for better performance
- Remove height change detection (only width changes trigger full redraw) - Change clearOnShrink default to false (use PI_CLEAR_ON_SHRINK=1 to enable) - Fix viewport check to use previousLines.length instead of maxLinesRendered (prevents false positive redraws when appending lines after content shrunk) - Add clearOnShrink setting to /settings in coding-agent - Remove line truncation in custom message component (always show full content)
This commit is contained in:
parent
419c07fb19
commit
0925fafe3b
8 changed files with 80 additions and 48 deletions
|
|
@ -199,7 +199,6 @@ export class TUI extends Container {
|
|||
public terminal: Terminal;
|
||||
private previousLines: string[] = [];
|
||||
private previousWidth = 0;
|
||||
private previousHeight = 0;
|
||||
private focusedComponent: Component | null = null;
|
||||
|
||||
/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */
|
||||
|
|
@ -210,6 +209,7 @@ export class TUI extends Container {
|
|||
private inputBuffer = ""; // Buffer for parsing terminal responses
|
||||
private cellSizeQueryPending = false;
|
||||
private showHardwareCursor = process.env.PI_HARDWARE_CURSOR === "1";
|
||||
private clearOnShrink = process.env.PI_CLEAR_ON_SHRINK === "1"; // Clear empty rows when content shrinks (default: off)
|
||||
private maxLinesRendered = 0; // Track terminal's working area (max lines ever rendered)
|
||||
private previousViewportTop = 0; // Track previous viewport top for resize-aware cursor moves
|
||||
private fullRedrawCount = 0;
|
||||
|
|
@ -248,6 +248,19 @@ export class TUI extends Container {
|
|||
this.requestRender();
|
||||
}
|
||||
|
||||
getClearOnShrink(): boolean {
|
||||
return this.clearOnShrink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to trigger full re-render when content shrinks.
|
||||
* When true (default), empty rows are cleared when content shrinks.
|
||||
* When false, empty rows remain (reduces redraws on slower terminals).
|
||||
*/
|
||||
setClearOnShrink(enabled: boolean): void {
|
||||
this.clearOnShrink = enabled;
|
||||
}
|
||||
|
||||
setFocus(component: Component | null): void {
|
||||
// Clear focused flag on old component
|
||||
if (isFocusable(this.focusedComponent)) {
|
||||
|
|
@ -397,7 +410,6 @@ export class TUI extends Container {
|
|||
if (force) {
|
||||
this.previousLines = [];
|
||||
this.previousWidth = -1; // -1 triggers widthChanged, forcing a full clear
|
||||
this.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear
|
||||
this.cursorRow = 0;
|
||||
this.hardwareCursorRow = 0;
|
||||
this.maxLinesRendered = 0;
|
||||
|
|
@ -827,9 +839,8 @@ export class TUI extends Container {
|
|||
|
||||
newLines = this.applyLineResets(newLines);
|
||||
|
||||
// Width or height changed - need full re-render
|
||||
// Width changed - need full re-render (line wrapping changes)
|
||||
const widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;
|
||||
const heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;
|
||||
|
||||
// Helper to clear scrollback and viewport and render all new lines
|
||||
const fullRender = (clear: boolean): void => {
|
||||
|
|
@ -854,24 +865,24 @@ export class TUI extends Container {
|
|||
this.positionHardwareCursor(cursorPos, newLines.length);
|
||||
this.previousLines = newLines;
|
||||
this.previousWidth = width;
|
||||
this.previousHeight = height;
|
||||
};
|
||||
|
||||
// First render - just output everything without clearing (assumes clean screen)
|
||||
if (this.previousLines.length === 0 && !widthChanged && !heightChanged) {
|
||||
if (this.previousLines.length === 0 && !widthChanged) {
|
||||
fullRender(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Width or height changed - full re-render
|
||||
if (widthChanged || heightChanged) {
|
||||
// Width changed - full re-render (line wrapping changes)
|
||||
if (widthChanged) {
|
||||
fullRender(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Content shrunk below the working area and no overlays - re-render to clear empty rows
|
||||
// (overlays need the padding, so only do this when no overlays are active)
|
||||
if (newLines.length < this.maxLinesRendered && this.overlayStack.length === 0) {
|
||||
// Configurable via setClearOnShrink() or PI_CLEAR_ON_SHRINK=0 env var
|
||||
if (this.clearOnShrink && newLines.length < this.maxLinesRendered && this.overlayStack.length === 0) {
|
||||
fullRender(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -941,15 +952,15 @@ export class TUI extends Container {
|
|||
this.positionHardwareCursor(cursorPos, newLines.length);
|
||||
this.previousLines = newLines;
|
||||
this.previousWidth = width;
|
||||
this.previousHeight = height;
|
||||
this.previousViewportTop = Math.max(0, this.maxLinesRendered - height);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if firstChanged is outside the viewport
|
||||
// Viewport is based on max lines ever rendered (terminal's working area)
|
||||
if (firstChanged < viewportTop) {
|
||||
// First change is above viewport - need full re-render
|
||||
// Check if firstChanged is above what was previously visible
|
||||
// Use previousLines.length (not maxLinesRendered) to avoid false positives after content shrinks
|
||||
const previousContentViewportTop = Math.max(0, this.previousLines.length - height);
|
||||
if (firstChanged < previousContentViewportTop) {
|
||||
// First change is above previous viewport - need full re-render
|
||||
fullRender(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1088,7 +1099,6 @@ export class TUI extends Container {
|
|||
|
||||
this.previousLines = newLines;
|
||||
this.previousWidth = width;
|
||||
this.previousHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue