Merge pull request #81 from asottile/fix_begin_end_hang
fix highlighting hang with empty begin end rules
This commit is contained in:
@@ -273,6 +273,7 @@ class CompiledRegsetRule(CompiledRule, Protocol):
|
|||||||
class Entry(NamedTuple):
|
class Entry(NamedTuple):
|
||||||
scope: Tuple[str, ...]
|
scope: Tuple[str, ...]
|
||||||
rule: CompiledRule
|
rule: CompiledRule
|
||||||
|
start: Tuple[str, int]
|
||||||
reg: _Reg = ERR_REG
|
reg: _Reg = ERR_REG
|
||||||
boundary: bool = False
|
boundary: bool = False
|
||||||
|
|
||||||
@@ -284,7 +285,7 @@ def _inner_capture_parse(
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
rule: CompiledRule,
|
rule: CompiledRule,
|
||||||
) -> Regions:
|
) -> Regions:
|
||||||
state = State.root(Entry(scope + rule.name, rule))
|
state = State.root(Entry(scope + rule.name, rule, (s, 0)))
|
||||||
_, regions = highlight_line(compiler, state, s, first_line=False)
|
_, regions = highlight_line(compiler, state, s, first_line=False)
|
||||||
return tuple(
|
return tuple(
|
||||||
r._replace(start=r.start + start, end=r.end + start) for r in regions
|
r._replace(start=r.start + start, end=r.end + start) for r in regions
|
||||||
@@ -440,7 +441,8 @@ class EndRule(NamedTuple):
|
|||||||
|
|
||||||
boundary = match.end() == len(match.string)
|
boundary = match.end() == len(match.string)
|
||||||
reg = make_reg(expand_escaped(match, self.end))
|
reg = make_reg(expand_escaped(match, self.end))
|
||||||
state = state.push(Entry(next_scope, self, reg, boundary))
|
start = (match.string, match.start())
|
||||||
|
state = state.push(Entry(next_scope, self, start, reg, boundary))
|
||||||
regions = _captures(compiler, scope, match, self.begin_captures)
|
regions = _captures(compiler, scope, match, self.begin_captures)
|
||||||
return state, True, regions
|
return state, True, regions
|
||||||
|
|
||||||
@@ -455,7 +457,16 @@ class EndRule(NamedTuple):
|
|||||||
if m.start() > pos:
|
if m.start() > pos:
|
||||||
ret.append(Region(pos, m.start(), state.cur.scope))
|
ret.append(Region(pos, m.start(), state.cur.scope))
|
||||||
ret.extend(_captures(compiler, state.cur.scope, m, self.end_captures))
|
ret.extend(_captures(compiler, state.cur.scope, m, self.end_captures))
|
||||||
return state.pop(), m.end(), False, tuple(ret)
|
# this is probably a bug in the grammar, but it pushed and popped at
|
||||||
|
# the same position.
|
||||||
|
# we'll advance the highlighter by one position to get past the loop
|
||||||
|
# this appears to be what vs code does as well
|
||||||
|
if state.entries[-1].start == (m.string, m.end()):
|
||||||
|
ret.append(Region(m.end(), m.end() + 1, state.cur.scope))
|
||||||
|
end = m.end() + 1
|
||||||
|
else:
|
||||||
|
end = m.end()
|
||||||
|
return state.pop(), end, False, tuple(ret)
|
||||||
|
|
||||||
def search(
|
def search(
|
||||||
self,
|
self,
|
||||||
@@ -501,7 +512,9 @@ class WhileRule(NamedTuple):
|
|||||||
|
|
||||||
boundary = match.end() == len(match.string)
|
boundary = match.end() == len(match.string)
|
||||||
reg = make_reg(expand_escaped(match, self.while_))
|
reg = make_reg(expand_escaped(match, self.while_))
|
||||||
state = state.push_while(self, Entry(next_scope, self, reg, boundary))
|
start = (match.string, match.start())
|
||||||
|
entry = Entry(next_scope, self, start, reg, boundary)
|
||||||
|
state = state.push_while(self, entry)
|
||||||
regions = _captures(compiler, scope, match, self.begin_captures)
|
regions = _captures(compiler, scope, match, self.begin_captures)
|
||||||
return state, True, regions
|
return state, True, regions
|
||||||
|
|
||||||
@@ -541,7 +554,7 @@ class Compiler:
|
|||||||
self._rule_to_grammar: Dict[_Rule, Grammar] = {}
|
self._rule_to_grammar: Dict[_Rule, Grammar] = {}
|
||||||
self._c_rules: Dict[_Rule, CompiledRule] = {}
|
self._c_rules: Dict[_Rule, CompiledRule] = {}
|
||||||
root = self._compile_root(grammar)
|
root = self._compile_root(grammar)
|
||||||
self.root_state = State.root(Entry(root.name, root))
|
self.root_state = State.root(Entry(root.name, root, ('', 0)))
|
||||||
|
|
||||||
def _visit_rule(self, grammar: Grammar, rule: _Rule) -> _Rule:
|
def _visit_rule(self, grammar: Grammar, rule: _Rule) -> _Rule:
|
||||||
self._rule_to_grammar[rule] = grammar
|
self._rule_to_grammar[rule] = grammar
|
||||||
|
|||||||
@@ -637,3 +637,25 @@ def test_backslash_z(compiler_state):
|
|||||||
assert regions2 == (
|
assert regions2 == (
|
||||||
Region(0, 6, ('test', 'comment')),
|
Region(0, 6, ('test', 'comment')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_buggy_begin_end_grammar(compiler_state):
|
||||||
|
# before this would result in an infinite loop of start / end
|
||||||
|
compiler, state = compiler_state({
|
||||||
|
'scopeName': 'test',
|
||||||
|
'patterns': [
|
||||||
|
{
|
||||||
|
'begin': '(?=</style)',
|
||||||
|
'end': '(?=</style)',
|
||||||
|
'name': 'css',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
state, regions = highlight_line(compiler, state, 'test </style', True)
|
||||||
|
|
||||||
|
assert regions == (
|
||||||
|
Region(0, 5, ('test',)),
|
||||||
|
Region(5, 6, ('test', 'css')),
|
||||||
|
Region(6, 12, ('test',)),
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user