diff --git a/.vscode/launch.json b/.vscode/launch.json index 20594863246..1cb73684248 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,8 +11,8 @@ // "runtimeArgs": ["--harmony-default-parameters", "--harmony-rest-parameters"], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out/src", - "preLaunchTask": "npm" + "outDir": "${workspaceRoot}/out/src" + // "preLaunchTask": "npm" }, { "name": "Launch Tests", @@ -23,8 +23,8 @@ // "runtimeArgs": ["--js-flags=\"--harmony --harmony-default-parameters\""], "stopOnEntry": false, "sourceMaps": true, - "outDir": "${workspaceRoot}/out/test", - "preLaunchTask": "npm" + "outDir": "${workspaceRoot}/out/test" + // "preLaunchTask": "npm" } ] } \ No newline at end of file diff --git a/extension.ts b/extension.ts index 31b2aee7b85..28f34aec79e 100644 --- a/extension.ts +++ b/extension.ts @@ -1,33 +1,37 @@ -"use strict" +"use strict"; + +/** + * Extension.ts is a lightweight wrapper around ModeHandler. It converts key + * events to their string names and passes them on to ModeHandler via + * handleKeyEvent(). + */ import * as vscode from 'vscode'; import {showCmdLine} from './src/cmd_line/main'; -import * as cc from './src/cmd_line/lexer'; import {ModeHandler} from "./src/mode/modeHandler"; -import {ModeName} from "./src/mode/mode"; -var modeHandler : ModeHandler; -var extensionContext : vscode.ExtensionContext; +var extensionContext: vscode.ExtensionContext; +var modeHandler: ModeHandler; export function activate(context: vscode.ExtensionContext) { extensionContext = context; registerCommand(context, 'type', async (args) => { - if (!vscode.window.activeTextEditor) { - return; - } - + if (!vscode.window.activeTextEditor) { + return; + } + console.log(args.text); - + var isHandled = await handleKeyEvent(args.text); - if (!isHandled) { + if (!isHandled) { vscode.commands.executeCommand('default:type', { text: args.text }); } }); - + registerCommand(context, 'extension.vim_esc', () => handleKeyEvent("esc")); registerCommand(context, 'extension.showCmdLine', () => { if (!modeHandler) { diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index c0c85d97018..426f7a5337e 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -29,10 +29,13 @@ export class ModeHandler implements vscode.Disposable { this.setCurrentModeByName(ModeName.Normal); } + /** + * The active mode. + */ get currentMode() : Mode { return this._modes.find(mode => mode.isActive); } - + setNormal() { this.setCurrentModeByName(ModeName.Normal); } @@ -56,7 +59,7 @@ export class ModeHandler implements vscode.Disposable { this.setupStatusBarItem(statusBarText ? `-- ${statusBarText.toUpperCase()} --` : ''); } - handleKeyEvent(key : string) : Promise { + async handleKeyEvent(key : string) : Promise { // Due to a limitation in Electron, en-US QWERTY char codes are used in international keyboards. // We'll try to mitigate this problem until it's fixed upstream. // https://github.com/Microsoft/vscode/issues/713 @@ -79,12 +82,21 @@ export class ModeHandler implements vscode.Disposable { if (nextMode) { this.currentMode.handleDeactivation(); this.setCurrentModeByName(nextMode.name); - return nextMode.handleActivation(key).then(() => { return true; }); + + await nextMode.handleActivation(key); + + return true; } else { return this.currentMode.handleKeyEvent(key); } } + async handleMultipleKeyEvents(keys: string[]): Promise { + for (const key of keys) { + await this.handleKeyEvent(key); + } + } + setupStatusBarItem(text : string) : void { if (!this._statusBarItem) { this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); diff --git a/src/mode/modeNormal.ts b/src/mode/modeNormal.ts index 544289fe7bb..ca16e956716 100644 --- a/src/mode/modeNormal.ts +++ b/src/mode/modeNormal.ts @@ -211,13 +211,10 @@ export class NormalMode extends Mode { } shouldBeActivated(key : string, currentMode : ModeName) : boolean { - // TODO: Have these keybinds configurable - return (key === 'esc' || key === 'ctrl+[' || (key === "v" && currentMode === ModeName.Visual)); + return (key === '' || key === '' || key === '' || (key === "v" && currentMode === ModeName.Visual)); } - async handleActivation(key : string): Promise { - this.motion.left().move(); - } + async handleActivation(key : string): Promise { ; } async handleKeyEvent(key : string): Promise { this._keyHistory.push(key); diff --git a/src/operator/put.ts b/src/operator/put.ts index 0e3c9b379f5..718bbf45fba 100644 --- a/src/operator/put.ts +++ b/src/operator/put.ts @@ -18,7 +18,7 @@ export class PutOperator extends Operator { * Run this operator on a range. */ public async run(start: Position, end: Position): Promise { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { paste(async (err, data) => { if (err) { reject(); diff --git a/src/textEditor.ts b/src/textEditor.ts index 655121d9706..6529ca619b3 100644 --- a/src/textEditor.ts +++ b/src/textEditor.ts @@ -33,7 +33,7 @@ export class TextEditor { } /** - * Delete the entire document. + * Removes all text in the entire document. */ static async deleteDocument(): Promise { const start = new vscode.Position(0, 0); diff --git a/test/mode/modeInsert.test.ts b/test/mode/modeInsert.test.ts index 44b41730f83..2a2cc76a8cb 100644 --- a/test/mode/modeInsert.test.ts +++ b/test/mode/modeInsert.test.ts @@ -1,93 +1,118 @@ "use strict"; -import * as assert from 'assert'; -import {CommandKeyMap} from '../../src/configuration/commandKeyMap'; -import {setupWorkspace, cleanUpWorkspace, assertEqualLines} from './../testUtils'; -import {InsertMode} from '../../src/mode/modeInsert'; +import {setupWorkspace, cleanUpWorkspace, assertEqualLines, assertEqual} from './../testUtils'; import {ModeName} from '../../src/mode/mode'; -import {Motion, MotionMode} from '../../src/motion/motion'; import {TextEditor} from '../../src/textEditor'; +import {ModeHandler} from "../../src/mode/modeHandler"; suite("Mode Insert", () => { - - let motion: Motion; - let modeInsert: InsertMode; + let modeHandler: ModeHandler; setup(async () => { await setupWorkspace(); - motion = new Motion(MotionMode.Cursor); - modeInsert = new InsertMode(motion, CommandKeyMap.DefaultInsertKeyMap()); + modeHandler = new ModeHandler(); }); teardown(cleanUpWorkspace); - test("can be activated", () => { - let activationKeys = ['i', 'I', 'o', 'O', 'a', 'A']; + test("can be activated", async () => { + let activationKeys = ['o', 'I', 'i', 'O', 'a', 'A']; for (let key of activationKeys) { - assert.equal(modeInsert.shouldBeActivated(key, ModeName.Normal), true, key); - } + await modeHandler.handleKeyEvent(key); + assertEqual(modeHandler.currentMode.name, ModeName.Insert); - assert.equal(modeInsert.shouldBeActivated("i", ModeName.Visual), false, "can be activated from visual"); + await modeHandler.handleKeyEvent(''); + } }); test("can handle key events", async () => { - await modeInsert.handleKeyEvent("!"); + await modeHandler.handleMultipleKeyEvents(['i', '!']); return assertEqualLines(["!"]); }); + test(" doesn't change cursor position", async () => { + await modeHandler.handleMultipleKeyEvents([ + 'i', + 'h', 'e', 'l', 'l', 'o', + '' + ]); + + assertEqual(TextEditor.getSelection().start.character, 5, " moved cursor position."); + }); + test("Can handle 'o'", async () => { - await TextEditor.insert("text"); - await modeInsert.handleActivation("o"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', + '', + 'o' + ]); return assertEqualLines(["text", ""]); }); test("Can handle 'O'", async () => { - await TextEditor.insert("text"); - await modeInsert.handleActivation("O"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', + '', + 'O' + ]); return assertEqualLines(["", "text"]); }); test("Can handle 'i'", async () => { - await TextEditor.insert("texttext"); - - motion = motion.moveTo(0, 4); - await modeInsert.handleActivation("i"); - await modeInsert.handleKeyEvent("!"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', 't', 'e', 'x', 't', // insert 'texttext' + '', + '^', 'l', 'l', 'l', 'l', // move to the 4th character + 'i', + '!' // insert a ! + ]); assertEqualLines(["text!text"]); }); test("Can handle 'I'", async () => { - await TextEditor.insert("text"); - motion = motion.moveTo(0, 3); - - await modeInsert.handleActivation("I"); - await modeInsert.handleKeyEvent("!"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', + '', + '^', 'l', 'l', 'l', + 'I', + '!', + ]); assertEqualLines(["!text"]); }); test("Can handle 'a'", async () => { - await TextEditor.insert("texttext"); - - motion = motion.moveTo(0, 4); - await modeInsert.handleActivation("a"); - await modeInsert.handleKeyEvent("!"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', 't', 'e', 'x', 't', // insert 'texttext' + '', + '^', 'l', 'l', 'l', 'l', // move to the 4th character + 'a', + '!' // append a ! + ]); assertEqualLines(["textt!ext"]); }); test("Can handle 'A'", async () => { - await TextEditor.insert("text"); - - motion = motion.moveTo(0, 0); - await modeInsert.handleActivation("A"); - await modeInsert.handleKeyEvent("!"); + await modeHandler.handleMultipleKeyEvents([ + 'i', + 't', 'e', 'x', 't', + '', + '^', + 'A', + '!', + ]); assertEqualLines(["text!"]); }); diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index 272ef624460..020bcb3dab8 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -26,7 +26,7 @@ suite("Mode Normal", () => { teardown(cleanUpWorkspace); test("can be activated", () => { - let activationKeys = ['esc', 'ctrl+[']; + let activationKeys = ['', '']; for (let i = 0; i < activationKeys.length; i++) { let key = activationKeys[i]; diff --git a/test/operator/put.test.ts b/test/operator/put.test.ts index 65cdeb97a1b..430c4cfd7ee 100644 --- a/test/operator/put.test.ts +++ b/test/operator/put.test.ts @@ -19,7 +19,10 @@ suite("put operator", () => { const position = new Position(0, 0, PositionOptions.CharacterWiseExclusive); const mode = new ModeHandler(); const put = new PutOperator(mode); - copy(expectedText); + + await new Promise(resolve => { + copy(expectedText, () => resolve()); + }); await put.run(position, position); @@ -39,7 +42,10 @@ suite("put operator", () => { const position = new Position(0, 3, PositionOptions.CharacterWiseExclusive); const mode = new ModeHandler(); const put = new PutOperator(mode); - copy(phrase); + + await new Promise(resolve => { + copy(phrase, () => resolve()); + }); // using ^ to show the cusor position // before : the dog diff --git a/test/testUtils.ts b/test/testUtils.ts index 1a2c7f5906c..1731a4b6a08 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -30,6 +30,16 @@ export function assertEqualLines(expectedLines: string[]) { } } +/** + * Assert that the first two arguments are equal, and fail a test otherwise. + * + * The only difference between this and assert.equal is that here we + * check to ensure the types of the variables are correct. + */ +export function assertEqual(one: T, two: T, message: string = ""): void { + assert.equal(one, two, message); +} + export async function setupWorkspace(): Promise { const file = await createRandomFile(""); const doc = await vscode.workspace.openTextDocument(file);