Hi, Here is another version of the patch. It includes a slightly modified version of Kai's patch and tries to set sensitivity only when diff or active text view has changed.
Cheers, Piotr
From a634c0e8dee10c982c29dbcd8d7b813a58e512b4 Mon Sep 17 00:00:00 2001 From: Piotr Piastucki <[email protected]> Date: Thu, 17 Jun 2010 11:24:10 +0200 Subject: [PATCH] Add new change-related actions This commit adds a set of new bulk change actions including: Pull all non-conflicing and Merge all non-conflicting. Differ class enhancements are aimed at providing an efficient way of checking if there is anything to merge between selected files. --- data/ui/filediff-ui.xml | 4 +++ meld/diffutil.py | 19 +++++++++++++++++ meld/filediff.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++- meld/merge.py | 45 +++++++++++++++++++++++++++++++---------- 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/data/ui/filediff-ui.xml b/data/ui/filediff-ui.xml index 668ceb2..0327b5d 100644 --- a/data/ui/filediff-ui.xml +++ b/data/ui/filediff-ui.xml @@ -15,6 +15,10 @@ <menuitem action="PullLeft"/> <menuitem action="PullRight"/> <menuitem action="Delete"/> + <separator/> + <menuitem action="PullNonConflictingLeft"/> + <menuitem action="PullNonConflictingRight"/> + <menuitem action="MergeNonConflicting"/> </placeholder> </menu> </menubar> diff --git a/meld/diffutil.py b/meld/diffutil.py index b1d4c7b..d46fa7f 100644 --- a/meld/diffutil.py +++ b/meld/diffutil.py @@ -86,6 +86,7 @@ class Differ(gobject.GObject): self._line_cache = [[], [], []] self.ignore_blanks = False self._initialised = False + self._has_mergeable_changes = (False, False) def _update_merge_cache(self, texts): if self.num_sequences == 3: @@ -101,6 +102,13 @@ class Differ(gobject.GObject): self._consume_blank_lines(c[1], texts, 1, 2)) self._merge_cache = [x for x in self._merge_cache if x != (None, None)] + mergeable0, mergeable1 = False, False + for (c0, c1) in self._merge_cache: + mergeable0 = mergeable0 or (c0 != None and c0[0] != 'conflict') + mergeable1 = mergeable1 or (c1 != None and c1[0] != 'conflict') + if mergeable0 and mergeable1: + break + self._has_mergeable_changes = (mergeable0, mergeable1) self._update_line_cache() self.emit("diffs-changed") @@ -388,3 +396,14 @@ class Differ(gobject.GObject): texts = [""] * self.num_sequences self._initialised = False self._update_merge_cache(texts) + + def has_mergeable_changes(self, which): + if which == 0: + return (False, self._has_mergeable_changes[0]) + elif which == 1: + if self.num_sequences == 2: + return (self._has_mergeable_changes[0], False) + else: + return self._has_mergeable_changes + else: # which == 2 + return (self._has_mergeable_changes[1], False) diff --git a/meld/filediff.py b/meld/filediff.py index c5415a6..d47068d 100644 --- a/meld/filediff.py +++ b/meld/filediff.py @@ -33,6 +33,7 @@ from ui import gnomeglade import misc import melddoc import paths +import merge from util.sourceviewer import srcviewer @@ -185,6 +186,9 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): ("Delete", gtk.STOCK_DELETE, _("Delete"), "<Alt>Delete", _("Delete change"), self.delete_change), ("CopyAllLeft", gtk.STOCK_GOTO_FIRST, _("Copy To Left"), None, _("Copy all changes from right pane to left pane"), lambda x: self.copy_selected(-1)), ("CopyAllRight", gtk.STOCK_GOTO_LAST, _("Copy To Right"), None, _("Copy all changes from left pane to right pane"), lambda x: self.copy_selected(1)), + ("PullNonConflictingLeft", None, _("Pull all non-conflicting from left"), None, _("Pull all non-conflicting changes from right pane to left pane"), lambda x: self.pull_all_non_conflicting_changes(-1)), + ("PullNonConflictingRight", None, _("Pull all non-conflicting from right"), None, _("Pull all non-conflicting changes from left pane to right pane"), lambda x: self.pull_all_non_conflicting_changes(1)), + ("MergeNonConflicting", None, _("Merge all non-conflicting"), None, _("Merge all non-conflicting changes from left and right pane"), lambda x: self.merge_all_non_conflicting_changes()), ) self.ui_file = paths.ui_dir("filediff-ui.xml") @@ -324,6 +328,33 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): assert(chunk is not None) self.replace_chunk(src, dst, chunk) + def pull_all_non_conflicting_changes(self, direction): + assert direction in (-1,1) + dst = self._get_focused_pane() + src = dst + direction + assert src in range(self.num_panes) + merger = merge.Merger() + merger.differ = self.linediffer + merger.texts = [t for t in self._get_texts(raw=1)] + for mergedfile in merger.merge_2_files(src, dst): + pass + self.on_textbuffer__begin_user_action() + self.textbuffer[dst].set_text(mergedfile) + self.on_textbuffer__end_user_action() + self.scheduler.add_task( lambda : self._sync_vscroll( self.scrolledwindow[src].get_vadjustment(), src ) and None ) + + def merge_all_non_conflicting_changes(self): + dst = 1 + merger = merge.Merger() + merger.differ = self.linediffer + merger.texts = [t for t in self._get_texts(raw=1)] + for mergedfile in merger.merge_3_files(False): + pass + self.on_textbuffer__begin_user_action() + self.textbuffer[dst].set_text(mergedfile) + self.on_textbuffer__end_user_action() + self.scheduler.add_task( lambda : self._sync_vscroll( self.scrolledwindow[0].get_vadjustment(), 0 ) and None ) + def delete_change(self, widget): pane = self._get_focused_pane() chunk = self.linediffer.get_chunk(self.cursor.chunk, pane) @@ -335,6 +366,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): self.textview_focussed = view self.findbar.textview = view self.on_cursor_position_changed(view.get_buffer(), None, True) + self._set_merge_action_sensitivity() def _after_text_modified(self, buffer, startline, sizechange): if self.num_panes > 1: @@ -365,7 +397,9 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): if not line_end.ends_line(): line_end.forward_to_line_end() return self.buf.get_text(line_start, line_end, False) - + def __len__(self): + return self.buf.get_line_count() + class FakeTextArray(object): def __init__(self, bufs, textfilter): self.texts = [FakeText(b, textfilter) for b in bufs] @@ -769,6 +803,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): self.queue_draw() self.scheduler.add_task(self._update_highlighting().next) self._connect_buffer_handlers() + self._set_merge_action_sensitivity() for i in range(len(files)): if files[i]: srcviewer.set_highlighting_enabled_from_file(self.textbuffer[i], files[i], self.prefs.use_syntax_highlighting) @@ -781,7 +816,20 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component): for i in self._diff_files(files, panetext): yield i + def _set_merge_action_sensitivity(self): + pane = self._get_focused_pane() + editable = self.textview[pane].get_editable(); + mergeable = self.linediffer.has_mergeable_changes(pane) + self.actiongroup.get_action("PullNonConflictingLeft").set_sensitive(mergeable[0] and editable) + self.actiongroup.get_action("PullNonConflictingRight").set_sensitive(mergeable[1] and editable) + if self.num_panes == 3 and self.textview[1].get_editable(): + mergeable = self.linediffer.has_mergeable_changes(1) + else: + mergeable = (False, False) + self.actiongroup.get_action("MergeNonConflicting").set_sensitive(mergeable[0] or mergeable[1]) + def on_diffs_changed(self, linediffer): + self._set_merge_action_sensitivity() if self.linediffer.sequences_identical(): error_message = True in [m.has_message() for m in self.msgarea_mgr] if self.num_panes == 1 or error_message: diff --git a/meld/merge.py b/meld/merge.py index 3333f86..9eee924 100644 --- a/meld/merge.py +++ b/meld/merge.py @@ -188,7 +188,7 @@ class Merger(diffutil.Differ): else: return change[HI] - change[LO] - def merge_3_files(self): + def merge_3_files(self, mark_conflicts = True): LO, HI = 1, 2 self.unresolved = [] lastline = 0 @@ -208,18 +208,19 @@ class Merger(diffutil.Differ): lastline = low_mark if change[0] != None and change[1] != None and change[0][0] == 'conflict': high_mark = max(change[0][HI], change[1][HI]) - if low_mark < high_mark: - for i in range(low_mark, high_mark): - mergedtext.append("(??)" + self.texts[1][i]) + if mark_conflicts: + if low_mark < high_mark: + for i in range(low_mark, high_mark): + mergedtext.append("(??)" + self.texts[1][i]) + self.unresolved.append(mergedline) + mergedline += 1 + else: + #conflictsize = min(1, max(change[0][HI + 2] - change[0][LO + 2], change[1][HI + 2] - change[1][LO + 2])) + #for i in range(conflictsize): + mergedtext.append("(??)") self.unresolved.append(mergedline) mergedline += 1 - else: - #conflictsize = min(1, max(change[0][HI + 2] - change[0][LO + 2], change[1][HI + 2] - change[1][LO + 2])) - #for i in range(conflictsize): - mergedtext.append("(??)") - self.unresolved.append(mergedline) - mergedline += 1 - lastline = high_mark + lastline = high_mark elif change[0] != None: lastline += self._apply_change(self.texts[0], change[0], mergedtext) mergedline += change[0][HI + 2] - change[0][LO + 2] @@ -231,3 +232,25 @@ class Merger(diffutil.Differ): mergedtext.append(self.texts[1][i]) yield "\n".join(mergedtext) + + def merge_2_files(self, fromindex, toindex): + LO, HI = 1, 2 + self.unresolved = [] + lastline = 0 + mergedtext = [] + for change in self.differ.pair_changes(toindex, fromindex): + yield None + if change[0] == 'conflict': + low_mark = change[HI] + else: + low_mark = change[LO] + for i in range(lastline, low_mark): + mergedtext.append(self.texts[toindex][i]) + lastline = low_mark + if change[0] != 'conflict': + lastline += self._apply_change(self.texts[fromindex], change, mergedtext) + baselen = len(self.texts[toindex]) + for i in range(lastline, baselen): + mergedtext.append(self.texts[toindex][i]) + + yield "\n".join(mergedtext) -- 1.7.0.4
_______________________________________________ meld-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/meld-list
