Skip to content
Browse files

Merge pull request #49 from legien/master

Head command, plus fix for cat
  • Loading branch information...
2 parents 2ef7efb + c6cb356 commit b9f9ee998f9be6738c42a028aad7a3b6d87ff4da @dthree committed
View
2 bin/head.js
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./parser')(process.argv, 'head');
View
3 commands.json
@@ -1,10 +1,12 @@
{
"commands": [
"alias",
+ "cat",
"cd",
"clear",
"cp",
"echo",
+ "head",
"export",
"false",
"kill",
@@ -17,7 +19,6 @@
"tail",
"touch",
"true",
- "cat",
"less",
"grep",
"rm",
View
6 dist/commands/cat.js
@@ -84,10 +84,14 @@ var cat = {
// If -E, append a $ to each line end.
var dollarStr = options.showends ? '$' : '';
var line = numStr + parts[j] + dollarStr;
- self.log(line);
stdout += line + '\n';
}
}
+
+ if (stdout.length > 0) {
+ self.log(stdout.slice(0, stdout.length - 1));
+ }
+
return 0;
} catch (e) {
/* istanbul ignore next */
View
90 dist/commands/head.js
@@ -0,0 +1,90 @@
+'use strict';
+
+var interfacer = require('./../util/interfacer');
+var fs = require('fs');
+var fsAutocomplete = require('vorpal-autocomplete-fs');
+
+var head = {
+ exec: function exec(args, options) {
+ var self = this;
+ options = options || {};
+
+ options.argsType = args.stdin === undefined ? 'files' : 'stdin';
+ options.n = options.n === undefined ? 10 : options.n;
+
+ if (options.n < 1) {
+ self.log('Option n must be a positive integer.');
+ return 1;
+ }
+
+ if (options.argsType === 'stdin') {
+ self.log(head.readLines(args.stdin[0], options.n));
+ return 0;
+ }
+
+ var files = args.files || args;
+ files = files === undefined ? [] : files;
+ files = typeof files === 'string' ? String(files).split(' ') : files;
+ files = files.filter(function (arg) {
+ return String(arg).trim() !== '';
+ });
+
+ var stdout = '';
+ var writeHeaders = false;
+ if (files.length > 1) {
+ writeHeaders = true;
+ }
+
+ var content = [];
+ for (var i = 0; i < files.length; i++) {
+ try {
+ content[i] = fs.readFileSync(files[i]).toString();
+ } catch (e) {
+ self.log('head: ' + files[i] + ': No such file or directory');
+ return 1;
+ }
+ }
+
+ for (var i = 0; i < files.length; i++) {
+ if (writeHeaders) {
+ stdout += (i > 0 ? '\n\n' : '') + '==> ' + files[i] + ' <==\n';
+ }
+
+ stdout += head.readLines(content[i], options.n);
+ }
+
+ self.log(stdout);
+ return 0;
+ },
+ readLines: function readLines(content, numberOfLines) {
+ var stdout = '';
+ var contentArray = content.split('\n');
+ var linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
+ for (var i = 0; i < linesToRead; i++) {
+ if (stdout === '') {
+ stdout = contentArray[i];
+ continue;
+ }
+
+ stdout += '\n' + contentArray[i];
+ }
+
+ return stdout;
+ }
+};
+
+module.exports = function (vorpal) {
+ if (vorpal === undefined) {
+ return head;
+ }
+ vorpal.api.head = head;
+ vorpal.command('head [files...]').option('-n [number]', 'The first number of lines will be copied to stdout.').autocomplete(fsAutocomplete()).action(function (args, callback) {
+ args.options = args.options || {};
+ return interfacer.call(this, {
+ command: head,
+ args: args,
+ options: args.options,
+ callback: callback
+ });
+ });
+};
View
3 dist/help/head.js
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = "\nUsage: head [OPTION] [files ...]\nShow first lines of file(s).\n\nReport head bugs to <https://github.com/dthree/cash>\nCash home page: <http://cash.js.org/>\n";
View
5 packages/cat/dist/commands/cat.js
@@ -84,10 +84,13 @@ var cat = {
// If -E, append a $ to each line end.
var dollarStr = options.showends ? '$' : '';
var line = numStr + parts[j] + dollarStr;
- self.log(line);
stdout += line + '\n';
}
}
+
+ if (stdout.length > 0) {
+ self.log(stdout.slice(0, stdout.length - 1));
+ }
return 0;
} catch (e) {
/* istanbul ignore next */
View
32 packages/head/README.md/template.README.md
@@ -0,0 +1,32 @@
+# {package-name}
+
+---
+
+
+This is a cross-platform, 100% ES6 implementation of the Unix `{command-name}` command.
+
+```bash
+npm install {package-name} -g
+```
+
+This will install `{command-name}` globally in your system path.
+
+For help on the command, type:
+
+```bash
+> {command-name} --help
+```
+
+## More
+
+This module is part of [Cash](https://github.com/dthree/cash), a project providing cross-platform implementations of all major Unix-based commands in pure Javascript.
+
+
+## Related
+
+{related}
+
+
+## License
+
+MIT © [David Caccavella](https://github.com/dthree)
View
2 packages/head/bin/head.js
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('./parser')(process.argv, 'head');
View
50 packages/head/bin/parser.js
@@ -0,0 +1,50 @@
+'use strict';
+
+module.exports = function (args, command) {
+ args.splice(0, 2);
+ var pipes = (args.indexOf('|') > -1);
+ if (args.length === 0) {
+ // If we don't have to parse arguments, do
+ // the quickest load: just the raw js file
+ // of the command and nothing else.
+ var cmd = require('./../dist/commands/' + command)();
+ cmd.exec.call(console, {options: {}}, {});
+ } else if (pipes === false) {
+ // If we need to parse args for this
+ // command only, pull up vorpal and just load
+ // that one command.
+ var vorpal = require('vorpal')();
+ vorpal.api = {};
+ require('./../dist/commands/' + command)(vorpal);
+ args = args.join(' ');
+
+ // If we passed in a help request, load in
+ // the help file.
+ if (args.indexOf('help') > -1 || args.indexOf('?') > -1) {
+ let help;
+ try {
+ help = require('./../dist/help/' + command + '.js');
+ help = String(help).replace(/^\n|\n$/g, '');
+ } catch (e) {}
+ let cmdObj = vorpal.find(command);
+ if (cmdObj && help) {
+ cmdObj.help(function (argus, cb) {
+ cb(help);
+ })
+ }
+ }
+ vorpal.exec(command + ' ' + args);
+ } else {
+ // If we get into piping other commands,
+ // we need to go full bore and load the
+ // entire cash library.
+ // I guess we could technically parse all
+ // of the passed args, look for applicable
+ // commands and only load those, but that's
+ // some messy work for something that might
+ // not matter. If you're reading this and
+ // have deemed it matters, do a PR.
+ var cash = require('./../dist/index');
+ cash.vorpal.exec(command + ' ' + args.join(' '));
+ }
+};
View
44 packages/head/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "",
+ "version": "0.0.1",
+ "description": "",
+ "main": "",
+ "scripts": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/dthree/cash.git"
+ },
+ "keywords": [
+ "cash",
+ "terminal",
+ "emulator",
+ "cygwin",
+ "cli",
+ "windows",
+ "linux",
+ "unix",
+ "posix",
+ "bash",
+ "tty",
+ "util",
+ "vorpal",
+ "vorpal.js"
+ ],
+ "author": "dthree",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/dthree/cash/issues"
+ },
+ "homepage": "https://github.com/dthree/cash#readme",
+ "devDependencies": {},
+ "bin": {},
+ "dependencies": {},
+ "engines": {
+ "node": ">= 4",
+ "iojs": ">= 1.0.0"
+ },
+ "files": [
+ "dist",
+ "bin"
+ ]
+}
View
56 src/commands/cat.js
@@ -82,18 +82,22 @@ const cat = {
ctr++;
}
const numStr = (numbered) ?
- `${lpad(String(ctr), 6, ' ')} ` :
- '';
+ `${lpad(String(ctr), 6, ' ')} ` :
+ '';
// If -E, append a $ to each line end.
const dollarStr = (options.showends) ? '$' : '';
const line =
- numStr +
- parts[j] +
- dollarStr;
- self.log(line);
+ numStr +
+ parts[j] +
+ dollarStr;
stdout += `${line}\n`;
}
}
+
+ if (stdout.length > 0) {
+ self.log(stdout.slice(0, stdout.length - 1));
+ }
+
return 0;
} catch (e) {
/* istanbul ignore next */
@@ -110,25 +114,25 @@ module.exports = function (vorpal) {
}
vorpal.api.cat = cat;
vorpal
- .command('cat [files...]')
- .parse(preparser)
- .option('-A, --show-all', 'equivalent to -vET')
- .option('-b, --number-nonblank', 'number nonempty output lines, overrides -n')
- .option('-e', 'equivalent to -vE')
- .option('-E, --show-ends', 'display $ at end of each line')
- .option('-n, --number', 'number all output lines')
- .option('-s, --squeeze-blank', 'suppress repeated empty output lines')
- .option('-t', 'equivalent to -vT')
- .option('-T, --show-tabs', 'display TAB characters as ^I')
- .option('-v, --show-nonprinting', 'use ^ and M- notation, except for LFD and TAB') // this doesn't work yet...
- .autocomplete(fsAutocomplete())
- .action(function (args, cb) {
- args.options = args.options || {};
- return interfacer.call(this, {
- command: cat,
- args,
- options: args.options,
- callback: cb
+ .command('cat [files...]')
+ .parse(preparser)
+ .option('-A, --show-all', 'equivalent to -vET')
+ .option('-b, --number-nonblank', 'number nonempty output lines, overrides -n')
+ .option('-e', 'equivalent to -vE')
+ .option('-E, --show-ends', 'display $ at end of each line')
+ .option('-n, --number', 'number all output lines')
+ .option('-s, --squeeze-blank', 'suppress repeated empty output lines')
+ .option('-t', 'equivalent to -vT')
+ .option('-T, --show-tabs', 'display TAB characters as ^I')
+ .option('-v, --show-nonprinting', 'use ^ and M- notation, except for LFD and TAB') // this doesn't work yet...
+ .autocomplete(fsAutocomplete())
+ .action(function (args, cb) {
+ args.options = args.options || {};
+ return interfacer.call(this, {
+ command: cat,
+ args,
+ options: args.options,
+ callback: cb
+ });
});
- });
};
View
94 src/commands/head.js
@@ -0,0 +1,94 @@
+'use strict';
+
+const interfacer = require('./../util/interfacer');
+const fs = require('fs');
+const fsAutocomplete = require('vorpal-autocomplete-fs');
+
+const head = {
+
+ exec(args, options) {
+ const self = this;
+ options = options || {};
+
+ options.argsType = args.stdin === undefined ? 'files' : 'stdin';
+ options.n = options.n === undefined ? 10 : options.n;
+
+ if (options.n < 1) {
+ self.log('Option n must be a positive integer.');
+ return 1;
+ }
+
+ if (options.argsType === 'stdin') {
+ self.log(head.readLines(args.stdin[0], options.n));
+ return 0;
+ }
+
+ let files = args.files || args;
+ files = (files === undefined) ? [] : files;
+ files = (typeof files === 'string') ? String(files).split(' ') : files;
+ files = files.filter(arg => String(arg).trim() !== '');
+
+ let stdout = '';
+ let writeHeaders = false;
+ if (files.length > 1) {
+ writeHeaders = true;
+ }
+
+ const content = [];
+ for (let i = 0; i < files.length; i++) {
+ try {
+ content[i] = fs.readFileSync(files[i]).toString();
+ } catch (e) {
+ self.log(`head: ${files[i]}: No such file or directory`);
+ return 1;
+ }
+ }
+
+ for (let i = 0; i < files.length; i++) {
+ if (writeHeaders) {
+ stdout += `${i > 0 ? '\n\n' : ''}==> ${files[i]} <==\n`;
+ }
+
+ stdout += head.readLines(content[i], options.n);
+ }
+
+ self.log(stdout);
+ return 0;
+ },
+
+ readLines(content, numberOfLines) {
+ let stdout = '';
+ const contentArray = content.split('\n');
+ const linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines;
+ for (let i = 0; i < linesToRead; i++) {
+ if (stdout === '') {
+ stdout = contentArray[i];
+ continue;
+ }
+
+ stdout += `\n${contentArray[i]}`;
+ }
+
+ return stdout;
+ }
+};
+
+module.exports = function (vorpal) {
+ if (vorpal === undefined) {
+ return head;
+ }
+ vorpal.api.head = head;
+ vorpal
+ .command('head [files...]')
+ .option('-n [number]', 'The first number of lines will be copied to stdout.')
+ .autocomplete(fsAutocomplete())
+ .action(function (args, callback) {
+ args.options = args.options || {};
+ return interfacer.call(this, {
+ command: head,
+ args,
+ options: args.options,
+ callback
+ });
+ });
+};
View
1 src/help.js
@@ -12,6 +12,7 @@ const commands = [
'export [-p][id=[value]]',
'false',
'grep [-bHhinqsvw] [-m max] [--silent] [--include pattern] pattern [files ...]',
+ 'head [-n number] [files...]',
'kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l',
'less [files ...]',
'ls [-aAdFhilQrRStUwx1] [paths ...]',
View
7 src/help/head.js
@@ -0,0 +1,7 @@
+module.exports = `
+Usage: head [OPTION] [files ...]
+Show first lines of file(s).
+
+Report head bugs to <https://github.com/dthree/cash>
+Cash home page: <http://cash.js.org/>
+`;
View
38 test/head.js
@@ -0,0 +1,38 @@
+'use strict';
+
+require('assert');
+require('mocha');
+const should = require('should');
+const cash = require('../dist/index.js');
+const $ = require('shelljs');
+require('shelljs/global');
+
+describe('head', function () {
+ before(function () {
+ 'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11'.to('eleven.test');
+ 'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10'.to('ten.test');
+ });
+
+ after(function () {
+ $.rm(['eleven.test', 'ten.test']);
+ });
+
+ it('should exist and be a function', function () {
+ should.exist(cash.head);
+ });
+
+ it('should give back ten lines when called without options', function () {
+ const result = cash.head('eleven.test');
+ result.should.be.equal('line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\n');
+ });
+
+ it('should give back five lines when called with option n set to 5', function () {
+ const result = cash.head('eleven.test', {n: 5});
+ result.should.be.equal('line1\nline2\nline3\nline4\nline5\n');
+ });
+
+ it('should write header when used with more than one file', function () {
+ const result = cash.head(['eleven.test', 'ten.test'], {n: 2});
+ result.should.be.equal('==> eleven.test <==\nline1\nline2\n\n==> ten.test <==\nline1\nline2\n');
+ });
+});

0 comments on commit b9f9ee9

Please sign in to comment.
Something went wrong with that request. Please try again.