Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
4.4 kB · 131 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132import chalk from 'chalk'import { ctrlOToExpand } from '../components/CtrlOToExpand.js'import { stringWidth } from '../ink/stringWidth.js'import sliceAnsi from './sliceAnsi.js'
// Text rendering utilities for terminal displayconst MAX_LINES_TO_SHOW = 3// Account for MessageResponse prefix (" ⎿ " = 5 chars) + parent width// reduction (columns - 5 in tool result rendering)const PADDING_TO_PREVENT_OVERFLOW = 10
/** * Inserts newlines in a string to wrap it at the specified width. * Uses ANSI-aware slicing to avoid splitting escape sequences. * @param text The text to wrap. * @param wrapWidth The width at which to wrap lines (in visible characters). * @returns The wrapped text. */function wrapText( text: string, wrapWidth: number,): { aboveTheFold: string; remainingLines: number } { const lines = text.split('\n') const wrappedLines: string[] = []
for (const line of lines) { const visibleWidth = stringWidth(line) if (visibleWidth <= wrapWidth) { wrappedLines.push(line.trimEnd()) } else { // Break long lines into chunks of wrapWidth visible characters // using ANSI-aware slicing to preserve escape sequences let position = 0 while (position < visibleWidth) { const chunk = sliceAnsi(line, position, position + wrapWidth) wrappedLines.push(chunk.trimEnd()) position += wrapWidth } } }
const remainingLines = wrappedLines.length - MAX_LINES_TO_SHOW
// If there's only 1 line after the fold, show it directly // instead of showing "... +1 line (ctrl+o to expand)" if (remainingLines === 1) { return { aboveTheFold: wrappedLines .slice(0, MAX_LINES_TO_SHOW + 1) .join('\n') .trimEnd(), remainingLines: 0, // All lines are shown, nothing remaining } }
// Otherwise show the standard MAX_LINES_TO_SHOW return { aboveTheFold: wrappedLines.slice(0, MAX_LINES_TO_SHOW).join('\n').trimEnd(), remainingLines: Math.max(0, remainingLines), }}
/** * Renders the content with line-based truncation for terminal display. * If the content exceeds the maximum number of lines, it truncates the content * and adds a message indicating the number of additional lines. * @param content The content to render. * @param terminalWidth Terminal width for wrapping lines. * @returns The rendered content with truncation if needed. */export function renderTruncatedContent( content: string, terminalWidth: number, suppressExpandHint = false,): string { const trimmedContent = content.trimEnd() if (!trimmedContent) { return '' }
const wrapWidth = Math.max(terminalWidth - PADDING_TO_PREVENT_OVERFLOW, 10)
// Only process enough content for the visible lines. Avoids O(n) wrapping // on huge outputs (e.g. 64MB binary dumps that cause 382K-row screens). const maxChars = MAX_LINES_TO_SHOW * wrapWidth * 4 const preTruncated = trimmedContent.length > maxChars const contentForWrapping = preTruncated ? trimmedContent.slice(0, maxChars) : trimmedContent
const { aboveTheFold, remainingLines } = wrapText( contentForWrapping, wrapWidth, )
const estimatedRemaining = preTruncated ? Math.max( remainingLines, Math.ceil(trimmedContent.length / wrapWidth) - MAX_LINES_TO_SHOW, ) : remainingLines
return [ aboveTheFold, estimatedRemaining > 0 ? chalk.dim( `… +${estimatedRemaining} lines${suppressExpandHint ? '' : ` ${ctrlOToExpand()}`}`, ) : '', ] .filter(Boolean) .join('\n')}
/** Fast check: would OutputLine truncate this content? Counts raw newlines * only (ignores terminal-width wrapping), so it may return false for a single * very long line that wraps past 3 visual rows — acceptable, since the common * case is multi-line output. */export function isOutputLineTruncated(content: string): boolean { let pos = 0 // Need more than MAX_LINES_TO_SHOW newlines (content fills > 3 lines). // The +1 accounts for wrapText showing an extra line when remainingLines==1. for (let i = 0; i <= MAX_LINES_TO_SHOW; i++) { pos = content.indexOf('\n', pos) if (pos === -1) return false pos++ } // A trailing newline is a terminator, not a new line — match // renderTruncatedContent's trimEnd() behavior. return pos < content.length}