index.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * grunt
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2016 "Cowboy" Ben Alman
  6. * Licensed under the MIT license.
  7. * https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
  8. */
  9. 'use strict';
  10. var chalk = require('chalk');
  11. var _ = require('lodash');
  12. // Pretty-format a word list.
  13. exports.wordlist = function(arr, options) {
  14. options = _.defaults(options || {}, {
  15. separator: ', ',
  16. color: 'cyan'
  17. });
  18. return arr.map(function(item) {
  19. return options.color ? chalk[options.color](item) : item;
  20. }).join(options.separator);
  21. };
  22. // Return a string, uncolored (suitable for testing .length, etc).
  23. exports.uncolor = function(str) {
  24. return str.replace(/\x1B\[\d+m/g, '');
  25. };
  26. // Word-wrap text to a given width, permitting ANSI color codes.
  27. exports.wraptext = function(width, text) {
  28. // notes to self:
  29. // grab 1st character or ansi code from string
  30. // if ansi code, add to array and save for later, strip from front of string
  31. // if character, add to array and increment counter, strip from front of string
  32. // if width + 1 is reached and current character isn't space:
  33. // slice off everything after last space in array and prepend it to string
  34. // etc
  35. // This result array will be joined on \n.
  36. var result = [];
  37. var matches, color, tmp;
  38. var captured = [];
  39. var charlen = 0;
  40. while (matches = text.match(/(?:(\x1B\[\d+m)|\n|(.))([\s\S]*)/)) {
  41. // Updated text to be everything not matched.
  42. text = matches[3];
  43. // Matched a color code?
  44. if (matches[1]) {
  45. // Save last captured color code for later use.
  46. color = matches[1];
  47. // Capture color code.
  48. captured.push(matches[1]);
  49. continue;
  50. // Matched a non-newline character?
  51. } else if (matches[2]) {
  52. // If this is the first character and a previous color code was set, push
  53. // that onto the captured array first.
  54. if (charlen === 0 && color) { captured.push(color); }
  55. // Push the matched character.
  56. captured.push(matches[2]);
  57. // Increment the current charlen.
  58. charlen++;
  59. // If not yet at the width limit or a space was matched, continue.
  60. if (charlen <= width || matches[2] === ' ') { continue; }
  61. // The current charlen exceeds the width and a space wasn't matched.
  62. // "Roll everything back" until the last space character.
  63. tmp = captured.lastIndexOf(' ');
  64. text = captured.slice(tmp === -1 ? tmp : tmp + 1).join('') + text;
  65. captured = captured.slice(0, tmp);
  66. }
  67. // The limit has been reached. Push captured string onto result array.
  68. result.push(captured.join(''));
  69. // Reset captured array and charlen.
  70. captured = [];
  71. charlen = 0;
  72. }
  73. result.push(captured.join(''));
  74. return result.join('\n');
  75. };
  76. // Format output into columns, wrapping words as-necessary.
  77. exports.table = function(widths, texts) {
  78. var rows = [];
  79. widths.forEach(function(width, i) {
  80. var lines = this.wraptext(width, texts[i]).split('\n');
  81. lines.forEach(function(line, j) {
  82. var row = rows[j];
  83. if (!row) { row = rows[j] = []; }
  84. row[i] = line;
  85. });
  86. }, this);
  87. var lines = [];
  88. rows.forEach(function(row) {
  89. var txt = '';
  90. var column;
  91. for (var i = 0; i < row.length; i++) {
  92. column = row[i] || '';
  93. txt += column;
  94. var diff = widths[i] - this.uncolor(column).length;
  95. if (diff > 0) { txt += _.repeat(' ', diff); }
  96. }
  97. lines.push(txt);
  98. }, this);
  99. return lines.join('\n');
  100. };