Skip to content

When used with monaco-languageclient does not provides auto-completion and proper intellisense for tsconfig files #270

Open
@paulosabayomi

Description

@paulosabayomi

Hi, I am using monaco-editor & monaco-languageclient (to connect to LSPs) with vscode-json-languageserver - which uses vscode-json-languageservice for intellisense for .json & .jsonc files in the text editor desktop app I am building, the issue is the vscode-json-languageserver doesn't work at all for tsconfig (jsonc) files and treats them as normal json files and it also doesn't provide hover suggestions for normal json files such as package.json

I have asked ChatGPT & Gemini and the suggestions I got was the schema configuration and which I have applied their suggestions but couldn't get it to work

The project environment

  • ElectronForge
  • React JS
  • TypeScript
  • vite
  • monaco-editor
  • monaco-languageclient
    I am running the vscode-json-languageserver in a child process (programmatically) with vscode-jsonrpc/node to handle the input and output stream and sending messages between the client and the server over electronjs IPC

This is my monaco-languageclient code

//...
async configure_lc (): Promise<any> {
        this.lang_client = this.createLanguageClient({
            reader: {
                onClose: () => {
                    console.log("LP client closed");
                },
                onError: () => {
                    console.log("reader closed");
                },
                onPartialMessage: (data: any) => {
                    console.log("onPartialMessage", data);
                },
                listen: (cb: Function) => {
                    console.log("reader onMessage", typeof cb);
                    this.winEvCallbackRef = (e: Event & {detail: any}) => {
                        console.log("window got event", e.detail);                        
                        cb(e.detail);
                    }
                    window.addEventListener(`lsp-${this.lang_id}-ev`, this.winEvCallbackRef)
                },
                dispose: () => {
                    console.log("reader disposed");
                },
            },
            writer: {
                onClose: () => {
                    console.log("LP client writer closed");
                },
                onError: () => {
                    console.log("writer closed");
                },
                write: (msg: any) => {
                    console.log("writer onMessage", msg);
                    window.mp_electron.lsp_msg(msg, this.lang_id)
                    return Promise.resolve();
                },
                dispose: () => {
                    console.log("reader disposed");
                },
            },
        } as any, this.rootPath);
        if(this.lang_is_running(this.lang_id)) return;

        this.lang_client.start()
        .then((v) => {
            this.running_language = this.lang_id
        })
        .catch((e) => {
            console.log("LC connect failed", e);
        });
    };
    
    createLanguageClient (messageTransports: MessageTransports, rootPath: string): MonacoLanguageClient {
        return new MonacoLanguageClient({
            name: LSClientHandler.textToTitleCase(this.lang_id) + ' Language Server',
            clientOptions: {
                documentSelector: [this.original_lang_id],
                errorHandler: {
                    error: () => ({ action: ErrorAction.Continue }),
                    closed: () => ({ action: CloseAction.DoNotRestart })
                },
                workspaceFolder: {
                    index: 0,
                    name: rootPath,
                    uri: monaco.Uri.parse(rootPath)
                }                
            },
            messageTransports: messageTransports,
            // @ts-ignore
            connectionProvider: {
                get: async (_encoding: string) => messageTransports
            }
        });
    }
//...

and this is my LSP code

console.log("running lsp data", lsp_proc, "languages::", running_languages);

    if (!(lang_id in lang_servers)) return;
    
    if (running_languages.includes(lang_id)) {
        lsp_proc[lang_id].kill();
    };

    const runner = "node";
    lsp_proc[lang_id] = cp.spawn(runner, [path.resolve(__dirname, lang_servers[lang_id as keyof typeof lang_servers]), '--stdio'], )

    stream_reader[lang_id] = new StreamMessageReader(lsp_proc[lang_id].stdout);
    stream_writer[lang_id] = new StreamMessageWriter(lsp_proc[lang_id].stdin);
    
    ipcMain.on(`lsp-${lang_id}-message`, async (ev, data) => {
        await stream_writer[lang_id].write(data)
        .catch(err => {
        console.log("error occured while writing data to stdout in msg write", err);
        });
    })

    stream_reader[lang_id].listen((msg) => {
        mainWindow.webContents.send(`lsp-${lang_id}-ev`, {data: msg, lang_id});  
    });

    lsp_proc[lang_id].on('spawn', () => {
        console.log("lsp proc spawned");
        running_languages.push(lang_id);
    })

    lsp_proc[lang_id].on('close', (code) => {
        console.log("lsp proc closed", code);
        running_languages.splice(running_languages.indexOf(lang_id), 1);
    })

Please what I'm I missing or doing wrong?

Based on suggestions from ChatGPT and Gemini this is what I've tried but didn't have any effects
Description: I tried to send a json/schemaAssociations notification to the json LSP after initialization but did not make any effects

//...
 this.lang_client.start()
        .then((v) => {
          if(this.original_lang_id == 'jsonc') {
            this.lang_client.sendNotification('json/schemaAssociations', {
                    "http": {
                        "proxy": "",
                        "proxyStrictSSL": false
                    },
                    "json": {
                        "format": {
                            "enable": true
                        },
                        "schemas": [
                            {
                                "fileMatch": ['tsconfig.json', 'tsconfig.*.json'],
                                "url": "https://json.schemastore.org/tsconfig.json",
                            }
                        ]
                    }
                })
           }
        })
        .catch((e) => {
            console.log("LC connect failed", e);
        });
//...

Thank you

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions