From 01984d3a14326c75c96450fdb93916b31e78f965 Mon Sep 17 00:00:00 2001 From: Shannon Moeller Date: Sat, 13 Feb 2016 17:09:22 -0500 Subject: [PATCH] initial commit --- .editorconfig | 16 +++++++++++ .gitattributes | 1 + .gitignore | 7 +++++ .travis.yml | 16 +++++++++++ package.json | 47 +++++++++++++++++++++++++++++++ src/cli-columns.js | 67 +++++++++++++++++++++++++++++++++++++++++++++ test/cli-columns.js | 58 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 212 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 package.json create mode 100644 src/cli-columns.js create mode 100644 test/cli-columns.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f1a02f1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +[*.json] +indent_size = 2 +indent_style = space + +[*.md] +indent_style = space diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c98594d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.nyc_output/ +coverage/ +node_modules/ + +*.log +.*.swp +.npmignore diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..68f2043 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: node_js +node_js: + - node + - '5.5' + - '5.4' + - '5.3' + - '5.2' + - '5.1' + - '5.0' + - '4.2' + - '4.1' + - '4.0' + - '0.12' +after_script: + - npm run coveralls diff --git a/package.json b/package.json new file mode 100644 index 0000000..5323b51 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "cli-columns", + "version": "1.0.0", + "description": "Columnated lists for the CLI.", + "main": "src/cli-columns.js", + "scripts": { + "coveralls": "nyc report -r text-lcov | coveralls", + "pretest": "xo src/*.js test/*.js", + "test": "nyc ava -v test/*.js", + "watch": "watch 'npm test' src test -du" + }, + "repository": { + "type": "git", + "url": "https://github.com/shannonmoeller/colonel" + }, + "keywords": [ + "ansi", + "cli", + "column", + "columns", + "list", + "log", + "ls", + "row", + "rows", + "unicode", + "unix" + ], + "author": "Shannon Moeller (http://shannonmoeller.com)", + "license": "MIT", + "bugs": { + "url": "https://github.com/shannonmoeller/colonel/issues" + }, + "homepage": "https://github.com/shannonmoeller/colonel", + "dependencies": { + "object-assign": "^4.0.1", + "string-width": "^1.0.1" + }, + "devDependencies": { + "ava": "^0.11.0", + "chalk": "^1.1.1", + "nyc": "^5.6.0", + "strip-ansi": "^3.0.0", + "watch": "^0.17.1", + "xo": "^0.12.1" + } +} diff --git a/src/cli-columns.js b/src/cli-columns.js new file mode 100644 index 0000000..0c56427 --- /dev/null +++ b/src/cli-columns.js @@ -0,0 +1,67 @@ +var assign = require('object-assign'); +var stringWidth = require('string-width'); +var stripAnsi = require('strip-ansi'); +var concat = Array.prototype.concat; + +var defaults = { + character: ' ', + newline: '\n', + padding: 2, + width: 0 +}; + +function byPlainText(a, b) { + return stripAnsi(a) > stripAnsi(b) ? 1 : -1; +} + +function makeArray() { + return []; +} + +function makeList(count) { + return Array.apply(null, Array(count)); +} + +function padCell(fullWidth, character, value) { + var valueWidth = stringWidth(value); + var filler = makeList(fullWidth - valueWidth + 1); + + return value + filler.join(character); +} + +function toRows(rows, cell, i) { + rows[i % rows.length].push(cell); + + return rows; +} + +function toString(arr) { + return arr.join(''); +} + +function columns(values, options) { + values = concat.apply([], values); + options = assign({}, defaults, options); + + var cells = values + .filter(Boolean) + .map(String) + .sort(byPlainText); + + var termWidth = options.width || process.stdout.columns; + var cellWidth = Math.max.apply(null, cells.map(stringWidth)) + options.padding; + var columnCount = Math.floor(termWidth / cellWidth) || 1; + var rowCount = Math.ceil(cells.length / columnCount) || 1; + + if (columnCount === 1) { + return cells.join(options.newline); + } + + return cells + .map(padCell.bind(null, cellWidth, options.character)) + .reduce(toRows, makeList(rowCount).map(makeArray)) + .map(toString) + .join(options.newline); +} + +module.exports = columns; diff --git a/test/cli-columns.js b/test/cli-columns.js new file mode 100644 index 0000000..54905fb --- /dev/null +++ b/test/cli-columns.js @@ -0,0 +1,58 @@ +import columns from '../src/cli-columns'; +import chalk from 'chalk'; +import stripAnsi from 'strip-ansi'; +import test from 'ava'; + +test('should print one column list', async assert => { + var cols = columns(['foo', ['bar', 'baz'], ['bat', 'qux']], { + width: 2 + }); + + console.log(cols); + + var expected = + 'bar\n' + + 'bat\n' + + 'baz\n' + + 'foo\n' + + 'qux'; + + assert.is(cols, expected); +}); + +test('should print three column list', async assert => { + var cols = columns(['foo', ['bar', 'baz'], ['bat', 'qux']], { + width: 16 + }); + + console.log(cols); + + var expected = + 'bar baz qux \n' + + 'bat foo '; + + assert.is(cols, expected); +}); + +test('should print complex list', async assert => { + var cols = columns( + [ + 'foo', 'bar', 'baz', chalk.blue('berry'), + chalk.red('apple'), 'pomegranate', + 'durian', chalk.green('star fruit'), + 'apricot', 'pear', 'banana pinapple' + ], + { + width: 80 + } + ); + + console.log(cols); + + var expected = + 'apple bar durian pomegranate \n' + + 'apricot baz foo star fruit \n' + + 'banana pinapple berry pear '; + + assert.is(stripAnsi(cols), expected); +});