[gitg/wip/albfan/gitattributes-textconv: 5/6] Side by side diff text renderers




commit adfc2fbdda925687e6829c2dac80e67eeb3403e3
Author: Xiaoguang Wang <xwang suse com>
Date:   Fri Nov 19 23:47:12 2021 +0100

    Side by side diff text renderers

 .../gitg-diff-view-file-renderer-text-split.vala   | 145 +++++++++++++
 .../gitg-diff-view-file-renderer-text-three.vala   | 158 ++++++++++++++
 libgitg/gitg-diff-view-file-renderer-text.vala     | 240 ++++++++++++++++-----
 libgitg/gitg-diff-view-file-renderer-textable.vala |  28 +++
 libgitg/gitg-diff-view-file.vala                   |  81 +++++--
 libgitg/gitg-diff-view-lines-renderer.vala         |  78 +++++--
 libgitg/gitg-diff-view.vala                        |  40 ++--
 libgitg/meson.build                                |   5 +
 libgitg/resources/resources.xml                    |   2 +
 .../ui/gitg-diff-view-file-renderer-text-split.ui  |  35 +++
 .../ui/gitg-diff-view-file-renderer-text-three.ui  |  44 ++++
 libgitg/resources/ui/gitg-diff-view-file.ui        |   2 -
 12 files changed, 749 insertions(+), 109 deletions(-)
