Compare commits
No commits in common. "67ea2f941117783aed2cf9c716f8d18236c3597a" and "098252794440736be008f91f979bf7207a944791" have entirely different histories.
67ea2f9411
...
0982527944
12 changed files with 146 additions and 606 deletions
|
@ -76,28 +76,34 @@ impl NavEntry {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the insert index of the entry inside an already sorted entry list
|
||||||
fn sort_entry(
|
fn sort_entry(
|
||||||
left: &(String, String, Option<String>),
|
title: &String,
|
||||||
right: &(String, String, Option<String>),
|
previous: &Option<String>,
|
||||||
) -> std::cmp::Ordering {
|
entries: &Vec<(String, String, Option<String>)>,
|
||||||
match (&left.2, &right.2) {
|
) -> usize {
|
||||||
(Some(_), Some(_)) => left.0.cmp(&right.0),
|
let mut insert_at = 0;
|
||||||
(Some(lp), None) => {
|
if let Some(previous) = &previous
|
||||||
if &right.0 == lp {
|
// Using sort key
|
||||||
std::cmp::Ordering::Greater
|
{
|
||||||
} else {
|
for (i, (ent_title, _, _)) in entries.iter().enumerate() {
|
||||||
left.0.cmp(&right.0)
|
if ent_title == previous {
|
||||||
|
insert_at = i + 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, Some(rp)) => {
|
|
||||||
if &left.0 == rp {
|
|
||||||
std::cmp::Ordering::Less
|
|
||||||
} else {
|
|
||||||
left.0.cmp(&right.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then sort alphabetically
|
||||||
|
for (ent_title, _, ent_previous) in entries.iter().skip(insert_at) {
|
||||||
|
if (previous.is_some() && ent_previous != previous) || ent_title > title {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
(None, None) => left.0.cmp(&right.0),
|
|
||||||
|
insert_at += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insert_at
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,49 +196,47 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
|
||||||
}
|
}
|
||||||
all_paths.insert(path.clone(), title.clone());
|
all_paths.insert(path.clone(), title.clone());
|
||||||
|
|
||||||
pent.entries.push((title.clone(), path.clone(), previous));
|
pent.entries.insert(
|
||||||
|
NavEntry::sort_entry(title, &previous, &pent.entries),
|
||||||
|
(title.clone(), path.clone(), previous),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort entries
|
|
||||||
fn sort_entries(nav: &mut NavEntry) {
|
|
||||||
nav.entries
|
|
||||||
.sort_unstable_by(|l, r| NavEntry::sort_entry(l, r));
|
|
||||||
|
|
||||||
for (_, child) in &mut nav.children {
|
|
||||||
sort_entries(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort_entries(&mut nav);
|
|
||||||
|
|
||||||
Ok(nav)
|
Ok(nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use rand::RngCore;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sort() {
|
fn sort() {
|
||||||
let entries: Vec<(String, String, Option<String>)> = vec![
|
let entries: Vec<(String, String, Option<String>)> = vec![
|
||||||
("Index".into(), "".into(), None),
|
("Root".into(), "".into(), None),
|
||||||
("AB".into(), "".into(), Some("Index".into())),
|
("First".into(), "".into(), Some("Root".into())),
|
||||||
("Getting Started".into(), "".into(), Some("Index".into())),
|
("1".into(), "".into(), Some("First".into())),
|
||||||
("Sections".into(), "".into(), Some("Getting Started".into())),
|
("2".into(), "".into(), Some("First".into())),
|
||||||
("Style".into(), "".into(), Some("Getting Started".into())),
|
|
||||||
];
|
];
|
||||||
let mut shuffled = entries.clone();
|
|
||||||
for _ in 0..10 {
|
|
||||||
for i in 0..5 {
|
|
||||||
let pos = OsRng.next_u64() % entries.len() as u64;
|
|
||||||
shuffled.swap(i, pos as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
shuffled.sort_by(|l, r| NavEntry::sort_entry(l, r));
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"E".into(), &Some("Root".into()), &entries),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"G".into(), &Some("Root".into()), &entries),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
// Orphans
|
||||||
|
assert_eq!(NavEntry::sort_entry(&"Q".into(), &None, &entries), 0);
|
||||||
|
assert_eq!(NavEntry::sort_entry(&"S".into(), &None, &entries), 4);
|
||||||
|
|
||||||
assert_eq!(shuffled, entries);
|
assert_eq!(
|
||||||
}
|
NavEntry::sort_entry(&"1.1".into(), &Some("First".into()), &entries),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"2.1".into(), &Some("First".into()), &entries),
|
||||||
|
4
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
use std::any::Any;
|
|
||||||
use std::cell::Ref;
|
|
||||||
use std::cell::RefMut;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::Range;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use crate::compiler::compiler::Compiler;
|
|
||||||
use crate::elements::layout::LayoutToken;
|
|
||||||
|
|
||||||
use super::document::Document;
|
|
||||||
|
|
||||||
/// Represents the type of a layout
|
|
||||||
pub trait LayoutType: core::fmt::Debug {
|
|
||||||
/// Name of the layout
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
|
|
||||||
/// Parses layout properties
|
|
||||||
fn parse_properties(&self, properties: &str) -> Result<Option<Box<dyn Any>>, String>;
|
|
||||||
|
|
||||||
/// Expected number of blocks
|
|
||||||
fn expects(&self) -> Range<usize>;
|
|
||||||
|
|
||||||
/// Compile layout
|
|
||||||
fn compile(
|
|
||||||
&self,
|
|
||||||
token: LayoutToken,
|
|
||||||
id: usize,
|
|
||||||
properties: &Option<Box<dyn Any>>,
|
|
||||||
compiler: &Compiler,
|
|
||||||
document: &dyn Document,
|
|
||||||
) -> Result<String, String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LayoutHolder {
|
|
||||||
/// gets a reference to all defined layouts
|
|
||||||
fn layouts(&self) -> Ref<'_, HashMap<String, Rc<dyn LayoutType>>>;
|
|
||||||
|
|
||||||
/// gets a (mutable) reference to all defined layours
|
|
||||||
fn layouts_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn LayoutType>>>;
|
|
||||||
|
|
||||||
fn get_layout(&self, layout_name: &str) -> Option<Rc<dyn LayoutType>> {
|
|
||||||
self.layouts().get(layout_name).map(|layout| layout.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_layout(&self, layout: Rc<dyn LayoutType>) {
|
|
||||||
self.layouts_mut().insert(layout.name().into(), layout);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,4 +4,3 @@ pub mod langdocument;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod variable;
|
pub mod variable;
|
||||||
pub mod style;
|
pub mod style;
|
||||||
pub mod layout;
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ use crate::compiler::compiler::Target;
|
||||||
use crate::document::document::Document;
|
use crate::document::document::Document;
|
||||||
use crate::document::element::ElemKind;
|
use crate::document::element::ElemKind;
|
||||||
use crate::document::element::Element;
|
use crate::document::element::Element;
|
||||||
use crate::document::layout::LayoutType;
|
|
||||||
use crate::lua::kernel::CTX;
|
|
||||||
use crate::parser::parser::Parser;
|
use crate::parser::parser::Parser;
|
||||||
use crate::parser::parser::ReportColors;
|
use crate::parser::parser::ReportColors;
|
||||||
use crate::parser::rule::RegexRule;
|
use crate::parser::rule::RegexRule;
|
||||||
|
@ -18,7 +16,6 @@ use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use mlua::Error::BadArgument;
|
|
||||||
use mlua::Function;
|
use mlua::Function;
|
||||||
use mlua::Lua;
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
|
@ -30,8 +27,6 @@ use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum LayoutToken {
|
pub(crate) enum LayoutToken {
|
||||||
|
@ -40,20 +35,31 @@ pub(crate) enum LayoutToken {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for LayoutToken {
|
/// Represents the type of a layout
|
||||||
type Err = String;
|
pub trait LayoutType: core::fmt::Debug {
|
||||||
|
/// Name of the layout
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
/// Parses layout properties
|
||||||
match s {
|
fn parse_properties(&self, properties: &str) -> Result<Option<Box<dyn Any>>, String>;
|
||||||
"Begin" | "begin" => Ok(LayoutToken::Begin),
|
|
||||||
"Next" | "next" => Ok(LayoutToken::Next),
|
/// Expected number of blocks
|
||||||
"End" | "end" => Ok(LayoutToken::End),
|
fn expects(&self) -> Range<usize>;
|
||||||
_ => Err(format!("Unable to find LayoutToken with name: {s}")),
|
|
||||||
}
|
/// Compile layout
|
||||||
}
|
fn compile(
|
||||||
|
&self,
|
||||||
|
token: LayoutToken,
|
||||||
|
id: usize,
|
||||||
|
properties: &Option<Box<dyn Any>>,
|
||||||
|
compiler: &Compiler,
|
||||||
|
document: &dyn Document,
|
||||||
|
) -> Result<String, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod default_layouts {
|
mod default_layouts {
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::parser::util::Property;
|
use crate::parser::util::Property;
|
||||||
use crate::parser::util::PropertyParser;
|
use crate::parser::util::PropertyParser;
|
||||||
|
|
||||||
|
@ -285,10 +291,19 @@ impl State for LayoutState {
|
||||||
|
|
||||||
pub struct LayoutRule {
|
pub struct LayoutRule {
|
||||||
re: [Regex; 3],
|
re: [Regex; 3],
|
||||||
|
layouts: HashMap<String, Rc<dyn LayoutType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutRule {
|
impl LayoutRule {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let mut layouts: HashMap<String, Rc<dyn LayoutType>> = HashMap::new();
|
||||||
|
|
||||||
|
let layout_centered = default_layouts::Centered::default();
|
||||||
|
layouts.insert(layout_centered.name().to_string(), Rc::new(layout_centered));
|
||||||
|
|
||||||
|
let layout_split = default_layouts::Split::default();
|
||||||
|
layouts.insert(layout_split.name().to_string(), Rc::new(layout_split));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
re: [
|
re: [
|
||||||
RegexBuilder::new(
|
RegexBuilder::new(
|
||||||
|
@ -310,23 +325,7 @@ impl LayoutRule {
|
||||||
.build()
|
.build()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
],
|
],
|
||||||
}
|
layouts,
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize_state(parser: &dyn Parser) -> Rc<RefCell<dyn State>> {
|
|
||||||
let query = parser.state().query(&STATE_NAME);
|
|
||||||
match query {
|
|
||||||
Some(state) => state,
|
|
||||||
None => {
|
|
||||||
// Insert as a new state
|
|
||||||
match parser.state_mut().insert(
|
|
||||||
STATE_NAME.clone(),
|
|
||||||
Rc::new(RefCell::new(LayoutState { stack: vec![] })),
|
|
||||||
) {
|
|
||||||
Err(_) => panic!("Unknown error"),
|
|
||||||
Ok(state) => state,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +391,20 @@ impl RegexRule for LayoutRule {
|
||||||
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
|
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
|
||||||
let mut reports = vec![];
|
let mut reports = vec![];
|
||||||
|
|
||||||
let state = LayoutRule::initialize_state(parser);
|
let query = parser.state().query(&STATE_NAME);
|
||||||
|
let state = match query {
|
||||||
|
Some(state) => state,
|
||||||
|
None => {
|
||||||
|
// Insert as a new state
|
||||||
|
match parser.state_mut().insert(
|
||||||
|
STATE_NAME.clone(),
|
||||||
|
Rc::new(RefCell::new(LayoutState { stack: vec![] })),
|
||||||
|
) {
|
||||||
|
Err(_) => panic!("Unknown error"),
|
||||||
|
Ok(state) => state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if index == 0
|
if index == 0
|
||||||
// BEGIN_LAYOUT
|
// BEGIN_LAYOUT
|
||||||
|
@ -453,7 +465,7 @@ impl RegexRule for LayoutRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get layout
|
// Get layout
|
||||||
let layout_type = match parser.get_layout(trimmed) {
|
let layout_type = match self.layouts.get(trimmed) {
|
||||||
None => {
|
None => {
|
||||||
reports.push(
|
reports.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
|
@ -651,212 +663,7 @@ impl RegexRule for LayoutRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
let mut bindings = vec![];
|
|
||||||
|
|
||||||
bindings.push((
|
|
||||||
"push".to_string(),
|
|
||||||
lua.create_function(
|
|
||||||
|_, (token, layout, properties): (String, String, String)| {
|
|
||||||
let mut result = Ok(());
|
|
||||||
|
|
||||||
// Parse token
|
|
||||||
let layout_token = match LayoutToken::from_str(token.as_str())
|
|
||||||
{
|
|
||||||
Err(err) => {
|
|
||||||
return Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("token".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(err))
|
|
||||||
});
|
|
||||||
},
|
|
||||||
Ok(token) => token,
|
|
||||||
};
|
|
||||||
|
|
||||||
CTX.with_borrow(|ctx| {
|
|
||||||
ctx.as_ref().map(|ctx| {
|
|
||||||
// Make sure the state has been initialized
|
|
||||||
let state = LayoutRule::initialize_state(ctx.parser);
|
|
||||||
|
|
||||||
// Get layout
|
|
||||||
let layout_type = match ctx.parser.get_layout(layout.as_str())
|
|
||||||
{
|
|
||||||
None => {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 2,
|
|
||||||
name: Some("layout".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!(
|
|
||||||
"Cannot find layout with name `{layout}`"
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
Some(layout) => layout,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse properties
|
|
||||||
let layout_properties = match layout_type.parse_properties(properties.as_str()) {
|
|
||||||
Err(err) => {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 3,
|
|
||||||
name: Some("properties".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(err)),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
Ok(properties) => properties,
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = match layout_token {
|
|
||||||
LayoutToken::Begin => {
|
|
||||||
ctx.parser.push(
|
|
||||||
ctx.document,
|
|
||||||
Box::new(Layout {
|
|
||||||
location: ctx.location.clone(),
|
|
||||||
layout: layout_type.clone(),
|
|
||||||
id: 0,
|
|
||||||
token: LayoutToken::Begin,
|
|
||||||
properties: layout_properties,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
state
|
|
||||||
.borrow_mut()
|
|
||||||
.downcast_mut::<LayoutState>()
|
|
||||||
.map_or_else(
|
|
||||||
|| panic!("Invalid state at: `{}`", STATE_NAME.as_str()),
|
|
||||||
|s| s.stack.push((vec![ctx.location.clone()], layout_type.clone())),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
LayoutToken::Next => {
|
|
||||||
let mut state_borrow = state.borrow_mut();
|
|
||||||
let state = state_borrow.downcast_mut::<LayoutState>().unwrap();
|
|
||||||
|
|
||||||
let (tokens, current_layout_type) = match state.stack.last_mut() {
|
|
||||||
None => {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("token".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Unable set next layout: No active layout found"))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Some(last) => last,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !Rc::ptr_eq(&layout_type, current_layout_type) {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 2,
|
|
||||||
name: Some("layout".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Invalid layout next, current layout is {} vs {}",
|
|
||||||
current_layout_type.name(),
|
|
||||||
layout_type.name())))
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if layout_type.expects().end < tokens.len()
|
|
||||||
// Too many blocks
|
|
||||||
{
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("token".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Unable set layout next: layout {} expect at most {} blocks, currently at {} blocks",
|
|
||||||
layout_type.name(),
|
|
||||||
layout_type.expects().end,
|
|
||||||
tokens.len()
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens.push(ctx.location.clone());
|
|
||||||
tokens.len() - 1
|
|
||||||
},
|
|
||||||
LayoutToken::End => {
|
|
||||||
let mut state_borrow = state.borrow_mut();
|
|
||||||
let state = state_borrow.downcast_mut::<LayoutState>().unwrap();
|
|
||||||
|
|
||||||
let (tokens, current_layout_type) = match state.stack.last_mut() {
|
|
||||||
None => {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("token".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Unable set layout end: No active layout found"))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Some(last) => last,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !Rc::ptr_eq(&layout_type, current_layout_type) {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 2,
|
|
||||||
name: Some("layout".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Invalid layout end, current layout is {} vs {}",
|
|
||||||
current_layout_type.name(),
|
|
||||||
layout_type.name())))
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if layout_type.expects().start > tokens.len()
|
|
||||||
// Not enough blocks
|
|
||||||
{
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("token".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!("Unable set next layout: layout {} expect at least {} blocks, currently at {} blocks",
|
|
||||||
layout_type.name(),
|
|
||||||
layout_type.expects().start,
|
|
||||||
tokens.len()
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = tokens.len();
|
|
||||||
state.stack.pop();
|
|
||||||
id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.parser.push(
|
|
||||||
ctx.document,
|
|
||||||
Box::new(Layout {
|
|
||||||
location: ctx.location.clone(),
|
|
||||||
layout: layout_type.clone(),
|
|
||||||
id,
|
|
||||||
token: layout_token,
|
|
||||||
properties: layout_properties,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
result
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(bindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_layouts(&self, parser: &dyn Parser) {
|
|
||||||
parser.insert_layout(Rc::new(default_layouts::Centered::default()));
|
|
||||||
parser.insert_layout(Rc::new(default_layouts::Split::default()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -920,56 +727,4 @@ mod tests {
|
||||||
Layout { token == LayoutToken::End, id == 2 };
|
Layout { token == LayoutToken::End, id == 2 };
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lua() {
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
%<nml.layout.push("begin", "Split", "style=A")>%
|
|
||||||
A
|
|
||||||
%<nml.layout.push("Begin", "Centered", "style=B")>%
|
|
||||||
B
|
|
||||||
%<nml.layout.push("end", "Centered", "")>%
|
|
||||||
%<nml.layout.push("next", "Split", "style=C")>%
|
|
||||||
C
|
|
||||||
%<nml.layout.push("Begin", "Split", "style=D")>%
|
|
||||||
D
|
|
||||||
%<nml.layout.push("Next", "Split", "style=E")>%
|
|
||||||
E
|
|
||||||
%<nml.layout.push("End", "Split", "")>%
|
|
||||||
%<nml.layout.push("End", "Split", "")>%
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let doc = parser.parse(source, None);
|
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
|
||||||
Layout { token == LayoutToken::Begin, id == 0 };
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "A" };
|
|
||||||
};
|
|
||||||
Layout { token == LayoutToken::Begin, id == 0 };
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "B" };
|
|
||||||
};
|
|
||||||
Layout { token == LayoutToken::End, id == 1 };
|
|
||||||
Layout { token == LayoutToken::Next, id == 1 };
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "C" };
|
|
||||||
};
|
|
||||||
Layout { token == LayoutToken::Begin, id == 0 };
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "D" };
|
|
||||||
};
|
|
||||||
Layout { token == LayoutToken::Next, id == 1 };
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "E" };
|
|
||||||
};
|
|
||||||
Layout { token == LayoutToken::End, id == 2 };
|
|
||||||
Layout { token == LayoutToken::End, id == 2 };
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::document::document::Document;
|
||||||
use crate::document::element::ContainerElement;
|
use crate::document::element::ContainerElement;
|
||||||
use crate::document::element::ElemKind;
|
use crate::document::element::ElemKind;
|
||||||
use crate::document::element::Element;
|
use crate::document::element::Element;
|
||||||
use crate::lua::kernel::CTX;
|
|
||||||
use crate::parser::parser::Parser;
|
use crate::parser::parser::Parser;
|
||||||
use crate::parser::rule::RegexRule;
|
use crate::parser::rule::RegexRule;
|
||||||
use crate::parser::source::Source;
|
use crate::parser::source::Source;
|
||||||
|
@ -15,14 +14,12 @@ use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
use mlua::Error::BadArgument;
|
|
||||||
use mlua::Function;
|
use mlua::Function;
|
||||||
use mlua::Lua;
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
|
@ -208,56 +205,8 @@ impl RegexRule for LinkRule {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
// TODO
|
||||||
let mut bindings = vec![];
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
|
|
||||||
bindings.push((
|
|
||||||
"push".to_string(),
|
|
||||||
lua.create_function(|_, (display, url): (String, String)| {
|
|
||||||
let mut result = Ok(());
|
|
||||||
CTX.with_borrow(|ctx| {
|
|
||||||
ctx.as_ref().map(|ctx| {
|
|
||||||
let source = Rc::new(VirtualSource::new(
|
|
||||||
ctx.location.clone(),
|
|
||||||
"Link Display".to_string(),
|
|
||||||
display,
|
|
||||||
));
|
|
||||||
let display_content =
|
|
||||||
match util::parse_paragraph(ctx.parser, source, ctx.document) {
|
|
||||||
Err(err) => {
|
|
||||||
result = Err(BadArgument {
|
|
||||||
to: Some("push".to_string()),
|
|
||||||
pos: 1,
|
|
||||||
name: Some("display".to_string()),
|
|
||||||
cause: Arc::new(mlua::Error::external(format!(
|
|
||||||
"Failed to parse link display: {err}"
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Ok(mut paragraph) => {
|
|
||||||
std::mem::replace(&mut paragraph.content, vec![])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ctx.parser.push(
|
|
||||||
ctx.document,
|
|
||||||
Box::new(Link {
|
|
||||||
location: ctx.location.clone(),
|
|
||||||
display: display_content,
|
|
||||||
url,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
result
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(bindings)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -298,34 +247,4 @@ Some [link](url).
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lua() {
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
Some %<nml.link.push("link", "url")>%.
|
|
||||||
%<
|
|
||||||
nml.link.push("**BOLD link**", "another url")
|
|
||||||
>%
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let doc = parser.parse(source, None);
|
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
|
||||||
Paragraph {
|
|
||||||
Text { content == "Some " };
|
|
||||||
Link { url == "url" } { Text { content == "link" }; };
|
|
||||||
Text { content == "." };
|
|
||||||
Link { url == "another url" } {
|
|
||||||
Style;
|
|
||||||
Text { content == "BOLD link" };
|
|
||||||
Style;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,29 +283,7 @@ Break{?[kind=block] Raw?}NewParagraph{?<b>?}
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
let parser = LangParser::default();
|
let parser = LangParser::default();
|
||||||
let doc = parser.parse(source, None);
|
let compiler = Compiler::new(Target::HTML, None);
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
|
||||||
Paragraph;
|
|
||||||
Raw { kind == ElemKind::Block, content == "Raw" };
|
|
||||||
Paragraph {
|
|
||||||
Text;
|
|
||||||
Raw { kind == ElemKind::Inline, content == "<b>" };
|
|
||||||
};
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lua() {
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
Break%<nml.raw.push("block", "Raw")>%NewParagraph%<nml.raw.push("inline", "<b>")>%
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let doc = parser.parse(source, None);
|
let doc = parser.parse(source, None);
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
validate_document!(doc.content().borrow(), 0,
|
||||||
|
|
|
@ -50,7 +50,8 @@ impl Element for Section {
|
||||||
let numbering = compiler.section_counter(self.depth);
|
let numbering = compiler.section_counter(self.depth);
|
||||||
|
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for num in numbering.iter() {
|
for num in numbering.iter()
|
||||||
|
{
|
||||||
result = result + num.to_string().as_str() + ".";
|
result = result + num.to_string().as_str() + ".";
|
||||||
}
|
}
|
||||||
result += " ";
|
result += " ";
|
||||||
|
@ -406,70 +407,3 @@ mod section_style {
|
||||||
|
|
||||||
impl_elementstyle!(SectionStyle, STYLE_KEY);
|
impl_elementstyle!(SectionStyle, STYLE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::parser::langparser::LangParser;
|
|
||||||
use crate::parser::source::SourceFile;
|
|
||||||
use crate::validate_document;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parser() {
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
# 1
|
|
||||||
##+ 2
|
|
||||||
###* 3
|
|
||||||
####+* 4
|
|
||||||
#####*+ 5
|
|
||||||
######{refname} 6
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let doc = parser.parse(source, None);
|
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
|
||||||
Section { depth == 1, title == "1" };
|
|
||||||
Section { depth == 2, title == "2", kind == section_kind::NO_TOC };
|
|
||||||
Section { depth == 3, title == "3", kind == section_kind::NO_NUMBER };
|
|
||||||
Section { depth == 4, title == "4", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
|
|
||||||
Section { depth == 5, title == "5", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
|
|
||||||
Section { depth == 6, title == "6", reference == Some("refname".to_string()) };
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lua() {
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#"
|
|
||||||
%<
|
|
||||||
nml.section.push("1", 1, "", nil)
|
|
||||||
nml.section.push("2", 2, "+", nil)
|
|
||||||
nml.section.push("3", 3, "*", nil)
|
|
||||||
nml.section.push("4", 4, "+*", nil)
|
|
||||||
nml.section.push("5", 5, "*+", nil)
|
|
||||||
nml.section.push("6", 6, "", "refname")
|
|
||||||
>%
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let doc = parser.parse(source, None);
|
|
||||||
|
|
||||||
validate_document!(doc.content().borrow(), 0,
|
|
||||||
Section { depth == 1, title == "1" };
|
|
||||||
Section { depth == 2, title == "2", kind == section_kind::NO_TOC };
|
|
||||||
Section { depth == 3, title == "3", kind == section_kind::NO_NUMBER };
|
|
||||||
Section { depth == 4, title == "4", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
|
|
||||||
Section { depth == 5, title == "5", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
|
|
||||||
Section { depth == 6, title == "6", reference == Some("refname".to_string()) };
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{cell::{RefCell, RefMut}, collections::HashMap, rc::Rc};
|
use std::{cell::{RefCell, RefMut}, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use crate::{document::{document::Document, element::Element, layout::{LayoutHolder, LayoutType}, style::{ElementStyle, StyleHolder}}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
use crate::{document::{document::Document, element::Element, style::{ElementStyle, StyleHolder}}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LineCursor
|
pub struct LineCursor
|
||||||
|
@ -156,13 +156,3 @@ impl StyleHolder for LsParser {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutHolder for LsParser {
|
|
||||||
fn layouts(&self) -> std::cell::Ref<'_, HashMap<String, Rc<dyn LayoutType>>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layouts_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn LayoutType>>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(char_indices_offset)]
|
||||||
mod cache;
|
mod cache;
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod document;
|
mod document;
|
||||||
|
|
|
@ -16,8 +16,6 @@ use crate::document::element::DocumentEnd;
|
||||||
use crate::document::element::ElemKind;
|
use crate::document::element::ElemKind;
|
||||||
use crate::document::element::Element;
|
use crate::document::element::Element;
|
||||||
use crate::document::langdocument::LangDocument;
|
use crate::document::langdocument::LangDocument;
|
||||||
use crate::document::layout::LayoutHolder;
|
|
||||||
use crate::document::layout::LayoutType;
|
|
||||||
use crate::document::style::ElementStyle;
|
use crate::document::style::ElementStyle;
|
||||||
use crate::document::style::StyleHolder;
|
use crate::document::style::StyleHolder;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
|
@ -48,7 +46,6 @@ pub struct LangParser {
|
||||||
pub state: RefCell<StateHolder>,
|
pub state: RefCell<StateHolder>,
|
||||||
pub kernels: RefCell<HashMap<String, Kernel>>,
|
pub kernels: RefCell<HashMap<String, Kernel>>,
|
||||||
pub styles: RefCell<HashMap<String, Rc<dyn ElementStyle>>>,
|
pub styles: RefCell<HashMap<String, Rc<dyn ElementStyle>>>,
|
||||||
pub layouts: RefCell<HashMap<String, Rc<dyn LayoutType>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LangParser {
|
impl LangParser {
|
||||||
|
@ -60,11 +57,11 @@ impl LangParser {
|
||||||
state: RefCell::new(StateHolder::new()),
|
state: RefCell::new(StateHolder::new()),
|
||||||
kernels: RefCell::new(HashMap::new()),
|
kernels: RefCell::new(HashMap::new()),
|
||||||
styles: RefCell::new(HashMap::new()),
|
styles: RefCell::new(HashMap::new()),
|
||||||
layouts: RefCell::new(HashMap::new()),
|
|
||||||
};
|
};
|
||||||
// Register rules
|
// Register rules
|
||||||
register(&mut s);
|
register(&mut s);
|
||||||
|
|
||||||
|
|
||||||
// Register default kernel
|
// Register default kernel
|
||||||
s.kernels
|
s.kernels
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -74,12 +71,6 @@ impl LangParser {
|
||||||
for rule in &s.rules {
|
for rule in &s.rules {
|
||||||
rule.register_styles(&s);
|
rule.register_styles(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register default layouts
|
|
||||||
for rule in &s.rules {
|
|
||||||
rule.register_layouts(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,15 +313,3 @@ impl StyleHolder for LangParser {
|
||||||
self.styles.borrow_mut()
|
self.styles.borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutHolder for LangParser {
|
|
||||||
fn layouts(&self) -> Ref<'_, HashMap<String, Rc<dyn crate::document::layout::LayoutType>>> {
|
|
||||||
self.layouts.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layouts_mut(
|
|
||||||
&self,
|
|
||||||
) -> RefMut<'_, HashMap<String, Rc<dyn crate::document::layout::LayoutType>>> {
|
|
||||||
self.layouts.borrow_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ use super::source::Source;
|
||||||
use super::state::StateHolder;
|
use super::state::StateHolder;
|
||||||
use crate::document::document::Document;
|
use crate::document::document::Document;
|
||||||
use crate::document::element::Element;
|
use crate::document::element::Element;
|
||||||
use crate::document::layout::LayoutHolder;
|
|
||||||
use crate::document::style::StyleHolder;
|
use crate::document::style::StyleHolder;
|
||||||
use crate::lua::kernel::KernelHolder;
|
use crate::lua::kernel::KernelHolder;
|
||||||
use ariadne::Color;
|
use ariadne::Color;
|
||||||
|
@ -43,7 +42,7 @@ impl ReportColors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parser: KernelHolder + StyleHolder + LayoutHolder {
|
pub trait Parser: KernelHolder + StyleHolder {
|
||||||
/// Gets the colors for formatting errors
|
/// Gets the colors for formatting errors
|
||||||
///
|
///
|
||||||
/// When colors are disabled, all colors should resolve to empty string
|
/// When colors are disabled, all colors should resolve to empty string
|
||||||
|
|
|
@ -29,9 +29,6 @@ pub trait Rule {
|
||||||
|
|
||||||
/// Registers default styles
|
/// Registers default styles
|
||||||
fn register_styles(&self, _parser: &dyn Parser) {}
|
fn register_styles(&self, _parser: &dyn Parser) {}
|
||||||
|
|
||||||
/// Registers default layouts
|
|
||||||
fn register_layouts(&self, _parser: &dyn Parser) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for dyn Rule {
|
impl core::fmt::Debug for dyn Rule {
|
||||||
|
@ -40,6 +37,45 @@ impl core::fmt::Debug for dyn Rule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub trait RegexRule: Rule
|
||||||
|
{
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
|
/// Returns the rule's regex
|
||||||
|
fn regex(&self) -> ®ex::Regex;
|
||||||
|
/// Callback on regex rule match
|
||||||
|
fn on_regex_match<'a>(&self, parser: &Parser, document: &Document, token: Token<'a>, matches: regex::Captures) -> Vec<Report<'a, (String, Range<usize>)>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RegexRule> Rule for T {
|
||||||
|
fn name(&self) -> &'static str { RegexRule::name(self) }
|
||||||
|
|
||||||
|
/// Finds the next match starting from [`cursor`]
|
||||||
|
fn next_match<'a>(&self, cursor: &'a Cursor) -> Option<usize>
|
||||||
|
{
|
||||||
|
let re = self.regex();
|
||||||
|
|
||||||
|
let content = cursor.file.content.as_ref().unwrap();
|
||||||
|
match re.find_at(content.as_str(), cursor.pos)
|
||||||
|
{
|
||||||
|
Some(m) => Some(m.start()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_match<'a>(&self, parser: &Parser, document: &Document, cursor: Cursor<'a>) -> (Cursor<'a>, Vec<Report<'a, (String, Range<usize>)>>)
|
||||||
|
{
|
||||||
|
let content = cursor.file.content.as_ref().unwrap();
|
||||||
|
let matches = self.regex().captures_at(content.as_str(), cursor.pos).unwrap();
|
||||||
|
let token = Token::new(cursor.pos, matches.get(0).unwrap().len(), cursor.file);
|
||||||
|
|
||||||
|
let token_end = token.end();
|
||||||
|
(cursor.at(token_end), self.on_regex_match(parser, document, token, matches))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub trait RegexRule {
|
pub trait RegexRule {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
|
@ -58,7 +94,6 @@ pub trait RegexRule {
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
fn register_styles(&self, _parser: &dyn Parser) {}
|
fn register_styles(&self, _parser: &dyn Parser) {}
|
||||||
fn register_layouts(&self, _parser: &dyn Parser) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RegexRule> Rule for T {
|
impl<T: RegexRule> Rule for T {
|
||||||
|
@ -120,8 +155,4 @@ impl<T: RegexRule> Rule for T {
|
||||||
fn register_styles(&self, parser: &dyn Parser) {
|
fn register_styles(&self, parser: &dyn Parser) {
|
||||||
self.register_styles(parser);
|
self.register_styles(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_layouts(&self, parser: &dyn Parser) {
|
|
||||||
self.register_layouts(parser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue