source: trip-planner-front/node_modules/cliui/index.js@ 84d0fbb

Last change on this file since 84d0fbb was e29cc2e, checked in by Ema <ema_spirova@…>, 3 years ago

primeNG components

  • Property mode set to 100644
File size: 8.1 KB
Line 
1var stringWidth = require('string-width')
2var stripAnsi = require('strip-ansi')
3var wrap = require('wrap-ansi')
4var align = {
5 right: alignRight,
6 center: alignCenter
7}
8var top = 0
9var right = 1
10var bottom = 2
11var left = 3
12
13function UI (opts) {
14 this.width = opts.width
15 this.wrap = opts.wrap
16 this.rows = []
17}
18
19UI.prototype.span = function () {
20 var cols = this.div.apply(this, arguments)
21 cols.span = true
22}
23
24UI.prototype.resetOutput = function () {
25 this.rows = []
26}
27
28UI.prototype.div = function () {
29 if (arguments.length === 0) this.div('')
30 if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
31 return this._applyLayoutDSL(arguments[0])
32 }
33
34 var cols = []
35
36 for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
37 if (typeof arg === 'string') cols.push(this._colFromString(arg))
38 else cols.push(arg)
39 }
40
41 this.rows.push(cols)
42 return cols
43}
44
45UI.prototype._shouldApplyLayoutDSL = function () {
46 return arguments.length === 1 && typeof arguments[0] === 'string' &&
47 /[\t\n]/.test(arguments[0])
48}
49
50UI.prototype._applyLayoutDSL = function (str) {
51 var _this = this
52 var rows = str.split('\n')
53 var leftColumnWidth = 0
54
55 // simple heuristic for layout, make sure the
56 // second column lines up along the left-hand.
57 // don't allow the first column to take up more
58 // than 50% of the screen.
59 rows.forEach(function (row) {
60 var columns = row.split('\t')
61 if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
62 leftColumnWidth = Math.min(
63 Math.floor(_this.width * 0.5),
64 stringWidth(columns[0])
65 )
66 }
67 })
68
69 // generate a table:
70 // replacing ' ' with padding calculations.
71 // using the algorithmically generated width.
72 rows.forEach(function (row) {
73 var columns = row.split('\t')
74 _this.div.apply(_this, columns.map(function (r, i) {
75 return {
76 text: r.trim(),
77 padding: _this._measurePadding(r),
78 width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
79 }
80 }))
81 })
82
83 return this.rows[this.rows.length - 1]
84}
85
86UI.prototype._colFromString = function (str) {
87 return {
88 text: str,
89 padding: this._measurePadding(str)
90 }
91}
92
93UI.prototype._measurePadding = function (str) {
94 // measure padding without ansi escape codes
95 var noAnsi = stripAnsi(str)
96 return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
97}
98
99UI.prototype.toString = function () {
100 var _this = this
101 var lines = []
102
103 _this.rows.forEach(function (row, i) {
104 _this.rowToString(row, lines)
105 })
106
107 // don't display any lines with the
108 // hidden flag set.
109 lines = lines.filter(function (line) {
110 return !line.hidden
111 })
112
113 return lines.map(function (line) {
114 return line.text
115 }).join('\n')
116}
117
118UI.prototype.rowToString = function (row, lines) {
119 var _this = this
120 var padding
121 var rrows = this._rasterize(row)
122 var str = ''
123 var ts
124 var width
125 var wrapWidth
126
127 rrows.forEach(function (rrow, r) {
128 str = ''
129 rrow.forEach(function (col, c) {
130 ts = '' // temporary string used during alignment/padding.
131 width = row[c].width // the width with padding.
132 wrapWidth = _this._negatePadding(row[c]) // the width without padding.
133
134 ts += col
135
136 for (var i = 0; i < wrapWidth - stringWidth(col); i++) {
137 ts += ' '
138 }
139
140 // align the string within its column.
141 if (row[c].align && row[c].align !== 'left' && _this.wrap) {
142 ts = align[row[c].align](ts, wrapWidth)
143 if (stringWidth(ts) < wrapWidth) ts += new Array(width - stringWidth(ts)).join(' ')
144 }
145
146 // apply border and padding to string.
147 padding = row[c].padding || [0, 0, 0, 0]
148 if (padding[left]) str += new Array(padding[left] + 1).join(' ')
149 str += addBorder(row[c], ts, '| ')
150 str += ts
151 str += addBorder(row[c], ts, ' |')
152 if (padding[right]) str += new Array(padding[right] + 1).join(' ')
153
154 // if prior row is span, try to render the
155 // current row on the prior line.
156 if (r === 0 && lines.length > 0) {
157 str = _this._renderInline(str, lines[lines.length - 1])
158 }
159 })
160
161 // remove trailing whitespace.
162 lines.push({
163 text: str.replace(/ +$/, ''),
164 span: row.span
165 })
166 })
167
168 return lines
169}
170
171function addBorder (col, ts, style) {
172 if (col.border) {
173 if (/[.']-+[.']/.test(ts)) return ''
174 else if (ts.trim().length) return style
175 else return ' '
176 }
177 return ''
178}
179
180// if the full 'source' can render in
181// the target line, do so.
182UI.prototype._renderInline = function (source, previousLine) {
183 var leadingWhitespace = source.match(/^ */)[0].length
184 var target = previousLine.text
185 var targetTextWidth = stringWidth(target.trimRight())
186
187 if (!previousLine.span) return source
188
189 // if we're not applying wrapping logic,
190 // just always append to the span.
191 if (!this.wrap) {
192 previousLine.hidden = true
193 return target + source
194 }
195
196 if (leadingWhitespace < targetTextWidth) return source
197
198 previousLine.hidden = true
199
200 return target.trimRight() + new Array(leadingWhitespace - targetTextWidth + 1).join(' ') + source.trimLeft()
201}
202
203UI.prototype._rasterize = function (row) {
204 var _this = this
205 var i
206 var rrow
207 var rrows = []
208 var widths = this._columnWidths(row)
209 var wrapped
210
211 // word wrap all columns, and create
212 // a data-structure that is easy to rasterize.
213 row.forEach(function (col, c) {
214 // leave room for left and right padding.
215 col.width = widths[c]
216 if (_this.wrap) wrapped = wrap(col.text, _this._negatePadding(col), { hard: true }).split('\n')
217 else wrapped = col.text.split('\n')
218
219 if (col.border) {
220 wrapped.unshift('.' + new Array(_this._negatePadding(col) + 3).join('-') + '.')
221 wrapped.push("'" + new Array(_this._negatePadding(col) + 3).join('-') + "'")
222 }
223
224 // add top and bottom padding.
225 if (col.padding) {
226 for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
227 for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
228 }
229
230 wrapped.forEach(function (str, r) {
231 if (!rrows[r]) rrows.push([])
232
233 rrow = rrows[r]
234
235 for (var i = 0; i < c; i++) {
236 if (rrow[i] === undefined) rrow.push('')
237 }
238 rrow.push(str)
239 })
240 })
241
242 return rrows
243}
244
245UI.prototype._negatePadding = function (col) {
246 var wrapWidth = col.width
247 if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
248 if (col.border) wrapWidth -= 4
249 return wrapWidth
250}
251
252UI.prototype._columnWidths = function (row) {
253 var _this = this
254 var widths = []
255 var unset = row.length
256 var unsetWidth
257 var remainingWidth = this.width
258
259 // column widths can be set in config.
260 row.forEach(function (col, i) {
261 if (col.width) {
262 unset--
263 widths[i] = col.width
264 remainingWidth -= col.width
265 } else {
266 widths[i] = undefined
267 }
268 })
269
270 // any unset widths should be calculated.
271 if (unset) unsetWidth = Math.floor(remainingWidth / unset)
272 widths.forEach(function (w, i) {
273 if (!_this.wrap) widths[i] = row[i].width || stringWidth(row[i].text)
274 else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
275 })
276
277 return widths
278}
279
280// calculates the minimum width of
281// a column, based on padding preferences.
282function _minWidth (col) {
283 var padding = col.padding || []
284 var minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
285 if (col.border) minWidth += 4
286 return minWidth
287}
288
289function getWindowWidth () {
290 if (typeof process === 'object' && process.stdout && process.stdout.columns) return process.stdout.columns
291}
292
293function alignRight (str, width) {
294 str = str.trim()
295 var padding = ''
296 var strWidth = stringWidth(str)
297
298 if (strWidth < width) {
299 padding = new Array(width - strWidth + 1).join(' ')
300 }
301
302 return padding + str
303}
304
305function alignCenter (str, width) {
306 str = str.trim()
307 var padding = ''
308 var strWidth = stringWidth(str.trim())
309
310 if (strWidth < width) {
311 padding = new Array(parseInt((width - strWidth) / 2, 10) + 1).join(' ')
312 }
313
314 return padding + str
315}
316
317module.exports = function (opts) {
318 opts = opts || {}
319
320 return new UI({
321 width: (opts || {}).width || getWindowWidth() || 80,
322 wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
323 })
324}
Note: See TracBrowser for help on using the repository browser.