mirror of
https://github.com/alecthomas/chroma.git
synced 2025-07-15 01:14:21 +02:00
Fixed a fundamental bug where ^ would always match.
The engine was always passing a string sliced to the current position, resulting in ^ always matching. Switched to use FindRunesMatchStartingAt. Fixes #242.
This commit is contained in:
1
go.mod
1
go.mod
@ -10,5 +10,6 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.0.9
|
github.com/mattn/go-colorable v0.0.9
|
||||||
github.com/mattn/go-isatty v0.0.4
|
github.com/mattn/go-isatty v0.0.4
|
||||||
github.com/sergi/go-diff v1.0.0 // indirect
|
github.com/sergi/go-diff v1.0.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect
|
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect
|
||||||
)
|
)
|
||||||
|
7
lexers/testdata/ballerina.expected
vendored
7
lexers/testdata/ballerina.expected
vendored
@ -7,13 +7,16 @@
|
|||||||
{"type":"Text","value":"\n\n"},
|
{"type":"Text","value":"\n\n"},
|
||||||
{"type":"KeywordDeclaration","value":"endpoint"},
|
{"type":"KeywordDeclaration","value":"endpoint"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
{"type":"NameLabel","value":"http:"},
|
{"type":"Name","value":"http"},
|
||||||
|
{"type":"Operator","value":":"},
|
||||||
{"type":"Name","value":"Listener"},
|
{"type":"Name","value":"Listener"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
{"type":"Name","value":"listener"},
|
{"type":"Name","value":"listener"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
{"type":"Operator","value":"{"},
|
{"type":"Operator","value":"{"},
|
||||||
{"type":"NameLabel","value":"\n port:"},
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"Name","value":"port"},
|
||||||
|
{"type":"Operator","value":":"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
{"type":"Name","value":"9090"},
|
{"type":"Name","value":"9090"},
|
||||||
{"type":"Text","value":"\n"},
|
{"type":"Text","value":"\n"},
|
||||||
|
2
lexers/testdata/csharp.expected
vendored
2
lexers/testdata/csharp.expected
vendored
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{"type":"Name","value":"DriveInfo"},
|
{"type":"Name","value":"DriveInfo"},
|
||||||
{"type":"NameAttribute","value":"[]"},
|
{"type":"Punctuation","value":"[]"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
{"type":"Name","value":"drives"},
|
{"type":"Name","value":"drives"},
|
||||||
{"type":"Text","value":" "},
|
{"type":"Text","value":" "},
|
||||||
|
15
lexers/testdata/erlang.actual
vendored
Normal file
15
lexers/testdata/erlang.actual
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-module(repl).
|
||||||
|
|
||||||
|
-export([run/0]).
|
||||||
|
|
||||||
|
run() ->
|
||||||
|
read_eval_process().
|
||||||
|
|
||||||
|
read_eval_process() ->
|
||||||
|
Line = io:get_line("> "),
|
||||||
|
Out = process_line(Line),
|
||||||
|
io:format("< ~s~n~n", [Out]),
|
||||||
|
read_eval_process().
|
||||||
|
|
||||||
|
process_line(Line) ->
|
||||||
|
string:uppercase(Line).
|
79
lexers/testdata/erlang.expected
vendored
Normal file
79
lexers/testdata/erlang.expected
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
[
|
||||||
|
{"type":"Punctuation","value":"-"},
|
||||||
|
{"type":"NameEntity","value":"module"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"Name","value":"repl"},
|
||||||
|
{"type":"Punctuation","value":")."},
|
||||||
|
{"type":"Text","value":"\n\n"},
|
||||||
|
{"type":"Punctuation","value":"-"},
|
||||||
|
{"type":"NameEntity","value":"export"},
|
||||||
|
{"type":"Punctuation","value":"(["},
|
||||||
|
{"type":"Name","value":"run"},
|
||||||
|
{"type":"Operator","value":"/"},
|
||||||
|
{"type":"LiteralNumberInteger","value":"0"},
|
||||||
|
{"type":"Punctuation","value":"])."},
|
||||||
|
{"type":"Text","value":"\n\n"},
|
||||||
|
{"type":"NameFunction","value":"run"},
|
||||||
|
{"type":"Punctuation","value":"()"},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Operator","value":"-\u003e"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"Name","value":"read_eval_process"},
|
||||||
|
{"type":"Punctuation","value":"()."},
|
||||||
|
{"type":"Text","value":"\n\n"},
|
||||||
|
{"type":"NameFunction","value":"read_eval_process"},
|
||||||
|
{"type":"Punctuation","value":"()"},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Operator","value":"-\u003e"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"NameVariable","value":"Line"},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Operator","value":"="},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"NameNamespace","value":"io"},
|
||||||
|
{"type":"Punctuation","value":":"},
|
||||||
|
{"type":"NameFunction","value":"get_line"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"LiteralString","value":"\"\u003e \""},
|
||||||
|
{"type":"Punctuation","value":"),"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"NameVariable","value":"Out"},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Operator","value":"="},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Name","value":"process_line"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"NameVariable","value":"Line"},
|
||||||
|
{"type":"Punctuation","value":"),"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"NameNamespace","value":"io"},
|
||||||
|
{"type":"Punctuation","value":":"},
|
||||||
|
{"type":"NameFunction","value":"format"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"LiteralString","value":"\"\u003c "},
|
||||||
|
{"type":"LiteralStringInterpol","value":"~s~n~n"},
|
||||||
|
{"type":"LiteralString","value":"\""},
|
||||||
|
{"type":"Punctuation","value":","},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Punctuation","value":"["},
|
||||||
|
{"type":"NameVariable","value":"Out"},
|
||||||
|
{"type":"Punctuation","value":"]),"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"Name","value":"read_eval_process"},
|
||||||
|
{"type":"Punctuation","value":"()."},
|
||||||
|
{"type":"Text","value":"\n\n"},
|
||||||
|
{"type":"NameFunction","value":"process_line"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"NameVariable","value":"Line"},
|
||||||
|
{"type":"Punctuation","value":")"},
|
||||||
|
{"type":"Text","value":" "},
|
||||||
|
{"type":"Operator","value":"-\u003e"},
|
||||||
|
{"type":"Text","value":"\n "},
|
||||||
|
{"type":"NameNamespace","value":"string"},
|
||||||
|
{"type":"Punctuation","value":":"},
|
||||||
|
{"type":"NameFunction","value":"uppercase"},
|
||||||
|
{"type":"Punctuation","value":"("},
|
||||||
|
{"type":"NameVariable","value":"Line"},
|
||||||
|
{"type":"Punctuation","value":")."},
|
||||||
|
{"type":"Text","value":"\n"}
|
||||||
|
]
|
15
regexp.go
15
regexp.go
@ -276,7 +276,7 @@ func (l *LexerState) Iterator() Token {
|
|||||||
if !ok {
|
if !ok {
|
||||||
panic("unknown state " + l.State)
|
panic("unknown state " + l.State)
|
||||||
}
|
}
|
||||||
ruleIndex, rule, groups := matchRules(l.Text[l.Pos:], selectedRule)
|
ruleIndex, rule, groups := matchRules(l.Text, l.Pos, selectedRule)
|
||||||
// No match.
|
// No match.
|
||||||
if groups == nil {
|
if groups == nil {
|
||||||
// From Pygments :\
|
// From Pygments :\
|
||||||
@ -363,7 +363,12 @@ func (r *RegexLexer) maybeCompile() (err error) {
|
|||||||
for state, rules := range r.rules {
|
for state, rules := range r.rules {
|
||||||
for i, rule := range rules {
|
for i, rule := range rules {
|
||||||
if rule.Regexp == nil {
|
if rule.Regexp == nil {
|
||||||
rule.Regexp, err = regexp2.Compile("^(?"+rule.flags+")(?:"+rule.Pattern+")", 0)
|
pattern := "(?:" + rule.Pattern + ")"
|
||||||
|
if rule.flags != "" {
|
||||||
|
pattern = "(?" + rule.flags + ")" + pattern
|
||||||
|
}
|
||||||
|
pattern = `\G` + pattern
|
||||||
|
rule.Regexp, err = regexp2.Compile(pattern, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to compile rule %s.%d: %s", state, i, err)
|
return fmt.Errorf("failed to compile rule %s.%d: %s", state, i, err)
|
||||||
}
|
}
|
||||||
@ -415,10 +420,10 @@ func (r *RegexLexer) Tokenise(options *TokeniseOptions, text string) (Iterator,
|
|||||||
return state.Iterator, nil
|
return state.Iterator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchRules(text []rune, rules []*CompiledRule) (int, *CompiledRule, []string) {
|
func matchRules(text []rune, pos int, rules []*CompiledRule) (int, *CompiledRule, []string) {
|
||||||
for i, rule := range rules {
|
for i, rule := range rules {
|
||||||
match, err := rule.Regexp.FindRunesMatch(text)
|
match, err := rule.Regexp.FindRunesMatchStartingAt(text, pos)
|
||||||
if match != nil && err == nil {
|
if match != nil && err == nil && match.Index == pos {
|
||||||
groups := []string{}
|
groups := []string{}
|
||||||
for _, g := range match.Groups() {
|
for _, g := range match.Groups() {
|
||||||
groups = append(groups, g.String())
|
groups = append(groups, g.String())
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/alecthomas/assert"
|
"github.com/alecthomas/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewlineAtEndOfFile(t *testing.T) {
|
func TestNewlineAtEndOfFile(t *testing.T) {
|
||||||
@ -25,3 +26,21 @@ func TestNewlineAtEndOfFile(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []Token{{Error, "hello"}}, it.Tokens())
|
assert.Equal(t, []Token{{Error, "hello"}}, it.Tokens())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatchingAtStart(t *testing.T) {
|
||||||
|
l := Coalesce(MustNewLexer(&Config{}, Rules{
|
||||||
|
"root": {
|
||||||
|
{`\s+`, Whitespace, nil},
|
||||||
|
{`^-`, Punctuation, Push("directive")},
|
||||||
|
{`->`, Operator, nil},
|
||||||
|
},
|
||||||
|
"directive": {
|
||||||
|
{"module", NameEntity, Pop(1)},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
it, err := l.Tokenise(nil, `-module ->`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.Equal(t,
|
||||||
|
[]Token{{Punctuation, "-"}, {NameEntity, "module"}, {Whitespace, " "}, {Operator, "->"}},
|
||||||
|
it.Tokens())
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user