Permalink
Browse files

Add smart output--automatically pretty-print and page if targeting a TTY

  • Loading branch information...
1 parent e087224 commit 1001a24859a763febb4b0bf55b80e2df63dfdb72 @misterfifths committed Jan 8, 2012
Showing with 56 additions and 5 deletions.
  1. +56 −5 jutil.js
View
@@ -37,6 +37,12 @@ var defaultConfig = {
// cycles) if you do a lot of piping of output.
alwaysPrettyPrint: false,
+ // By default, if stdout is a terminal, the output will be pretty-printed
+ // and, if it is larger than your window, piped into your pager (the PAGER
+ // environment variable or 'less', by default). Setting this to true
+ // disables that behavior.
+ disableSmartOutput: false,
+
// Always sort keys in the output. Useful for automated testing or
// doing diffs against the results.
alwaysSort: false,
@@ -498,14 +504,19 @@ function makeRuntimeSettings(commandDesc, config, opts)
{
var fs = require('fs'),
vm = require('vm'),
+ isatty = require('tty').isatty(process.stdout.fd),
settings = {},
dirs;
if(commandDesc.outputsJSON) {
+ if(opts.disableSmartOutput) settings.smartOutput = false;
+ else settings.smartOutput = opts.disableSmartOutput === false || !config.disableSmartOutput;
+
if(opts.prettyPrint === false) {} // --no-pretty-print
- else if(opts.prettyPrint || config.alwaysPrettyPrint) settings.prettyPrinter = config.prettyPrinter;
+ else if(opts.prettyPrint || config.alwaysPrettyPrint || (settings.smartOutput && isatty))
+ settings.prettyPrinter = config.prettyPrinter;
- if(opts.sort === false) {} // --no-pretty-print
+ if(opts.sort === false) {} // --no-sort
else if(opts.sort || config.alwaysSort) settings.sort = true;
}
@@ -599,8 +610,10 @@ function loadModules(modulePaths, sandbox)
function outputJSON(obj, runtimeSettings, config)
{
- var fs = require('fs'),
- buffer;
+ var buffer,
+ lineCount,
+ pagerCmd,
+ pager;
if(obj === undefined)
return;
@@ -626,12 +639,44 @@ function outputJSON(obj, runtimeSettings, config)
return;
}
+ if(runtimeSettings.smartOutput &&
+ require('tty').isatty(process.stdout.fd))
+ {
+ lineCount = obj.length - obj.replace(new RegExp('\n', 'g'), '').length;
+ if(lineCount > process.stdout.getWindowSize()[1]) {
+ // Autopage
+ pagerCmd = process.env.PAGER || 'less';
+
+ pager = require('child_process')
+ .spawn(pagerCmd, [], {
+ customFds: [-1, process.stdout.fd, -1]
+ });
+
+ pager.stderr.setEncoding('utf8');
+ pager.stderr.on('data', function(data) {
+ console.error('Error running pager command ("' + pagerCmd + '"): ' + data);
+ process.exit(1);
+ });
+
+ pager.stdin.end(obj);
+ pager.stdin.on('error', function(exc) {
+ // Silence EPIPE; just means that they closed the pager before
+ // we finished writing (or the pager never started, in which
+ // case the stderr output will be sufficient).
+ if(exc.code != 'EPIPE')
+ throw exc;
+ });
+
+ return;
+ }
+ }
+
// process.stdout.write seems like the obvious choice here, but
// it causes an exception if we pipe a big result to something
// and close the whole shebang before it can finish writing.
// Should probably file a node bug...
buffer = new Buffer(obj);
- fs.write(1, buffer, 0, buffer.length);
+ require('fs').write(process.stdout.fd, buffer, 0, buffer.length);
}
@@ -713,6 +758,12 @@ function parseCommandLine(commands)
abbr: 's',
flag: true,
help: 'Sort keys in the output.'
+ },
+ disableSmartOutput: {
+ abbr: 'S',
+ full: 'disable-smart',
+ flag: true,
+ help: 'Don\'t pretty-print or autopage if stdout is a terminal.'
}
};

0 comments on commit 1001a24

Please sign in to comment.