Skip to content

Commit

Permalink
Add basic support for delaying and combining text changes (#262)
Browse files Browse the repository at this point in the history
  • Loading branch information
strpbrk committed Dec 4, 2021
1 parent b768b01 commit dd5f623
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@clangd/install": "0.1.4",
"abort-controller": "^3.0.0",
"jsonc-parser": "^2.1.0",
"vscode-languageclient": "7.1.0-next.1",
"vscode-languageclient": "7.1.0-next.2",
"vscode-languageserver-types": "3.16.0"
},
"devDependencies": {
Expand Down
74 changes: 74 additions & 0 deletions src/clangd-context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as vscode from 'vscode';
import * as vscodelc from 'vscode-languageclient/node';
import * as vscodelcAsync from 'vscode-languageclient/lib/common/utils/async';

import * as ast from './ast';
import * as config from './config';
Expand Down Expand Up @@ -55,6 +56,41 @@ class EnableEditsNearCursorFeature implements vscodelc.StaticFeature {
dispose() {}
}

class PendingTextChange {
_document: vscode.TextDocument;
_consumer: (data: vscode.TextDocumentChangeEvent) => vscode.ProviderResult<void>;
_changes?: ReadonlyArray<vscode.TextDocumentContentChangeEvent>;

constructor(document: vscode.TextDocument, consumer: (data: vscode.TextDocumentChangeEvent) => vscode.ProviderResult<void>) {
this._document = document;
this._consumer = consumer;
}

matches(document: vscode.TextDocument) {
return document.uri == this._document.uri;
}

merge(changes: ReadonlyArray<vscode.TextDocumentContentChangeEvent>) {
if (this._changes) {
this._changes = this._changes.concat(changes);
}
else {
this._changes = changes;
}
}

async send() {
let event: vscode.TextDocumentChangeEvent = {
document: this._document,
contentChanges: this._changes ? this._changes : [],
};

this._changes = undefined;

return await this._consumer(event);
}
}

export class ClangdContext implements vscode.Disposable {
subscriptions: vscode.Disposable[] = [];
client!: ClangdLanguageClient;
Expand Down Expand Up @@ -107,6 +143,8 @@ export class ClangdContext implements vscode.Disposable {
middleware: {
provideCompletionItem: async (document, position, context, token,
next) => {
await this.flushPendingTextChanges();

let list = await next(document, position, context, token);
if (!config.get<boolean>('serverCompletionRanking'))
return list;
Expand All @@ -126,6 +164,8 @@ export class ClangdContext implements vscode.Disposable {
// from filtering out any results, e.g. enable workspaceSymbols for
// qualified symbols.
provideWorkspaceSymbols: async (query, token, next) => {
await this.flushPendingTextChanges();

let symbols = await next(query, token);
return symbols?.map(symbol => {
// Only make this adjustment if the query is in fact qualified.
Expand All @@ -142,6 +182,28 @@ export class ClangdContext implements vscode.Disposable {
return symbol;
})
},
didChange: async (event, next) => {
if (this.pendingTextChange) {
this.textChangeDelayer.cancel();

if (this.pendingTextChange.matches(event.document)) {
this.pendingTextChange.merge(event.contentChanges);
}
else {
let sendingTextChange = this.pendingTextChange;
this.pendingTextChange = new PendingTextChange(event.document, next);
this.pendingTextChange.merge(event.contentChanges);

await sendingTextChange.send();
}
}
else {
this.pendingTextChange = new PendingTextChange(event.document, next);
this.pendingTextChange.merge(event.contentChanges);
}

this.textChangeDelayer.trigger(() => { this.flushPendingTextChanges(); });
},
},
};

Expand Down Expand Up @@ -175,4 +237,16 @@ export class ClangdContext implements vscode.Disposable {
this.subscriptions.forEach((d) => { d.dispose(); });
this.subscriptions = []
}

pendingTextChange?: PendingTextChange;
textChangeDelayer = new vscodelcAsync.Delayer<void>(2000);

async flushPendingTextChanges() {
let sendingTextChange = this.pendingTextChange;
if (sendingTextChange) {
this.pendingTextChange = undefined;

return await sendingTextChange.send();
}
}
}

0 comments on commit dd5f623

Please sign in to comment.