WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
top = { SOI ~ "|"* ~ selector_chain? ~ EOI }
selector_chain = { selector ~ ("|"+ ~ selector?)* }
selector = {
select_section
| select_list_item
| select_link
| select_block_quote
| select_code_block
| select_front_matter
| select_html
| select_paragraph
| select_table
}
selector_delim = _{ explicit_space | EOI }
explicit_space = !{ " " } // making this a rule lets us have nicer error messages if the user doesn't include it
select_section = { section_start ~ PUSH_LITERAL("|") ~ #title = string }
section_start = ${ "#" ~ section_opts? ~ selector_delim }
section_opts = ${
"{"
~ #level_min = section_num?
~ #level_comma = section_comma?
~ #level_max = section_num?
~ "}"
}
section_num = @{ ('0' .. '9')+ }
section_comma = @{ "," }
select_list_item = { list_start ~ list_task_options? ~ PUSH_LITERAL("|") ~ #contents = string }
list_start = ${ (list_ordered | "-") ~ selector_delim }
list_ordered = ${ "1." }
list_task_options = ${ "[" ~ (task_unchecked | task_checked | task_either) ~ task_end }
task_checked = ${ "x" }
task_unchecked = ${ " " }
task_either = ${ "?" }
task_end = ${ "]" }
select_link = { link_start ~ PUSH_LITERAL("]") ~ #display_text = string ~ "](" ~ PUSH_LITERAL(")")~ #url_text = string ~ ")" }
link_start = ${ image_start? ~ "[" }
image_start = @{ "!" }
select_block_quote = { select_block_quote_start ~ PUSH_LITERAL("|") ~ #text = string }
select_block_quote_start = @{ ">" ~ selector_delim }
select_code_block = { code_block_start ~ PUSH_LITERAL("|") ~ #text = string }
code_block_start = ${ "```" ~ PUSH_LITERAL(" ") ~ #language = string ~ selector_delim }
select_front_matter = { front_matter_start ~ PUSH_LITERAL("|") ~ #text = string }
front_matter_start = ${ "+++" ~ PUSH_LITERAL(" ") ~ #variant = string ~ selector_delim }
select_html = { html_start ~ PUSH_LITERAL("|") ~ #text = string }
html_start = @{ "</>" ~ selector_delim }
select_paragraph = { select_paragraph_start ~ PUSH_LITERAL("|") ~ #text = string }
select_paragraph_start = @{ "P:" ~ selector_delim }
select_table = { table_start ~ PUSH_LITERAL(":") ~ #column = string ~ ":-:" ~ PUSH_LITERAL("|") ~ #row = string }
table_start = ${":-:" ~ explicit_space }
// helper rule, just for unit tests
string_for_unit_tests__do_not_use_pipe = { PUSH_LITERAL("|") ~ string }
string_for_unit_tests__do_not_use_angle = { PUSH_LITERAL(">") ~ string }
string = {
// end delimiter for unquoted string will have been PUSH_LITERAL'd by here
(
asterisk
| regex
| ( anchor_start? ~ ( quoted_string | unquoted_string ) ~ anchor_end? )
| ( anchor_start ~ anchor_end )
)?
~ DROP
}
asterisk = @{ "*" }
unquoted_string = @{ LETTER ~ (!(PEEK | "$") ~ ANY)* }
regex = ${
// Put these into a single rule, so that the error message just says "regex" for both the plain and replace variant.
("/" ~ regex_char* ~ "/")
| ("!s/" ~ regex_char* ~ "/" ~ regex_replacement_segment? ~ "/")
}
regex_char = ${
(regex_escaped_slash | regex_normal_char)
}
regex_replacement_segment = ${ regex_char+ }
regex_escaped_slash = @{ "\\/" }
regex_normal_char = @{ !("/") ~ ANY }
quoted_string = ${ PUSH("'" | "\"") ~ quoted_char* ~ POP }
quoted_char = ${
quoted_plain_chars
| ("\\" ~ (escaped_char | "u{" ~ unicode_seq ~ "}"))
}
anchor_start = @{ "^" }
anchor_end = @{ "$" }
quoted_plain_chars = @{ (!(PEEK | "\\") ~ ANY)+ }
escaped_char = @{ ("\"" | "'" | "`" | "\\" | "n" | "r" | "t") }
unicode_seq = @{ ASCII_HEX_DIGIT{1, 6} }