pixl-cli 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +3 -1
  2. package/cli.js +11 -7
  3. package/package.json +1 -1
  4. package/util.js +29 -1
package/README.md CHANGED
@@ -20,6 +20,8 @@
20
20
  * [Displaying Info Boxes](#displaying-info-boxes)
21
21
  + [Centering Text](#centering-text)
22
22
  + [Word-Wrapping Text](#word-wrapping-text)
23
+ * [Displaying Definition Lists](#displaying-definition-lists)
24
+ * [Displaying Dashboard Grids](#displaying-dashboard-grids)
23
25
  * [Displaying Tables](#displaying-tables)
24
26
  * [Graphical Progress Bars](#graphical-progress-bars)
25
27
  + [Configuration](#configuration)
@@ -491,7 +493,7 @@ You can customize the dashboard grid with these options:
491
493
  | `unitWidth` | Target outer width used to select the responsive column count. Defaults to `20`. |
492
494
  | `minCols` | Preferred minimum number of columns. Defaults to `3`. Extremely narrow terminals may use fewer to avoid overflow. |
493
495
  | `maxCols` | Maximum number of columns. Defaults to `5`. |
494
- | `gap` | Horizontal spaces between units and blank lines between grid rows. Defaults to `1`. |
496
+ | `gap` | Horizontal spaces between units. Grid rows use `gap - 1` blank lines. Defaults to `1`, producing no vertical blank line. |
495
497
  | `indent` | Horizontal margin in characters on both sides of the grid. Defaults to `0`. |
496
498
  | `valueStyles` | An array of [chalk](https://www.npmjs.com/package/chalk) styles or functions for values. Defaults to `["bold"]`. |
497
499
  | `labelStyles` | An array of styles or functions for labels. Defaults to `["gray"]`. |
package/cli.js CHANGED
@@ -176,7 +176,11 @@ var cli = module.exports = {
176
176
  output.push( indent + this.applyStyles("┌" + this.repeat("─", width) + "┐", styles) );
177
177
 
178
178
  // left, content, right
179
- var lines = text.split(/\n/);
179
+ // Styled text normally carries its SGR modes across newlines, but the styled
180
+ // right border resets those modes before the next content line. Make each
181
+ // line self-contained before inserting borders between them.
182
+ var safeText = (styles && styles.length) ? Util.preserveAnsiLineStyles(text) : text;
183
+ var lines = safeText.split(/\n/);
180
184
  while (vspace-- > 0) {
181
185
  lines.unshift( "" );
182
186
  lines.push( "" );
@@ -290,7 +294,7 @@ var cli = module.exports = {
290
294
 
291
295
  dashGrid: function(rows, args) {
292
296
  // Render a responsive grid of equal-sized dashboard units. Each unit has a
293
- // centered value, a centered label, two blank spacer rows and its own border.
297
+ // centered value, a centered label, a blank spacer row and its own border.
294
298
  var self = this;
295
299
  if (!rows || !rows.length) return '';
296
300
  if (!args) args = {};
@@ -375,7 +379,7 @@ var cli = module.exports = {
375
379
  } );
376
380
 
377
381
  var renderUnit = function(unit) {
378
- // The interior layout is: blank, value, blank, label.
382
+ // The interior layout is: value, blank, label.
379
383
  var top = self.applyStyles(
380
384
  '┌' + self.repeat('─', innerWidth) + '┐', borderStyles
381
385
  );
@@ -388,7 +392,6 @@ var cli = module.exports = {
388
392
 
389
393
  return [
390
394
  top,
391
- // blank,
392
395
  leftBorder + centerCell(truncate(unit.value)) + rightBorder,
393
396
  blank,
394
397
  leftBorder + centerCell(truncate(unit.label)) + rightBorder,
@@ -401,7 +404,7 @@ var cli = module.exports = {
401
404
  var gridRow = units.slice(rowIdx, rowIdx + numCols).map(renderUnit);
402
405
 
403
406
  // Join corresponding lines from each unit to form one complete grid row.
404
- for (var lineIdx = 0; lineIdx < 6; lineIdx++) {
407
+ for (var lineIdx = 0; lineIdx < gridRow[0].length; lineIdx++) {
405
408
  output.push(
406
409
  indent + gridRow.map( function(unit) {
407
410
  return unit[lineIdx];
@@ -409,9 +412,10 @@ var cli = module.exports = {
409
412
  );
410
413
  }
411
414
 
412
- // The same gap controls vertical blank lines between rows of units.
415
+ // Adjacent text lines already provide one row of vertical separation, so
416
+ // subtract one when translating the horizontal gap into blank lines.
413
417
  if (rowIdx + numCols < units.length) {
414
- for (var gapIdx = 0; gapIdx < gap; gapIdx++) output.push('');
418
+ for (var gapIdx = 0; gapIdx < Math.max(0, gap - 1); gapIdx++) output.push('');
415
419
  }
416
420
  }
417
421
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixl-cli",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Tools for building command-line apps for Node.js.",
5
5
  "author": "Joseph Huckaby <jhuckaby@gmail.com>",
6
6
  "homepage": "https://github.com/jhuckaby/pixl-cli",
package/util.js CHANGED
@@ -32,8 +32,36 @@ function splitAnsiGraphemes(text) {
32
32
  return units;
33
33
  }
34
34
 
35
+ function preserveAnsiLineStyles(text) {
36
+ // A styled multi-line string normally relies on terminal modes carrying across
37
+ // newline characters. Callers such as cli.box() insert independently styled
38
+ // borders between those lines, whose reset codes can cancel the content styles.
39
+ // Close all modes at each line ending, then restore the exact SGR state after the
40
+ // next border by replaying the original SGR history at the next line's start.
41
+ var lines = text.split('\n');
42
+ if (lines.length < 2) return text;
43
+
44
+ var sgrHistory = '';
45
+ var sgrPattern = /^(?:\u001B\[|\u009B)[0-9:;]*m$/;
46
+ var reset = '\u001b[0m';
47
+
48
+ return lines.map( function(line, idx) {
49
+ var reopen = sgrHistory;
50
+
51
+ // Only sequences from the original text enter the history. Synthetic reset
52
+ // and replay sequences added here must not accumulate on subsequent lines.
53
+ splitAnsiGraphemes(line).forEach( function(unit) {
54
+ if (unit.ansi && unit.text.match(sgrPattern)) sgrHistory += unit.text;
55
+ } );
56
+
57
+ if ((idx < lines.length - 1) && sgrHistory) line += reset;
58
+ return reopen + line;
59
+ } ).join('\n');
60
+ }
61
+
35
62
  module.exports = {
36
63
  ansiPattern: ansiPattern,
37
64
  graphemeSegmenter: graphemeSegmenter,
38
- splitAnsiGraphemes: splitAnsiGraphemes
65
+ splitAnsiGraphemes: splitAnsiGraphemes,
66
+ preserveAnsiLineStyles: preserveAnsiLineStyles
39
67
  };