-
Notifications
You must be signed in to change notification settings - Fork 41
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
Multiple event hooks don't work with clones #289
Comments
Workaround: view = sublime.active_window().active_view() |
Ah nice, this seems to work (even the simple version). |
on_activated will work always, but on on_post_save will work only if the view has focus. (imagine a Save all action will not get the expected result...) |
unhighlight when unselecting with arrow keys sometimes, with workaround from sublimehq/sublime_text#289 Multiple event hooks don't work with clones
Extending titoBouzout's fix also for output panels and widgets:
The |
Note that you probably shouldn't do anything in your listener if you encounter widgets or panels when you are filtering them out. |
from sublimehq/sublime_text#289 Multiple event hooks don't work with clones
So currently this affects:
The reason is, these are "text buffer" events, and multiple views into a file doesn't change the fact that they all share a single text buffer. The question, to me, is if these should ever be called on a clone? The ViewEventListener has the concept of |
Not sure whether all plugins implement the one buffer multiple view infrastructure under all circumstances. GitGutter for instance is organized to work on each view separately. It relies on A plugin should be able to decide whether to handle the events by separate ViewEventListeners with _ ... or maybe by a Another argument might be the type of those events not to be too obvious as the hooks receive a |
For my plugin, I'd like |
The selection is the property of a view, not a buffer, so The situation has improved greatly with ViewEventListeners, which allow you to track state for a view, but there are still situations they don't handle. For example, if you only need to do something when Furthermore, some additional documentation for |
You are right and the current behavior of working with "text buffer" is correct. However, as was demonstrated by @FichteFoll on #1253 (comment), the actual problem is that the view passed on As can be seem the first issue (or at least close to the first issue) I opened on some Sublime Text package 3 years ago: facelessuser/BracketHighlighter#356 Highlight not working on multiples files The package developer just closed the issue as a bug on Sublime Text:
At the time, nobody understood what was happening and the issue get closed. Only now, we can understand why the plugin was not working. The event was being called, but not with the active view, but with the primary view. And this is how I fix all my plugins, instead of using the view passed by the It should not be required for the primary view to be passed on the |
Maybe a simple enough workaround for some certain plugins, but I'd expect to always work on the What if both views are visible, but none is active? The Both the primary view and its clone(s) may be visible at the same time (e.g.: next to each other in a 2-column layout) showing the same lines of the buffer. Modifying one of the views, causes the diff gutter (internal diff feature) of both views to be updated simultanously. A plugin should be able to do the same. A linter for instance calls Either way. The type of event would need a clear documentation. |
To add 2ct. The concept of an active view is misleading here. These are low-level events and can come from any view. In SublimeLinter we usually only care about events from the active view and we have synthesized events for that. What I don't like is the double, quadruple calling here. (E.g. iirc you click with a mouse you get two 'selection-changed' events per view into the same buffer but all events refer the primary view.) Implementing a throttler/guard all the time is error-prone and seems unnecessary, and honestly most plugins don't do that. Only for the 'selection-changed' event, calling it with the primary view is a bug. |
So far I remember, always I call try:
from FixedToggleFindPanel.fixed_toggle_find_panel import is_panel_focused
except ImportError as error:
print( 'WordHighlightOnSelection Error: Could not import the FixedToggleFindPanel package!', error )
def is_panel_focused():
return False
# ...later on
def on_selection_modified(self, view):
if not is_panel_focused():
window = view.window() or sublime.active_window()
view = window.active_view() References:
Lovely put. If I have 10 clones into a view, I get # I am saving the state in this class because it is a royal pain in the ass
# to keep typing `global` every time/everywhere I would like to use a global!
class State(object):
lasttime = time.time()
# ...later on
def on_selection_modified(self, view):
if view.settings().get('is_widget'):
return
timenow = time.time()
if timenow - State.lasttime < 0.5:
return
State.lasttime = timenow
I would prefer the latter. Each view At least for now, only one thing makes sense. This behavior of
Indeed. This hack just makes the problem goes "unnoticed" for certain plugins and cases. |
Createing a list of clones would be possible with existing APIs already. In order to avoid object creation overhead a method # sublime.py
class View:
def clones(self):
my_buffer_id = self.buffer_id()
return [
View(view_id)
for window_id in sublime_api.windows()
for view_id in sublime_api.window_views(window_id)
if view_id != self.view_id and my_buffer_id == sublime_api.view_buffer_id(view_id)
]
It's not a question about whether a view is renturned but whether the event_handler acts on the correct or relevant view then.
Agree. |
Here is the related PackageDev issue SublimeText/PackageDev#142 suffering from this core issue. |
Each cloned view receives the events in question with the correct view object being passed. It's up to a plugin to handle or ignore the event for all, the active or the primary view only. class MyListener(sublime_plugin.EventListener):
def on_reload(self, view):
print(f"on_reload View {view.id()} : {view.file_name()}.")
def on_selection_modified(self, view):
if not view.window():
return
if view == view.window().active_view():
print(f"on_selection_modified called for active View {view.id()} : {view.file_name()}.")
else:
print(f"on_selection_modified called for inactive View {view.id()} : {view.file_name()}.")
def on_post_save(self, view):
if not view.window():
return
if view == view.window().active_view():
print(f"on_post_save called for active View {view.id()} : {view.file_name()}.")
else:
print(f"on_post_save called for inactive View {view.id()} : {view.file_name()}.")
def on_activated(self, view):
if not view.window():
return
if view == view.window().active_view():
print(f"on_activated called for active View {view.id()} : {view.file_name()}.")
else:
print(f"on_activated called for inactive View {view.id()} : {view.file_name()}.") |
ST 3062, Win 7
Steps to reproduce:
on_post_save
andon_activated
(see below)Now you can see in the console that
on_post_save
is called twice with the parent view but not with the clone. As comparison,on_activated
is called correctly.on_selection_modified
will print the same id for all clones. (from #349)Test plugin:
The text was updated successfully, but these errors were encountered: