source dump of claude code
at main 74 lines 1.8 kB view raw
1import sliceAnsi from '../utils/sliceAnsi.js' 2import { stringWidth } from './stringWidth.js' 3import type { Styles } from './styles.js' 4import { wrapAnsi } from './wrapAnsi.js' 5 6const ELLIPSIS = '…' 7 8// sliceAnsi may include a boundary-spanning wide char (e.g. CJK at position 9// end-1 with width 2 overshoots by 1). Retry with a tighter bound once. 10function sliceFit(text: string, start: number, end: number): string { 11 const s = sliceAnsi(text, start, end) 12 return stringWidth(s) > end - start ? sliceAnsi(text, start, end - 1) : s 13} 14 15function truncate( 16 text: string, 17 columns: number, 18 position: 'start' | 'middle' | 'end', 19): string { 20 if (columns < 1) return '' 21 if (columns === 1) return ELLIPSIS 22 23 const length = stringWidth(text) 24 if (length <= columns) return text 25 26 if (position === 'start') { 27 return ELLIPSIS + sliceFit(text, length - columns + 1, length) 28 } 29 if (position === 'middle') { 30 const half = Math.floor(columns / 2) 31 return ( 32 sliceFit(text, 0, half) + 33 ELLIPSIS + 34 sliceFit(text, length - (columns - half) + 1, length) 35 ) 36 } 37 return sliceFit(text, 0, columns - 1) + ELLIPSIS 38} 39 40export default function wrapText( 41 text: string, 42 maxWidth: number, 43 wrapType: Styles['textWrap'], 44): string { 45 if (wrapType === 'wrap') { 46 return wrapAnsi(text, maxWidth, { 47 trim: false, 48 hard: true, 49 }) 50 } 51 52 if (wrapType === 'wrap-trim') { 53 return wrapAnsi(text, maxWidth, { 54 trim: true, 55 hard: true, 56 }) 57 } 58 59 if (wrapType!.startsWith('truncate')) { 60 let position: 'end' | 'middle' | 'start' = 'end' 61 62 if (wrapType === 'truncate-middle') { 63 position = 'middle' 64 } 65 66 if (wrapType === 'truncate-start') { 67 position = 'start' 68 } 69 70 return truncate(text, maxWidth, position) 71 } 72 73 return text 74}