1 | var clc = require('cli-color'),
|
2 | ansiTrim = require('cli-color/trim'),
|
3 | sprintf = require('util').format;
|
4 |
|
5 | var sparklineSymbols = [
|
6 | '\u2581',
|
7 | '\u2582',
|
8 | '\u2583',
|
9 | '\u2584',
|
10 | '\u2585',
|
11 | '\u2586',
|
12 | '\u2587',
|
13 | '\u2588'
|
14 | ];
|
15 |
|
16 |
|
17 | function pick(value, defaultValue) {
|
18 | return (typeof value == 'undefined' ? defaultValue : value);
|
19 | }
|
20 |
|
21 | var helpers = {
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | Spinner: function (message, style) {
|
27 | var spinnerMessage = message;
|
28 | var spinnerStyle = style;
|
29 |
|
30 | this.start = function () {
|
31 | var self = this;
|
32 | var spinner = spinnerStyle;
|
33 |
|
34 | if (!spinner || spinner.length === 0) {
|
35 | spinner = 'win32' == process.platform ? ['|','/','-','\\'] : ['◜','◠','◝','◞','◡','◟'];
|
36 | }
|
37 |
|
38 | function play(arr, interval) {
|
39 | var len = arr.length, i = 0;
|
40 | interval = interval || 100;
|
41 |
|
42 | var drawTick = function () {
|
43 | var str = arr[i++ % len];
|
44 | process.stdout.write('\u001b[0G' + str + '\u001b[90m' + spinnerMessage + '\u001b[0m');
|
45 | };
|
46 |
|
47 | self.timer = setInterval(drawTick, interval);
|
48 | }
|
49 |
|
50 | var frames = spinner.map(function(c) {
|
51 | return sprintf(' \u001b[96m%s ', c);
|
52 | });
|
53 |
|
54 | play(frames, 70);
|
55 | };
|
56 |
|
57 | this.message = function (message) {
|
58 | spinnerMessage = message;
|
59 | };
|
60 |
|
61 | this.stop = function () {
|
62 | process.stdout.write('\u001b[0G\u001b[2K');
|
63 | clearInterval(this.timer);
|
64 | };
|
65 | },
|
66 |
|
67 |
|
68 | Gauge: function (value, maxValue, width, dangerZone, suffix) {
|
69 | if (maxValue === 0) {
|
70 | return '[]';
|
71 | } else {
|
72 | var barLength = value ? Math.ceil(value / maxValue * width) : 1;
|
73 | if (barLength > width)
|
74 | barLength = width;
|
75 |
|
76 | var barColor = clc.green;
|
77 | if (value > dangerZone)
|
78 | barColor = clc.red;
|
79 |
|
80 | return '['+
|
81 | barColor(Array(barLength).join("|")) +
|
82 | Array(width + 1 - barLength).join("-") +
|
83 | '] ' + clc.blackBright(suffix);
|
84 | }
|
85 | },
|
86 |
|
87 |
|
88 | Progress: function (width) {
|
89 | var currentValue = 0;
|
90 | var maxValue = 0;
|
91 | var self = this;
|
92 |
|
93 | this.update = function (currentValue, maxValue) {
|
94 | if(maxValue === 0) {
|
95 | return '[]';
|
96 | }
|
97 |
|
98 |
|
99 | if (typeof maxValue === 'undefined')
|
100 | maxValue = 1
|
101 |
|
102 |
|
103 | var barLength = currentValue ? Math.ceil(currentValue / maxValue * width) : 1;
|
104 |
|
105 |
|
106 | if (barLength > width)
|
107 | barLength = width;
|
108 |
|
109 |
|
110 | if (currentValue > maxValue)
|
111 | currentValue = maxValue
|
112 |
|
113 | return '['+
|
114 | clc.green(Array(barLength).join("|")) +
|
115 | Array(width + 1 - barLength).join("-") +
|
116 | '] ' + clc.blackBright(Math.ceil(currentValue / maxValue * 100) + '%');
|
117 | };
|
118 | },
|
119 |
|
120 |
|
121 | Sparkline: function (points, suffix) {
|
122 | if(typeof suffix == 'undefined')
|
123 | suffix = '';
|
124 |
|
125 | var max = Math.max.apply(Math, points);
|
126 |
|
127 | var scaledSequence = points.map(function (thisPoint) {
|
128 | if(max === 0)
|
129 | return [0, 0];
|
130 | else if(thisPoint === 0)
|
131 | return [0, 0];
|
132 | else
|
133 | return [
|
134 | Math.ceil(thisPoint / max * (sparklineSymbols.length-1)),
|
135 | thisPoint
|
136 | ];
|
137 | });
|
138 |
|
139 | var sparklineGraph = '';
|
140 | var alreadyDrawnMax = false;
|
141 | scaledSequence.forEach(function (symbolNumber) {
|
142 | if(symbolNumber[1] == max & !alreadyDrawnMax)
|
143 | {
|
144 | sparklineGraph += clc.green(sparklineSymbols[symbolNumber[0]]);
|
145 | alreadyDrawnMax = true;
|
146 | }
|
147 | else
|
148 | sparklineGraph += sparklineSymbols[symbolNumber[0]];
|
149 | });
|
150 |
|
151 | return sparklineGraph + ' ' + clc.blackBright(points[points.length-1] + suffix + ' (') + clc.green(max + suffix) + clc.blackBright(')');
|
152 | },
|
153 |
|
154 |
|
155 | LineBuffer: function (userOptions) {
|
156 | var self = this;
|
157 | self.lines = [];
|
158 |
|
159 |
|
160 | var defaultOptions = {
|
161 | x: 0,
|
162 | y: 0,
|
163 | width: 'console',
|
164 | height: 'console',
|
165 | scroll: 0
|
166 | };
|
167 |
|
168 | if(typeof userOptions == 'undefined')
|
169 | self.userOptions = defaultOptions;
|
170 | else
|
171 | {
|
172 | self.userOptions = {
|
173 | x: pick(userOptions.x, defaultOptions.x),
|
174 | y: pick(userOptions.y, defaultOptions.y),
|
175 | width: pick(userOptions.width, defaultOptions.width),
|
176 | height: pick(userOptions.height, defaultOptions.height),
|
177 | scroll: pick(userOptions.scroll, defaultOptions.scroll)
|
178 | };
|
179 | }
|
180 |
|
181 | this.height = function ()
|
182 | {
|
183 | if(self.userOptions.height == 'console')
|
184 | return process.stdout.rows;
|
185 | else
|
186 | return self.userOptions.height;
|
187 | };
|
188 |
|
189 | this.width = function ()
|
190 | {
|
191 | if(self.userOptions.width == 'console')
|
192 | return process.stdout.columns;
|
193 | else
|
194 | return self.userOptions.width;
|
195 | };
|
196 |
|
197 |
|
198 | this.addLine = function (lineObject) {
|
199 | self.lines.push(lineObject);
|
200 | return self;
|
201 | };
|
202 |
|
203 |
|
204 |
|
205 | this.fill = function (fillLine) {
|
206 | var fillHeight = self.height()-self.lines.length;
|
207 | if(fillHeight > 0)
|
208 | {
|
209 | for(var i = 0; i < fillHeight; i++)
|
210 | {
|
211 | self.addLine(fillLine);
|
212 | }
|
213 | }
|
214 | return self;
|
215 | };
|
216 |
|
217 |
|
218 | this.output = function () {
|
219 |
|
220 | var outputLines;
|
221 | var sliceEnd;
|
222 | var outputHeight = self.height();
|
223 | if(self.userOptions.scroll > self.lines.length)
|
224 | return;
|
225 |
|
226 | if(self.lines.length - self.userOptions.scroll > outputHeight)
|
227 | outputLines = self.lines.slice(self.userOptions.scroll, self.userOptions.scroll + outputHeight);
|
228 | else
|
229 | outputLines = self.lines.slice(self.userOptions.scroll);
|
230 |
|
231 |
|
232 | var currentY = self.userOptions.y;
|
233 | outputLines.forEach(function (line) {
|
234 | process.stdout.write(clc.moveTo(self.userOptions.x, currentY));
|
235 | line.output();
|
236 | currentY++;
|
237 | });
|
238 | };
|
239 | },
|
240 |
|
241 |
|
242 | Table: function () {
|
243 | var self = this;
|
244 | var tableContent = '';
|
245 |
|
246 |
|
247 | self.tr = function () {
|
248 | return self;
|
249 | };
|
250 |
|
251 |
|
252 | self.td = function (cellContent, cellWidth) {
|
253 | return self;
|
254 | };
|
255 |
|
256 |
|
257 | self.output = function () {
|
258 | return self;
|
259 | };
|
260 |
|
261 | return self;
|
262 | },
|
263 |
|
264 |
|
265 | Line: function (defaultBuffer) {
|
266 | var lineContent = "";
|
267 | var self = this;
|
268 | self.defaultBuffer = defaultBuffer;
|
269 |
|
270 |
|
271 | this.text = function (text, styles) {
|
272 | for(var styleNumber in styles)
|
273 | {
|
274 | text = styles[styleNumber](text);
|
275 | }
|
276 | lineContent += text;
|
277 | return self;
|
278 | };
|
279 |
|
280 |
|
281 | this.padding = function (width, styles) {
|
282 | var padding = Array(width+1).join(" ");
|
283 | for(var styleNumber in styles)
|
284 | {
|
285 | padding = styles[styleNumber](padding);
|
286 | }
|
287 | lineContent += padding;
|
288 | return self;
|
289 | };
|
290 |
|
291 |
|
292 | this.column = function (text, columnWidth, textStyles) {
|
293 | var textWidth = ansiTrim(text).length;
|
294 |
|
295 | if(textWidth > columnWidth)
|
296 | {
|
297 | self.text(text.slice(0, columnWidth), textStyles);
|
298 | }
|
299 | else if(textWidth < columnWidth)
|
300 | {
|
301 | self.text(text, textStyles)
|
302 | .padding(columnWidth - textWidth);
|
303 | }
|
304 | else
|
305 | {
|
306 | self.text(text, textStyles);
|
307 | }
|
308 | return self;
|
309 | };
|
310 |
|
311 |
|
312 | this.fill = function (styles) {
|
313 | var fillWidth = process.stdout.columns-ansiTrim(lineContent).length;
|
314 | if(fillWidth > 0)
|
315 | self.padding(fillWidth, styles);
|
316 | return self;
|
317 | };
|
318 |
|
319 |
|
320 | this.store = function (buffer) {
|
321 | if(typeof buffer == 'undefined')
|
322 | {
|
323 | if(typeof self.defaultBuffer == 'undefined')
|
324 | process.stderr.write('Attempt to store a line in a line buffer, without providing a line buffer to store that line in.');
|
325 | else
|
326 | self.defaultBuffer.addLine(self);
|
327 | }
|
328 | else
|
329 | {
|
330 | buffer.addLine(self);
|
331 | }
|
332 | return self;
|
333 | };
|
334 |
|
335 |
|
336 | this.output = function () {
|
337 | process.stdout.write(lineContent+"\n");
|
338 | return self;
|
339 | };
|
340 |
|
341 |
|
342 | this.contents = function () {
|
343 | return lineContent;
|
344 | };
|
345 | },
|
346 |
|
347 |
|
348 |
|
349 |
|
350 | Clear: function(clear) {
|
351 | if (clear !== false) {
|
352 |
|
353 | process.stdout.write('\033[2J');
|
354 | }
|
355 |
|
356 | process.stdout.write('\033[0;0f');
|
357 | }
|
358 | };
|
359 |
|
360 | module.exports = helpers;
|