monaco-languageclient icon indicating copy to clipboard operation
monaco-languageclient copied to clipboard

LSP Server Connected Successfully but No Automatic Notifications Initiated

Open NGC2207 opened this issue 11 months ago • 6 comments

Hello, I referenced the code in example and wrote a C language service.

Since I'm using Next.js, to avoid the annoying SSR issues, I opted for @monaco-editor/react , which is relatively more SSR-friendly.

I then ran my Next.js project and the language server. Fortunately, my language server responded and received the code. Unfortunately, my Editor interface did not display any intelligent suggestions.

I compared the logs of my language server with those of a server that successfully provided intelligent completions (using @typefox/monaco-editor-react ) and found that the issue seems to be that it did not automatically initiate textDocument/didOpen, textDocument/documentLink, textDocument/inlayHint,etc.

I reviewed related issues and tried their solutions, including importing npm:@codingame/monaco-vscode-editor-api,but it still didn't work.

I've been trying to resolve this issue for over two weeks, experimenting with various approaches. The only time I succeeded was when I used @typefox/monaco-editor-react,but due to various reasons, I have to use @monaco-editor/react.

I really hope someone with similar experiences can help me. Thank you very much!

My code is only in here

NGC2207 avatar Jan 01 '25 16:01 NGC2207

This is the WebSocket request-response diagram in the browser after my code was executed. image This is the WebSocket request-response diagram in the browser after using @typefox/react-editor-react. image

NGC2207 avatar Jan 01 '25 16:01 NGC2207

@NGC2207 did you enforce the monaco-editor version? I have just updated the monaco-editor/react section in the README. If you don't enforce a specific monaco-editor with overrides you may have rivaling versions.

Also, we have next.js verification example that I forgot to mention in the README (just updated that, too).

kaisalmen avatar Jan 02 '25 10:01 kaisalmen

@kaisalmen Thank you for your response. I’ve retried the process and believe I’ve pinpointed the issue. Let me walk you through the steps with a new demo:

  1. I created a new Next.js project using npx [email protected].
  2. I installed @monaco-editor/react, which automatically installed [email protected]. image
  3. Since the version of monaco-editor needs to be enforced to npm:@codingame/monaco-vscode-editor-api@~11.1.2, I ran npm install monaco-editor@npm:@codingame/monaco-vscode-editor-api. Initially, everything appeared to work correctly. However, upon checking the version of monaco-editor again, I noticed it had changed to 11.1.2, which is actually the version of @codingame/monaco-vscode-editor-api. image

According to the compatibility table, @codingame/[email protected] is compatible with [email protected]. However, @monaco-editor/react seems to interpret it as [email protected], which causes it to malfunction. image

Here’s a comparison of the behavior:

  • When @monaco-editor/react uses [email protected]:

    • Code in src/app/page.tsx: image
    • The editor in the browser displays syntax highlighting: image
  • When using @codingame/monaco-vscode-editor-api:

    • Code in src/app/page.tsx: image
    • The editor loses syntax highlighting: image

I’m unsure if this is the correct approach, but when I attempt to initialize services using initServices: image the browser encounters an issue: image Even after commenting out initServices, the browser still behaves unexpectedly: image

Here’s my code:

"use client";

import {
  toSocket,
  WebSocketMessageReader,
  WebSocketMessageWriter,
} from "vscode-ws-jsonrpc";
import * as monaco from "monaco-editor";
import {
  CloseAction,
  ErrorAction,
  MessageTransports,
} from "vscode-languageclient/browser.js";
import { MonacoLanguageClient } from "monaco-languageclient";
import { Editor, loader, Monaco } from "@monaco-editor/react";
import getConfigurationServiceOverride, {
  updateUserConfiguration,
} from "@codingame/monaco-vscode-configuration-service-override";
import { initServices } from "monaco-languageclient/vscode/services";

loader.config({ monaco });

export default function HomePage() {
  return (
    <Editor
      height="100vh"
      language="cpp"
      value={`#include<stdio.h>
int main() {
  printf("Hello, World!");
  return 0;
}
`}
      beforeMount={async (monaco: Monaco) => {
        //   await initServices(
        //     {
        //       serviceOverrides: {
        //         ...getConfigurationServiceOverride(),
        //       },
        //     },
        //     {}
        //   );
        updateUserConfiguration(
          JSON.stringify({
            "editor.experimental.asyncTokenization": true,
          })
        );

        monaco.languages.register({
          id: "cpp",
          extensions: [".cpp"],
          aliases: ["C++", "cpp"],
          mimetypes: ["text/x-c++src"],
        });
      }}
      onMount={(
        editor: monaco.editor.IStandaloneCodeEditor,
        monaco: Monaco
      ) => {
        initWebSocketAndStartClient("ws://localhost:30001/clangd");
      }}
    />
  );
}

/** Parameterized version, supports all language IDs */
export const initWebSocketAndStartClient = (url: string): WebSocket => {
  const webSocket = new WebSocket(url);
  webSocket.onopen = () => {
    const socket = toSocket(webSocket);
    const reader = new WebSocketMessageReader(socket);
    const writer = new WebSocketMessageWriter(socket);
    const languageClient = createLanguageClient({
      reader,
      writer,
    });
    languageClient.start();
    reader.onClose(() => languageClient.stop());
  };
  return webSocket;
};

export const createLanguageClient = (
  messageTransports: MessageTransports
): MonacoLanguageClient => {
  return new MonacoLanguageClient({
    name: "Cpp Language Client",
    clientOptions: {
      // Use a language ID as a document selector
      documentSelector: ["cpp"],
      // 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
    messageTransports,
  });
};

NGC2207 avatar Jan 03 '25 10:01 NGC2207

@kaisalmen Thank you for your response. I’ve retried the process and believe I’ve pinpointed the issue. Let me walk you through the steps with a new demo:感谢您的回复。我重新尝试了一遍,相信已经找到了问题所在。让我通过一个新的演示来指导您完成这些步骤:

  1. I created a new Next.js project using npx [email protected].我使用 npx [email protected] 创建了一个新的 Next.js 项目。
  2. I installed @monaco-editor/react, which automatically installed [email protected].我安装了 @monaco-editor/react ,它自动安装了 [email protected]image
  3. Since the version of monaco-editor needs to be enforced to npm:@codingame/monaco-vscode-editor-api@~11.1.2, I ran npm install monaco-editor@npm:@codingame/monaco-vscode-editor-api.由于需要将 monaco-editor 的版本强制为 ** npm:@codingame/monaco-vscode-editor-api@~11.1.2 ** ,因此我运行了 ** npm install monaco-editor@npm:@codingame/monaco-vscode-editor-api ** 。 Initially, everything appeared to work correctly. However, upon checking the version of monaco-editor again, I noticed it had changed to 11.1.2, which is actually the version of @codingame/monaco-vscode-editor-api.起初,一切似乎都运行正常。然而,当我再次检查 monaco-editor 的版本时,我发现它已经变成了 11.1.2 ,而这实际上是 ** @codingame/monaco-vscode-editor-api ** 的版本。 image

According to the compatibility table, @codingame/[email protected] is compatible with [email protected]. However, @monaco-editor/react seems to interpret it as [email protected], which causes it to malfunction.根据兼容性表 , ** @codingame/[email protected] ** 与 [email protected] 兼容。但是, @monaco-editor/react 似乎将其解释为 [email protected] ,这导致其出现故障。 image

Here’s a comparison of the behavior:以下是行为的比较:

  • When @monaco-editor/react uses [email protected]:当 @monaco-editor/react 使用 [email protected] 时:

    • Code in src/app/page.tsx:src/app/page.tsx 中的代码: image
    • The editor in the browser displays syntax highlighting:浏览器中的编辑器显示语法高亮: image
  • When using @codingame/monaco-vscode-editor-api:使用 ** @codingame/monaco-vscode-editor-api ** 时:

    • Code in src/app/page.tsx:src/app/page.tsx 中的代码: image
    • The editor loses syntax highlighting:编辑器失去语法高亮: image

I’m unsure if this is the correct approach, but when I attempt to initialize services using initServices:我不确定这是否是正确的方法,但是当我尝试使用 initServices 初始化服务时: image the browser encounters an issue:浏览器遇到问题: image Even after commenting out initServices, the browser still behaves unexpectedly:即使注释掉 initServices 之后,浏览器仍然会出现意外行为: image

Here’s my code:  这是我的代码:

"use client";

import { toSocket, WebSocketMessageReader, WebSocketMessageWriter, } from "vscode-ws-jsonrpc"; import * as monaco from "monaco-editor"; import { CloseAction, ErrorAction, MessageTransports, } from "vscode-languageclient/browser.js"; import { MonacoLanguageClient } from "monaco-languageclient"; import { Editor, loader, Monaco } from "@monaco-editor/react"; import getConfigurationServiceOverride, { updateUserConfiguration, } from "@codingame/monaco-vscode-configuration-service-override"; import { initServices } from "monaco-languageclient/vscode/services";

loader.config({ monaco });

export default function HomePage() { return ( <Editor height="100vh" language="cpp" value={#include<stdio.h> int main() { printf("Hello, World!"); return 0; } } beforeMount={async (monaco: Monaco) => { // await initServices( // { // serviceOverrides: { // ...getConfigurationServiceOverride(), // }, // }, // {} // ); updateUserConfiguration( JSON.stringify({ "editor.experimental.asyncTokenization": true, }) );

    monaco.languages.register({
      id: "cpp",
      extensions: [".cpp"],
      aliases: ["C++", "cpp"],
      mimetypes: ["text/x-c++src"],
    });
  }}
  onMount={(
    editor: monaco.editor.IStandaloneCodeEditor,
    monaco: Monaco
  ) => {
    initWebSocketAndStartClient("ws://localhost:30001/clangd");
  }}
/>

); }

/** Parameterized version, supports all language IDs */ export const initWebSocketAndStartClient = (url: string): WebSocket => { const webSocket = new WebSocket(url); webSocket.onopen = () => { const socket = toSocket(webSocket); const reader = new WebSocketMessageReader(socket); const writer = new WebSocketMessageWriter(socket); const languageClient = createLanguageClient({ reader, writer, }); languageClient.start(); reader.onClose(() => languageClient.stop()); }; return webSocket; };

export const createLanguageClient = ( messageTransports: MessageTransports ): MonacoLanguageClient => { return new MonacoLanguageClient({ name: "Cpp Language Client", clientOptions: { // Use a language ID as a document selector documentSelector: ["cpp"], // 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 messageTransports, }); };

Have you solved it?

xiaogonggong-w avatar Apr 28 '25 16:04 xiaogonggong-w

Hi @xiaogonggong-w with next.js you have to do everything inside a dynamic function, see here: https://github.com/TypeFox/monaco-languageclient/blob/main/verify/next/app/page.tsx

Regarding your above example, please share a repo with build re-production instructions. Thanks.

kaisalmen avatar Apr 29 '25 06:04 kaisalmen

Issue review before new release. I will close this now. There is sophisticated next.js verification example available now.

kaisalmen avatar Sep 19 '25 11:09 kaisalmen