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

Refactor code lenses #1755

Merged
merged 4 commits into from
Jun 19, 2021
Merged

Refactor code lenses #1755

merged 4 commits into from
Jun 19, 2021

Conversation

Rapptz
Copy link
Contributor

@Rapptz Rapptz commented Jun 19, 2021

This changes the following:

  • Code lens state is stored in its own class
  • Code lenses are moved to SessionView instead of DocumentSyncListener
  • The code lens debounce time is lowered to 300ms from 2300ms

I'm aware this is a big change. The development was discussed in the Discord server in preparation of allowing to render code lenses as phantoms. As a result the PR for that one is blocked until this one is finalised since it depends on the refactoring done here.

I tried my best to separate the code that dealt with the phantom representation but some of the data changes might still linger and seem bizarre.

This changes the following:

* Code lens state is stored in its own class
* Code lenses are moved to SessionView instead of DocumentSyncListener
* The code lens debounce time is lowered to 300ms from 2300ms
plugin/documents.py Outdated Show resolved Hide resolved
Comment on lines 343 to 351
def start_code_lenses_async(self) -> None:
...

def resolve_visible_code_lenses_async(self) -> None:
...

def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generator[CodeLens, None, None]:
...

Copy link
Member

Choose a reason for hiding this comment

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

I don't think these methods are required to be declared here? You should be able to remove them and mypy won't complain.

Copy link
Member

Choose a reason for hiding this comment

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

BTW, you can run tox locally to check mypy and flake8.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If they're not given a type error is given when you eventually access it down the chain since e.g. AbstractViewListener makes use of it and failing to meet that interface leads to a type error.

Copy link
Member

Choose a reason for hiding this comment

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

I see. get_resolved_code_lenses_for_region is used in the text command. start_code_lenses_async and resolve_visible_code_lenses_async can go away.

Comment on lines 518 to 523
def _do_code_lenses_async(self) -> None:
session = self.session_async("codeLensProvider")
if session and session.uses_plugin():
params = {"textDocument": text_document_identifier(self.view)}
for sv in self.session_views_async():
if sv.session == session:
for request_id, request in sv.active_requests.items():
if request.method == "codeAction/resolve":
session.send_notification(Notification("$/cancelRequest", {"id": request_id}))
name = session.config.name
session.send_request_async(
Request("textDocument/codeLens", params, self.view),
lambda r: self._on_code_lenses_async(name, r))

def _on_code_lenses_async(self, name: str, response: Optional[List[CodeLens]]) -> None:
for i in range(0, len(self._code_lenses)):
self.view.erase_regions(self._code_lens_key(i))
self._code_lenses.clear()
if not isinstance(response, list):
return
for index, c in enumerate(response):
region = range_to_region(Range.from_lsp(c["range"]), self.view)
self._code_lenses.append((c, region))
if "command" in c:
# We consider a code lens that has a command to be already resolved.
self._on_resolved_code_lens_async(name, index, region, c)
else:
self._render_code_lens(name, index, region, None)
self._code_lenses = list((c, range_to_region(Range.from_lsp(c["range"]), self.view)) for c in response)
self._resolve_visible_code_lenses_async()
sv.start_code_lenses_async()
Copy link
Member

Choose a reason for hiding this comment

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

Because the data is now stored in SessionView, can't we now request code lenses for all sessions attached to the view?

Comment on lines 527 to 530
if session and session.uses_plugin():
for sv in self.session_views_async():
if sv.session == session:
sv.resolve_visible_code_lenses_async()
Copy link
Member

Choose a reason for hiding this comment

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

resolve for all sessions attached to the view because the data is stored per session now?

Comment on lines 81 to 82
def _region_key(self, index: int) -> str:
return '{0}.{1}'.format(self.CODE_LENS_KEY, index)
Copy link
Member

Choose a reason for hiding this comment

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

We're still keying on only the index, not the session. Oh well, maybe for a next step.

Copy link
Member

@rwols rwols left a comment

Choose a reason for hiding this comment

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

Alright, let's roll with this. Couple things to do still:

  • it probably doesn't work with cloned views (it didn't work with cloned views before either I think), code lens data needs to move to SessionBuffer for that. SessionView is for presentation of the data
  • there's some flickering of the annotations when they're updated. Probably because they're updated from the worker thread.
  • we can actually request code lenses for all sessions, not just the most suited one

@rwols rwols merged commit 05d6462 into sublimelsp:main Jun 19, 2021
Comment on lines 309 to 310
def get_resolved_code_lenses_for_region(self, region: sublime.Region) -> Generator[CodeLens, None, None]:
yield from self._code_lenses.get_resolved_code_lenses_for_region(region)
Copy link
Member

@rchl rchl Jun 19, 2021

Choose a reason for hiding this comment

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

This code is equivalent to the old one so not a new issue but I don't really see the point of returning a generator when the caller is always gonna iterate through all the results anyway. I haven't measured it but it must be quite a bit slower than just returning a plain list or even a tuple.

litezzzout pushed a commit to litezzzout/LSP that referenced this pull request Jul 2, 2021
This changes the following:

* Code lens state is stored in its own class
* Code lenses are moved to SessionView instead of DocumentSyncListener
* The code lens debounce time is lowered to 300ms from 2300ms
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.

3 participants