On Fri, Mar 1, 2013 at 5:49 PM, Kai Willadsen <[email protected]> wrote:
> On 26 February 2013 06:58, Pedro Pedruzzi <[email protected]> wrote:
>> Hello, everyone!
>>
>> I'm a happy meld user and I've just joined this list because I have
>> some improvement ideas I'd like to share, discuss and help implement.
>>
>> The current visual highlighting of matching chunks is awesome. But the
>> scrolling can get a little confusing to use because it lacks
>> one-to-one alignment between lines in the panes.
>>
>> I'd like to experiment adding an option to make the diff view
>> scrolling fixed between panes. I'd have to add vertical spacing in the
>> panes to fill the gaps (can be done with "null" lines), so that
>> identical lines are always aligned (regardless of the scrolling
>> position) and so are matching chunks.
>>
>> What do you guys think of this idea?
>
> Plenty of people have requested this before, and I'm pretty sure
> there's a bug somewhere. It would be nice to have, but it's not all
> that easy to add.
>
>> I'd appreciate some guidance on how this could be hacked in the code base.
>
> It will be difficult to know what the best approach is until you're
> half way through. There are two basic options that come to mind: add
> extra linebreaks into the buffer, but make sure to account for them
> whenever handling text; or try to get the textview to do the extra
> padding for you. Both are probably broken in different ways (e.g.,
> line wrapping).
>
> For the first option, Meld has a strong assumption that the textbuffer
> isn't going to lie to us about line numbers. We assume that line 7 in
> our comparison will be line 7 in the buffer and vice versa. Fixing
> this would be a big undertaking, and would have all sorts of edge
> cases, but if done properly would be very worthwhile.
>
> The second option is to get the gtk.TextView to artificially inflate
> the last line of each misaligned chunk. This *should* be significantly
> easier, but not trivial to do properly. Basically, you'd create a tag
> per chunk and per pane, and iterate over chunks, checking to see
> whether their ending text iters y-locations match. If not, adjust the
> relevant tag's pixels-below-lines & pixels-below-lines-set properties
> to make them match. The hard part comes when the buffer changes and
> the tags need to be cleaned, adjusted, revalidated, etc. As a
> proof-of-concept, the first part could be done in
> FileDiff.on_textview_expose() I think, but in the long term I think
> doing the tag manipulation in there would be too slow. I haven't tried
> this, but I think it should work.
>
> Anyway, it would be cool to have this option, so if you have any
> questions, feel free to ask.

Thanks for the pointers.

I've came up with this proof-of-concept based on the second option.
The tags isn't getting updated on buffer change yet. This is just to
demonstrate how would it look and feel.

Please, tell me what you think.

I have some questions:

1. Where is a good place to do the tag creation? I tried somewhere in
the constructor but it seems that the linediffer was not ready to
iterate over changes yet.

2. How about 3 way filediffs? I would need to iterate over chunks on
the 3 panes.

The patch is also available on github if you prefer:

https://github.com/pedrox/meld/commit/9bc4113b8b128c9053b7cb3509a6b4437049a47b

Regards,
Pedro Pedruzzi

-- >8 --
Subject: [PATCH] Proof-of-concept: Make filediff panes aligned and with the
 same height by adding extra padding

---
 meld/filediff.py | 41 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 37 insertions(+), 4 deletions(-)

diff --git a/meld/filediff.py b/meld/filediff.py
index 36220c1..587d016 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -212,9 +212,14 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         self._cached_match = CachedSequenceMatcher()
         self.anim_source_id = [None for buf in self.textbuffer]
         self.animating_chunks = [[] for buf in self.textbuffer]
+        self._nopad = 0
         for buf in self.textbuffer:
             buf.create_tag("inline")

+        # self.linediffer.single_changes(0) is still empty at this point.
+        for change in self.linediffer.single_changes(0):
+            print(change)
+
         actions = (
             ("MakePatch", None, _("Format as patch..."), None,
_("Create a patch using differences between files"), self.make_patch),
             ("PrevConflict", None, _("Previous conflict"), "<Ctrl>I",
_("Go to the previous conflict"), lambda x:
self.on_next_conflict(gtk.gdk.SCROLL_UP)),
@@ -1271,6 +1276,28 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             self.text_filters = []
             self.refresh_comparison()

+    def xxx_init_paddings(self):
+        if self._nopad:
+            return
+
+        sumdy = 0
+
+        for change in self.linediffer.single_changes(0):
+            self._nopad = 1
+            dy = self.textview[0].get_y_for_line_num(change[2] - 1) -
self.textview[1].get_y_for_line_num(change[4] - 1) - sumdy
+            sumdy = sumdy + dy
+
+            if dy >= 0:
+                panepad = 1
+                padline = change[4] - 1
+            else:
+                panepad = 0
+                padline = change[2] - 1
+                dy = -dy
+
+            tag = self.textbuffer[panepad].create_tag(**{
"pixels-below-lines": dy, "pixels-below-lines-set": True })
+            self.textbuffer[panepad].apply_tag(tag,
self.textbuffer[panepad].get_iter_at_line(padline),
self.textbuffer[panepad].get_iter_at_line(padline + 1))
+
     def on_textview_expose_event(self, textview, event):
         if self.num_panes == 1:
             return
@@ -1299,6 +1326,8 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         context.clip()
         context.set_line_width(1.0)

+        self.xxx_init_paddings()
+
         for change in self.linediffer.single_changes(pane, bounds):
             ypos0 = textview.get_y_for_line_num(change[1]) - visible.y
             ypos1 = textview.get_y_for_line_num(change[2]) - visible.y
@@ -1551,7 +1580,14 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         if self._sync_vscroll_lock:
             return

-        if not self._scroll_lock and (self.keymask & MASK_SHIFT) == 0:
+        # scrollbar influence 0->1->2 or 0<-1->2 or 0<-1<-2
+        scrollbar_influence = ((1, 2), (0, 2), (1, 0))
+
+        if 1: # FIXME: aligned mode
+            # all the scrollbars get the same raw adjustment
+            for i in scrollbar_influence[master][:self.num_panes - 1]:
+
self.scrolledwindow[i].get_vadjustment().set_value(adjustment.value)
+        elif not self._scroll_lock and (self.keymask & MASK_SHIFT) == 0:
             self._sync_vscroll_lock = True
             syncpoint = 0.5

@@ -1561,9 +1597,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             line_y, height = self.textview[master].get_line_yrange(it)
             line = it.get_line() + ((master_y-line_y)/height)

-            # scrollbar influence 0->1->2 or 0<-1->2 or 0<-1<-2
-            scrollbar_influence = ((1, 2), (0, 2), (1, 0))
-
             for i in scrollbar_influence[master][:self.num_panes - 1]:
                 adj = self.scrolledwindow[i].get_vadjustment()
                 mbegin, mend = 0, self.textbuffer[master].get_line_count()
--
1.8.2.rc1
_______________________________________________
meld-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/meld-list

Reply via email to