feat(caddy): add Caddyfile TextMate grammar and enable Shiki syntax highlighting
Adds lib/grammars/caddyfile.json with scopes for directives, named-matchers (@prefix), placeholders, strings, and comments. Updates /caddy page to use createHighlighter with the local grammar instead of the nginx fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0514810115
commit
93b50254e5
2 changed files with 92 additions and 5 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { codeToHtml } from 'shiki'
|
import { createHighlighter } from 'shiki'
|
||||||
|
import caddyfileGrammar from '@/lib/grammars/caddyfile.json'
|
||||||
import { getCurrentUser } from '@/lib/session'
|
import { getCurrentUser } from '@/lib/session'
|
||||||
import { execAgent } from '@/lib/agent-client'
|
import { execAgent } from '@/lib/agent-client'
|
||||||
import { parseCertList, type CertInfo } from '@/lib/parse-caddy'
|
import { parseCertList, type CertInfo } from '@/lib/parse-caddy'
|
||||||
|
|
@ -16,10 +17,13 @@ export default async function CaddyPage() {
|
||||||
let configError: string | null = null
|
let configError: string | null = null
|
||||||
try {
|
try {
|
||||||
const raw = await execAgent('caddy_show_config')
|
const raw = await execAgent('caddy_show_config')
|
||||||
// shiki 1.29 bundelt geen caddyfile-grammar; nginx is syntactisch het
|
const highlighter = await createHighlighter({
|
||||||
// dichtst bij (directives + braces + reverse_proxy lijkt op locations)
|
themes: ['github-dark'],
|
||||||
configHtml = await codeToHtml(raw || '# (empty)', {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
lang: 'nginx',
|
langs: [caddyfileGrammar as any],
|
||||||
|
})
|
||||||
|
configHtml = highlighter.codeToHtml(raw || '# (empty)', {
|
||||||
|
lang: 'caddyfile',
|
||||||
theme: 'github-dark',
|
theme: 'github-dark',
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
83
lib/grammars/caddyfile.json
Normal file
83
lib/grammars/caddyfile.json
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
{
|
||||||
|
"name": "caddyfile",
|
||||||
|
"scopeName": "source.Caddyfile",
|
||||||
|
"fileTypes": ["Caddyfile"],
|
||||||
|
"patterns": [
|
||||||
|
{ "include": "#comment" },
|
||||||
|
{ "include": "#site-address" },
|
||||||
|
{ "include": "#named-matcher-def" },
|
||||||
|
{ "include": "#named-matcher-ref" },
|
||||||
|
{ "include": "#directive" },
|
||||||
|
{ "include": "#placeholder" },
|
||||||
|
{ "include": "#string-double" },
|
||||||
|
{ "include": "#string-backtick" },
|
||||||
|
{ "include": "#number" },
|
||||||
|
{ "include": "#braces" }
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"comment": {
|
||||||
|
"name": "comment.line.number-sign.caddyfile",
|
||||||
|
"match": "#.*$"
|
||||||
|
},
|
||||||
|
"site-address": {
|
||||||
|
"name": "entity.name.section.caddyfile",
|
||||||
|
"match": "^(?:https?://)?[a-zA-Z0-9][a-zA-Z0-9.*-]*(?::[0-9]+)?(?=\\s*(?:\\{|,|$))"
|
||||||
|
},
|
||||||
|
"named-matcher-def": {
|
||||||
|
"name": "entity.other.attribute-name.caddyfile",
|
||||||
|
"match": "@[a-zA-Z_][a-zA-Z0-9_-]*(?=\\s)"
|
||||||
|
},
|
||||||
|
"named-matcher-ref": {
|
||||||
|
"name": "entity.other.attribute-name.caddyfile",
|
||||||
|
"match": "(?<=\\s)@[a-zA-Z_][a-zA-Z0-9_-]*"
|
||||||
|
},
|
||||||
|
"directive": {
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"name": "keyword.control.caddyfile",
|
||||||
|
"match": "\\b(reverse_proxy|encode|file_server|handle_errors|handle_path|handle|root|header|request_header|response_header|redir|respond|rewrite|uri|try_files|php_fastcgi|push|templates|basicauth|forward_auth|map|vars|log|tls|bind|import|snippet|abort|error|static_response|acme_server|invoke)\\b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "support.function.caddyfile",
|
||||||
|
"match": "\\b(on_demand|off|auto|internal|force|strip_prefix|replace|path_regexp|method|host|header_regexp|remote_ip|client_ip|not|query|cookie|expression|path|protocol|vars_regexp|file|jwt|geo_ip)\\b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "keyword.other.option.caddyfile",
|
||||||
|
"match": "\\b(auto_https|admin|debug|grace_period|shutdown_delay|servers|storage|order|email|acme_ca|acme_ca_root|acme_eab|ocsp_stapling|key_type|cert_issuer|local_certs|skip_install_trust|renew_interval|check_interval|persistent_key|insecure_secrets_log|prefer_wildcard|resolvers|max_size|retention|format|output|level|sampling|include|exclude|dial|upstream|transport|lb_policy|health_uri|health_interval|health_timeout|health_status|health_body|flush_interval|buffer_requests|buffer_responses|max_buffer_size|trusted_proxies|to|from|prefix|replacements|gzip|zstd|br)\\b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"name": "variable.other.caddyfile",
|
||||||
|
"match": "\\{(?:http\\.(?:request|response|vars|regexp|handlers)|tls|env|vars|system|time|rand|counter|uuid|path|query|header|cookie|form|file|dir|args|blocks|labels|err|http)[^}]*\\}"
|
||||||
|
},
|
||||||
|
"string-double": {
|
||||||
|
"name": "string.quoted.double.caddyfile",
|
||||||
|
"begin": "\"",
|
||||||
|
"end": "\"",
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"name": "constant.character.escape.caddyfile",
|
||||||
|
"match": "\\\\."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "variable.other.caddyfile",
|
||||||
|
"match": "\\{[^}]+\\}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"string-backtick": {
|
||||||
|
"name": "string.quoted.other.caddyfile",
|
||||||
|
"begin": "`",
|
||||||
|
"end": "`"
|
||||||
|
},
|
||||||
|
"number": {
|
||||||
|
"name": "constant.numeric.caddyfile",
|
||||||
|
"match": "\\b[0-9]+(?:\\.[0-9]+)?(?:s|ms|m|h|d|kb|mb|gb)?\\b"
|
||||||
|
},
|
||||||
|
"braces": {
|
||||||
|
"name": "punctuation.section.block.caddyfile",
|
||||||
|
"match": "[{}]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue