Change:
<!-- Do Not Delete This! featurerequesttemplate --<!-- Please read our Rules of Conduct: --<!-- Please search existing issues to avoid creating duplicates. --<!-- Describe the feature you'd like. --I was testing the server on neovim. I noticed the requires a lot from the client. Would it be possible to bundle default implementations of and all other custom requests to make the server self-contained?
I'd take a PR that does this (likely using service injection) but the current design is deliberate lets the client bring their own parser versionThe custom file messages means the server is not restricted to working with local files. Ideally the LSP would also include this functionality but right now it does not
I can make a PR. Wouldn't it be simpler to add a setting for a custom tokenizer? Then call with or make a request?
makes this easier to use the server as a library. For a client that doesn't want to implement the custom messages we use, you'd instead want to use the new version of which lets you pass in your own parser and workspace implementations

Discussion:
*--------------------------------------------------------------------------------------------*/ import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser'; <del> import { startServer } from '../server'; </del> <ins> import { startVsCodeServer } from '../server'; </ins> declare let self: any;

const connection = createConnection(messageReader, messageWriter); <del> startServer(connection); </del> <ins> startVsCodeServer(connection); </ins>

import { Disposable } from 'vscode-notebook-renderer/events'; import { URI } from 'vscode-uri'; import { ConfigurationManager, ValidateEnabled } from '../configuration'; <del> import { VsCodeClientWorkspace } from '../workspace'; </del> const defaultDiagnosticOptions: md.DiagnosticOptions = { validateFileLinks: md.DiagnosticLevel.ignore,

export function registerValidateSupport( connection: Connection, <del> workspace: VsCodeClientWorkspace, </del> <ins> workspace: md.IWorkspace, </ins> ls: md.IMdLanguageService, config: ConfigurationManager, logger: md.ILogger,

*--------------------------------------------------------------------------------------------*/ import { Connection, createConnection } from 'vscode-languageserver/node'; <del> import { startServer } from '../server'; </del> <ins> import { startVsCodeServer } from '../server'; </ins> // Create a connection for the server. const connection: Connection = createConnection();

connection.console.error(`Unhandled exception ${e}`); }); <del> startServer(connection); </del> <ins> startVsCodeServer(connection); </ins>

interface MdServerInitializationOptions extends LsConfiguration { } const organizeLinkDefKind = 'source.organizeLinkDefinitions'; <del> export async function startServer(connection: Connection) { </del> <ins> 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() }); } }; </ins> const documents = new TextDocuments(TextDocument); const notebooks = new NotebookDocuments(documents); <del> const configurationManager = new ConfigurationManager(connection); </del> <ins> 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; }; </ins> <del> let mdLs: md.IMdLanguageService | undefined; let workspace: VsCodeClientWorkspace | undefined; </del> <ins> return startServer(connection, { documents, notebooks, logger, parser, workspaceFactory }); } </ins> <del> connection.onInitialize((params: InitializeParams): InitializeResult => { const parser = new class implements md.IMdParser { slugifier = md.githubSlugifier; </del> <ins> 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; </ins> <del> async tokenize(document: md.ITextDocument): Promise<md.Token[]> { return await connection.sendRequest(protocol.parse, { uri: document.uri.toString() }); } }; </del> <ins> let mdLs: md.IMdLanguageService | undefined; connection.onInitialize((params: InitializeParams): InitializeResult => { </ins> const initOptions = params.initializationOptions as MdServerInitializationOptions | undefined; const config = getLsConfiguration(initOptions ?? {}); <del> const logger = new LogFunctionLogger(connection.console.log.bind(connection.console)); workspace = new VsCodeClientWorkspace(connection, config, documents, notebooks, logger); </del> <ins> const configurationManager = new ConfigurationManager(connection); const workspace = serverConfig.workspaceFactory({ connection, config, workspaceFolders: params.workspaceFolders }); </ins> mdLs = md.createLanguageService({ workspace, <del> parser, logger, </del> <ins> parser: serverConfig.parser, logger: serverConfig.logger, </ins> markdownFileExtensions: config.markdownFileExtensions, excludePaths: config.excludePaths, }); registerCompletionsSupport(connection, documents, mdLs, configurationManager); <del> registerValidateSupport(connection, workspace, mdLs, configurationManager, logger); </del> <ins> registerValidateSupport(connection, workspace, mdLs, configurationManager, serverConfig.logger); </ins> <del> workspace.workspaceFolders = (params.workspaceFolders ?? []).map(x => URI.parse(x.uri)); </del> return { capabilities: { diagnosticProvider: {

})); documents.listen(connection); <del> notebooks.listen(connection); </del> <ins> notebooks?.listen(connection); </ins> connection.listen(); } function registerCompletionsSupport( connection: Connection, <del> documents: TextDocuments<TextDocument>, </del> <ins> documents: TextDocuments<md.ITextDocument>, </ins> ls: md.IMdLanguageService, config: ConfigurationManager, ): IDisposable {

import { LsConfiguration } from '../config'; export function looksLikeMarkdownPath(config: LsConfiguration, resolvedHrefPath: URI) { <del> return config.markdownFileExtensions.includes(Utils.extname(URI.from(resolvedHrefPath)).toLowerCase().replace('.', '')); </del> <ins> return config.markdownFileExtensions.includes(Utils.extname(resolvedHrefPath).toLowerCase().replace('.', '')); </ins> } export function isMarkdownFile(document: TextDocument) {