[gitg/mainlining: 1/4] Implement preserving mainlines on history lanes



commit 15e441e7733dd7d4e21fddf0b5b96340f7eaf4f3
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Sun Dec 21 19:33:33 2014 +0100

    Implement preserving mainlines on history lanes

 gitg/history/gitg-history.vala        |   71 ++++++++++++++-----
 libgitg/gitg-cell-renderer-lanes.vala |   34 ++++++++-
 libgitg/gitg-commit-model.vala        |   86 ++++++++++++++++++------
 libgitg/gitg-lane.vala                |    3 +-
 libgitg/gitg-lanes.vala               |  121 ++++++++++++++++++++++++++++-----
 5 files changed, 253 insertions(+), 62 deletions(-)
---
diff --git a/gitg/history/gitg-history.vala b/gitg/history/gitg-history.vala
index 3869c06..d12fd05 100644
--- a/gitg/history/gitg-history.vala
+++ b/gitg/history/gitg-history.vala
@@ -504,42 +504,77 @@ namespace GitgHistory
                        return popup_menu_for_ref(references.first());
                }
 
+               private Ggit.OId? id_for_ref(Ggit.Ref r)
+               {
+                       Ggit.OId? id = null;
+
+                       try
+                       {
+                               var resolved = r.resolve();
+
+                               if (resolved.is_tag())
+                               {
+                                       var t = 
application.repository.lookup<Ggit.Tag>(resolved.get_target());
+
+                                       id = t.get_target_id();
+                               }
+                               else
+                               {
+                                       id = resolved.get_target();
+                               }
+                       }
+                       catch {}
+
+                       return id;
+               }
+
                private void update_walker()
                {
                        d_selected.clear();
 
-                       var include = new Ggit.OId[0];
+                       var include = new Gee.HashSet<Ggit.OId>((Gee.HashDataFunc)Ggit.OId.hash,
+                                                               (Gee.EqualDataFunc)Ggit.OId.equal);
+
                        var isall = d_main.refs_list.is_all;
 
-                       foreach (var r in d_main.refs_list.selection)
+                       var permanent = new Ggit.OId[0];
+
+                       var seen = new Gee.HashSet<Ggit.OId>((Gee.HashDataFunc)Ggit.OId.hash,
+                                                            (Gee.EqualDataFunc)Ggit.OId.equal);
+
+                       try
                        {
-                               try
-                               {
-                                       var resolved = r.resolve();
-                                       Ggit.OId? id;
+                               var head = id_for_ref(application.repository.get_head());
 
-                                       if (resolved.is_tag())
-                                       {
-                                               var t = 
application.repository.lookup<Ggit.Tag>(resolved.get_target());
+                               if (head != null)
+                               {
+                                       permanent += head;
+                                       seen.add(head);
+                               }
+                       } catch {}
 
-                                               id = t.get_target_id();
-                                       }
-                                       else
-                                       {
-                                               id = resolved.get_target();
-                                       }
+                       foreach (var r in d_main.refs_list.selection)
+                       {
+                               var id = id_for_ref(r);
 
-                                       include += id;
+                               if (id != null)
+                               {
+                                       include.add(id);
 
                                        if (!isall)
                                        {
                                                d_selected.add(id);
+
+                                               if (seen.add(id))
+                                               {
+                                                       permanent += id;
+                                               }
                                        }
                                }
-                               catch {}
                        }
 
-                       d_commit_list_model.set_include(include);
+                       d_commit_list_model.permanent_lanes = permanent;
+                       d_commit_list_model.set_include(include.to_array());
                        d_commit_list_model.reload();
                }
 
diff --git a/libgitg/gitg-cell-renderer-lanes.vala b/libgitg/gitg-cell-renderer-lanes.vala
index c3f5e6a..86f9c26 100644
--- a/libgitg/gitg-cell-renderer-lanes.vala
+++ b/libgitg/gitg-cell-renderer-lanes.vala
@@ -31,14 +31,34 @@ namespace Gitg
 
                private delegate double DirectionFunc(double i);
 
-               private uint num_lanes
+               private uint num_visible_lanes
                {
-                       get { return commit.get_lanes().length(); }
+                       get
+                       {
+                               int ret = 0;
+                               int trailing_hidden = 0;
+
+                               foreach (var lane in commit.get_lanes())
+                               {
+                                       ++ret;
+
+                                       if ((lane.tag & LaneTag.HIDDEN) != 0)
+                                       {
+                                               trailing_hidden++;
+                                       }
+                                       else
+                                       {
+                                               trailing_hidden = 0;
+                                       }
+                               }
+
+                               return ret - trailing_hidden;
+                       }
                }
 
                private uint total_width(Gtk.Widget widget)
                {
-                       return num_lanes * lane_width +
+                       return num_visible_lanes * lane_width +
                               LabelRenderer.width(widget, font_desc, labels);
                }
 
@@ -117,6 +137,12 @@ namespace Gitg
 
                        foreach (var lane in commit.get_lanes())
                        {
+                               if ((lane.tag & LaneTag.HIDDEN) != 0)
+                               {
+                                       ++to;
+                                       continue;
+                               }
+
                                var color = lane.color;
                                context.set_source_rgb(color.r, color.g, color.b);
 
@@ -203,7 +229,7 @@ namespace Gitg
                {
                        int offset;
 
-                       offset = (int)(num_lanes * lane_width);
+                       offset = (int)(num_visible_lanes * lane_width);
 
                        var rtl = (widget.get_style_context().get_state() & Gtk.StateFlags.DIR_RTL) != 0;
 
diff --git a/libgitg/gitg-commit-model.vala b/libgitg/gitg-commit-model.vala
index ba88f30..22f6ace 100644
--- a/libgitg/gitg-commit-model.vala
+++ b/libgitg/gitg-commit-model.vala
@@ -66,6 +66,7 @@ namespace Gitg
                private Repository d_repository;
                private Cancellable? d_cancellable;
                private Commit[] d_ids;
+               private Commit[] d_hidden_ids;
                private Thread<void*>? d_thread;
                private Ggit.RevisionWalker? d_walker;
                private uint d_advertized_size;
@@ -108,6 +109,8 @@ namespace Gitg
                        }
                }
 
+               public Ggit.OId[] permanent_lanes { get; set; }
+
                public signal void started();
                public signal void update(uint added);
                public signal void finished();
@@ -148,6 +151,7 @@ namespace Gitg
                        }
 
                        d_ids = new Commit[0];
