Repository: timbrel/gitsavvy
Issue: Failure to refresh upon switching project

Quite a few times now I've found myself staring at an out-of-date STATUS or BRANCHES tab, being thoroughly confused about what's going on, e.g. why certain files don't exist, or why the STATUS screen shows nothing modified even though I know for sure there are some modified files. The confusion usually lasts a couple of seconds before I realize I need to close the tab and re-open it to refresh it.

## How to reproduce

Make sure you have two projects, let's call them A and B. Project A has one directory tracked by git. 

- Open Project A (Ctrl + Alt + P)
- Make sure it's on master and has no modified files
- Open a STATUS and a BRANCHES view in their own tabs
- Switch to project B using Ctrl + Alt + P
- Switch to a different branch in project A through your terminal
- Edit some file from project A through some other means (`nano`, `vim`, `echo/cat`, whatever floats your boat)
- Switch back to project A using Ctrl + Alt + P
- Observe in BRANCHES tab that it looks like you're still on master
- Observe in STATUS tab that your manually edited file does not show up as modified
- Close both tabs and re-open them
- Observe changes

## Probable cause

The tabs refresh perfectly fine upon Sublime startup. That implies that there is some logic to refresh on certain events. This logic doesn't appear to be fired when a project is switched to. That probably needs to be added.

Changed files:
common/ui.py

diff --git a/common/ui.py b/common/ui.py
index 7ae311f5..6f751632 100644
--- a/common/ui.py
+++ b/common/ui.py
@@ -6,6 +6,7 @@ import sublime
 from sublime_plugin import TextCommand
 
 from . import util
+from ..core.runtime import enqueue_on_worker
 from ..core.settings import GitSavvySettings
 from ..core.utils import focus_view
 
@@ -302,19 +303,19 @@ class GsInterfaceRefreshCommand(TextCommand):
     """
 
     def run(self, edit, nuke_cursors=False):
-        sublime.set_timeout_async(self.run_async, 0)
-        self.nuke_cursors = nuke_cursors
+        enqueue_on_worker(self.run_async, nuke_cursors)
 
-    def run_async(self):
+    def run_async(self, nuke_cursors):
+        # type: (bool) -> None
         interface_type = self.view.settings().get("git_savvy.interface")
-        for InterfaceSubclass in subclasses:
-            if InterfaceSubclass.interface_type == interface_type:
-                existing_interface = interfaces.get(self.view.id(), None)
-                if existing_interface:
-                    existing_interface.render(nuke_cursors=self.nuke_cursors)
-                else:
-                    interface = InterfaceSubclass(view=self.view)
-                    interfaces[interface.view.id()] = interface
+        for cls in subclasses:
+            if cls.interface_type == interface_type:
+                vid = self.view.id()
+                interface = interfaces.get(vid, None)
+                if not interface:
+                    interface = interfaces[vid] = cls(view=self.view)
+                interface.render(nuke_cursors=nuke_cursors)  # type: ignore[union-attr]
+                break
 
 
 class GsInterfaceToggleHelpCommand(TextCommand):