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?