Skip to content

Commit

Permalink
Merge pull request #736 from dominic31/read-command
Browse files Browse the repository at this point in the history
Read command
  • Loading branch information
johnfn authored Sep 15, 2016
2 parents 98a538e + 1c65324 commit c16a57c
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 2 deletions.
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ Status | Command | Description

Status | Command | Description
---|--------|------------------------------
:arrow_down:| :r [file] | insert the contents of [file] below the cursor
:arrow_down:| :r! {command} | insert the standard output of {command} below the cursor
:warning: | :r [file] | insert the contents of [file] below the cursor
:warning: | :r! {command} | insert the standard output of {command} below the cursor

## Deleting text

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@
"postinstall": "node ./node_modules/vscode/bin/install && gulp init"
},
"dependencies": {
"child-process": "^1.0.2",
"copy-paste": "^1.3.0",
"diff-match-patch": "^1.0.0",
"lodash": "^4.12.0"
Expand Down
81 changes: 81 additions & 0 deletions src/cmd_line/commands/read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use strict";

import * as node from "../node";
import {readFile} from 'fs';
import {exec} from 'child_process';
import {TextEditor} from '../../textEditor';

export interface IReadCommandArguments extends node.ICommandArgs {
file?: string;
cmd?: string;
}

//
// Implements :read and :read!
// http://vimdoc.sourceforge.net/htmldoc/insert.html#:read
// http://vimdoc.sourceforge.net/htmldoc/insert.html#:read!
//
export class ReadCommand extends node.CommandBase {
protected _arguments : IReadCommandArguments;

constructor(args : IReadCommandArguments) {
super();
this._name = 'read';
this._shortName = 'r';
this._arguments = args;
}

get arguments() : IReadCommandArguments {
return this._arguments;
}

async execute() : Promise<void> {
const textToInsert = await this.getTextToInsert();
if (textToInsert) {
await TextEditor.insert(textToInsert);
}
}

async getTextToInsert() : Promise<string> {
if (this.arguments.file && this.arguments.file.length > 0) {
return await this.getTextToInsertFromFile();
} else if (this.arguments.cmd && this.arguments.cmd.length > 0) {
return await this.getTextToInsertFromCmd();
} else {
throw Error('Invalid arguments');
}
}

async getTextToInsertFromFile() : Promise<string> {
// TODO: Read encoding from ++opt argument.
return new Promise<string>((resolve, reject) => {
try {
readFile(this.arguments.file as string, 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
} catch (e) {
reject(e);
}
});
}

async getTextToInsertFromCmd() : Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
exec(this.arguments.cmd as string, (err, stdout, stderr) => {
if (err) {
reject(err);
} else {
resolve(stdout);
}
});
} catch (e) {
reject(e);
}
});
}
}
8 changes: 8 additions & 0 deletions src/cmd_line/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ export class Scanner {
return s;
}

// Returns the text from the current position to the end.
remaining() : string {
while (!this.isAtEof) {
this.next();
}
return this.emit();
}

backup(): void {
this.pos--;
}
Expand Down
4 changes: 4 additions & 0 deletions src/cmd_line/subparser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as tabCmd from './subparsers/tab';
import * as fileCmd from './subparsers/file';
import {parseOptionsCommandArgs} from './subparsers/setoptions';
import {parseSubstituteCommandArgs} from './subparsers/substitute';
import {parseReadCommandArgs} from './subparsers/read';
import {parseRegisterCommandArgs} from './subparsers/register';

// maps command names to parsers for said commands.
Expand Down Expand Up @@ -61,5 +62,8 @@ export const commandParsers = {
set: parseOptionsCommandArgs,
se: parseOptionsCommandArgs,

read: parseReadCommandArgs,
r: parseReadCommandArgs,

reg: parseRegisterCommandArgs
};
32 changes: 32 additions & 0 deletions src/cmd_line/subparsers/read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";

import {ReadCommand, IReadCommandArguments} from '../commands/read';
import {Scanner} from '../scanner';

export function parseReadCommandArgs(args : string) : ReadCommand {
if (!args) {
throw Error('Expected arguments.');
}

var scannedArgs : IReadCommandArguments = {};
var scanner = new Scanner(args);

scanner.skipWhiteSpace();
let c = scanner.next();
// read command has 2 forms - 'read <file-path>' and 'read! <shell-command>'
if (c === '!') {
scanner.ignore();
scanner.skipWhiteSpace();
scannedArgs.cmd = scanner.remaining();
if (!scannedArgs.cmd || scannedArgs.cmd.length === 0) {
throw Error('Expected shell command.');
}
} else {
scannedArgs.file = scanner.remaining();
if (!scannedArgs.file || scannedArgs.file.length === 0) {
throw Error('Expected file path.');
}
}

return new ReadCommand(scannedArgs);
}
25 changes: 25 additions & 0 deletions test/cmd_line/read.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use strict";

import { ModeHandler } from '../../src/mode/modeHandler';
import { setupWorkspace, cleanUpWorkspace, assertEqualLines } from './../testUtils';
import { runCmdLine } from '../../src/cmd_line/main';

suite("read", () => {
let modeHandler: ModeHandler;

setup(async () => {
await setupWorkspace();
modeHandler = new ModeHandler();
});

teardown(cleanUpWorkspace);

test("Can read shell command output", async () => {
await runCmdLine('r! echo hey\\\\n\\\\tho', modeHandler);
assertEqualLines([
'hey',
'\tho',
''
]);
});
});

0 comments on commit c16a57c

Please sign in to comment.