Automatic rules registration
This commit is contained in:
parent
85fe0425b9
commit
4784921bb8
24 changed files with 157 additions and 74 deletions
|
@ -296,6 +296,7 @@ impl Element for Code {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct CodeRule {
|
||||
re: [Regex; 2],
|
||||
properties: PropertyParser,
|
||||
|
@ -330,6 +331,7 @@ impl CodeRule {
|
|||
|
||||
impl RegexRule for CodeRule {
|
||||
fn name(&self) -> &'static str { "Code" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("List") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ impl Element for Comment {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct CommentRule {
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
@ -53,6 +54,8 @@ impl CommentRule {
|
|||
impl RegexRule for CommentRule {
|
||||
fn name(&self) -> &'static str { "Comment" }
|
||||
|
||||
fn previous(&self) -> Option<&'static str> { None }
|
||||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
fn on_regex_match<'a>(
|
||||
|
|
|
@ -178,10 +178,16 @@ impl RuleState for CustomStyleState {
|
|||
|
||||
static STATE_NAME: &'static str = "elements.custom_style";
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct CustomStyleRule;
|
||||
|
||||
impl CustomStyleRule {
|
||||
pub fn new() -> Self { Self{} }
|
||||
}
|
||||
|
||||
impl Rule for CustomStyleRule {
|
||||
fn name(&self) -> &'static str { "Custom Style" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Style") }
|
||||
|
||||
fn next_match(&self, state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
let content = cursor.source.content();
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::parser::rule::Rule;
|
|||
use crate::parser::source::Cursor;
|
||||
use crate::parser::source::Source;
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ElemStyleRule {
|
||||
start_re: Regex,
|
||||
}
|
||||
|
@ -58,6 +59,7 @@ impl ElemStyleRule {
|
|||
|
||||
impl Rule for ElemStyleRule {
|
||||
fn name(&self) -> &'static str { "Element Style" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Script") }
|
||||
|
||||
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
self.start_re
|
||||
|
|
|
@ -146,6 +146,7 @@ impl Element for Graphviz {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct GraphRule {
|
||||
re: [Regex; 1],
|
||||
properties: PropertyParser,
|
||||
|
@ -178,6 +179,7 @@ impl GraphRule {
|
|||
|
||||
impl RegexRule for GraphRule {
|
||||
fn name(&self) -> &'static str { "Graph" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Tex") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use std::rc::Rc;
|
|||
|
||||
use super::paragraph::Paragraph;
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ImportRule {
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
@ -40,6 +41,7 @@ impl ImportRule {
|
|||
|
||||
impl RegexRule for ImportRule {
|
||||
fn name(&self) -> &'static str { "Import" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Paragraph") }
|
||||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -284,6 +284,7 @@ impl RuleState for LayoutState {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct LayoutRule {
|
||||
re: [Regex; 3],
|
||||
}
|
||||
|
@ -378,6 +379,7 @@ static STATE_NAME: &'static str = "elements.layout";
|
|||
|
||||
impl RegexRule for LayoutRule {
|
||||
fn name(&self) -> &'static str { "Layout" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Media") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ impl ContainerElement for Link {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct LinkRule {
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
@ -85,6 +86,7 @@ impl LinkRule {
|
|||
|
||||
impl RegexRule for LinkRule {
|
||||
fn name(&self) -> &'static str { "Link" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Link") }
|
||||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ impl ContainerElement for ListEntry {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ListRule {
|
||||
start_re: Regex,
|
||||
continue_re: Regex,
|
||||
|
@ -249,6 +250,7 @@ impl ListRule {
|
|||
|
||||
impl Rule for ListRule {
|
||||
fn name(&self) -> &'static str { "List" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Raw") }
|
||||
|
||||
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
self.start_re
|
||||
|
|
|
@ -221,6 +221,7 @@ impl ReferenceableElement for Medium {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct MediaRule {
|
||||
re: [Regex; 1],
|
||||
properties: PropertyParser,
|
||||
|
@ -325,6 +326,7 @@ impl MediaRule {
|
|||
|
||||
impl RegexRule for MediaRule {
|
||||
fn name(&self) -> &'static str { "Media" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Graph") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ pub mod media;
|
|||
pub mod paragraph;
|
||||
pub mod raw;
|
||||
pub mod reference;
|
||||
pub mod registrar;
|
||||
pub mod script;
|
||||
pub mod section;
|
||||
pub mod style;
|
||||
|
|
|
@ -91,6 +91,7 @@ impl ContainerElement for Paragraph {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ParagraphRule {
|
||||
re: Regex,
|
||||
}
|
||||
|
@ -104,7 +105,8 @@ impl ParagraphRule {
|
|||
}
|
||||
|
||||
impl Rule for ParagraphRule {
|
||||
fn name(&self) -> &'static str { "Paragraphing" }
|
||||
fn name(&self) -> &'static str { "Paragraph" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Comment") }
|
||||
|
||||
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
self.re
|
||||
|
|
|
@ -44,6 +44,7 @@ impl Element for Raw {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct RawRule {
|
||||
re: [Regex; 1],
|
||||
properties: PropertyParser,
|
||||
|
@ -72,6 +73,7 @@ impl RawRule {
|
|||
|
||||
impl RegexRule for RawRule {
|
||||
fn name(&self) -> &'static str { "Raw" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Variable Substitution") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ impl Element for Reference {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ReferenceRule {
|
||||
re: [Regex; 1],
|
||||
properties: PropertyParser,
|
||||
|
@ -127,6 +128,7 @@ impl ReferenceRule {
|
|||
|
||||
impl RegexRule for ReferenceRule {
|
||||
fn name(&self) -> &'static str { "Reference" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Text") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
use crate::parser::parser::Parser;
|
||||
|
||||
use super::code::CodeRule;
|
||||
use super::comment::CommentRule;
|
||||
use super::elemstyle::ElemStyleRule;
|
||||
use super::graphviz::GraphRule;
|
||||
use super::import::ImportRule;
|
||||
use super::layout::LayoutRule;
|
||||
use super::link::LinkRule;
|
||||
use super::list::ListRule;
|
||||
use super::media::MediaRule;
|
||||
use super::paragraph::ParagraphRule;
|
||||
use super::raw::RawRule;
|
||||
use super::script::ScriptRule;
|
||||
use super::section::SectionRule;
|
||||
use super::style::StyleRule;
|
||||
use super::customstyle::CustomStyleRule;
|
||||
use super::tex::TexRule;
|
||||
use super::text::TextRule;
|
||||
use super::variable::VariableRule;
|
||||
use super::variable::VariableSubstitutionRule;
|
||||
use super::reference::ReferenceRule;
|
||||
|
||||
pub fn register<P: Parser>(parser: &mut P) {
|
||||
parser.add_rule(Box::new(CommentRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(ParagraphRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(ImportRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(ScriptRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(ElemStyleRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(VariableRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(VariableSubstitutionRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(RawRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(ListRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(CodeRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(TexRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(GraphRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(MediaRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(LayoutRule::new()), None).unwrap();
|
||||
|
||||
parser.add_rule(Box::new(StyleRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(CustomStyleRule{}), None).unwrap();
|
||||
parser.add_rule(Box::new(SectionRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(LinkRule::new()), None).unwrap();
|
||||
parser.add_rule(Box::new(TextRule::default()), None).unwrap();
|
||||
parser.add_rule(Box::new(ReferenceRule::new()), None).unwrap();
|
||||
}
|
|
@ -20,6 +20,7 @@ use std::rc::Rc;
|
|||
|
||||
use super::text::Text;
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct ScriptRule {
|
||||
re: [Regex; 2],
|
||||
eval_kinds: [(&'static str, &'static str); 3],
|
||||
|
@ -77,6 +78,7 @@ impl ScriptRule {
|
|||
|
||||
impl RegexRule for ScriptRule {
|
||||
fn name(&self) -> &'static str { "Script" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Import") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -135,6 +135,7 @@ impl ReferenceableElement for Section {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct SectionRule {
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
@ -155,6 +156,7 @@ pub mod section_kind {
|
|||
|
||||
impl RegexRule for SectionRule {
|
||||
fn name(&self) -> &'static str { "Section" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Custom Style") }
|
||||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ impl RuleState for StyleState {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct StyleRule {
|
||||
re: [Regex; 4],
|
||||
}
|
||||
|
@ -157,6 +158,7 @@ static STATE_NAME: &'static str = "elements.style";
|
|||
|
||||
impl RegexRule for StyleRule {
|
||||
fn name(&self) -> &'static str { "Style" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Layout") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ impl Element for Tex {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct TexRule {
|
||||
re: [Regex; 2],
|
||||
properties: PropertyParser,
|
||||
|
@ -296,6 +297,7 @@ impl TexRule {
|
|||
|
||||
impl RegexRule for TexRule {
|
||||
fn name(&self) -> &'static str { "Tex" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Code") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -42,13 +42,20 @@ impl Element for Text {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct TextRule;
|
||||
|
||||
impl TextRule {
|
||||
pub fn new() -> Self { Self {} }
|
||||
}
|
||||
|
||||
impl Rule for TextRule {
|
||||
fn name(&self) -> &'static str { "Text" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Link") }
|
||||
|
||||
fn next_match(&self, _state: &ParserState, _cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { None }
|
||||
fn next_match(&self, _state: &ParserState, _cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn on_match(
|
||||
&self,
|
||||
|
|
|
@ -37,6 +37,7 @@ impl FromStr for VariableKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct VariableRule {
|
||||
re: [Regex; 1],
|
||||
kinds: Vec<(String, String)>,
|
||||
|
@ -117,6 +118,7 @@ impl VariableRule {
|
|||
|
||||
impl RegexRule for VariableRule {
|
||||
fn name(&self) -> &'static str { "Variable" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Element Style") }
|
||||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
|
@ -295,6 +297,7 @@ impl RegexRule for VariableRule {
|
|||
}
|
||||
}
|
||||
|
||||
#[auto_registry::auto_registry(registry = "rules")]
|
||||
pub struct VariableSubstitutionRule {
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
@ -309,6 +312,7 @@ impl VariableSubstitutionRule {
|
|||
|
||||
impl RegexRule for VariableSubstitutionRule {
|
||||
fn name(&self) -> &'static str { "Variable Substitution" }
|
||||
fn previous(&self) -> Option<&'static str> { Some("Variable") }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::rc::Rc;
|
|||
use crate::document::document::Document;
|
||||
use crate::document::element::DocumentEnd;
|
||||
use crate::document::langdocument::LangDocument;
|
||||
use crate::elements::registrar::register;
|
||||
use crate::elements::text::Text;
|
||||
|
||||
use super::parser::Parser;
|
||||
|
@ -35,8 +34,10 @@ impl LangParser {
|
|||
};
|
||||
|
||||
// Register rules
|
||||
// TODO: use https://docs.rs/inventory/latest/inventory/
|
||||
register(&mut s);
|
||||
for rule in super::rule::get_rule_registry()
|
||||
{
|
||||
s.add_rule(rule).unwrap();
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use crate::document::document::DocumentAccessors;
|
|||
use crate::document::element::ContainerElement;
|
||||
use crate::document::element::ElemKind;
|
||||
use crate::document::element::Element;
|
||||
use crate::elements::customstyle::CustomStyleRule;
|
||||
use crate::elements::paragraph::Paragraph;
|
||||
use crate::lua::kernel::Kernel;
|
||||
use crate::lua::kernel::KernelHolder;
|
||||
|
@ -186,7 +185,6 @@ impl<'a, 'b> ParserState<'a, 'b> {
|
|||
.for_each(|(rule, (matched_at, match_data))| {
|
||||
// Don't upate if not stepped over yet
|
||||
if *matched_at > cursor.pos {
|
||||
// TODO: maybe we should expose matches() so it becomes possible to dynamically register a new rule
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -369,7 +367,7 @@ pub trait Parser {
|
|||
/// # Warning
|
||||
///
|
||||
/// This method must not be called if a [`ParserState`] for this parser exists.
|
||||
fn add_rule(&mut self, rule: Box<dyn Rule>, after: Option<&'static str>) -> Result<(), String> {
|
||||
fn add_rule(&mut self, rule: Box<dyn Rule>) -> Result<(), String> {
|
||||
if let Some(_) = self
|
||||
.rules()
|
||||
.iter()
|
||||
|
@ -381,23 +379,7 @@ pub trait Parser {
|
|||
));
|
||||
}
|
||||
|
||||
// Try to insert after
|
||||
if let Some(after) = after {
|
||||
let index = self
|
||||
.rules()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, rule)| rule.name() == after)
|
||||
.map(|(idx, _)| idx);
|
||||
|
||||
if let Some(index) = index {
|
||||
self.rules_mut().insert(index, rule);
|
||||
} else {
|
||||
return Err(format!("Unable to find rule `{after}` to insert after"));
|
||||
}
|
||||
} else {
|
||||
self.rules_mut().push(rule);
|
||||
}
|
||||
self.rules_mut().push(rule);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -12,12 +12,66 @@ use mlua::Function;
|
|||
use mlua::Lua;
|
||||
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
macro_rules! create_registry {
|
||||
( $($construct:expr),+ $(,)? ) => {{
|
||||
let mut map = HashMap::new();
|
||||
$(
|
||||
let boxed = Box::new($construct) as Box<dyn Rule>;
|
||||
map.insert(boxed.name(), boxed);
|
||||
)+
|
||||
map
|
||||
}};
|
||||
}
|
||||
|
||||
/// Gets the list of all rules exported with the [`auto_registry`] proc macro.
|
||||
/// Rules are sorted according to topological order using the [`Rule::previous`] method.
|
||||
#[auto_registry::generate_registry(registry = "rules", target = make_rules, return_type = HashMap<&'static str, Box<dyn Rule>>, maker = create_registry)]
|
||||
pub fn get_rule_registry() -> Vec<Box<dyn Rule>> {
|
||||
fn cmp(
|
||||
map: &HashMap<&'static str, Box<dyn Rule>>,
|
||||
lname: &'static str,
|
||||
rname: &'static str,
|
||||
) -> std::cmp::Ordering {
|
||||
let l = map.get(lname).unwrap();
|
||||
let r = map.get(rname).unwrap();
|
||||
if l.previous() == Some(r.name()) {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if r.previous() == Some(l.name()) {
|
||||
std::cmp::Ordering::Less
|
||||
} else if l.previous().is_some() && r.previous().is_none() {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if r.previous().is_some() && l.previous().is_none() {
|
||||
std::cmp::Ordering::Less
|
||||
} else if let (Some(pl), Some(pr)) = (l.previous(), r.previous()) {
|
||||
cmp(map, pl, pr)
|
||||
} else {
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
let mut map = make_rules();
|
||||
let mut sorted_keys = map.iter().map(|(key, _)| *key).collect::<Vec<_>>();
|
||||
sorted_keys.sort_by(|l, r| cmp(&map, l, r));
|
||||
|
||||
let mut owned = Vec::with_capacity(sorted_keys.len());
|
||||
for key in sorted_keys {
|
||||
let rule = map.remove(key).unwrap();
|
||||
owned.push(rule);
|
||||
}
|
||||
|
||||
owned
|
||||
}
|
||||
|
||||
pub trait Rule: Downcast {
|
||||
/// Returns rule's name
|
||||
/// The rule name
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// The name of the rule that should come before this one
|
||||
fn previous(&self) -> Option<&'static str>;
|
||||
|
||||
/// Finds the next match starting from [`cursor`]
|
||||
fn next_match(&self, state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)>;
|
||||
/// Callback when rule matches
|
||||
|
@ -47,8 +101,12 @@ impl core::fmt::Debug for dyn Rule {
|
|||
}
|
||||
|
||||
pub trait RegexRule {
|
||||
/// The rule name
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// The name of the rule that should come before this one
|
||||
fn previous(&self) -> Option<&'static str>;
|
||||
|
||||
/// Returns the rule's regexes
|
||||
fn regexes(&self) -> &[regex::Regex];
|
||||
|
||||
|
@ -69,6 +127,7 @@ pub trait RegexRule {
|
|||
|
||||
impl<T: RegexRule + 'static> Rule for T {
|
||||
fn name(&self) -> &'static str { RegexRule::name(self) }
|
||||
fn previous(&self) -> Option<&'static str> { RegexRule::previous(self) }
|
||||
|
||||
/// Finds the next match starting from [`cursor`]
|
||||
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
|
||||
|
@ -120,3 +179,41 @@ impl<T: RegexRule + 'static> Rule for T {
|
|||
|
||||
fn register_layouts(&self, holder: &mut LayoutHolder) { self.register_layouts(holder); }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn registry() {
|
||||
let rules = get_rule_registry();
|
||||
let names: Vec<&'static str> = rules.iter().map(|rule| rule.name()).collect();
|
||||
|
||||
assert_eq!(
|
||||
names,
|
||||
vec![
|
||||
"Comment",
|
||||
"Paragraph",
|
||||
"Import",
|
||||
"Script",
|
||||
"Element Style",
|
||||
"Variable",
|
||||
"Variable Substitution",
|
||||
"Raw",
|
||||
"List",
|
||||
"Code",
|
||||
"Tex",
|
||||
"Graph",
|
||||
"Media",
|
||||
"Layout",
|
||||
"Style",
|
||||
"Custom Style",
|
||||
"Section",
|
||||
"Link",
|
||||
"Text",
|
||||
"Reference",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue