Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struggling to run the language server standalone #100

Open
djzager opened this issue Jun 30, 2023 · 3 comments
Open

Struggling to run the language server standalone #100

djzager opened this issue Jun 30, 2023 · 3 comments

Comments

@djzager
Copy link

djzager commented Jun 30, 2023

@razzmatazz thank you for the work you have put into this language server. I will apologize up front that my experience with C#, F#, and dotnet in general is pretty weak.

What I'm trying to do is to make specific calls to your language server independent of an editor like vscode/neovim.

What I have is a project at /opt/app-root/src that looks like:

Filetree:

├──  HelloWorld.csproj
└──  Program.cs

HelloWorld.csproj

───────┼───────────────────────────────────────────────────────────────────────────────────
   1   │ <Project Sdk="Microsoft.NET.Sdk">
   2   │
   3   │   <PropertyGroup>
   4   │     <OutputType>Exe</OutputType>
   5   │     <TargetFramework>net6.0</TargetFramework>
   6   │     <LangVersion>7.1</LangVersion>
   7   │     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   8   │     <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
   9   │     <PlatformTarget>x64</PlatformTarget>
  10   │   </PropertyGroup>
  11   │
  12   │ </Project>
───────┴───────────────────────────────────────────────────────────────────────────────────

Program.cs

───────┼───────────────────────────────────────────────────────────────────────────────────
   1   │ using System;
   2   │
   3   │ namespace HelloWorld
   4   │ {
   5   │     class Program
   6   │     {
   7   │         static void Main(string[] args)
   8   │         {
   9   │             Console.WriteLine("Hello World!");
  10   │         }
  11   │     }
  12   │ }
───────┴───────────────────────────────────────────────────────────────────────────────────

I'm able to initialize the server just fine, but get nothing back when I make a workspace/symbol query. Here is me printing everything meaningful to demonstrate what I'm talking about.

Starting language server: '/opt/app-root/.dotnet/tools/csharp-ls' in directory '/opt/app-root/golang-lsp-cli'
Language server started
Initializing language server
Request:
{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "processId": 0,
    "rootUri": "file:///opt/app-root/src",
    "capabilities": {
      "workspace": {
        "workspaceEdit": {},
        "didChangeConfiguration": {},
        "didChangeWatchedFiles": {},
        "symbol": {},
        "executeCommand": {}
      },
      "textDocument": {
        "documentSymbol": {
          "hierarchicalDocumentSymbolSupport": true
        }
      }
    },
    "workspaceFolders": null,
    "extendedClientCapabilities": {
      "classFileContentsSupport": true
    }
  },
  "id": 1
}
Response:
{
  "capabilities": {
    "textDocumentSync": {
      "openClose": true,
      "change": 2,
      "save": {
        "includeText": true
      }
    },
    "hoverProvider": true,
    "completionProvider": {
      "triggerCharacters": [
        ".",
        "'"
      ]
    },
    "signatureHelpProvider": {
      "triggerCharacters": [
        "(",
        ",",
        "\u003c",
        "{",
        "["
      ]
    },
    "definitionProvider": true,
    "implementationProvider": true,
    "referencesProvider": true,
    "documentHighlightProvider": true,
    "documentSymbolProvider": true,
    "workspaceSymbolProvider": true,
    "codeActionProvider": {
      "resolveProvider": true
    },
    "codeLensProvider": {
      "resolveProvider": true
    },
    "documentFormattingProvider": true,
    "documentRangeFormattingProvider": true,
    "documentOnTypeFormattingProvider": {
      "firstTriggerCharacter": ";",
      "moreTriggerCharacter": [
        "}",
        ")"
      ]
    },
    "renameProvider": true,
    "callHierarchyProvider": true,
    "semanticTokensProvider": {
      "legend": {
        "tokenTypes": [
          "class",
          "comment",
          "property",
          "enumMember",
          "enum",
          "event",
          "method",
          "variable",
          "interface",
          "keyword",
          "namespace",
          "number",
          "operator",
          "parameter",
          "struct",
          "regex",
          "string",
          "typeParameter"
        ],
        "tokenModifiers": [
          "static"
        ]
      },
      "range": true,
      "full": true
    },
    "typeHierarchyProvider": true,
    "inlayHintProvider": {
      "resolveProvider": false
    }
  }
}
Language server initialized
Making call to language server
Request:
{
  "jsonrpc": "2.0",
  "method": "workspace/symbol",
  "params": {
    "query": ""
  },
  "id": 2
}
Response:
nil
Language server called

Questions:

  1. When running the LSP this way, where are the logs?
  2. Any idea what I could be missing as far as making a valid query?
@tcx4c70
Copy link
Contributor

tcx4c70 commented Jul 1, 2023

@djzager

  1. For now, all logs are sent to client via window/showMessageRequest. You can receive the notifications then print the content.
  2. It looks like that you forget to send initialized notification to csharp-ls, which tells csharp-ls that the client is ready and csharp-ls can start loading solution/project files. I don't know what lsp client you are using or you're using a lsp client written by yourself, but csharp-ls will send 2 requests, client/registerCapability and workspace/configuration, to client during loading solution/project and client should response them. For example, here is a trace from my client during initialized:
[Trace - 15:27:27.492] Sending notification 'initialized'.
Params: {}

[Trace - 15:27:27.535] Received request 'client/registerCapability - (2)'.
Params: {
    "registrations": [
        {
            "id": "id:workspace/didChangeWatchedFiles",
            "method": "workspace/didChangeWatchedFiles",
            "registerOptions": {
                "watchers": [
                    {
                        "globPattern": "**/*.{cs,csproj,sln}"
                    }
                ]
            }
        }
    ]
}

[Trace - 15:27:27.537] Sending response 'client/registerCapability - (2)'. Processing request took 2ms
No result returned.

[Trace - 15:27:27.553] Received request 'workspace/configuration - (3)'.
Params: {
    "items": [
        {
            "section": "csharp"
        }
    ]
}

[Trace - 15:27:27.555] Sending response 'workspace/configuration - (3)'. Processing request took 2ms                                                  Result: [
    null
]

@djzager
Copy link
Author

djzager commented Jul 13, 2023

Thank you @tcx4c70 . That helped a ton. There were a lot of changes required in the client I am working on to get it up and running. That leads me to a couple of questions:

  1. According to the specificationn related to client/registerCapability, this is something that the client would "opt-in"to. Are we certain the server should be sending this request to clients that do not support dynamicRegistration?
  2. Looking at the clientCapabilities, the client should be able to declare that they do not support the workspace/configuration requests. Is this something this server should respect?

djzager added a commit to djzager/analyzer-dotnet-provider that referenced this issue Jul 26, 2023
This commit introduces a container image + main.go that integrates with
analyzer-lsp; namely it makes this project a legit external provider to
the analyzer for .NET projects.

- We opt to use the csharp-ls that, while hacky, implements the 3.17 LSP
  spec.
- Introduce a server on the client side of the LSP communication to
  handle requests from the server back to our client. Should `csharp-ls`
  be sending us these requests? Probably not, see
  razzmatazz/csharp-language-server#100
- Wait until the server responds that the project is loaded before
  handing our service client back to whoever asked for it.
- Also do, what I think at least, are nifty tricks to put the stdio
  chatter client<->server in our logs.

Signed-off-by: David Zager <[email protected]>
@tcx4c70
Copy link
Contributor

tcx4c70 commented Jul 27, 2023

@djzager

  1. csharp-ls will not send client/registerCapability if client says it doesn't support it (set workspace.didChangeWatchedFiles.dynamicRegistration to false). But if client doesn't say it, csharp-ls will think client support it, which I think we can improve it.
  2. Yes, I think csharp-ls should not send the request if client declares that it doesn't support it. But for now, csharp-ls just think that all clients support it and will always send the request to client.

I'm working on rework of csharp-ls, you can try it #102 if you're interested. I think it might fix the issues you have met, but you still need to send initialized notification before you send any other requests.

djzager added a commit to djzager/analyzer-dotnet-provider that referenced this issue Aug 15, 2023
This commit introduces a container image + main.go that integrates with
analyzer-lsp; namely it makes this project a legit external provider to
the analyzer for .NET projects.

- We opt to use the csharp-ls that, while hacky, implements the 3.17 LSP
  spec.
- Introduce a server on the client side of the LSP communication to
  handle requests from the server back to our client. Should `csharp-ls`
  be sending us these requests? Probably not, see
  razzmatazz/csharp-language-server#100
- Wait until the server responds that the project is loaded before
  handing our service client back to whoever asked for it.
- Also do, what I think at least, are nifty tricks to put the stdio
  chatter client<->server in our logs.

Signed-off-by: David Zager <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants