Refactor code to use single state object instead of two

This commit is contained in:
Matt Bierner 2019-07-19 18:35:35 -07:00
parent feef95c707
commit cf69f2f1af

View file

@ -34,6 +34,27 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined
return undefined;
}
class CloseOperation {
readonly type = 'close';
constructor(
public readonly args: string
) { }
}
class OpenOperation {
readonly type = 'open';
constructor(
public readonly args: Proto.OpenRequestArgs
) { }
}
class ChangeOperation {
readonly type = 'change';
constructor(
public readonly args: Proto.FileCodeEdits
) { }
}
/**
* Manages synchronization of buffers with the TS server.
*
@ -41,8 +62,7 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined
*/
class BufferSynchronizer {
private _pending: Proto.UpdateOpenRequestArgs = {};
private readonly _pendingFiles = new Set<string>();
private readonly _pending = new Map<string, CloseOperation | OpenOperation | ChangeOperation>();
constructor(
private readonly client: ITypeScriptServiceClient
@ -51,10 +71,7 @@ class BufferSynchronizer {
public open(args: Proto.OpenRequestArgs) {
if (this.supportsBatching) {
this.updatePending(args.file, pending => {
if (!pending.openFiles) {
pending.openFiles = [];
}
pending.openFiles.push(args);
pending.set(args.file, new OpenOperation(args));
});
} else {
this.client.executeWithoutWaitingForResponse('open', args);
@ -64,10 +81,7 @@ class BufferSynchronizer {
public close(filepath: string) {
if (this.supportsBatching) {
this.updatePending(filepath, pending => {
if (!pending.closedFiles) {
pending.closedFiles = [];
}
pending.closedFiles.push(filepath);
pending.set(filepath, new CloseOperation(filepath));
});
} else {
const args: Proto.FileRequestArgs = { file: filepath };
@ -82,18 +96,14 @@ class BufferSynchronizer {
if (this.supportsBatching) {
this.updatePending(filepath, pending => {
if (!pending.changedFiles) {
pending.changedFiles = [];
}
pending.changedFiles.push({
pending.set(filepath, new ChangeOperation({
fileName: filepath,
textChanges: events.map((change): Proto.CodeEdit => ({
newText: change.text,
start: typeConverters.Position.toLocation(change.range.start),
end: typeConverters.Position.toLocation(change.range.end),
})).reverse(), // Send the edits end-of-document to start-of-document order
});
}));
});
} else {
for (const { range, text } of events) {
@ -117,13 +127,23 @@ class BufferSynchronizer {
private flush() {
if (!this.supportsBatching) {
// We've already eagerly synchronized
this._pending.clear();
return;
}
if (this._pending.changedFiles || this._pending.closedFiles || this._pending.openFiles) {
this.client.executeWithoutWaitingForResponse('updateOpen', this._pending);
this._pending = {};
this._pendingFiles.clear();
if (this._pending.size > 0) {
const closedFiles: string[] = [];
const openFiles: Proto.OpenRequestArgs[] = [];
const changedFiles: Proto.FileCodeEdits[] = [];
for (const change of this._pending.values()) {
switch (change.type) {
case 'change': changedFiles.push(change.args); break;
case 'open': openFiles.push(change.args); break;
case 'close': closedFiles.push(change.args); break;
}
}
this.client.executeWithoutWaitingForResponse('updateOpen', { changedFiles, closedFiles, openFiles });
this._pending.clear();
}
}
@ -131,18 +151,12 @@ class BufferSynchronizer {
return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get<boolean>('useBatchedBufferSync', true);
}
private updatePending(filepath: string, f: (pending: Proto.UpdateOpenRequestArgs) => void): void {
if (this.supportsBatching) {
if (this._pendingFiles.has(filepath)) {
// we saw this file before, make sure we flush before working with it again
this.flush();
this._pendingFiles.clear();
}
this._pendingFiles.add(filepath);
f(this._pending);
} else {
f(this._pending);
private updatePending(filepath: string, f: (pending: Map<string, CloseOperation | OpenOperation | ChangeOperation>) => void): void {
if (this._pending.has(filepath)) {
// we saw this file before, make sure we flush before working with it again
this.flush();
}
f(this._pending);
}
}