def __add__(self, other): """ Adds another diff to this one. Will throw an exception if this is not possible. (This will *not* be done in place.) """ if not isinstance(other, Diff): raise TypeError('Only diffs can be added to a diff.') if self.rename != other.rename and False not in (self.rename, other.rename): raise ConflictError('Diffs contain conflicting renamings.') result = copy.deepcopy(self) result.rename = self.rename or other.rename result.delete = self.delete or other.delete for line_nr in other._changes: change = other._changes[line_nr] if change.delete is True: result.delete_line(line_nr) if change.add_after is not False: result.add_lines(line_nr, change.add_after) if change.change is not False: result.change_line(line_nr, change.change[0], change.change[1]) return result
def change_line(self, line_nr, original_line, replacement): """ Changes the given line with the given line number. The replacement will be there instead. """ linediff = self._get_change(line_nr) if linediff.change is not False and linediff.change[1] != replacement: raise ConflictError("An already changed line cannot be changed.") linediff.change = (original_line, replacement) self._changes[line_nr] = linediff
def change_line(self, line_nr, original_line, replacement): r""" Changes the given line with the given line number. The replacement will be there instead. Given an empty diff object: >>> diff = Diff(['Hey there! Gorgeous.\n', ... "It's nice that we're here.\n"]) We can change a line easily: >>> diff.change_line(1, ... 'Hey there! Gorgeous.\n', ... 'Hey there! This is sad.\n') >>> diff.modified ['Hey there! This is sad.\n', "It's nice that we're here.\n"] We can even merge changes within one line: >>> diff.change_line(1, ... 'Hey there! Gorgeous.\n', ... 'Hello. :( Gorgeous.\n') >>> diff.modified ['Hello. :( This is sad.\n', "It's nice that we're here.\n"] However, if we change something that has been changed before, we'll get a conflict: >>> diff.change_line(1, # +ELLIPSIS ... 'Hey there! Gorgeous.\n', ... 'Hello. This is not ok. Gorgeous.\n') Traceback (most recent call last): ... coalib.results.LineDiff.ConflictError: ... """ linediff = self._get_change(line_nr) if linediff.change is not False and linediff.change[1] != replacement: if len(replacement) == len(linediff.change[1]) == 1: raise ConflictError('Cannot merge the given line changes.') orig_diff = Diff.from_string_arrays(linediff.change[0], linediff.change[1]) new_diff = Diff.from_string_arrays(linediff.change[0], replacement) replacement = ''.join((orig_diff + new_diff).modified) linediff.change = (original_line, replacement) self._changes[line_nr] = linediff
def add_lines(self, line_nr_before, lines): """ Adds lines after the given line number. :param line_nr_before: Line number of the line before the additions. Use 0 for insert lines before everything. :param lines: A list of lines to add. """ if lines == []: return # No action linediff = self._get_change(line_nr_before, min_line=0) if linediff.add_after is not False: raise ConflictError('Cannot add lines after the given line since ' 'there are already lines.') linediff.add_after = lines self._changes[line_nr_before] = linediff