207 lines
6.4 KiB
Go
207 lines
6.4 KiB
Go
|
package c
|
||
|
|
||
|
import (
|
||
|
. "github.com/alecthomas/chroma" // nolint
|
||
|
"github.com/alecthomas/chroma/lexers/internal"
|
||
|
)
|
||
|
|
||
|
// caddyfileCommon are the rules common to both of the lexer variants
|
||
|
var caddyfileCommon = Rules{
|
||
|
"site_block_common": {
|
||
|
// Import keyword
|
||
|
{`(import)(\s+)([^\s]+)`, ByGroups(Keyword, Text, NameVariableMagic), nil},
|
||
|
// Matcher definition
|
||
|
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
|
||
|
// Matcher token stub for docs
|
||
|
{`\[\<matcher\>\]`, NameDecorator, Push("matcher")},
|
||
|
// These cannot have matchers but may have things that look like
|
||
|
// matchers in their arguments, so we just parse as a subdirective.
|
||
|
{`try_files`, Keyword, Push("subdirective")},
|
||
|
// These are special, they can nest more directives
|
||
|
{`handle_errors|handle|route|handle_path|not`, Keyword, Push("nested_directive")},
|
||
|
// Any other directive
|
||
|
{`[^\s#]+`, Keyword, Push("directive")},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"matcher": {
|
||
|
{`\{`, Punctuation, Push("block")},
|
||
|
// Not can be one-liner
|
||
|
{`not`, Keyword, Push("deep_not_matcher")},
|
||
|
// Any other same-line matcher
|
||
|
{`[^\s#]+`, Keyword, Push("arguments")},
|
||
|
// Terminators
|
||
|
{`\n`, Text, Pop(1)},
|
||
|
{`\}`, Punctuation, Pop(1)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"block": {
|
||
|
{`\}`, Punctuation, Pop(2)},
|
||
|
// Not can be one-liner
|
||
|
{`not`, Keyword, Push("not_matcher")},
|
||
|
// Any other subdirective
|
||
|
{`[^\s#]+`, Keyword, Push("subdirective")},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"nested_block": {
|
||
|
{`\}`, Punctuation, Pop(2)},
|
||
|
// Matcher definition
|
||
|
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
|
||
|
// Something that starts with literally < is probably a docs stub
|
||
|
{`\<[^#]+\>`, Keyword, Push("nested_directive")},
|
||
|
// Any other directive
|
||
|
{`[^\s#]+`, Keyword, Push("nested_directive")},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"not_matcher": {
|
||
|
{`\}`, Punctuation, Pop(2)},
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
{`[^\s#]+`, Keyword, Push("arguments")},
|
||
|
{`\s+`, Text, nil},
|
||
|
},
|
||
|
"deep_not_matcher": {
|
||
|
{`\}`, Punctuation, Pop(2)},
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
{`[^\s#]+`, Keyword, Push("deep_subdirective")},
|
||
|
{`\s+`, Text, nil},
|
||
|
},
|
||
|
"directive": {
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
Include("matcher_token"),
|
||
|
Include("comments_pop_1"),
|
||
|
{`\n`, Text, Pop(1)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"nested_directive": {
|
||
|
{`\{(?=\s)`, Punctuation, Push("nested_block")},
|
||
|
Include("matcher_token"),
|
||
|
Include("comments_pop_1"),
|
||
|
{`\n`, Text, Pop(1)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"subdirective": {
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
Include("comments_pop_1"),
|
||
|
{`\n`, Text, Pop(1)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"arguments": {
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
Include("comments_pop_2"),
|
||
|
{`\\\n`, Text, nil}, // Skip escaped newlines
|
||
|
{`\n`, Text, Pop(2)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"deep_subdirective": {
|
||
|
{`\{(?=\s)`, Punctuation, Push("block")},
|
||
|
Include("comments_pop_3"),
|
||
|
{`\n`, Text, Pop(3)},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"matcher_token": {
|
||
|
{`@[^\s]+`, NameDecorator, Push("arguments")}, // Named matcher
|
||
|
{`/[^\s]+`, NameDecorator, Push("arguments")}, // Path matcher
|
||
|
{`\*`, NameDecorator, Push("arguments")}, // Wildcard path matcher
|
||
|
{`\[\<matcher\>\]`, NameDecorator, Push("arguments")}, // Matcher token stub for docs
|
||
|
},
|
||
|
"comments": {
|
||
|
{`^#.*\n`, CommentSingle, nil}, // Comment at start of line
|
||
|
{`\s+#.*\n`, CommentSingle, nil}, // Comment preceded by whitespace
|
||
|
},
|
||
|
"comments_pop_1": {
|
||
|
{`^#.*\n`, CommentSingle, Pop(1)}, // Comment at start of line
|
||
|
{`\s+#.*\n`, CommentSingle, Pop(1)}, // Comment preceded by whitespace
|
||
|
},
|
||
|
"comments_pop_2": {
|
||
|
{`^#.*\n`, CommentSingle, Pop(2)}, // Comment at start of line
|
||
|
{`\s+#.*\n`, CommentSingle, Pop(2)}, // Comment preceded by whitespace
|
||
|
},
|
||
|
"comments_pop_3": {
|
||
|
{`^#.*\n`, CommentSingle, Pop(3)}, // Comment at start of line
|
||
|
{`\s+#.*\n`, CommentSingle, Pop(3)}, // Comment preceded by whitespace
|
||
|
},
|
||
|
"base": {
|
||
|
Include("comments"),
|
||
|
{`(on|off|first|last|before|after|internal|strip_prefix|strip_suffix|replace)\b`, NameConstant, nil},
|
||
|
{`(https?://)?([a-z0-9.-]+)(:)([0-9]+)`, ByGroups(Name, Name, Punctuation, LiteralNumberInteger), nil},
|
||
|
{`[a-z-]+/[a-z-+]+`, LiteralString, nil},
|
||
|
{`[0-9]+[km]?\b`, LiteralNumberInteger, nil},
|
||
|
{`\{[\w+.\$-]+\}`, LiteralStringEscape, nil}, // Placeholder
|
||
|
{`\[(?=[^#{}$]+\])`, Punctuation, nil},
|
||
|
{`\]|\|`, Punctuation, nil},
|
||
|
{`[^\s#{}$\]]+`, LiteralString, nil},
|
||
|
{`/[^\s#]*`, Name, nil},
|
||
|
{`\s+`, Text, nil},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
// Caddyfile lexer.
|
||
|
var Caddyfile = internal.Register(MustNewLexer(
|
||
|
&Config{
|
||
|
Name: "Caddyfile",
|
||
|
Aliases: []string{"caddyfile", "caddy"},
|
||
|
Filenames: []string{"Caddyfile*"},
|
||
|
MimeTypes: []string{},
|
||
|
},
|
||
|
Rules{
|
||
|
"root": {
|
||
|
Include("comments"),
|
||
|
// Global options block
|
||
|
{`^\s*(\{)\s*$`, ByGroups(Punctuation), Push("globals")},
|
||
|
// Snippets
|
||
|
{`(\([^\s#]+\))(\s*)(\{)`, ByGroups(NameVariableAnonymous, Text, Punctuation), Push("snippet")},
|
||
|
// Site label
|
||
|
{`[^#{(\s,]+`, GenericHeading, Push("label")},
|
||
|
// Site label with placeholder
|
||
|
{`\{[\w+.\$-]+\}`, LiteralStringEscape, Push("label")},
|
||
|
{`\s+`, Text, nil},
|
||
|
},
|
||
|
"globals": {
|
||
|
{`\}`, Punctuation, Pop(1)},
|
||
|
{`[^\s#]+`, Keyword, Push("directive")},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"snippet": {
|
||
|
{`\}`, Punctuation, Pop(1)},
|
||
|
// Matcher definition
|
||
|
{`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
|
||
|
// Any directive
|
||
|
{`[^\s#]+`, Keyword, Push("directive")},
|
||
|
Include("base"),
|
||
|
},
|
||
|
"label": {
|
||
|
// Allow multiple labels, comma separated, newlines after
|
||
|
// a comma means another label is coming
|
||
|
{`,\s*\n?`, Text, nil},
|
||
|
{` `, Text, nil},
|
||
|
// Site label with placeholder
|
||
|
{`\{[\w+.\$-]+\}`, LiteralStringEscape, nil},
|
||
|
// Site label
|
||
|
{`[^#{(\s,]+`, GenericHeading, nil},
|
||
|
// Comment after non-block label (hack because comments end in \n)
|
||
|
{`#.*\n`, CommentSingle, Push("site_block")},
|
||
|
// Note: if \n, we'll never pop out of the site_block, it's valid
|
||
|
{`\{(?=\s)|\n`, Punctuation, Push("site_block")},
|
||
|
},
|
||
|
"site_block": {
|
||
|
{`\}`, Punctuation, Pop(2)},
|
||
|
Include("site_block_common"),
|
||
|
},
|
||
|
}.Merge(caddyfileCommon),
|
||
|
))
|
||
|
|
||
|
// Caddyfile directive-only lexer.
|
||
|
var CaddyfileDirectives = internal.Register(MustNewLexer(
|
||
|
&Config{
|
||
|
Name: "Caddyfile Directives",
|
||
|
Aliases: []string{"caddyfile-directives", "caddyfile-d", "caddy-d"},
|
||
|
Filenames: []string{},
|
||
|
MimeTypes: []string{},
|
||
|
},
|
||
|
Rules{
|
||
|
// Same as "site_block" in Caddyfile
|
||
|
"root": {
|
||
|
Include("site_block_common"),
|
||
|
},
|
||
|
}.Merge(caddyfileCommon),
|
||
|
))
|