import { lengthAnsi } from "./ansi.js" ; import type { IWordSplit , WordWrapOpts } from "./api.js" ; import { split } from "./split.js" ; internal class Line { n = 0 ; w : string [ ] = [ ] ; constructor ( word ? , n ? ) { word != null && this . add ( word , n ) ; } add ( word , n = word . length ) { this . w . push ( word ) ; this . n += n + ~ ~ ( this . n > 0 ) ; return this ; } toString ( ) { return this . w . join ( " " ) ; } } /**
 * (Default) wordwrap word splitting strategy for plain text.
 */ export const SPLIT_PLAIN = { length : ( x ) => x . length , split : ( _ , max ) => max , } ; /**
 * Wordwrap word splitting strategy for text containing ANSI control sequences.
 */ export const SPLIT_ANSI = { length : lengthAnsi , split : ( x , max ) => { const re = /\x1b\[[0-9;]+m/g ; let i = max ; let match ; while ( ( match = re . exec ( x ) ) ) { if ( match . index >= max ) break ; const n = match [ 0 ] . length ; i += n ; max += n ; } return i ; } , } ; internal const append = ( acc , word , wordLen , width ) => { const curr = acc [ acc . length - 1 ] ; curr && width - curr . n > wordLen ? curr . add ( word , wordLen ) : acc . push ( new Line ( word , wordLen ) ) ; } ; remarks Splitting uses the provided  IWordSplit impl (or, if missing,
 *  SPLIT_PLAIN ). If the current start line only has less than
 *  WordWrapOpts . min chars available and the word is longer than that, it
 * will be placed into a new line (thus minimizing legibility issues).
 *
 *  param word param opts param offset param acc internal const wrapWord = ( word , { width , min , hard , splitter } , offset = 0 , acc = [ ] ) => { let len = splitter . length ( word ) ; let free = width - offset ; if ( free < min && free < len ) { free = width ; } while ( hard && len > free ) { const split = splitter . split ( word , free ) ; const chunk = word . substr ( 0 , split ) ; append ( acc , chunk , free , width ) ; word = word . substr ( split ) ; free = width ; len = splitter . length ( word ) ; } append ( acc , word , len , width ) ; return acc ; } ; /**
 * Wordwraps a single-`line` string using provided options. Returns array of
 *  Line objects, which can simply be `.join("\n")`ed to convert back
 * into text.
 *
 *  see wordWrap for main user facing alternative.
 *
 *  param line param opts param acc internal export const wordWrapLine = ( line , opts , acc = [ ] ) => { if ( ! line . length ) { acc . push ( new Line ( ) ) ; return acc ; } const $opts = < WordWrapOpts > { width : 80 , min : 4 , hard : false , splitter : SPLIT_PLAIN , ... opts , } ; for ( let word of split ( line , opts . delimWord || /\s/g ) ) { const curr = acc [ acc . length - 1 ] ; wrapWord ( word , $opts , curr && curr . n > 0 ? curr . n + 1 : 0 , acc ) ; } return acc ; } ; /**
 * Wordwraps a multi-`line` string using provided options. Returns array of
 *  Line objects, which can simply be `.join("\n")`ed to convert back
 * into text.
 *
 *  see wordWrap for main user facing alternative.
 *
 *  param lines param opts export const wordWrapLines = ( lines , opts ) => { let acc = [ ] ; for ( let line of split ( lines , opts . delimLine ) ) { acc = acc . concat ( wordWrapLine ( line , opts ) ) ; } return acc ; } ; /**
 * Same as  wordWrapLines , but returns wordwrapped result as string. See
 *  WordWrapOpts for options.
 *
 *  param str param opts export const wordWrap = ( str , opts ) => wordWrapLines ( str , opts ) . join ( "\n" ) ;