mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-06-13 07:10:26 +08:00
Normalize the vim sample
This commit is contained in:
@ -90,7 +90,13 @@ const samples = [{
|
||||
apis: ['window.createTreeView', 'window.registerTreeDataProvider', 'TreeView', 'TreeDataProvider'],
|
||||
contributions: ['views', 'viewsContainers']
|
||||
},
|
||||
// { description: 'vim-sample', path: 'vim-sample', guide: null, apis: [], contributions: [] },
|
||||
{
|
||||
description: 'vim-sample',
|
||||
path: 'vim-sample',
|
||||
guide: null,
|
||||
apis: [`commands`, `StatusBarItem`, `window.createStatusBarItem`, `TextEditorCursorStyle`, `window.activeTextEditor`, `Position`, `Range`, `Selection`, `TextEditor`, `TextEditorRevealType`, `TextDocument`],
|
||||
contributions: []
|
||||
},
|
||||
// { description: 'webpack-sample', path: 'webpack-sample', guide: null, apis: [], contributions: [] },
|
||||
];
|
||||
|
||||
|
||||
7
vim-sample/.vscode/extensions.json
vendored
Normal file
7
vim-sample/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"eg2.tslint"
|
||||
]
|
||||
}
|
||||
21
vim-sample/.vscode/launch.json
vendored
21
vim-sample/.vscode/launch.json
vendored
@ -1,27 +1,14 @@
|
||||
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/out/src/**/*.js"],
|
||||
"preLaunchTask": "npm: watch"
|
||||
},
|
||||
{
|
||||
"name": "Launch Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/out/test/**/*.js"],
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
|
||||
"outFiles": ["${workspaceFolder}/out/**/*.js"],
|
||||
"preLaunchTask": "npm: watch"
|
||||
}
|
||||
]
|
||||
|
||||
13
vim-sample/.vscode/settings.json
vendored
13
vim-sample/.vscode/settings.json
vendored
@ -1,14 +1,3 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.exclude": {
|
||||
"out": false // set this to true to hide the "out" folder with the compiled JS files
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"search.exclude": {
|
||||
"out": true // set this to false to include "out" folder in search results
|
||||
},
|
||||
// Turn off tsc task auto detection since we have the necessary task as npm scripts
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
|
||||
"editor.insertSpaces": false,
|
||||
}
|
||||
@ -1,38 +1,32 @@
|
||||
# VSCode vim sample
|
||||
|
||||
This is an extension sample showing how vim emulation could be implemented in a VS Code extension, starting with VS Code version 0.10.12.
|
||||
This is an extension sample showing how vim emulation could be implemented in a VS Code extension.
|
||||
|
||||

