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

Allow attaching to URI schemes other than the 'file' scheme #1758

Merged
merged 23 commits into from
Jun 29, 2021

Conversation

rwols
Copy link
Member

@rwols rwols commented Jun 20, 2021

This allows servers to attach to schemes like:

  • buffer: in-memory buffers
  • res: ST resource files in .sublime-packages
  • other foreign schemes, like deno, json-schema, jdt, etc

The way this works is that we have a new client configuration setting
called "schemes" which is a list of allowable URI schemes.

If "schemes" is not specified, then it's by default ["file"].

Resolves #1739

I've tried this with LSP-json, LSP-pyright and these language servers
are working well with non-file URIs. clangd on the other hand refuses
to work with in-memory buffers.

This allows servers to attach to schemes like:

- `buffer`: in-memory buffers
- `res`: ST resource files in .sublime-packages
- other foreign schemes, like `deno`, `json-schema`, `jdt`, etc

The way this works is that we have a new client configuration setting
called `"schemes"` which is a list of allowable URI schemes.

If `"schemes"` is not specified, then it's by default `["file"]`.
@rwols rwols requested a review from rchl June 20, 2021 12:49
Comment on lines 790 to 796
def _on_settings_object_changed(self) -> None:
new_syntax = self.view.settings().get("syntax")
if new_syntax != self._current_syntax:
self._current_syntax = new_syntax
self._cleanup()
self._setup()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have to unregister the listener and then register it back and trigger "on_activated" to trigger didOpen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need: container of SessionViews is cleared, _is_registered is set to False, and then on_activated_async is called by ST.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't checked but I've assumed that on_activated_async won't necessarily be called. Not unless the user changes the focus of the files manually.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 5294c95

@rchl
Copy link
Member

rchl commented Jun 21, 2021

Don't have time to investigate now but noticed that languageId is empty for LSP-eslint (at least in a Vue file).

@rwols
Copy link
Member Author

rwols commented Jun 25, 2021

@rchl in what circumstances is languageid empty? do you have an example?

@rchl
Copy link
Member

rchl commented Jun 25, 2021

We don't seem to be handling file renames and are sending the old file name to the server even after rename.

@rchl
Copy link
Member

rchl commented Jun 25, 2021

Also found some bad issue where LSP gets confused with what file (URI) was closed and reports one for a different file.

I'm not entirely sure how this happens but have sort of solid repro so can look closer when I have more time.

EDIT: It's probably related to backward-compatibility problem with files that were already open before those changes were introduced.

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

We don't seem to be handling file renames and are sending the old file name to the server even after rename.

Works fine for me in pyright:

::  -> LSP-pyright textDocument/didClose: {'textDocument': {'uri': 'buffer://sublime/156'}}
::  -> LSP-pyright textDocument/didOpen: {'textDocument': {'version': 15, 'text': 'import functools\n\n', 'uri': 'file:///Users/raoulwols/Desktop/test2.py', 'languageId': 'python'}}

pyright does have problems with publishing diagnostics though. It publishes diagnostics for file:///156 instead of buffer://sublime/156. I think that's a bug in pyright.

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

Saving existing files on disk to a different filename also works:

::  -> LSP-pyright textDocument/didClose: {'textDocument': {'uri': 'file:///Users/raoulwols/Desktop/test2.py'}}
::  -> LSP-pyright textDocument/didOpen: {'textDocument': {'languageId': 'python', 'version': 1, 'uri': 'file:///Users/raoulwols/Desktop/test3.py', 'text': 'import functools\n'}}

@rchl
Copy link
Member

rchl commented Jun 26, 2021

I don't mean saving files. I mean open a normal file and use rename command on it.

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

Seems to be missing callbacks in the ST API.

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

made an issue for it sublimehq/sublime_text#4540

@rchl
Copy link
Member

rchl commented Jun 26, 2021

Instead of waiting for a fix in ST, maybe we should consider only falling back to a saved URI when the file has no filename so that we in most cases always access native view.file_name(). Otherwise it's easy for regressions and corner cases to bite us (besides the already mentioned one).

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

maybe we should consider only falling back to a saved URI when the file has no filename

Sorry, could you expand more on what you mean here?

@rchl
Copy link
Member

rchl commented Jun 26, 2021

Basically what I'm thinking is to only set lsp_uri in the view if the view has no file name. Then the get_uri method would get the lsp_uri from view, if set, otherwise calculate the URI from view.file_name() each time.

I'm not sure how much of a performance impact it would have but it would ensure that we always ask the real source of truth for the file name instead of relying on our cached value and having to worry about invalidating it in all cases.

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

Trying to figure out why the CI fails

@rwols
Copy link
Member Author

rwols commented Jun 26, 2021

Something in 3a495bc makes the CI fail spectacularly :D

@rwols rwols requested a review from rchl June 27, 2021 21:54
@rchl
Copy link
Member

rchl commented Jun 27, 2021

What's your plan regarding this issue: #1758 (comment) ?

Integrate with that flaw, wait or have my suggested workaround?

While previously we didn't detect the renames either (I guess those would ideally trigger didClose and didOpen), now renames cause various errors with various servers (I guess because we notify about file that is no longer on disk).

@rwols
Copy link
Member Author

rwols commented Jun 27, 2021

I would go ahead with this in spite of not handling renames as it doesn’t work on main as well.

Comment on lines 35 to +49
def uri_to_filename(uri: str) -> str:
"""
DEPRECATED: An URI associated to a view does not necessarily have a "file:" scheme.
Use urllib.parse.urlparse to determine the scheme and go from there.
Use urllib.parse.unquote to unquote the path.
"""
parsed = urlparse(uri)
assert parsed.scheme == "file"
if os.name == 'nt':
# url2pathname does not understand %3A (VS Code's encoding forced on all servers :/)
return url2pathname(parsed.path).strip('\\')
else:
return url2pathname(parsed.path)


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have an alternative helper function for getting filename from URI? I'd need to use something in eslint.

Having to play with urllib doesn't sound like fun and also I wonder if such helper needs to apply some path transformations to stay consistent.

I imagine such helper could return a tuple with scheme and file path (if file scheme at least).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also do that in another PR?

@rchl
Copy link
Member

rchl commented Jun 28, 2021

I would go ahead with this in spite of not handling renames as it doesn’t work on main as well.

But I could argue that the situation is worse now. Previously at least the server would more or less happily work after rename. Now there are errors like:

LSP-eslint: ENOENT: no such file or directory, realpath '/xxx/app/pages/notifications.vue'

Though, won't hold it against this change as previous behavior wasn't perfect either.

@rwols rwols merged commit 7673446 into main Jun 29, 2021
@rwols rwols deleted the feat/attach-to-non-file-uris branch June 29, 2021 20:12
litezzzout pushed a commit to litezzzout/LSP that referenced this pull request Jul 2, 2021
…sp#1758)

This allows servers to attach to schemes like:

- `buffer`: in-memory buffers
- `res`: ST resource files in .sublime-packages
- other foreign schemes, like `deno`, `json-schema`, `jdt`, etc

The way this works is that we have a new client configuration setting
called `"schemes"` which is a list of allowable URI schemes.

If `"schemes"` is not specified, then it's by default `["file"]`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Attach to non-files
2 participants