diff --git a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/break_classes.json b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/break_classes.json index 2a17f9f03550..778b02d022ad 100644 --- a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/break_classes.json +++ b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/break_classes.json @@ -8,6 +8,8 @@ "]": "CL", "}": "CL", "`": "QU", + "'": "QU", + "\"": "QU", ".": "IS", ",": "IS", ":": "IS", diff --git a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/main.js b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/main.js index 1822b467715e..4a0c38362b5b 100644 --- a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/main.js +++ b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/lib/main.js @@ -29,6 +29,28 @@ var BREAK_CLASSES = require( './break_classes.json' ); // FUNCTIONS // +/** +* Determines whether a character at a specified position opens a quoted span. +* +* @private +* @param {string} text - input string +* @param {NonNegativeInteger} idx - character position +* @param {(string|null)} prev - break class of preceding character +* @returns {boolean} whether the character opens a quoted span +*/ +function isQuoteStart( text, idx, prev ) { + var ch = text.charAt( idx ); + if ( BREAK_CLASSES[ ch ] !== 'QU' ) { + return false; + } + // A quote character only opens a span at the start of a line or when following a space or open punctuation (e.g., an apostrophe in a contraction does not open a span): + if ( prev !== null && prev !== 'SP' && prev !== 'OP' ) { + return false; + } + // Require a matching closing character in order to avoid treating the remainder of a line as unbreakable: + return text.indexOf( ch, idx+1 ) !== -1; +} + /** * Determines whether a break opportunity exists between two adjacent characters. * @@ -74,23 +96,37 @@ function canBreak( prev, next ) { */ function findBreakUnits( text ) { var segments; + var quote; var start; var prev; var curr; var len; + var ch; var i; len = text.length; segments = []; start = 0; - prev = BREAK_CLASSES[ text.charAt( 0 ) ] || 'AL'; - + ch = text.charAt( 0 ); + prev = BREAK_CLASSES[ ch ] || 'AL'; + quote = ''; + if ( isQuoteStart( text, 0, null ) ) { + quote = ch; + } for ( i = 1; i < len; i++ ) { - curr = BREAK_CLASSES[ text.charAt( i ) ] || 'AL'; - if ( canBreak( prev, curr ) ) { + ch = text.charAt( i ); + curr = BREAK_CLASSES[ ch ] || 'AL'; + + // Suppress break opportunities within quoted spans so that a span is always kept intact: + if ( quote === '' && canBreak( prev, curr ) ) { segments.push( text.substring( start, i ) ); start = i; } + if ( quote === ch ) { + quote = ''; + } else if ( quote === '' && isQuoteStart( text, i, prev ) ) { + quote = ch; + } prev = curr; } segments.push( text.substring( start ) ); diff --git a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/test/test.js b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/test/test.js index 0b3dc743527e..5a00c2ed66d4 100644 --- a/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/test/test.js +++ b/lib/node_modules/@stdlib/_tools/repl-txt/wrap-text/test/test.js @@ -237,6 +237,153 @@ tape( 'the function breaks at hyphens', function test( t ) { t.end(); }); +tape( 'the function does not break within backtick-delimited spans', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'Beep boop `-1`'; + + expected = ' Beep boop\n `-1`'; + + actual = wrap( txt, { + 'indent': 4, + 'maxWidth': 16 + }); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function does not break within single-quoted spans', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'Beep boop \'hello world\''; + + expected = ' Beep boop\n \'hello world\''; + + actual = wrap( txt, { + 'indent': 4, + 'maxWidth': 20 + }); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function does not break within double-quoted spans', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'Beep boop "hello world"'; + + expected = ' Beep boop\n "hello world"'; + + actual = wrap( txt, { + 'indent': 4, + 'maxWidth': 20 + }); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function does not treat an apostrophe within a word as opening a quoted span', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'The function doesn\'t break when a word\'s apostrophe appears mid-sentence.'; + + expected = ' The function doesn\'t break when a\n word\'s apostrophe appears mid-\n sentence.'; + + actual = wrap( txt, { + 'indent': 4, + 'maxWidth': 40 + }); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function ignores unmatched quote characters', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'An unmatched ` backtick must not prevent wrapping of subsequent text.'; + + expected = ' An unmatched ` backtick must not\n prevent wrapping of subsequent text.'; + + actual = wrap( txt, { + 'indent': 4, + 'maxWidth': 40 + }); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function wraps text containing quoted spans', function test( t ) { + var expected; + var actual; + var txt; + + txt = 'Rendering mode. If `true`, an instance renders on each \'change\' event; otherwise, rendering must be triggered manually.'; + + expected = ' Rendering mode. If `true`, an instance renders on each \'change\' event;\n otherwise, rendering must be triggered manually.'; + + actual = wrap( txt ); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + +tape( 'the function preserves table rows and does not break quoted spans', function test( t ) { + var expected; + var actual; + var txt; + + txt = [ + 'Returns a sparkline up/down chart instance.', + '', + 'Glyphs:', + '', + '| Value | Glyph |', + '|:-----:|:-----:|', + '| 1 | ↑ |', + '| -1 | ↓ |', + '', + 'If provided any other value other than 1 or `-1`, the value is encoded as a missing value.', + '', + 'The `data` argument takes precedence over the `data` option.' + ].join( '\n' ); + + expected = [ + ' Returns a sparkline up/down chart instance.', + '', + ' Glyphs:', + '', + ' | Value | Glyph |', + ' |:-----:|:-----:|', + ' | 1 | ↑ |', + ' | -1 | ↓ |', + '', + ' If provided any other value other than 1 or `-1`, the value is encoded as a', + ' missing value.', + '', + ' The `data` argument takes precedence over the `data` option.' + ].join( '\n' ); + + actual = wrap( txt ); + + t.strictEqual( actual, expected, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports custom indent levels', function test( t ) { var expected; var actual;