|
||||
|
||||
## Why create this sample and not contribute to an existing vim extension?
|
||||
The reason for creating this sample was to figure out the APIs missing in VS Code in order to be able to create a good vim emulation experience.
|
||||
There are already multiple [vim extensions for VS Code](https://marketplace.visualstudio.com/search?term=vim&target=VSCode&sortBy=Relevance) and I don't want to send mixed signals by picking one to contribute to.
|
||||
And it's fun to write an extension, even if it's just a sample! :)
|
||||
|
||||
|
||||
## Approach (what is new in 0.10.12)
|
||||
## Approach
|
||||
|
||||
### Typing
|
||||
|
||||
* When a key is pressed, VS Code gets a `keydown` event. The `keydown` event contains information about modifier keys (`ctrl`, `alt`, etc.) and about the key code. The `keydown` event does not contain information about what character would get produced and not all `keydown` events produce characters.
|
||||
* The `keydown` event runs through the keybinding rules and the first rule that matches gets executed. This allows to bind commands to key combinations that would usually not produce visual characters.
|
||||
* An extension should generally not add rules for key combinations that might produce characters (e.g. don't add rules for `"a"`, `"shift+a"` or `"ctrl+alt+o"`, as these key combinations will not necessarily produce the same characters under different keyboard layouts).
|
||||
* When a `keydown` is not matched by any keybinding rule, it might produce a character. Since 0.10.12 this is dispatched to the `type` command.
|
||||
* When a `keydown` is not matched by any keybinding rule, it might produce a character. This is dispatched to the `type` command.
|
||||
* It is therefore possible for an extension to **overwrite** the `type` command and handle characters instead of the VS Code editor.
|
||||
* There is a `default:type` command that maps to the VS Code editor's type handler in case an extension wishes to delegate back typing to VS Code.
|
||||
* There is another command, `replacePreviousChar` that you should be aware of. On the Mac if I remember correctly, it is possible to generate certain accented characters by long pressing a key. When this happens, a `replacePreviousChar` command is invoked containing the new characters and the number of characters that should be replaced before.
|
||||
* There is another command, `replacePreviousChar` that you should be aware of. On the Mac it is possible to generate certain accented characters by long pressing a key. When this happens, a `replacePreviousChar` command is invoked containing the new characters and the number of characters that should be replaced before.
|
||||
* At this time, `type`, `replacePreviousChar`, `paste` and `cut` are dispatched through the keybinding rules. There are [other internal VS Code editor commands](https://github.com/Microsoft/vscode/blob/master/src/vs/editor/browser/view/viewController.ts) (such as those coming in from mouse operations) that are not dispatched and cannot be at this time overwritten from an extension. From writing this sample, I haven't found the need to overwrite them, but if you have a use-case where that would make sense, please open an issue on the vscode repo.
|
||||
|
||||
### Cursor Style
|
||||
|
||||
* The `TextEditorOptions` now also has a `cursorStyle` property that allows to change the cursor style programmatically.
|
||||
* The `TextEditorOptions` has a `cursorStyle` property that allows to change the cursor style programmatically.
|
||||
|
||||
### Keybinding contexts
|
||||
|
||||
* There is a new command, `setContext`, that can be invoked with two arguments, a key and a value. It allows to add custom properties to the keybinding conditions.
|
||||
|
||||
|
||||
## Take it for a spin
|
||||
## Running the Sample
|
||||
|
||||
> Note: You need to run from VS Code source, as the 0.10.12 version is not yet released.
|
||||
|
||||
|
||||
823
vim-sample/package-lock.json
generated
823
vim-sample/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -70,8 +70,9 @@
|
||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^2.1.4",
|
||||
"vscode": "^1.1.17",
|
||||
"@types/node": "*"
|
||||
"@types/node": "8.x.x",
|
||||
"tslint": "^5.11.0",
|
||||
"typescript": "^2.9.2",
|
||||
"vscode": "^1.1.17"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { MotionState, Motion } from './motions';
|
||||
|
||||
export enum Mode {
|
||||
@ -14,9 +13,9 @@ export enum Mode {
|
||||
}
|
||||
|
||||
export interface ModifierKeys {
|
||||
ctrl?: boolean,
|
||||
alt?: boolean,
|
||||
shifit?: boolean
|
||||
ctrl?: boolean;
|
||||
alt?: boolean;
|
||||
shifit?: boolean;
|
||||
}
|
||||
|
||||
export class DeleteRegister {
|
||||
@ -48,6 +47,6 @@ export abstract class AbstractCommandDescriptor {
|
||||
}
|
||||
|
||||
export interface Command {
|
||||
commandId: string,
|
||||
args?: any[]
|
||||
commandId: string;
|
||||
args?: any[];
|
||||
}
|
||||
|
||||
@ -4,15 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
TextEditorCursorStyle,
|
||||
Position,
|
||||
Range,
|
||||
Selection,
|
||||
TextEditor,
|
||||
TextEditorRevealType,
|
||||
window
|
||||
} from 'vscode';
|
||||
import { TextEditorCursorStyle, Position, Range, Selection, TextEditor, TextEditorRevealType, window } from 'vscode';
|
||||
|
||||
import { Words } from './words';
|
||||
import { MotionState, Motion } from './motions';
|
||||
|
||||
@ -6,11 +6,7 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { Words } from './words';
|
||||
import { MotionState, Motion, Motions } from './motions';
|
||||
import { Operator, Operators } from './operators';
|
||||
import { Mode, IController, ModifierKeys } from './common';
|
||||
import { Mappings } from './mappings';
|
||||
import { Mode, ModifierKeys } from './common';
|
||||
import { Controller } from './controller';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
@ -95,7 +91,7 @@ class VimExt {
|
||||
this._hasInput = new ContextKey('vim.hasInput');
|
||||
this._statusBar = new StatusBar();
|
||||
|
||||
this._controller = new Controller()
|
||||
this._controller = new Controller();
|
||||
|
||||
vscode.window.onDidChangeActiveTextEditor((textEditor) => {
|
||||
if (!textEditor) {
|
||||
|
||||
@ -13,39 +13,39 @@ const CHAR_TO_BINDING: { [char: string]: any; } = {};
|
||||
function defineBinding(char: string, value: any, modifierKeys: ModifierKeys): void {
|
||||
let key = modifierKeys.ctrl ? 'CTRL + ' + char : char;
|
||||
CHAR_TO_BINDING[key] = value;
|
||||
};
|
||||
}
|
||||
function getBinding(char: string, modifierKeys: ModifierKeys): any {
|
||||
let key = modifierKeys.ctrl ? 'CTRL + ' + char : char;
|
||||
return CHAR_TO_BINDING[key];
|
||||
};
|
||||
}
|
||||
|
||||
function defineOperator(char: string, operator: Operator, modifierKeys: ModifierKeys = {}): void {
|
||||
defineBinding(char + '__operator__', operator, modifierKeys);
|
||||
};
|
||||
}
|
||||
function getOperator(char: string, modifierKeys: ModifierKeys = {}): Operator {
|
||||
return getBinding(char + '__operator__', modifierKeys);
|
||||
};
|
||||
}
|
||||
|
||||
function defineCommand(char: string, commandId: string, modifierKeys: ModifierKeys = {}): void {
|
||||
defineBinding(char + '__command__', { commandId: commandId }, modifierKeys);
|
||||
};
|
||||
}
|
||||
function getCommand(char: string, modifierKeys: ModifierKeys = {}): Command {
|
||||
return getBinding(char + '__command__', modifierKeys);
|
||||
};
|
||||
}
|
||||
|
||||
function defineMotion(char: string, motion: Motion, modifierKeys: ModifierKeys = {}): void {
|
||||
defineBinding(char + '__motion__', motion, modifierKeys);
|
||||
};
|
||||
}
|
||||
function getMotion(char: string, modifierKeys: ModifierKeys = {}): Motion {
|
||||
return getBinding(char + '__motion__', modifierKeys);
|
||||
};
|
||||
}
|
||||
|
||||
function defineMotionCommand(char: string, motionCommand: AbstractCommandDescriptor, modifierKeys: ModifierKeys = {}): void {
|
||||
defineBinding(char + '__motioncommand__', motionCommand, modifierKeys);
|
||||
};
|
||||
}
|
||||
function getMotionCommand(char: string, modifierKeys: ModifierKeys = {}): AbstractCommandDescriptor {
|
||||
return getBinding(char + '__motioncommand__', modifierKeys);
|
||||
};
|
||||
}
|
||||
|
||||
// Operators
|
||||
defineOperator('x', Operators.DeleteCharUnderCursor);
|
||||
@ -223,7 +223,7 @@ function _parseNumberAndString(input: string, numberAtBeginning: boolean = true)
|
||||
hasRepeatCount: false,
|
||||
repeatCount: 1,
|
||||
input: input
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
interface INumberAndString {
|
||||
|
||||
@ -256,7 +256,7 @@ class CursorMoveCommand extends AbstractCommandDescriptor {
|
||||
by: this.by,
|
||||
value: args.repeat || 1,
|
||||
select: !!args.isVisual
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'cursorMove',
|
||||
args: cursorMoveArgs
|
||||
@ -276,7 +276,7 @@ class EditorScrollCommand extends AbstractCommandDescriptor {
|
||||
by: this.by,
|
||||
value: args.repeat || 1,
|
||||
revealCursor: true
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'editorScroll',
|
||||
args: editorScrollArgs
|
||||
@ -313,7 +313,7 @@ class MoveActiveEditorCommandByPosition extends AbstractCommandDescriptor {
|
||||
let moveActiveEditorArgs: any = {
|
||||
to: args.repeat === void 0 ? 'last' : 'position',
|
||||
value: args.repeat !== void 0 ? args.repeat + 1 : undefined
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'moveActiveEditor',
|
||||
args: moveActiveEditorArgs
|
||||
@ -331,7 +331,7 @@ class MoveActiveEditorCommand extends AbstractCommandDescriptor {
|
||||
let moveActiveEditorArgs: any = {
|
||||
to: this.to,
|
||||
value: args.repeat ? args.repeat : 1
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'moveActiveEditor',
|
||||
args: moveActiveEditorArgs
|
||||
@ -348,7 +348,7 @@ class FoldCommand extends AbstractCommandDescriptor {
|
||||
let foldEditorArgs: any = {
|
||||
levels: args.repeat ? args.repeat : 1,
|
||||
direction: 'up'
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'editor.fold',
|
||||
args: foldEditorArgs
|
||||
@ -366,7 +366,7 @@ class UnfoldCommand extends AbstractCommandDescriptor {
|
||||
let foldEditorArgs: any = {
|
||||
levels: args.repeat ? args.repeat : 1,
|
||||
direction: 'up'
|
||||
}
|
||||
};
|
||||
return {
|
||||
commandId: 'editor.unfold',
|
||||
args: foldEditorArgs
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { Position, Selection, Range, TextDocument, TextEditor, TextEditorRevealType } from 'vscode';
|
||||
import { MotionState, Motion, Motions } from './motions';
|
||||
import { Motion, Motions } from './motions';
|
||||
import { Mode, IController, DeleteRegister } from './common';
|
||||
|
||||
export abstract class Operator {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": ["es6"],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src"
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
"exclude": ["node_modules", ".vscode-test"]
|
||||
}
|
||||
6
vim-sample/tslint.json
Normal file
6
vim-sample/tslint.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"rules": {
|
||||
"indent": [true, "tabs"],
|
||||
"semicolon": [true, "always"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user