Only compute diagnostics for opened md files (#153395)

* Only compute diagnostics for opened md files

For #152494

* Make tests stable for result ordering
This commit is contained in:
Matt Bierner
2022-06-27 15:55:38 -07:00
committed by GitHub
parent 87e684ef9b
commit e13feea6ae
9 changed files with 91 additions and 40 deletions

View File

@@ -242,7 +242,9 @@ export abstract class DiagnosticReporter extends Disposable {
public abstract delete(uri: vscode.Uri): void;
public abstract areDiagnosticsEnabled(uri: vscode.Uri): boolean;
public abstract isOpen(uri: vscode.Uri): boolean;
public abstract getOpenDocuments(): ITextDocument[];
public addWorkItem(promise: Promise<any>): Promise<any> {
this.pending.add(promise);
@@ -256,6 +258,7 @@ export abstract class DiagnosticReporter extends Disposable {
}
export class DiagnosticCollectionReporter extends DiagnosticReporter {
private readonly collection: vscode.DiagnosticCollection;
constructor() {
@@ -269,11 +272,11 @@ export class DiagnosticCollectionReporter extends DiagnosticReporter {
}
public set(uri: vscode.Uri, diagnostics: readonly vscode.Diagnostic[]): void {
this.collection.set(uri, this.areDiagnosticsEnabled(uri) ? diagnostics : []);
this.collection.set(uri, this.isOpen(uri) ? diagnostics : []);
}
public areDiagnosticsEnabled(uri: vscode.Uri): boolean {
const tabs = this.getAllTabResources();
public isOpen(uri: vscode.Uri): boolean {
const tabs = this.getTabResources();
return tabs.has(uri);
}
@@ -281,7 +284,12 @@ export class DiagnosticCollectionReporter extends DiagnosticReporter {
this.collection.delete(uri);
}
private getAllTabResources(): ResourceMap<void> {
public getOpenDocuments(): ITextDocument[] {
const tabs = this.getTabResources();
return vscode.workspace.textDocuments.filter(doc => tabs.has(doc.uri));
}
private getTabResources(): ResourceMap<void> {
const openedTabDocs = new ResourceMap<void>();
for (const group of vscode.window.tabGroups.all) {
for (const tab of group.tabs) {
@@ -365,7 +373,7 @@ export class DiagnosticManager extends Disposable {
return this.reporter.addWorkItem(
(async () => {
const triggered = new ResourceMap<Promise<void>>();
for (const ref of await this.referencesProvider.getAllReferencesToFile(uri, noopToken)) {
for (const ref of await this.referencesProvider.getReferencesToFileInDocs(uri, this.reporter.getOpenDocuments(), noopToken)) {
const file = ref.location.uri;
if (!triggered.has(file)) {
triggered.set(file, this.triggerDiagnostics(file));
@@ -398,7 +406,7 @@ export class DiagnosticManager extends Disposable {
const doc = await this.workspace.getOrLoadMarkdownDocument(resource);
if (doc) {
await this.inFlightDiagnostics.trigger(doc.uri, async (token) => {
if (this.reporter.areDiagnosticsEnabled(doc.uri)) {
if (this.reporter.isOpen(doc.uri)) {
const state = await this.recomputeDiagnosticState(doc, token);
this.linkWatcher.updateLinksForDocument(doc.uri, state.config.enabled && state.config.validateFileLinks ? state.links : []);
this.reporter.set(doc.uri, state.diagnostics);
@@ -417,12 +425,7 @@ export class DiagnosticManager extends Disposable {
this.inFlightDiagnostics.clear();
return this.reporter.addWorkItem(
(async () => {
// TODO: This pulls in all md files in the workspace. Instead we only care about opened text documents.
// Need a new way to handle that.
const allDocs = await this.workspace.getAllMarkdownDocuments();
await Promise.all(Array.from(allDocs, doc => this.triggerDiagnostics(doc.uri)));
})()
Promise.all(Array.from(this.reporter.getOpenDocuments(), doc => this.triggerDiagnostics(doc.uri)))
);
}

View File

@@ -33,7 +33,7 @@ export class FindFileReferencesCommand implements Command {
location: vscode.ProgressLocation.Window,
title: localize('progress.title', "Finding file references")
}, async (_progress, token) => {
const references = await this.referencesProvider.getAllReferencesToFile(resource!, token);
const references = await this.referencesProvider.getReferencesToFileInWorkspace(resource!, token);
const locations = references.map(ref => ref.location);
const config = vscode.workspace.getConfiguration('references');

View File

@@ -67,7 +67,6 @@ export type MdReference = MdLinkReference | MdHeaderReference;
export class MdReferencesProvider extends Disposable {
private readonly _linkCache: MdWorkspaceInfoCache<readonly MdLink[]>;
private readonly _linkComputer: MdLinkComputer;
public constructor(
private readonly parser: IMdParser,
@@ -77,8 +76,8 @@ export class MdReferencesProvider extends Disposable {
) {
super();
this._linkComputer = new MdLinkComputer(parser);
this._linkCache = this._register(new MdWorkspaceInfoCache(workspace, doc => this._linkComputer.getAllLinks(doc, noopToken)));
const linkComputer = new MdLinkComputer(parser);
this._linkCache = this._register(new MdWorkspaceInfoCache(workspace, doc => linkComputer.getAllLinks(doc, noopToken)));
}
public async getReferencesAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
@@ -97,11 +96,26 @@ export class MdReferencesProvider extends Disposable {
}
}
public async getAllReferencesToFile(resource: vscode.Uri, _token: vscode.CancellationToken): Promise<MdReference[]> {
this.logger.verbose('ReferencesProvider', `getAllReferencesToFile: ${resource}`);
public async getReferencesToFileInWorkspace(resource: vscode.Uri, token: vscode.CancellationToken): Promise<MdReference[]> {
this.logger.verbose('ReferencesProvider', `getAllReferencesToFileInWorkspace: ${resource}`);
const allLinksInWorkspace = (await this._linkCache.values()).flat();
return Array.from(this.findAllLinksToFile(resource, allLinksInWorkspace, undefined));
if (token.isCancellationRequested) {
return [];
}
return Array.from(this.findLinksToFile(resource, allLinksInWorkspace, undefined));
}
public async getReferencesToFileInDocs(resource: vscode.Uri, otherDocs: readonly ITextDocument[], token: vscode.CancellationToken): Promise<MdReference[]> {
this.logger.verbose('ReferencesProvider', `getAllReferencesToFileInFiles: ${resource}`);
const links = (await this._linkCache.getForDocs(otherDocs)).flat();
if (token.isCancellationRequested) {
return [];
}
return Array.from(this.findLinksToFile(resource, links, undefined));
}
private async getReferencesToHeader(document: ITextDocument, header: TocEntry): Promise<MdReference[]> {
@@ -137,7 +151,7 @@ export class MdReferencesProvider extends Disposable {
}
private async getReferencesToLinkAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
const docLinks = await this._linkComputer.getAllLinks(document, token);
const docLinks = (await this._linkCache.getForDocs([document]))[0];
for (const link of docLinks) {
if (link.kind === 'definition') {
@@ -223,7 +237,7 @@ export class MdReferencesProvider extends Disposable {
}
}
} else { // Triggered on a link without a fragment so we only require matching the file and ignore fragments
references.push(...this.findAllLinksToFile(resolvedResource ?? sourceLink.href.path, allLinksInWorkspace, sourceLink));
references.push(...this.findLinksToFile(resolvedResource ?? sourceLink.href.path, allLinksInWorkspace, sourceLink));
}
return references;
@@ -238,8 +252,8 @@ export class MdReferencesProvider extends Disposable {
|| uri.Utils.extname(href.path) === '' && href.path.with({ path: href.path.path + '.md' }).fsPath === targetDoc.fsPath;
}
private *findAllLinksToFile(resource: vscode.Uri, allLinksInWorkspace: readonly MdLink[], sourceLink: MdLink | undefined): Iterable<MdReference> {
for (const link of allLinksInWorkspace) {
private *findLinksToFile(resource: vscode.Uri, links: readonly MdLink[], sourceLink: MdLink | undefined): Iterable<MdReference> {
for (const link of links) {
if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, resource)) {
continue;
}