如何创建集成 LSP 支持多语言的 Web 代码编辑器

这篇具有很好参考价值的文章主要介绍了如何创建集成 LSP 支持多语言的 Web 代码编辑器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

对于一个云开发平台来说,一个好的 Web IDE 能很大程度地提高用户的编码体验,而一个 Web IDE 的一个重要组成部分就是代码编辑器。

目前有着多款 web 上的代码编辑器可供选择,比如 AceCodeMirrorMonaco,这三款编辑器的比较在这篇文章中有着详细的介绍,在此就不作过多赘述。这篇文章我们选择 Monaco Editor 来对 LSP 进行集成,从而在理论上能够支持所有的编程语言。

原文链接:https://forum.laf.run/d/1027

什么是 LSP

如何创建集成 LSP 支持多语言的 Web 代码编辑器

LSP(Language Server Protocol),也就是语言服务协议,更具体更通俗地说就是定义了在代码编辑器和语言服务器之间的一套规范,从而让原本

m 个编辑器与 n 个编程语言之间的对应关系

变为

m 个编辑器与 LSP 的关系和 n 个编程语言与 LSP 之间的关系,

从而将开发的复杂度由 m*n 降到了 m+n

除了对编辑器开发者和编程语言开发者友好,对我们这种尝试让一个编辑器支持多种语言的开发者也更是友好,有 vscode 这样的编辑器珠玉在前,便能轻松地根据 vscode 的设计思路实现我们的需求。

预览

在这篇文章中,我们会开发一个最小最轻量的编辑器 Demo 作为演示,架构非常简单,就是前端创建一个 Monaco Editor,后端创建一个语言服务器,二者之间通过 vscode-ws-jsonrpcWebSocket 服务进行传输,实际实现的 WebPython 编辑器如下:

如何创建集成 LSP 支持多语言的 Web 代码编辑器

Server 端开发

Web 端能接入语言服务前,我们得先在服务端运行一个语言服务,https://langserver.org/ 这个网站收录了许多语言服务的实现,

如何创建集成 LSP 支持多语言的 Web 代码编辑器

这里我们选择微软官方维护的 pyright 提供语言服务

首先创建 Express 服务器,配置静态文件服务,使用 fileURLToPathdirname 来获取当前文件的路径,并将服务设置在 30000 端口

const app = express();
const __filename = fileURLToPath(import.meta.url);
const dir = dirname(__filename);
app.use(express.static(dir));
const server = app.listen(30000);

然后我们需要创建一个 WebSocket Server,注意这里的 noServer 参数,如果没有指定 noServer,那么 WebSocketServer 会自动创建一个 http server 来处理浏览器的 HTTP 请求到 WebSocket 请求的 upgrade。

const wss = new WebSocketServer({
	noServer: true,
});

而这里我们需要创建自己的 HTTP 服务器,并手动处理浏览器的 upgrade 请求。下面代码便是如何监听 upgrade 事件并进行处理。

server.on('upgrade',()=>{});

在处理函数中,按照下面的代码将 WebSocket 使用到 jsonrpc 协议中,并启动语言服务器让二者相连。

先构建语言服务器的路径,找到 pyright 包所在的位置。

const baseDir = resolve(getLocalDirectory(import.meta.url));
const relativeDir = '../../../node_modules/pyright/dist/pyright-langserver.js';
const ls = resolve(baseDir, relativeDir); 

再创建语言服务器的连接 和 创建 WebSocket 的数据连接

const serverConnection = createServerProcess(serverName, 'node', [ls, '--stdio']);
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
const socketConnection = createConnection(reader, writer, () => socket.dispose());

最后用 forward 函数将消息从 soketConnection 转发到 serverConnection,如下:

forward(socketConnection, serverConnection, message => {
    if (Message.isRequest(message)) {
        console.log(`Received:`);
        console.log(message);
	}
    if (Message.isResponse(message)) {
        console.log(`Sent:`);
        console.log(message);
    }
	return message;
});

于是我们将语言服务器跑起来,并在文章后面阶段会写的前端编辑器中随便输入一点东西,可以看到终端里输出了 message,

如何创建集成 LSP 支持多语言的 Web 代码编辑器

这样我们就使用 pyright 完成了语言服务器的开发。

Web 端开发

接下来我们开发前端的内容,还是在上面的那个网站中,

如何创建集成 LSP 支持多语言的 Web 代码编辑器

可以看到 Monaco Editor 也是有支持 LSP 的方案的,所以我们使用 TypeFox 开发的 monaco-languageclient 对monaco 进行集成 lsp 的开发。

首先使用 monaco-languageclient 的 initServices 函数初始化一些服务,其中最重要的就是下面四个配置,定义了 Monaco 的语言服务与主题显示。

await initServices({
    enableModelService: true,
    enableThemeService: true,
    enableTextmateService: true,
    enableLanguagesService: true,
})

然后创建能够与语言服务器相连的 WebSocket 连接。

createWebSocket("ws://localhost:30000/pyright");

而创建这个连接也需要用到 monaco-languageclient。

const createWebSocket = (url: string): WebSocket => {
    const webSocket = new WebSocket(url);
    webSocket.onopen = async () => {
        const socket = toSocket(webSocket);
        const reader = new WebSocketMessageReader(socket);
        const writer = new WebSocketMessageWriter(socket);
        languageClient = createLanguageClient({
            reader,
            writer
        });
        await languageClient.start();
        reader.onClose(() => languageClient.stop());
    };
    return webSocket;
};

const createLanguageClient = (transports: MessageTransports): MonacoLanguageClient => {
    return new MonacoLanguageClient({
        name: 'Pyright Language Client',
        clientOptions: {
            documentSelector: [languageId],
            errorHandler: {
                error: () => ({ action: ErrorAction.Continue }),
                closed: () => ({ action: CloseAction.DoNotRestart })
            },
            workspaceFolder: {
                index: 0,
                name: 'workspace',
                uri: monaco.Uri.parse('/tmp')
            },
            synchronize: {
                fileEvents: [vscode.workspace.createFileSystemWatcher('**')]
            }
        },
        connectionProvider: {
            get: () => {
                return Promise.resolve(transports);
            }
        }
    });
};

接下来这里需要创建一个虚拟文件系统,作为 Monaco Editor 实例的输入输出。

const fileSystemProvider = new RegisteredFileSystemProvider(false);
fileSystemProvider.registerFile(new RegisteredMemoryFile(vscode.Uri.file('/test.py'), 'print("Hello, laf!")'));
registerFileSystemOverlay(1, fileSystemProvider);
const modelRef = await createModelReference(monaco.Uri.file('/test.py'));

最后创建 Monaco Editor 实例即可,还能进行些许的配置。

createConfiguredEditor(document.getElementById('container')!, {
    model: modelRef.object.textEditorModel,
    automaticLayout: true,
    minimap: {
    	enabled: false
    },
    scrollbar: {
        verticalScrollbarSize: 4,
        horizontalScrollbarSize: 8,
    },
    overviewRulerLanes: 0,
    lineNumbersMinChars: 4,
    scrollBeyondLastLine: false,
    theme: 'vs',
});

就这样我们也完成了前端。

import Editor from './python/Editor';

function App() {
  
  return (
    <>
      <h2>monaco python lsp</h2>
      <div style={{height:"500px", width:"800px", border:"1px solid black", padding:"8px 0"}}>
        <Editor />
      </div>
    </>
  )
}

export default App

效果如下

如何创建集成 LSP 支持多语言的 Web 代码编辑器

小结

要深入理解 LSP 以及其背后的工作原理还是有很大的难度的,但是好在有 languageserver,languageclient 这类优秀的开源项目提供支持,能够让我们在仅仅拼凑了几段代码后拥有不错的代码编辑器效果。下一步计划用 LSP 改造 Laf 的 Web IDE。

由于我也只是刚刚接触这块知识,文章中难免有错漏,希望能与读到这里的各位共同交流进步。文章来源地址https://www.toymoban.com/news/detail-705994.html

参考资料

  • https://github.com/microsoft/language-server-protocol/wiki/Protocol-History
  • https://medium.com/@malintha1996/understanding-the-language-server-protocol-5c0ba3ac83d2
  • https://ubug.io/blog/workpad-part-6
  • https://www.typefox.io/blog/how-to-embed-a-monaco-editor-in-a-browser-as-a-part-of-my-first-task-at-typefox
  • https://www.typefox.io/blog/teaching-the-language-server-protocol-to-microsofts-monaco-editor

到了这里,关于如何创建集成 LSP 支持多语言的 Web 代码编辑器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 轻量级Web报表工具ActiveReportsJS全新发布v4.0,支持集成更多前端框架!

    ActiveReportsJS 是一款基于 JavaScript 和 HTML5 的轻量级Web报表工具,采用拖拽式设计模式,不需任何服务器和组件支持,即可在 Mac、Linux 和 Windows 操作系统中,设计多种类型的报表。ActiveReportsJS 同时提供跨平台报表设计、纯前端报表展示、多数据源绑定、前端打印导出等功能,

    2024年02月15日
    浏览(35)
  • SpringBoot集成国际化多语言配置

    在当今全球化的环境下,为了更好地满足用户的多语言需求,越来越多的应用程序需要支持国际化多语言配置。Spring Boot作为一种快速开发框架,提供了方便的国际化支持,使得应用程序可以轻松地适应不同的语言环境。通过集成Spring Boot的国际化多语言配置,应用程序可以根

    2024年02月07日
    浏览(48)
  • 扩展语音识别系统:增强功能与多语言支持

            在之前的博客中,我们成功构建了一个基于 LibriSpeech 数据集的英文语音识别系统。现在,我们将对系统进行扩展,增加一些增强功能,并尝试支持多语言识别。 语音合成   --除了语音识别,我们还可以增加语音合成( Text-to-Speech, TTS )功能,将文本转换为语音输

    2024年02月19日
    浏览(28)
  • Vue应用多语言支持工程化最佳实践

    VoerkaI18n是一款非常优秀的 全新的开源国际化多语言解决方案 ,主要特性包括: 全面工程化解决方案,提供初始化、提取文本、自动翻译、编译等工具链支持。 符合直觉,不需要手动定义文本Key映射。 强大的插值变量格式化器机制,可以扩展出强大的多语言特性。 支持 b

    2024年02月03日
    浏览(39)
  • WPF项目创建HTTP WEB服务,不使用IIS业务 WPF桌面程序WebApi WPF 集成WebApi C# 创建HTTP Web API服务

    在C# WPF应用程序中直接创建HTTP服务或WebAPI服务有以下优点: 自托管服务: 简化部署:无需依赖外部服务器或IIS(Internet Information Services),可以直接在应用程序内部启动和运行Web服务。 集成紧密:与WPF应用程序的其他组件和逻辑可以更紧密地集成,因为它们都在同一个进程

    2024年02月02日
    浏览(53)
  • Android Studio快速实现Flutter应用的国际化和多语言支持

    在Flutter中实现国际化和多语言支持通常涉及以下步骤: 首先,你需要添加flutter_localizations依赖库到你的pubspec.yaml文件中。这个库包含了Flutter国际化所需的核心功能。 Android Studio菜单File-Settings-Plugins(直接搜索效率菜单效率更高) 安装Flutter Intl插件后重启Android Studio 插件安装

    2024年02月08日
    浏览(31)
  • C#桌面程序 winform 集成内置WebApi C# 创建HTTP Web API服务,winform项目创建HTTP WEB服务,不使用IIS业务 C#桌面程序WebApi C#winform集

     在维护旧的项目时,有时需要提供APP连接的需求,就要提供HTTP服务,winform项目就要提供HTTP服务,就不用再去写个c# web的IIS相关的业务了,简化项目的复杂度。只需要简单化实例就可以实现提供HTTP服务

    2024年02月08日
    浏览(44)
  • SpringBoot 如何使用 MockMvc 进行 Web 集成测试

    SpringBoot 是一个流行的 Java Web 开发框架,它提供了一些强大的工具和库,使得开发 Web 应用程序变得更加容易。其中之一是 MockMvc,它提供了一种测试 SpringBoot Web 应用程序的方式,可以模拟 HTTP 请求和响应的行为。 在本文中,我们将介绍 SpringBoot 中的 MockMvc,演示如何使用它

    2024年02月16日
    浏览(41)
  • vite 创建vue3项目,使用 Prettier 统一格式化代码,集成 ESLint、Stylelint 代码校验规范

    在团队开发中,保持代码风格的一致性和代码质量的高度,对于项目的可维护性和可读性非常重要。为了实现这一目标,我们可以使用工具来自动格式化代码并进行代码校验,在开发过程中捕获潜在的问题,并提供修复建议。 本示例中,我们将使用 Vite 来创建一个新的 Vue

    2024年04月28日
    浏览(54)
  • 【人工智能AI代码:AIXCodeCompletionHelper】一个集成了 Open AI 人工智能写代码的 Jetbrains IDE 插件(支持 Golang,IDEA等)

    目录 AIXCodeCompletionHelper 简介  支持平台 项目源代码 GitHub - to-be-architect/AIXCodeCompletionHelper 核心实现代码

    2023年04月08日
    浏览(87)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包