racket-langserver icon indicating copy to clipboard operation
racket-langserver copied to clipboard

Error with coc.nvim on windows

Open s-cerevisiae opened this issue 4 years ago • 8 comments

I tried to use racket-langserver with coc.nvim, but it doesn't seem to work. (I'm on windows with racket 8.0) Log:

Caught exn:
current-load-relative-directory: contract violation
  expected: (or/c (and/c path-string? complete-path?) #f)
  given: #<path:g%3A/Programming/Racket/misc/>
  context...:
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\check-syntax.rkt:82:0: check-syntax
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\text-document.rkt:86:0: did-open!
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   [repeats 1 more time]
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\main.rkt:53:2: consume

Caught exn:
hash-ref: no value found for key
  key: 'file:///g%3A/Programming/Racket/misc/test.rkt
  context...:
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\text-document.rkt:102:0: did-change!
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   [repeats 1 more time]
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\main.rkt:53:2: consume

The incorrectly encoded colon (%3A) is suspicious but I couldn't find where it is produced.

PS: Everything works fine for me with VSCode and Magic Racket.

s-cerevisiae avatar Apr 17 '21 11:04 s-cerevisiae

Can you grab a log of the JSON/LSP requests that are being sent? I have a theory that there's a URL that is being encoded by the client and not decoded by server

jeapostrophe avatar Apr 17 '21 15:04 jeapostrophe

The verbose mode output with JSON requests and responses:

[Trace - 下午1:35:45] Sending request 'initialize - (0)'.
Params: {
    "processId": 25664,
    "rootPath": "g:\\Programming\\Racket\\misc",
    "rootUri": "file:///g%3A/Programming/Racket/misc",
    "capabilities": {
        "workspace": {
            "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,
                        18,
                        19,
                        20,
                        21,
                        22,
                        23,
                        24,
                        25,
                        26
                    ]
                },
                "tagSupport": {
                    "valueSet": [
                        1
                    ]
                }
            },
            "executeCommand": {
                "dynamicRegistration": true
            },
            "configuration": true,
            "workspaceFolders": true
        },
        "textDocument": {
            "publishDiagnostics": {
                "relatedInformation": true,
                "versionSupport": false,
                "tagSupport": {
                    "valueSet": [
                        1,
                        2
                    ]
                }
            },
            "synchronization": {
                "dynamicRegistration": true,
                "willSave": true,
                "willSaveWaitUntil": true,
                "didSave": true
            },
            "completion": {
                "dynamicRegistration": true,
                "contextSupport": true,
                "completionItem": {
                    "snippetSupport": true,
                    "commitCharactersSupport": true,
                    "documentationFormat": [
                        "markdown",
                        "plaintext"
                    ],
                    "deprecatedSupport": true,
                    "preselectSupport": true,
                    "tagSupport": {
                        "valueSet": [
                            1
                        ]
                    }
                },
                "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,
                "contextSupport": true,
                "signatureInformation": {
                    "documentationFormat": [
                        "markdown",
                        "plaintext"
                    ],
                    "activeParameterSupport": true,
                    "parameterInformation": {
                        "labelOffsetSupport": true
                    }
                }
            },
            "definition": {
                "dynamicRegistration": true
            },
            "references": {
                "dynamicRegistration": 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,
                        18,
                        19,
                        20,
                        21,
                        22,
                        23,
                        24,
                        25,
                        26
                    ]
                },
                "hierarchicalDocumentSymbolSupport": true,
                "tagSupport": {
                    "valueSet": [
                        1
                    ]
                }
            },
            "codeAction": {
                "dynamicRegistration": true,
                "isPreferredSupport": true,
                "codeActionLiteralSupport": {
                    "codeActionKind": {
                        "valueSet": [
                            "",
                            "quickfix",
                            "refactor",
                            "refactor.extract",
                            "refactor.inline",
                            "refactor.rewrite",
                            "source",
                            "source.organizeImports"
                        ]
                    }
                }
            },
            "codeLens": {
                "dynamicRegistration": true
            },
            "formatting": {
                "dynamicRegistration": true
            },
            "rangeFormatting": {
                "dynamicRegistration": true
            },
            "onTypeFormatting": {
                "dynamicRegistration": true
            },
            "rename": {
                "dynamicRegistration": true,
                "prepareSupport": true
            },
            "documentLink": {
                "dynamicRegistration": true,
                "tooltipSupport": true
            },
            "typeDefinition": {
                "dynamicRegistration": true
            },
            "implementation": {
                "dynamicRegistration": true
            },
            "declaration": {
                "dynamicRegistration": true
            },
            "colorProvider": {
                "dynamicRegistration": true
            },
            "foldingRange": {
                "dynamicRegistration": true,
                "rangeLimit": 5000,
                "lineFoldingOnly": true
            },
            "selectionRange": {
                "dynamicRegistration": true
            }
        },
        "window": {
            "workDoneProgress": true
        }
    },
    "initializationOptions": {},
    "trace": "verbose",
    "workspaceFolders": [
        {
            "uri": "file:///g%3A/Programming/Racket/misc",
            "name": "misc"
        }
    ],
    "clientInfo": {
        "name": "coc.nvim",
        "version": "0.0.80"
    },
    "workDoneToken": "547fe8d9-a9f9-4bec-ace5-09abf23e221d"
}


[Trace - 下午1:35:49] Received response 'initialize - (0)' in 3813ms.
Result: {
    "capabilities": {
        "completionProvider": {
            "triggerCharacters": [
                "("
            ]
        },
        "definitionProvider": true,
        "documentFormattingProvider": true,
        "documentHighlightProvider": true,
        "documentOnTypeFormattingProvider": {
            "firstTriggerCharacter": ")",
            "moreTriggerCharacter": [
                "\n",
                "]"
            ]
        },
        "documentRangeFormattingProvider": true,
        "documentSymbolProvider": true,
        "hoverProvider": true,
        "referencesProvider": true,
        "renameProvider": {
            "prepareProvider": true
        },
        "signatureHelpProvider": {
            "triggerCharacters": [
                " ",
                ")",
                "]"
            ]
        },
        "textDocumentSync": {
            "change": 2,
            "openClose": true,
            "willSave": false,
            "willSaveWaitUntil": false
        }
    }
}


[Trace - 下午1:35:49] Sending notification 'initialized'.
Params: {}


[Trace - 下午1:35:49] Sending notification 'textDocument/didOpen'.
Params: {
    "textDocument": {
        "uri": "file:///g%3A/Programming/Racket/misc/test.rkt",
        "languageId": "racket",
        "version": 1,
        "text": "#lang racket\n\n(define hello\n  \"hello world\")\n"
    }
}



Caught exn:
current-load-relative-directory: contract violation
  expected: (or/c (and/c path-string? complete-path?) #f)
  given: #<path:g%3A/Programming/Racket/misc/>
  context...:
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\check-syntax.rkt:82:0: check-syntax
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\text-document.rkt:86:0: did-open!
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   [repeats 1 more time]
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\main.rkt:53:2: consume

[Trace - 下午1:35:55] Sending request 'textDocument/documentHighlight - (1)'.
Params: {
    "textDocument": {
        "uri": "file:///g%3A/Programming/Racket/misc/test.rkt"
    },
    "position": {
        "line": 0,
        "character": 0
    }
}


Caught exn in request "textDocument/documentHighlight"
hash-ref: no value found for key
  key: 'file:///g%3A/Programming/Racket/misc/test.rkt
  context...:
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\text-document.rkt:367:0: get-decl
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\text-document.rkt:291:0: document-highlight
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\methods.rkt:26:0: process-message
   D:\Racket\collects\racket\contract\private\arrow-val-first.rkt:486:18
   C:\Users\Spore\AppData\Roaming\Racket\8.0\pkgs\racket-langserver\main.rkt:53:2: consume

[Trace - 下午1:35:55] Received response 'textDocument/documentHighlight - (1)' in 2ms. Request failed: internal error in method "textDocument/documentHighlight" (-32603).
[Error  - 下午1:35:55] Request textDocument/documentHighlight failed.
  Message: internal error in method "textDocument/documentHighlight"
  Code: -32603 

s-cerevisiae avatar Apr 18 '21 05:04 s-cerevisiae

Well, quite confirmed. I added uri-decode in uri->path function and it works (but only for coc.nvim) now.

(define (uri->path encoded-uri)
  (define uri (uri-decode encoded-uri))
  (cond
    [(eq? (system-type 'os) 'windows)
     ;; If a file URI begins with file:// or file:////, Windows translates it
     ;; as a UNC path. If it begins with file:///, it's translated to an MS-DOS
     ;; path. (https://en.wikipedia.org/wiki/File_URI_scheme#Windows_2)
     (cond
       [(string-prefix? uri "file:////") (substring uri 7)]
       [(string-prefix? uri "file:///") (substring uri 8)]
       [else (string-append "//" (substring uri 7))])]
    [else (substring uri 7)]))

It seems that Magic Racket's behavior (not encoding the uri) is the incorrect one according to the spec, and that's because it was influenced by racket-langserver... (See this issue.)

s-cerevisiae avatar Apr 18 '21 06:04 s-cerevisiae

This seems to be a problem in vscode-uri (which is used by coc.nvim) with a long history: https://github.com/microsoft/vscode-languageserver-node/issues/228, https://github.com/microsoft/vscode/issues/75027, https://github.com/microsoft/vscode/issues/2990

Since VSC stores lots of metadata by string URIs, they were never able to fix the default behavior, so instead they added a toString override toString(true) to get "correct" behavior. That is to say, sending the language server uri-encoded colons in drive letters is definitely not to spec (RFC-3986 defers to RFC-8089 for file scheme uris), but I guess most language servers uri decode anyway so it's not noticed.

Magic Racket uses the toString(true) override and most other language clients don't seem to contain this incorrect encoding, hence why the issue seems to only appear in coc.nvim (which uses the faulty behavior of vscode-uri but without an override option).

That all being said, we should just uri-decode anyway as it's correct to do so by the spec.

Runi-c avatar Apr 18 '21 20:04 Runi-c

That's shocking. I had never thought of the official implementation could be incorrect...

just uri-decode anyway

But wouldn't this cause potential bug between "decoding server" and "not encoding clients" since "%" is allowed in file path?

s-cerevisiae avatar Apr 19 '21 02:04 s-cerevisiae

Ah. I expected the official client to encode spaces and "%"s, but it appears to just send them as plaintext. So you're right, we shouldn't just uri-decode. I wonder how other language servers work with coc.nvim given this disparity? :/

Edit: Oops, turns out that toString() override I mentioned is literally just a switch to disable encoding the URI. That's why when I tested it the percent-sign etc. aren't encoded.

Runi-c avatar Apr 19 '21 03:04 Runi-c

how other language servers work with coc.nvim given this disparity?

It seems that not only coc.nvim but also vscode default to this. Here're their solutions. For coc.nvim an extension can be made to alter the client's behavior though.

s-cerevisiae avatar Apr 19 '21 04:04 s-cerevisiae

I just had this same error with emacs and eglot. The fix with decode-uri worked for me.

egelja avatar Feb 02 '23 16:02 egelja