Implement preserving mainlines on history lanes

This commit is contained in:
Jesse van den Kieboom 2014-12-21 19:33:33 +01:00
parent 0886b19872
commit 15e441e773
5 changed files with 257 additions and 66 deletions

View file

@ -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;
var permanent = new Ggit.OId[0];
var seen = new Gee.HashSet<Ggit.OId>((Gee.HashDataFunc)Ggit.OId.hash,
(Gee.EqualDataFunc)Ggit.OId.equal);
try
{
var head = id_for_ref(application.repository.get_head());
if (head != null)
{
permanent += head;
seen.add(head);
}
} catch {}
foreach (var r in d_main.refs_list.selection)
{
try
var id = id_for_ref(r);
if (id != null)
{
var resolved = r.resolve();
Ggit.OId? id;
if (resolved.is_tag())
{
var t = application.repository.lookup<Ggit.Tag>(resolved.get_target());
id = t.get_target_id();
}
else
{
id = resolved.get_target();
}
include += id;
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();
}

View file

@ -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;

View file

@ -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);
}
// Add the id
if (d_ids.length == size)
{
lock(d_ids)
{
var oldlen = d_ids.length;
size *= 2;
d_ids.resize((int)size);
d_ids.length = oldlen;
}
}
d_ids += commit;
int mylane;
var lanes = d_lanes.next(commit, out mylane);
SList<Lane> lanes;
commit.update_lanes((owned)lanes, mylane);
if (d_lanes.next(commit, out lanes, out mylane))
{
commit.update_lanes((owned)lanes, mylane);
lock(d_id_hash)
{
d_id_hash.set(id, d_ids.length);
}
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();
}

View file

@ -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

View file

@ -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;
return res;
lanes = lanes_list();
prepare_lanes(next, nextpos, hidden);
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);