Allow passing in custom workspace/parser to markdown server (#160429)

For #159805

This splits the markdown server into two main functions:

- `startVsCodeServer` which assumes the client can implement all the functionality of VS Code. It is not specific to VS Code however, the client just need to implement the custom messages that VS Code does

- `startServer` which lets you pass in your own implementation of the parser and workspace. A consumer of the server can then use this to have their own custom server implementation, which might use normal node apis to read files
This commit is contained in:
Matt Bierner 2022-09-08 11:35:42 -07:00 committed by GitHub
parent a844e8a922
commit 5d5ea15a65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 26 deletions

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser';
import { startServer } from '../server';
import { startVsCodeServer } from '../server';
declare let self: any;
@ -13,4 +13,4 @@ const messageWriter = new BrowserMessageWriter(self);
const connection = createConnection(messageReader, messageWriter);
startServer(connection);
startVsCodeServer(connection);

View file

@ -9,7 +9,6 @@ import { disposeAll } from 'vscode-markdown-languageservice/out/util/dispose';
import { Disposable } from 'vscode-notebook-renderer/events';
import { URI } from 'vscode-uri';
import { ConfigurationManager, ValidateEnabled } from '../configuration';
import { VsCodeClientWorkspace } from '../workspace';
const defaultDiagnosticOptions: md.DiagnosticOptions = {
validateFileLinks: md.DiagnosticLevel.ignore,
@ -45,7 +44,7 @@ function getDiagnosticsOptions(config: ConfigurationManager): md.DiagnosticOptio
export function registerValidateSupport(
connection: Connection,
workspace: VsCodeClientWorkspace,
workspace: md.IWorkspace,
ls: md.IMdLanguageService,
config: ConfigurationManager,
logger: md.ILogger,

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Connection, createConnection } from 'vscode-languageserver/node';
import { startServer } from '../server';
import { startVsCodeServer } from '../server';
// Create a connection for the server.
const connection: Connection = createConnection();
@ -16,4 +16,4 @@ process.on('unhandledRejection', (e: any) => {
connection.console.error(`Unhandled exception ${e}`);
});
startServer(connection);
startVsCodeServer(connection);

View file

@ -22,41 +22,65 @@ const localize = nls.loadMessageBundle();
interface MdServerInitializationOptions extends LsConfiguration { }
const organizeLinkDefKind = 'source.organizeLinkDefinitions';
export async function startServer(connection: Connection) {
export async function startVsCodeServer(connection: Connection) {
const logger = new LogFunctionLogger(connection.console.log.bind(connection.console));
const parser = new class implements md.IMdParser {
slugifier = md.githubSlugifier;
tokenize(document: md.ITextDocument): Promise<md.Token[]> {
return connection.sendRequest(protocol.parse, { uri: document.uri.toString() });
}
};
const documents = new TextDocuments(TextDocument);
const notebooks = new NotebookDocuments(documents);
const configurationManager = new ConfigurationManager(connection);
const workspaceFactory: WorkspaceFactory = ({ connection, config, workspaceFolders }) => {
const workspace = new VsCodeClientWorkspace(connection, config, documents, notebooks, logger);
workspace.workspaceFolders = (workspaceFolders ?? []).map(x => URI.parse(x.uri));
return workspace;
};
return startServer(connection, { documents, notebooks, logger, parser, workspaceFactory });
}
type WorkspaceFactory = (config: {
connection: Connection;
config: LsConfiguration;
workspaceFolders?: lsp.WorkspaceFolder[] | null;
}) => md.IWorkspace;
export async function startServer(connection: Connection, serverConfig: {
documents: TextDocuments<md.ITextDocument>;
notebooks?: NotebookDocuments<md.ITextDocument>;
logger: md.ILogger;
parser: md.IMdParser;
workspaceFactory: WorkspaceFactory;
}) {
const { documents, notebooks } = serverConfig;
let mdLs: md.IMdLanguageService | undefined;
let workspace: VsCodeClientWorkspace | undefined;
connection.onInitialize((params: InitializeParams): InitializeResult => {
const parser = new class implements md.IMdParser {
slugifier = md.githubSlugifier;
async tokenize(document: md.ITextDocument): Promise<md.Token[]> {
return await connection.sendRequest(protocol.parse, { uri: document.uri.toString() });
}
};
const initOptions = params.initializationOptions as MdServerInitializationOptions | undefined;
const config = getLsConfiguration(initOptions ?? {});
const logger = new LogFunctionLogger(connection.console.log.bind(connection.console));
workspace = new VsCodeClientWorkspace(connection, config, documents, notebooks, logger);
const configurationManager = new ConfigurationManager(connection);
const workspace = serverConfig.workspaceFactory({ connection, config, workspaceFolders: params.workspaceFolders });
mdLs = md.createLanguageService({
workspace,
parser,
logger,
parser: serverConfig.parser,
logger: serverConfig.logger,
markdownFileExtensions: config.markdownFileExtensions,
excludePaths: config.excludePaths,
});
registerCompletionsSupport(connection, documents, mdLs, configurationManager);
registerValidateSupport(connection, workspace, mdLs, configurationManager, logger);
registerValidateSupport(connection, workspace, mdLs, configurationManager, serverConfig.logger);
workspace.workspaceFolders = (params.workspaceFolders ?? []).map(x => URI.parse(x.uri));
return {
capabilities: {
diagnosticProvider: {
@ -212,14 +236,14 @@ export async function startServer(connection: Connection) {
}));
documents.listen(connection);
notebooks.listen(connection);
notebooks?.listen(connection);
connection.listen();
}
function registerCompletionsSupport(
connection: Connection,
documents: TextDocuments<TextDocument>,
documents: TextDocuments<md.ITextDocument>,
ls: md.IMdLanguageService,
config: ConfigurationManager,
): IDisposable {

View file

@ -8,7 +8,7 @@ import { URI, Utils } from 'vscode-uri';
import { LsConfiguration } from '../config';
export function looksLikeMarkdownPath(config: LsConfiguration, resolvedHrefPath: URI) {
return config.markdownFileExtensions.includes(Utils.extname(URI.from(resolvedHrefPath)).toLowerCase().replace('.', ''));
return config.markdownFileExtensions.includes(Utils.extname(resolvedHrefPath).toLowerCase().replace('.', ''));
}
export function isMarkdownFile(document: TextDocument) {