Optimize markdown workspace scanning (#152563)

* Optimize markdown workspace scanning

- Adds cache for markdown file
- Avoid reading non-markdown files from disk (when we expect markdown files)
- Use `range.contains(pos)` instead of `range.intersects(range)`

* Don't remove cached document on change

We only want to invalidate the cached document when it is first opened (since the cached version is the one from disk). Otherwise we can use the live version of the doc
This commit is contained in:
Matt Bierner 2022-06-19 09:40:10 -07:00 committed by GitHub
parent 5a175207de
commit 4c72dedb4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 2 deletions

View file

@ -260,7 +260,7 @@ class NoLinkRanges {
contains(range: vscode.Range): boolean {
return this.multiline.some(interval => range.start.line >= interval[0] && range.start.line < interval[1]) ||
this.inline.some(position => position.intersection(range));
this.inline.some(inlineRange => inlineRange.contains(range.start));
}
}

View file

@ -4,11 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as URI from 'vscode-uri';
import { coalesce } from './util/arrays';
import { Disposable } from './util/dispose';
import { isMarkdownFile } from './util/file';
import { InMemoryDocument } from './util/inMemoryDocument';
import { Limiter } from './util/limiter';
import { ResourceMap } from './util/resourceMap';
/**
* Minimal version of {@link vscode.TextLine}. Used for mocking out in testing.
@ -62,6 +64,8 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
private _watcher: vscode.FileSystemWatcher | undefined;
private readonly _documentCache = new ResourceMap<SkinnyTextDocument>();
private readonly utf8Decoder = new TextDecoder('utf-8');
/**
@ -118,6 +122,7 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
this._watcher = this._register(vscode.workspace.createFileSystemWatcher('**/*.md'));
this._register(this._watcher.onDidChange(async resource => {
this._documentCache.delete(resource);
const document = await this.getMarkdownDocument(resource);
if (document) {
this._onDidChangeMarkdownDocumentEmitter.fire(document);
@ -132,14 +137,23 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
}));
this._register(this._watcher.onDidDelete(resource => {
this._documentCache.delete(resource);
this._onDidDeleteMarkdownDocumentEmitter.fire(resource);
}));
this._register(vscode.workspace.onDidOpenTextDocument(e => {
this._documentCache.delete(e.uri);
}));
this._register(vscode.workspace.onDidChangeTextDocument(e => {
if (this.isRelevantMarkdownDocument(e.document)) {
this._onDidChangeMarkdownDocumentEmitter.fire(e.document);
}
}));
this._register(vscode.workspace.onDidCloseTextDocument(e => {
this._documentCache.delete(e.uri);
}));
}
private isRelevantMarkdownDocument(doc: vscode.TextDocument) {
@ -147,17 +161,30 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
}
public async getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
const existing = this._documentCache.get(resource);
if (existing) {
return existing;
}
const matchingDocument = vscode.workspace.textDocuments.find((doc) => this.isRelevantMarkdownDocument(doc) && doc.uri.toString() === resource.toString());
if (matchingDocument) {
this._documentCache.set(resource, matchingDocument);
return matchingDocument;
}
const ext = URI.Utils.extname(resource).toLowerCase();
if (ext !== '.md') {
return undefined;
}
try {
const bytes = await vscode.workspace.fs.readFile(resource);
// We assume that markdown is in UTF-8
const text = this.utf8Decoder.decode(bytes);
return new InMemoryDocument(resource, text, 0);
const doc = new InMemoryDocument(resource, text, 0);
this._documentCache.set(resource, doc);
return doc;
} catch {
return undefined;
}