racket-langserver
racket-langserver copied to clipboard
Error with coc.nvim on windows
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.
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
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
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.)
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.
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?
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.
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.
I just had this same error with emacs and eglot. The fix with decode-uri worked for me.