Repository: mitmproxy/mitmproxy

Issue:
Feature request: Preserve marked flows when clearing flow list
When I'm busy in mitmproxy, I often mark an important flow using `m` to preserve it for easy access; my flow list grows pretty quickly even when I'm using a filter, so I often clear the list using `z` to tidy up.

Up until very recently clearing the list preserved my marked flows, this was very convenient because I could "clean up" my window and keep what's important (my marked flows) around and continue working.

I've installed the latest version (mitmproxy 1.0.2) and I've just noticed that clearing the flow list also removes the marked flows. 

Could I request this be added as a feature if what I've described was occurring by coincidence, or to be fixed if this is a regression. It is a super handy feature for myself, and hopefully others too. 

Thanks


Discussion:
This sounds like a reasonable request to me. Maybe we can add this under `Z`?
There is also another issue with the flow list. The marked flows can get randomly rearranged whenever `M` or `Z` is pressed, as it iterates through `view._store` which is a dictionary, to refresh the view. 
@lymanZerga11: Yes, good catch - needs to be replaced with OrderedDict I believe. Can you open a separate issue (or PR 😛) for this please?
Yeah okay!

Resolving patch:
diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py
--- a/mitmproxy/addons/view.py
+++ b/mitmproxy/addons/view.py
@@ -230,6 +230,17 @@ def clear(self):
         self.sig_view_refresh.send(self)
         self.sig_store_refresh.send(self)
 
+    def clear_not_marked(self):
+        """
+            Clears only the unmarked flows.
+        """
+        for flow in self._store.copy().values():
+            if not flow.marked:
+                self._store.pop(flow.id)
+
+        self._refilter()
+        self.sig_store_refresh.send(self)
+
     def add(self, f: mitmproxy.flow.Flow) -> bool:
         """
             Adds a flow to the state. If the flow already exists, it is
diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py
--- a/mitmproxy/tools/console/flowlist.py
+++ b/mitmproxy/tools/console/flowlist.py
@@ -35,6 +35,7 @@ def _mkhelp():
         ("W", "stream flows to file"),
         ("X", "kill and delete flow, even if it's mid-intercept"),
         ("z", "clear flow list or eventlog"),
+        ("Z", "clear unmarked flows"),
         ("tab", "tab between eventlog and flow list"),
         ("enter", "view flow"),
         ("|", "run script on this flow"),
@@ -354,6 +355,8 @@ def keypress(self, size, key):
                     self.master.view.update(f)
         elif key == "z":
             self.master.view.clear()
+        elif key == "Z":
+            self.master.view.clear_not_marked()
         elif key == "e":
             self.master.toggle_eventlog()
         elif key == "g":


Test patch:
diff --git a/test/mitmproxy/addons/test_view.py b/test/mitmproxy/addons/test_view.py
--- a/test/mitmproxy/addons/test_view.py
+++ b/test/mitmproxy/addons/test_view.py
@@ -108,6 +108,13 @@ def test_simple():
     assert list(v) == [f, f3, f2]
     assert len(v._store) == 3
 
+    f.marked = not f.marked
+    f2.marked = not f2.marked
+    v.clear_not_marked()
+    assert list(v) == [f, f2]
+    assert len(v) == 2
+    assert len(v._store) == 2
+
     v.clear()
     assert len(v) == 0
     assert len(v._store) == 0