| /* |
| * grunt |
| * http://gruntjs.com/ |
| * |
| * Copyright (c) 2016 "Cowboy" Ben Alman |
| * Licensed under the MIT license. |
| * https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT |
| */ |
| |
| 'use strict'; |
| |
| var chalk = require('chalk'); |
| var _ = require('lodash'); |
| |
| // Pretty-format a word list. |
| exports.wordlist = function(arr, options) { |
| options = _.defaults(options || {}, { |
| separator: ', ', |
| color: 'cyan' |
| }); |
| return arr.map(function(item) { |
| return options.color ? chalk[options.color](item) : item; |
| }).join(options.separator); |
| }; |
| |
| // Return a string, uncolored (suitable for testing .length, etc). |
| exports.uncolor = function(str) { |
| return str.replace(/\x1B\[\d+m/g, ''); |
| }; |
| |
| // Word-wrap text to a given width, permitting ANSI color codes. |
| exports.wraptext = function(width, text) { |
| // notes to self: |
| // grab 1st character or ansi code from string |
| // if ansi code, add to array and save for later, strip from front of string |
| // if character, add to array and increment counter, strip from front of string |
| // if width + 1 is reached and current character isn't space: |
| // slice off everything after last space in array and prepend it to string |
| // etc |
| |
| // This result array will be joined on \n. |
| var result = []; |
| var matches, color, tmp; |
| var captured = []; |
| var charlen = 0; |
| |
| while (matches = text.match(/(?:(\x1B\[\d+m)|\n|(.))([\s\S]*)/)) { |
| // Updated text to be everything not matched. |
| text = matches[3]; |
| |
| // Matched a color code? |
| if (matches[1]) { |
| // Save last captured color code for later use. |
| color = matches[1]; |
| // Capture color code. |
| captured.push(matches[1]); |
| continue; |
| |
| // Matched a non-newline character? |
| } else if (matches[2]) { |
| // If this is the first character and a previous color code was set, push |
| // that onto the captured array first. |
| if (charlen === 0 && color) { captured.push(color); } |
| // Push the matched character. |
| captured.push(matches[2]); |
| // Increment the current charlen. |
| charlen++; |
| // If not yet at the width limit or a space was matched, continue. |
| if (charlen <= width || matches[2] === ' ') { continue; } |
| // The current charlen exceeds the width and a space wasn't matched. |
| // "Roll everything back" until the last space character. |
| tmp = captured.lastIndexOf(' '); |
| text = captured.slice(tmp === -1 ? tmp : tmp + 1).join('') + text; |
| captured = captured.slice(0, tmp); |
| } |
| |
| // The limit has been reached. Push captured string onto result array. |
| result.push(captured.join('')); |
| |
| // Reset captured array and charlen. |
| captured = []; |
| charlen = 0; |
| } |
| |
| result.push(captured.join('')); |
| return result.join('\n'); |
| }; |
| |
| // Format output into columns, wrapping words as-necessary. |
| exports.table = function(widths, texts) { |
| var rows = []; |
| widths.forEach(function(width, i) { |
| var lines = this.wraptext(width, texts[i]).split('\n'); |
| lines.forEach(function(line, j) { |
| var row = rows[j]; |
| if (!row) { row = rows[j] = []; } |
| row[i] = line; |
| }); |
| }, this); |
| |
| var lines = []; |
| rows.forEach(function(row) { |
| var txt = ''; |
| var column; |
| for (var i = 0; i < row.length; i++) { |
| column = row[i] || ''; |
| txt += column; |
| var diff = widths[i] - this.uncolor(column).length; |
| if (diff > 0) { txt += _.repeat(' ', diff); } |
| } |
| lines.push(txt); |
| }, this); |
| |
| return lines.join('\n'); |
| }; |