You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
6.4 KiB

  1. package c
  2. import (
  3. . "github.com/alecthomas/chroma" // nolint
  4. "github.com/alecthomas/chroma/lexers/internal"
  5. )
  6. // caddyfileCommon are the rules common to both of the lexer variants
  7. var caddyfileCommon = Rules{
  8. "site_block_common": {
  9. // Import keyword
  10. {`(import)(\s+)([^\s]+)`, ByGroups(Keyword, Text, NameVariableMagic), nil},
  11. // Matcher definition
  12. {`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
  13. // Matcher token stub for docs
  14. {`\[\<matcher\>\]`, NameDecorator, Push("matcher")},
  15. // These cannot have matchers but may have things that look like
  16. // matchers in their arguments, so we just parse as a subdirective.
  17. {`try_files`, Keyword, Push("subdirective")},
  18. // These are special, they can nest more directives
  19. {`handle_errors|handle|route|handle_path|not`, Keyword, Push("nested_directive")},
  20. // Any other directive
  21. {`[^\s#]+`, Keyword, Push("directive")},
  22. Include("base"),
  23. },
  24. "matcher": {
  25. {`\{`, Punctuation, Push("block")},
  26. // Not can be one-liner
  27. {`not`, Keyword, Push("deep_not_matcher")},
  28. // Any other same-line matcher
  29. {`[^\s#]+`, Keyword, Push("arguments")},
  30. // Terminators
  31. {`\n`, Text, Pop(1)},
  32. {`\}`, Punctuation, Pop(1)},
  33. Include("base"),
  34. },
  35. "block": {
  36. {`\}`, Punctuation, Pop(2)},
  37. // Not can be one-liner
  38. {`not`, Keyword, Push("not_matcher")},
  39. // Any other subdirective
  40. {`[^\s#]+`, Keyword, Push("subdirective")},
  41. Include("base"),
  42. },
  43. "nested_block": {
  44. {`\}`, Punctuation, Pop(2)},
  45. // Matcher definition
  46. {`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
  47. // Something that starts with literally < is probably a docs stub
  48. {`\<[^#]+\>`, Keyword, Push("nested_directive")},
  49. // Any other directive
  50. {`[^\s#]+`, Keyword, Push("nested_directive")},
  51. Include("base"),
  52. },
  53. "not_matcher": {
  54. {`\}`, Punctuation, Pop(2)},
  55. {`\{(?=\s)`, Punctuation, Push("block")},
  56. {`[^\s#]+`, Keyword, Push("arguments")},
  57. {`\s+`, Text, nil},
  58. },
  59. "deep_not_matcher": {
  60. {`\}`, Punctuation, Pop(2)},
  61. {`\{(?=\s)`, Punctuation, Push("block")},
  62. {`[^\s#]+`, Keyword, Push("deep_subdirective")},
  63. {`\s+`, Text, nil},
  64. },
  65. "directive": {
  66. {`\{(?=\s)`, Punctuation, Push("block")},
  67. Include("matcher_token"),
  68. Include("comments_pop_1"),
  69. {`\n`, Text, Pop(1)},
  70. Include("base"),
  71. },
  72. "nested_directive": {
  73. {`\{(?=\s)`, Punctuation, Push("nested_block")},
  74. Include("matcher_token"),
  75. Include("comments_pop_1"),
  76. {`\n`, Text, Pop(1)},
  77. Include("base"),
  78. },
  79. "subdirective": {
  80. {`\{(?=\s)`, Punctuation, Push("block")},
  81. Include("comments_pop_1"),
  82. {`\n`, Text, Pop(1)},
  83. Include("base"),
  84. },
  85. "arguments": {
  86. {`\{(?=\s)`, Punctuation, Push("block")},
  87. Include("comments_pop_2"),
  88. {`\\\n`, Text, nil}, // Skip escaped newlines
  89. {`\n`, Text, Pop(2)},
  90. Include("base"),
  91. },
  92. "deep_subdirective": {
  93. {`\{(?=\s)`, Punctuation, Push("block")},
  94. Include("comments_pop_3"),
  95. {`\n`, Text, Pop(3)},
  96. Include("base"),
  97. },
  98. "matcher_token": {
  99. {`@[^\s]+`, NameDecorator, Push("arguments")}, // Named matcher
  100. {`/[^\s]+`, NameDecorator, Push("arguments")}, // Path matcher
  101. {`\*`, NameDecorator, Push("arguments")}, // Wildcard path matcher
  102. {`\[\<matcher\>\]`, NameDecorator, Push("arguments")}, // Matcher token stub for docs
  103. },
  104. "comments": {
  105. {`^#.*\n`, CommentSingle, nil}, // Comment at start of line
  106. {`\s+#.*\n`, CommentSingle, nil}, // Comment preceded by whitespace
  107. },
  108. "comments_pop_1": {
  109. {`^#.*\n`, CommentSingle, Pop(1)}, // Comment at start of line
  110. {`\s+#.*\n`, CommentSingle, Pop(1)}, // Comment preceded by whitespace
  111. },
  112. "comments_pop_2": {
  113. {`^#.*\n`, CommentSingle, Pop(2)}, // Comment at start of line
  114. {`\s+#.*\n`, CommentSingle, Pop(2)}, // Comment preceded by whitespace
  115. },
  116. "comments_pop_3": {
  117. {`^#.*\n`, CommentSingle, Pop(3)}, // Comment at start of line
  118. {`\s+#.*\n`, CommentSingle, Pop(3)}, // Comment preceded by whitespace
  119. },
  120. "base": {
  121. Include("comments"),
  122. {`(on|off|first|last|before|after|internal|strip_prefix|strip_suffix|replace)\b`, NameConstant, nil},
  123. {`(https?://)?([a-z0-9.-]+)(:)([0-9]+)`, ByGroups(Name, Name, Punctuation, LiteralNumberInteger), nil},
  124. {`[a-z-]+/[a-z-+]+`, LiteralString, nil},
  125. {`[0-9]+[km]?\b`, LiteralNumberInteger, nil},
  126. {`\{[\w+.\$-]+\}`, LiteralStringEscape, nil}, // Placeholder
  127. {`\[(?=[^#{}$]+\])`, Punctuation, nil},
  128. {`\]|\|`, Punctuation, nil},
  129. {`[^\s#{}$\]]+`, LiteralString, nil},
  130. {`/[^\s#]*`, Name, nil},
  131. {`\s+`, Text, nil},
  132. },
  133. }
  134. // Caddyfile lexer.
  135. var Caddyfile = internal.Register(MustNewLexer(
  136. &Config{
  137. Name: "Caddyfile",
  138. Aliases: []string{"caddyfile", "caddy"},
  139. Filenames: []string{"Caddyfile*"},
  140. MimeTypes: []string{},
  141. },
  142. Rules{
  143. "root": {
  144. Include("comments"),
  145. // Global options block
  146. {`^\s*(\{)\s*$`, ByGroups(Punctuation), Push("globals")},
  147. // Snippets
  148. {`(\([^\s#]+\))(\s*)(\{)`, ByGroups(NameVariableAnonymous, Text, Punctuation), Push("snippet")},
  149. // Site label
  150. {`[^#{(\s,]+`, GenericHeading, Push("label")},
  151. // Site label with placeholder
  152. {`\{[\w+.\$-]+\}`, LiteralStringEscape, Push("label")},
  153. {`\s+`, Text, nil},
  154. },
  155. "globals": {
  156. {`\}`, Punctuation, Pop(1)},
  157. {`[^\s#]+`, Keyword, Push("directive")},
  158. Include("base"),
  159. },
  160. "snippet": {
  161. {`\}`, Punctuation, Pop(1)},
  162. // Matcher definition
  163. {`@[^\s]+(?=\s)`, NameDecorator, Push("matcher")},
  164. // Any directive
  165. {`[^\s#]+`, Keyword, Push("directive")},
  166. Include("base"),
  167. },
  168. "label": {
  169. // Allow multiple labels, comma separated, newlines after
  170. // a comma means another label is coming
  171. {`,\s*\n?`, Text, nil},
  172. {` `, Text, nil},
  173. // Site label with placeholder
  174. {`\{[\w+.\$-]+\}`, LiteralStringEscape, nil},
  175. // Site label
  176. {`[^#{(\s,]+`, GenericHeading, nil},
  177. // Comment after non-block label (hack because comments end in \n)
  178. {`#.*\n`, CommentSingle, Push("site_block")},
  179. // Note: if \n, we'll never pop out of the site_block, it's valid
  180. {`\{(?=\s)|\n`, Punctuation, Push("site_block")},
  181. },
  182. "site_block": {
  183. {`\}`, Punctuation, Pop(2)},
  184. Include("site_block_common"),
  185. },
  186. }.Merge(caddyfileCommon),
  187. ))
  188. // Caddyfile directive-only lexer.
  189. var CaddyfileDirectives = internal.Register(MustNewLexer(
  190. &Config{
  191. Name: "Caddyfile Directives",
  192. Aliases: []string{"caddyfile-directives", "caddyfile-d", "caddy-d"},
  193. Filenames: []string{},
  194. MimeTypes: []string{},
  195. },
  196. Rules{
  197. // Same as "site_block" in Caddyfile
  198. "root": {
  199. Include("site_block_common"),
  200. },
  201. }.Merge(caddyfileCommon),
  202. ))