Sublime Forum

On_modified doesn't seem to be delivered to multiple ViewEventListeners

#1

I have a plugin for a log viewer. My plugin maintains state about each buffer and each view (with the applicable syntax). When the contents of the file change, all of my state needs to be rebuilt. It’s a log file, so I don’t expect them to be modified often, but it does happen.

What I want to happen is when a ViewEventListener gets an on_modified() event, I want to invalidate my data structures for that view, and if the view is the primary view, invalidate my data structures for the buffer as well.

The problem is that on_modified doesn’t behave as expected. Here’s a test snippet:

class TestEventListener(sublime_plugin.ViewEventListener):

    @classmethod
    def is_applicable(cls, settings):
        return 'Packages/Text/Plain text.tmLanguage' in settings.get('syntax') 

    @classmethod
    def applies_to_primary_view_only(cls):
        return False
        
    def on_modified(self):
        print("on_modified on view_id=%d" % self.view.id())

I open a file with the “Plain text” syntax, and then I create a second view with File->New View Into File. Then, I modify one of the views.

Because there are two views and I set applies_to_primary_view_only() to False, I have two ViewEventListeners. Therefore, when I modify the buffer, I get two calls to on_modified(), as expected. The problem is that both calls to on_modified() go the same ViewEventListener (I think it’s the primary, but I haven’t verified that). Because of that, the other view doesn’t get notified at all.

I have workaround for this, but I was wondering if I was missing something.

0 Likes

#2

I don’t think you’re missing something here; there’s currently an issue wherein when an event is triggered, the event handler is always given the primary view even if there are clones and regardless of which one the event originated in. From my own recollection facing this in the past this is true regardless of the event that you’re interested in or whether you’re using EventListener or ViewEventListener (but it’s been a while).

One of the issues linked below is tagged to indicate that it will hopefully be addressed in the next dev cycle, so possibly there’s a fix for this in the near future.

1 Like

#3

Thanks! I did a little more experimenting, and it looks like on_close() and on_pre_close() are delivered to the correct view.

It sounds like I need two ViewEventListener classes: one for the primary-view-only to handle on_modified (which will have to find the other views and handle them appropriately) and one that’s not primary-view-only to handle on_close/on_pre_close.

On a related issue, if the file is reloaded (say the log file is regenerated outside of sublime), I seem to get two on_modified() events (one when it starts loading and one when it finishes loading), even if there is only one view. It seems odd, but I can handle that part. The more difficult problem is that if I set the buffer to read-only, then I get no events at all if the file is reloaded (and least not any events I can find - I definitely don’t get on_modified or on_load). The only modification I really care about is the file being reloaded (users ought not to be editing log files anyway), but at the moment I’m stuck making the buffers not read-only just so I can get on_modified events. Is there a better way?

0 Likes

#4

Actually, it looks like I spoke too soon. Even if I put my on_modified handler in a ViewEventListener for the primary view only, it gets called multiple times (once per each view) when the file changes. I don’t see any way to tell this situation from multiple actual modifications, which means I could wind up doing a bunch of unnecessary work if something changes while multiple views are open.

0 Likes

#5

I think on_load only triggers on the initial load of a file and not for reloads in general. Or at least with a simple listener I can see a message being generated by Sublime when a file reloads, but my event listener is not triggered for it.

I don’t think I’ve ever noticed before but indeed on_modified() doesn’t trigger for a view that’s read only. I suppose at some level that’s an optimization of sorts since if a view can’t be modified it doesn’t need to be considered for those kinds of events, but the core is modifying the buffer when it reloads it seems like it should.

The on_activated event still triggers for read-only buffers, so I played a bit with maybe using that in combination with view.change_count() to be able to notice when the buffer was activated that a change had occurred, but it turns out that Sublime’s reload of files doesn’t trigger a change count either. Of course that event is also problematic if it happens to already be the focused view and the file changes in the background too…

0 Likes

#6

Thanks for checking into it. I hadn’t thought of using change_count(). As you say, it doesn’t solve the reload problem, but it does solve my problem with getting multiple on_modified() calls when things change.

I might have to force the user to run a command after a reload to update everything if I’m going to use read-only buffers. Not my favorite thing to do, but I don’t see any workarounds.

0 Likes