Skip to content

Commit 84f1d5a

Browse files
authored
Merge pull request #5089 from JoeRobich/debounce-diagnostic-requests
Debounce diagnostic requests
2 parents a8df773 + 786580c commit 84f1d5a

File tree

1 file changed

+69
-76
lines changed

1 file changed

+69
-76
lines changed

src/features/diagnosticsProvider.ts

+69-76
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { isVirtualCSharpDocument } from './virtualDocumentTracker';
1515
import { TextDocument } from '../vscodeAdapter';
1616
import OptionProvider from '../observers/OptionProvider';
1717
import { Subject, Subscription } from 'rxjs';
18-
import { throttleTime } from 'rxjs/operators';
18+
import { debounceTime } from 'rxjs/operators';
1919
import { DiagnosticStatus } from '../omnisharp/protocol';
2020
import { LanguageMiddlewareFeature } from '../omnisharp/LanguageMiddlewareFeature';
2121

@@ -122,7 +122,7 @@ class DiagnosticsProvider extends AbstractSupport {
122122
private _disposable: CompositeDisposable;
123123
private _diagnostics: vscode.DiagnosticCollection;
124124
private _validateCurrentDocumentPipe = new Subject<vscode.TextDocument>();
125-
private _validateAllPipe = new Subject();
125+
private _validateAllPipe = new Subject<string>();
126126
private _analyzersEnabled: boolean;
127127
private _subscriptions: Subscription[] = [];
128128
private _suppressHiddenDiagnostics: boolean;
@@ -136,26 +136,24 @@ class DiagnosticsProvider extends AbstractSupport {
136136
this._suppressHiddenDiagnostics = vscode.workspace.getConfiguration('csharp').get('suppressHiddenDiagnostics', true);
137137

138138
this._subscriptions.push(this._validateCurrentDocumentPipe
139-
.asObservable()
140-
.pipe(throttleTime(750))
141-
.subscribe(async x => await this._validateDocument(x)));
139+
.pipe(debounceTime(750))
140+
.subscribe(x => this._validateDocument(x)));
142141

143142
this._subscriptions.push(this._validateAllPipe
144-
.asObservable()
145-
.pipe(throttleTime(3000))
146-
.subscribe(async () => {
143+
.pipe(debounceTime(3000))
144+
.subscribe(reason => {
147145
if (this._validationAdvisor.shouldValidateAll()) {
148-
await this._validateEntireWorkspace();
146+
this._validateEntireWorkspace();
149147
}
150148
else if (this._validationAdvisor.shouldValidateFiles()) {
151-
await this._validateOpenDocuments();
149+
this._validateOpenDocuments();
152150
}
153151
}));
154152

155153

156154
this._disposable = new CompositeDisposable(this._diagnostics,
157-
this._server.onPackageRestore(() => this._validateAllPipe.next(), this),
158-
this._server.onProjectChange(() => this._validateAllPipe.next(), this),
155+
this._server.onPackageRestore(() => this._validateAllPipe.next("onPackageRestore"), this),
156+
this._server.onProjectChange(() => this._validateAllPipe.next("onProjectChanged"), this),
159157
this._server.onProjectDiagnosticStatus(this._onProjectAnalysis, this),
160158
vscode.workspace.onDidOpenTextDocument(event => this._onDocumentOpenOrChange(event), this),
161159
vscode.workspace.onDidChangeTextDocument(event => this._onDocumentOpenOrChange(event.document), this),
@@ -208,12 +206,13 @@ class DiagnosticsProvider extends AbstractSupport {
208206
// This check is just small perf optimization to reduce queries
209207
// for omnisharp with analyzers (which has event to notify about updates.)
210208
if (!this._analyzersEnabled) {
211-
this._validateAllPipe.next();
209+
this._validateAllPipe.next("onDocumentOpenOrChange");
212210
}
213211
}
214212

215213
private _onProjectAnalysis(event: protocol.ProjectDiagnosticStatus) {
216-
if (event.Status == DiagnosticStatus.Ready) {
214+
if (event.Status == DiagnosticStatus.Ready &&
215+
event.ProjectFilePath === "(100 %)") {
217216
this._validateAllPipe.next();
218217
}
219218
}
@@ -224,54 +223,50 @@ class DiagnosticsProvider extends AbstractSupport {
224223
}
225224
}
226225

227-
private _validateDocument(document: vscode.TextDocument): NodeJS.Timeout {
226+
private async _validateDocument(document: vscode.TextDocument) {
228227
if (!this._validationAdvisor.shouldValidateFiles()) {
229228
return;
230229
}
231230

232-
return setTimeout(async () => {
233-
let source = new vscode.CancellationTokenSource();
234-
try {
235-
let value = await serverUtils.codeCheck(this._server, { FileName: document.fileName }, source.token);
236-
let quickFixes = value.QuickFixes;
237-
// Easy case: If there are no diagnostics in the file, we can clear it quickly.
238-
if (quickFixes.length === 0) {
239-
if (this._diagnostics.has(document.uri)) {
240-
this._diagnostics.delete(document.uri);
241-
}
242-
243-
return;
244-
}
231+
// No problems published for virtual files
232+
if (isVirtualCSharpDocument(document)) {
233+
return;
234+
}
245235

246-
// No problems published for virtual files
247-
if (isVirtualCSharpDocument(document)) {
248-
return;
236+
let source = new vscode.CancellationTokenSource();
237+
try {
238+
let value = await serverUtils.codeCheck(this._server, { FileName: document.fileName }, source.token);
239+
let quickFixes = value.QuickFixes;
240+
// Easy case: If there are no diagnostics in the file, we can clear it quickly.
241+
if (quickFixes.length === 0) {
242+
if (this._diagnostics.has(document.uri)) {
243+
this._diagnostics.delete(document.uri);
249244
}
250245

251-
// (re)set new diagnostics for this document
252-
let diagnosticsInFile = this._mapQuickFixesAsDiagnosticsInFile(quickFixes);
253-
254-
this._diagnostics.set(document.uri, diagnosticsInFile.map(x => x.diagnostic));
255-
}
256-
catch (error) {
257246
return;
258247
}
259-
}, 2000);
248+
249+
// (re)set new diagnostics for this document
250+
let diagnosticsInFile = this._mapQuickFixesAsDiagnosticsInFile(quickFixes);
251+
252+
this._diagnostics.set(document.uri, diagnosticsInFile.map(x => x.diagnostic));
253+
}
254+
catch (error) {
255+
return;
256+
}
260257
}
261258

262259
// On large workspaces (if maxProjectFileCountForDiagnosticAnalysis) is less than workspace size,
263260
// diagnostic fallback to mode where only open documents are analyzed.
264-
private _validateOpenDocuments(): NodeJS.Timeout {
265-
return setTimeout(async () => {
266-
for (let editor of vscode.window.visibleTextEditors) {
267-
let document = editor.document;
268-
if (this.shouldIgnoreDocument(document)) {
269-
continue;
270-
}
271-
272-
await this._validateDocument(document);
261+
private async _validateOpenDocuments() {
262+
for (let editor of vscode.window.visibleTextEditors) {
263+
let document = editor.document;
264+
if (this.shouldIgnoreDocument(document)) {
265+
continue;
273266
}
274-
}, 3000);
267+
268+
await this._validateDocument(document);
269+
}
275270
}
276271

277272
private _mapQuickFixesAsDiagnosticsInFile(quickFixes: protocol.QuickFix[]): { diagnostic: vscode.Diagnostic, fileName: string }[] {
@@ -280,41 +275,39 @@ class DiagnosticsProvider extends AbstractSupport {
280275
.filter(diagnosticInFile => diagnosticInFile !== undefined);
281276
}
282277

283-
private _validateEntireWorkspace(): NodeJS.Timeout {
284-
return setTimeout(async () => {
285-
let value = await serverUtils.codeCheck(this._server, { FileName: null }, new vscode.CancellationTokenSource().token);
278+
private async _validateEntireWorkspace() {
279+
let value = await serverUtils.codeCheck(this._server, { FileName: null }, new vscode.CancellationTokenSource().token);
286280

287-
let quickFixes = value.QuickFixes
288-
.sort((a, b) => a.FileName.localeCompare(b.FileName));
281+
let quickFixes = value.QuickFixes
282+
.sort((a, b) => a.FileName.localeCompare(b.FileName));
289283

290-
let entries: [vscode.Uri, vscode.Diagnostic[]][] = [];
291-
let lastEntry: [vscode.Uri, vscode.Diagnostic[]];
284+
let entries: [vscode.Uri, vscode.Diagnostic[]][] = [];
285+
let lastEntry: [vscode.Uri, vscode.Diagnostic[]];
292286

293-
for (let diagnosticInFile of this._mapQuickFixesAsDiagnosticsInFile(quickFixes)) {
294-
let uri = vscode.Uri.file(diagnosticInFile.fileName);
287+
for (let diagnosticInFile of this._mapQuickFixesAsDiagnosticsInFile(quickFixes)) {
288+
let uri = vscode.Uri.file(diagnosticInFile.fileName);
295289

296-
if (lastEntry && lastEntry[0].toString() === uri.toString()) {
297-
lastEntry[1].push(diagnosticInFile.diagnostic);
298-
} else {
299-
// We're replacing all diagnostics in this file. Pushing an entry with undefined for
300-
// the diagnostics first ensures that the previous diagnostics for this file are
301-
// cleared. Otherwise, new entries will be merged with the old ones.
302-
entries.push([uri, undefined]);
303-
lastEntry = [uri, [diagnosticInFile.diagnostic]];
304-
entries.push(lastEntry);
305-
}
290+
if (lastEntry && lastEntry[0].toString() === uri.toString()) {
291+
lastEntry[1].push(diagnosticInFile.diagnostic);
292+
} else {
293+
// We're replacing all diagnostics in this file. Pushing an entry with undefined for
294+
// the diagnostics first ensures that the previous diagnostics for this file are
295+
// cleared. Otherwise, new entries will be merged with the old ones.
296+
entries.push([uri, undefined]);
297+
lastEntry = [uri, [diagnosticInFile.diagnostic]];
298+
entries.push(lastEntry);
306299
}
300+
}
307301

308-
// Clear diagnostics for files that no longer have any diagnostics.
309-
this._diagnostics.forEach((uri) => {
310-
if (!entries.find(tuple => tuple[0].toString() === uri.toString())) {
311-
this._diagnostics.delete(uri);
312-
}
313-
});
302+
// Clear diagnostics for files that no longer have any diagnostics.
303+
this._diagnostics.forEach((uri) => {
304+
if (!entries.find(tuple => tuple[0].toString() === uri.toString())) {
305+
this._diagnostics.delete(uri);
306+
}
307+
});
314308

315-
// replace all entries
316-
this._diagnostics.set(entries);
317-
}, 3000);
309+
// replace all entries
310+
this._diagnostics.set(entries);
318311
}
319312

320313
private _asDiagnosticInFileIfAny(quickFix: protocol.QuickFix): { diagnostic: vscode.Diagnostic, fileName: string } {

0 commit comments

Comments
 (0)