mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Refactor markdown language features (#152402)
(sorry for the size of this PR) This change cleans up the markdown language features by making the following changes: - Use `registerXSupport` public functions to register these - Expose the slugifier the `MarkdownEngine` uses. You never want to use a different one if you already have a markdown engine - Sort of clean up names. I'd introduced a bunch of confusing names while iterating in this space. What I'm working towards: - `Computer` — Stateless thing that computer data - `Provider` — Potentially stateful thing that provides data (which may be cached) - `VsCodeProvider` — The actual implementation of the various vscode language features (which should only be used by VS Code and in tests, not shared with other features) - Introduce `MdLinkProvider` to avoid recomputing links for a given document. Also use this to hide more internals of link computation
This commit is contained in:
parent
54f5758f81
commit
623f55f437
|
@ -6,19 +6,19 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { CommandManager } from './commandManager';
|
||||
import * as commands from './commands/index';
|
||||
import { registerPasteProvider } from './languageFeatures/copyPaste';
|
||||
import { MdDefinitionProvider } from './languageFeatures/definitionProvider';
|
||||
import { register as registerDiagnostics } from './languageFeatures/diagnostics';
|
||||
import { MdLinkComputer, registerDocumentLinkProvider } from './languageFeatures/documentLinkProvider';
|
||||
import { MdDocumentSymbolProvider } from './languageFeatures/documentSymbolProvider';
|
||||
import { registerDropIntoEditor } from './languageFeatures/dropIntoEditor';
|
||||
import { registerFindFileReferences } from './languageFeatures/fileReferences';
|
||||
import { MdFoldingProvider } from './languageFeatures/foldingProvider';
|
||||
import { MdPathCompletionProvider } from './languageFeatures/pathCompletions';
|
||||
import { MdReferencesComputer, registerReferencesProvider } from './languageFeatures/references';
|
||||
import { MdRenameProvider } from './languageFeatures/rename';
|
||||
import { MdSmartSelect } from './languageFeatures/smartSelect';
|
||||
import { MdWorkspaceSymbolProvider } from './languageFeatures/workspaceSymbolProvider';
|
||||
import { registerPasteSupport } from './languageFeatures/copyPaste';
|
||||
import { registerDefinitionSupport } from './languageFeatures/definitionProvider';
|
||||
import { registerDiagnosticSupport } from './languageFeatures/diagnostics';
|
||||
import { MdLinkProvider, registerDocumentLinkSupport } from './languageFeatures/documentLinkProvider';
|
||||
import { MdDocumentSymbolProvider, registerDocumentSymbolSupport } from './languageFeatures/documentSymbolProvider';
|
||||
import { registerDropIntoEditorSupport } from './languageFeatures/dropIntoEditor';
|
||||
import { registerFindFileReferenceSupport } from './languageFeatures/fileReferences';
|
||||
import { registerFoldingSupport } from './languageFeatures/foldingProvider';
|
||||
import { registerPathCompletionSupport } from './languageFeatures/pathCompletions';
|
||||
import { MdReferencesProvider, registerReferencesSupport } from './languageFeatures/references';
|
||||
import { registerRenameSupport } from './languageFeatures/rename';
|
||||
import { registerSmartSelectSupport } from './languageFeatures/smartSelect';
|
||||
import { registerWorkspaceSymbolSupport } from './languageFeatures/workspaceSymbolProvider';
|
||||
import { Logger } from './logger';
|
||||
import { MarkdownEngine } from './markdownEngine';
|
||||
import { getMarkdownExtensionContributions } from './markdownExtensions';
|
||||
|
@ -43,11 +43,10 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
const commandManager = new CommandManager();
|
||||
|
||||
const contentProvider = new MarkdownContentProvider(engine, context, cspArbiter, contributions, logger);
|
||||
const symbolProvider = new MdDocumentSymbolProvider(engine);
|
||||
const previewManager = new MarkdownPreviewManager(contentProvider, logger, contributions, engine);
|
||||
context.subscriptions.push(previewManager);
|
||||
|
||||
context.subscriptions.push(registerMarkdownLanguageFeatures(commandManager, symbolProvider, engine));
|
||||
context.subscriptions.push(registerMarkdownLanguageFeatures(commandManager, engine));
|
||||
context.subscriptions.push(registerMarkdownCommands(commandManager, previewManager, telemetryReporter, cspArbiter, engine));
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
|
||||
|
@ -58,30 +57,35 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
|
||||
function registerMarkdownLanguageFeatures(
|
||||
commandManager: CommandManager,
|
||||
symbolProvider: MdDocumentSymbolProvider,
|
||||
engine: MarkdownEngine
|
||||
): vscode.Disposable {
|
||||
const selector: vscode.DocumentSelector = { language: 'markdown', scheme: '*' };
|
||||
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const workspaceContents = new VsCodeMdWorkspaceContents();
|
||||
|
||||
const referencesComputer = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const linkProvider = new MdLinkProvider(engine, workspaceContents);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspaceContents);
|
||||
const symbolProvider = new MdDocumentSymbolProvider(engine);
|
||||
|
||||
return vscode.Disposable.from(
|
||||
workspaceContents,
|
||||
vscode.languages.registerDocumentSymbolProvider(selector, symbolProvider),
|
||||
vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(engine)),
|
||||
vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(engine)),
|
||||
vscode.languages.registerWorkspaceSymbolProvider(new MdWorkspaceSymbolProvider(symbolProvider, workspaceContents)),
|
||||
vscode.languages.registerRenameProvider(selector, new MdRenameProvider(referencesComputer, workspaceContents, githubSlugifier)),
|
||||
vscode.languages.registerDefinitionProvider(selector, new MdDefinitionProvider(referencesComputer)),
|
||||
MdPathCompletionProvider.register(selector, engine, linkComputer),
|
||||
registerDocumentLinkProvider(selector, linkComputer),
|
||||
registerDiagnostics(selector, engine, workspaceContents, linkComputer, commandManager, referencesComputer),
|
||||
registerDropIntoEditor(selector),
|
||||
registerReferencesProvider(selector, referencesComputer),
|
||||
registerPasteProvider(selector),
|
||||
registerFindFileReferences(commandManager, referencesComputer),
|
||||
linkProvider,
|
||||
referencesProvider,
|
||||
|
||||
// Language features
|
||||
registerDefinitionSupport(selector, referencesProvider),
|
||||
registerDiagnosticSupport(selector, engine, workspaceContents, linkProvider, commandManager, referencesProvider),
|
||||
registerDocumentLinkSupport(selector, linkProvider),
|
||||
registerDocumentSymbolSupport(selector, engine),
|
||||
registerDropIntoEditorSupport(selector),
|
||||
registerFindFileReferenceSupport(commandManager, referencesProvider),
|
||||
registerFoldingSupport(selector, engine),
|
||||
registerPasteSupport(selector),
|
||||
registerPathCompletionSupport(selector, engine, linkProvider),
|
||||
registerReferencesSupport(selector, referencesProvider),
|
||||
registerRenameSupport(selector, workspaceContents, referencesProvider, engine.slugifier),
|
||||
registerSmartSelectSupport(selector, engine),
|
||||
registerWorkspaceSymbolSupport(workspaceContents, symbolProvider),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { tryGetUriListSnippet } from './dropIntoEditor';
|
||||
|
||||
export function registerPasteProvider(selector: vscode.DocumentSelector) {
|
||||
export function registerPasteSupport(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentPasteEditProvider(selector, new class implements vscode.DocumentPasteEditProvider {
|
||||
|
||||
async provideDocumentPasteEdits(
|
||||
|
|
|
@ -3,21 +3,25 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
import { MdReferencesComputer } from './references';
|
||||
import { MdReferencesProvider } from './references';
|
||||
|
||||
export class MdDefinitionProvider extends Disposable implements vscode.DefinitionProvider {
|
||||
export class MdDefinitionProvider implements vscode.DefinitionProvider {
|
||||
|
||||
constructor(
|
||||
private readonly referencesComputer: MdReferencesComputer
|
||||
) {
|
||||
super();
|
||||
}
|
||||
private readonly referencesProvider: MdReferencesProvider
|
||||
) { }
|
||||
|
||||
async provideDefinition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Definition | undefined> {
|
||||
const allRefs = await this.referencesComputer.getReferencesAtPosition(document, position, token);
|
||||
const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token);
|
||||
|
||||
return allRefs.find(ref => ref.kind === 'link' && ref.isDefinition)?.location;
|
||||
}
|
||||
}
|
||||
|
||||
export function registerDefinitionSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
referencesProvider: MdReferencesProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerDefinitionProvider(selector, new MdDefinitionProvider(referencesProvider));
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ import { Limiter } from '../util/limiter';
|
|||
import { ResourceMap } from '../util/resourceMap';
|
||||
import { MdTableOfContentsWatcher } from '../test/tableOfContentsWatcher';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref, LinkDefinitionSet, MdLink, MdLinkComputer, MdLinkSource } from './documentLinkProvider';
|
||||
import { MdReferencesComputer, tryFindMdDocumentForLink } from './references';
|
||||
import { InternalHref, MdLink, MdLinkSource, MdLinkProvider, LinkDefinitionSet } from './documentLinkProvider';
|
||||
import { MdReferencesProvider, tryFindMdDocumentForLink } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -305,7 +305,7 @@ export class DiagnosticManager extends Disposable {
|
|||
private readonly computer: DiagnosticComputer,
|
||||
private readonly configuration: DiagnosticConfiguration,
|
||||
private readonly reporter: DiagnosticReporter,
|
||||
private readonly referencesComputer: MdReferencesComputer,
|
||||
private readonly referencesProvider: MdReferencesProvider,
|
||||
delay = 300,
|
||||
) {
|
||||
super();
|
||||
|
@ -344,7 +344,7 @@ export class DiagnosticManager extends Disposable {
|
|||
this._register(this.tableOfContentsWatcher.onTocChanged(async e => {
|
||||
// When the toc of a document changes, revalidate every file that linked to it too
|
||||
const triggered = new ResourceMap<void>();
|
||||
for (const ref of await this.referencesComputer.getAllReferencesToFile(e.uri, noopToken)) {
|
||||
for (const ref of await this.referencesProvider.getAllReferencesToFile(e.uri, noopToken)) {
|
||||
const file = ref.location.uri;
|
||||
if (!triggered.has(file)) {
|
||||
this.triggerDiagnostics(file);
|
||||
|
@ -450,11 +450,11 @@ export class DiagnosticComputer {
|
|||
constructor(
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly linkComputer: MdLinkComputer,
|
||||
private readonly linkProvider: MdLinkProvider,
|
||||
) { }
|
||||
|
||||
public async getDiagnostics(doc: SkinnyTextDocument, options: DiagnosticOptions, token: vscode.CancellationToken): Promise<{ readonly diagnostics: vscode.Diagnostic[]; readonly links: MdLink[] }> {
|
||||
const links = await this.linkComputer.getAllLinks(doc, token);
|
||||
public async getDiagnostics(doc: SkinnyTextDocument, options: DiagnosticOptions, token: vscode.CancellationToken): Promise<{ readonly diagnostics: vscode.Diagnostic[]; readonly links: readonly MdLink[] }> {
|
||||
const { links, definitions } = await this.linkProvider.getLinks(doc);
|
||||
if (token.isCancellationRequested || !options.enabled) {
|
||||
return { links, diagnostics: [] };
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ export class DiagnosticComputer {
|
|||
links,
|
||||
diagnostics: (await Promise.all([
|
||||
this.validateFileLinks(options, links, token),
|
||||
Array.from(this.validateReferenceLinks(options, links)),
|
||||
Array.from(this.validateReferenceLinks(options, links, definitions)),
|
||||
this.validateFragmentLinks(doc, options, links, token),
|
||||
])).flat()
|
||||
};
|
||||
|
@ -501,15 +501,14 @@ export class DiagnosticComputer {
|
|||
return diagnostics;
|
||||
}
|
||||
|
||||
private *validateReferenceLinks(options: DiagnosticOptions, links: readonly MdLink[]): Iterable<vscode.Diagnostic> {
|
||||
private *validateReferenceLinks(options: DiagnosticOptions, links: readonly MdLink[], definitions: LinkDefinitionSet): Iterable<vscode.Diagnostic> {
|
||||
const severity = toSeverity(options.validateReferences);
|
||||
if (typeof severity === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const definitionSet = new LinkDefinitionSet(links);
|
||||
for (const link of links) {
|
||||
if (link.href.kind === 'reference' && !definitionSet.lookup(link.href.ref)) {
|
||||
if (link.href.kind === 'reference' && !definitions.lookup(link.href.ref)) {
|
||||
yield new vscode.Diagnostic(
|
||||
link.source.hrefRange,
|
||||
localize('invalidReferenceLink', 'No link definition found: \'{0}\'', link.href.ref),
|
||||
|
@ -620,19 +619,19 @@ class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider {
|
|||
}
|
||||
}
|
||||
|
||||
export function register(
|
||||
export function registerDiagnosticSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
workspaceContents: MdWorkspaceContents,
|
||||
linkComputer: MdLinkComputer,
|
||||
linkProvider: MdLinkProvider,
|
||||
commandManager: CommandManager,
|
||||
referenceComputer: MdReferencesComputer,
|
||||
referenceComputer: MdReferencesProvider,
|
||||
): vscode.Disposable {
|
||||
const configuration = new VSCodeDiagnosticConfiguration();
|
||||
const manager = new DiagnosticManager(
|
||||
engine,
|
||||
workspaceContents,
|
||||
new DiagnosticComputer(engine, workspaceContents, linkComputer),
|
||||
new DiagnosticComputer(engine, workspaceContents, linkProvider),
|
||||
configuration,
|
||||
new DiagnosticCollectionReporter(),
|
||||
referenceComputer);
|
||||
|
|
|
@ -9,8 +9,11 @@ import * as uri from 'vscode-uri';
|
|||
import { OpenDocumentLinkCommand } from '../commands/openDocumentLink';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { coalesce } from '../util/arrays';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { getUriForLinkWithKnownExternalScheme, isOfScheme, Schemes } from '../util/schemes';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { MdDocumentInfoCache } from './workspaceCache';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -242,6 +245,9 @@ class NoLinkRanges {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stateless object that extracts link information from markdown files.
|
||||
*/
|
||||
export class MdLinkComputer {
|
||||
|
||||
constructor(
|
||||
|
@ -257,7 +263,7 @@ export class MdLinkComputer {
|
|||
return Array.from([
|
||||
...this.getInlineLinks(document, noLinkRanges),
|
||||
...this.getReferenceLinks(document, noLinkRanges),
|
||||
...this.getLinkDefinitions2(document, noLinkRanges),
|
||||
...this.getLinkDefinitions(document, noLinkRanges),
|
||||
...this.getAutoLinks(document, noLinkRanges),
|
||||
]);
|
||||
}
|
||||
|
@ -369,12 +375,7 @@ export class MdLinkComputer {
|
|||
}
|
||||
}
|
||||
|
||||
public async getLinkDefinitions(document: SkinnyTextDocument): Promise<Iterable<MdLinkDefinition>> {
|
||||
const noLinkRanges = await NoLinkRanges.compute(document, this.engine);
|
||||
return this.getLinkDefinitions2(document, noLinkRanges);
|
||||
}
|
||||
|
||||
private *getLinkDefinitions2(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLinkDefinition> {
|
||||
private *getLinkDefinitions(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLinkDefinition> {
|
||||
const text = document.getText();
|
||||
for (const match of text.matchAll(definitionPattern)) {
|
||||
const pre = match[1];
|
||||
|
@ -419,7 +420,37 @@ export class MdLinkComputer {
|
|||
}
|
||||
}
|
||||
|
||||
export class LinkDefinitionSet {
|
||||
/**
|
||||
* Stateful object which provides links for markdown files the workspace.
|
||||
*/
|
||||
export class MdLinkProvider extends Disposable {
|
||||
|
||||
private readonly _linkCache: MdDocumentInfoCache<readonly MdLink[]>;
|
||||
|
||||
private readonly linkComputer: MdLinkComputer;
|
||||
|
||||
constructor(
|
||||
engine: MarkdownEngine,
|
||||
workspaceContents: MdWorkspaceContents,
|
||||
) {
|
||||
super();
|
||||
this.linkComputer = new MdLinkComputer(engine);
|
||||
this._linkCache = this._register(new MdDocumentInfoCache(workspaceContents, doc => this.linkComputer.getAllLinks(doc, noopToken)));
|
||||
}
|
||||
|
||||
public async getLinks(document: SkinnyTextDocument): Promise<{
|
||||
readonly links: readonly MdLink[];
|
||||
readonly definitions: LinkDefinitionSet;
|
||||
}> {
|
||||
const links = (await this._linkCache.get(document.uri)) ?? [];
|
||||
return {
|
||||
links,
|
||||
definitions: new LinkDefinitionSet(links),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class LinkDefinitionSet implements Iterable<[string, MdLinkDefinition]> {
|
||||
private readonly _map = new Map<string, MdLinkDefinition>();
|
||||
|
||||
constructor(links: Iterable<MdLink>) {
|
||||
|
@ -430,29 +461,31 @@ export class LinkDefinitionSet {
|
|||
}
|
||||
}
|
||||
|
||||
public [Symbol.iterator](): Iterator<[string, MdLinkDefinition]> {
|
||||
return this._map.entries();
|
||||
}
|
||||
|
||||
public lookup(ref: string): MdLinkDefinition | undefined {
|
||||
return this._map.get(ref);
|
||||
}
|
||||
}
|
||||
|
||||
export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
||||
export class MdVsCodeLinkProvider implements vscode.DocumentLinkProvider {
|
||||
|
||||
constructor(
|
||||
private readonly _linkComputer: MdLinkComputer,
|
||||
private readonly _linkProvider: MdLinkProvider,
|
||||
) { }
|
||||
|
||||
public async provideDocumentLinks(
|
||||
document: SkinnyTextDocument,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<vscode.DocumentLink[]> {
|
||||
const allLinks = (await this._linkComputer.getAllLinks(document, token)) ?? [];
|
||||
const { links, definitions } = await this._linkProvider.getLinks(document);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const definitionSet = new LinkDefinitionSet(allLinks);
|
||||
return coalesce(allLinks
|
||||
.map(data => this.toValidDocumentLink(data, definitionSet)));
|
||||
return coalesce(links.map(data => this.toValidDocumentLink(data, definitions)));
|
||||
}
|
||||
|
||||
private toValidDocumentLink(link: MdLink, definitionSet: LinkDefinitionSet): vscode.DocumentLink | undefined {
|
||||
|
@ -482,9 +515,9 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider {
|
|||
}
|
||||
}
|
||||
|
||||
export function registerDocumentLinkProvider(
|
||||
export function registerDocumentLinkSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
linkComputer: MdLinkComputer,
|
||||
linkProvider: MdLinkProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerDocumentLinkProvider(selector, new MdLinkProvider(linkComputer));
|
||||
return vscode.languages.registerDocumentLinkProvider(selector, new MdVsCodeLinkProvider(linkProvider));
|
||||
}
|
||||
|
|
|
@ -74,3 +74,10 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||
return '#'.repeat(entry.level) + ' ' + entry.text;
|
||||
}
|
||||
}
|
||||
|
||||
export function registerDocumentSymbolSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerDocumentSymbolProvider(selector, new MdDocumentSymbolProvider(engine));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const imageFileExtensions = new Set<string>([
|
|||
'.webp',
|
||||
]);
|
||||
|
||||
export function registerDropIntoEditor(selector: vscode.DocumentSelector) {
|
||||
export function registerDropIntoEditorSupport(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentOnDropEditProvider(selector, new class implements vscode.DocumentOnDropEditProvider {
|
||||
async provideDocumentOnDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> {
|
||||
const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Command, CommandManager } from '../commandManager';
|
||||
import { MdReferencesComputer } from './references';
|
||||
import { MdReferencesProvider } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -16,7 +16,7 @@ export class FindFileReferencesCommand implements Command {
|
|||
public readonly id = 'markdown.findAllFileReferences';
|
||||
|
||||
constructor(
|
||||
private readonly referencesComputer: MdReferencesComputer,
|
||||
private readonly referencesProvider: MdReferencesProvider,
|
||||
) { }
|
||||
|
||||
public async execute(resource?: vscode.Uri) {
|
||||
|
@ -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.referencesComputer.getAllReferencesToFile(resource!, token);
|
||||
const references = await this.referencesProvider.getAllReferencesToFile(resource!, token);
|
||||
const locations = references.map(ref => ref.location);
|
||||
|
||||
const config = vscode.workspace.getConfiguration('references');
|
||||
|
@ -49,6 +49,9 @@ export class FindFileReferencesCommand implements Command {
|
|||
}
|
||||
}
|
||||
|
||||
export function registerFindFileReferences(commandManager: CommandManager, referencesProvider: MdReferencesComputer): vscode.Disposable {
|
||||
export function registerFindFileReferenceSupport(
|
||||
commandManager: CommandManager,
|
||||
referencesProvider: MdReferencesProvider
|
||||
): vscode.Disposable {
|
||||
return commandManager.register(new FindFileReferencesCommand(referencesProvider));
|
||||
}
|
||||
|
|
|
@ -111,3 +111,10 @@ const isFoldableToken = (token: Token): token is MarkdownItTokenWithMap => {
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export function registerFoldingSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(engine));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { MarkdownEngine } from '../markdownEngine';
|
|||
import { TableOfContents } from '../tableOfContents';
|
||||
import { resolveUriToMarkdownFile } from '../util/openDocumentLink';
|
||||
import { SkinnyTextDocument } from '../workspaceContents';
|
||||
import { MdLinkComputer } from './documentLinkProvider';
|
||||
import { MdLinkProvider } from './documentLinkProvider';
|
||||
|
||||
enum CompletionContextKind {
|
||||
/** `[...](|)` */
|
||||
|
@ -76,19 +76,14 @@ function tryDecodeUriComponent(str: string): string {
|
|||
}
|
||||
}
|
||||
|
||||
export class MdPathCompletionProvider implements vscode.CompletionItemProvider {
|
||||
|
||||
public static register(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
linkComputer: MdLinkComputer,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerCompletionItemProvider(selector, new MdPathCompletionProvider(engine, linkComputer), '.', '/', '#');
|
||||
}
|
||||
/**
|
||||
* Adds path completions in markdown files by implementing {@link vscode.CompletionItemProvider}.
|
||||
*/
|
||||
export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProvider {
|
||||
|
||||
constructor(
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly linkComputer: MdLinkComputer,
|
||||
private readonly linkProvider: MdLinkProvider,
|
||||
) { }
|
||||
|
||||
public async provideCompletionItems(document: SkinnyTextDocument, position: vscode.Position, _token: vscode.CancellationToken, _context: vscode.CompletionContext): Promise<vscode.CompletionItem[]> {
|
||||
|
@ -240,8 +235,8 @@ export class MdPathCompletionProvider implements vscode.CompletionItemProvider {
|
|||
const insertionRange = new vscode.Range(context.linkTextStartPosition, position);
|
||||
const replacementRange = new vscode.Range(insertionRange.start, position.translate({ characterDelta: context.linkSuffix.length }));
|
||||
|
||||
const definitions = await this.linkComputer.getLinkDefinitions(document);
|
||||
for (const def of definitions) {
|
||||
const { definitions } = await this.linkProvider.getLinks(document);
|
||||
for (const [_, def] of definitions) {
|
||||
yield {
|
||||
kind: vscode.CompletionItemKind.Reference,
|
||||
label: def.ref.text,
|
||||
|
@ -351,3 +346,11 @@ export class MdPathCompletionProvider implements vscode.CompletionItemProvider {
|
|||
return document.uri;
|
||||
}
|
||||
}
|
||||
|
||||
export function registerPathCompletionSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
linkProvider: MdLinkProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerCompletionItemProvider(selector, new MdVsCodePathCompletionProvider(engine, linkProvider), '.', '/', '#');
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as uri from 'vscode-uri';
|
||||
import { MarkdownEngine } from '../markdownEngine';
|
||||
import { Slugifier } from '../slugify';
|
||||
import { TableOfContents, TocEntry } from '../tableOfContents';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
import { InternalHref, MdLink, MdLinkComputer } from './documentLinkProvider';
|
||||
import { MdWorkspaceCache } from './workspaceCache';
|
||||
import { MdWorkspaceInfoCache } from './workspaceCache';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -59,19 +58,22 @@ export interface MdHeaderReference {
|
|||
|
||||
export type MdReference = MdLinkReference | MdHeaderReference;
|
||||
|
||||
export class MdReferencesComputer extends Disposable {
|
||||
/**
|
||||
* Stateful object that computes references for markdown files.
|
||||
*/
|
||||
export class MdReferencesProvider extends Disposable {
|
||||
|
||||
private readonly _linkCache: MdWorkspaceCache<readonly MdLink[]>;
|
||||
private readonly _linkCache: MdWorkspaceInfoCache<readonly MdLink[]>;
|
||||
private readonly _linkComputer: MdLinkComputer;
|
||||
|
||||
public constructor(
|
||||
private readonly linkComputer: MdLinkComputer,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly engine: MarkdownEngine,
|
||||
private readonly slugifier: Slugifier,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._linkCache = this._register(new MdWorkspaceCache(workspaceContents, doc => linkComputer.getAllLinks(doc, noopToken)));
|
||||
this._linkComputer = new MdLinkComputer(engine);
|
||||
this._linkCache = this._register(new MdWorkspaceInfoCache(workspaceContents, doc => this._linkComputer.getAllLinks(doc, noopToken)));
|
||||
}
|
||||
|
||||
public async getReferencesAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
|
||||
|
@ -110,7 +112,7 @@ export class MdReferencesComputer extends Disposable {
|
|||
for (const link of links) {
|
||||
if (link.href.kind === 'internal'
|
||||
&& this.looksLikeLinkToDoc(link.href, document.uri)
|
||||
&& this.slugifier.fromHeading(link.href.fragment).value === header.slug.value
|
||||
&& this.engine.slugifier.fromHeading(link.href.fragment).value === header.slug.value
|
||||
) {
|
||||
references.push({
|
||||
kind: 'link',
|
||||
|
@ -126,7 +128,7 @@ export class MdReferencesComputer extends Disposable {
|
|||
}
|
||||
|
||||
private async getReferencesToLinkAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
|
||||
const docLinks = await this.linkComputer.getAllLinks(document, token);
|
||||
const docLinks = await this._linkComputer.getAllLinks(document, token);
|
||||
|
||||
for (const link of docLinks) {
|
||||
if (link.kind === 'definition') {
|
||||
|
@ -200,7 +202,7 @@ export class MdReferencesComputer extends Disposable {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (this.slugifier.fromHeading(link.href.fragment).equals(this.slugifier.fromHeading(sourceLink.href.fragment))) {
|
||||
if (this.engine.slugifier.fromHeading(link.href.fragment).equals(this.engine.slugifier.fromHeading(sourceLink.href.fragment))) {
|
||||
const isTriggerLocation = sourceLink.source.resource.fsPath === link.source.resource.fsPath && sourceLink.source.hrefRange.isEqual(link.source.hrefRange);
|
||||
references.push({
|
||||
kind: 'link',
|
||||
|
@ -284,27 +286,27 @@ export class MdReferencesComputer extends Disposable {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Implements {@link vscode.ReferenceProvider} for markdown documents.
|
||||
*/
|
||||
export class MdVsCodeReferencesProvider implements vscode.ReferenceProvider {
|
||||
|
||||
public constructor(
|
||||
private readonly referencesComputer: MdReferencesComputer
|
||||
private readonly referencesProvider: MdReferencesProvider
|
||||
) { }
|
||||
|
||||
async provideReferences(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[]> {
|
||||
const allRefs = await this.referencesComputer.getReferencesAtPosition(document, position, token);
|
||||
const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token);
|
||||
return allRefs
|
||||
.filter(ref => context.includeDeclaration || !ref.isDefinition)
|
||||
.map(ref => ref.location);
|
||||
}
|
||||
}
|
||||
|
||||
export function registerReferencesProvider(
|
||||
export function registerReferencesSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
computer: MdReferencesComputer,
|
||||
referencesProvider: MdReferencesProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(computer));
|
||||
return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(referencesProvider));
|
||||
}
|
||||
|
||||
export async function tryFindMdDocumentForLink(href: InternalHref, workspaceContents: MdWorkspaceContents): Promise<SkinnyTextDocument | 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, MdReferencesComputer, tryFindMdDocumentForLink } from './references';
|
||||
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryFindMdDocumentForLink } from './references';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -45,7 +45,7 @@ function tryDecodeUri(str: string): string {
|
|||
}
|
||||
}
|
||||
|
||||
export class MdRenameProvider extends Disposable implements vscode.RenameProvider {
|
||||
export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameProvider {
|
||||
|
||||
private cachedRefs?: {
|
||||
readonly resource: vscode.Uri;
|
||||
|
@ -58,8 +58,8 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
|
|||
private readonly renameNotSupportedText = localize('invalidRenameLocation', "Rename not supported at location");
|
||||
|
||||
public constructor(
|
||||
private readonly referencesComputer: MdReferencesComputer,
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly referencesProvider: MdReferencesProvider,
|
||||
private readonly slugifier: Slugifier,
|
||||
) {
|
||||
super();
|
||||
|
@ -253,7 +253,7 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
|
|||
return this.cachedRefs;
|
||||
}
|
||||
|
||||
const references = await this.referencesComputer.getReferencesAtPosition(document, position, token);
|
||||
const references = await this.referencesProvider.getReferencesAtPosition(document, position, token);
|
||||
const triggerRef = references.find(ref => ref.isTriggerLocation);
|
||||
if (!triggerRef) {
|
||||
return undefined;
|
||||
|
@ -270,3 +270,12 @@ export class MdRenameProvider extends Disposable implements vscode.RenameProvide
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
export function registerRenameSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
workspaceContents: MdWorkspaceContents,
|
||||
referencesProvider: MdReferencesProvider,
|
||||
slugifier: Slugifier,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerRenameProvider(selector, new MdVsCodeRenameProvider(workspaceContents, referencesProvider, slugifier));
|
||||
}
|
||||
|
|
|
@ -249,3 +249,10 @@ function getFirstChildHeader(document: SkinnyTextDocument, header?: TocEntry, to
|
|||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function registerSmartSelectSupport(
|
||||
selector: vscode.DocumentSelector,
|
||||
engine: MarkdownEngine,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(engine));
|
||||
}
|
||||
|
|
|
@ -9,12 +9,89 @@ import { Lazy, lazy } from '../util/lazy';
|
|||
import { ResourceMap } from '../util/resourceMap';
|
||||
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
|
||||
|
||||
/**
|
||||
* Cache of information for markdown files in the workspace.
|
||||
*/
|
||||
export class MdWorkspaceCache<T> extends Disposable {
|
||||
class LazyResourceMap<T> {
|
||||
private readonly _map = new ResourceMap<Lazy<Promise<T>>>();
|
||||
|
||||
private readonly _cache = new ResourceMap<Lazy<Promise<T>>>();
|
||||
public has(resource: vscode.Uri): boolean {
|
||||
return this._map.has(resource);
|
||||
}
|
||||
|
||||
public get(resource: vscode.Uri): Promise<T> | undefined {
|
||||
return this._map.get(resource)?.value;
|
||||
}
|
||||
|
||||
public set(resource: vscode.Uri, value: Lazy<Promise<T>>) {
|
||||
this._map.set(resource, value);
|
||||
}
|
||||
|
||||
public delete(resource: vscode.Uri) {
|
||||
this._map.delete(resource);
|
||||
}
|
||||
|
||||
public entries(): Promise<Array<[vscode.Uri, T]>> {
|
||||
return Promise.all(Array.from(this._map.entries(), async ([key, entry]) => {
|
||||
return [key, await entry.value];
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache of information per-document in the workspace.
|
||||
*
|
||||
* The values are computed lazily and invalidated when the document changes.
|
||||
*/
|
||||
export class MdDocumentInfoCache<T> extends Disposable {
|
||||
|
||||
private readonly _cache = new LazyResourceMap<T>();
|
||||
|
||||
public constructor(
|
||||
private readonly workspaceContents: MdWorkspaceContents,
|
||||
private readonly getValue: (document: SkinnyTextDocument) => Promise<T>,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this.workspaceContents.onDidChangeMarkdownDocument(doc => this.onDidChangeDocument(doc)));
|
||||
this._register(this.workspaceContents.onDidCreateMarkdownDocument(doc => this.onDidChangeDocument(doc)));
|
||||
this._register(this.workspaceContents.onDidDeleteMarkdownDocument(this.onDidDeleteDocument, this));
|
||||
}
|
||||
|
||||
public async get(resource: vscode.Uri): Promise<T | undefined> {
|
||||
const existing = this._cache.get(resource);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
const doc = await this.workspaceContents.getMarkdownDocument(resource);
|
||||
return doc && this.onDidChangeDocument(doc, true)?.value;
|
||||
}
|
||||
|
||||
public async entries(): Promise<Array<[vscode.Uri, T]>> {
|
||||
return this._cache.entries();
|
||||
}
|
||||
|
||||
private onDidChangeDocument(document: SkinnyTextDocument, forceAdd = false): Lazy<Promise<T>> | undefined {
|
||||
if (forceAdd || this._cache.has(document.uri)) {
|
||||
const value = lazy(() => this.getValue(document));
|
||||
this._cache.set(document.uri, value);
|
||||
return value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private onDidDeleteDocument(resource: vscode.Uri) {
|
||||
this._cache.delete(resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache of information across all markdown files in the workspace.
|
||||
*
|
||||
* Unlike {@link MdDocumentInfoCache}, the entries here are computed eagerly for every file in the workspace.
|
||||
* However the computation of the values is still lazy.
|
||||
*/
|
||||
export class MdWorkspaceInfoCache<T> extends Disposable {
|
||||
|
||||
private readonly _cache = new LazyResourceMap<T>();
|
||||
private _init?: Promise<void>;
|
||||
|
||||
public constructor(
|
||||
|
@ -26,14 +103,12 @@ export class MdWorkspaceCache<T> extends Disposable {
|
|||
|
||||
public async entries(): Promise<Array<[vscode.Uri, T]>> {
|
||||
await this.ensureInit();
|
||||
return Promise.all(Array.from(this._cache.entries(), async ([key, entry]) => {
|
||||
return [key, await entry.value];
|
||||
}));
|
||||
return this._cache.entries();
|
||||
}
|
||||
|
||||
public async values(): Promise<Array<T>> {
|
||||
await this.ensureInit();
|
||||
return Promise.all(Array.from(this._cache.values(), x => x.value));
|
||||
return Array.from(await this._cache.entries(), x => x[1]);
|
||||
}
|
||||
|
||||
private async ensureInit(): Promise<void> {
|
||||
|
|
|
@ -7,11 +7,11 @@ import * as vscode from 'vscode';
|
|||
import { Disposable } from '../util/dispose';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
import { MdDocumentSymbolProvider } from './documentSymbolProvider';
|
||||
import { MdWorkspaceCache } from './workspaceCache';
|
||||
import { MdWorkspaceInfoCache } from './workspaceCache';
|
||||
|
||||
export class MdWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider {
|
||||
|
||||
private readonly _cache: MdWorkspaceCache<vscode.SymbolInformation[]>;
|
||||
private readonly _cache: MdWorkspaceInfoCache<vscode.SymbolInformation[]>;
|
||||
|
||||
public constructor(
|
||||
symbolProvider: MdDocumentSymbolProvider,
|
||||
|
@ -19,7 +19,7 @@ export class MdWorkspaceSymbolProvider extends Disposable implements vscode.Work
|
|||
) {
|
||||
super();
|
||||
|
||||
this._cache = this._register(new MdWorkspaceCache(workspaceContents, doc => symbolProvider.provideDocumentSymbolInformation(doc)));
|
||||
this._cache = this._register(new MdWorkspaceInfoCache(workspaceContents, doc => symbolProvider.provideDocumentSymbolInformation(doc)));
|
||||
}
|
||||
|
||||
public async provideWorkspaceSymbols(query: string): Promise<vscode.SymbolInformation[]> {
|
||||
|
@ -27,3 +27,10 @@ export class MdWorkspaceSymbolProvider extends Disposable implements vscode.Work
|
|||
return allSymbols.filter(symbolInformation => symbolInformation.name.toLowerCase().indexOf(query.toLowerCase()) !== -1);
|
||||
}
|
||||
}
|
||||
|
||||
export function registerWorkspaceSymbolSupport(
|
||||
workspaceContents: MdWorkspaceContents,
|
||||
symbolProvider: MdDocumentSymbolProvider,
|
||||
): vscode.Disposable {
|
||||
return vscode.languages.registerWorkspaceSymbolProvider(new MdWorkspaceSymbolProvider(symbolProvider, workspaceContents));
|
||||
}
|
||||
|
|
|
@ -98,10 +98,14 @@ export class MarkdownEngine {
|
|||
private _slugCount = new Map<string, number>();
|
||||
private _tokenCache = new TokenCache();
|
||||
|
||||
public readonly slugifier: Slugifier;
|
||||
|
||||
public constructor(
|
||||
private readonly contributionProvider: MarkdownContributionProvider,
|
||||
private readonly slugifier: Slugifier,
|
||||
slugifier: Slugifier,
|
||||
) {
|
||||
this.slugifier = slugifier;
|
||||
|
||||
contributionProvider.onContributionsChanged(() => {
|
||||
// Markdown plugin contributions may have changed
|
||||
this.md = undefined;
|
||||
|
|
|
@ -7,9 +7,7 @@ import * as assert from 'assert';
|
|||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdDefinitionProvider } from '../languageFeatures/definitionProvider';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesComputer } from '../languageFeatures/references';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -18,11 +16,10 @@ import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
|||
import { joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
function getDefinition(doc: InMemoryDocument, pos: vscode.Position, workspaceContents: MdWorkspaceContents) {
|
||||
function getDefinition(doc: InMemoryDocument, pos: vscode.Position, workspace: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const referencesComputer = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const provider = new MdDefinitionProvider(referencesComputer);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const provider = new MdDefinitionProvider(referencesProvider);
|
||||
return provider.provideDefinition(doc, pos, noopToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,8 @@ import * as assert from 'assert';
|
|||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { DiagnosticCollectionReporter, DiagnosticComputer, DiagnosticConfiguration, DiagnosticLevel, DiagnosticManager, DiagnosticOptions, DiagnosticReporter } from '../languageFeatures/diagnostics';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesComputer } from '../languageFeatures/references';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { disposeAll } from '../util/dispose';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
@ -28,10 +27,10 @@ const defaultDiagnosticsOptions = Object.freeze<DiagnosticOptions>({
|
|||
ignoreLinks: [],
|
||||
});
|
||||
|
||||
async function getComputedDiagnostics(doc: InMemoryDocument, workspaceContents: MdWorkspaceContents, options: Partial<DiagnosticOptions> = {}): Promise<vscode.Diagnostic[]> {
|
||||
async function getComputedDiagnostics(doc: InMemoryDocument, workspace: MdWorkspaceContents, options: Partial<DiagnosticOptions> = {}): Promise<vscode.Diagnostic[]> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const computer = new DiagnosticComputer(engine, workspaceContents, linkComputer);
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const computer = new DiagnosticComputer(engine, workspace, linkProvider);
|
||||
return (
|
||||
await computer.getDiagnostics(doc, { ...defaultDiagnosticsOptions, ...options, }, noopToken)
|
||||
).diagnostics;
|
||||
|
@ -430,17 +429,17 @@ suite('Markdown: Diagnostics manager', () => {
|
|||
reporter: DiagnosticReporter = new DiagnosticCollectionReporter(),
|
||||
) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const referencesComputer = new MdReferencesComputer(linkComputer, workspace, engine, githubSlugifier);
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const manager = new DiagnosticManager(
|
||||
engine,
|
||||
workspace,
|
||||
new DiagnosticComputer(engine, workspace, linkComputer),
|
||||
new DiagnosticComputer(engine, workspace, linkProvider),
|
||||
configuration,
|
||||
reporter,
|
||||
referencesComputer,
|
||||
referencesProvider,
|
||||
0);
|
||||
_disposables.push(manager, referencesComputer);
|
||||
_disposables.push(manager, referencesProvider);
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,19 +6,21 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkComputer, MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdLinkProvider, MdVsCodeLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { assertRangeEqual, joinLines } from './util';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { assertRangeEqual, joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
const testFile = vscode.Uri.joinPath(vscode.workspace.workspaceFolders![0].uri, 'x.md');
|
||||
|
||||
function getLinksForFile(fileContents: string) {
|
||||
const doc = new InMemoryDocument(testFile, fileContents);
|
||||
const linkComputer = new MdLinkComputer(createNewMarkdownEngine());
|
||||
const provider = new MdLinkProvider(linkComputer);
|
||||
const doc = new InMemoryDocument(workspacePath('x.md'), fileContents);
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const provider = new MdVsCodeLinkProvider(linkProvider);
|
||||
return provider.provideDocumentLinks(doc, noopToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,22 +5,18 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbolProvider';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
import { workspacePath } from './util';
|
||||
|
||||
|
||||
function getSymbolsForFile(fileContents: string) {
|
||||
const doc = new InMemoryDocument(testFileName, fileContents);
|
||||
const doc = new InMemoryDocument(workspacePath('test.md'), fileContents);
|
||||
const provider = new MdDocumentSymbolProvider(createNewMarkdownEngine());
|
||||
return provider.provideDocumentSymbols(doc);
|
||||
}
|
||||
|
||||
|
||||
suite('markdown.DocumentSymbolProvider', () => {
|
||||
test('Should not return anything for empty document', async () => {
|
||||
const symbols = await getSymbolsForFile('');
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReference, MdReferencesComputer } from '../languageFeatures/references';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { MdReference, MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -19,8 +17,7 @@ import { joinLines, workspacePath } from './util';
|
|||
|
||||
function getFileReferences(resource: vscode.Uri, workspaceContents: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const computer = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const computer = new MdReferencesProvider(engine, workspaceContents);
|
||||
return computer.getAllReferencesToFile(resource, noopToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,19 +6,22 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdPathCompletionProvider } from '../languageFeatures/pathCompletions';
|
||||
import { MdLinkProvider } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdVsCodePathCompletionProvider } from '../languageFeatures/pathCompletions';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
import { InMemoryWorkspaceMarkdownDocuments } from './inMemoryWorkspace';
|
||||
import { CURSOR, getCursorPositions, joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
function getCompletionsAtCursor(resource: vscode.Uri, fileContents: string) {
|
||||
const doc = new InMemoryDocument(resource, fileContents);
|
||||
const workspace = new InMemoryWorkspaceMarkdownDocuments([doc]);
|
||||
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const provider = new MdPathCompletionProvider(engine, linkComputer);
|
||||
const linkProvider = new MdLinkProvider(engine, workspace);
|
||||
const provider = new MdVsCodePathCompletionProvider(engine, linkProvider);
|
||||
const cursorPositions = getCursorPositions(fileContents, doc);
|
||||
return provider.provideCompletionItems(doc, cursorPositions[0], noopToken, {
|
||||
triggerCharacter: undefined,
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesComputer, MdVsCodeReferencesProvider } from '../languageFeatures/references';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { MdReferencesProvider, MdVsCodeReferencesProvider } from '../languageFeatures/references';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
import { MdWorkspaceContents } from '../workspaceContents';
|
||||
|
@ -19,8 +17,7 @@ import { joinLines, workspacePath } from './util';
|
|||
|
||||
function getReferences(doc: InMemoryDocument, pos: vscode.Position, workspaceContents: MdWorkspaceContents) {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const computer = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const computer = new MdReferencesProvider(engine, workspaceContents);
|
||||
const provider = new MdVsCodeReferencesProvider(computer);
|
||||
return provider.provideReferences(doc, pos, { includeDeclaration: true }, noopToken);
|
||||
}
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { MdLinkComputer } from '../languageFeatures/documentLinkProvider';
|
||||
import { MdReferencesComputer } from '../languageFeatures/references';
|
||||
import { MdRenameProvider, MdWorkspaceEdit } from '../languageFeatures/rename';
|
||||
import { MdReferencesProvider } from '../languageFeatures/references';
|
||||
import { MdVsCodeRenameProvider, MdWorkspaceEdit } from '../languageFeatures/rename';
|
||||
import { githubSlugifier } from '../slugify';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { InMemoryDocument } from '../util/inMemoryDocument';
|
||||
|
@ -21,22 +20,20 @@ import { assertRangeEqual, joinLines, workspacePath } from './util';
|
|||
/**
|
||||
* Get prepare rename info.
|
||||
*/
|
||||
function prepareRename(doc: InMemoryDocument, pos: vscode.Position, workspaceContents: MdWorkspaceContents): Promise<undefined | { readonly range: vscode.Range; readonly placeholder: string }> {
|
||||
function prepareRename(doc: InMemoryDocument, pos: vscode.Position, workspace: MdWorkspaceContents): Promise<undefined | { readonly range: vscode.Range; readonly placeholder: string }> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const referenceComputer = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const renameProvider = new MdRenameProvider(referenceComputer, workspaceContents, githubSlugifier);
|
||||
const referenceComputer = new MdReferencesProvider(engine, workspace);
|
||||
const renameProvider = new MdVsCodeRenameProvider(workspace, referenceComputer, githubSlugifier);
|
||||
return renameProvider.prepareRename(doc, pos, noopToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the edits for the rename.
|
||||
*/
|
||||
function getRenameEdits(doc: InMemoryDocument, pos: vscode.Position, newName: string, workspaceContents: MdWorkspaceContents): Promise<MdWorkspaceEdit | undefined> {
|
||||
function getRenameEdits(doc: InMemoryDocument, pos: vscode.Position, newName: string, workspace: MdWorkspaceContents): Promise<MdWorkspaceEdit | undefined> {
|
||||
const engine = createNewMarkdownEngine();
|
||||
const linkComputer = new MdLinkComputer(engine);
|
||||
const referencesProvider = new MdReferencesComputer(linkComputer, workspaceContents, engine, githubSlugifier);
|
||||
const renameProvider = new MdRenameProvider(referencesProvider, workspaceContents, githubSlugifier);
|
||||
const referencesProvider = new MdReferencesProvider(engine, workspace);
|
||||
const renameProvider = new MdVsCodeRenameProvider(workspace, referencesProvider, githubSlugifier);
|
||||
return renameProvider.provideRenameEditsImpl(doc, pos, newName, noopToken);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue