MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / compositeOverlays

Method compositeOverlays

packages/pi-tui/src/tui.ts:1042–1101  ·  view source on GitHub ↗

Composite all overlays into content lines (sorted by focusOrder, higher = on top).

(lines: string[], termWidth: number, termHeight: number)

Source from the content-addressed store, hash-verified

1040
1041 /** Composite all overlays into content lines (sorted by focusOrder, higher = on top). */
1042 private compositeOverlays(lines: string[], termWidth: number, termHeight: number): string[] {
1043 if (this.overlayStack.length === 0) return lines;
1044 const result = [...lines];
1045
1046 // Pre-render all visible overlays and calculate positions
1047 const rendered: { overlayLines: string[]; row: number; col: number; w: number }[] = [];
1048 let minLinesNeeded = result.length;
1049
1050 const visibleEntries = this.overlayStack.filter((e) => this.isOverlayVisible(e));
1051 visibleEntries.sort((a, b) => a.focusOrder - b.focusOrder);
1052 for (const entry of visibleEntries) {
1053 const { component, options } = entry;
1054
1055 // Get layout with height=0 first to determine width and maxHeight
1056 // (width and maxHeight don't depend on overlay height)
1057 const { width, maxHeight } = this.resolveOverlayLayout(options, 0, termWidth, termHeight);
1058
1059 // Render component at calculated width
1060 let overlayLines = component.render(width);
1061
1062 // Apply maxHeight if specified
1063 if (maxHeight !== undefined && overlayLines.length > maxHeight) {
1064 overlayLines = overlayLines.slice(0, maxHeight);
1065 }
1066
1067 // Get final row/col with actual overlay height
1068 const { row, col } = this.resolveOverlayLayout(options, overlayLines.length, termWidth, termHeight);
1069
1070 rendered.push({ overlayLines, row, col, w: width });
1071 minLinesNeeded = Math.max(minLinesNeeded, row + overlayLines.length);
1072 }
1073
1074 // Pad to at least terminal height so overlays have screen-relative positions.
1075 // Excludes maxLinesRendered: the historical high-water mark caused self-reinforcing
1076 // inflation that pushed content into scrollback on terminal widen.
1077 const workingHeight = Math.max(result.length, termHeight, minLinesNeeded);
1078
1079 // Extend result with empty lines if content is too short for overlay placement or working area
1080 while (result.length < workingHeight) {
1081 result.push("");
1082 }
1083
1084 const viewportStart = Math.max(0, workingHeight - termHeight);
1085
1086 // Composite each overlay
1087 for (const { overlayLines, row, col, w } of rendered) {
1088 for (let i = 0; i < overlayLines.length; i++) {
1089 const idx = viewportStart + row + i;
1090 if (idx >= 0 && idx < result.length) {
1091 // Defensive: truncate overlay line to declared width before compositing
1092 // (components should already respect width, but this ensures it)
1093 const truncatedOverlayLine =
1094 visibleWidth(overlayLines[i]!) > w ? sliceByColumn(overlayLines[i]!, 0, w, true) : overlayLines[i]!;
1095 result[idx] = this.compositeLineAt(result[idx]!, truncatedOverlayLine, col, w, termWidth);
1096 }
1097 }
1098 }
1099

Callers 1

doRenderMethod · 0.95

Calls 7

isOverlayVisibleMethod · 0.95
resolveOverlayLayoutMethod · 0.95
compositeLineAtMethod · 0.95
visibleWidthFunction · 0.90
sliceByColumnFunction · 0.90
renderMethod · 0.65
pushMethod · 0.45

Tested by

no test coverage detected