Commit 122d40e3 authored by Kai Willadsen's avatar Kai Willadsen

Move BufferLines shim for line-based buffer access to meldbuffer

parent 0fed1f55
......@@ -77,89 +77,10 @@ class CachedSequenceMatcher(object):
del self.cache[item[0]]
class BufferLines(object):
"""gtk.TextBuffer shim with line-based access and optional filtering
This class allows a gtk.TextBuffer to be treated as a list of lines of
possibly-filtered text. If no filter is given, the raw output from the
gtk.TextBuffer is used.
The logic here (and in places in FileDiff) requires that Python's
unicode splitlines() implementation and gtk.TextBuffer agree on where
linebreaks occur. Happily, this is usually the case.
"""
def __init__(self, buf, textfilter=None):
self.buf = buf
if textfilter is not None:
self.textfilter = textfilter
else:
self.textfilter = lambda x: x
def __getslice__(self, lo, hi):
# FIXME: If we ask for arbitrary slices past the end of the buffer,
# this will return the last line.
start = self.buf.get_iter_at_line_or_eof(lo)
end = self.buf.get_iter_at_line_or_eof(hi)
txt = unicode(self.buf.get_text(start, end, False), 'utf8')
filter_txt = self.textfilter(txt)
lines = filter_txt.splitlines()
ends = filter_txt.splitlines(True)
# The last line in a gtk.TextBuffer is guaranteed never to end in a
# newline. As splitlines() discards an empty line at the end, we need
# to artificially add a line if the requested slice is past the end of
# the buffer, and the last line in the slice ended in a newline.
if hi >= self.buf.get_line_count() and \
lo < self.buf.get_line_count() and \
(len(lines) == 0 or len(lines[-1]) != len(ends[-1])):
lines.append(u"")
ends.append(u"")
hi = self.buf.get_line_count() if hi == sys.maxint else hi
if hi - lo != len(lines):
# These codepoints are considered line breaks by Python, but not
# by GtkTextStore.
additional_breaks = set((u'\x0c', u'\x85'))
i = 0
while i < len(ends):
line, end = lines[i], ends[i]
# It's possible that the last line in a file would end in a
# line break character, which requires no joining.
if end and end[-1] in additional_breaks and \
(not line or line[-1] not in additional_breaks):
assert len(ends) >= i + 1
lines[i:i + 2] = [line + end[-1] + lines[i + 1]]
ends[i:i + 2] = [end + ends[i + 1]]
i += 1
return lines
def __getitem__(self, i):
if i >= len(self):
raise IndexError
line_start = self.buf.get_iter_at_line_or_eof(i)
line_end = line_start.copy()
if not line_end.ends_line():
line_end.forward_to_line_end()
txt = self.buf.get_text(line_start, line_end, False)
return unicode(self.textfilter(txt), 'utf8')
def __len__(self):
return self.buf.get_line_count()
################################################################################
#
# FileDiff
#
################################################################################
MASK_SHIFT, MASK_CTRL = 1, 2
MODE_REPLACE, MODE_DELETE, MODE_INSERT = 0, 1, 2
class CursorDetails(object):
__slots__ = ("pane", "pos", "line", "offset", "chunk", "prev", "next",
"prev_conflict", "next_conflict")
......@@ -236,12 +157,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self.textview_focussed = None
self.textview_overwrite_handlers = [ t.connect("toggle-overwrite", self.on_textview_toggle_overwrite) for t in self.textview ]
self.textbuffer = [v.get_buffer() for v in self.textview]
self.buffer_texts = [BufferLines(b) for b in self.textbuffer]
self.buffer_texts = [meldbuffer.BufferLines(b) for b in self.textbuffer]
self.text_filters = []
self.create_text_filters()
app.connect("text-filters-changed", self.on_text_filters_changed)
self.buffer_filtered = [BufferLines(b, self._filter_text) for
b in self.textbuffer]
self.buffer_filtered = [meldbuffer.BufferLines(b, self._filter_text)
for b in self.textbuffer]
for (i, w) in enumerate(self.scrolledwindow):
w.get_vadjustment().connect("value-changed", self._sync_vscroll, i)
w.get_hadjustment().connect("value-changed", self._sync_hscroll)
......
### Copyright (C) 2002-2006 Stephen Kennedy <stevek@gnome.org>
### Copyright (C) 2009-2010 Kai Willadsen <kai.willadsen@gmail.com>
### Copyright (C) 2009-2011 Kai Willadsen <kai.willadsen@gmail.com>
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
......@@ -15,6 +15,8 @@
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import sys
import meld.util.sourceviewer
......@@ -63,3 +65,76 @@ class MeldBufferData(object):
self.encoding = None
self.newlines = None
class BufferLines(object):
"""gtk.TextBuffer shim with line-based access and optional filtering
This class allows a gtk.TextBuffer to be treated as a list of lines of
possibly-filtered text. If no filter is given, the raw output from the
gtk.TextBuffer is used.
The logic here (and in places in FileDiff) requires that Python's
unicode splitlines() implementation and gtk.TextBuffer agree on where
linebreaks occur. Happily, this is usually the case.
"""
def __init__(self, buf, textfilter=None):
self.buf = buf
if textfilter is not None:
self.textfilter = textfilter
else:
self.textfilter = lambda x: x
def __getslice__(self, lo, hi):
# FIXME: If we ask for arbitrary slices past the end of the buffer,
# this will return the last line.
start = self.buf.get_iter_at_line_or_eof(lo)
end = self.buf.get_iter_at_line_or_eof(hi)
txt = unicode(self.buf.get_text(start, end, False), 'utf8')
filter_txt = self.textfilter(txt)
lines = filter_txt.splitlines()
ends = filter_txt.splitlines(True)
# The last line in a gtk.TextBuffer is guaranteed never to end in a
# newline. As splitlines() discards an empty line at the end, we need
# to artificially add a line if the requested slice is past the end of
# the buffer, and the last line in the slice ended in a newline.
if hi >= self.buf.get_line_count() and \
lo < self.buf.get_line_count() and \
(len(lines) == 0 or len(lines[-1]) != len(ends[-1])):
lines.append(u"")
ends.append(u"")
hi = self.buf.get_line_count() if hi == sys.maxint else hi
if hi - lo != len(lines):
# These codepoints are considered line breaks by Python, but not
# by GtkTextStore.
additional_breaks = set((u'\x0c', u'\x85'))
i = 0
while i < len(ends):
line, end = lines[i], ends[i]
# It's possible that the last line in a file would end in a
# line break character, which requires no joining.
if end and end[-1] in additional_breaks and \
(not line or line[-1] not in additional_breaks):
assert len(ends) >= i + 1
lines[i:i + 2] = [line + end[-1] + lines[i + 1]]
ends[i:i + 2] = [end + ends[i + 1]]
i += 1
return lines
def __getitem__(self, i):
if i >= len(self):
raise IndexError
line_start = self.buf.get_iter_at_line_or_eof(i)
line_end = line_start.copy()
if not line_end.ends_line():
line_end.forward_to_line_end()
txt = self.buf.get_text(line_start, line_end, False)
return unicode(self.textfilter(txt), 'utf8')
def __len__(self):
return self.buf.get_line_count()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment