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

Ensure view gets registered when tab is moved to create new window #1927

Merged
merged 2 commits into from
Jan 15, 2022

Conversation

jwortmann
Copy link
Member

This is a workaround for the following ST bug: sublimehq/sublime_text#4630

With this change, LspTextCommands still work after a tab is dragged out of a window to create a new window. For example lsp_hover will work again in such a case :)

The 1ms delay appears to be sufficient, so that this check still works:

if new_window.id() == old_window.id():

listeners = sublime_plugin.view_event_listeners.get(view.id())
if not isinstance(listeners, list):
return
for listener in listeners:
if isinstance(listener, DocumentSyncListener):
return listener.on_post_move_window_async()
# we need a small delay here, so that the DocumentSyncListener will recognize a possible new window
sublime.set_timeout_async(listener.on_post_move_window_async, timeout_ms=1)
Copy link
Member

Choose a reason for hiding this comment

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

We usually just skip the timeout argument. Should be equivalent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Should I remove or leave it? I figured it would be nice to see at first glance what this parameter "1" stands for.

Copy link
Member

Choose a reason for hiding this comment

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

You could skip the timeout value completely, including the number. I feel that that would be more meaningful since it would mean "as soon as possible after current message loop iteration finishes" instead of "after some arbitrary time".

In practice it would of course work the same pretty much.

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, that is not possible, see my comment in the line above. If there is no delay, the view.window() will still point to the old window, which will result the logic in DocumentSyncListener.on_post_move_window_async not working.
ST needs a little time (>0, but <1ms) after on_pre_move was fired, to create the new window (or to attach the tab to an existing window). At least it didn't work when I tested it without the 1ms delay.

Copy link
Member Author

Choose a reason for hiding this comment

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

With this 1ms delay we basically craft our own on_post_move_async, but without the bug from the same ST API function :)

Copy link
Member

Choose a reason for hiding this comment

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

If those two behave differently then it doesn't bode well for the reliability of this solution. It means it relies on some arbitrary time period that might not be guaranteed in all cases.

Copy link
Member Author

Choose a reason for hiding this comment

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

So what do you suggest then? Increase the delay to for example 5ms? Or keep the current behavior of LSP being mostly broken whenever a tab is dragged out of the window to create a new one?

Copy link
Member

@rchl rchl Jan 7, 2022

Choose a reason for hiding this comment

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

Tried this in safe mode on Mac and "no timeout" works the same as 1ms timeout in this simple case.
(Though I can imagine that different platforms might behave differently)

import sublime
import sublime_plugin

class Listener(sublime_plugin.EventListener):
    def on_pre_move(self, view):
        print('on_pre_move before', view.window())
        sublime.set_timeout_async(lambda: print('on_pre_move after timeout (0ms)', view.window()))
        sublime.set_timeout_async(lambda: print('on_pre_move after timeout (1ms)', view.window()), 1)

on_pre_move before Window(3)
on_pre_move after timeout (0ms) Window(6)
on_pre_move after timeout (1ms) Window(6)

Copy link
Member Author

Choose a reason for hiding this comment

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

I can confirm your results in safe mode on Windows, and surprisingly it seems to work for me in LSP without the delay as well now. But I can swear that when I tested this yesterday, that it didn't work for me without the delay. While I was debugging this, I even added a print statement in

LSP/plugin/documents.py

Lines 205 to 206 in 19a01aa

if new_window.id() == old_window.id():
return
and it would print everytime if, and only if I had not specified the delay.

When I use Tools > Developer > Profile plugins, it shows no other package under on_pre_move, which could possibly block the operation.

Not sure how we should proceed now. If we remove the delay, one option could be to keep the is_enabled: return True in the subclasses of LspTextCommand, for safety in case it doesn't work sometimes or for some users without the delay.

@rwols rwols merged commit ffd9068 into sublimelsp:main Jan 15, 2022
@jwortmann jwortmann deleted the move-tab-workaround branch January 16, 2022 11:06
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