【译】monaco-vscode-api 入门指南

译者的话:
最近在使用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 设置开始。在这里,将使用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 编辑器跑起来了:
简易monaco-editor

添加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 为 typescriptjavascript 提供了一个内置的 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带来的解析能力,提供了高亮、提示
但是,这种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 会帮助你理解,特别是以下内容:

本库更改了编辑器代码,但一些核心概念是相同的。让我们再次从一个最小示例开始来演示这一点。

新轮子

让我们以与之前相同的方式创建一个新项目,但这次我们将安装 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

这些包名称可能看起来很奇怪,因为它们使用别名作为 vscodemonaco-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"
});

虽然跑起来了,没有任何警告或错误,但高亮尚未添加。要添加它,我们需要最后集成:

  1. Python 语言默认扩展,它将提供 Python 语法;
  2. TextMate worker,它将基于语法对代码进行标记;
  3. 主题(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中的示例以获取更多信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值