+                       d_hidden_ids = new Commit[0];
                        d_advertized_size = 0;
 
                        d_id_hash = new Gee.HashMap<Ggit.OId, int>();
@@ -247,6 +251,29 @@ namespace Gitg
                        });
                }
 
+               private void resize_ids(ref Gitg.Commit[] ids, ref uint size)
+               {
+                       if (ids.length == size)
+                       {
+                               lock(d_ids)
+                               {
+                                       var oldlen = ids.length;
+
+                                       if (oldlen < 20000)
+                                       {
+                                               size *= 2;
+                                       }
+                                       else
+                                       {
+                                               size = (uint)((double)size * 1.2);
+                                       }
+
+                                       ids.resize((int)size);
+                                       ids.length = oldlen;
+                               }
+                       }
+               }
+
                private async void walk()
                {
                        Ggit.OId[] included = d_include;
@@ -273,11 +300,15 @@ namespace Gitg
                                d_walker.reset();
                                d_walker.set_sort_mode(d_sortmode);
 
+                               var incset = new 
Gee.HashSet<Ggit.OId>((Gee.HashDataFunc<Ggit.OId>)Ggit.OId.hash,
+                                                                      
(Gee.EqualDataFunc<Ggit.OId>)Ggit.OId.equal);
+
                                foreach (Ggit.OId oid in included)
                                {
                                        try
                                        {
                                                d_walker.push(oid);
+                                               incset.add(oid);
                                        } catch {};
                                }
 
@@ -286,19 +317,38 @@ namespace Gitg
                                        try
                                        {
                                                d_walker.hide(oid);
+                                               incset.remove(oid);
                                        } catch {};
                                }
 
+                               var permanent = new Ggit.OId[0];
+
+                               foreach (Ggit.OId oid in permanent_lanes)
+                               {
+                                       try
+                                       {
+                                               d_walker.push(oid);
+                                               permanent += oid;
+                                       } catch {}
+                               }
+
+                               d_lanes.reset(permanent, incset);
+
                                uint size;
+                               uint hidden_size;
 
                                // Pre-allocate array to store commits
                                lock(d_ids)
                                {
                                        d_ids = new Commit[1000];
+                                       d_hidden_ids = new Commit[100];
 
                                        size = d_ids.length;
+                                       hidden_size = d_hidden_ids.length;
 
                                        d_ids.length = 0;
+                                       d_hidden_ids.length = 0;
+
                                        d_advertized_size = 0;
                                }
 
@@ -331,31 +381,26 @@ namespace Gitg
                                                commit = d_repository.lookup<Commit>(id);
                                        } catch { break; }
 
-                                       lock(d_id_hash)
-                                       {
-                                               d_id_hash.set(id, d_ids.length);
-                                       }
+                                       int mylane;
+                                       SList<Lane> lanes;
 
-                                       // Add the id
-                                       if (d_ids.length == size)
+                                       if (d_lanes.next(commit, out lanes, out mylane))
                                        {
-                                               lock(d_ids)
-                                               {
-                                                       var oldlen = d_ids.length;
+                                               commit.update_lanes((owned)lanes, mylane);
 
-                                                       size *= 2;
-
-                                                       d_ids.resize((int)size);
-                                                       d_ids.length = oldlen;
+                                               lock(d_id_hash)
+                                               {
+                                                       d_id_hash.set(id, d_ids.length);
                                                }
-                                       }
 
-                                       d_ids += commit;
-
-                                       int mylane;
-                                       var lanes = d_lanes.next(commit, out mylane);
-
-                                       commit.update_lanes((owned)lanes, mylane);
+                                               resize_ids(ref d_ids, ref size);
+                                               d_ids += commit;
+                                       }
+                                       else
+                                       {
+                                               resize_ids(ref d_hidden_ids, ref hidden_size);
+                                               d_hidden_ids += commit;
+                                       }
 
                                        if (timer.elapsed() >= 200)
                                        {
@@ -394,7 +439,6 @@ namespace Gitg
                private void emit_started()
                {
                        clear();
-                       d_lanes.reset();
                        started();
                }
 
diff --git a/libgitg/gitg-lane.vala b/libgitg/gitg-lane.vala
index 65cd95b..f73841b 100644
--- a/libgitg/gitg-lane.vala
+++ b/libgitg/gitg-lane.vala
@@ -28,7 +28,8 @@ public enum LaneTag
        END = 1 << 1,
        SIGN_STASH = 1 << 2,
        SIGN_STAGED = 1 << 3,
-       SIGN_UNSTAGED = 1 << 4
+       SIGN_UNSTAGED = 1 << 4,
+       HIDDEN = 1 << 5
 }
 
 public class Lane : Object
diff --git a/libgitg/gitg-lanes.vala b/libgitg/gitg-lanes.vala
index f2d99f5..9194958 100644
--- a/libgitg/gitg-lanes.vala
+++ b/libgitg/gitg-lanes.vala
@@ -30,11 +30,12 @@ public class Lanes : Object
        private SList<weak Commit> d_previous;
        private Gee.LinkedList<LaneContainer> d_lanes;
        private HashTable<Ggit.OId, CollapsedLane> d_collapsed;
+       private Gee.HashSet<Ggit.OId>? d_roots;
 
        class LaneContainer
        {
                public Lane lane;
-               public uint inactive;
+               public int inactive;
                public Ggit.OId? from;
                public Ggit.OId? to;
 
@@ -56,17 +57,40 @@ public class Lanes : Object
 
                public void next(int index)
                {
+                       var hidden = is_hidden;
                        lane = lane.copy();
 
                        lane.tag = LaneTag.NONE;
                        lane.from = new SList<int>();
-                       lane.from.prepend(index);
 
-                       if (to != null)
+                       if (!hidden)
+                       {
+                               lane.from.prepend(index);
+                       }
+
+                       is_hidden = hidden;
+
+                       if (to != null && inactive >= 0)
                        {
                                ++inactive;
                        }
                }
+
+               public bool is_hidden
+               {
+                       get { return (lane.tag & LaneTag.HIDDEN) != 0; }
+                       set
+                       {
+                               if (value)
+                               {
+                                       lane.tag |= LaneTag.HIDDEN;
+                               }
+                               else
+                               {
+                                       lane.tag &= ~LaneTag.HIDDEN;
+                               }
+                       }
+               }
        }
 
        [Compact]
