WHITESPACE = _{ " " | "\t" }
spec = _{ SOI ~ url ~ (";" ~ attributes)? ~ EOI }
url = ${ (short_url | alias_url | full_url) ~ ("#" ~ branch)? }
short_url = ${ user ~ "/" ~ repo }
full_url = ${ ((!"/" ~ ANY)+ ~ "/")+ ~ repo ~ ".git"? }
alias_url = ${ prefix ~ ":" ~ short_url }
prefix = { prefix_codeberg | prefix_github | prefix_gitlab | prefix_bitbucket }
prefix_codeberg = { "codeberg" }
prefix_github = { "github" }
prefix_gitlab = { "gitlab" }
prefix_bitbucket = { "bitbucket" }
user = @{ ident }
repo = @{ ident }
branch = @{ ident ~ ("/" ~ ident)? }
attr_sep = _{ "," }
attributes = _{ attribute ~ (attr_sep ~ attribute)? }
attribute = { attr_key ~ "=" ~ attr_val ~ WHITESPACE* }
attr_key = { ident }
attr_val = ${ quoted_string | unquoted_val }
unquoted_val = { (("\\" ~ attr_sep) | (!(attr_sep | WHITESPACE) ~ ANY))+ }
ident = _{ (ASCII_ALPHA | ASCII_DIGIT | "_" | "-")+ }
//
// --- Quoted String ----------------------------------------------------------
//
quoted_string = _{ (single_quoted_string | double_quoted_string) }
single_quoted_string = ${ PUSH("\"") ~ quoted_inner ~ POP }
double_quoted_string = ${ PUSH("'") ~ quoted_inner ~ POP }
// This allows to escape double quote characters when inside a double-quoted
// string but does not allow escaping single quote characters inside a
// single-quoted string.
// To also allow escaping single quotes inside single-quoted strings, replace
// `("\\\"")` with `("\\" ~ PEEK)`.
quoted_inner = { (("\\\"") | (!PEEK ~ ANY))* }