译者的话:
最近在使用electron开发一些小工具,其中用到了monaco-editor作为富文本编辑器。但monaco官方文档做的不是很友好(除了API接口定义与示例,没有像样的教程)。中文文档更是少之又少。所以计划结合使用过程中遇到的文档、库、资料,翻译或编写发布一些帖子供大家参考。
本次翻译的是【monaco-vscode-api】代码库的教程。这个库封装了monaco,让它能实现类似vscode的效果。
原文链接:
本指南目标:教你如何用 monaco-vscode-api 包,一步步的构建起带有LSP支持的,简易代码编辑器。
LSP:别想歪了,LSP是Language Server Protocol,是将各种开发语言抽象成通用的语言服务的协议,便于IDE工具开发。官方链接
目前,想要将 LSP 语言服务器连接到自定义编辑器(不是 Neovim 和 VSCode)并不简单,文档通常很难找,而且缺乏实现此功能的,简单且有文档记录的项目。
本指南将涵盖以下内容:
- monaco-editor 的基础知识
- 使用 monaco-editor 与多个编辑器窗口
- 使用 monaco-vscode-api 包并设置基本语言功能
- 添加 monaco-languageclient 和 Python LSP
- 一个monaco-editor的简单例子
- VSCode-API
- 介绍语言服务器
- 接下来干嘛
一个monaco-editor的简单例子
咱们从最简单的 Monaco 设置开始。在这里,将使用TypeScript + Vite + Bun包管理工具,希望可以轻松地扩展到其他不同的前端框架。
如果您了解过基本的 monaco-editor 设置,可随时跳过这一部分。
初始化项目
首先,让我们按照 Bun 初始化方法,初始化一个 Vite 项目并安装 monaco-editor:
bun create vite my-monaco-editor
cd my-monaco-editor
bun install
bun add monaco-editor
然后,我们只需要一个带有一个 div 的简单 html 页面,并把作为未来的编辑器。
<!-- index.html -->
<html>
<body>
<div id="editor"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
添加一些css样式:
/* style.css */
body {
background-color: #242424;
}
#editor {
margin: 10vh auto;
width: 720px;
height: 20vh;
}
现在我们可以创建一个 Monaco 编辑器实例,它将自动用交互式编辑器填充 div:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
// 绑定到#editor,并且初始化内容为"Hello world!"
monaco.editor.create(document.getElementById('editor')!, {
value: "Hello world!",
});
好了!Monaco 编辑器跑起来了:
添加workers
如果您按F12,查看 DevTools 控制台,您可能会看到一个警告:
main.ts:5 Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq
译:无法创建 web worker(s)。回退到在主线程中加载 web worker 代码,这可能会导致 UI 冻结。请参见https://github.com/microsoft/monaco-editor#faq”
这是因为, Monaco 编辑器通常将文本处理和 UI 交互,分离到不同的进程中,以便它们能够异步工作而不会相互干扰。
可以手动这样做:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
window.MonacoEnvironment = {
getWorker(_workerId: any, _label: string) {
return new editorWorker();
}
};
monaco.editor.create(document.getElementById('editor')!, { value: "Hello world!", });
我们可以通过 window.MonacoEnvironment
属性为文本处理提供 workers。getWorker
函数接收一个 label——这是编辑器所需的 worker 的名称。由于当前我们没有使用任何语言,所以默认的 editorWorker
就可以了。
现在一切正常,控制台中警告没了。
添加编程语言
既然 Monaco 是一个代码编辑器,我们尝试添加一些编程语言处理(高亮、提示)。可以向 monaco.editor.create
调用中的 options
对象添加 language 属性来完成:
// main.ts
monaco.editor.create(document.getElementById('editor')!, {
value: "console.log('Hello world!');",
language: "typescript"
});
但是,我们还没有提供相应的 worker。幸运的是,Monaco 为 typescript 和 javascript 提供了一个内置的 worker:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
// 导入tsWorker
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
window.MonacoEnvironment = {
getWorker(_workerId: any, label: string) {
if (label === 'typescript' || label === 'javascript') {
// 用tsWorker
return new tsWorker();
}
return new editorWorker();
}
};
monaco.editor.create(document.getElementById('editor')!, {
value: "console.log('Hello world!');",
language: "typescript"
});
我们首先需要确认每个语言需要的worker,然后返回相应的 worker。当我们用给定的 language 创建编辑器时,Monaco 会调用 getWorker
,并提供 language 作为 label 参数。这样,我们将看到语法高亮和内置的 LSP 在工作(处理代码,提供高亮和提示):
但是,这种worker绑定方法,只能用于 Monaco 默认内置的一些语言worker:
- json
- css
- html
- typescript
- javascript
除此之外的其他语言,Monaco 默认worker提供的功能较少(纯文本展示)。
提示:即使你用的语言不在内置worker范围,编辑器的完整功能也还是需要editorWorker。因此,假设你的编辑器仅用于Python,你可以在getWorker函数中返回默认的
editorWorker
,然后创建编辑器时传入language: "python"
:'monaco-editor'; import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; window.MonacoEnvironment = { getWorker(_workerId: any, _label: string) { return new editorWorker(); } }; monaco.editor.create(document.getElementById('editor')!, { value: "print('Hello world!')", language: "python" }); ```
添加更多的editor
想象一下,您需要多个编辑器,例如用于不同的文件。最直接的方法是再创建一个 div 并再调用一次 monaco.editor.create
:
<!-- index.html -->
<html>
<body>
<div id="editor1"></div>
<div id="editor2"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
/* style.css */
body {
background-color: #242424;
}
#editor1, #editor2 {
margin: 10vh auto;
width: 720px;
height: 20vh;
}
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
window.MonacoEnvironment = {
getWorker(_workerId: any, _label: string) {
return new editorWorker();
}
};
monaco.editor.create(
document.getElementById('editor1')!, { value: "print('Hello world 1!')", language: "python" });
monaco.editor.create(
document.getElementById('editor2')!, { value: "print('Hello world 2!')", language: "python" });
这能用,但并不理想——Monaco 会尝试从不同的编辑器中自动补全变量名:
这种问题比较容易修复,只需将 wordBasedSuggestions
字段设置为currentDocument
:
monaco.editor.create(document.getElementById('editor2')!, {
value: "print('Hello world 2!')",
language: "python",
wordBasedSuggestions: 'currentDocument' // 修复两个编辑器间变量串通的问题。
});
以上是 monaco-editor
的基本设置。如果您将其用于 TypeScript/CSS/HTML,由于内置的 workers,这可能已经足够了。但是,如果您需要它用于 Python 或任何其他语言,您可能需要集成自定义 LSP 以支持诸如 IntelliSense、默认关键字自动完成、代码导航、linting 等高级功能。
VSCode-API
让我们尝试构建一个具有完整 LSP 功能的 Monaco 编辑器,用于 Python。
不幸的是,Monaco 原生内置并不支持LSP,所以想想中的做法是做不到的:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import languageClient from 'monaco-lsp' // doesn't exist
window.MonacoEnvironment = {
getWorker(_workerId: any, _label: string) {
return new editorWorker();
}
};
const lsp = new languageClient( // doesn't exist
serverUri="ws://localhost:5007",
rootUri="file:///",
languageId="python"
)
monaco.editor.create(document.getElementById('editor')!, {
value: "print('Hello world!')",
language: "python",
lsp: lsp // doesn't work,不起作用
});
但是,大多数语言服务器(LSP的实现),是可以通过扩展与 VSCode 一起工作的。由于 VSCode 是围绕 Monaco 构建的,因此可以将 VSCode API(例如扩展和其他内容)集成到 Monaco 中。包括 LSP 支持。
monaco-vscode-api
库正是这样做的。但此外,它在某种程度上重新设计了 monaco-editor,使其更加模块化(但也更复杂)。
关于它的文档还不是很好。您可能会发现,wiki、示例代码和 issues 会帮助你理解,特别是以下内容:
- 最简例子—Minimal example
- 支持扩展组件的最小例子—Minimal example with extension support
- 来看这哥们花了4小时来设置主题样式—I have officially spent four hours of my lifespan to set a color theme. #510
本库更改了编辑器代码,但一些核心概念是相同的。让我们再次从一个最小示例开始来演示这一点。
新轮子
让我们以与之前相同的方式创建一个新项目,但这次我们将安装 monaco-vscode-api
包而不是 monaco-editor
。
# 执行前确保目录不存在
bun create vite my-monaco-api-editor
cd my-monaco-api-editor
bun install
bun add vscode@npm:@codingame/monaco-vscode-api
bun add monaco-editor@npm:@codingame/monaco-vscode-editor-api
bun add -D @types/vscode
这些包名称可能看起来很奇怪,因为它们使用别名作为 vscode
和 monaco-editor
包的增强型即用型替换。它们更改其功能以允许在 Monaco 中使用 VSCode 服务和扩展,但提供与原始包相同的接口。
然后,我们只需要一个带有一个 div 的简单 html 页面——它将作为编辑器。
<!-- index.html -->
<html>
<body>
<div id="editor"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
添加一点样式:
/* style.css */
body {
background-color: #242424;
}
#editor {
margin: 10vh auto;
width: 720px;
height: 20vh;
}
对于 main.ts,我们可以从完全相同的示例开始,因为我们只是使用了即用型替换:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
window.MonacoEnvironment = {
getWorker: function (_moduleId, _label) {
return new editorWorker();
}
}
monaco.editor.create(document.getElementById('editor')!, {
value: "Hello world!",
});
在 monaco-vscode-api 仓库的问题和示例项目中,您会遇到以下添加 worker 的变体:
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
export type WorkerLoader = () => Worker;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(
new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' })
})
}
window.MonacoEnvironment = {
getWorker: function (_workerId, label) {
const workerFactory = workerLoaders[label]
if (workerFactory != null) {
return workerFactory()
}
throw new Error(`Worker ${label} not found`)
}
}
monaco.editor.create(document.getElementById('editor')!, {
value: "Hello world!",
});
这和之前基本上是一样的,但更严格地检查所需的 worker 是否已实现。此外,worker 初始化略有不同,但功能仍然相同——TextEditorWorker 是之前示例中默认 editorWorker 的标签。
在您的打包器(vite等)中需要注意亿点点“细节”。它们在仓库的故障排除部分中有所描述。由于我在这里使用 Vite,我将在下面提供 Vite 用户的详细信息。
{% “亿点点细节”开始%}
对于 Vite 用户,由于本代码库使用 import.meta.url
基础,这与 Vite 原生配合不佳。因此,如果您正在使用 Vite,请在您的vite.config.ts
中添加以下内容(如果不存在则创建它):
// vite.config.ts
import type { UserConfig } from 'vite'
import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin'
export default {
optimizeDeps: {
esbuildOptions: {
plugins: [importMetaUrlPlugin]
}
}
} satisfies UserConfig
并安装相应的包
bun add @codingame/esbuild-import-meta-url-plugin
{% “亿点点细节”结束 %}
接下来,我们将使用后面的 worker 初始化方法,以便读者更习惯于本库的基本用法。此外,我们将通过控制台中的错误知道 worker添加的对不对。
添加语言高亮
因此,我们已经使用新的 monaco-vscode-api
构建了一个基本的文本编辑器,作为 monaco-editor 的即用型替换。让我们尝试添加 Python 高亮。以前,这是通过向 monaco.editor.create
选项对象添加 language
属性来完成的。
但是,如果我们添加 language
,什么也没有改变,甚至高亮也不存在:
import './style.css'
import * as monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
export type WorkerLoader = () => Worker;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' })
})
}
window.MonacoEnvironment = {
getWorker: function (_workerId, label) {
const workerFactory = workerLoaders[label]
if (workerFactory != null) {
return workerFactory()
}
throw new Error(`Worker ${label} not found`)
}
}
monaco.editor.create(document.getElementById('editor')!, {
value: "print('Hello world!')",
language: "python"
});
这是因为默认 workers 提供的大多数功能在 monaco-vscode-api
中不再以与 monaco-editor
相同的方式工作。现在,大多数编辑器功能都基于 VSCode 服务——提供特定功能的组件,甚至是基本功能。以下是 monaco-vscode-api 支持的一大批服务列表。要使此功能工作,需要手动添加相应的服务。
例如,为了支持高亮,我们现在需要添加以下服务:
- Textmate: @codingame/monaco-vscode-textmate-service-override
- 允许使用 TextMate 语法对语言进行标记以进行高亮。
- Themes: @codingame/monaco-vscode-theme-service-override
- 允许使用 VSCode 主题。注意:此包中的原始 Monaco 主题与 VSCode 主题不同。VSCode 主题作为 VSCode 扩展表示和安装。另请参阅 # I have officially spent four hours of my lifespan to set a color theme. #510 问题以获取详细信息。
- Languages: @codingame/monaco-vscode-languages-service-override
- 允许考虑 language 字段并设置 TextMate 语法以进行高亮和其他特定于语言的功能。
# split into several commands for readability
bun add @codingame/monaco-vscode-textmate-service-override
bun add @codingame/monaco-vscode-theme-service-override
bun add @codingame/monaco-vscode-languages-service-override
bun add @codingame/monaco-vscode-python-default-extension
bun add @codingame/monaco-vscode-theme-defaults-default-extension
给编辑器添加服务
// main.ts
import './style.css'
import * as monaco from 'monaco-editor';
// importing installed services
import { initialize } from 'vscode/services'
import getLanguagesServiceOverride from "@codingame/monaco-vscode-languages-service-override";
import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override";
import getTextMateServiceOverride from "@codingame/monaco-vscode-textmate-service-override";
// adding worker
export type WorkerLoader = () => Worker;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' })
})
}
window.MonacoEnvironment = {
getWorker: function (_workerId, label) {
const workerFactory = workerLoaders[label]
if (workerFactory != null) {
return workerFactory()
}
throw new Error(`Worker ${label} not found`)
}
}
// adding services
await initialize({
...getTextMateServiceOverride(),
...getThemeServiceOverride(),
...getLanguagesServiceOverride(),
});
monaco.editor.create(document.getElementById('editor')!, {
value: "print('Hello world!')",
language: "python"
});
虽然跑起来了,没有任何警告或错误,但高亮尚未添加。要添加它,我们需要最后集成:
- Python 语言默认扩展,它将提供 Python 语法;
- TextMate worker,它将基于语法对代码进行标记;
- 主题(Theme),以便不同的关键字可以有独特的颜色。
Python 语言和主题都是 VSCode 扩展。安装扩展在 README.md 中有详细说明。幸运的是,对于我们需要的默认 VSCode 扩展,仓库的作者提供了预构建的包:
@codingame/monaco-vscode-python-default-extension
用于 Python@codingame/monaco-vscode-theme-defaults-default-extension
用于默认 VSCode 主题。将它们添加到项目中就像安装包并在main.ts
的开头添加相应的导入一样简单。
// main.ts
import '@codingame/monaco-vscode-python-default-extension';
import "@codingame/monaco-vscode-theme-defaults-default-extension";
要将 TextMate worker 集成,我们需要将其添加到 workerLoaders
映射中:
// main.ts
...
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }),
TextMateWorker: () => new Worker(new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url), { type: 'module' })
}
...
{% “亿点点细节”之《如何找到所需的服务和/或扩展?》%}
你可以在此处找到服务和扩展的完整列表:
https://www.npmjs.com/search?q=%40codingame%2Fmonaco-vscode-*-default-extension
由于没有完整的文档,你通常需要查看使用monaco-vscode-api的 issues / demo / 其他项目,并复制相关内容,或者根据服务/扩展的名称直观地添加它们,直到找到不工作的那个。至少,我目前还没有找到更好的方法。
{% 细节结束 %}
import '@codingame/monaco-vscode-python-default-extension';
import "@codingame/monaco-vscode-theme-defaults-default-extension";
import './style.css'
import * as monaco from 'monaco-editor';
import { initialize } from 'vscode/services'
import getLanguagesServiceOverride from "@codingame/monaco-vscode-languages-service-override";
import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override";
import getTextMateServiceOverride from "@codingame/monaco-vscode-textmate-service-override";
export type WorkerLoader = () => Worker;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }),
TextMateWorker: () => new Worker(new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url), { type: 'module' })
}
window.MonacoEnvironment = {
getWorker: function (_moduleId, label) {
console.log('getWorker', _moduleId, label);
const workerFactory = workerLoaders[label]
if (workerFactory != null) {
return workerFactory()
}
throw new Error(`Worker ${label} not found`)
}
}
await initialize({
...getTextMateServiceOverride(),
...getThemeServiceOverride(),
...getLanguagesServiceOverride(),
});
monaco.editor.create(document.getElementById('editor')!, {
value: "import numpy as np\nprint('Hello world!')",
language: 'python'
});
语言服务(language server)介绍
现在,让我们最终添加一个语言服务器。为此,我们将需要使用一个名为monaco-languageclient
的与monaco-vscode-api
相关的包,该包积极利用了后者。
我们还需要一个语言服务器本身。
{% details 关于LSP服务器的说明 %}
通常在使用VSCode时,你只需选择一个语言,并从Marketplace安装相应的语言服务器扩展,例如Python的Pyright或Ruff。在底层,大多数这些VSCode语言服务器扩展都使用了vscode-languageclient
API。该API允许以多种方式启动LSP服务器,例如作为在VSCode本身提供的运行时中运行的节点模块,或者作为可通过命令运行的子进程。你可以查看Pylyzer Python LSP扩展,以了解API使用的一个示例。
请注意,要使用它,你需要一个可以访问你的文件的运行时环境。
虽然可以在你的Monaco项目中添加一个VSCode服务器并使用它来启动语言服务器,但这会增加额外的复杂性和依赖。在本指南中,我们将避免这样做。
还有其他运行语言服务器的方法,例如,可以使用pygls创建一个新的语言服务器或现有语言服务器的包装器,以Python进程的形式运行它,并提供WebSocket服务器。这里有一个很棒的指南,介绍了语言服务器和Monaco语言客户端。另一个类似但针对Rust的选项是tower-lsp。
{% enddetails %}
我们将采用Python的最简单方法——使用python-lsp-server,它提供了一个开箱即用的带有所有功能的WebSocket LSP服务器。
以下示例将基于monaco-languageclient仓库中的一个基础客户端示例实现。
要继续操作,我们需要安装两个额外的包:
bun add vscode-ws-jsonrpc
bun add monaco-languageclient
然后,让我们创建一个名为lsp-client.ts
的文件。在这里,我们将为LSP客户端编写初始化函数。我们将在此处理与服务器的WebSocket连接。
// lsp-client.ts
import { WebSocketMessageReader } from 'vscode-ws-jsonrpc';
import { CloseAction, ErrorAction, MessageTransports } from 'vscode-languageclient/browser.js';
import { WebSocketMessageWriter } from 'vscode-ws-jsonrpc';
import { toSocket } from 'vscode-ws-jsonrpc';
import { MonacoLanguageClient } from 'monaco-languageclient';
export const initWebSocketAndStartClient = (url: string): WebSocket => {
const webSocket = new WebSocket(url);
webSocket.onopen = () => {
// creating messageTransport
const socket = toSocket(webSocket);
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
// creating language client
const languageClient = createLanguageClient({
reader,
writer
});
languageClient.start();
reader.onClose(() => languageClient.stop());
};
return webSocket;
};
const createLanguageClient = (messageTransports: MessageTransports): MonacoLanguageClient => {
return new MonacoLanguageClient({
name: 'Sample Language Client',
clientOptions: {
// use a language id as a document selector
documentSelector: ['python'],
// disable the default error handler
errorHandler: {
error: () => ({ action: ErrorAction.Continue }),
closed: () => ({ action: CloseAction.DoNotRestart })
}
},
// create a language client connection from the JSON RPC connection on demand
connectionProvider: {
get: async (_encoding: string) => messageTransports
}
});
};
这里的关键概念是createLanguageClient
函数中的messageTransports参数。它是一对初始化的WebSocket读取器和写入器,用于与服务器进行通信。
现在,我们需要做的就是在main.ts中运行initWebSocketAndStartClient
函数,并提供WebSocket语言服务器的URL和端口:
import '@codingame/monaco-vscode-python-default-extension';
import "@codingame/monaco-vscode-theme-defaults-default-extension";
import './style.css'
import * as monaco from 'monaco-editor';
import { initialize } from 'vscode/services'
// we need to import this so monaco-languageclient can use vscode-api
import "vscode/localExtensionHost";
import { initWebSocketAndStartClient } from 'lsp-client'
// everything else is the same except the last line
import getLanguagesServiceOverride from "@codingame/monaco-vscode-languages-service-override";
import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override";
import getTextMateServiceOverride from "@codingame/monaco-vscode-textmate-service-override";
export type WorkerLoader = () => Worker;
const workerLoaders: Partial<Record<string, WorkerLoader>> = {
TextEditorWorker: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }),
TextMateWorker: () => new Worker(new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url), { type: 'module' })
}
window.MonacoEnvironment = {
getWorker: function (_moduleId, label) {
console.log('getWorker', _moduleId, label);
const workerFactory = workerLoaders[label]
if (workerFactory != null) {
return workerFactory()
}
throw new Error(`Worker ${label} not found`)
}
}
await initialize({
...getTextMateServiceOverride(),
...getThemeServiceOverride(),
...getLanguagesServiceOverride(),
});
monaco.editor.create(document.getElementById('editor')!, {
value: "import numpy as np\nprint('Hello world!')",
language: 'python'
});
// start web socket lsp client on port 5007
// (you can choose any port, just make sure the server uses the same)
initWebSocketAndStartClient("ws://localhost:5007/")
现在,只需在你所选择的端口上安装并运行python-lsp-server:
pip install python-lsp-server
pylsp --ws --port 5007
最终效果:
接下来干嘛
通过使用monaco-editor-wrapper,你可以减少样板代码的数量(例如,为诸如主题、高亮等基本功能添加服务)。
你可以更深入地了解模型的概念,以便更好地控制项目中文件之间的LSP功能。
你可以尝试设置一些基于Node.js的语言服务器,如pyright或basedpyright。
请查看monaco-languageclient中的示例以获取更多信息。