@@ -105,18 +129,35 @@ public class Lanes : Object
                reset();
        }
 
-       public void reset()
+       public void reset(Ggit.OId[]?           reserved = null,
+                         Gee.HashSet<Ggit.OId>? roots    = null)
        {
                d_previous = new SList<weak Commit>();
+
                d_lanes = new Gee.LinkedList<LaneContainer>();
+               d_roots = roots;
 
                Color.reset();
 
+               if (reserved != null)
+               {
+                       foreach (var r in reserved)
+                       {
+                               var ct = new LaneContainer(null, r);
+                               ct.inactive = -1;
+                               ct.is_hidden = true;
+
+                               d_lanes.add(ct);
+                       }
+               }
+
                d_collapsed.remove_all();
+               d_previous = new SList<weak Commit>();
        }
 
-       public SList<Lane> next(Commit  next,
-                               out int nextpos)
+       public bool next(Commit           next,
+                        out SList<Lane> lanes,
+                        out int         nextpos)
        {
                var myoid = next.get_id();
 
@@ -128,10 +169,18 @@ public class Lanes : Object
 
                LaneContainer? mylane = find_lane_by_oid(myoid, out nextpos);
 
+               if (mylane == null && d_roots != null && !d_roots.contains(myoid))
+               {
+                       lanes = null;
+                       return false;
+               }
+
                if (mylane == null)
                {
-                       // there is no lane reserver for this comit, add a new lane
-                       d_lanes.add(new LaneContainer(myoid, null));
+                       // there is no lane reserved for this commit, add a new lane
+                       mylane = new LaneContainer(myoid, null);
+
+                       d_lanes.add(mylane);
                        nextpos = (int)d_lanes.size - 1;
                }
                else
@@ -141,16 +190,28 @@ public class Lanes : Object
 
                        mylane.to = null;
                        mylane.from = next.get_id();
-                       mylane.inactive = 0;
+
+                       if (mylane.is_hidden && d_roots != null && d_roots.contains(myoid))
+                       {
+                               mylane.is_hidden = false;
+                               mylane.lane.from = new SList<int>();
+                       }
+
+                       if (mylane.inactive >= 0)
+                       {
+                               mylane.inactive = 0;
+                       }
                }
 
-               var res = lanes_list();
-               prepare_lanes(next, nextpos);
+               var hidden = mylane.is_hidden;
+
+               lanes = lanes_list();
+               prepare_lanes(next, nextpos, hidden);
 
-               return res;
+               return !hidden;
        }
 
-       private void prepare_lanes(Commit next, int pos)
+       private void prepare_lanes(Commit next, int pos, bool hidden)
        {
                var parents = next.get_parents();
                var myoid = next.get_id();
@@ -177,18 +238,42 @@ public class Lanes : Object
                                        // our lane instead.
                                        mylane.to = poid;
                                        mylane.from = myoid;
-                                       mylane.lane.from.append(lnpos);
+
+                                       if (!container.is_hidden)
+                                       {
+                                               mylane.lane.from.append(lnpos);
+                                               mylane.is_hidden = false;
+                                       }
+
                                        mylane.lane.color = mylane.lane.color.copy();
-                                       mylane.inactive = 0;
+
+                                       if (mylane.inactive >= 0)
+                                       {
+                                               mylane.inactive = 0;
+                                       }
 
                                        d_lanes.remove(container);
                                }
                                else
                                {
                                        container.from = myoid;
-                                       container.lane.from.append(pos);
+
+                                       if (!hidden)
+                                       {
+                                               container.lane.from.append(pos);
+                                       }
+
                                        container.lane.color = container.lane.color.copy();
-                                       container.inactive = 0;
+
+                                       if (!hidden)
+                                       {
+                                               container.is_hidden = false;
+                                       }
+
+                                       if (container.inactive >= 0)
+                                       {
+                                               container.inactive = 0;
+                                       }
                                }
 
                                continue;
@@ -201,7 +286,7 @@ public class Lanes : Object
 
                                mylane.lane.color = mylane.lane.color.copy();
                        }
-                       else
+                       else if (!hidden)
                        {
                                // generate a new lane for this parent
                                var newlane = new LaneContainer(myoid, poid);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]