292 lines
6.2 KiB
JavaScript
292 lines
6.2 KiB
JavaScript
var Structr = require('structr');
|
||
|
||
exports.plugin = function(cli)
|
||
{
|
||
function normalizeOptions(ops)
|
||
{
|
||
var cliWidth = cli.columns();
|
||
|
||
var columns = ops.columns,
|
||
normCols = [],
|
||
vert = ops.vertical || ops.vert || ' ',
|
||
horz = ops.horizontal || ops.horz || '',
|
||
pad = Structr.copy(ops.pad, { left: 0, right: 0, top: 0, bottom: 0 });
|
||
|
||
if(ops.padRight) pad.right = ops.padRight;
|
||
if(ops.padLeft) pad.left = ops.padLeft;
|
||
if(ops.padTop) pad.top = ops.padTop;
|
||
if(ops.padBottom) pad.bottom = ops.padBottom;
|
||
if(!ops.width) ops.width = cliWidth;
|
||
|
||
ops.width = Math.min(ops.width, cliWidth - pad.left - pad.right);
|
||
|
||
|
||
if(ops.border)
|
||
{
|
||
if(vert == ' ') vert = ' | ';
|
||
if(horz == '') horz = '–';
|
||
}
|
||
|
||
|
||
//sum width of all columns combined
|
||
var sumWidth = 0;
|
||
|
||
for(var prop in columns)
|
||
{
|
||
var columnValue = columns[prop],
|
||
normCol = { minWidth: 6, align: 'left' },
|
||
tocv = typeof columnValue;
|
||
|
||
normCols.push(normCol)
|
||
|
||
//['columnName']
|
||
if(tocv == 'string')
|
||
{
|
||
normCol.name = columnValue;
|
||
}
|
||
else
|
||
{
|
||
//{columnName:value}
|
||
if(typeof prop == 'string')
|
||
{
|
||
normCol.name = prop;
|
||
}
|
||
|
||
|
||
if(tocv == 'number')
|
||
{
|
||
normCol.width = columnValue;
|
||
}
|
||
else
|
||
if(tocv == 'object')
|
||
{
|
||
Structr.copy(columnValue, normCol);
|
||
}
|
||
}
|
||
|
||
if(!normCol.width) normCol.width = 100/columns.length;
|
||
|
||
|
||
|
||
sumWidth += normCol.width;
|
||
}
|
||
|
||
|
||
//subtract vert padding
|
||
|
||
|
||
var sumActualWidth = 0,
|
||
colsTaken = 0,
|
||
numCols = normCols.length;
|
||
var tableWidth = ops.width - vert.length * numCols;
|
||
|
||
|
||
for(var i = 0; i < numCols; i++)
|
||
{
|
||
|
||
var column = normCols[i]/*,
|
||
isLast = i == numCols-1,
|
||
align = column.align;
|
||
|
||
if(!align)
|
||
{
|
||
column.align = isLast ? 'right' : 'left';
|
||
}*/
|
||
|
||
var percWidth = Math.round(column.width/sumWidth * tableWidth);
|
||
actualWidth = Math.max(column.minWidth, percWidth),
|
||
|
||
//diff between calculated perc width, and min width. used for penalization
|
||
difference = actualWidth - percWidth;
|
||
|
||
sumActualWidth += actualWidth;
|
||
|
||
|
||
//this may happen if there are too many minWidths specified. In which case, not all columns
|
||
//will be shown. Actual width will be set to zero
|
||
if(sumActualWidth > ops.width) actualWidth -= Math.min(actualWidth, sumActualWidth - tableWidth);
|
||
|
||
//actual width CANNOT be less than min width. e.g: single char column couold be huge.
|
||
if(actualWidth < column.minWidth) actualWidth = 0;
|
||
|
||
column.actualWidth = actualWidth;
|
||
|
||
//penalize the rest of the columns. Width must *not* cli width
|
||
sumWidth -= difference;
|
||
}
|
||
|
||
return {
|
||
columns: normCols,
|
||
ellipsis: ops.ellipsis,
|
||
vert: vert,
|
||
horz: horz,
|
||
pad: pad,
|
||
width: ops.width,
|
||
numColumns: numCols,
|
||
showLabels: !!ops.showLabels
|
||
}
|
||
}
|
||
|
||
function addLines(colLines, value, column)
|
||
{
|
||
var newLines = (value ? value.toString() : '').split(/[\r\n]/g);
|
||
|
||
for(var i = 0, n = newLines.length; i < n; i++)
|
||
{
|
||
//trim whitespace off the ends. line breaks = whitespace
|
||
var buffer = newLines[i].replace(/^\s+|\s+$/g,'');
|
||
|
||
var colors = buffer.match(/\u001b\[\d+m/g) || [];
|
||
|
||
var padding = column.actualWidth - buffer.length + colors.join('').length;
|
||
|
||
switch(column.align)
|
||
{
|
||
case 'right':
|
||
buffer = cli.utils.padLeft(buffer, padding, ' ');
|
||
break;
|
||
|
||
case 'center':
|
||
buffer = cli.utils.pad(buffer, Math.floor(padding/2), ' ', Math.ceil(padding/2));
|
||
break;
|
||
|
||
default:
|
||
buffer = cli.utils.padRight(buffer, padding, ' ');
|
||
break;
|
||
}
|
||
|
||
colLines.push(buffer);
|
||
}
|
||
}
|
||
|
||
function getRowLineTable(item, ops)
|
||
{
|
||
var lineTable = [],
|
||
numLines = 0,
|
||
cols = ops.numColumns;
|
||
|
||
|
||
//get the lines.
|
||
for(var j = 0, jn = cols; j < jn; j++)
|
||
{
|
||
var column = ops.columns[j],
|
||
value = item[ops.columns[j].name] || '',
|
||
colLines = [],
|
||
actualWidth = column.actualWidth;
|
||
|
||
//width not present? skip the column
|
||
if(!actualWidth) continue;
|
||
|
||
|
||
if(value.length > actualWidth)
|
||
{
|
||
if(ops.ellipsis)
|
||
{
|
||
var newBuffer = value.substr(0, actualWidth-3) + cli.utils.repeat('.', Math.min(actualWidth, 3));
|
||
|
||
addLines(colLines, newBuffer, column);
|
||
}
|
||
else
|
||
{
|
||
var start = 0;
|
||
|
||
//splice apart the single line, treating each chunk as a new line
|
||
for(var k = actualWidth; k < value.length + actualWidth; k += actualWidth)
|
||
{
|
||
addLines(colLines, value.substr(start, actualWidth), column);
|
||
start = k;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
addLines(colLines, value, column);
|
||
}
|
||
|
||
//if this column lines
|
||
numLines = Math.max(numLines, colLines.length);
|
||
|
||
|
||
//next add the line - need to check against all lines now
|
||
lineTable.push(colLines);
|
||
|
||
|
||
//need to go through all the column lines again, and
|
||
//make sure all the lines match up properly
|
||
for(var k = 0, kn = lineTable.length; k < kn; k++)
|
||
{
|
||
var line = lineTable[k];
|
||
|
||
//must have same number of lineTable
|
||
if(line.length < numLines)
|
||
{
|
||
addLines(lineTable[k], cli.utils.repeat('\n', numLines - line.length -1), ops.columns[k]);
|
||
}
|
||
}
|
||
}
|
||
|
||
var rows = [];
|
||
//inversed
|
||
for(var i = 0, n = lineTable.length; i < n; i++)
|
||
{
|
||
var col = lineTable[i];
|
||
|
||
//each row
|
||
for(var j = 0, jn = col.length; j < jn; j++)
|
||
{
|
||
if(!rows[j]) rows[j] = [];
|
||
|
||
rows[j].push(col[j]);
|
||
}
|
||
}
|
||
|
||
return rows;
|
||
}
|
||
|
||
function logRow(ops, buffer)
|
||
{
|
||
console.log(cli.utils.repeat(' ', ops.pad.left) + buffer);
|
||
}
|
||
|
||
function drawBreak(ops)
|
||
{
|
||
if(ops.horz) logRow(ops, cli.utils.repeat(ops.horz, ops.width));
|
||
}
|
||
|
||
function drawRow(lineTable, ops)
|
||
{
|
||
for(var i = 0, n = lineTable.length; i < n; i++)
|
||
{
|
||
logRow(ops, lineTable[i].join(ops.vert))
|
||
}
|
||
|
||
drawBreak(ops);
|
||
}
|
||
|
||
function drawTable(source, ops)
|
||
{
|
||
if(ops.pad.top) console.log(cli.utils.repeat('\n', ops.pad.top-1));
|
||
|
||
drawBreak(ops);
|
||
|
||
for(var i = source.length; i--;)
|
||
{
|
||
var lineTable = getRowLineTable(source[i], ops)
|
||
|
||
drawRow(lineTable, ops);
|
||
}
|
||
|
||
if(ops.pad.bottom) console.log(cli.utils.repeat('\n', ops.pad.bottom-1));
|
||
|
||
}
|
||
|
||
|
||
cli.drawTable = function(source, ops)
|
||
{
|
||
ops = normalizeOptions(ops);
|
||
drawTable(source, ops);
|
||
|
||
// console.log(ops)
|
||
|
||
}
|
||
} |