index.js 3.6 KB

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