Sublime Forum

Does a ViewEventListener get created on clone_file?

#1

I have a custom syntax for a large log file, and it can take a while to run. I would like a plugin to be able to open such a log file, but copy it to a temporary directory first, because /tmp is always local and is therefore much faster than a remote disk.

Of course, I don’t want to leave a trail of temp files around, so I’d like to clean up afterwards.

My general strategy is that when my plugin wants to open a file in a temp directory, it calls tempfile.mkdtemp(), copies the file into the temp directory, then calls open_file(). When open_file() returns a view, I add a setting to that view with the location of the temp directory.

In a ViewEventListener, I have an is_applicable() method that returns true if my custom setting exists, and its on_close() method removes the temp directory.

The problem happens if the user calls clone_file on the view of the temp file. What I see is that the cloned view has the setting with the temp directory, but it does not have an associated ViewEventListener.

In my on_close() method, I check to see if other views exist to the same file, in which case I don’t want to delete the temp directory. If I see other views, even though they have the correct setting, because they don’t have a ViewEventListener, nothing gets called when they close. Even if I overwrite the setting in the other views, I don’t get a ViewEventListener. In the python console, I can change some setting in the cloned view, and that will “kick” it into creating a ViewEventListener, but doing it programmatically doesn’t seem to work.

When I create the original view, I call view.settings.set('log_tempdir', temp_dir). My ViewEventListener is:

class TempListener(sublime_plugin.ViewEventListener):

    @classmethod
    def is_applicable(cls, settings):
        return settings.get('log_tempdir') is not None

    def on_close(self):
        tempdir = self.view.settings().get('log_tempdir')
        if tempdir is None:
            return

        buffer_id = self.view.buffer_id()
        views_to_this_buffer = [ v for w in sublime.windows() for v in w.views() if v.buffer_id() == buffer_id]

        if views_to_this_buffer:
            for v in views_to_this_buffer:
                # When there are cloned views, they have log_tempdir set correctly already
                view_log = v.settings().get('log_tempdir')

                # I have tried doing this settings().set() unconditionally
                # I've also tried setting some random setting just to make sure something changed
                if view_log is None or view_log != tempdir:
                  v.settings().set('log_tempdir', tempdir)
            return

        if not os.path.isdir(tempdir):
            return

        shutil.rmtree( tempdir )

The symptom is that on_close() never fires for a cloned view, even if the original view is closed first. By the way, I have also tried using applies_to_primary_view_only(), and that didn’t seem to work, either. The problem there was that after the primary view was closed, none of the other views seemed to become the primary view.

Is there a way to force the ViewEventListener to get created for the cloned view?

0 Likes

#2

I think I figured it out.

It appears that applies_to_primary_view_only() defaults to True. It’s a bit counter-intuitive, but okay.

The problem is that when you clone a file and then close the primary view, the clone does not become the primary view. Apparently, there is no primary view in that case. Given that behavior, it doesn’t sound like applies_to_primary_view_only() is all that useful.

Now that I know what it’s doing, I can work around it.

1 Like