`deoplete-lsp` incorrectly processes candidates when using `textEdit`
kdheepak opened this issue · comments
Thank you for writing deoplete-lsp
! With the built in neovim lsp source, deoplete will become an even more powerful completion framework ( if that's even possible :) )!
I think some fields in the response for deoplete-lsp are not being processed properly. This is an example of a response when I type pri
from LanguageServer.jl in a Julia buffer.
2020-06-10 06:46:38 [100] INFO {'isIncomplete': True, 'items': [{'label': 'primitive', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'mitive type $1\n $0\nend'}, 'documentation': 'primitive', 'kind': 14, 'insertTextFormat': 2}, {'label': 'printstyled', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'ntstyled'}, 'documentation': {'kind': 'markdown', 'value': '```\nprintstyled([io], xs...; bold::Bool=false, color::Union{Symbol,Int}=:normal)\n```\n\nPrint `xs` in a color specified as a symbol or integer, optionally in bold.\n\n`color` may take any of the values `:normal`, `:default`, `:bold`, `:black`, `:blink`, `:blue`, `:cyan`, `:green`, `:hidden`, `:light_black`, `:light_blue`, `:light_cyan`, `:light_green`, `:light_magenta`, `:light_red`, `:light_yellow`, `:magenta`, `:nothing`, `:red`, `:reverse`, `:underline`, `:white`, or `:yellow` or an integer between 0 and 255 inclusive. Note that not all terminals support 256 colors. If the keyword `bold` is given as `true`, the result will be printed in bold.\n'}, 'kind': 3, 'insertTextFormat': 2}, {'label': 'println', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'ntln'}, 'documentation': {'kind': 'markdown', 'value': '```\nprintln([io::IO], xs...)\n```\n\nPrint (using [`print`](@ref)) `xs` followed by a newline. If `io` is not supplied, prints to [`stdout`](@ref).\n\n### Examples\n\n```julia\njulia> println("Hello, world")\nHello, world\n\njulia> io = IOBuffer();\n\njulia> println(io, "Hello, world")\n\njulia> String(take!(io))\n"Hello, world\\n"\n```\n'}, 'kind': 3, 'insertTextFormat': 2}, {'label': 'print', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'nt'}, 'documentation': {'kind': 'markdown', 'value': '```\nprint([io::IO], xs...)\n```\n\nWrite to `io` (or to the default output stream [`stdout`](@ref) if `io` is not given) a canonical (un-decorated) text representation. The representation used by `print` includes minimal formatting and tries to avoid Julia-specific details.\n\n`print` falls back to calling `show`, so most types should just define `show`. Define `print` if your type has a separate "plain" representation. For example, `show` displays strings with quotes, and `print` displays strings without quotes.\n\n[`string`](@ref) returns the output of `print` as a string.\n\n### Examples\n\n```julia\njulia> print("Hello World!")\nHello World!\njulia> io = IOBuffer();\n\njulia> print(io, "Hello", \' \', :World!)\n\njulia> String(take!(io))\n"Hello World!"\n```\n'}, 'kind': 3, 'insertTextFormat': 2}]}
2020-06-10 06:46:38 [102] INFO {'label': 'primitive', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'mitive type $1\n $0\nend'}, 'documentation': 'primitive', 'kind': 14, 'insertTextFormat': 2}
2020-06-10 06:46:38 [102] INFO {'label': 'printstyled', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'ntstyled'}, 'documentation': {'kind': 'markdown', 'value': '```\nprintstyled([io], xs...; bold::Bool=false, color::Union{Symbol,Int}=:normal)\n```\n\nPrint `xs` in a color specified as a symbol or integer, optionally in bold.\n\n`color` may take any of the values `:normal`, `:default`, `:bold`, `:black`, `:blink`, `:blue`, `:cyan`, `:green`, `:hidden`, `:light_black`, `:light_blue`, `:light_cyan`, `:light_green`, `:light_magenta`, `:light_red`, `:light_yellow`, `:magenta`, `:nothing`, `:red`, `:reverse`, `:underline`, `:white`, or `:yellow` or an integer between 0 and 255 inclusive. Note that not all terminals support 256 colors. If the keyword `bold` is given as `true`, the result will be printed in bold.\n'}, 'kind': 3, 'insertTextFormat': 2}
2020-06-10 06:46:38 [102] INFO {'label': 'println', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'ntln'}, 'documentation': {'kind': 'markdown', 'value': '```\nprintln([io::IO], xs...)\n```\n\nPrint (using [`print`](@ref)) `xs` followed by a newline. If `io` is not supplied, prints to [`stdout`](@ref).\n\n### Examples\n\n```julia\njulia> println("Hello, world")\nHello, world\n\njulia> io = IOBuffer();\n\njulia> println(io, "Hello, world")\n\njulia> String(take!(io))\n"Hello, world\\n"\n```\n'}, 'kind': 3, 'insertTextFormat': 2}
2020-06-10 06:46:38 [102] INFO {'label': 'print', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'nt'}, 'documentation': {'kind': 'markdown', 'value': '```\nprint([io::IO], xs...)\n```\n\nWrite to `io` (or to the default output stream [`stdout`](@ref) if `io` is not given) a canonical (un-decorated) text representation. The representation used by `print` includes minimal formatting and tries to avoid Julia-specific details.\n\n`print` falls back to calling `show`, so most types should just define `show`. Define `print` if your type has a separate "plain" representation. For example, `show` displays strings with quotes, and `print` displays strings without quotes.\n\n[`string`](@ref) returns the output of `print` as a string.\n\n### Examples\n\n```julia\njulia> print("Hello World!")\nHello World!\njulia> io = IOBuffer();\n\njulia> print(io, "Hello", \' \', :World!)\n\njulia> String(take!(io))\n"Hello World!"\n```\n'}, 'kind': 3, 'insertTextFormat': 2}
This is an example of a single completion candidate:
{'label': 'println', 'textEdit': {'range': {'end': {'character': 3, 'line': 27}, 'start': {'character': 3, 'line': 27}}, 'newText': 'ntln'}, 'documentation': {'kind': 'markdown', 'value': '```\nprintln([io::IO], xs...)\n```\n\nPrint (using [`print`](@ref)) `xs` followed by a newline. If `io` is not supplied, prints to [`stdout`](@ref).\n\n### Examples\n\n```julia\njulia> println("Hello, world")\nHello, world\n\njulia> io = IOBuffer();\n\njulia> println(io, "Hello, world")\n\njulia> String(take!(io))\n"Hello, world\\n"\n```\n'}, 'kind': 3, 'insertTextFormat': 2}
In Julia println
is the function to print a string to stdout with a new line.
You'll notice that rec['textEdit']['newText'] == 'ntln'
because the user has already typed in pri
in the buffer. The Language Server Protocol says the following in the TextEdit
interface:
To insert text into a document create a range where start === end.
Which I'm understanding as rec['textEdit']['newText']
to contain the string that needs to be appended to the existing string.
In the current implementation of deoplete-lsp, this is currently not the case.
This causes word
to be set to ntln
. Which then gets filter out when using the fuzzy matcher filter in deoplete.
So these suggestions never appear in deoplete completions.
I've submitted a PR that resolves this particular issue when using the Julia LanguageServer.
This change falls back to the previous implementation if the range is different. I think something more sophisticated would need to be done in that case though. This is just a small improvement over the current implementation.
Thanks.
Thanks for merging!