[gitg/highlighting] Enable experimental diff highlightingo
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/highlighting] Enable experimental diff highlightingo
- Date: Tue, 22 Dec 2015 23:13:19 +0000 (UTC)
commit 01b6823414c0ac677cc99a5f75f66f8080a38142
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Wed Dec 23 00:12:45 2015 +0100
Enable experimental diff highlightingo
gitg/commit/gitg-commit.vala | 1 +
libgitg/gitg-diff-view-file.vala | 324 +++++++++++++++++++++++++++++++++++---
libgitg/gitg-diff-view.vala | 4 +-
plugins/diff/gitg-diff.vala | 3 +
4 files changed, 309 insertions(+), 23 deletions(-)
---
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index 1e95473..dd7ca92 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -1807,6 +1807,7 @@ namespace GitgCommit
}
});
+ d_main.diff_view.repository = application.repository;
d_main.diff_view.default_collapse_all = false;
d_main.sidebar.deselected.connect(() => {
diff --git a/libgitg/gitg-diff-view-file.vala b/libgitg/gitg-diff-view-file.vala
index ccf360d..4185fab 100644
--- a/libgitg/gitg-diff-view-file.vala
+++ b/libgitg/gitg-diff-view-file.vala
@@ -20,6 +20,21 @@
[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file.ui")]
class Gitg.DiffViewFile : Gtk.Grid
{
+ private enum RegionType
+ {
+ ADDED,
+ REMOVED,
+ CONTEXT
+ }
+
+ private struct Region
+ {
+ public RegionType type;
+ public int buffer_line_start;
+ public int source_line_start;
+ public int length;
+ }
+
[GtkChild( name = "expander" )]
private Gtk.Expander d_expander;
@@ -39,10 +54,20 @@ class Gitg.DiffViewFile : Gtk.Grid
private uint d_removed;
private bool d_expanded;
private int64 d_doffset;
-
private Gee.HashMap<int, PatchSet.Patch?> d_lines;
-
private DiffViewFileSelectable d_selectable;
+ private DiffViewLinesRenderer d_old_lines;
+ private DiffViewLinesRenderer d_new_lines;
+ private DiffViewLinesRenderer d_sym_lines;
+ private bool d_highlight;
+ private Repository? d_repository;
+ private Cancellable? d_higlight_cancellable;
+ private Gtk.SourceBuffer? d_old_highlight_buffer;
+ private Gtk.SourceBuffer? d_new_highlight_buffer;
+ private bool d_old_highlight_ready;
+ private bool d_new_highlight_ready;
+ private Ggit.DiffDelta? d_delta;
+ private Region[] d_regions;
public bool expanded
{
@@ -100,32 +125,47 @@ class Gitg.DiffViewFile : Gtk.Grid
}
}
- public int maxlines
- {
- get; set;
- }
+ public int maxlines { get; set; }
+ public bool has_selection { get; private set; }
+ public bool handle_selection { get; construct set; }
- public bool has_selection
+ public Ggit.DiffDelta? delta
{
- get;
- private set;
+ get { return d_delta; }
+ construct set
+ {
+ d_delta = value;
+ update_highlight();
+ }
}
- public Ggit.DiffDelta delta
+ public bool highlight
{
- get;
- construct set;
- }
+ get { return d_highlight; }
+
+ construct set
+ {
+ d_highlight = value;
+ update_highlight();
+ }
- public bool handle_selection
+ default = true;
+ }
+
+ public Repository repository
{
- get;
- construct set;
+ get { return d_repository; }
+
+ construct set
+ {
+ d_repository = value;
+ update_highlight();
+ }
}
- public DiffViewFile(Ggit.DiffDelta delta, bool handle_selection)
+ public DiffViewFile(Repository repository, Ggit.DiffDelta delta, bool handle_selection)
{
- Object(delta: delta, handle_selection: handle_selection);
+ Object(repository: repository, delta: delta, handle_selection: handle_selection);
}
public PatchSet selection
@@ -175,10 +215,6 @@ class Gitg.DiffViewFile : Gtk.Grid
}
}
- private DiffViewLinesRenderer d_old_lines;
- private DiffViewLinesRenderer d_new_lines;
- private DiffViewLinesRenderer d_sym_lines;
-
construct
{
var gutter = d_sourceview_hunks.get_gutter(Gtk.TextWindowType.LEFT);
@@ -221,6 +257,204 @@ class Gitg.DiffViewFile : Gtk.Grid
d_sourceview_hunks.draw.connect_after(sourceview_hunks_on_draw);
}
+ protected override void dispose()
+ {
+ base.dispose();
+
+ if (d_higlight_cancellable != null)
+ {
+ d_higlight_cancellable.cancel();
+ d_higlight_cancellable = null;
+ }
+ }
+
+ private void update_highlight()
+ {
+ if (d_higlight_cancellable != null)
+ {
+ d_higlight_cancellable.cancel();
+ d_higlight_cancellable = null;
+ }
+
+ d_old_highlight_buffer = null;
+ d_new_highlight_buffer = null;
+
+ d_old_highlight_ready = false;
+ d_new_highlight_ready = false;
+
+ if (highlight && repository != null && delta != null)
+ {
+ var cancellable = new Cancellable();
+ d_higlight_cancellable = cancellable;
+
+ init_highlighting_buffer.begin(delta.get_old_file(), cancellable, (obj, res) => {
+ var buffer = init_highlighting_buffer.end(res);
+
+ if (!cancellable.is_cancelled())
+ {
+ d_old_highlight_buffer = buffer;
+ d_old_highlight_ready = true;
+
+ update_highlighting_ready();
+ }
+ });
+
+ init_highlighting_buffer.begin(delta.get_new_file(), cancellable, (obj, res) => {
+ var buffer = init_highlighting_buffer.end(res);
+
+ if (!cancellable.is_cancelled())
+ {
+ d_new_highlight_buffer = buffer;
+ d_new_highlight_ready = true;
+
+ update_highlighting_ready();
+ }
+ });
+ }
+ else
+ {
+ update_highlighting_ready();
+ }
+ }
+
+ private async Gtk.SourceBuffer? init_highlighting_buffer(Ggit.DiffFile file, Cancellable cancellable)
+ {
+ var id = file.get_oid();
+
+ if (id.is_zero())
+ {
+ return null;
+ }
+
+ var sfile = new Gtk.SourceFile();
+ sfile.location = repository.get_workdir().get_child(file.get_path());
+
+ var basename = sfile.location.get_basename();
+
+ Ggit.Blob blob;
+
+ try
+ {
+ blob = repository.lookup<Ggit.Blob>(id);
+ }
+ catch
+ {
+ return null;
+ }
+
+ var content = blob.get_raw_content();
+
+ bool uncertain;
+ var content_type = GLib.ContentType.guess(basename, content, out uncertain);
+
+ var bytes = new Bytes(content);
+ var stream = new GLib.MemoryInputStream.from_bytes(bytes);
+
+ var manager = Gtk.SourceLanguageManager.get_default();
+ var language = manager.guess_language(basename, content_type);
+
+ if (language == null)
+ {
+ return null;
+ }
+
+ var buffer = new Gtk.SourceBuffer(d_sourceview_hunks.buffer.tag_table);
+
+ var style_scheme_manager = Gtk.SourceStyleSchemeManager.get_default();
+
+ buffer.language = language;
+ buffer.highlight_syntax = true;
+ buffer.style_scheme = style_scheme_manager.get_scheme("classic");
+
+ var loader = new Gtk.SourceFileLoader.from_stream(buffer, sfile, stream);
+
+ try
+ {
+ yield loader.load_async(GLib.Priority.LOW, cancellable, null);
+ }
+ catch (Error e)
+ {
+ stderr.printf(@"ERROR: failed to load $(file.get_path()) for highlighting:
$(e.message)\n");
+ return null;
+ }
+
+ return buffer;
+ }
+
+ private void update_highlighting_ready()
+ {
+ if (!d_old_highlight_ready && !d_new_highlight_ready)
+ {
+ // Remove highlights
+ return;
+ }
+ else if (!d_old_highlight_ready || !d_new_highlight_ready)
+ {
+ // Both need to be loaded
+ return;
+ }
+
+ var buffer = d_sourceview_hunks.buffer;
+
+ // Go over all the source chunks and match up to old/new buffer. Then,
+ // apply the tags that are applied to the highlighted source buffers.
+ foreach (var region in d_regions)
+ {
+ Gtk.SourceBuffer? source;
+
+ if (region.type == RegionType.REMOVED)
+ {
+ source = d_old_highlight_buffer;
+ }
+ else
+ {
+ source = d_new_highlight_buffer;
+ }
+
+ if (source == null)
+ {
+ continue;
+ }
+
+ Gtk.TextIter buffer_iter, source_iter;
+
+ buffer.get_iter_at_line(out buffer_iter, region.buffer_line_start);
+ source.get_iter_at_line(out source_iter, region.source_line_start);
+
+ var source_end_iter = source_iter;
+ source_end_iter.forward_lines(region.length);
+
+ source.ensure_highlight(source_iter, source_end_iter);
+
+ var buffer_end_iter = buffer_iter;
+ buffer_end_iter.forward_lines(region.length);
+
+ var source_next_iter = source_iter;
+ var tags = source_iter.get_tags();
+
+ while (source_next_iter.forward_to_tag_toggle(null) &&
source_next_iter.compare(source_end_iter) < 0)
+ {
+ var buffer_next_iter = buffer_iter;
+ buffer_next_iter.forward_chars(source_next_iter.get_offset() -
source_iter.get_offset());
+
+ foreach (var tag in tags)
+ {
+ buffer.apply_tag(tag, buffer_iter, buffer_next_iter);
+ }
+
+ source_iter = source_next_iter;
+ buffer_iter = buffer_next_iter;
+
+ tags = source_iter.get_tags();
+ }
+
+ foreach (var tag in tags)
+ {
+ buffer.apply_tag(tag, buffer_iter, buffer_end_iter);
+ }
+ }
+ }
+
private bool sourceview_hunks_on_draw(Cairo.Context cr)
{
var win = d_sourceview_hunks.get_window(Gtk.TextWindowType.LEFT);
@@ -338,6 +572,13 @@ class Gitg.DiffViewFile : Gtk.Grid
/* Diff Content */
var content = new StringBuilder();
+ var region = Region() {
+ type = RegionType.CONTEXT,
+ buffer_line_start = 0,
+ source_line_start = 0,
+ length = 0
+ };
+
for (var i = 0; i < lines.size; i++)
{
var line = lines[i];
@@ -346,15 +587,21 @@ class Gitg.DiffViewFile : Gtk.Grid
var removed = false;
var origin = line.get_origin();
+ var rtype = RegionType.CONTEXT;
+
switch (origin)
{
case Ggit.DiffLineType.ADDITION:
added = true;
d_added++;
+
+ rtype = RegionType.ADDED;
break;
case Ggit.DiffLineType.DELETION:
removed = true;
d_removed++;
+
+ rtype = RegionType.REMOVED;
break;
case Ggit.DiffLineType.CONTEXT_EOFNL:
case Ggit.DiffLineType.ADD_EOFNL:
@@ -363,6 +610,34 @@ class Gitg.DiffViewFile : Gtk.Grid
break;
}
+ if (i == 0 || rtype != region.type)
+ {
+ if (i != 0)
+ {
+ d_regions += region;
+ }
+
+ int source_line_start;
+
+ if (rtype == RegionType.REMOVED)
+ {
+ source_line_start = line.get_old_lineno() - 1;
+ }
+ else
+ {
+ source_line_start = line.get_new_lineno() - 1;
+ }
+
+ region = Region() {
+ type = rtype,
+ buffer_line_start = buffer_line,
+ source_line_start = source_line_start,
+ length = 0
+ };
+ }
+
+ region.length++;
+
if (added || removed)
{
var offset = (size_t)line.get_content_offset();
@@ -397,6 +672,11 @@ class Gitg.DiffViewFile : Gtk.Grid
buffer_line++;
}
+ if (lines.size != 0)
+ {
+ d_regions += region;
+ }
+
int line_hunk_start = iter.get_line();
buffer.insert(ref iter, (string)content.data, -1);
diff --git a/libgitg/gitg-diff-view.vala b/libgitg/gitg-diff-view.vala
index d8bfa3e..0f2a5fa 100644
--- a/libgitg/gitg-diff-view.vala
+++ b/libgitg/gitg-diff-view.vala
@@ -101,6 +101,8 @@ public class Gitg.DiffView : Gtk.Grid
public bool use_gravatar { get; construct set; default = true; }
public int tab_width { get; construct set; default = 4; }
public bool handle_selection { get; construct set; default = false; }
+ public bool highlight { get; construct set; default = true; }
+ public Repository repository { get; set; }
private bool flag_get(Ggit.DiffOption f)
{
@@ -325,7 +327,7 @@ public class Gitg.DiffView : Gtk.Grid
add_file();
- current_file = new Gitg.DiffViewFile(delta, handle_selection);
+ current_file = new Gitg.DiffViewFile(repository, delta,
handle_selection);
return 0;
},
diff --git a/plugins/diff/gitg-diff.vala b/plugins/diff/gitg-diff.vala
index fb03617..2a29462 100644
--- a/plugins/diff/gitg-diff.vala
+++ b/plugins/diff/gitg-diff.vala
@@ -35,7 +35,10 @@ namespace GitgDiff
construct
{
d_diff = new Gitg.DiffView();
+
d_diff.show_parents = true;
+ d_diff.repository = application.repository;
+
d_diff.show();
var settings = new Settings("org.gnome.gitg.preferences.diff");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]