Rename types in the markdown extension (#152905)

Renames in the markdown extension

This renames some types and splits up some files as part of an exploration towards a proper LSP. Changes:

- `SkinnyTextDocument` -> `ITextDocument`
- Moved `ITextDocument` to own file
- `MdWorkspaceContents` -> `IMdWorkspace`
This commit is contained in:
Matt Bierner
2022-06-22 14:12:48 -07:00
committed by GitHub
parent 5f0a3888b4
commit 07144d22c4
35 changed files with 353 additions and 336 deletions

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { SkinnyTextDocument } from '../workspaceContents';
import { ITextDocument } from '../types/textDocument';
import { MdReferencesProvider } from './references';
export class MdVsCodeDefinitionProvider implements vscode.DefinitionProvider {
@@ -12,7 +12,7 @@ export class MdVsCodeDefinitionProvider implements vscode.DefinitionProvider {
private readonly referencesProvider: MdReferencesProvider,
) { }
async provideDefinition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Definition | undefined> {
async provideDefinition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Definition | undefined> {
const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token);
return allRefs.find(ref => ref.kind === 'link' && ref.isDefinition)?.location;

View File

@@ -9,6 +9,7 @@ import * as nls from 'vscode-nls';
import { CommandManager } from '../commandManager';
import { ILogger } from '../logging';
import { MdTableOfContentsProvider } from '../tableOfContents';
import { ITextDocument } from '../types/textDocument';
import { Delayer } from '../util/async';
import { noopToken } from '../util/cancellation';
import { Disposable } from '../util/dispose';
@@ -16,7 +17,7 @@ import { isMarkdownFile, looksLikeMarkdownPath } from '../util/file';
import { Limiter } from '../util/limiter';
import { ResourceMap } from '../util/resourceMap';
import { MdTableOfContentsWatcher } from '../util/tableOfContentsWatcher';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { IMdWorkspace } from '../workspace';
import { InternalHref, LinkDefinitionSet, MdLink, MdLinkProvider, MdLinkSource } from './documentLinks';
import { MdReferencesProvider, tryResolveLinkPath } from './references';
@@ -305,7 +306,7 @@ export class DiagnosticManager extends Disposable {
public readonly ready: Promise<void>;
constructor(
private readonly workspaceContents: MdWorkspaceContents,
private readonly workspace: IMdWorkspace,
private readonly computer: DiagnosticComputer,
private readonly configuration: DiagnosticConfiguration,
private readonly reporter: DiagnosticReporter,
@@ -322,17 +323,17 @@ export class DiagnosticManager extends Disposable {
this.rebuild();
}));
this._register(workspaceContents.onDidCreateMarkdownDocument(doc => {
this._register(workspace.onDidCreateMarkdownDocument(doc => {
this.triggerDiagnostics(doc.uri);
// Links in other files may have become valid
this.triggerForReferencingFiles(doc.uri);
}));
this._register(workspaceContents.onDidChangeMarkdownDocument(doc => {
this._register(workspace.onDidChangeMarkdownDocument(doc => {
this.triggerDiagnostics(doc.uri);
}));
this._register(workspaceContents.onDidDeleteMarkdownDocument(uri => {
this._register(workspace.onDidDeleteMarkdownDocument(uri => {
this.triggerForReferencingFiles(uri);
}));
@@ -352,7 +353,7 @@ export class DiagnosticManager extends Disposable {
}
}));
this.tableOfContentsWatcher = this._register(new MdTableOfContentsWatcher(workspaceContents, tocProvider, delay / 2));
this.tableOfContentsWatcher = this._register(new MdTableOfContentsWatcher(workspace, tocProvider, delay / 2));
this._register(this.tableOfContentsWatcher.onTocChanged(e => {
return this.triggerForReferencingFiles(e.uri);
}));
@@ -379,7 +380,7 @@ export class DiagnosticManager extends Disposable {
this.pendingDiagnostics.clear();
}
private async recomputeDiagnosticState(doc: SkinnyTextDocument, token: vscode.CancellationToken): Promise<{ diagnostics: readonly vscode.Diagnostic[]; links: readonly MdLink[]; config: DiagnosticOptions }> {
private async recomputeDiagnosticState(doc: ITextDocument, token: vscode.CancellationToken): Promise<{ diagnostics: readonly vscode.Diagnostic[]; links: readonly MdLink[]; config: DiagnosticOptions }> {
this.logger.verbose('DiagnosticManager', `recomputeDiagnosticState - ${doc.uri}`);
const config = this.configuration.getOptions(doc.uri);
@@ -394,7 +395,7 @@ export class DiagnosticManager extends Disposable {
this.pendingDiagnostics.clear();
await Promise.all(pending.map(async resource => {
const doc = await this.workspaceContents.getOrLoadMarkdownDocument(resource);
const doc = await this.workspace.getOrLoadMarkdownDocument(resource);
if (doc) {
await this.inFlightDiagnostics.trigger(doc.uri, async (token) => {
if (this.reporter.areDiagnosticsEnabled(doc.uri)) {
@@ -419,7 +420,7 @@ export class DiagnosticManager extends Disposable {
(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.workspaceContents.getAllMarkdownDocuments();
const allDocs = await this.workspace.getAllMarkdownDocuments();
await Promise.all(Array.from(allDocs, doc => this.triggerDiagnostics(doc.uri)));
})()
);
@@ -475,12 +476,12 @@ class FileLinkMap {
export class DiagnosticComputer {
constructor(
private readonly workspaceContents: MdWorkspaceContents,
private readonly workspace: IMdWorkspace,
private readonly linkProvider: MdLinkProvider,
private readonly tocProvider: MdTableOfContentsProvider,
) { }
public async getDiagnostics(doc: SkinnyTextDocument, options: DiagnosticOptions, token: vscode.CancellationToken): Promise<{ readonly diagnostics: vscode.Diagnostic[]; readonly links: readonly MdLink[] }> {
public async getDiagnostics(doc: ITextDocument, 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: [] };
@@ -496,7 +497,7 @@ export class DiagnosticComputer {
};
}
private async validateFragmentLinks(doc: SkinnyTextDocument, options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
private async validateFragmentLinks(doc: ITextDocument, options: DiagnosticOptions, links: readonly MdLink[], token: vscode.CancellationToken): Promise<vscode.Diagnostic[]> {
const severity = toSeverity(options.validateFragmentLinks);
if (typeof severity === 'undefined') {
return [];
@@ -567,7 +568,7 @@ export class DiagnosticComputer {
return;
}
const resolvedHrefPath = await tryResolveLinkPath(path, this.workspaceContents);
const resolvedHrefPath = await tryResolveLinkPath(path, this.workspace);
if (!resolvedHrefPath) {
const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath);
for (const link of links) {
@@ -595,7 +596,7 @@ export class DiagnosticComputer {
}
private isMarkdownPath(resolvedHrefPath: vscode.Uri) {
return this.workspaceContents.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
return this.workspace.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
}
private isIgnoredLink(options: DiagnosticOptions, link: string): boolean {
@@ -652,7 +653,7 @@ class AddToIgnoreLinksQuickFixProvider implements vscode.CodeActionProvider {
export function registerDiagnosticSupport(
selector: vscode.DocumentSelector,
workspaceContents: MdWorkspaceContents,
workspace: IMdWorkspace,
linkProvider: MdLinkProvider,
commandManager: CommandManager,
referenceProvider: MdReferencesProvider,
@@ -661,8 +662,8 @@ export function registerDiagnosticSupport(
): vscode.Disposable {
const configuration = new VSCodeDiagnosticConfiguration();
const manager = new DiagnosticManager(
workspaceContents,
new DiagnosticComputer(workspaceContents, linkProvider, tocProvider),
workspace,
new DiagnosticComputer(workspace, linkProvider, tocProvider),
configuration,
new DiagnosticCollectionReporter(),
referenceProvider,

View File

@@ -7,14 +7,15 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as uri from 'vscode-uri';
import { OpenDocumentLinkCommand } from '../commands/openDocumentLink';
import { ILogger } from '../logging';
import { IMdParser } from '../markdownEngine';
import { ITextDocument } from '../types/textDocument';
import { coalesce } from '../util/arrays';
import { noopToken } from '../util/cancellation';
import { Disposable } from '../util/dispose';
import { getUriForLinkWithKnownExternalScheme, isOfScheme, Schemes } from '../util/schemes';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { MdDocumentInfoCache } from '../util/workspaceCache';
import { ILogger } from '../logging';
import { IMdWorkspace } from '../workspace';
const localize = nls.loadMessageBundle();
@@ -38,7 +39,7 @@ export type LinkHref = ExternalHref | InternalHref | ReferenceHref;
function parseLink(
document: SkinnyTextDocument,
document: ITextDocument,
link: string,
): ExternalHref | InternalHref | undefined {
const cleanLink = stripAngleBrackets(link);
@@ -91,7 +92,7 @@ function parseLink(
};
}
function getWorkspaceFolder(document: SkinnyTextDocument) {
function getWorkspaceFolder(document: ITextDocument) {
return vscode.workspace.getWorkspaceFolder(document.uri)?.uri
|| vscode.workspace.workspaceFolders?.[0]?.uri;
}
@@ -131,7 +132,7 @@ export interface MdLinkDefinition {
export type MdLink = MdInlineLink | MdLinkDefinition;
function extractDocumentLink(
document: SkinnyTextDocument,
document: ITextDocument,
pre: string,
rawLink: string,
matchIndex: number | undefined
@@ -170,7 +171,7 @@ function getFragmentRange(text: string, start: vscode.Position, end: vscode.Posi
return new vscode.Range(start.translate({ characterDelta: index + 1 }), end);
}
function getLinkSourceFragmentInfo(document: SkinnyTextDocument, link: string, linkStart: vscode.Position, linkEnd: vscode.Position): { fragmentRange: vscode.Range | undefined; pathText: string } {
function getLinkSourceFragmentInfo(document: ITextDocument, link: string, linkStart: vscode.Position, linkEnd: vscode.Position): { fragmentRange: vscode.Range | undefined; pathText: string } {
const fragmentRange = getFragmentRange(link, linkStart, linkEnd);
return {
pathText: document.getText(new vscode.Range(linkStart, fragmentRange ? fragmentRange.start.translate(0, -1) : linkEnd)),
@@ -234,7 +235,7 @@ const definitionPattern = /^([\t ]*\[(?!\^)((?:\\\]|[^\]])+)\]:\s*)([^<]\S*|<[^>
const inlineCodePattern = /(?:^|[^`])(`+)(?:.+?|.*?(?:(?:\r?\n).+?)*?)(?:\r?\n)?\1(?:$|[^`])/gm;
class NoLinkRanges {
public static async compute(tokenizer: IMdParser, document: SkinnyTextDocument): Promise<NoLinkRanges> {
public static async compute(tokenizer: IMdParser, document: ITextDocument): Promise<NoLinkRanges> {
const tokens = await tokenizer.tokenize(document);
const multiline = tokens.filter(t => (t.type === 'code_block' || t.type === 'fence' || t.type === 'html_block') && !!t.map).map(t => t.map) as [number, number][];
@@ -274,7 +275,7 @@ export class MdLinkComputer {
private readonly tokenizer: IMdParser,
) { }
public async getAllLinks(document: SkinnyTextDocument, token: vscode.CancellationToken): Promise<MdLink[]> {
public async getAllLinks(document: ITextDocument, token: vscode.CancellationToken): Promise<MdLink[]> {
const noLinkRanges = await NoLinkRanges.compute(this.tokenizer, document);
if (token.isCancellationRequested) {
return [];
@@ -288,7 +289,7 @@ export class MdLinkComputer {
]);
}
private *getInlineLinks(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
private *getInlineLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
const text = document.getText();
for (const match of text.matchAll(linkPattern)) {
const matchLinkData = extractDocumentLink(document, match[1], match[2], match.index);
@@ -306,7 +307,7 @@ export class MdLinkComputer {
}
}
private * getAutoLinks(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
private * getAutoLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
const text = document.getText();
for (const match of text.matchAll(autoLinkPattern)) {
@@ -334,7 +335,7 @@ export class MdLinkComputer {
}
}
private *getReferenceLinks(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
private *getReferenceLinks(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLink> {
const text = document.getText();
for (const match of text.matchAll(referenceLinkPattern)) {
let linkStart: vscode.Position;
@@ -382,7 +383,7 @@ export class MdLinkComputer {
}
}
private *getLinkDefinitions(document: SkinnyTextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLinkDefinition> {
private *getLinkDefinitions(document: ITextDocument, noLinkRanges: NoLinkRanges): Iterable<MdLinkDefinition> {
const text = document.getText();
for (const match of text.matchAll(definitionPattern)) {
const pre = match[1];
@@ -443,12 +444,12 @@ export class MdLinkProvider extends Disposable {
constructor(
tokenizer: IMdParser,
workspaceContents: MdWorkspaceContents,
workspace: IMdWorkspace,
logger: ILogger,
) {
super();
this.linkComputer = new MdLinkComputer(tokenizer);
this._linkCache = this._register(new MdDocumentInfoCache(workspaceContents, async doc => {
this._linkCache = this._register(new MdDocumentInfoCache(workspace, async doc => {
logger.verbose('LinkProvider', `compute - ${doc.uri}`);
const links = await this.linkComputer.getAllLinks(doc, noopToken);
@@ -459,7 +460,7 @@ export class MdLinkProvider extends Disposable {
}));
}
public async getLinks(document: SkinnyTextDocument): Promise<MdDocumentLinks> {
public async getLinks(document: ITextDocument): Promise<MdDocumentLinks> {
return this._linkCache.getForDocument(document);
}
}
@@ -491,7 +492,7 @@ export class MdVsCodeLinkProvider implements vscode.DocumentLinkProvider {
) { }
public async provideDocumentLinks(
document: SkinnyTextDocument,
document: ITextDocument,
token: vscode.CancellationToken
): Promise<vscode.DocumentLink[]> {
const { links, definitions } = await this._linkProvider.getLinks(document);

View File

@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import { ILogger } from '../logging';
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
import { SkinnyTextDocument } from '../workspaceContents';
import { ITextDocument } from '../types/textDocument';
interface MarkdownSymbol {
readonly level: number;
@@ -21,13 +21,13 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
private readonly logger: ILogger,
) { }
public async provideDocumentSymbolInformation(document: SkinnyTextDocument): Promise<vscode.SymbolInformation[]> {
public async provideDocumentSymbolInformation(document: ITextDocument): Promise<vscode.SymbolInformation[]> {
this.logger.verbose('DocumentSymbolProvider', `provideDocumentSymbolInformation - ${document.uri}`);
const toc = await this.tocProvider.getForDocument(document);
return toc.entries.map(entry => this.toSymbolInformation(entry));
}
public async provideDocumentSymbols(document: SkinnyTextDocument): Promise<vscode.DocumentSymbol[]> {
public async provideDocumentSymbols(document: ITextDocument): Promise<vscode.DocumentSymbol[]> {
const toc = await this.tocProvider.getForDocument(document);
const root: MarkdownSymbol = {
level: -Infinity,

View File

@@ -7,7 +7,7 @@ import type Token = require('markdown-it/lib/token');
import * as vscode from 'vscode';
import { IMdParser } from '../markdownEngine';
import { MdTableOfContentsProvider } from '../tableOfContents';
import { SkinnyTextDocument } from '../workspaceContents';
import { ITextDocument } from '../types/textDocument';
const rangeLimit = 5000;
@@ -23,7 +23,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
) { }
public async provideFoldingRanges(
document: SkinnyTextDocument,
document: ITextDocument,
_: vscode.FoldingContext,
_token: vscode.CancellationToken
): Promise<vscode.FoldingRange[]> {
@@ -35,7 +35,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
return foldables.flat().slice(0, rangeLimit);
}
private async getRegions(document: SkinnyTextDocument): Promise<vscode.FoldingRange[]> {
private async getRegions(document: ITextDocument): Promise<vscode.FoldingRange[]> {
const tokens = await this.parser.tokenize(document);
const regionMarkers = tokens.filter(isRegionMarker)
.map(token => ({ line: token.map[0], isStart: isStartRegion(token.content) }));
@@ -55,7 +55,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
.filter((region: vscode.FoldingRange | null): region is vscode.FoldingRange => !!region);
}
private async getHeaderFoldingRanges(document: SkinnyTextDocument): Promise<vscode.FoldingRange[]> {
private async getHeaderFoldingRanges(document: ITextDocument): Promise<vscode.FoldingRange[]> {
const toc = await this.tocProvide.getForDocument(document);
return toc.entries.map(entry => {
let endLine = entry.sectionLocation.range.end.line;
@@ -66,7 +66,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
});
}
private async getBlockFoldingRanges(document: SkinnyTextDocument): Promise<vscode.FoldingRange[]> {
private async getBlockFoldingRanges(document: ITextDocument): Promise<vscode.FoldingRange[]> {
const tokens = await this.parser.tokenize(document);
const multiLineListItems = tokens.filter(isFoldableToken);
return multiLineListItems.map(listItem => {

View File

@@ -7,8 +7,8 @@ import { dirname, resolve } from 'path';
import * as vscode from 'vscode';
import { IMdParser } from '../markdownEngine';
import { TableOfContents } from '../tableOfContents';
import { ITextDocument } from '../types/textDocument';
import { resolveUriToMarkdownFile } from '../util/openDocumentLink';
import { SkinnyTextDocument } from '../workspaceContents';
import { MdLinkProvider } from './documentLinks';
enum CompletionContextKind {
@@ -86,7 +86,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
private readonly linkProvider: MdLinkProvider,
) { }
public async provideCompletionItems(document: SkinnyTextDocument, position: vscode.Position, _token: vscode.CancellationToken, _context: vscode.CompletionContext): Promise<vscode.CompletionItem[]> {
public async provideCompletionItems(document: ITextDocument, position: vscode.Position, _token: vscode.CancellationToken, _context: vscode.CompletionContext): Promise<vscode.CompletionItem[]> {
if (!this.arePathSuggestionEnabled(document)) {
return [];
}
@@ -144,7 +144,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
}
}
private arePathSuggestionEnabled(document: SkinnyTextDocument): boolean {
private arePathSuggestionEnabled(document: ITextDocument): boolean {
const config = vscode.workspace.getConfiguration('markdown', document.uri);
return config.get('suggest.paths.enabled', true);
}
@@ -158,7 +158,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
/// [id]: |
private readonly definitionPattern = /^\s*\[[\w\-]+\]:\s*([^\s]*)$/m;
private getPathCompletionContext(document: SkinnyTextDocument, position: vscode.Position): CompletionContext | undefined {
private getPathCompletionContext(document: ITextDocument, position: vscode.Position): CompletionContext | undefined {
const line = document.lineAt(position.line).text;
const linePrefixText = line.slice(0, position.character);
@@ -231,7 +231,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
};
}
private async *provideReferenceSuggestions(document: SkinnyTextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable<vscode.CompletionItem> {
private async *provideReferenceSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable<vscode.CompletionItem> {
const insertionRange = new vscode.Range(context.linkTextStartPosition, position);
const replacementRange = new vscode.Range(insertionRange.start, position.translate({ characterDelta: context.linkSuffix.length }));
@@ -248,7 +248,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
}
}
private async *provideHeaderSuggestions(document: SkinnyTextDocument, position: vscode.Position, context: CompletionContext, insertionRange: vscode.Range): AsyncIterable<vscode.CompletionItem> {
private async *provideHeaderSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext, insertionRange: vscode.Range): AsyncIterable<vscode.CompletionItem> {
const toc = await TableOfContents.createForDocumentOrNotebook(this.parser, document);
for (const entry of toc.entries) {
const replacementRange = new vscode.Range(insertionRange.start, position.translate({ characterDelta: context.linkSuffix.length }));
@@ -263,7 +263,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
}
}
private async *providePathSuggestions(document: SkinnyTextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable<vscode.CompletionItem> {
private async *providePathSuggestions(document: ITextDocument, position: vscode.Position, context: CompletionContext): AsyncIterable<vscode.CompletionItem> {
const valueBeforeLastSlash = context.linkPrefix.substring(0, context.linkPrefix.lastIndexOf('/') + 1); // keep the last slash
const parentDir = this.resolveReference(document, valueBeforeLastSlash || '.');
@@ -304,7 +304,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
}
}
private resolveReference(document: SkinnyTextDocument, ref: string): vscode.Uri | undefined {
private resolveReference(document: ITextDocument, ref: string): vscode.Uri | undefined {
const docUri = this.getFileUriOfTextDocument(document);
if (ref.startsWith('/')) {
@@ -333,7 +333,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
}
}
private getFileUriOfTextDocument(document: SkinnyTextDocument) {
private getFileUriOfTextDocument(document: ITextDocument) {
if (document.uri.scheme === 'vscode-notebook-cell') {
const notebook = vscode.workspace.notebookDocuments
.find(notebook => notebook.getCells().some(cell => cell.document === document));

View File

@@ -7,11 +7,12 @@ import * as uri from 'vscode-uri';
import { ILogger } from '../logging';
import { IMdParser } from '../markdownEngine';
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
import { ITextDocument } from '../types/textDocument';
import { noopToken } from '../util/cancellation';
import { Disposable } from '../util/dispose';
import { looksLikeMarkdownPath } from '../util/file';
import { MdWorkspaceInfoCache } from '../util/workspaceCache';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { IMdWorkspace } from '../workspace';
import { InternalHref, MdLink, MdLinkComputer } from './documentLinks';
@@ -70,17 +71,17 @@ export class MdReferencesProvider extends Disposable {
public constructor(
private readonly parser: IMdParser,
private readonly workspaceContents: MdWorkspaceContents,
private readonly workspace: IMdWorkspace,
private readonly tocProvider: MdTableOfContentsProvider,
private readonly logger: ILogger,
) {
super();
this._linkComputer = new MdLinkComputer(parser);
this._linkCache = this._register(new MdWorkspaceInfoCache(workspaceContents, doc => this._linkComputer.getAllLinks(doc, noopToken)));
this._linkCache = this._register(new MdWorkspaceInfoCache(workspace, doc => this._linkComputer.getAllLinks(doc, noopToken)));
}
public async getReferencesAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
public async getReferencesAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
this.logger.verbose('ReferencesProvider', `getReferencesAtPosition: ${document.uri}`);
const toc = await this.tocProvider.getForDocument(document);
@@ -103,7 +104,7 @@ export class MdReferencesProvider extends Disposable {
return Array.from(this.findAllLinksToFile(resource, allLinksInWorkspace, undefined));
}
private async getReferencesToHeader(document: SkinnyTextDocument, header: TocEntry): Promise<MdReference[]> {
private async getReferencesToHeader(document: ITextDocument, header: TocEntry): Promise<MdReference[]> {
const links = (await this._linkCache.values()).flat();
const references: MdReference[] = [];
@@ -135,7 +136,7 @@ export class MdReferencesProvider extends Disposable {
return references;
}
private async getReferencesToLinkAtPosition(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
private async getReferencesToLinkAtPosition(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
const docLinks = await this._linkComputer.getAllLinks(document, token);
for (const link of docLinks) {
@@ -184,7 +185,7 @@ export class MdReferencesProvider extends Disposable {
return references;
}
const resolvedResource = await tryResolveLinkPath(sourceLink.href.path, this.workspaceContents);
const resolvedResource = await tryResolveLinkPath(sourceLink.href.path, this.workspace);
if (token.isCancellationRequested) {
return [];
}
@@ -229,7 +230,7 @@ export class MdReferencesProvider extends Disposable {
}
private isMarkdownPath(resolvedHrefPath: vscode.Uri) {
return this.workspaceContents.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
return this.workspace.hasMarkdownDocument(resolvedHrefPath) || looksLikeMarkdownPath(resolvedHrefPath);
}
private looksLikeLinkToDoc(href: InternalHref, targetDoc: vscode.Uri) {
@@ -306,7 +307,7 @@ export class MdVsCodeReferencesProvider implements vscode.ReferenceProvider {
private readonly referencesProvider: MdReferencesProvider
) { }
async provideReferences(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[]> {
async provideReferences(document: ITextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[]> {
const allRefs = await this.referencesProvider.getReferencesAtPosition(document, position, token);
return allRefs
.filter(ref => context.includeDeclaration || !ref.isDefinition)
@@ -321,15 +322,15 @@ export function registerReferencesSupport(
return vscode.languages.registerReferenceProvider(selector, new MdVsCodeReferencesProvider(referencesProvider));
}
export async function tryResolveLinkPath(originalUri: vscode.Uri, workspaceContents: MdWorkspaceContents): Promise<vscode.Uri | undefined> {
if (await workspaceContents.pathExists(originalUri)) {
export async function tryResolveLinkPath(originalUri: vscode.Uri, workspace: IMdWorkspace): Promise<vscode.Uri | undefined> {
if (await workspace.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(originalUri) === '') {
const dotMdResource = originalUri.with({ path: originalUri.path + '.md' });
if (await workspaceContents.pathExists(dotMdResource)) {
if (await workspace.pathExists(dotMdResource)) {
return dotMdResource;
}
}

View File

@@ -7,9 +7,10 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as URI from 'vscode-uri';
import { Slugifier } from '../slugify';
import { ITextDocument } from '../types/textDocument';
import { Disposable } from '../util/dispose';
import { resolveDocumentLink } from '../util/openDocumentLink';
import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents';
import { IMdWorkspace } from '../workspace';
import { InternalHref } from './documentLinks';
import { MdHeaderReference, MdLinkReference, MdReference, MdReferencesProvider, tryResolveLinkPath } from './references';
@@ -58,14 +59,14 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
private readonly renameNotSupportedText = localize('invalidRenameLocation', "Rename not supported at location");
public constructor(
private readonly workspaceContents: MdWorkspaceContents,
private readonly workspace: IMdWorkspace,
private readonly referencesProvider: MdReferencesProvider,
private readonly slugifier: Slugifier,
) {
super();
}
public async prepareRename(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<undefined | { readonly range: vscode.Range; readonly placeholder: string }> {
public async prepareRename(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<undefined | { readonly range: vscode.Range; readonly placeholder: string }> {
const allRefsInfo = await this.getAllReferences(document, position, token);
if (token.isCancellationRequested) {
return undefined;
@@ -122,11 +123,11 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
return references.find(ref => ref.isDefinition && ref.kind === 'header') as MdHeaderReference | undefined;
}
public async provideRenameEdits(document: SkinnyTextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise<vscode.WorkspaceEdit | undefined> {
public async provideRenameEdits(document: ITextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise<vscode.WorkspaceEdit | undefined> {
return (await this.provideRenameEditsImpl(document, position, newName, token))?.edit;
}
public async provideRenameEditsImpl(document: SkinnyTextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise<MdWorkspaceEdit | undefined> {
public async provideRenameEditsImpl(document: ITextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): Promise<MdWorkspaceEdit | undefined> {
const allRefsInfo = await this.getAllReferences(document, position, token);
if (token.isCancellationRequested || !allRefsInfo || !allRefsInfo.references.length) {
return undefined;
@@ -153,7 +154,7 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
const edit = new vscode.WorkspaceEdit();
const fileRenames: MdFileRenameEdit[] = [];
const targetUri = await tryResolveLinkPath(triggerHref.path, this.workspaceContents) ?? triggerHref.path;
const targetUri = await tryResolveLinkPath(triggerHref.path, this.workspace) ?? triggerHref.path;
const rawNewFilePath = resolveDocumentLink(newName, triggerDocument);
let resolvedNewFilePath = rawNewFilePath;
@@ -168,7 +169,7 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
}
// First rename the file
if (await this.workspaceContents.pathExists(targetUri)) {
if (await this.workspace.pathExists(targetUri)) {
fileRenames.push({ from: targetUri, to: resolvedNewFilePath });
edit.renameFile(targetUri, resolvedNewFilePath);
}
@@ -241,7 +242,7 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
return { edit };
}
private async getAllReferences(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReferencesResponse | undefined> {
private async getAllReferences(document: ITextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReferencesResponse | undefined> {
const version = document.version;
if (this.cachedRefs
@@ -272,9 +273,9 @@ export class MdVsCodeRenameProvider extends Disposable implements vscode.RenameP
export function registerRenameSupport(
selector: vscode.DocumentSelector,
workspaceContents: MdWorkspaceContents,
workspace: IMdWorkspace,
referencesProvider: MdReferencesProvider,
slugifier: Slugifier,
): vscode.Disposable {
return vscode.languages.registerRenameProvider(selector, new MdVsCodeRenameProvider(workspaceContents, referencesProvider, slugifier));
return vscode.languages.registerRenameProvider(selector, new MdVsCodeRenameProvider(workspace, referencesProvider, slugifier));
}

View File

@@ -6,7 +6,7 @@ import Token = require('markdown-it/lib/token');
import * as vscode from 'vscode';
import { IMdParser } from '../markdownEngine';
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
import { SkinnyTextDocument } from '../workspaceContents';
import { ITextDocument } from '../types/textDocument';
interface MarkdownItTokenWithMap extends Token {
map: [number, number];
@@ -19,24 +19,24 @@ export class MdSmartSelect implements vscode.SelectionRangeProvider {
private readonly tocProvider: MdTableOfContentsProvider,
) { }
public async provideSelectionRanges(document: SkinnyTextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise<vscode.SelectionRange[] | undefined> {
public async provideSelectionRanges(document: ITextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise<vscode.SelectionRange[] | undefined> {
const promises = await Promise.all(positions.map((position) => {
return this.provideSelectionRange(document, position, _token);
}));
return promises.filter(item => item !== undefined) as vscode.SelectionRange[];
}
private async provideSelectionRange(document: SkinnyTextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.SelectionRange | undefined> {
private async provideSelectionRange(document: ITextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.SelectionRange | undefined> {
const headerRange = await this.getHeaderSelectionRange(document, position);
const blockRange = await this.getBlockSelectionRange(document, position, headerRange);
const inlineRange = await this.getInlineSelectionRange(document, position, blockRange);
return inlineRange || blockRange || headerRange;
}
private async getInlineSelectionRange(document: SkinnyTextDocument, position: vscode.Position, blockRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
private async getInlineSelectionRange(document: ITextDocument, position: vscode.Position, blockRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
return createInlineRange(document, position, blockRange);
}
private async getBlockSelectionRange(document: SkinnyTextDocument, position: vscode.Position, headerRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
private async getBlockSelectionRange(document: ITextDocument, position: vscode.Position, headerRange?: vscode.SelectionRange): Promise<vscode.SelectionRange | undefined> {
const tokens = await this.parser.tokenize(document);
const blockTokens = getBlockTokensForPosition(tokens, position, headerRange);
@@ -52,7 +52,7 @@ export class MdSmartSelect implements vscode.SelectionRangeProvider {
return currentRange;
}
private async getHeaderSelectionRange(document: SkinnyTextDocument, position: vscode.Position): Promise<vscode.SelectionRange | undefined> {
private async getHeaderSelectionRange(document: ITextDocument, position: vscode.Position): Promise<vscode.SelectionRange | undefined> {
const toc = await this.tocProvider.getForDocument(document);
const headerInfo = getHeadersForPosition(toc.entries, position);
@@ -107,7 +107,7 @@ function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, p
return sortedTokens;
}
function createBlockRange(block: MarkdownItTokenWithMap, document: SkinnyTextDocument, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
if (block.type === 'fence') {
return createFencedRange(block, cursorLine, document, parent);
} else {
@@ -129,7 +129,7 @@ function createBlockRange(block: MarkdownItTokenWithMap, document: SkinnyTextDoc
}
}
function createInlineRange(document: SkinnyTextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
function createInlineRange(document: ITextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
const lineText = document.lineAt(cursorPosition.line).text;
const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent);
const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent);
@@ -146,7 +146,7 @@ function createInlineRange(document: SkinnyTextDocument, cursorPosition: vscode.
return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection;
}
function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, document: SkinnyTextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, document: ITextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange {
const startLine = token.map[0];
const endLine = token.map[1] - 1;
const onFenceLine = cursorLine === startLine || cursorLine === endLine;
@@ -236,7 +236,7 @@ function isBlockElement(token: Token): boolean {
return !['list_item_close', 'paragraph_close', 'bullet_list_close', 'inline', 'heading_close', 'heading_open'].includes(token.type);
}
function getFirstChildHeader(document: SkinnyTextDocument, header?: TocEntry, toc?: readonly TocEntry[]): vscode.Position | undefined {
function getFirstChildHeader(document: ITextDocument, header?: TocEntry, toc?: readonly TocEntry[]): vscode.Position | undefined {
let childRange: vscode.Position | undefined;
if (header && toc) {
const children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line);

View File

@@ -5,9 +5,9 @@
import * as vscode from 'vscode';
import { Disposable } from '../util/dispose';
import { MdWorkspaceContents } from '../workspaceContents';
import { MdDocumentSymbolProvider } from './documentSymbols';
import { MdWorkspaceInfoCache } from '../util/workspaceCache';
import { IMdWorkspace } from '../workspace';
import { MdDocumentSymbolProvider } from './documentSymbols';
export class MdWorkspaceSymbolProvider extends Disposable implements vscode.WorkspaceSymbolProvider {
@@ -15,11 +15,11 @@ export class MdWorkspaceSymbolProvider extends Disposable implements vscode.Work
public constructor(
symbolProvider: MdDocumentSymbolProvider,
workspaceContents: MdWorkspaceContents,
workspace: IMdWorkspace,
) {
super();
this._cache = this._register(new MdWorkspaceInfoCache(workspaceContents, doc => symbolProvider.provideDocumentSymbolInformation(doc)));
this._cache = this._register(new MdWorkspaceInfoCache(workspace, doc => symbolProvider.provideDocumentSymbolInformation(doc)));
}
public async provideWorkspaceSymbols(query: string): Promise<vscode.SymbolInformation[]> {
@@ -29,8 +29,8 @@ export class MdWorkspaceSymbolProvider extends Disposable implements vscode.Work
}
export function registerWorkspaceSymbolSupport(
workspaceContents: MdWorkspaceContents,
workspace: IMdWorkspace,
symbolProvider: MdDocumentSymbolProvider,
): vscode.Disposable {
return vscode.languages.registerWorkspaceSymbolProvider(new MdWorkspaceSymbolProvider(symbolProvider, workspaceContents));
return vscode.languages.registerWorkspaceSymbolProvider(new MdWorkspaceSymbolProvider(symbolProvider, workspace));
}