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

LanguageServer only works with VSCode #34523

Closed
onur opened this issue Dec 21, 2019 · 52 comments
Closed

LanguageServer only works with VSCode #34523

onur opened this issue Dec 21, 2019 · 52 comments
Assignees
Milestone

Comments

@onur
Copy link
Contributor

onur commented Dec 21, 2019

Godot version: Godot Engine v3.2.beta4.official

OS/device including version: Debian GNU/Linux sid

Issue description:

I tried to use Godot Language Server with coc.nvim and LanguageClient-neovim clients. Godot is returning this error when clients sends initialize method:

ERROR: _parse_request: Not enough response headers, got: 1, expected >= 4.
   At: modules/websocket/wsl_server.cpp:49.

This is the assert line it's failing: wsl_server.cpp:49. Both clients are only sending Content-Lenght header and nothing else and godot is expecting more.

This is the request client is sending:
T 127.0.0.1:54458 -> 127.0.0.1:6008 [AP] #94
  Content-Length: 2601....                                                                                                                                                                  
##
T 127.0.0.1:54458 -> 127.0.0.1:6008 [AP] #96
  {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":1522387,"rootPath":"/home/onur/gamedev/04-tycoon","rootUri":"file:///home/onur/gamedev/04-tycoon","capabilities":{"wor
  kspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"
  dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,1
  8,19,20,21,22,23,24,25,26]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true},
  "synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"s
  nippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true},"completionItemKind":{"valueSet":[1,2,
  3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true
  ,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true}}},"definition":{"dynamicRegistration":true},"references":{"dyna
  micRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,1
  8,19,20,21,22,23,24,25,26]}},"codeAction":{"dynamicRegistration":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inli
  ne","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":tr
  ue},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true},"typeDefinition":{"dynamicRegi
  stration":true},"implementation":{"dynamicRegistration":true},"declaration":{"dynamicRegistration":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration
  ":true,"rangeLimit":5000,"lineFoldingOnly":true}}},"initializationOptions":{},"trace":"verbose","workspaceFolders":[{"uri":"file:///home/onur/gamedev/04-tycoon","name":"04-tycoon"}]}}   
#

cc @Faless

@Faless
Copy link
Collaborator

Faless commented Dec 22, 2019

@onur I don't know much about the LSP, but the WebSocketServer, expects a valid websocket client handshake. A valid and minimal WebSocket handshake is like this:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Maybe your LanguageClient does not use websocket as a transport for LSP?

@onur
Copy link
Contributor Author

onur commented Dec 22, 2019

@Faless that's the issue right there, Godot's Language Server is not actually a Language Server, it is a websocket server. According to LSP Specification a Language Server only supports two headers: Content-Lenght and Content-Type. IDK why godot requires a websocketserver on top of this.

None of the clients (except godot's vscode plugin) using a protocol like this to communicate a Language Server.

@Faless
Copy link
Collaborator

Faless commented Dec 22, 2019 via email

@Zylann
Copy link
Contributor

Zylann commented Dec 23, 2019

Maybe websocket ended up being the choice because the subject was VSCode, which is built with web technology?

@Geequlim
Copy link
Contributor

@Faless that's the issue right there, Godot's Language Server is not actually a Language Server, it is a websocket server. According to LSP Specification a Language Server only supports two headers: Content-Lenght and Content-Type. IDK why godot requires a websocketserver on top of this.

I think the LSP only specifies the message content format. It doesn't force implementations to use what kind of the connection method. I choose the websocket as it is quite simple for the implementation of both the server and the client (The VSCode extention). With websocket is is easy to allow multi-clients.

The LSP is designed to reduce the work of editor plugins which doesn't mean the client don't need to do anything.

@Geequlim
Copy link
Contributor

And the GDScript Language Server is not work only with VSCode but also with Atom
https://github.com/PrestonKnopp/language-gdscript

If your client does not support Websocket there are two main ways to connect to the GDScript language servser

  1. Make a middleware for connecting to GDScript language service through websocket, and connect to the client through the methods supported by your editor.
  2. If most of client support TCP connecting out of box. We can consider replacing the websocket server with a TCP server, but the existing clients must be refactored.

@habamax
Copy link

habamax commented Jan 26, 2020

If your client does not support Websocket there are two main ways to connect to the GDScript language servser

That is sad. I was waiting for godot language server thinking I would be able to use it with vim.

I guess emacs folks will not be able to use it as well. (don't remember if emacs has websocket implementation)

PS, don't get me wrong, I use vim now for gdscript and will continue using it no matter if godot language server would be implemented in a websocket only way.

PPS, thanks for language server!

@Calinou
Copy link
Member

Calinou commented Jan 27, 2020

@Geequlim How much work would it be to add LSP communication using HTTP requests? It's probably a bit slower than WebSocket, but it should be far easier to integrate into most editors. If the latency difference is large enough, we can keep both implementations.

@Geequlim
Copy link
Contributor

Geequlim commented Jan 28, 2020

@Calinou I'm not sure it is possible with HTTP because both the server and the client need to send messages to each other realtime

@habamax
Copy link

habamax commented Jan 28, 2020

Not sure about HTTP, but there are language servers that does both stdio and socket communications. For example, solargraph of ruby https://github.com/castwide/solargraph

 Clients can connect using either stdio or TCP

I don't know how websocket is different with regular socket, though

@howdoicomputer
Copy link

@NathanLovato
Copy link
Contributor

I can confirm the issue. @ofrank123 told me that according to the Language Server specification, the server should accept messages starting with the Content-Length: header, but that the GDScript LSP server does not.

lsp-mode for Emacs does only support TCP right now, but the maintainer was saying he was okay with the idea of adding web socket support. On the other hand, most language servers I've seen out there communicate over TCP. So I'd expect also most editors to expect and support TCP rather than web-sockets by default.

@CyanBlob
Copy link
Contributor

I think moving to TCP makes more sense, given how much more popular it seems for language clients. I could potentially work on this but I wouldn't expect to get anything done anytime soon. Unfortunately, I've been pretty busy recently

@NathanLovato
Copy link
Contributor

If there's a consensus to move to TCP and there's someone who wants to take on that, I'd gladly sponsor the work through GDQuest. That is, up to some amount at least, depending on the scope of the task, as we are running on a limited budget.

@Geequlim @Faless may either of you be interested, or may you know someone who could do it?

@Geequlim
Copy link
Contributor

Geequlim commented Feb 1, 2020

@NathanLovato For me it is about two full day of work to replace it to raw tcp for the server and the vscode plugin. But I can't find time to do it before February 21.

@NathanLovato
Copy link
Contributor

@Geequlim Thanks for the info. 🙂

@ofrank123 said he would get a fork and PR started for that moments ago.

@avahe-kellenberger
Copy link

Very excited to see this being looked into, thanks everyone. If there's a way to help sponsor/support the work specifically for the language server, I'd like to know.

@CyanBlob
Copy link
Contributor

CyanBlob commented Feb 3, 2020

Work is being tracked in this PR: #35864
@ofrank123 seems to be almost finished with it. Their current PR doesn't support multiple clients, but we're not sure if anybody would mind losing that functionality or not. If you do, what's your use case?

@Faless
Copy link
Collaborator

Faless commented Feb 3, 2020 via email

@avahe-kellenberger
Copy link

Is that a common use case?

@CyanBlob
Copy link
Contributor

CyanBlob commented Feb 3, 2020

@Faless Why do you need/want to run two instances of vim? Do other language servers allow this?

@habamax
Copy link

habamax commented Feb 3, 2020

@Faless Why do you need/want to run two instances of vim? Do other language servers allow this?

Well this is quite common. I usually do have more than 1 vim instances open.

And yes other, I would say most of the servers are ok with it.

@NathanLovato
Copy link
Contributor

NathanLovato commented Feb 3, 2020

What about running two instances of vim?

For vim it's normal to run multiple instances, e.g. use tmux or a program like tilix to have several tabs or sessions running in parallel, and to pop in and out of vim.

For emacs you typically use a daemon, as with many packages it becomes slow to load. But you can run several servers or open a single gui process as well. So no problem with that.

If that's enough to have two Godot projects open in parallel with completion, that sounds good to me.

@Faless
Copy link
Collaborator

Faless commented Feb 3, 2020 via email

@avahe-kellenberger
Copy link

I could see that when working on multiple projects at once.

@CyanBlob
Copy link
Contributor

CyanBlob commented Feb 4, 2020

I just tested your new changes and it seems to be working great, multiple clients and all! Thanks for implementing this :)
I'll go ahead and add instructions for coc.nvim, since this wasn't very clear to me:
You need to add a custom language server (in CocConfig)

"languageserver": {
    "godot": {
      "host": "127.0.0.1",
      "filetypes": ["gd", "gdscript3"],
      "port": 6008
    }
  }

The filetype is not necessarily the same as the file extension. By default, vim doesn't assign a filetype to .gd files. You can set that up however you want, but this plugin does it for you, along with adding syntax highlighting: https://github.com/calviken/vim-gdscript3

@ofrank123
Copy link
Contributor

Awesome! Glad to hear it's working for you! I might try messing with the VSCode and Atom plugins to see if I can get them to work, but no promises as I've never worked with those editors.

@0xh007
Copy link

0xh007 commented Feb 10, 2020

Fantastic work everyone! I've been keeping an eye out for anything like this for probably a year now. Great to hear we've got it now. Thanks!

@Shatur
Copy link
Contributor

Shatur commented Feb 15, 2020

@CyanBlob, it works for me too, but I also see [coc.nvim] Command: not found error after completion. Do you have this behavior too?

@mlvl42
Copy link

mlvl42 commented Apr 18, 2020

I was making a quick and dirty port of the vscode extension to coc.nvim when I stumbled upon this issue, switching from websocket to tcp is awesome news !
While we wait for the 3.2.2 release, perhaps this could help some vim users https://github.com/j3d42/coc-godot

@rafaeldelboni
Copy link
Contributor

I've been using Godot + Nvim, since this merge #35864, and is being a lovely experience!

@Rybadour
Copy link

Rybadour commented Apr 22, 2020

As a fellow Vim user this is excellent news! Thanks everyone!

@Calinou
Copy link
Member

Calinou commented Jul 18, 2020

This was resolved in 3.2.2 by #35864, closing. Please create new issues in editor extensions' repositories if you can encounter any.

@Calinou Calinou closed this as completed Jul 18, 2020
@Calinou Calinou added archived and removed archived labels Jul 18, 2020
@Calinou Calinou added this to the 3.2 milestone Jul 18, 2020
@TobiasDev
Copy link

I've been using Godot + Nvim, since this merge #35864, and is being a lovely experience!

@rafaeldelboni sorry to call you out like this, but I can't get auto-complete to work in my NVIM, would you mind sharing your how you got it to work?

I added this to my Exec Flags like stated in the documentation: "+call cursor({line}, {col})" {file} and changed Exec Path to my nvim-qt.exe.

Not sure if I need anything else? I have tried both with coc-godot installed and without it. Neither of them works for me. :(

@rafaeldelboni
Copy link
Contributor

Hey hello Tobias, how you doing? No problem, could you double check your godot version is above 3.2.2 and if your coc-settings is looking similar to mine? Btw you could double check my init.nvim, I don't use coc-godot, just vannila coc.nvim and some other vim plugins.

I tested my setup yesterday with the current godot and everything was working fine :)

https://github.com/rafaeldelboni/dotfiles/blob/299e8a9f32446b272613ff1f133dc0b0db30b2fb/config/nvim/coc-settings.json#L12

@TobiasDev
Copy link

Hey hello Tobias, how you doing? No problem, could you double check your godot version is above 3.2.2 and if your coc-settings is looking similar to mine? Btw you could double check my init.nvim, I don't use coc-godot, just vannila coc.nvim and some other vim plugins.

I tested my setup yesterday with the current godot and everything was working fine :)

https://github.com/rafaeldelboni/dotfiles/blob/299e8a9f32446b272613ff1f133dc0b0db30b2fb/config/nvim/coc-settings.json#L12

Wow! Thanks! Using your CocConfing instantly fixed the issue for me. :) And even started showing me warnings and errors etc.!

