wrap-ansi 0.1.0 → 2.0.0

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 (3) hide show
  1. package/index.js +139 -15
  2. package/package.json +9 -4
  3. package/readme.md +16 -5
package/index.js CHANGED
@@ -1,18 +1,65 @@
1
1
  'use strict';
2
- var spliceString = require('splice-string');
2
+ var stringWidth = require('string-width');
3
3
 
4
- module.exports = function (str, cols) {
5
- var ret = '';
4
+ var ESCAPES = [
5
+ '\u001b',
6
+ '\u009b'
7
+ ];
8
+
9
+ var END_CODE = 39;
10
+
11
+ var ESCAPE_CODES = {
12
+ 0: 0,
13
+ 1: 22,
14
+ 2: 22,
15
+ 3: 23,
16
+ 4: 24,
17
+ 7: 27,
18
+ 8: 28,
19
+ 9: 29,
20
+ 30: 39,
21
+ 31: 39,
22
+ 32: 39,
23
+ 33: 39,
24
+ 34: 39,
25
+ 35: 39,
26
+ 36: 39,
27
+ 37: 39,
28
+ 90: 39,
29
+ 40: 49,
30
+ 41: 49,
31
+ 42: 49,
32
+ 43: 49,
33
+ 44: 49,
34
+ 45: 49,
35
+ 46: 49,
36
+ 47: 49
37
+ };
38
+
39
+ function wrapAnsi(code) {
40
+ return ESCAPES[0] + '[' + code + 'm';
41
+ }
42
+
43
+ // calculate the length of words split on ' ', ignoring
44
+ // the extra characters added by ansi escape codes.
45
+ function wordLengths(str) {
46
+ return str.split(' ').map(function (s) {
47
+ return stringWidth(s);
48
+ });
49
+ }
50
+
51
+ // wrap a long word across multiple rows.
52
+ // ansi escape codes do not count towards length.
53
+ function wrapWord(rows, word, cols) {
6
54
  var insideEscape = false;
7
- var visible = 0;
8
- var lastSpace = 0;
55
+ var visible = rows[rows.length - 1].length;
9
56
 
10
- for (var i = 0; i < str.length; i++) {
11
- var x = str[i];
57
+ for (var i = 0; i < word.length; i++) {
58
+ var x = word[i];
12
59
 
13
- ret += x;
60
+ rows[rows.length - 1] += x;
14
61
 
15
- if (x === '\u001b') {
62
+ if (ESCAPES.indexOf(x) !== -1) {
16
63
  insideEscape = true;
17
64
  } else if (insideEscape && x === 'm') {
18
65
  insideEscape = false;
@@ -23,16 +70,93 @@ module.exports = function (str, cols) {
23
70
  continue;
24
71
  }
25
72
 
26
- if (x === ' ') {
27
- lastSpace = i;
28
- }
73
+ visible++;
29
74
 
30
- if (++visible >= cols - 2 && lastSpace > 0) {
31
- ret = spliceString(ret, lastSpace, 1, '\n');
32
- lastSpace = 0;
75
+ if (visible >= cols && i < word.length - 1) {
76
+ rows.push('');
33
77
  visible = 0;
34
78
  }
35
79
  }
36
80
 
81
+ // it's possible that the last row we copy over is only
82
+ // ansi escape characters, handle this edge-case.
83
+ if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) {
84
+ rows[rows.length - 2] += rows.pop();
85
+ }
86
+ }
87
+
88
+ // the wrap-ansi module can be invoked
89
+ // in either 'hard' or 'soft' wrap mode.
90
+ //
91
+ // 'hard' will never allow a string to take up more
92
+ // than cols characters.
93
+ //
94
+ // 'soft' allows long words to expand past the column length.
95
+ function exec(str, cols, opts) {
96
+ var options = opts || {};
97
+
98
+ var pre = '';
99
+ var ret = '';
100
+ var escapeCode;
101
+
102
+ var lengths = wordLengths(str);
103
+ var words = str.split(' ');
104
+ var rows = [''];
105
+
106
+ for (var i = 0, word; (word = words[i]) !== undefined; i++) {
107
+ var rowLength = stringWidth(rows[rows.length - 1]);
108
+
109
+ if (rowLength) {
110
+ rows[rows.length - 1] += ' ';
111
+ rowLength++;
112
+ }
113
+
114
+ // in 'hard' wrap mode, the length of a line is
115
+ // never allowed to extend past 'cols'.
116
+ if (lengths[i] > cols && options.hard) {
117
+ if (rowLength) {
118
+ rows.push('');
119
+ }
120
+ wrapWord(rows, word, cols);
121
+ continue;
122
+ }
123
+
124
+ if (rowLength + lengths[i] > cols && rowLength > 0) {
125
+ rows.push('');
126
+ }
127
+
128
+ rows[rows.length - 1] += word;
129
+ }
130
+
131
+ pre = rows.map(function (r) {
132
+ return r.trim();
133
+ }).join('\n');
134
+
135
+ for (var j = 0; j < pre.length; j++) {
136
+ var y = pre[j];
137
+
138
+ ret += y;
139
+
140
+ if (ESCAPES.indexOf(y) !== -1) {
141
+ var code = parseFloat(/[0-9][^m]*/.exec(pre.slice(j, j + 4)));
142
+ escapeCode = code === END_CODE ? null : code;
143
+ }
144
+
145
+ if (escapeCode && ESCAPE_CODES[escapeCode]) {
146
+ if (pre[j + 1] === '\n') {
147
+ ret += wrapAnsi(ESCAPE_CODES[escapeCode]);
148
+ } else if (y === '\n') {
149
+ ret += wrapAnsi(escapeCode);
150
+ }
151
+ }
152
+ }
153
+
37
154
  return ret;
155
+ }
156
+
157
+ // for each line break, invoke the method separately.
158
+ module.exports = function (str, cols, opts) {
159
+ return String(str).split('\n').map(function (substr) {
160
+ return exec(substr, cols, opts);
161
+ }).join('\n');
38
162
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrap-ansi",
3
- "version": "0.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "Wordwrap a string with ANSI escape codes",
5
5
  "license": "MIT",
6
6
  "repository": "chalk/wrap-ansi",
@@ -12,13 +12,15 @@
12
12
  "maintainers": [
13
13
  "Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)",
14
14
  "Joshua Appelman <jappelman@xebia.com> (jbnicolai.com)",
15
- "JD Ballard <i.am.qix@gmail.com> (github.com/qix-)"
15
+ "JD Ballard <i.am.qix@gmail.com> (github.com/qix-)",
16
+ "Benjamin Coe <ben@npmjs.com> (github.com/bcoe)"
16
17
  ],
17
18
  "engines": {
18
19
  "node": ">=0.10.0"
19
20
  },
20
21
  "scripts": {
21
- "test": "xo && node test.js"
22
+ "test": "xo && nyc node test.js",
23
+ "coverage": "nyc --reporter=text-lcov node test.js | coveralls"
22
24
  },
23
25
  "files": [
24
26
  "index.js"
@@ -51,11 +53,14 @@
51
53
  "text"
52
54
  ],
53
55
  "dependencies": {
54
- "splice-string": "^1.0.0"
56
+ "string-width": "^1.0.1"
55
57
  },
56
58
  "devDependencies": {
57
59
  "ava": "0.0.4",
58
60
  "chalk": "^1.1.0",
61
+ "coveralls": "^2.11.4",
62
+ "has-ansi": "^2.0.0",
63
+ "nyc": "^3.2.2",
59
64
  "strip-ansi": "^3.0.0",
60
65
  "xo": "*"
61
66
  }
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # wrap-ansi [![Build Status](https://travis-ci.org/chalk/wrap-ansi.svg?branch=master)](https://travis-ci.org/chalk/wrap-ansi)
1
+ # wrap-ansi [![Build Status](https://travis-ci.org/chalk/wrap-ansi.svg?branch=master)](https://travis-ci.org/chalk/wrap-ansi) [![Coverage Status](https://coveralls.io/repos/chalk/wrap-ansi/badge.svg?branch=master&service=github)](https://coveralls.io/github/chalk/wrap-ansi?branch=master)
2
2
 
3
3
  > Wordwrap a string with [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles)
4
4
 
@@ -13,10 +13,10 @@ $ npm install --save wrap-ansi
13
13
  ## Usage
14
14
 
15
15
  ```js
16
- var chalk = require('chalk');
17
- var wrapAnsi = require('wrap-ansi');
16
+ const chalk = require('chalk');
17
+ const wrapAnsi = require('wrap-ansi');
18
18
 
19
- var input = 'The quick brown ' + chalk.red('fox jumped over ') +
19
+ const input = 'The quick brown ' + chalk.red('fox jumped over ') +
20
20
  'the lazy ' + chalk.green('dog and then ran away with the unicorn.');
21
21
 
22
22
  console.log(wrapAnsi(input, 20));
@@ -27,7 +27,9 @@ console.log(wrapAnsi(input, 20));
27
27
 
28
28
  ## API
29
29
 
30
- ### wrapAnsi(input, columns)
30
+ ### wrapAnsi(input, columns, [options])
31
+
32
+ Wrap words to the specified column width.
31
33
 
32
34
  #### input
33
35
 
@@ -41,10 +43,19 @@ Type: `number`
41
43
 
42
44
  Number of columns to wrap the text to.
43
45
 
46
+ #### options.hard
47
+
48
+ Type: `boolean`
49
+ Default: `false`
50
+
51
+ By default the wrap is soft, meaning long words may extend past the column width. Setting this to `true` will make it hard wrap at the column width.
52
+
44
53
 
45
54
  ## Related
46
55
 
56
+ - [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
47
57
  - [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
58
+ - [jsesc](https://github.com/mathiasbynens/jsesc) - Generate ASCII-only output from Unicode strings. Useful for creating test fixtures.
48
59
 
49
60
 
50
61
  ## License