diff options
| author | Elvin <[email protected]> | 2025-07-15 19:35:03 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-15 23:35:03 +0000 |
| commit | 615748657aaf5c0b5d19c7ff046346a29275ed81 (patch) | |
| tree | bc56ecb5a8da3c0705e0de7c04d8f9e25e0bbc76 /packages/cli/src/ui/components/shared/MaxSizedBox.tsx | |
| parent | 222e362fc2b390ae8259de8d9507b8c239fb59e4 (diff) | |
Update MaxSizedBox.tsx (#2233)
Co-authored-by: Jacob Richman <[email protected]>
Co-authored-by: Scott Densmore <[email protected]>
Co-authored-by: Pascal Birchler <[email protected]>
Diffstat (limited to 'packages/cli/src/ui/components/shared/MaxSizedBox.tsx')
| -rw-r--r-- | packages/cli/src/ui/components/shared/MaxSizedBox.tsx | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/packages/cli/src/ui/components/shared/MaxSizedBox.tsx b/packages/cli/src/ui/components/shared/MaxSizedBox.tsx index eb5ef6b4..346472bf 100644 --- a/packages/cli/src/ui/components/shared/MaxSizedBox.tsx +++ b/packages/cli/src/ui/components/shared/MaxSizedBox.tsx @@ -432,8 +432,85 @@ function layoutInkElementAsStyledText( const availableWidth = maxWidth - noWrappingWidth; if (availableWidth < 1) { - // No room to render the wrapping segments. TODO(jacob314): consider an alternative fallback strategy. - output.push(nonWrappingContent); + // No room to render the wrapping segments. Truncate the non-wrapping + // content and append an ellipsis so the line always fits within maxWidth. + + // Handle line breaks in non-wrapping content when truncating + const lines: StyledText[][] = []; + let currentLine: StyledText[] = []; + let currentLineWidth = 0; + + for (const segment of nonWrappingContent) { + const textLines = segment.text.split('\n'); + textLines.forEach((text, index) => { + if (index > 0) { + // New line encountered, finish current line and start new one + lines.push(currentLine); + currentLine = []; + currentLineWidth = 0; + } + + if (text) { + const textWidth = stringWidth(text); + + // When there's no room for wrapping content, be very conservative + // For lines after the first line break, show only ellipsis if the text would be truncated + if (index > 0 && textWidth > 0) { + // This is content after a line break - just show ellipsis to indicate truncation + currentLine.push({ text: '…', props: {} }); + currentLineWidth = stringWidth('…'); + } else { + // This is the first line or a continuation, try to fit what we can + const maxContentWidth = Math.max(0, maxWidth - stringWidth('…')); + + if (textWidth <= maxContentWidth && currentLineWidth === 0) { + // Text fits completely on this line + currentLine.push({ text, props: segment.props }); + currentLineWidth += textWidth; + } else { + // Text needs truncation + const codePoints = toCodePoints(text); + let truncatedWidth = currentLineWidth; + let sliceEndIndex = 0; + + for (const char of codePoints) { + const charWidth = stringWidth(char); + if (truncatedWidth + charWidth > maxContentWidth) { + break; + } + truncatedWidth += charWidth; + sliceEndIndex++; + } + + const slice = codePoints.slice(0, sliceEndIndex).join(''); + if (slice) { + currentLine.push({ text: slice, props: segment.props }); + } + currentLine.push({ text: '…', props: {} }); + currentLineWidth = truncatedWidth + stringWidth('…'); + } + } + } + }); + } + + // Add the last line if it has content or if the last segment ended with \n + if ( + currentLine.length > 0 || + (nonWrappingContent.length > 0 && + nonWrappingContent[nonWrappingContent.length - 1].text.endsWith('\n')) + ) { + lines.push(currentLine); + } + + // If we don't have any lines yet, add an ellipsis line + if (lines.length === 0) { + lines.push([{ text: '…', props: {} }]); + } + + for (const line of lines) { + output.push(line); + } return; } |
