/
modeHandler.ts
121 lines (101 loc) · 4.28 KB
/
modeHandler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"use strict";
import * as _ from 'lodash';
import * as vscode from 'vscode';
import * as cmds from './commands';
import {Mode, ModeName} from './mode';
import {Motion, MotionMode} from './../motion/motion';
import {NormalMode} from './modeNormal';
import {InsertMode} from './modeInsert';
import {VisualMode} from './modeVisual';
import {Configuration} from '../configuration';
export class ModeHandler implements vscode.Disposable {
private _motion : Motion;
private _modes : Mode[];
private _statusBarItem : vscode.StatusBarItem;
private _configuration : Configuration;
constructor() {
this._configuration = Configuration.fromUserFile();
// This probably should be somewhere else but will work for now.
let normalKeymap = cmds.newDefaultNormalKeymap();
let insertKeymap = cmds.newDefaultInsertKeymap();
let visualKeymap = cmds.newDefaultVisualKeymap();
let normalKeymapConf = vscode.workspace.getConfiguration("vim")
.get("normalModeKeybindings", cmds.newDefaultNormalKeymap());
let insertKeymapConf = vscode.workspace.getConfiguration("vim")
.get("insertModeKeybindings", cmds.newDefaultInsertKeymap());
let visualKeymapConf = vscode.workspace.getConfiguration("vim")
.get("visualModeKeybindings", cmds.newDefaultVisualKeymap());
let copyFunc = function (to: {[key: string]: cmds.Command},
source: {[key: string]: cmds.Command}) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
to[key] = source[key];
}
}
};
copyFunc(normalKeymap, normalKeymapConf);
copyFunc(insertKeymap, insertKeymapConf);
copyFunc(visualKeymap, visualKeymapConf);
this._motion = new Motion(null);
this._modes = [
new NormalMode(this._motion, this, normalKeymap),
new InsertMode(this._motion, insertKeymap),
new VisualMode(this._motion, this, visualKeymap),
];
this.setCurrentModeByName(ModeName.Normal);
}
get currentMode() : Mode {
return this._modes.find(mode => mode.isActive);
}
setCurrentModeByName(modeName : ModeName) {
for (let mode of this._modes) {
mode.isActive = (mode.name === modeName);
}
switch (modeName) {
case ModeName.Insert:
this._motion = this._motion.changeMode(MotionMode.Cursor);
break;
case ModeName.Normal:
this._motion = this._motion.changeMode(MotionMode.Caret);
break;
}
const statusBarText = (this.currentMode.name === ModeName.Normal) ? '' : ModeName[modeName];
this.setupStatusBarItem(statusBarText ? `-- ${statusBarText.toUpperCase()} --` : '');
}
handleKeyEvent(key : string) : void {
// 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
key = this._configuration.keyboardLayout.translate(key);
let currentModeName = this.currentMode.name;
let keysPressed = this.currentMode.keyHistory.join('') + key;
let nextMode : Mode;
let inactiveModes = _.filter(this._modes, (m) => !m.isActive);
for (let mode of inactiveModes) {
if (mode.shouldBeActivated(keysPressed, currentModeName)) {
if (nextMode) {
console.error("More that one mode matched in handleKeyEvent!");
}
nextMode = mode;
}
}
if (nextMode) {
this.currentMode.handleDeactivation();
this.setCurrentModeByName(nextMode.name);
nextMode.handleActivation(key);
} else {
this.currentMode.handleKeyEvent(key);
}
}
setupStatusBarItem(text : string) : void {
if (!this._statusBarItem) {
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
}
this._statusBarItem.text = text || '';
this._statusBarItem.show();
}
dispose() {
this._statusBarItem.dispose();
this._motion.dispose();
}
}