Repository: sublimelinter/sublimelinter
Issue: Status bar message does not update on secondary views into one buffer

Looks like `def on_selection_modified_async(self, view)` gets always called with the primary view, therefore the `@util.distinct_until_selection_changed` blocks.

Changed files:
panel_view.py, status_bar_view.py, highlight_view.py, lint/util.py

diff --git a/highlight_view.py b/highlight_view.py
index c6391df..bfe38b6 100644
--- a/highlight_view.py
+++ b/highlight_view.py
@@ -52,6 +52,7 @@ def get_regions_keys(view):
 
 State = {
     'active_view': None,
+    'current_sel': tuple(),
     'idle_views': set(),
     'quiet_views': set()
 }
@@ -211,7 +212,10 @@ def demote_warnings(selected_text, error_type, **kwargs):
 class IdleViewController(sublime_plugin.EventListener):
     def on_activated_async(self, active_view):
         previous_view = State['active_view']
-        State.update({'active_view': active_view})
+        State.update({
+            'active_view': active_view,
+            'current_sel': get_current_sel(active_view)
+        })
 
         if previous_view and previous_view.id() != active_view.id():
             set_idle(previous_view, True)
@@ -230,19 +234,29 @@ class IdleViewController(sublime_plugin.EventListener):
         if view.buffer_id() == active_view.buffer_id():
             set_idle(active_view, True)
 
-    @util.distinct_until_selection_changed
     def on_selection_modified_async(self, view):
         active_view = State['active_view']
         # Do not race between `plugin_loaded` and this event handler
         if active_view is None:
             return
 
-        time_to_idle = persist.settings.get('highlights.time_to_idle')
-        if view.buffer_id() == active_view.buffer_id():
+        if view.buffer_id() != active_view.buffer_id():
+            return
+
+        current_sel = get_current_sel(active_view)
+        if current_sel != State['current_sel']:
+            State.update({'current_sel': current_sel})
+
+            time_to_idle = persist.settings.get('highlights.time_to_idle')
             queue.debounce(
                 partial(set_idle, active_view, True),
                 delay=time_to_idle,
-                key='highlights.{}'.format(view.id()))
+                key='highlights.{}'.format(active_view.id())
+            )
+
+
+def get_current_sel(view):
+    return tuple(s for s in view.sel())
 
 
 def set_idle(view, idle):
diff --git a/lint/util.py b/lint/util.py
index a6d789a..9085c5c 100644
--- a/lint/util.py
+++ b/lint/util.py
@@ -59,23 +59,6 @@ def distinct_until_buffer_changed(method):
     return wrapper
 
 
-def distinct_until_selection_changed(method):
-    last_call = None
-
-    @wraps(method)
-    def wrapper(self, view):
-        nonlocal last_call
-
-        this_call = (view.buffer_id(),) + tuple(s for s in view.sel())
-        if this_call == last_call:
-            return
-
-        last_call = this_call
-        method(self, view)
-
-    return wrapper
-
-
 def canonical_filename(view):
     return (
         os.path.basename(view.file_name()) if view.file_name()
diff --git a/panel_view.py b/panel_view.py
index e5cd419..ed372c3 100644
--- a/panel_view.py
+++ b/panel_view.py
@@ -86,10 +86,13 @@ class UpdateState(sublime_plugin.EventListener):
         if panel_is_active(window):
             update_panel_selection(**State)
 
-    @util.distinct_until_selection_changed
     def on_selection_modified_async(self, view):
         active_view = State['active_view']
-        if not active_view or active_view.buffer_id() != view.buffer_id():
+        # Do not race between `plugin_loaded` and this event handler
+        if active_view is None:
+            return
+
+        if view.buffer_id() != active_view.buffer_id():
             return
 
         current_pos = get_current_pos(active_view)
diff --git a/status_bar_view.py b/status_bar_view.py
index caa9d11..200d9cb 100644
--- a/status_bar_view.py
+++ b/status_bar_view.py
@@ -1,7 +1,7 @@
 import sublime
 import sublime_plugin
 
-from .lint import persist, util
+from .lint import persist
 from .lint import events
 
 
@@ -44,12 +44,16 @@ class UpdateState(sublime_plugin.EventListener):
         })
         draw(**State)
 
-    @util.distinct_until_selection_changed
+    # Fires multiple times for each view into the same buffer, but
+    # the argument is unfortunately always the same view, the primary.
+    # Activating a view via mouse click fires this also, twice per view.
     def on_selection_modified_async(self, view):
         active_view = State['active_view']
-        # It is possible that views (e.g. panels) update in the background.
-        # So we check here and return early.
-        if not active_view or active_view.buffer_id() != view.buffer_id():
+        # Do not race between `plugin_loaded` and this event handler
+        if active_view is None:
+            return
+
+        if view.buffer_id() != active_view.buffer_id():
             return
 
         current_pos = get_current_pos(active_view)