mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Don't try parsing non-markdown files (#152661)
This fixes our references and rename provider to not try parsing non-markdown files as if they were markdown
This commit is contained in:
parent
b3dc3301dd
commit
0bc3109761
|
@ -13,12 +13,12 @@ import { MdTableOfContentsWatcher } from '../test/tableOfContentsWatcher';
|
|||
import { Delayer } from '../util/async';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { isMarkdownFile } from '../util/file';
|
||||
import { isMarkdownFile, looksLikeMarkdownPath } from '../util/file';
|
||||
import { Limiter } from '../util/limiter';
|
||||
import { ResourceMap } from '../util/resourceMap';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref, LinkDefinitionSet, MdLink, MdLinkProvider, MdLinkSource } from './documentLinkProvider';
|
||||
import { MdReferencesProvider, tryFindMdDocumentForLink } from './references';
|
||||
import { MdReferencesProvider, tryResolveLinkPath } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -374,7 +374,7 @@ export class DiagnosticManager extends Disposable {
|
|||
this.pendingDiagnostics.clear();
|
||||
|
||||
await Promise.all(pending.map(async resource => {
|
||||
const doc = await this.workspaceContents.getMarkdownDocument(resource);
|
||||
const doc = await this.workspaceContents.getOrLoadMarkdownDocument(resource);
|
||||
if (doc) {
|
||||
await this.inFlightDiagnostics.trigger(doc.uri, async (token) => {
|
||||
const state = await this.recomputeDiagnosticState(doc, token);
|
||||
|
@ -540,19 +540,19 @@ export class DiagnosticComputer {
|
|||
return;
|
||||
}
|
||||
|
||||
const hrefDoc = await tryFindMdDocumentForLink({ kind: 'internal', path: path, fragment: '' }, this.workspaceContents);
|
||||
if (!hrefDoc && !await this.workspaceContents.pathExists(path)) {
|
||||
const resolvedHrefPath = await tryResolveLinkPath(path, this.workspaceContents);
|
||||
if (!resolvedHrefPath) {
|
||||
const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath);
|
||||
for (const link of links) {
|
||||
if (!this.isIgnoredLink(options, link.source.pathText)) {
|
||||
diagnostics.push(new LinkDoesNotExistDiagnostic(link.source.hrefRange, msg, pathErrorSeverity, link.source.pathText));
|
||||
}
|
||||
}
|
||||
} else if (hrefDoc && typeof fragmentErrorSeverity !== 'undefined') {
|
||||
} else if (typeof fragmentErrorSeverity !== 'undefined' && this.isMarkdownPath(resolvedHrefPath)) {
|
||||
// Validate each of the links to headers in the file
|
||||
const fragmentLinks = links.filter(x => x.fragment);
|
||||
if (fragmentLinks.length) {
|
||||
const toc = await this.tocProvider.get(hrefDoc.uri);
|
||||
const toc = await this.tocProvider.get(resolvedHrefPath);
|
||||
for (const link of fragmentLinks) {
|
||||
if (!toc.lookup(link.fragment) && !this.isIgnoredLink(options, link.source.pathText) && !this.isIgnoredLink(options, link.source.text)) {
|
||||
const msg = localize('invalidLinkToHeaderInOtherFile', 'Header does not exist in file: {0}', link.fragment);
|
||||
|
@ -567,6 +567,10 @@ export class DiagnosticComputer {
|
|||
return diagnostics;
|
||||
}
|
||||
|
||||
private isMarkdownPath(resolvedHrefPath: vscode.Uri) {
|
||||
return this.workspaceContents.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
|
||||
}
|
||||
|
||||
private isIgnoredLink(options: DiagnosticOptions, link: string): boolean {
|
||||
return options.ignoreLinks.some(glob => picomatch.isMatch(link, glob));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { MarkdownEngine } from '../markdownEngine';
|
|||
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { looksLikeMarkdownPath } from '../util/file';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref, MdLink, MdLinkComputer } from './documentLinkProvider';
|
||||
import { MdWorkspaceInfoCache } from './workspaceCache';
|
||||
|
@ -177,15 +178,15 @@ export class MdReferencesProvider extends Disposable {
|
|||
return references;
|
||||
}
|
||||
|
||||
const targetDoc = await tryFindMdDocumentForLink(sourceLink.href, this.workspaceContents);
|
||||
const resolvedResource = await tryResolveLinkPath(sourceLink.href.path, this.workspaceContents);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const references: MdReference[] = [];
|
||||
|
||||
if (targetDoc && sourceLink.href.fragment && sourceLink.source.fragmentRange?.contains(triggerPosition)) {
|
||||
const toc = await this.tocProvider.get(targetDoc.uri);
|
||||
if (resolvedResource && this.isMarkdownPath(resolvedResource) && sourceLink.href.fragment && sourceLink.source.fragmentRange?.contains(triggerPosition)) {
|
||||
const toc = await this.tocProvider.get(resolvedResource);
|
||||
const entry = toc.lookup(sourceLink.href.fragment);
|
||||
if (entry) {
|
||||
references.push({
|
||||
|
@ -199,7 +200,7 @@ export class MdReferencesProvider extends Disposable {
|
|||
}
|
||||
|
||||
for (const link of allLinksInWorkspace) {
|
||||
if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, targetDoc.uri)) {
|
||||
if (link.href.kind !== 'internal' || !this.looksLikeLinkToDoc(link.href, resolvedResource)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -215,12 +216,16 @@ 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(targetDoc?.uri ?? sourceLink.href.path, allLinksInWorkspace, sourceLink));
|
||||
references.push(...this.findAllLinksToFile(resolvedResource ?? sourceLink.href.path, allLinksInWorkspace, sourceLink));
|
||||
}
|
||||
|
||||
return references;
|
||||
}
|
||||
|
||||
private isMarkdownPath(resolvedHrefPath: vscode.Uri) {
|
||||
return this.workspaceContents.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
|
||||
}
|
||||
|
||||
private looksLikeLinkToDoc(href: InternalHref, targetDoc: vscode.Uri) {
|
||||
return href.path.fsPath === targetDoc.fsPath
|
||||
|| uri.Utils.extname(href.path) === '' && href.path.with({ path: href.path.path + '.md' }).fsPath === targetDoc.fsPath;
|
||||
|
@ -310,16 +315,17 @@ export function registerReferencesSupport(
|
|||
return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(referencesProvider));
|
||||
}
|
||||
|
||||
export async function tryFindMdDocumentForLink(href: InternalHref, workspaceContents: MdWorkspaceContents): Promise<SkinnyTextDocument | undefined> {
|
||||
const targetDoc = await workspaceContents.getMarkdownDocument(href.path);
|
||||
if (targetDoc) {
|
||||
return targetDoc;
|
||||
export async function tryResolveLinkPath(originalUri: vscode.Uri, workspaceContents: MdWorkspaceContents): Promise<vscode.Uri | undefined> {
|
||||
if (await workspaceContents.pathExists(originalUri)) {
|
||||
return originalUri;
|
||||
}
|
||||
|
||||
// We don't think the file exists. If it doesn't already have an extension, try tacking on a `.md` and using that instead
|
||||
if (uri.Utils.extname(href.path) === '') {
|
||||
const dotMdResource = href.path.with({ path: href.path.path + '.md' });
|
||||
return workspaceContents.getMarkdownDocument(dotMdResource);
|
||||
if (uri.Utils.extname(originalUri) === '') {
|
||||
const dotMdResource = originalUri.with({ path: originalUri.path + '.md' });
|
||||
if (await workspaceContents.pathExists(dotMdResource)) {
|
||||
return dotMdResource;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Disposable } from '../util/dispose';
|
|||
import { resolveDocumentLink } from '../util/openDocumentLink';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref } from './documentLinkProvider';
|
||||
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryFindMdDocumentForLink } from './references';
|
||||
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryResolveLinkPath } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -153,8 +153,7 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
|
|||
const edit = new vscode.WorkspaceEdit();
|
||||
const fileRenames: MdFileRenameEdit[] = [];
|
||||
|
||||
const targetDoc = await tryFindMdDocumentForLink(triggerHref, this.workspaceContents);
|
||||
const targetUri = targetDoc?.uri ?? triggerHref.path;
|
||||
const targetUri = await tryResolveLinkPath(triggerHref.path, this.workspaceContents) ?? triggerHref.path;
|
||||
|
||||
const rawNewFilePath = resolveDocumentLink(newName, triggerDocument);
|
||||
let resolvedNewFilePath = rawNewFilePath;
|
||||
|
|
|
@ -61,7 +61,7 @@ export class MdDocumentInfoCache<T> extends Disposable {
|
|||
return existing;
|
||||
}
|
||||
|
||||
const doc = await this.workspaceContents.getMarkdownDocument(resource);
|
||||
const doc = await this.workspaceContents.getOrLoadMarkdownDocument(resource);
|
||||
return doc && this.onDidChangeDocument(doc, true)?.value;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,14 @@ export class InMemoryWorkspaceMarkdownDocuments implements MdWorkspaceContents {
|
|||
return Array.from(this._documents.values());
|
||||
}
|
||||
|
||||
public async getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
|
||||
public async getOrLoadMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
|
||||
return this._documents.get(resource);
|
||||
}
|
||||
|
||||
public hasMarkdownDocument(resolvedHrefPath: vscode.Uri): boolean {
|
||||
return this._documents.has(resolvedHrefPath);
|
||||
}
|
||||
|
||||
public async pathExists(resource: vscode.Uri): Promise<boolean> {
|
||||
return this._documents.has(resource);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,24 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as URI from 'vscode-uri';
|
||||
|
||||
const markdownFileExtensions = Object.freeze<string[]>([
|
||||
'.md',
|
||||
'.mkd',
|
||||
'.mdwn',
|
||||
'.mdown',
|
||||
'.markdown',
|
||||
'.markdn',
|
||||
'.mdtxt',
|
||||
'.mdtext',
|
||||
'.workbook',
|
||||
]);
|
||||
|
||||
export function isMarkdownFile(document: vscode.TextDocument) {
|
||||
return document.languageId === 'markdown';
|
||||
}
|
||||
}
|
||||
|
||||
export function looksLikeMarkdownPath(resolvedHrefPath: vscode.Uri) {
|
||||
return markdownFileExtensions.includes(URI.Utils.extname(resolvedHrefPath).toLowerCase());
|
||||
}
|
||||
|
|
|
@ -32,15 +32,3 @@ export function getUriForLinkWithKnownExternalScheme(link: string): vscode.Uri |
|
|||
export function isOfScheme(scheme: string, link: string): boolean {
|
||||
return link.toLowerCase().startsWith(scheme);
|
||||
}
|
||||
|
||||
export const MarkdownFileExtensions: readonly string[] = [
|
||||
'.md',
|
||||
'.mkd',
|
||||
'.mdwn',
|
||||
'.mdown',
|
||||
'.markdown',
|
||||
'.markdn',
|
||||
'.mdtxt',
|
||||
'.mdtext',
|
||||
'.workbook',
|
||||
];
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { isMarkdownFile, looksLikeMarkdownPath } from './util/file';
|
||||
import { InMemoryDocument } from './util/inMemoryDocument';
|
||||
import { Limiter } from './util/limiter';
|
||||
import { ResourceMap } from './util/resourceMap';
|
||||
|
@ -42,7 +41,12 @@ export interface MdWorkspaceContents {
|
|||
*/
|
||||
getAllMarkdownDocuments(): Promise<Iterable<SkinnyTextDocument>>;
|
||||
|
||||
getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined>;
|
||||
/**
|
||||
* Check if a document already exists in the workspace contents.
|
||||
*/
|
||||
hasMarkdownDocument(resource: vscode.Uri): boolean;
|
||||
|
||||
getOrLoadMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined>;
|
||||
|
||||
pathExists(resource: vscode.Uri): Promise<boolean>;
|
||||
|
||||
|
@ -84,7 +88,7 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
|
|||
const resources = await vscode.workspace.findFiles('**/*.md', '**/node_modules/**');
|
||||
const onDiskResults = await Promise.all(resources.map(resource => {
|
||||
return limiter.queue(async () => {
|
||||
const doc = await this.getMarkdownDocument(resource);
|
||||
const doc = await this.getOrLoadMarkdownDocument(resource);
|
||||
if (doc) {
|
||||
foundFiles.add(doc.uri.toString());
|
||||
}
|
||||
|
@ -123,14 +127,14 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
|
|||
|
||||
this._register(this._watcher.onDidChange(async resource => {
|
||||
this._documentCache.delete(resource);
|
||||
const document = await this.getMarkdownDocument(resource);
|
||||
const document = await this.getOrLoadMarkdownDocument(resource);
|
||||
if (document) {
|
||||
this._onDidChangeMarkdownDocumentEmitter.fire(document);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._watcher.onDidCreate(async resource => {
|
||||
const document = await this.getMarkdownDocument(resource);
|
||||
const document = await this.getOrLoadMarkdownDocument(resource);
|
||||
if (document) {
|
||||
this._onDidCreateMarkdownDocumentEmitter.fire(document);
|
||||
}
|
||||
|
@ -160,7 +164,7 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
|
|||
return isMarkdownFile(doc) && doc.uri.scheme !== 'vscode-bulkeditpreview';
|
||||
}
|
||||
|
||||
public async getMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
|
||||
public async getOrLoadMarkdownDocument(resource: vscode.Uri): Promise<SkinnyTextDocument | undefined> {
|
||||
const existing = this._documentCache.get(resource);
|
||||
if (existing) {
|
||||
return existing;
|
||||
|
@ -172,8 +176,7 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
|
|||
return matchingDocument;
|
||||
}
|
||||
|
||||
const ext = URI.Utils.extname(resource).toLowerCase();
|
||||
if (ext !== '.md') {
|
||||
if (!looksLikeMarkdownPath(resource)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -190,6 +193,10 @@ export class VsCodeMdWorkspaceContents extends Disposable implements MdWorkspace
|
|||
}
|
||||
}
|
||||
|
||||
public hasMarkdownDocument(resolvedHrefPath: vscode.Uri): boolean {
|
||||
return this._documentCache.has(resolvedHrefPath);
|
||||
}
|
||||
|
||||
public async pathExists(target: vscode.Uri): Promise<boolean> {
|
||||
let targetResourceStat: vscode.FileStat | undefined;
|
||||
try {
|
||||
|
|
Loading…
Reference in a new issue