mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add line numbers to the diff view
This commit is contained in:
parent
a7695626bf
commit
69f1382768
@ -9,10 +9,12 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import sys
|
import sys
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt4.Qt import (QSplitter, QApplication, QPlainTextDocumentLayout, QTextDocument, QTextCursor, QTextCharFormat)
|
from PyQt4.Qt import (
|
||||||
|
QSplitter, QApplication, QPlainTextDocumentLayout, QTextDocument,
|
||||||
|
QTextCursor, QTextCharFormat, Qt, QRect, QPainter, QPalette)
|
||||||
|
|
||||||
from calibre.gui2.tweak_book import tprefs
|
from calibre.gui2.tweak_book import tprefs
|
||||||
from calibre.gui2.tweak_book.editor.text import PlainTextEdit, get_highlighter, default_font_family
|
from calibre.gui2.tweak_book.editor.text import PlainTextEdit, get_highlighter, default_font_family, LineNumbers
|
||||||
from calibre.gui2.tweak_book.editor.themes import THEMES, default_theme, theme_color
|
from calibre.gui2.tweak_book.editor.themes import THEMES, default_theme, theme_color
|
||||||
from calibre.utils.diff import get_sequence_matcher
|
from calibre.utils.diff import get_sequence_matcher
|
||||||
|
|
||||||
@ -22,12 +24,13 @@ def get_theme():
|
|||||||
theme = THEMES[default_theme()]
|
theme = THEMES[default_theme()]
|
||||||
return theme
|
return theme
|
||||||
|
|
||||||
class TextBrowser(PlainTextEdit):
|
class TextBrowser(PlainTextEdit): # {{{
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
PlainTextEdit.__init__(self, parent)
|
PlainTextEdit.__init__(self, parent)
|
||||||
self.setReadOnly(True)
|
self.setReadOnly(True)
|
||||||
w = self.fontMetrics()
|
w = self.fontMetrics()
|
||||||
|
self.number_width = max(map(lambda x:w.width(str(x)), xrange(10)))
|
||||||
self.space_width = w.width(' ')
|
self.space_width = w.width(' ')
|
||||||
self.setLineWrapMode(self.WidgetWidth if tprefs['editor_line_wrap'] else self.NoWrap)
|
self.setLineWrapMode(self.WidgetWidth if tprefs['editor_line_wrap'] else self.NoWrap)
|
||||||
self.setTabStopWidth(tprefs['editor_tab_stop_width'] * self.space_width)
|
self.setTabStopWidth(tprefs['editor_tab_stop_width'] * self.space_width)
|
||||||
@ -46,8 +49,62 @@ class TextBrowser(PlainTextEdit):
|
|||||||
pal.setColor(pal.Highlight, theme_color(theme, 'Visual', 'bg'))
|
pal.setColor(pal.Highlight, theme_color(theme, 'Visual', 'bg'))
|
||||||
pal.setColor(pal.HighlightedText, theme_color(theme, 'Visual', 'fg'))
|
pal.setColor(pal.HighlightedText, theme_color(theme, 'Visual', 'fg'))
|
||||||
self.setPalette(pal)
|
self.setPalette(pal)
|
||||||
|
self.viewport().setCursor(Qt.ArrowCursor)
|
||||||
|
self.line_number_area = LineNumbers(self)
|
||||||
|
self.blockCountChanged[int].connect(self.update_line_number_area_width)
|
||||||
|
self.updateRequest.connect(self.update_line_number_area)
|
||||||
|
self.line_number_palette = pal = QPalette()
|
||||||
|
pal.setColor(pal.Base, theme_color(theme, 'LineNr', 'bg'))
|
||||||
|
pal.setColor(pal.Text, theme_color(theme, 'LineNr', 'fg'))
|
||||||
|
pal.setColor(pal.BrightText, theme_color(theme, 'LineNrC', 'fg'))
|
||||||
|
self.line_number_map = {}
|
||||||
|
|
||||||
class Highlight(QTextDocument):
|
def update_line_number_area_width(self, block_count=0):
|
||||||
|
self.setViewportMargins(self.line_number_area_width(), 0, 0, 0)
|
||||||
|
|
||||||
|
def line_number_area_width(self):
|
||||||
|
digits = 1
|
||||||
|
limit = max(1, self.blockCount())
|
||||||
|
while limit >= 10:
|
||||||
|
limit /= 10
|
||||||
|
digits += 1
|
||||||
|
|
||||||
|
return 8 + self.number_width * digits
|
||||||
|
|
||||||
|
def update_line_number_area(self, rect, dy):
|
||||||
|
if dy:
|
||||||
|
self.line_number_area.scroll(0, dy)
|
||||||
|
else:
|
||||||
|
self.line_number_area.update(0, rect.y(), self.line_number_area.width(), rect.height())
|
||||||
|
if rect.contains(self.viewport().rect()):
|
||||||
|
self.update_line_number_area_width()
|
||||||
|
|
||||||
|
def resizeEvent(self, ev):
|
||||||
|
PlainTextEdit.resizeEvent(self, ev)
|
||||||
|
cr = self.contentsRect()
|
||||||
|
self.line_number_area.setGeometry(QRect(cr.left(), cr.top(), self.line_number_area_width(), cr.height()))
|
||||||
|
|
||||||
|
def paint_line_numbers(self, ev):
|
||||||
|
painter = QPainter(self.line_number_area)
|
||||||
|
painter.fillRect(ev.rect(), self.line_number_palette.color(QPalette.Base))
|
||||||
|
|
||||||
|
block = self.firstVisibleBlock()
|
||||||
|
num = block.blockNumber()
|
||||||
|
top = int(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
|
||||||
|
bottom = top + int(self.blockBoundingRect(block).height())
|
||||||
|
painter.setPen(self.line_number_palette.color(QPalette.Text))
|
||||||
|
|
||||||
|
while block.isValid() and top <= ev.rect().bottom():
|
||||||
|
if block.isVisible() and bottom >= ev.rect().top():
|
||||||
|
painter.drawText(0, top, self.line_number_area.width() - 5, self.fontMetrics().height(),
|
||||||
|
Qt.AlignRight, unicode(self.line_number_map.get(num, '')))
|
||||||
|
block = block.next()
|
||||||
|
top = bottom
|
||||||
|
bottom = top + int(self.blockBoundingRect(block).height())
|
||||||
|
num += 1
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class Highlight(QTextDocument): # {{{
|
||||||
|
|
||||||
def __init__(self, parent, text, syntax):
|
def __init__(self, parent, text, syntax):
|
||||||
QTextDocument.__init__(self, parent)
|
QTextDocument.__init__(self, parent)
|
||||||
@ -77,6 +134,7 @@ class Highlight(QTextDocument):
|
|||||||
cursor.insertBlock()
|
cursor.insertBlock()
|
||||||
cursor.setCharFormat(QTextCharFormat())
|
cursor.setCharFormat(QTextCharFormat())
|
||||||
block = block.next()
|
block = block.next()
|
||||||
|
# }}}
|
||||||
|
|
||||||
class TextDiffView(QSplitter):
|
class TextDiffView(QSplitter):
|
||||||
|
|
||||||
@ -92,8 +150,8 @@ class TextDiffView(QSplitter):
|
|||||||
self.left_highlight, self.right_highlight = Highlight(self, left_text, syntax), Highlight(self, right_text, syntax)
|
self.left_highlight, self.right_highlight = Highlight(self, left_text, syntax), Highlight(self, right_text, syntax)
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
self.left_insert = partial(self.do_insert, self.left.textCursor(), self.left_highlight)
|
self.left_insert = partial(self.do_insert, self.left.textCursor(), self.left_highlight, self.left.line_number_map)
|
||||||
self.right_insert = partial(self.do_insert, self.right.textCursor(), self.right_highlight)
|
self.right_insert = partial(self.do_insert, self.right.textCursor(), self.right_highlight, self.right.line_number_map)
|
||||||
self.cruncher = get_sequence_matcher()(None, left_lines, right_lines)
|
self.cruncher = get_sequence_matcher()(None, left_lines, right_lines)
|
||||||
self.do_layout(context)
|
self.do_layout(context)
|
||||||
|
|
||||||
@ -102,6 +160,7 @@ class TextDiffView(QSplitter):
|
|||||||
|
|
||||||
def do_layout(self, context=None):
|
def do_layout(self, context=None):
|
||||||
self.left.clear(), self.right.clear()
|
self.left.clear(), self.right.clear()
|
||||||
|
self.left.line_number_map.clear(), self.right.line_number_map.clear()
|
||||||
if context is None:
|
if context is None:
|
||||||
for tag, alo, ahi, blo, bhi in self.cruncher.get_opcodes():
|
for tag, alo, ahi, blo, bhi in self.cruncher.get_opcodes():
|
||||||
getattr(self, tag)(alo, ahi, blo, bhi)
|
getattr(self, tag)(alo, ahi, blo, bhi)
|
||||||
@ -115,9 +174,11 @@ class TextDiffView(QSplitter):
|
|||||||
c.movePosition(c.Start)
|
c.movePosition(c.Start)
|
||||||
v.setTextCursor(c)
|
v.setTextCursor(c)
|
||||||
|
|
||||||
def do_insert(self, cursor, highlighter, lo, hi):
|
def do_insert(self, cursor, highlighter, line_number_map, lo, hi):
|
||||||
start_block = cursor.blockNumber()
|
start_block = cursor.blockNumber()
|
||||||
highlighter.copy_lines(lo, hi, cursor)
|
highlighter.copy_lines(lo, hi, cursor)
|
||||||
|
for num, i in enumerate(xrange(start_block, cursor.blockNumber())):
|
||||||
|
line_number_map[i] = lo + num + 1
|
||||||
return start_block, cursor.blockNumber()
|
return start_block, cursor.blockNumber()
|
||||||
|
|
||||||
def equal(self, alo, ahi, blo, bhi):
|
def equal(self, alo, ahi, blo, bhi):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user