---
diff --git a/libgitg/gitg-diff-view-file-renderer-text-split.vala 
b/libgitg/gitg-diff-view-file-renderer-text-split.vala
new file mode 100644
index 00000000..53cc469e
--- /dev/null
+++ b/libgitg/gitg-diff-view-file-renderer-text-split.vala
@@ -0,0 +1,145 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2016 - Jesse van den Kieboom
+ *
+ * gitg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gitg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file-renderer-text-split.ui")]
+class Gitg.DiffViewFileRendererTextSplit : Gtk.Box, DiffSelectable, DiffViewFileRenderer, 
DiffViewFileRendererTextable
+{
+       [GtkChild( name = "scroll_left" )]
+       private unowned Gtk.ScrolledWindow d_scroll_left;
+       [GtkChild( name = "scroll_right" )]
+       private unowned Gtk.ScrolledWindow d_scroll_right;
+
+       private Gitg.DiffViewFileRendererText d_renderer_left;
+       private Gitg.DiffViewFileRendererText d_renderer_right;
+
+       public DiffViewFileInfo info { get; construct set; }
+
+       public Ggit.DiffDelta? delta
+       {
+               get { return info.delta; }
+       }
+
+       public Repository? repository
+       {
+               get { return info.repository; }
+       }
+
+       public bool wrap_lines
+       {
+               get { return d_renderer_left.wrap_mode != Gtk.WrapMode.NONE; }
+               set
+               {
+                       if (value)
+                       {
+                               d_renderer_left.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+                               d_renderer_right.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+                       }
+                       else
+                       {
+                               d_renderer_left.wrap_mode = Gtk.WrapMode.NONE;
+                               d_renderer_right.wrap_mode = Gtk.WrapMode.NONE;
+                       }
+               }
+       }
+
+       public new int tab_width
+       {
+               get
+               {
+                       return (int)d_renderer_left.get_tab_width();
+               }
+               set
+               {
+                       d_renderer_left.set_tab_width((uint)value);
+                       d_renderer_right.set_tab_width((uint)value);
+               }
+       }
+
+       public int maxlines
+       {
+               get
+               {
+                       return (int)d_renderer_left.maxlines;
+               }
+               set
+               {
+                       d_renderer_left.maxlines = value;
+                       d_renderer_right.maxlines = value;
+               }
+       }
+
+       public bool highlight
+       {
+               get { return d_renderer_left.highlight; }
+
+               construct set
+               {
+                       if (highlight != value)
+                       {
+                               d_renderer_left.highlight = value;
+                               d_renderer_right.highlight = value;
+                       }
+               }
+       }
+
+       public DiffViewFileRendererTextSplit(DiffViewFileInfo info, bool handle_selection)
+       {
+               Object(info: info);
+               d_renderer_left = new Gitg.DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.OLD);
+               d_renderer_right = new Gitg.DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.NEW);
+               d_scroll_left.add(d_renderer_left);
+               d_scroll_right.add(d_renderer_right);
+       }
+
+       construct
+       {
+               //can_select = d_renderer_left.can_select() || d_renderer_right.can_select();
+               can_select = false;
+       }
+
+       public void add_hunk(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
+       {
+               d_renderer_left.add_hunk(hunk, lines);
+               d_renderer_right.add_hunk(hunk, lines);
+       }
+
+       public bool has_selection
+       {
+               get
+               {
+                       //return d_renderer_left.has_selection() || d_renderer_right.has_selection();
+                       return false;
+               }
+       }
+
+       public bool can_select { get; construct set; }
+
+       public PatchSet selection
+       {
+               owned get
+               {
+                       /*if (d_renderer_left.has_selection())
+                               return d_renderer_left.get_selection();
+                       if (d_renderer_right.has_selection())
+                               return d_renderer_right.get_selection();
+                       */
+                       return new PatchSet();
+               }
+       }
+}
diff --git a/libgitg/gitg-diff-view-file-renderer-text-three.vala 
b/libgitg/gitg-diff-view-file-renderer-text-three.vala
new file mode 100644
index 00000000..755ba10b
--- /dev/null
+++ b/libgitg/gitg-diff-view-file-renderer-text-three.vala
@@ -0,0 +1,158 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2016 - Jesse van den Kieboom
+ *
+ * gitg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gitg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file-renderer-text-three.ui")]
+class Gitg.DiffViewFileRendererTextThree : Gtk.Box, DiffSelectable, DiffViewFileRenderer, 
DiffViewFileRendererTextable
+{
+       [GtkChild( name = "scroll_left" )]
+       private unowned Gtk.ScrolledWindow d_scroll_left;
+       [GtkChild( name = "scroll_center" )]
+       private unowned Gtk.ScrolledWindow d_scroll_center;
+       [GtkChild( name = "scroll_right" )]
+       private unowned Gtk.ScrolledWindow d_scroll_right;
+
+
+       private Gitg.DiffViewFileRendererText d_renderer_left;
+       private Gitg.DiffViewFileRendererText d_renderer_center;
+       private Gitg.DiffViewFileRendererText d_renderer_right;
+
+       public DiffViewFileInfo info { get; construct set; }
+
+       public Ggit.DiffDelta? delta
+       {
+               get { return info.delta; }
+       }
+
+       public Repository? repository
+       {
+               get { return info.repository; }
+       }
+
+       public bool wrap_lines
+       {
+               get { return d_renderer_left.wrap_mode != Gtk.WrapMode.NONE; }
+               set
+               {
+                       if (value)
+                       {
+                               d_renderer_left.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+                               d_renderer_center.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+                               d_renderer_right.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+                       }
+                       else
+                       {
+                               d_renderer_left.wrap_mode = Gtk.WrapMode.NONE;
+                               d_renderer_center.wrap_mode = Gtk.WrapMode.NONE;
+                               d_renderer_right.wrap_mode = Gtk.WrapMode.NONE;
+                       }
+               }
+       }
+
+       public new int tab_width
+       {
+               get
+               {
+                       return (int)d_renderer_left.get_tab_width();
+               }
+               set
+               {
+                       d_renderer_left.set_tab_width((uint)value);
+                       d_renderer_center.set_tab_width((uint)value);
+                       d_renderer_right.set_tab_width((uint)value);
+               }
+       }
+
+       public int maxlines
+       {
+               get
+               {
+                       return (int)d_renderer_left.maxlines;
+               }
+               set
+               {
+                       d_renderer_left.maxlines = value;
+                       d_renderer_center.maxlines = value;
+                       d_renderer_right.maxlines = value;
+               }
+       }
+
+       public bool highlight
+       {
+               get { return d_renderer_left.highlight; }
+
+               construct set
+               {
+                       if (highlight != value)
+                       {
+                               d_renderer_left.highlight = value;
+                               d_renderer_center.highlight = value;
+                               d_renderer_right.highlight = value;
+                       }
+               }
+       }
+
+       public DiffViewFileRendererTextThree(DiffViewFileInfo info, bool handle_selection)
+       {
+               Object(info: info);
+               d_renderer_left = new Gitg.DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.OLD);
+               d_renderer_center = new Gitg.DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.ONE);
+               d_renderer_right = new Gitg.DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.NEW);
+               d_scroll_left.add(d_renderer_left);
+               d_scroll_center.add(d_renderer_center);
+               d_scroll_right.add(d_renderer_right);
+       }
+
+       construct
+       {
+       }
+
+       public void add_hunk(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
+       {
+               can_select = false;
+               d_renderer_left.add_hunk(hunk, lines);
+               d_renderer_center.add_hunk(hunk, lines);
+               d_renderer_right.add_hunk(hunk, lines);
+       }
+
+       public bool has_selection
+       {
+               get
+               {
+                       //return d_renderer_left.has_selection() || d_renderer_right.has_selection() || 
d_renderer_center.has_selection();
+                       return false;
+               }
+       }
+
+       public bool can_select { get; construct set; }
+
+       public PatchSet selection
+       {
+               owned get
+               {
+                       /*if (d_renderer_left.has_selection())
+                               return d_renderer_left.get_selection();
+                       if (d_renderer_center.has_selection())
+                               return d_renderer_center.get_selection();
+                       if (d_renderer_right.has_selection())
+                               return d_renderer_right.get_selection();
+                       */
+                       return new PatchSet();
+               }
+       }
+}
diff --git a/libgitg/gitg-diff-view-file-renderer-text.vala b/libgitg/gitg-diff-view-file-renderer-text.vala
index 6ef2a984..b20dba7a 100644
--- a/libgitg/gitg-diff-view-file-renderer-text.vala
+++ b/libgitg/gitg-diff-view-file-renderer-text.vala
@@ -18,7 +18,7 @@
  */
 
 [GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file-renderer-text.ui")]
-class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFileRenderer
+class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFileRenderer, 
DiffViewFileRendererTextable
 {
        private enum RegionType
        {
@@ -27,6 +27,13 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
                CONTEXT
        }
 
+       public enum Style
+       {
+               ONE,
+               OLD,
+               NEW
+       }
+
        private struct Region
        {
                public RegionType type;
@@ -61,6 +68,7 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
        private Settings? d_stylesettings;
 
        private FontManager d_font_manager;
+       public Style d_style { get; construct set; }
 
        public bool new_is_workdir { get; construct set; }
 
@@ -170,29 +178,58 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
                }
        }
 
-       public DiffViewFileRendererText(DiffViewFileInfo info, bool can_select)
+       public DiffViewFileRendererText(DiffViewFileInfo info, bool can_select, Style style)
        {
-               Object(info: info, can_select: can_select);
+               Object(info: info, can_select: can_select, d_style: style);
        }
 
        construct
        {
                var gutter = this.get_gutter(Gtk.TextWindowType.LEFT);
 
-               d_old_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.OLD);
-               d_new_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.NEW);
-               d_sym_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.SYMBOL);
+               if (d_style == Style.ONE)
+               {
+                       d_old_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.OLD);
+                       d_new_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.NEW);
+                       d_sym_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.SYMBOL);
 
-               this.bind_property("maxlines", d_old_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
-               this.bind_property("maxlines", d_new_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
+                       this.bind_property("maxlines", d_old_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
+                       this.bind_property("maxlines", d_new_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
 
-               d_old_lines.xpad = 8;
-               d_new_lines.xpad = 8;
-               d_sym_lines.xpad = 6;
+                       d_old_lines.xpad = 8;
+                       d_new_lines.xpad = 8;
+                       d_sym_lines.xpad = 6;
 
-               gutter.insert(d_old_lines, 0);
-               gutter.insert(d_new_lines, 1);
-               gutter.insert(d_sym_lines, 2);
+                       gutter.insert(d_old_lines, 0);
+                       gutter.insert(d_new_lines, 1);
+                       gutter.insert(d_sym_lines, 2);
+               }
+               else if (d_style == Style.OLD)
+               {
+                       d_old_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.OLD);
+                       d_sym_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.SYMBOL_OLD);
+
+                       this.bind_property("maxlines", d_old_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
+
+                       d_old_lines.xpad = 8;
+                       d_sym_lines.xpad = 6;
+
+                       gutter.insert(d_old_lines, 0);
+                       gutter.insert(d_sym_lines, 1);
+               }
+               else if (d_style == Style.NEW)
+               {
+                       d_new_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.NEW);
+                       d_sym_lines = new DiffViewLinesRenderer(DiffViewLinesRenderer.Style.SYMBOL_NEW);
+
+                       this.bind_property("maxlines", d_new_lines, "maxlines", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE);
+
+                       d_new_lines.xpad = 8;
+                       d_sym_lines.xpad = 6;
+
+                       gutter.insert(d_new_lines, 0);
+                       gutter.insert(d_sym_lines, 1);
+               }
 
                this.set_border_window_size(Gtk.TextWindowType.TOP, 1);
 
@@ -563,15 +600,35 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
 
                var ctx = this.get_style_context();
 
-               var old_lines_width = d_old_lines.size + d_old_lines.xpad * 2;
-               var new_lines_width = d_new_lines.size + d_new_lines.xpad * 2;
+               var old_lines_width = 0;
+               var new_lines_width = 0;
+
+               switch (d_style)
+               {
+               case Style.ONE:
+                       old_lines_width = d_old_lines.size + d_old_lines.xpad * 2;
+                       new_lines_width = d_new_lines.size + d_new_lines.xpad * 2;
+                       break;
+
+               case Style.OLD:
+                       old_lines_width = d_old_lines.size + d_old_lines.xpad * 2;
+                       break;
+
+               case Style.NEW:
+                       new_lines_width = d_new_lines.size + d_new_lines.xpad * 2;
+                       break;
+               }
+
                var sym_lines_width = d_sym_lines.size + d_sym_lines.xpad * 2;
 
-               ctx.save();
-               Gtk.cairo_transform_to_window(cr, this, win);
-               ctx.add_class("diff-lines-separator");
-               ctx.render_frame(cr, 0, 0, old_lines_width, win.get_height());
-               ctx.restore();
+               if (d_style == Style.ONE)
+               {
+                       ctx.save();
+                       Gtk.cairo_transform_to_window(cr, this, win);
+                       ctx.add_class("diff-lines-separator");
+                       ctx.render_frame(cr, 0, 0, old_lines_width, win.get_height());
+                       ctx.restore();
+               }
 
                ctx.save();
                Gtk.cairo_transform_to_window(cr, this, win);
@@ -647,8 +704,7 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
 
                int buffer_line = iter.get_line();
 
-               /* Diff Content */
-               var content = new StringBuilder();
+               int line_hunk_start = iter.get_line();
 
                var region = Region() {
                        type = RegionType.CONTEXT,
@@ -659,6 +715,9 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
 
                this.freeze_notify();
 
+               var add_line_num = 0;
+               var remove_line_num = 0;
+               var in_change_line = false;
                for (var i = 0; i < lines.size; i++)
                {
                        var line = lines[i];
@@ -716,7 +775,8 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
                                };
                        }
 
-                       region.length++;
+                       if (d_style == Style.ONE)
+                               region.length++;
 
                        if (added || removed)
                        {
@@ -748,45 +808,123 @@ class Gitg.DiffViewFileRendererText : Gtk.SourceView, DiffSelectable, DiffViewFi
                                text = text.slice(0, text.length - 1);
                        }
 
-                       content.append(text);
-                       buffer_line++;
-               }
+                       if (rtype == RegionType.CONTEXT)
+                       {
+                               if (d_style == Style.OLD || d_style == Style.NEW)
+                               {
+                                       if (in_change_line == true)
+                                       {
+                                               bool check = d_style == Style.OLD ? add_line_num > 
remove_line_num : remove_line_num > add_line_num;
+                                               if (check)
+                                               {
+                                                       int end = d_style == Style.OLD ? add_line_num - 
remove_line_num : remove_line_num - add_line_num;
+                                                       for (var l = 0; l < end; l++)
+                                                       {
+                                                               Gtk.TextIter t_iter;
+                                                               buffer.get_end_iter(out t_iter);
+                                                               buffer.create_source_mark(null, "empty", 
t_iter);
+
+                                                               buffer.insert(ref iter, "\n", -1);
+                                                               buffer_line++;
+                                                               region.buffer_line_start = buffer_line;
+                                                       }
+                                               }
+
+                                               add_line_num = 0;
+                                               remove_line_num = 0;
+                                       }
+
+                                       in_change_line = false;
+                               }
 
-               if (lines.size != 0)
-               {
-                       d_regions += region;
-               }
+                               buffer.insert(ref iter, text, -1);
+                               buffer_line++;
+                               if (d_style == Style.OLD || d_style == Style.NEW)
+                               {
+                                       region.length++;
+                               }
+                       }
 
-               int line_hunk_start = iter.get_line();
+                       RegionType? rtype_check = null;
+                       string mark = null;
+                       switch (d_style)
+                       {
+                       case Style.ONE:
+                       case Style.OLD:
+                               rtype_check = RegionType.REMOVED;
+                               mark = "removed";
+                               break;
+                       case Style.NEW:
+                               rtype_check = RegionType.ADDED;
+                               mark = "added";
+                               break;
+                       }
 
-               buffer.insert(ref iter, (string)content.data, -1);
+                       if (rtype == rtype_check)
+                       {
+                               Gtk.TextIter t_iter;
+                               buffer.get_end_iter(out t_iter);
+                               buffer.create_source_mark(null, mark, t_iter);
 
-               d_old_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, lines);
-               d_new_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, lines);
-               d_sym_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, lines);
+                               buffer.insert(ref iter, text, -1);
+                               buffer_line++;
+                               if (d_style == Style.OLD || d_style == Style.NEW)
+                               {
+                                       region.length++;
 
-               for (var i = 0; i < lines.size; i++)
-               {
-                       var line = lines[i];
-                       string? category = null;
+                                       if (d_style == Style.OLD)
+                                               remove_line_num++;
+                                       else
+                                               add_line_num++;
+                                       in_change_line = true;
+                               }
+                       }
 
-                       switch (line.get_origin())
+                       switch (d_style)
                        {
-                               case Ggit.DiffLineType.ADDITION:
-                                       category = "added";
-                                       break;
-                               case Ggit.DiffLineType.DELETION:
-                                       category = "removed";
-                                       break;
+                       case Style.ONE:
+                       case Style.OLD:
+                               rtype_check = RegionType.ADDED;
+                               break;
+                       case Style.NEW:
+                               rtype_check = RegionType.REMOVED;
+                               break;
                        }
-
-                       if (category != null)
+                       if (rtype == rtype_check)
                        {
-                               buffer.get_iter_at_line(out iter, line_hunk_start + i);
-                               buffer.create_source_mark(null, category, iter);
+                               if (d_style == Style.OLD || d_style == Style.NEW)
+                               {
+                                       if (d_style == Style.OLD)
+                                               add_line_num++;
+                                       else
+                                               remove_line_num++;
+                                       in_change_line = true;
+                               } else if (d_style == Style.ONE) {
+                                       Gtk.TextIter t_iter;
+                                       buffer.get_end_iter(out t_iter);
+                                       buffer.create_source_mark(null, "added", t_iter);
+
+                                       buffer.insert(ref iter, text, -1);
+                                       buffer_line++;
+                               }
                        }
                }
 
+               if (lines.size != 0)
+               {
+                       d_regions += region;
+               }
+
+               if (d_style == Style.ONE || d_style == Style.OLD)
+               {
+                       d_old_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, buffer);
+               }
+               if (d_style == Style.ONE || d_style == Style.NEW)
+               {
+                       d_new_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, buffer);
+               }
+               d_sym_lines.add_hunk(line_hunk_start, iter.get_line(), hunk, buffer);
+
                this.thaw_notify();
 
                sensitive = true;
diff --git a/libgitg/gitg-diff-view-file-renderer-textable.vala 
b/libgitg/gitg-diff-view-file-renderer-textable.vala
new file mode 100644
index 00000000..0bf7e603
--- /dev/null
+++ b/libgitg/gitg-diff-view-file-renderer-textable.vala
@@ -0,0 +1,28 @@
+/*
+ * This file is part of gitg
+ *
+ * Copyright (C) 2016 - Jesse van den Kieboom
+ *
+ * gitg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gitg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gitg. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+interface Gitg.DiffViewFileRendererTextable : DiffSelectable, DiffViewFileRenderer
+{
+       public abstract bool wrap_lines { get; set; }
+       public abstract new int tab_width { get; set; }
+       public abstract int maxlines { get; set; }
+       public abstract bool highlight { get; construct set; }
+}
+
+// ex:ts=4 noet
diff --git a/libgitg/gitg-diff-view-file.vala b/libgitg/gitg-diff-view-file.vala
index 3794f92d..b7b9331e 100644
--- a/libgitg/gitg-diff-view-file.vala
+++ b/libgitg/gitg-diff-view-file.vala
@@ -40,7 +40,7 @@ class Gitg.DiffViewFile : Gtk.Grid
 
        private bool d_expanded;
 
-       public DiffViewFileRendererText? renderer_text {get; private set;}
+       public Gee.ArrayList<DiffViewFileRenderer> renderer_list {get; private set;}
 
        public bool new_is_workdir { get; construct set; }
 
@@ -75,11 +75,44 @@ class Gitg.DiffViewFile : Gtk.Grid
        public DiffViewFileInfo? info {get; construct set;}
        private Gee.HashMap<Gtk.Widget, bool> d_diff_stat_visible_map = new Gee.HashMap<Gtk.Widget, bool>();
 
+       public bool has_selection()
+       {
+               bool has_selection = false;
+               foreach (DiffViewFileRenderer renderer in renderer_list)
+               {
+                       var selectable = renderer as DiffSelectable;
+                       if (selectable != null)
+                               has_selection = selectable.has_selection;
+                       if (has_selection)
+                               break;
+               }
+               return has_selection;
+       }
+
+       public PatchSet get_selection()
+       {
+               var ret = new PatchSet();
+
+               foreach (var renderer in renderer_list)
+               {
+                       var sel = renderer as DiffSelectable;
+
+                       if (sel != null && sel.has_selection && sel.selection.patches.length != 0)
+                       {
+                               ret = sel.selection;
+                               break;
+                       }
+               }
+
+               return ret;
+       }
+
        public DiffViewFile(DiffViewFileInfo? info)
        {
                Object(info: info);
                bind_property("vexpand", d_stack_file_renderer, "vexpand", BindingFlags.SYNC_CREATE);
                d_stack_file_renderer.notify["visible-child"].connect(page_changed);
+               renderer_list = new Gee.ArrayList<DiffViewFileRenderer>();
        }
 
        private void page_changed()
@@ -89,40 +122,53 @@ class Gitg.DiffViewFile : Gtk.Grid
                d_diff_stat_file.set_visible(visible);
        }
 
-       public void add_renderer(Gtk.Widget widget, string name, string title, bool show_stats)
+       public void add_renderer(DiffViewFileRenderer renderer, Gtk.Widget widget, string name, string title, 
bool show_stats)
        {
                d_diff_stat_visible_map.set(widget, show_stats);
+               renderer_list.add(renderer);
                d_stack_file_renderer.add_titled(widget, name, title);
                bool visible = d_stack_file_renderer.get_children().length() > 1;
                d_stack_switcher.set_visible(visible);
        }
 
-       public void add_text_renderer(bool handle_selection)
+       public void add_text_renderer(bool handle_selection, uint num_parents)
        {
-               renderer_text = new DiffViewFileRendererText(info, handle_selection);
-               renderer_text.show();
+               var renderer = new DiffViewFileRendererText(info, handle_selection, 
DiffViewFileRendererText.Style.ONE);
+               renderer.show();
                var scrolled_window = new Gtk.ScrolledWindow (null, null);
-               scrolled_window.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
-               scrolled_window.add(renderer_text);
+               scrolled_window.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.NEVER);
+               scrolled_window.add(renderer);
                scrolled_window.show();
 
-               renderer_text.bind_property("added", d_diff_stat_file, "added");
-               renderer_text.bind_property("removed", d_diff_stat_file, "removed");
-               add_renderer(scrolled_window, "text", _("Text"), true);
+               renderer.bind_property("added", d_diff_stat_file, "added");
+               renderer.bind_property("removed", d_diff_stat_file, "removed");
+               add_renderer(renderer, scrolled_window, "text", _("Unif"), true);
+
+               var renderer_split = new DiffViewFileRendererTextSplit(info, handle_selection);
+               renderer_split.show();
+               add_renderer(renderer_split, renderer_split, "splittext", _("Split"), true);
+
+               if (num_parents > 1)
+               {
+                       var renderer_three = new DiffViewFileRendererTextThree(info, handle_selection);
+                       renderer_three.show();
+                       add_renderer(renderer_three, renderer_three, "threetext", _("Merge"), true);
+               }
+
        }
 
        public void add_binary_renderer()
        {
                var renderer = new DiffViewFileRendererBinary();
                renderer.show();
-               add_renderer(renderer, "binary", _("Binary"), false);
+               add_renderer(renderer, renderer, "binary", _("Binary"), false);
        }
 
        public void add_image_renderer()
        {
                var renderer = new DiffViewFileRendererImage(info.repository, info.delta);
                renderer.show();
-               add_renderer(renderer, "image", _("Image"), false);
+               add_renderer(renderer, renderer, "image", _("Image"), false);
        }
 
        protected override void constructed()
@@ -253,16 +299,9 @@ class Gitg.DiffViewFile : Gtk.Grid
 
        public void add_hunk(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
        {
-               if (renderer_text != null) {
-                       renderer_text.add_hunk(hunk, lines);
-               }
-               foreach (Gtk.Widget page in d_stack_file_renderer.get_children())
+               foreach (DiffViewFileRenderer renderer in renderer_list)
                {
-                       if (page is DiffViewFileRenderer)
-                       {
-                               var renderer = (DiffViewFileRenderer)page;
-                               renderer.add_hunk(hunk, lines);
-                       }
+                       renderer.add_hunk(hunk, lines);
                }
        }
 }
diff --git a/libgitg/gitg-diff-view-lines-renderer.vala b/libgitg/gitg-diff-view-lines-renderer.vala
index 51d8444a..51d50f0e 100644
--- a/libgitg/gitg-diff-view-lines-renderer.vala
+++ b/libgitg/gitg-diff-view-lines-renderer.vala
@@ -23,7 +23,17 @@ class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText
        {
                OLD,
                NEW,
-               SYMBOL
+               SYMBOL,
+               SYMBOL_OLD,
+               SYMBOL_NEW
+       }
+
+       private enum Line_Style
+       {
+               CONTEXT,
+               ADDED,
+               REMOVED,
+               EMPTY
        }
 
        private int d_num_digits;
@@ -104,7 +114,7 @@ class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText
 
                if (info == null || (line - info.start) >= info.line_infos.length)
                {
-                       if (is_hunk && style != Style.SYMBOL)
+                       if (is_hunk && style != Style.SYMBOL && style != Style.SYMBOL_OLD && style != 
Style.SYMBOL_NEW)
                        {
                                set_text("...", -1);
                        }
@@ -186,48 +196,87 @@ class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText
                d_num_digits_fill = string.nfill(num_digits, ' ');
        }
 
-       private string[] precalculate_line_strings(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
+       private Line_Style get_origin(int buffer_line, Gtk.SourceBuffer buffer)
+       {
+               var origin = Line_Style.CONTEXT;
+
+               var mark = buffer.get_source_marks_at_line(buffer_line, null);
+               if (mark != null)
+               {
+                       mark.@foreach ((item) => {
+                               switch (item.get_category())
+                               {
+                               case "added":
+                                       origin = Line_Style.ADDED;
+                                       break;
+                               case "removed":
+                                       origin = Line_Style.REMOVED;
+                                       break;
+                               case "empty":
+                                       origin = Line_Style.EMPTY;
+                                       break;
+                               }
+                       });
+               }
+
+               return origin;
+       }
+
+       private string[] precalculate_line_strings(Ggit.DiffHunk hunk, Gtk.SourceBuffer buffer, int 
buffer_line_start)
        {
                var oldn = hunk.get_old_start();
                var newn = hunk.get_new_start();
 
-               var lns = lines;
+               Gtk.TextIter iter;
+               buffer.get_end_iter(out iter);
+               int buffer_line_end = iter.get_line();
 
-               var line_infos = new string[lns.size];
+               var line_infos = new string[buffer_line_end - buffer_line_start + 1];
 
-               for (var i = 0; i < lns.size; i++)
+               for (var i = 0; i <= (buffer_line_end - buffer_line_start); i++)
                {
-                       var line = lns[i];
-                       var origin = line.get_origin();
+                       var origin = get_origin(buffer_line_start + i, buffer);
 
                        string ltext = "";
 
                        switch (style)
                        {
                        case Style.NEW:
-                               if (origin == Ggit.DiffLineType.CONTEXT || origin == 
Ggit.DiffLineType.ADDITION)
+                               if (origin == Line_Style.CONTEXT || origin == Line_Style.ADDED)
                                {
                                        ltext = "%*d".printf(d_num_digits, newn);
                                        newn++;
                                }
                                break;
                        case Style.OLD:
-                               if (origin == Ggit.DiffLineType.CONTEXT || origin == 
Ggit.DiffLineType.DELETION)
+                               if (origin == Line_Style.CONTEXT || origin == Line_Style.REMOVED)
                                {
                                        ltext = "%*d".printf(d_num_digits, oldn);
                                        oldn++;
                                }
                                break;
                        case Style.SYMBOL:
-                               if (origin == Ggit.DiffLineType.ADDITION)
+                               if (origin == Line_Style.ADDED)
                                {
                                        ltext = "+";
                                }
-                               else if (origin == Ggit.DiffLineType.DELETION)
+                               else if (origin == Line_Style.REMOVED)
+                               {
+                                       ltext = "-";
+                               }
+                               break;
+                       case Style.SYMBOL_OLD:
+                               if (origin == Line_Style.REMOVED)
                                {
                                        ltext = "-";
                                }
                                break;
+                       case Style.SYMBOL_NEW:
+                               if (origin == Line_Style.ADDED)
+                               {
+                                       ltext = "+";
+                               }
+                               break;
                        }
 
                        line_infos[i] = ltext;
@@ -235,8 +284,7 @@ class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText
 
                return line_infos;
        }
-
-       public void add_hunk(int buffer_line_start, int buffer_line_end, Ggit.DiffHunk hunk, 
Gee.ArrayList<Ggit.DiffLine> lines)
+       public void add_hunk(int buffer_line_start, int buffer_line_end, Ggit.DiffHunk hunk, Gtk.SourceBuffer 
buffer)
        {
                HunkInfo info = HunkInfo();
 
@@ -246,7 +294,7 @@ class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText
                info.end = buffer_line_end;
                info.hunk_line = buffer_line_start - 1;
                info.hunk = hunk;
-               info.line_infos = precalculate_line_strings(hunk, lines);
+               info.line_infos = precalculate_line_strings(hunk, buffer, buffer_line_start);
 
                d_hunks_list.add(info);
 
diff --git a/libgitg/gitg-diff-view.vala b/libgitg/gitg-diff-view.vala
index 86c87f70..9e182fb1 100644
--- a/libgitg/gitg-diff-view.vala
+++ b/libgitg/gitg-diff-view.vala
@@ -590,7 +590,7 @@ public class Gitg.DiffView : Gtk.Grid
 
                if (d_diff != null)
                {
-                       update_diff(d_diff, preserve_expanded, d_cancellable);
+                       update_diff(d_diff, preserve_expanded, d_cancellable, d_commit.get_parents().size);
                }
        }
 
@@ -645,9 +645,7 @@ public class Gitg.DiffView : Gtk.Grid
 
                foreach (var file in d_grid_files.get_children())
                {
-                       var selectable = ((Gitg.DiffViewFile) file).renderer_text as DiffSelectable;
-
-                       if (selectable != null && selectable.has_selection)
+                       if (((Gitg.DiffViewFile) file).has_selection())
                        {
                                something_selected = true;
                                break;
@@ -695,7 +693,7 @@ public class Gitg.DiffView : Gtk.Grid
                return "";
        }
 
-       private void update_diff(Ggit.Diff diff, bool preserve_expanded, Cancellable? cancellable)
+       private void update_diff(Ggit.Diff diff, bool preserve_expanded, Cancellable? cancellable, uint 
num_parents)
        {
                var nqueries = 0;
                var finished = false;
@@ -705,7 +703,7 @@ public class Gitg.DiffView : Gtk.Grid
                        if (nqueries == 0 && finished && (cancellable == null || !cancellable.is_cancelled()))
                        {
                                finished = false;
-                               update_diff_hunks(diff, preserve_expanded, infomap, cancellable);
+                               update_diff_hunks(diff, preserve_expanded, infomap, cancellable, num_parents);
                        }
                };
 
@@ -732,7 +730,7 @@ public class Gitg.DiffView : Gtk.Grid
                check_finish();
        }
 
-       private void update_diff_hunks(Ggit.Diff diff, bool preserve_expanded, Gee.HashMap<string, 
DiffViewFileInfo> infomap, Cancellable? cancellable)
+       private void update_diff_hunks(Ggit.Diff diff, bool preserve_expanded, Gee.HashMap<string, 
DiffViewFileInfo> infomap, Cancellable? cancellable, uint num_parents)
        {
                var files = new Gee.ArrayList<Gitg.DiffViewFile>();
 
@@ -836,13 +834,20 @@ public class Gitg.DiffView : Gtk.Grid
                                        }
                                        if (can_diff_as_text)
                                        {
-                                               current_file.add_text_renderer(handle_selection);
-                                               var renderer_text = current_file.renderer_text;
-                                               bind_property("highlight", renderer_text, "highlight", 
BindingFlags.SYNC_CREATE);
-                                               bind_property("wrap-lines", renderer_text, "wrap-lines", 
BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
-                                               bind_property("tab-width", renderer_text, "tab-width", 
BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
-                                               renderer_text.maxlines = maxlines;
-                                               
renderer_text.notify["has-selection"].connect(on_selection_changed);
+                                               current_file.add_text_renderer(handle_selection, num_parents);
+                                               var renderer_list = current_file.renderer_list;
+                                               foreach (DiffViewFileRenderer renderer in renderer_list)
+                                               {
+                                                       var renderer_text = renderer as 
DiffViewFileRendererTextable;
+                                                       if (renderer_text != null)
+                                                       {
+                                                               bind_property("highlight", renderer_text, 
"highlight", BindingFlags.SYNC_CREATE);
+                                                               bind_property("wrap-lines", renderer_text, 
"wrap-lines", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
+                                                               bind_property("tab-width", renderer_text, 
"tab-width", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
+                                                               renderer_text.maxlines = maxlines;
+                                                               
renderer_text.notify["has-selection"].connect(on_selection_changed);
+                                                       }
+                                               }
                                        }
                                        if (current_is_binary)
                                        {
@@ -962,12 +967,7 @@ public class Gitg.DiffView : Gtk.Grid
 
                foreach (var file in d_grid_files.get_children())
                {
-                       var sel = ((Gitg.DiffViewFile) file).renderer_text as DiffSelectable;
-
-                       if (sel != null && sel.has_selection && sel.selection.patches.length != 0)
-                       {
-                               ret += sel.selection;
-                       }
+                       ret += ((Gitg.DiffViewFile)file).get_selection();
                }
 
                return ret;
diff --git a/libgitg/meson.build b/libgitg/meson.build
index e20e07c8..56105239 100644
--- a/libgitg/meson.build
+++ b/libgitg/meson.build
@@ -43,6 +43,9 @@ sources = files(
   'gitg-diff-view-file-renderer-binary.vala',
   'gitg-diff-view-file-renderer-image.vala',
   'gitg-diff-view-file-renderer-text.vala',
+  'gitg-diff-view-file-renderer-textable.vala',
+  'gitg-diff-view-file-renderer-text-split.vala',
+  'gitg-diff-view-file-renderer-text-three.vala',
   'gitg-diff-view-file-renderer.vala',
   'gitg-diff-view-file-selectable.vala',
   'gitg-diff-view-file.vala',
@@ -76,6 +79,8 @@ resource_data = files(
   'resources/ui/gitg-diff-view-file-renderer-binary.ui',
   'resources/ui/gitg-diff-view-file-renderer-image.ui',
   'resources/ui/gitg-diff-view-file-renderer-text.ui',
+  'resources/ui/gitg-diff-view-file-renderer-text-split.ui',
+  'resources/ui/gitg-diff-view-file-renderer-text-three.ui',
   'resources/ui/gitg-diff-view-file.ui',
   'resources/ui/gitg-diff-view-options-spacing.ui',
   'resources/ui/gitg-diff-view-options.ui',
diff --git a/libgitg/resources/resources.xml b/libgitg/resources/resources.xml
index b47a8e21..87a4f333 100644
--- a/libgitg/resources/resources.xml
+++ b/libgitg/resources/resources.xml
@@ -8,6 +8,8 @@
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-image.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-text.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-binary.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-text-split.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-text-three.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-options.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-options-spacing.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-commit-details.ui</file>
diff --git a/libgitg/resources/ui/gitg-diff-view-file-renderer-text-split.ui 
b/libgitg/resources/ui/gitg-diff-view-file-renderer-text-split.ui
new file mode 100644
index 00000000..572bb56f
--- /dev/null
+++ b/libgitg/resources/ui/gitg-diff-view-file-renderer-text-split.ui
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.19.0 -->
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <template class="GitgDiffViewFileRendererTextSplit" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="homogeneous">False</property>
+    <property name="orientation">horizontal</property>
+    <child>
+      <object class="GtkScrolledWindow" id="scroll_left">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+       <property name="vscrollbar-policy">never</property>
+      </object>
+      <packing>
+        <property name="pack-type">start</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="scroll_right">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+       <property name="vscrollbar-policy">never</property>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/libgitg/resources/ui/gitg-diff-view-file-renderer-text-three.ui 
b/libgitg/resources/ui/gitg-diff-view-file-renderer-text-three.ui
new file mode 100644
index 00000000..a3f7772d
--- /dev/null
+++ b/libgitg/resources/ui/gitg-diff-view-file-renderer-text-three.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.19.0 -->
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <template class="GitgDiffViewFileRendererTextThree" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="homogeneous">False</property>
+    <property name="orientation">horizontal</property>
+    <child>
+      <object class="GtkScrolledWindow" id="scroll_left">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+       <property name="vscrollbar-policy">never</property>
+      </object>
+      <packing>
+        <property name="pack-type">start</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="scroll_center">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+       <property name="vscrollbar-policy">never</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="scroll_right">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+       <property name="vscrollbar-policy">never</property>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/libgitg/resources/ui/gitg-diff-view-file.ui b/libgitg/resources/ui/gitg-diff-view-file.ui
index 22e67905..8fcd9118 100644
--- a/libgitg/resources/ui/gitg-diff-view-file.ui
+++ b/libgitg/resources/ui/gitg-diff-view-file.ui
@@ -80,8 +80,6 @@
         <child>
           <object class="GtkStack" id="stack_file_renderer">
             <property name="visible">True</property>
-            <property name="vexpand">True</property>
-            <property name="hexpand">True</property>
           </object>
         </child>
       </object>


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