Edit book: Fix a hang when editing an HTML or XML file with text of the form <abc: (i.e. a tag name with a trailing colon). Fixes #1314009 [Editor: wrongly placed colon causes hang](https://bugs.launchpad.net/calibre/+bug/1314009)

This commit is contained in:
Kovid Goyal 2014-04-29 10:13:14 +05:30
parent c3812f131b
commit f8d91b7a09
2 changed files with 29 additions and 23 deletions

View File

@ -24,8 +24,8 @@ class Tag(object):
def __init__(self, start_block, tag_start, end_block, tag_end, self_closing=False): def __init__(self, start_block, tag_start, end_block, tag_end, self_closing=False):
self.start_block, self.end_block = start_block, end_block self.start_block, self.end_block = start_block, end_block
self.start_offset, self.end_offset = tag_start.offset, tag_end.offset self.start_offset, self.end_offset = tag_start.offset, tag_end.offset
tag = tag_start.name or tag_start.prefix tag = tag_start.name
if tag_start.name and tag_start.prefix: if tag_start.prefix:
tag = tag_start.prefix + ':' + tag tag = tag_start.prefix + ':' + tag
self.name = tag self.name = tag
self.self_closing = self_closing self.self_closing = self_closing
@ -101,8 +101,8 @@ def find_tag_definition(block, offset):
return None, False return None, False
tag_start = boundary tag_start = boundary
closing = tag_start.closing closing = tag_start.closing
tag = tag_start.name or tag_start.prefix tag = tag_start.name
if tag_start.name and tag_start.prefix: if tag_start.prefix:
tag = tag_start.prefix + ':' + tag tag = tag_start.prefix + ':' + tag
return tag, closing return tag, closing

View File

@ -234,7 +234,7 @@ def css(state, text, i, formats):
if m is not None: if m is not None:
state.sub_parser_state = 0 state.sub_parser_state = 0
state.parse = IN_CLOSING_TAG state.parse = IN_CLOSING_TAG
add_tag_data(state, TagStart(m.start(), 'style', '', True, True)) add_tag_data(state, TagStart(m.start(), '', 'style', True, True))
ans.extend([(2, formats['end_tag']), (len(m.group()) - 2, formats['tag_name'])]) ans.extend([(2, formats['end_tag']), (len(m.group()) - 2, formats['tag_name'])])
return ans return ans
@ -248,7 +248,7 @@ def cdata(state, text, i, formats):
return [(len(text) - i, fmt)] return [(len(text) - i, fmt)]
state.parse = IN_CLOSING_TAG state.parse = IN_CLOSING_TAG
num = m.start() - i num = m.start() - i
add_tag_data(state, TagStart(m.start(), name, '', True, True)) add_tag_data(state, TagStart(m.start(), '', name, True, True))
return [(num, fmt), (2, formats['end_tag']), (len(m.group()) - 2, formats['tag_name'])] return [(num, fmt), (2, formats['end_tag']), (len(m.group()) - 2, formats['tag_name'])]
def mark_nbsp(state, text, nbsp_format): def mark_nbsp(state, text, nbsp_format):
@ -288,18 +288,23 @@ def normal(state, text, i, formats):
if m is None: if m is None:
return [(1, formats['<'])] return [(1, formats['<'])]
name = m.group() tname = m.group()
closing = name.startswith('/') closing = tname.startswith('/')
state.parse = IN_CLOSING_TAG if closing else IN_OPENING_TAG
ans = [(2 if closing else 1, formats['end_tag' if closing else 'tag'])]
if closing: if closing:
name = name[1:] tname = tname[1:]
prefix, name = name.partition(':')[0::2] if ':' in tname:
if prefix and name: prefix, name = tname.split(':', 1)
else:
prefix, name = '', tname
if prefix and not name:
return [(len(m.group()) + 1, formats['only-prefix'])]
ans = [(2 if closing else 1, formats['end_tag' if closing else 'tag'])]
if prefix:
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), formats['tag_name']))
state.parse = IN_CLOSING_TAG if closing else IN_OPENING_TAG
add_tag_data(state, TagStart(i, prefix, name, closing, True)) add_tag_data(state, TagStart(i, prefix, name, closing, True))
(state.close_tag if closing else state.open_tag)(name or prefix) (state.close_tag if closing else state.open_tag)(name)
return ans return ans
if ch == '&': if ch == '&':
@ -452,6 +457,7 @@ def create_formats(highlighter):
'?': _('Unknown character'), '?': _('Unknown character'),
'bad-closing': _('A closing tag must contain only the tag name and nothing else'), 'bad-closing': _('A closing tag must contain only the tag name and nothing else'),
'no-attr-value': _('Expecting an attribute value'), 'no-attr-value': _('Expecting an attribute value'),
'only-prefix': _('A tag name cannot end with a colon'),
}.iteritems(): }.iteritems():
f = formats[name] = SyntaxTextCharFormat(formats['error']) f = formats[name] = SyntaxTextCharFormat(formats['error'])
f.setToolTip(msg) f.setToolTip(msg)
@ -507,7 +513,7 @@ if __name__ == '__main__':
</style> </style>
<style type="text/css">p.small { font-size: x-small; color:gray }</style> <style type="text/css">p.small { font-size: x-small; color:gray }</style>
</head id="invalid attribute on closing tag"> </head id="invalid attribute on closing tag">
<body> <body><p:
<!-- The start of the actual body text --> <!-- The start of the actual body text -->
<h1>A heading that should appear in bold, with an <i>italic</i> word</h1> <h1>A heading that should appear in bold, with an <i>italic</i> word</h1>
<p>Some text with inline formatting, that is syntax highlighted. A <b>bold</b> word, and an <em>italic</em> word. \ <p>Some text with inline formatting, that is syntax highlighted. A <b>bold</b> word, and an <em>italic</em> word. \