mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-10-05 16:17:18 +03:00
refactor taskqueue
This commit is contained in:
parent
347f5ef005
commit
9b7c7333ed
11
.vscode/tasks.json
vendored
11
.vscode/tasks.json
vendored
@ -16,17 +16,8 @@
|
||||
"taskName": "build",
|
||||
"args": [],
|
||||
"isBuildCommand": true,
|
||||
"isWatching": false,
|
||||
"problemMatcher": "$tsc-watch"
|
||||
},
|
||||
|
||||
{
|
||||
"taskName": "yolo",
|
||||
"args": ["nothing"],
|
||||
"isBuildCommand": true,
|
||||
"isWatching": false,
|
||||
"isBackground": false,
|
||||
"problemMatcher": "$tsc-watch"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 VSCode-Extension
|
||||
Copyright (c) 2015 VSCodeVim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
135
extension.ts
135
extension.ts
@ -213,66 +213,54 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
});
|
||||
|
||||
overrideCommand(context, 'type', async args => {
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
taskQueue.enqueueTask(async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
|
||||
if (compositionState.isInComposition) {
|
||||
compositionState.composingText += args.text;
|
||||
} else {
|
||||
await mh.handleKeyEvent(args.text);
|
||||
}
|
||||
},
|
||||
isRunning: false,
|
||||
if (compositionState.isInComposition) {
|
||||
compositionState.composingText += args.text;
|
||||
} else {
|
||||
await mh.handleKeyEvent(args.text);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
overrideCommand(context, 'replacePreviousChar', async args => {
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
taskQueue.enqueueTask(async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
|
||||
if (compositionState.isInComposition) {
|
||||
compositionState.composingText =
|
||||
compositionState.composingText.substr(
|
||||
0,
|
||||
compositionState.composingText.length - args.replaceCharCnt
|
||||
) + args.text;
|
||||
} else {
|
||||
await vscode.commands.executeCommand('default:replacePreviousChar', {
|
||||
text: args.text,
|
||||
replaceCharCnt: args.replaceCharCnt,
|
||||
});
|
||||
mh.vimState.cursorPosition = Position.FromVSCodePosition(
|
||||
mh.vimState.editor.selection.start
|
||||
);
|
||||
mh.vimState.cursorStartPosition = Position.FromVSCodePosition(
|
||||
mh.vimState.editor.selection.start
|
||||
);
|
||||
}
|
||||
},
|
||||
isRunning: false,
|
||||
if (compositionState.isInComposition) {
|
||||
compositionState.composingText =
|
||||
compositionState.composingText.substr(
|
||||
0,
|
||||
compositionState.composingText.length - args.replaceCharCnt
|
||||
) + args.text;
|
||||
} else {
|
||||
await vscode.commands.executeCommand('default:replacePreviousChar', {
|
||||
text: args.text,
|
||||
replaceCharCnt: args.replaceCharCnt,
|
||||
});
|
||||
mh.vimState.cursorPosition = Position.FromVSCodePosition(
|
||||
mh.vimState.editor.selection.start
|
||||
);
|
||||
mh.vimState.cursorStartPosition = Position.FromVSCodePosition(
|
||||
mh.vimState.editor.selection.start
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
overrideCommand(context, 'compositionStart', async args => {
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
compositionState.isInComposition = true;
|
||||
},
|
||||
isRunning: false,
|
||||
taskQueue.enqueueTask(async () => {
|
||||
compositionState.isInComposition = true;
|
||||
});
|
||||
});
|
||||
|
||||
overrideCommand(context, 'compositionEnd', async args => {
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
let text = compositionState.composingText;
|
||||
compositionState = new CompositionState();
|
||||
await mh.handleMultipleKeyEvents(text.split(''));
|
||||
},
|
||||
isRunning: false,
|
||||
taskQueue.enqueueTask(async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
let text = compositionState.composingText;
|
||||
compositionState = new CompositionState();
|
||||
await mh.handleMultipleKeyEvents(text.split(''));
|
||||
});
|
||||
});
|
||||
|
||||
@ -284,29 +272,26 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
});
|
||||
|
||||
registerCommand(context, 'vim.remap', async (args: ICodeKeybinding) => {
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
if (args.after) {
|
||||
for (const key of args.after) {
|
||||
await mh.handleKeyEvent(AngleBracketNotation.Normalize(key));
|
||||
}
|
||||
return;
|
||||
taskQueue.enqueueTask(async () => {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
if (args.after) {
|
||||
for (const key of args.after) {
|
||||
await mh.handleKeyEvent(AngleBracketNotation.Normalize(key));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.commands) {
|
||||
for (const command of args.commands) {
|
||||
// Check if this is a vim command by looking for :
|
||||
if (command.command.slice(0, 1) === ':') {
|
||||
await runCmdLine(command.command.slice(1, command.command.length), mh);
|
||||
await mh.updateView(mh.vimState);
|
||||
} else {
|
||||
await vscode.commands.executeCommand(command.command, command.args);
|
||||
}
|
||||
if (args.commands) {
|
||||
for (const command of args.commands) {
|
||||
// Check if this is a vim command by looking for :
|
||||
if (command.command.slice(0, 1) === ':') {
|
||||
await runCmdLine(command.command.slice(1, command.command.length), mh);
|
||||
await mh.updateView(mh.vimState);
|
||||
} else {
|
||||
await vscode.commands.executeCommand(command.command, command.args);
|
||||
}
|
||||
}
|
||||
},
|
||||
isRunning: false,
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -447,11 +432,8 @@ function registerCommand(
|
||||
async function handleKeyEvent(key: string): Promise<void> {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
await mh.handleKeyEvent(key);
|
||||
},
|
||||
isRunning: false,
|
||||
taskQueue.enqueueTask(async () => {
|
||||
await mh.handleKeyEvent(key);
|
||||
});
|
||||
}
|
||||
|
||||
@ -474,15 +456,12 @@ async function handleActiveEditorChange(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
if (vscode.window.activeTextEditor !== undefined) {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
taskQueue.enqueueTask(async () => {
|
||||
if (vscode.window.activeTextEditor !== undefined) {
|
||||
const mh = await getAndUpdateModeHandler();
|
||||
|
||||
mh.updateView(mh.vimState, { drawSelection: false, revealRange: false });
|
||||
}
|
||||
},
|
||||
isRunning: false,
|
||||
mh.updateView(mh.vimState, { drawSelection: false, revealRange: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -361,25 +361,19 @@ function overlapSetting(args: {
|
||||
set: function(value) {
|
||||
this['_' + propertyKey] = value;
|
||||
|
||||
taskQueue.enqueueTask({
|
||||
promise: async () => {
|
||||
if (value === undefined || Globals.isTesting) {
|
||||
return;
|
||||
}
|
||||
taskQueue.enqueueTask(async () => {
|
||||
if (value === undefined || Globals.isTesting) {
|
||||
return;
|
||||
}
|
||||
|
||||
let codeValue = value;
|
||||
let codeValue = value;
|
||||
|
||||
if (args.codeValueMapping) {
|
||||
codeValue = args.codeValueMapping[value];
|
||||
}
|
||||
if (args.codeValueMapping) {
|
||||
codeValue = args.codeValueMapping[value];
|
||||
}
|
||||
|
||||
await vscode.workspace
|
||||
.getConfiguration('editor')
|
||||
.update(args.codeName, codeValue, true);
|
||||
},
|
||||
isRunning: false,
|
||||
queue: 'config',
|
||||
});
|
||||
await vscode.workspace.getConfiguration('editor').update(args.codeName, codeValue, true);
|
||||
}, 'config');
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -581,16 +581,15 @@ export class ModeHandler implements vscode.Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
taskQueue.enqueueTask({
|
||||
promise: () => this.handleSelectionChange(e),
|
||||
isRunning: false,
|
||||
|
||||
taskQueue.enqueueTask(
|
||||
() => this.handleSelectionChange(e),
|
||||
undefined,
|
||||
/**
|
||||
* We don't want these to become backlogged! If they do, we'll update
|
||||
* the selection to an incorrect value and see a jittering cursor.
|
||||
*/
|
||||
highPriority: true,
|
||||
});
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
107
src/taskQueue.ts
107
src/taskQueue.ts
@ -1,26 +1,34 @@
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export interface IEnqueuedTask {
|
||||
interface IEnqueuedTask {
|
||||
promise: () => Promise<void>;
|
||||
isRunning: boolean;
|
||||
queue?: string;
|
||||
highPriority?: boolean;
|
||||
queue: string;
|
||||
isHighPriority: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* TaskQueue
|
||||
*
|
||||
* Enqueue promises here. They will be run sequentially.
|
||||
*/
|
||||
class TaskQueue {
|
||||
private _taskQueue: {
|
||||
[key: string]: {
|
||||
tasks: IEnqueuedTask[];
|
||||
highPriorityCount: number;
|
||||
};
|
||||
} = {};
|
||||
|
||||
private async _runTasks(queueName: string): Promise<void> {
|
||||
private isRunning(queueName: string): boolean {
|
||||
return (
|
||||
this._taskQueue[queueName] &&
|
||||
_.filter(this._taskQueue[queueName].tasks, x => x.isRunning).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
private numHighPriority(queueName: string): number {
|
||||
if (!this._taskQueue[queueName]) {
|
||||
return 0;
|
||||
}
|
||||
return _.filter(this._taskQueue[queueName].tasks, x => x.isHighPriority).length;
|
||||
}
|
||||
|
||||
private async runTasks(queueName: string): Promise<void> {
|
||||
while (this._taskQueue[queueName].tasks.length > 0) {
|
||||
let task: IEnqueuedTask = this._taskQueue[queueName].tasks[0];
|
||||
|
||||
@ -29,73 +37,54 @@ class TaskQueue {
|
||||
await task.promise();
|
||||
task.isRunning = false;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log(e.stack);
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.removeTask(task);
|
||||
|
||||
if (task.highPriority) {
|
||||
this._taskQueue[queueName].highPriorityCount--;
|
||||
}
|
||||
this.dequeueTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get tasks(): number {
|
||||
let result = 0;
|
||||
|
||||
for (const list in this._taskQueue) {
|
||||
if (this._taskQueue.hasOwnProperty(list)) {
|
||||
result += this._taskQueue[list].tasks.length;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a task from the task queue.
|
||||
* Dequeues a task from the task queue.
|
||||
*
|
||||
* (Keep in mind that if the task is already running, the semantics of
|
||||
* promises don't allow you to stop it.)
|
||||
* Note: If the task is already running, the semantics of
|
||||
* promises don't allow you to stop it.
|
||||
*/
|
||||
public removeTask(task: IEnqueuedTask): void {
|
||||
let queueName = task.queue || 'default';
|
||||
this._taskQueue[queueName].tasks.splice(
|
||||
_.findIndex(this._taskQueue[queueName].tasks, t => t === task),
|
||||
1
|
||||
);
|
||||
private dequeueTask(task: IEnqueuedTask): void {
|
||||
_.remove(this._taskQueue[task.queue].tasks, t => t === task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a task to the task queue.
|
||||
*/
|
||||
public enqueueTask(task: IEnqueuedTask): void {
|
||||
let queueName = task.queue || 'default';
|
||||
let otherTaskRunning =
|
||||
this._taskQueue[queueName] &&
|
||||
_.filter(this._taskQueue[queueName].tasks, x => x.isRunning).length > 0;
|
||||
public enqueueTask(
|
||||
action: () => Promise<void>,
|
||||
queueName: string = 'default',
|
||||
isHighPriority: boolean = false
|
||||
): void {
|
||||
let task: IEnqueuedTask = {
|
||||
promise: action,
|
||||
queue: queueName,
|
||||
isHighPriority: isHighPriority,
|
||||
isRunning: false,
|
||||
};
|
||||
|
||||
if (this._taskQueue[queueName]) {
|
||||
if (task.highPriority) {
|
||||
// Insert task as the last high priotity task.
|
||||
|
||||
const numHighPriority = this._taskQueue[queueName].highPriorityCount;
|
||||
|
||||
this._taskQueue[queueName].tasks.splice(numHighPriority, 0, task);
|
||||
this._taskQueue[queueName].highPriorityCount++;
|
||||
} else {
|
||||
this._taskQueue[queueName].tasks.push(task);
|
||||
}
|
||||
} else {
|
||||
if (!this._taskQueue[queueName]) {
|
||||
this._taskQueue[queueName] = {
|
||||
tasks: [task],
|
||||
highPriorityCount: 0,
|
||||
tasks: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (!otherTaskRunning) {
|
||||
this._runTasks(queueName);
|
||||
if (isHighPriority) {
|
||||
// Insert task as the last high priotity task.
|
||||
const numHighPriority = this.numHighPriority(queueName);
|
||||
this._taskQueue[queueName].tasks.splice(numHighPriority, 0, task);
|
||||
} else {
|
||||
this._taskQueue[queueName].tasks.push(task);
|
||||
}
|
||||
|
||||
if (!this.isRunning(queueName)) {
|
||||
this.runTasks(queueName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user