mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 12:33:35 +01:00
Move md path completions and document links to language server (#155100)
This commit is contained in:
@@ -6,10 +6,12 @@
|
||||
import { RequestType } from 'vscode-languageserver';
|
||||
import * as md from 'vscode-markdown-languageservice';
|
||||
|
||||
declare const TextDecoder: any;
|
||||
|
||||
export const parseRequestType: RequestType<{ uri: string }, md.Token[], any> = new RequestType('markdown/parse');
|
||||
|
||||
export const readFileRequestType: RequestType<{ uri: string }, number[], any> = new RequestType('markdown/readFile');
|
||||
|
||||
export const statFileRequestType: RequestType<{ uri: string }, md.FileStat | undefined, any> = new RequestType('markdown/statFile');
|
||||
|
||||
export const readDirectoryRequestType: RequestType<{ uri: string }, [string, md.FileStat][], any> = new RequestType('markdown/readDirectory');
|
||||
|
||||
export const findFilesRequestTypes: RequestType<{}, string[], any> = new RequestType('markdown/findFiles');
|
||||
|
||||
@@ -3,27 +3,35 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Connection, InitializeParams, InitializeResult, TextDocuments } from 'vscode-languageserver';
|
||||
import { Connection, InitializeParams, InitializeResult, NotebookDocuments, TextDocuments } from 'vscode-languageserver';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import * as lsp from 'vscode-languageserver-types';
|
||||
import * as md from 'vscode-markdown-languageservice';
|
||||
import { URI } from 'vscode-uri';
|
||||
import { LogFunctionLogger } from './logging';
|
||||
import { parseRequestType } from './protocol';
|
||||
import { VsCodeClientWorkspace } from './workspace';
|
||||
|
||||
declare const TextDecoder: any;
|
||||
|
||||
export function startServer(connection: Connection) {
|
||||
export async function startServer(connection: Connection) {
|
||||
const documents = new TextDocuments(TextDocument);
|
||||
documents.listen(connection);
|
||||
const notebooks = new NotebookDocuments(documents);
|
||||
|
||||
connection.onInitialize((_params: InitializeParams): InitializeResult => {
|
||||
connection.onInitialize((params: InitializeParams): InitializeResult => {
|
||||
workspace.workspaceFolders = (params.workspaceFolders ?? []).map(x => URI.parse(x.uri));
|
||||
return {
|
||||
capabilities: {
|
||||
documentLinkProvider: { resolveProvider: true },
|
||||
documentSymbolProvider: true,
|
||||
completionProvider: { triggerCharacters: ['.', '/', '#'] },
|
||||
foldingRangeProvider: true,
|
||||
selectionRangeProvider: true,
|
||||
workspaceSymbolProvider: true,
|
||||
workspace: {
|
||||
workspaceFolders: {
|
||||
supported: true,
|
||||
changeNotifications: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -36,15 +44,36 @@ export function startServer(connection: Connection) {
|
||||
}
|
||||
};
|
||||
|
||||
const workspace = new VsCodeClientWorkspace(connection, documents);
|
||||
const workspace = new VsCodeClientWorkspace(connection, documents, notebooks);
|
||||
const logger = new LogFunctionLogger(connection.console.log.bind(connection.console));
|
||||
const provider = md.createLanguageService({ workspace, parser, logger });
|
||||
|
||||
connection.onDocumentLinks(async (params, token): Promise<lsp.DocumentLink[]> => {
|
||||
try {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return await provider.getDocumentLinks(document, token);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
connection.onDocumentLinkResolve(async (link, token): Promise<lsp.DocumentLink | undefined> => {
|
||||
try {
|
||||
return await provider.resolveDocumentLink(link, token);
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
connection.onDocumentSymbol(async (params, token): Promise<lsp.DocumentSymbol[]> => {
|
||||
try {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return await provider.provideDocumentSymbols(document, token);
|
||||
return await provider.getDocumentSymbols(document, token);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
@@ -56,7 +85,7 @@ export function startServer(connection: Connection) {
|
||||
try {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return await provider.provideFoldingRanges(document, token);
|
||||
return await provider.getFoldingRanges(document, token);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
@@ -68,7 +97,7 @@ export function startServer(connection: Connection) {
|
||||
try {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return await provider.provideSelectionRanges(document, params.positions, token);
|
||||
return await provider.getSelectionRanges(document, params.positions, token);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
@@ -78,13 +107,26 @@ export function startServer(connection: Connection) {
|
||||
|
||||
connection.onWorkspaceSymbol(async (params, token): Promise<lsp.WorkspaceSymbol[]> => {
|
||||
try {
|
||||
return await provider.provideWorkspaceSymbols(params.query, token);
|
||||
return await provider.getWorkspaceSymbols(params.query, token);
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
connection.onCompletion(async (params, token): Promise<lsp.CompletionItem[]> => {
|
||||
try {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
return await provider.getCompletionItems(document, params.position, params.context!, token);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
documents.listen(connection);
|
||||
notebooks.listen(connection);
|
||||
connection.listen();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const Schemes = Object.freeze({
|
||||
notebookCell: 'vscode-notebook-cell',
|
||||
});
|
||||
@@ -3,15 +3,17 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Connection, Emitter, FileChangeType, TextDocuments } from 'vscode-languageserver';
|
||||
import { Connection, Emitter, FileChangeType, NotebookDocuments, TextDocuments } from 'vscode-languageserver';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import * as md from 'vscode-markdown-languageservice';
|
||||
import { ContainingDocumentContext } from 'vscode-markdown-languageservice/out/workspace';
|
||||
import { URI } from 'vscode-uri';
|
||||
import * as protocol from './protocol';
|
||||
import { coalesce } from './util/arrays';
|
||||
import { isMarkdownDocument, looksLikeMarkdownPath } from './util/file';
|
||||
import { Limiter } from './util/limiter';
|
||||
import { ResourceMap } from './util/resourceMap';
|
||||
import { Schemes } from './util/schemes';
|
||||
|
||||
declare const TextDecoder: any;
|
||||
|
||||
@@ -33,6 +35,7 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
constructor(
|
||||
private readonly connection: Connection,
|
||||
private readonly documents: TextDocuments<TextDocument>,
|
||||
private readonly notebooks: NotebookDocuments<TextDocument>,
|
||||
) {
|
||||
documents.onDidOpen(e => {
|
||||
this._documentCache.delete(URI.parse(e.document.uri));
|
||||
@@ -57,14 +60,14 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
switch (change.type) {
|
||||
case FileChangeType.Changed: {
|
||||
this._documentCache.delete(resource);
|
||||
const document = await this.getOrLoadMarkdownDocument(resource);
|
||||
const document = await this.openMarkdownDocument(resource);
|
||||
if (document) {
|
||||
this._onDidChangeMarkdownDocument.fire(document);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FileChangeType.Created: {
|
||||
const document = await this.getOrLoadMarkdownDocument(resource);
|
||||
const document = await this.openMarkdownDocument(resource);
|
||||
if (document) {
|
||||
this._onDidCreateMarkdownDocument.fire(document);
|
||||
}
|
||||
@@ -80,6 +83,22 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
});
|
||||
}
|
||||
|
||||
public listen() {
|
||||
this.connection.workspace.onDidChangeWorkspaceFolders(async () => {
|
||||
this.workspaceFolders = (await this.connection.workspace.getWorkspaceFolders() ?? []).map(x => URI.parse(x.uri));
|
||||
});
|
||||
}
|
||||
|
||||
private _workspaceFolders: readonly URI[] = [];
|
||||
|
||||
get workspaceFolders(): readonly URI[] {
|
||||
return this._workspaceFolders;
|
||||
}
|
||||
|
||||
set workspaceFolders(value: readonly URI[]) {
|
||||
this._workspaceFolders = value;
|
||||
}
|
||||
|
||||
async getAllMarkdownDocuments(): Promise<Iterable<md.ITextDocument>> {
|
||||
const maxConcurrent = 20;
|
||||
|
||||
@@ -91,7 +110,7 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
const onDiskResults = await Promise.all(resources.map(strResource => {
|
||||
return limiter.queue(async () => {
|
||||
const resource = URI.parse(strResource);
|
||||
const doc = await this.getOrLoadMarkdownDocument(resource);
|
||||
const doc = await this.openMarkdownDocument(resource);
|
||||
if (doc) {
|
||||
foundFiles.set(resource);
|
||||
}
|
||||
@@ -110,7 +129,7 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
return !!this.documents.get(resource.toString());
|
||||
}
|
||||
|
||||
async getOrLoadMarkdownDocument(resource: URI): Promise<md.ITextDocument | undefined> {
|
||||
async openMarkdownDocument(resource: URI): Promise<md.ITextDocument | undefined> {
|
||||
const existing = this._documentCache.get(resource);
|
||||
if (existing) {
|
||||
return existing;
|
||||
@@ -141,12 +160,25 @@ export class VsCodeClientWorkspace implements md.IWorkspace {
|
||||
}
|
||||
}
|
||||
|
||||
async pathExists(_resource: URI): Promise<boolean> {
|
||||
return false;
|
||||
stat(resource: URI): Promise<md.FileStat | undefined> {
|
||||
return this.connection.sendRequest(protocol.statFileRequestType, { uri: resource.toString() });
|
||||
}
|
||||
|
||||
async readDirectory(_resource: URI): Promise<[string, { isDir: boolean }][]> {
|
||||
return [];
|
||||
async readDirectory(resource: URI): Promise<[string, md.FileStat][]> {
|
||||
return this.connection.sendRequest(protocol.readDirectoryRequestType, { uri: resource.toString() });
|
||||
}
|
||||
|
||||
getContainingDocument(resource: URI): ContainingDocumentContext | undefined {
|
||||
if (resource.scheme === Schemes.notebookCell) {
|
||||
const nb = this.notebooks.findNotebookDocumentForCell(resource.toString());
|
||||
if (nb) {
|
||||
return {
|
||||
uri: URI.parse(nb.uri),
|
||||
children: nb.cells.map(cell => ({ uri: URI.parse(cell.document) })),
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isRelevantMarkdownDocument(doc: TextDocument) {
|
||||
|
||||
Reference in New Issue
Block a user