Skip to content

Commit 557fe83

Browse files
committed
Add wrapOnWordBoundary option (#125)
1 parent 3950b7f commit 557fe83

File tree

7 files changed

+111
-23
lines changed

7 files changed

+111
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ unmaintained. `cli-table3` includes all the additional features from
1919
- Ability to make cells span columns and/or rows.
2020
- Ability to set custom styles per cell (border characters/colors, padding, etc).
2121
- Vertical alignment (top, bottom, center).
22-
- Automatic word wrapping.
22+
- [Word wrapping options](./basic-usage.md#set-wordwrap-to-true-to-wrap-text-on-word-boundaries).
2323
- More robust truncation of cell text that contains ansi color characters.
2424
- Better handling of text color that spans multiple lines.
2525
- API compatible with the original cli-table.

basic-usage.md

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,44 @@
125125
```
126126

127127

128-
##### Set `wordWrap` to true to make lines of text wrap instead of being truncated
129-
┌───────┬─────────┐
130-
│ Hello │ I am │
131-
│ how │ fine │
132-
│ are │ thanks! │
133-
│ you? │
134-
└───────┴─────────┘
128+
##### Set `wordWrap` to true to wrap text on word boundaries
129+
┌───────┬─────────┬───────────────────┬──────────────
130+
│ Hello │ I am │ Words that exceed │ Text is only │
131+
│ how │ fine │ the colWidth will │ wrapped for │
132+
│ are │ thanks! │ be truncated. │ fixed width │
133+
│ you? │ Looooo… │ │ columns.
134+
└───────┴─────────┴───────────────────┴──────────────
135135
```javascript
136136
let table = new Table({
137137
style: { border: [], header: [] },
138-
colWidths: [7, 9],
138+
colWidths: [7, 9], // Requires fixed column widths
139139
wordWrap: true,
140140
});
141141

142-
table.push(['Hello how are you?', 'I am fine thanks!']);
142+
table.push([
143+
'Hello how are you?',
144+
'I am fine thanks! Looooooong',
145+
['Words that exceed', 'the colWidth will', 'be truncated.'].join('\n'),
146+
['Text is only', 'wrapped for', 'fixed width', 'columns.'].join('\n'),
147+
]);
143148

144149
```
145150

151+
152+
##### Using `wordWrap`, set `wrapOnWordBoundary` to false to ignore word boundaries
153+
┌───┬───┐
154+
│ W │ T │
155+
│ r │ e │
156+
│ a │ x │
157+
│ p │ t │
158+
└───┴───┘
159+
```javascript
160+
const table = new Table({
161+
style: { border: [], header: [] },
162+
colWidths: [3, 3], // colWidths must all be greater than 2!!!!
163+
wordWrap: true,
164+
wrapOnWordBoundary: false,
165+
});
166+
table.push(['Wrap', 'Text']);
167+
```
168+

examples/basic-usage-examples.js

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,55 @@ module.exports = function (runTest) {
182182
return [makeTable, expected, 'multi-line-colors'];
183183
});
184184

185-
it('Set `wordWrap` to true to make lines of text wrap instead of being truncated', function () {
185+
it('Set `wordWrap` to true to wrap text on word boundaries', function () {
186186
function makeTable() {
187187
let table = new Table({
188188
style: { border: [], header: [] },
189-
colWidths: [7, 9],
189+
colWidths: [7, 9], // Requires fixed column widths
190190
wordWrap: true,
191191
});
192192

193-
table.push(['Hello how are you?', 'I am fine thanks!']);
193+
table.push([
194+
'Hello how are you?',
195+
'I am fine thanks! Looooooong',
196+
['Words that exceed', 'the colWidth will', 'be truncated.'].join('\n'),
197+
['Text is only', 'wrapped for', 'fixed width', 'columns.'].join('\n'),
198+
]);
194199

195200
return table;
196201
}
197202

198203
let expected = [
199-
'┌───────┬─────────┐',
200-
'│ Hello │ I am │',
201-
'│ how │ fine │',
202-
'│ are │ thanks! │',
203-
'│ you? │ │',
204-
'└───────┴─────────┘',
204+
'┌───────┬─────────┬───────────────────┬──────────────┐',
205+
'│ Hello │ I am │ Words that exceed │ Text is only │',
206+
'│ how │ fine │ the colWidth will │ wrapped for │',
207+
'│ are │ thanks! │ be truncated. │ fixed width │',
208+
'│ you? │ Looooo… │ │ columns. │',
209+
'└───────┴─────────┴───────────────────┴──────────────┘',
210+
];
211+
212+
return [makeTable, expected];
213+
});
214+
215+
it('Using `wordWrap`, set `wrapOnWordBoundary` to false to ignore word boundaries', function () {
216+
function makeTable() {
217+
const table = new Table({
218+
style: { border: [], header: [] },
219+
colWidths: [3, 3], // colWidths must all be greater than 2!!!!
220+
wordWrap: true,
221+
wrapOnWordBoundary: false,
222+
});
223+
table.push(['Wrap', 'Text']);
224+
return table;
225+
}
226+
227+
let expected = [
228+
'┌───┬───┐',
229+
'│ W │ T │',
230+
'│ r │ e │',
231+
'│ a │ x │',
232+
'│ p │ t │',
233+
'└───┴───┘',
205234
];
206235

207236
return [makeTable, expected];

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ declare namespace CliTable3 {
2727
rowAligns: VerticalAlignment[];
2828
head: string[];
2929
wordWrap: boolean;
30+
wrapOnWordBoundary: boolean;
3031
}
3132

3233
interface TableInstanceOptions extends TableOptions {

src/cell.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class Cell {
5858
this.border = style.border || tableStyle.border;
5959

6060
let fixedWidth = tableOptions.colWidths[this.x];
61-
if (tableOptions.wordWrap && fixedWidth) {
61+
if ((tableOptions.wordWrap || tableOptions.textWrap) && fixedWidth) {
6262
fixedWidth -= this.paddingLeft + this.paddingRight;
6363
if (this.colSpan) {
6464
let i = 1;
@@ -67,7 +67,8 @@ class Cell {
6767
i++;
6868
}
6969
}
70-
this.lines = utils.colorizeLines(utils.wordWrap(fixedWidth, this.content));
70+
const { wrapOnWordBoundary = true } = tableOptions;
71+
this.lines = utils.colorizeLines(utils.wordWrap(fixedWidth, this.content, wrapOnWordBoundary));
7172
} else {
7273
this.lines = utils.colorizeLines(this.content.split('\n'));
7374
}

src/utils.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ function mergeOptions(options, defaults) {
240240
return ret;
241241
}
242242

243+
// Wrap on word boundary
243244
function wordWrap(maxLength, input) {
244245
let lines = [];
245246
let split = input.split(/(\s+)/g);
@@ -270,11 +271,32 @@ function wordWrap(maxLength, input) {
270271
return lines;
271272
}
272273

273-
function multiLineWordWrap(maxLength, input) {
274+
// Wrap text (ignoring word boundaries)
275+
function textWrap(maxLength, input) {
276+
let lines = [];
277+
let line = '';
278+
function pushLine(str, ws) {
279+
if (line.length && ws) line += ws;
280+
line += str;
281+
while (line.length > maxLength) {
282+
lines.push(line.slice(0, maxLength));
283+
line = line.slice(maxLength);
284+
}
285+
}
286+
let split = input.split(/(\s+)/g);
287+
for (let i = 0; i < split.length; i += 2) {
288+
pushLine(split[i], i && split[i - 1]);
289+
}
290+
if (line.length) lines.push(line);
291+
return lines;
292+
}
293+
294+
function multiLineWordWrap(maxLength, input, wrapOnWordBoundary = true) {
274295
let output = [];
275296
input = input.split('\n');
297+
const handler = wrapOnWordBoundary ? wordWrap : textWrap;
276298
for (let i = 0; i < input.length; i++) {
277-
output.push.apply(output, wordWrap(maxLength, input[i]));
299+
output.push.apply(output, handler(maxLength, input[i]));
278300
}
279301
return output;
280302
}

test/utils-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,18 @@ describe('utils', function () {
322322
let expected = ['\x1b[31m漢字\x1b[0m', ' 漢字'];
323323
expect(wordWrap(5, input)).toEqual(expected);
324324
});
325+
326+
describe('textWrap', function () {
327+
it('wraps long words', function () {
328+
expect(wordWrap(10, 'abcdefghijklmnopqrstuvwxyz', false)).toEqual(['abcdefghij', 'klmnopqrst', 'uvwxyz']);
329+
expect(wordWrap(10, 'abcdefghijk lmnopqrstuv wxyz', false)).toEqual(['abcdefghij', 'k lmnopqrs', 'tuv wxyz']);
330+
expect(wordWrap(10, 'ab cdefghijk lmnopqrstuv wx yz', false)).toEqual([
331+
'ab cdefghi',
332+
'jk lmnopqr',
333+
'stuv wx yz',
334+
]);
335+
});
336+
});
325337
});
326338

327339
describe('colorizeLines', function () {

0 commit comments

Comments
 (0)