Have the HTML syntax highlighter store data about tag locations so the rest of the editor can use it

This commit is contained in:
Kovid Goyal 2014-02-01 12:58:39 +05:30
parent 7cdb090057
commit b37a78fd89
2 changed files with 23 additions and 1 deletions

View File

@ -56,6 +56,7 @@ class SyntaxHighlighter(QSyntaxHighlighter):
if state == -1: if state == -1:
state = 0 state = 0
state = self.state_class(state) state = self.state_class(state)
state.get_user_data, state.set_user_data = self.currentBlockUserData, self.setCurrentBlockUserData
for i, num, fmt in run_loop(state, self.state_map, self.formats, unicode(text)): for i, num, fmt in run_loop(state, self.state_map, self.formats, unicode(text)):
if fmt is not None: if fmt is not None:
self.setFormat(i, num, fmt) self.setFormat(i, num, fmt)

View File

@ -8,8 +8,9 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import re import re
from functools import partial from functools import partial
from collections import namedtuple
from PyQt4.Qt import QFont from PyQt4.Qt import QFont, QTextBlockUserData
from calibre.gui2.tweak_book.editor import SyntaxTextCharFormat from calibre.gui2.tweak_book.editor import SyntaxTextCharFormat
from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter, run_loop from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter, run_loop
@ -122,6 +123,22 @@ def mark_nbsp(state, text, nbsp_format):
ans = [(len(text), fmt)] ans = [(len(text), fmt)]
return ans return ans
TagStart = namedtuple('TagStart', 'prefix name closing offset')
TagEnd = namedtuple('TagEnd', 'self_closing offset')
class HTMLUserData(QTextBlockUserData):
def __init__(self):
QTextBlockUserData.__init__(self)
self.tags = []
def add_tag_data(state, tag):
ud = q = state.get_user_data()
if ud is None:
ud = HTMLUserData()
ud.tags.append(tag)
if q is None:
state.set_user_data(ud)
def normal(state, text, i, formats): def normal(state, text, i, formats):
' The normal state in between tags ' ' The normal state in between tags '
@ -154,6 +171,7 @@ def normal(state, text, i, formats):
if prefix and name: if prefix and name:
ans.append((len(prefix)+1, formats['nsprefix'])) ans.append((len(prefix)+1, formats['nsprefix']))
ans.append((len(name or prefix), formats['tag_name'])) ans.append((len(name or prefix), formats['tag_name']))
add_tag_data(state, TagStart(prefix, name, closing, i))
return ans return ans
if ch == '&': if ch == '&':
@ -179,6 +197,7 @@ def opening_tag(cdata_tags, state, text, i, formats):
return [(1, formats['/'])] return [(1, formats['/'])]
state.parse = state.NORMAL state.parse = state.NORMAL
state.tag = State.UNKNOWN_TAG state.tag = State.UNKNOWN_TAG
add_tag_data(state, TagEnd(True, i))
return [(len(m.group()), formats['tag'])] return [(len(m.group()), formats['tag'])]
if ch == '>': if ch == '>':
state.parse = state.NORMAL state.parse = state.NORMAL
@ -190,6 +209,7 @@ def opening_tag(cdata_tags, state, text, i, formats):
state.parse = state.CSS state.parse = state.CSS
state.bold += int(tag in bold_tags) state.bold += int(tag in bold_tags)
state.italic += int(tag in italic_tags) state.italic += int(tag in italic_tags)
add_tag_data(state, TagEnd(False, i))
return [(1, formats['tag'])] return [(1, formats['tag'])]
m = attribute_name_pat.match(text, i) m = attribute_name_pat.match(text, i)
if m is None: if m is None:
@ -256,6 +276,7 @@ def closing_tag(state, text, i, formats):
if num > 1: if num > 1:
ans.insert(0, (num - 1, formats['bad-closing'])) ans.insert(0, (num - 1, formats['bad-closing']))
state.tag = State.UNKNOWN_TAG state.tag = State.UNKNOWN_TAG
add_tag_data(state, TagEnd(False, pos))
return ans return ans
def in_comment(state, text, i, formats): def in_comment(state, text, i, formats):