-
Notifications
You must be signed in to change notification settings - Fork 182
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
Try to utilize LS completion textEdit if possible #295
Try to utilize LS completion textEdit if possible #295
Conversation
plugin/completion.py
Outdated
if last_row == start_row == end_row and start_col <= last_col: | ||
# sublime does not support explicit replacement with completion | ||
# at given range, but we try to trim the textEdit range and text | ||
# to the start location of the completion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using the LspApplyDocumentEditCommand
? (it's in edit.py
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that insert_text
is prepared for each completion before the choice is made by the user.
After choice is made Sublime simply replaces prefix with whatever was the completion text returned by plugin in previous step, at this point there is no way to run plugin callback such as LspApplyDocumentEditCommand
.
On the other hand language server does not know what is the prefix Sublime tries to complete, it does receive only the location you want to complete and knows document content, hence when you do $tru
CtrlSpace language server does not know if the prefix was tru
or $tru
.
In my Powershell example Sublime prefix is tru
however language server is returning $true
, and after completion we end up with $$true
(double dollar sign) instead $true
.
My PR uses extra information from textEdit
response (if present) to make sure the completion starts exactly where the prefix begins, so Sublime does the proper replacement.
It is not perfect solution, it does assumption that everything happens on single line, and may not work as intended in extreme cases e.g. if language server returns %true
for $tru
CtrlSpace, even it does not make sense, it will be still completed to $true
instead of %true
, but we can't do anything about this with the way Sublime currently handles completions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points.
ed368e8
to
a05eef6
Compare
FYI fixed |
019380a
to
a9e5f85
Compare
a9e5f85
to
aca4141
Compare
plugin/completion.py
Outdated
@@ -243,6 +243,24 @@ def format_completion(self, item: dict) -> 'Tuple[str, str]': | |||
hint = completion_item_kind_names[kind] | |||
# label is an alternative for insertText if insertText not provided | |||
insert_text = item.get("insertText") or label | |||
# try to handle textEdit if present | |||
text_edit = item.get("textEdit") | |||
if text_edit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we hide this behaviour behind a global LSP setting for now? I'd like to avoid hitting this code path automatically for all language servers that happen to send textEdit.
Additionally, can we extract the logic into a function returning an Optional[str]
, which is assigned to insert_text
if not None?
plugin/completion.py
Outdated
start_row, start_col = range_start.get("line"), range_start.get("character") | ||
end_row, end_col = range_end.get("line"), range_end.get("character") | ||
if all([start_row is not None, start_col is not None, | ||
end_row is not None, end_col is not None]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The range is probably specified to be required, in which case I like to avoid the None checks (I'm fine with errors from non-compliant servers).
There is existing logic for parsing ranges in protocol.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining the changes, sorry about the super late review!
@tomv564 No pbm for late review, I'll adapt my changes to your comments beginning of the next week. Cheers. |
aca4141
to
b94f8dc
Compare
Sublime Text does not support explicit replacement with completion at given range, instead it replaces current completion prefix with the completion text. Knowing the completion prefix boundaries at plugin side, we can trim textEdit range and text given by language server to the boundaries of the prefix. Fixes sublimelsp#294 E.g. for PowerShell grammar and PowerShellEditorServices LS: $tru<Ctrl+Space> (prefix "tru") -> now "true" instead of "$true" $env:U<Ctrl+Space> (prefix "U") -> now "USER" instead of "$env:USER"
b94f8dc
to
1993f04
Compare
@tomv564 I have applied your remarks to my patch, except your request to make
I think NOTE: I have also changed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing out the spec, sounds like defaulting to textEdit
is the preferred solution. Looks like tight code, too. Can you look at the comment I left about your escape fix?
if len(insert_text) > 0 and insert_text[0] == '$': # sublime needs leading '$' escaped. | ||
insert_text = '\$' + insert_text[1:] | ||
insert_text = '\\$' + insert_text[1:] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit worried about this change as it was a working fix for completions from PHP language servers. Can you tell me what is problematic, or should we take this change in a separate PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is just about escaping in Python -- '...'
still respects backslash escape codes, \$
is not proper escape code so Python leaves it as is, however Linters complain about this invalid escape code, hence backslash should be escaped, or raw Python string should be used.
@tomv564 Thanks a lot! |
Sublime Text does not support explicit replacement with completion at given range, instead it replaces current completion prefix with the completion text. Knowing the completion prefix boundaries at plugin
side, we can trim
textEdit
range and text given by language server to the boundaries of the prefix.Fixes #294
E.g. for PowerShell grammar and PowerShellEditorServices LS: