Repository: alecthomas/chroma
Pull request #465 (2021-04-05 04:56:37)

fix: synthesisable entries are ignored when cloned
For example, if `chroma` is invoked on the command line, `LineNumbers`, `LineHighlight` et al are ignored.


Patch:
diff --git a/README.md b/README.md
index 21b21c7..c617130 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ Prefix | Language
 A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Arduino, Awk
 B | Ballerina, Base Makefile, Bash, Batchfile, BibTeX, BlitzBasic, BNF, Brainfuck
 C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython
-D | D, Dart, Diff, Django/Jinja, Docker, DTD
+D | D, Dart, Diff, Django/Jinja, Docker, DTD, Dylan
 E | EBNF, Elixir, Elm, EmacsLisp, Erlang
 F | Factor, Fish, Forth, Fortran, FSharp
 G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groovy
diff --git a/lexers/d/dylan.go b/lexers/d/dylan.go
new file mode 100644
index 0000000..0e51f45
--- /dev/null
+++ b/lexers/d/dylan.go
@@ -0,0 +1,74 @@
+package d
+
+import (
+	. "github.com/alecthomas/chroma" // nolint
+	"github.com/alecthomas/chroma/lexers/internal"
+)
+
+// Dylan lexer.
+var Dylan = internal.Register(MustNewLexer(
+	&Config{
+		Name:            "Dylan",
+		Aliases:         []string{"dylan"},
+		Filenames:       []string{"*.dylan", "*.dyl", "*.intr"},
+		MimeTypes:       []string{"text/x-dylan"},
+		CaseInsensitive: true,
+	},
+	Rules{
+		"root": {
+			{`\s+`, Whitespace, nil},
+			{`//.*?\n`, CommentSingle, nil},
+			{`([a-z0-9-]+:)([ \t]*)(.*(?:\n[ \t].+)*)`, ByGroups(NameAttribute, Whitespace, LiteralString), nil},
+			Default(Push("code")),
+		},
+		"code": {
+			{`\s+`, Whitespace, nil},
+			{`//.*?\n`, CommentSingle, nil},
+			{`/\*`, CommentMultiline, Push("comment")},
+			{`"`, LiteralString, Push("string")},
+			{`'(\\.|\\[0-7]{1,3}|\\x[a-f0-9]{1,2}|[^\\\'\n])'`, LiteralStringChar, nil},
+			{`#b[01]+`, LiteralNumberBin, nil},
+			{`#o[0-7]+`, LiteralNumberOct, nil},
+			{`[-+]?(\d*\.\d+([ed][-+]?\d+)?|\d+(\.\d*)?e[-+]?\d+)`, LiteralNumberFloat, nil},
+			{`[-+]?\d+`, LiteralNumberInteger, nil},
+			{`#x[0-9a-f]+`, LiteralNumberHex, nil},
+
+			{`(\?\\?)([\w!&*<>|^$%@+~?/=-]+)(:)(token|name|variable|expression|body|case-body|\*)`,
+				ByGroups(Operator, NameVariable, Operator, NameBuiltin), nil},
+			{`(\?)(:)(token|name|variable|expression|body|case-body|\*)`,
+				ByGroups(Operator, Operator, NameVariable), nil},
+			{`(\?\\?)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(Operator, NameVariable), nil},
+
+			{`(=>|::|#\(|#\[|##|\?\?|\?=|\?|[(){}\[\],.;])`, Punctuation, nil},
+			{`:=`, Operator, nil},
+			{`#[tf]`, Literal, nil},
+			{`#"`, LiteralStringSymbol, Push("symbol")},
+			{`#[a-z0-9-]+`, Keyword, nil},
+			{`#(all-keys|include|key|next|rest)`, Keyword, nil},
+			{`[\w!&*<>|^$%@+~?/=-]+:`, KeywordConstant, nil},
+			{`<[\w!&*<>|^$%@+~?/=-]+>`, NameClass, nil},
+			{`\*[\w!&*<>|^$%@+~?/=-]+\*`, NameVariableGlobal, nil},
+			{`\$[\w!&*<>|^$%@+~?/=-]+`, NameConstant, nil},
+			{`(let|method|function)([ \t]+)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(NameBuiltin, Whitespace, NameVariable), nil},
+			{`(error|signal|return|break)`, NameException, nil},
+			{`(\\?)([\w!&*<>|^$%@+~?/=-]+)`, ByGroups(Operator, Name), nil},
+		},
+		"comment": {
+			{`[^*/]`, CommentMultiline, nil},
+			{`/\*`, CommentMultiline, Push()},
+			{`\*/`, CommentMultiline, Pop(1)},
+			{`[*/]`, CommentMultiline, nil},
+		},
+		"symbol": {
+			{`"`, LiteralStringSymbol, Pop(1)},
+			{`[^\\"]+`, LiteralStringSymbol, nil},
+		},
+		"string": {
+			{`"`, LiteralString, Pop(1)},
+			{`\\([\\abfnrtv"\']|x[a-f0-9]{2,4}|[0-7]{1,3})`, LiteralStringEscape, nil},
+			{`[^\\"\n]+`, LiteralString, nil},
+			{`\\\n`, LiteralString, nil},
+			{`\\`, LiteralString, nil},
+		},
+	},
+))
diff --git a/lexers/p/powershell.go b/lexers/p/powershell.go
index de36dbe..9b7b56e 100644
--- a/lexers/p/powershell.go
+++ b/lexers/p/powershell.go
@@ -33,9 +33,9 @@ func powershellRules() Rules {
 			{`"`, LiteralStringDouble, Push("string")},
 			{`'([^']|'')*'`, LiteralStringSingle, nil},
 			{`(\$|@@|@)((global|script|private|env):)?\w+`, NameVariable, nil},
+			{`[a-z]\w*-[a-z]\w*\b`, NameBuiltin, nil},
 			{`(while|validateset|validaterange|validatepattern|validatelength|validatecount|until|trap|switch|return|ref|process|param|parameter|in|if|global:|function|foreach|for|finally|filter|end|elseif|else|dynamicparam|do|default|continue|cmdletbinding|break|begin|alias|\?|%|#script|#private|#local|#global|mandatory|parametersetname|position|valuefrompipeline|valuefrompipelinebypropertyname|valuefromremainingarguments|helpmessage|try|catch|throw)\b`, Keyword, nil},
 			{`-(and|as|band|bnot|bor|bxor|casesensitive|ccontains|ceq|cge|cgt|cle|clike|clt|cmatch|cne|cnotcontains|cnotlike|cnotmatch|contains|creplace|eq|exact|f|file|ge|gt|icontains|ieq|ige|igt|ile|ilike|ilt|imatch|ine|inotcontains|inotlike|inotmatch|ireplace|is|isnot|le|like|lt|match|ne|not|notcontains|notlike|notmatch|or|regex|replace|wildcard)\b`, Operator, nil},
-			{`(write|where|watch|wait|use|update|unregister|unpublish|unprotect|unlock|uninstall|undo|unblock|trace|test|tee|take|sync|switch|suspend|submit|stop|step|start|split|sort|skip|show|set|send|select|search|scroll|save|revoke|resume|restore|restart|resolve|resize|reset|request|repair|rename|remove|register|redo|receive|read|push|publish|protect|pop|ping|out|optimize|open|new|move|mount|merge|measure|lock|limit|join|invoke|install|initialize|import|hide|group|grant|get|format|foreach|find|export|expand|exit|enter|enable|edit|dismount|disconnect|disable|deny|debug|cxnew|copy|convertto|convertfrom|convert|connect|confirm|compress|complete|compare|close|clear|checkpoint|block|backup|assert|approve|aggregate|add)-[a-z_]\w*\b`, NameBuiltin, nil},
 			{`(ac|asnp|cat|cd|cfs|chdir|clc|clear|clhy|cli|clp|cls|clv|cnsn|compare|copy|cp|cpi|cpp|curl|cvpa|dbp|del|diff|dir|dnsn|ebp|echo|epal|epcsv|epsn|erase|etsn|exsn|fc|fhx|fl|foreach|ft|fw|gal|gbp|gc|gci|gcm|gcs|gdr|ghy|gi|gjb|gl|gm|gmo|gp|gps|gpv|group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md|measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri|rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|wget|where|wjb|write)\s`, NameBuiltin, nil},
 			{"\\[[a-z_\\[][\\w. `,\\[\\]]*\\]", NameConstant, nil},
 			{`-[a-z_]\w*`, Name, nil},
diff --git a/style.go b/style.go
index dce9e0a..516fef5 100644
--- a/style.go
+++ b/style.go
@@ -265,12 +265,12 @@ func (s *Style) Get(ttype TokenType) StyleEntry {
 
 func (s *Style) get(ttype TokenType) StyleEntry {
 	out := s.entries[ttype]
-	if out.IsZero() && s.synthesisable(ttype) {
-		out = s.synthesise(ttype)
-	}
 	if out.IsZero() && s.parent != nil {
 		return s.parent.get(ttype)
 	}
+	if out.IsZero() && s.synthesisable(ttype) {
+		out = s.synthesise(ttype)
+	}
 	return out
 }
 


Test patch:
diff --git a/lexers/testdata/dylan.actual b/lexers/testdata/dylan.actual
new file mode 100644
index 0000000..7c075f1
--- /dev/null
+++ b/lexers/testdata/dylan.actual
@@ -0,0 +1,20 @@
+Module: mod
+
+define constant $pi = 3.1415927d0;
+
+define macro moo
+  { moo(?:name, ?e:expression) } => { let ?name = ?e; }
+end;
+
+// abc
+define method foo-bar (n :: <integer>, #rest a, #key k, #all-keys) => (m :: <float>, b :: <boolean>)
+  let x = n + 2.0 + #b10 + #o2 + #x02;
+  format-out("dog // cat\n");
+  local method pi () $pi end;
+  pi()
+end method foo-bar;
+
+/*
+ cow
+ */
+foo-bar(2, k: k, a-b: c);
diff --git a/lexers/testdata/dylan.expected b/lexers/testdata/dylan.expected
new file mode 100644
index 0000000..e5e27da
--- /dev/null
+++ b/lexers/testdata/dylan.expected
@@ -0,0 +1,175 @@
+[
+  {"type":"NameAttribute","value":"Module:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralString","value":"mod"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"constant"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameConstant","value":"$pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberFloat","value":"3.1415927d0"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"macro"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"moo"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"moo"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Operator","value":"?:"},
+  {"type":"NameVariable","value":"name"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Operator","value":"?"},
+  {"type":"NameVariable","value":"e"},
+  {"type":"Operator","value":":"},
+  {"type":"NameBuiltin","value":"expression"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"=\u003e"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"let"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"?name"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Operator","value":"?"},
+  {"type":"NameVariable","value":"e"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"end"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"CommentSingle","value":"// abc\n"},
+  {"type":"Name","value":"define"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"foo-bar"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"n"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cinteger\u003e"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#rest"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"a"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#key"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"k"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Keyword","value":"#all-keys"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"=\u003e"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"m"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cfloat\u003e"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"b"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"::"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"\u003cboolean\u003e"},
+  {"type":"Punctuation","value":")"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"NameBuiltin","value":"let"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"x"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"="},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"n"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberFloat","value":"2.0"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberBin","value":"#b10"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberOct","value":"#o2"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"+"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberHex","value":"#x02"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"format-out"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralString","value":"\"dog // cat"},
+  {"type":"LiteralStringEscape","value":"\\n"},
+  {"type":"LiteralString","value":"\""},
+  {"type":"Punctuation","value":");"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"local"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"()"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameConstant","value":"$pi"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"end"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n  "},
+  {"type":"Name","value":"pi"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"end"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"method"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameVariable","value":"foo-bar"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"CommentMultiline","value":"/*\n cow\n */"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Name","value":"foo-bar"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralNumberInteger","value":"2"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"KeywordConstant","value":"k:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"k"},
+  {"type":"Punctuation","value":","},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"KeywordConstant","value":"a-b:"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Name","value":"c"},
+  {"type":"Punctuation","value":");"},
+  {"type":"TextWhitespace","value":"\n"}
+]
diff --git a/style_test.go b/style_test.go
index fca55b4..0a2292b 100644
--- a/style_test.go
+++ b/style_test.go
@@ -48,3 +48,18 @@ func TestSynthesisedStyleEntries(t *testing.T) {
 	assert.Equal(t, "#7f7f7f bg:#ffffff", style.Get(LineNumbers).String())
 	assert.Equal(t, "#7f7f7f bg:#ffffff", style.Get(LineNumbersTable).String())
 }
+
+func TestSynthesisedStyleClone(t *testing.T) {
+	style, err := NewStyle("test", StyleEntries{
+		Background:    "bg:#ffffff",
+		LineHighlight: "bg:#ffffff",
+		LineNumbers:   "bg:#fffff1",
+	})
+	assert.NoError(t, err)
+	style, err = style.Builder().Build()
+	assert.NoError(t, err)
+	assert.True(t, style.Has(LineHighlight))
+	assert.True(t, style.Has(LineNumbers))
+	assert.Equal(t, "bg:#ffffff", style.Get(LineHighlight).String())
+	assert.Equal(t, "bg:#fffff1", style.Get(LineNumbers).String())
+}