0

I have an LSP server that works fine with VS 2019 IDE. I am now trying to get it to work with VSCode. I wrote a simple extension for VSCode that was working with the server at one point, but VSCode is now not working at all. So, I decided to write a simple C program that simply reads stdin and echos the characters to stderr, not expecting it to work, but to verify that VSCode is at least trying to communicate with the server. As with my original server, this program receives absolutely nothing: VSCode is not sending any packets to the server, and I don't know why.

Here is the simple "echo" server code. All it does is read stdin one character indefinitely then echo the char more or less to stderr, flush()ing each time.

#include <iostream>
#include <stdio.h>
#include <stdio.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <io.h>

int main()
{
    for (;;)
    {
        char buf[10];
        int readc = _read(0, buf, 1);
        fprintf(stderr, "%d\n", buf[0]);
        fflush(stderr);
    }
    return 0;
}

Here is a stripped-down VSCode client extension, derived from the doc, which so happens to provide zero information on spawning a server as a process. This calls spawn() of the server with a window.

export function activate(context: vscode.ExtensionContext) {

    const server: vscodelc.Executable = {
        command: `C:/Users/kenne/source/repos/ConsoleApplication1/Debug/ConsoleApplication1.exe`,
        args: [],
        options: {shell: true, detached: true }
    };

    const serverOptions: vscodelc.ServerOptions = server;

    let clientOptions: vscodelc.LanguageClientOptions = {
        // Register the server for plain text documents
        documentSelector: [{ scheme: 'file', language: 'plaintext' }]
    };

    const client = new vscodelc.LanguageClient('Antlr Language Server', serverOptions, clientOptions);
    console.log('Antlr Language Server is now active!');
    client.start();
}

(Via debugging, I figured out that I needed options: {shell: true, detached: true } in the ServerOptions struct to make spawn() create a detached window for the process.) Running the client, the server is spawned with a window, but there is indeed no characters written to the server, even for the simple C "echo" program. In the debugger, I even see that write() is called in the client code, into the json write code, and then into the Node write code. For the VS2019 IDE, this all works perfectly fine.

Does anyone have any ideas on how to get an executable server that uses stdin/stdout to work with VSCode?

kaby76
  • 1,142
  • 1
  • 7
  • 10
  • In what language did you write that language server? You can always find an open source VSCode extension with similar feature and then dig into its code. – Lex Li Aug 29 '20 at 20:34
  • @LexLi It is written in C#. I did find with debugging that one cannot perform a Node.js spawn() with `shell=true` (https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options). I can now attach to the C# program after spawn() and verify VSCode is talking to my C# server--at least two calls. However, the window with all the debug output is now gone. And spawn does not support Windows ProcessStartInfo.CreateNoWindow=false, even though it says so in Node 14.9 doc. JS/TS/VSCode is just a terrible environment compared to C#/VS 2019. – kaby76 Aug 29 '20 at 23:20
  • 1
    I have a sample extension for your reference, https://github.com/lextm/vscode-ansic and its language server is https://github.com/lextm/ansi-c-antlr. I think you can play with that first to see how TypeScript/C# work together, and then revise your own accordingly. – Lex Li Aug 29 '20 at 23:44
  • Thanks, I'll give it a look next. On creating a window for stderr output, I see that it's not available for spawn() options. https://github.com/microsoft/vscode-languageserver-node/blob/master/client/src/node/main.ts#L26 . Apparently, no one uses Windows. I see calls to forward stderr to a log in VSCode, but I can't find it in this log in the "UI". I'll shunt debug info to a file for server. I really don't understand the author didn't do what is done in VS2019-leave the fork to client, and pass transport to LSP client. – kaby76 Aug 30 '20 at 00:33
  • Even after changing @dbaeumer's code, I debugged it all the way into Nodejs: `windowsHide` does not work. Nodejs passes it to libuv (https://github.com/nodejs/node/blob/768b0f54eb143329743d2696bd36327f1bad7744/src/process_wrap.cc#L238), but libuv does not call CreateProcessW correctly (https://github.com/libuv/libuv/blob/v1.x/src/win/process.c#L1076). The process create flag is hidden behind an array of convoluted illogic. This code is wrong. No wonder @dbaeumer did not include it. – kaby76 Aug 30 '20 at 11:13

1 Answers1

0

The answer is that the tables that the package.json file were messed up. It contains tables required for the server: "activationEvents" describes all the languages supported; "languages" associate a file extension with a language. In addition, the language table is duplicated in the LanguageClientOptions in the activate() function. Without these tables, VSCode may not send an open file request to the LSP server, or even not start the LSP server. In addition, there is a bug in libuv that prevents "windowHidden" to not be processed correctly for Windows. Therefore, the server process cannot be created with a window until fixed. Instead, send server debugging output to a file. The server now works great with VSCode for Antlr2, 3, 4, Bison, and W3C EBNF.

kaby76
  • 1,142
  • 1
  • 7
  • 10