Thank you once again! Now I can finally use Godot and NeoVim together!!! :) This made my day.

@khalid151
Copy link

khalid151 commented Aug 16, 2020

I'm using neovim with coc-nvim and suggestions work but I get Command: not found upon completion (C-y).
Screenshot_20200816_230214

Edit:
This is a workaround for the time being, for my <CR> mapping:

inoremap <expr> <CR> complete_info().selected != -1 ?
            \ &filetype == "gdscript" ? (coc#expandable() ?  "\<C-y>" : "\<Esc>a") : "\<C-y>"
            \ : "\<C-g>u\<CR>"

@sQu1rr
Copy link

sQu1rr commented Nov 29, 2020

@khalid151 how does it work? In particular, what does the C-g u\ does? And what does coc#expandable() do (which didn't work for me)?
I modified it to be

inoremap <expr> <CR> complete_info().selected != -1 ? "\<Esc>a" : "\<C-g>u\<CR>"

and placed it in after/ftplugin/gdscript.vim

@khalid151
Copy link

@sQu1rr It first checks if there's a completion menu open and there's an item selected with complete_info().
If there is, coc#expandable() will check if the current entry is a snippet to expand it. When there is no item selected and <CR> is needed, "\<C-g>u\<CR>" is run.

As I understood, <C-g>u is there to help with undo sequence. (here's the patch info that introduced this mapping)

@kovasap
Copy link

kovasap commented Jun 15, 2021

Has anyone gotten this to work with neovim's native LSP (not CoC), for instance like these language servers: https://github.com/neovim/nvim-lspconfig?

@beyarkay
Copy link
Contributor

beyarkay commented Sep 3, 2023

Anyone coming from Godot 4, note that the port has changed to 6005 and you'll want to use the filetype "gdscript":

  "languageserver": {
    "godot": {
      "host": "127.0.0.1",
      "filetypes": ["gd", "gdscript"],
      "port": 6005
    }
  }

You can change your LSP settings for godot by going to Editor > Editor Settings > Network > Language Server.

And you can setup neovim as an external editor for godot by:

  1. Navigating to the directory containing project.godot and running the command nvim --listen ./godothost
  2. Going to the settings menu at Editor > Editor Settings > General > Text Editor > External
  3. Tick Use external editor
  4. Set Exec Path to either nvim or the full nvim path. My full nvim path is /opt/homebrew/bin/nvim
  5. Set the Exec Flags to --server ./godothost --remote-send "<C-\><C-N>:n {file}<CR>{line}G{col}|"

Now, when you click to open a gdscript file in Godot, neovim will jump to that location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests