Skip to content

Commit

Permalink
Wrap help text to the terminal width
Browse files Browse the repository at this point in the history
  • Loading branch information
sgravrock committed Jul 16, 2024
1 parent 9eba295 commit 7884d34
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 24 deletions.
8 changes: 7 additions & 1 deletion bin/jasmine.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const path = require('path');
const os = require('os');
const process = require('process');
const Command = require('../lib/command');
const Jasmine = require('../lib/jasmine');
const ParallelRunner = require("../lib/parallel_runner");
Expand All @@ -11,7 +12,12 @@ const command = new Command(path.resolve(), examplesDir, {
Jasmine,
ParallelRunner,
print: console.log,
terminalColumns: process.stdout.columns,
platform: os.platform,
});

command.run(process.argv.slice(2));
command.run(process.argv.slice(2))
.catch(e => {
console.error(e);
process.exit(1);
});
96 changes: 74 additions & 22 deletions lib/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const subCommands = {
};

function Command(projectBaseDir, examplesDir, deps) {
const {print, platform, Jasmine, ParallelRunner} = deps;
const {print, platform, terminalColumns, Jasmine, ParallelRunner} = deps;
const isWindows = platform() === 'win32';

this.projectBaseDir = isWindows ? unWindows(projectBaseDir) : projectBaseDir;
Expand All @@ -54,7 +54,8 @@ function Command(projectBaseDir, examplesDir, deps) {
projectBaseDir,
specDir: command.specDir,
examplesDir: examplesDir,
print
print,
terminalColumns
});
} else {
const options = parseOptions(args, isWindows);
Expand All @@ -66,7 +67,7 @@ function Command(projectBaseDir, examplesDir, deps) {
}

print('');
help({print: print});
help({print, terminalColumns});
} else {
await runJasmine(Jasmine, ParallelRunner, projectBaseDir, options);
}
Expand Down Expand Up @@ -284,39 +285,90 @@ function installExamples(options) {
);
}

function help(options) {
const print = options.print;
print('Usage: jasmine [command] [options] [files] [--]');
function help(deps) {
const print = deps.print;
let terminalColumns = deps.terminalColumns || 80;

print(wrap(terminalColumns, 'Usage: jasmine [command] [options] [files] [--]'));
print('');
print('Commands:');
Object.keys(subCommands).forEach(function(cmd) {
let commandNameText = cmd;
if(subCommands[cmd].alias) {
commandNameText = commandNameText + ',' + subCommands[cmd].alias;
}
print('%s\t%s', lPad(commandNameText, 10), subCommands[cmd].description);
print(wrapWithIndent(terminalColumns, lPad(commandNameText, 10) + ' ', subCommands[cmd].description));
});
print('');
print('If no command is given, jasmine specs will be run');
print(wrap(terminalColumns, 'If no command is given, Jasmine specs will be run.'));
print('');
print('');

print('Options:');
print('%s\tRun in parallel with N workers', lPad('--parallel=N', 18));
print('%s\tRun in parallel with an automatically chosen number of workers', lPad('--parallel=auto', 18));
print('%s\tturn off color in spec output', lPad('--no-color', 18));
print('%s\tforce turn on color in spec output', lPad('--color', 18));
print('%s\tfilter specs to run only those that match the given string', lPad('--filter=', 18));
print('%s\tload helper files that match the given string', lPad('--helper=', 18));
print('%s\tload module that match the given string', lPad('--require=', 18));
print('%s\tstop Jasmine execution on spec failure', lPad('--fail-fast', 18));
print('%s\tpath to your optional jasmine.json', lPad('--config=', 18));
print('%s\tpath to reporter to use instead of the default Jasmine reporter', lPad('--reporter=', 18));
print('%s\tprint information that may be useful for debugging configuration', lPad('--verbose', 18));
print('%s\tmarker to signal the end of options meant for Jasmine', lPad('--', 18));

const options = [
{ syntax: '--parallel=N', help: 'Run in parallel with N workers' },
{ syntax: '--parallel=auto', help: 'Run in parallel with an automatically chosen number of workers' },
{ syntax: '--no-color', help: 'turn off color in spec output' },
{ syntax: '--color', help: 'force turn on color in spec output' },
{ syntax: '--filter=', help: 'filter specs to run only those that match the given string' },
{ syntax: '--helper=', help: 'load helper files that match the given string' },
{ syntax: '--require=', help: 'load module that matches the given string' },
{ syntax: '--fail-fast', help: 'stop Jasmine execution on spec failure' },
{ syntax: '--config=', help: 'path to the Jasmine configuration file' },
{ syntax: '--reporter=', help: 'path to reporter to use instead of the default Jasmine reporter' },
{ syntax: '--verbose', help: 'print information that may be useful for debugging configuration' },
{ syntax: '--', help: 'marker to signal the end of options meant for Jasmine' },
];

for (const o of options) {
print(wrapWithIndent(terminalColumns, lPad(o.syntax, 18) + ' ', o.help));
}

print('');
print('The given arguments take precedence over options in your jasmine.json');
print('The path to your optional jasmine.json can also be configured by setting the JASMINE_CONFIG_PATH environment variable');
print(wrap(terminalColumns,
'The given arguments take precedence over options in your jasmine.json.'));
print(wrap(terminalColumns,
'The path to your optional jasmine.json can also be configured by setting the JASMINE_CONFIG_PATH environment variable.'));
}

function wrapWithIndent(cols, prefix, suffix) {
const lines = wrap2(cols - prefix.length, suffix);
const indent = lPad('', prefix.length);
return prefix + lines.join('\n' + indent);
}

function wrap(cols, input) {
return wrap2(cols, input).join('\n');
}

function wrap2(cols, input) {
let lines = [];
let start = 0;

while (start < input.length) {
const splitAt = indexOfLastSpaceInRange(start, start + cols, input);

if (splitAt === -1 || input.length - start <= cols) {
lines.push(input.substring(start));
break;
} else {
lines.push(input.substring(start, splitAt));
start = splitAt + 1;
}
}

return lines;
}

function indexOfLastSpaceInRange(start, end, s) {
for (let i = end; i >= start; i--) {
if (s[i] === ' ') {
return i;
}
}

return -1;
}

function version(options) {
Expand Down
48 changes: 47 additions & 1 deletion spec/command_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('command', function() {
let output = "";
return {
print: function(str) {
output += str;
output += str + '\n';
},
getOutput: function() {
return output;
Expand Down Expand Up @@ -565,6 +565,52 @@ describe('command', function() {
});
});
});

describe('help', function() {
it('wraps text to the terminal width', async function() {
this.command = new Command(projectBaseDir, '', {
print: this.out.print,
terminalColumns: 50,
platform() {
return 'arbitrary';
}
});

await this.command.run(['help']);

const output = this.out.getOutput();
expect(output).toContain('version,-v show jasmine and jasmine-core\n' +
' versions\n');
expect(output).toContain(' --parallel=auto Run in parallel with an\n' +
' automatically chosen number\n' +
' of workers\n' +
' --no-color turn off color in spec\n' +
' output\n' +
' --color force turn on color in spec\n' +
' output\n');
expect(output).toContain('The given arguments take precedence over options\n' +
'in your jasmine.json.\n' +
'The path to your optional jasmine.json can also be\n' +
'configured by setting the JASMINE_CONFIG_PATH\n' +
'environment variable.\n');
});

it('wraps text to 80 columns when the terminal width is unknown', function() {
this.command = new Command(projectBaseDir, '', {
print: this.out.print,
terminalColumns: undefined,
platform() {
return 'arbitrary';
}
});

this.command.run(['help']);

const output = this.out.getOutput();
expect(output).toContain(' --parallel=auto Run in parallel with an automatically chosen number of\n' +
' workers\n');
});
});
});

// Adapted from Sindre Sorhus's escape-string-regexp (MIT license)
Expand Down

0 comments on commit 7884d34

Please sign in to comment.