DenoでLSPサーバを実装しているお話
概要
追記
モチベーション
Import mapやリモートURL(https://deno.land/std@0.76.0/http/server.ts等)のサポートが欲しい
アイデア
code:deps.ts
import {
default as _ts,
LanguageServiceHost as _LanguageServiceHost,
LanguageService as _LanguageService,
CompilerOptions as _CompilerOptions,
export type LanguageServiceHost = _LanguageServiceHost;
export type LanguageService = _LanguageService;
export type CompilerOptions = _CompilerOptions;
export const ts = _ts;
code:host.ts
import { ts } from "./deps.ts";
import type { CompilerOptions, LanguageServiceHost } from "./deps.ts";
import { directoryExistsSync, existsSync, fileExistsSync } from "./fs.ts";
export function createServiceHost(
rootFileNames: string[],
options: CompilerOptions,
): LanguageServiceHost {
const files = rootFileNames.reduce((files, rootFileName) => {
return files;
return {
getScriptFileNames: () => rootFileNames,
getScriptVersion(fileName: string): string {
},
getScriptSnapshot(fileName: string) {
if (!existsSync(fileName)) {
return undefined;
}
return ts.ScriptSnapshot.fromString(Deno.readTextFileSync(fileName));
},
getCurrentDirectory: () => Deno.cwd(),
getCompilationSettings: () => options,
getDefaultLibFileName(options: CompilerOptions) {
return ts.getDefaultLibFilePath(options);
},
fileExists: fileExistsSync,
readFile(path) {
console.log(path);
return Deno.readTextFileSync(path);
},
readDirectory(path, extensions, exclude, include, depth) {
throw new Error("readDirectory(): unimplemented");
},
directoryExists: directoryExistsSync,
getDirectories(path: string): string[] {
const directories = [];
for (const entry of Deno.readDirSync(path)) {
// TODO isSymlink
if (entry.isDirectory) {
directories.push(entry.name);
}
}
return directories;
},
};
}
あとは、上記のLanguageServiceHostを使ってts.createLanguageServiceを呼べば実現できるはず🤔
code:language_service.ts
import { ts } from "./deps.ts";
import type { LanguageService, CompilerOptions } from "./deps.ts";
import { createServiceHost } from "./host.ts";
export async function createLanguageService(rootFileNames: string[], tsConfig: CompilerOptions): Promise<LanguageService> {
const host = createServiceHost(rootFileNames, tsConfig);
const languageService = ts.createLanguageService(host, ts.createDocumentRegistry());
return languageService;
}
参考情報
Language Server Protocol Specification - 3.15の日本語訳