Compare commits

..

No commits in common. "67ea2f941117783aed2cf9c716f8d18236c3597a" and "098252794440736be008f91f979bf7207a944791" have entirely different histories.

12 changed files with 146 additions and 606 deletions

View file

@ -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)
}
}
(None, None) => 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;
}
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
);
} }
} }

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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 };
);
}
} }

View file

@ -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;
};
};
);
}
} }

View file

@ -283,6 +283,7 @@ Break{?[kind=block] Raw?}NewParagraph{?<b>?}
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let compiler = Compiler::new(Target::HTML, None);
let doc = parser.parse(source, None); let doc = parser.parse(source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
@ -294,27 +295,4 @@ Break{?[kind=block] Raw?}NewParagraph{?<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);
validate_document!(doc.content().borrow(), 0,
Paragraph;
Raw { kind == ElemKind::Block, content == "Raw" };
Paragraph {
Text;
Raw { kind == ElemKind::Inline, content == "<b>" };
};
);
}
} }

View file

@ -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()) };
);
}
}

View file

@ -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!()
}
}

View file

@ -1,3 +1,4 @@
#![feature(char_indices_offset)]
mod cache; mod cache;
mod compiler; mod compiler;
mod document; mod document;

View file

@ -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()
}
}

View file

@ -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

View file

@ -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) -> &regex::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);
}
} }