This commit is contained in:
ef3d0c3e 2024-08-14 22:50:32 +02:00
parent fa68b68bf6
commit 6eae5cd79b
37 changed files with 178 additions and 238 deletions

4
src/cache/cache.rs vendored
View file

@ -62,10 +62,10 @@ pub trait Cached {
if let Some(value) = value { if let Some(value) = value {
// Found in cache // Found in cache
return Ok(value); Ok(value)
} else { } else {
// Compute a value // Compute a value
let value = match f(&self) { let value = match f(self) {
Ok(val) => val, Ok(val) => val,
Err(e) => return Err(CachedError::GenErr(e)), Err(e) => return Err(CachedError::GenErr(e)),
}; };

View file

@ -48,7 +48,7 @@ impl<'a> Compiler<'a> {
.borrow_mut() .borrow_mut()
.last_mut() .last_mut()
.map(|id| *id += 1); .map(|id| *id += 1);
return Ref::map(self.sections_counter.borrow(), |b| &*b); return Ref::map(self.sections_counter.borrow(), |b| b);
} }
// Close // Close
@ -61,7 +61,7 @@ impl<'a> Compiler<'a> {
self.sections_counter.borrow_mut().push(1); self.sections_counter.borrow_mut().push(1);
} }
Ref::map(self.sections_counter.borrow(), |b| &*b) Ref::map(self.sections_counter.borrow(), |b| b)
} }
/// Sanitizes text for a [`Target`] /// Sanitizes text for a [`Target`]
@ -86,7 +86,7 @@ impl<'a> Compiler<'a> {
/// ///
/// # Parameters /// # Parameters
/// - [`reference`] The reference to get or insert /// - [`reference`] The reference to get or insert
pub fn reference_id<'b>(&self, document: &'b dyn Document, reference: ElemReference) -> usize { pub fn reference_id(&self, document: &dyn Document, reference: ElemReference) -> usize {
let mut borrow = self.reference_count.borrow_mut(); let mut borrow = self.reference_count.borrow_mut();
let reference = document.get_from_reference(&reference).unwrap(); let reference = document.get_from_reference(&reference).unwrap();
let refkey = reference.refcount_key(); let refkey = reference.refcount_key();
@ -133,7 +133,6 @@ impl<'a> Compiler<'a> {
) -> Option<Rc<dyn Variable>> { ) -> Option<Rc<dyn Variable>> {
document document
.get_variable(var_name) .get_variable(var_name)
.and_then(|var| Some(var))
.or_else(|| { .or_else(|| {
println!( println!(
"Missing variable `{var_name}` in {}", "Missing variable `{var_name}` in {}",

View file

@ -125,7 +125,7 @@ pub fn create_navigation(
let title = doc_borrow let title = doc_borrow
.get_variable("nav.title") .get_variable("nav.title")
.or(doc_borrow.get_variable("doc.title")); .or(doc_borrow.get_variable("doc.title"));
let previous = doc_borrow.get_variable("nav.previous").map(|s| s.clone()); let previous = doc_borrow.get_variable("nav.previous").cloned();
let path = doc_borrow.get_variable("compiler.output"); let path = doc_borrow.get_variable("compiler.output");
let (title, path) = match (title, path) { let (title, path) = match (title, path) {
@ -205,7 +205,7 @@ pub fn create_navigation(
// Sort entries // Sort entries
fn sort_entries(nav: &mut NavEntry) { fn sort_entries(nav: &mut NavEntry) {
nav.entries nav.entries
.sort_unstable_by(|l, r| NavEntry::sort_entry(l, r)); .sort_unstable_by(NavEntry::sort_entry);
for (_, child) in &mut nav.children { for (_, child) in &mut nav.children {
sort_entries(child); sort_entries(child);

View file

@ -38,7 +38,7 @@ impl PostProcess {
return Err(format!("Cannot use an unspecific reference for reference named: `{name}`. Found in document `{}` but also in `{}`. Specify the source of the reference to resolve the conflict.", previous_doc.borrow().input, doc.borrow().input)); return Err(format!("Cannot use an unspecific reference for reference named: `{name}`. Found in document `{}` but also in `{}`. Specify the source of the reference to resolve the conflict.", previous_doc.borrow().input, doc.borrow().input));
} }
found_ref = Some((found.clone(), &doc)); found_ref = Some((found.clone(), doc));
} }
} }
} }
@ -67,9 +67,7 @@ impl PostProcess {
} }
if let Some((found_ref, found_doc)) = &found_ref { if let Some((found_ref, found_doc)) = &found_ref {
let found_borrow = found_doc.borrow(); let found_borrow = found_doc.borrow();
let found_path = found_borrow.get_variable("compiler.output").ok_or(format!( let found_path = found_borrow.get_variable("compiler.output").ok_or("Unable to get the output. Aborting postprocessing.".to_string())?;
"Unable to get the output. Aborting postprocessing."
))?;
let insert_content = format!("{found_path}#{found_ref}"); let insert_content = format!("{found_path}#{found_ref}");
content.insert_str(pos + offset, insert_content.as_str()); content.insert_str(pos + offset, insert_content.as_str());
offset += insert_content.len(); offset += insert_content.len();

View file

@ -74,7 +74,7 @@ pub fn process(
let con = db_path let con = db_path
.as_ref() .as_ref()
.map_or(Connection::open_in_memory(), |path| Connection::open(path)) .map_or(Connection::open_in_memory(), Connection::open)
.map_err(|err| format!("Unable to open connection to the database: {err}"))?; .map_err(|err| format!("Unable to open connection to the database: {err}"))?;
CompiledDocument::init_cache(&con) CompiledDocument::init_cache(&con)
.map_err(|err| format!("Failed to initialize cached document table: {err}"))?; .map_err(|err| format!("Failed to initialize cached document table: {err}"))?;
@ -137,7 +137,7 @@ pub fn process(
let body = postprocess let body = postprocess
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply(target, &compiled, &doc)?; .apply(target, &compiled, doc)?;
doc.borrow_mut().body = body; doc.borrow_mut().body = body;
// Insert into cache // Insert into cache
@ -157,6 +157,7 @@ pub fn process(
/// Processes sources from in-memory strings /// Processes sources from in-memory strings
/// This function is indented for testing /// This function is indented for testing
#[cfg(test)]
pub fn process_from_memory(target: Target, sources: Vec<String>) -> Result<Vec<(RefCell<CompiledDocument>, Option<PostProcess>)>, String> { pub fn process_from_memory(target: Target, sources: Vec<String>) -> Result<Vec<(RefCell<CompiledDocument>, Option<PostProcess>)>, String> {
let mut compiled = vec![]; let mut compiled = vec![];
@ -187,7 +188,7 @@ pub fn process_from_memory(target: Target, sources: Vec<String>) -> Result<Vec<(
let body = postprocess let body = postprocess
.as_ref() .as_ref()
.unwrap() .unwrap()
.apply(target, &compiled, &doc)?; .apply(target, &compiled, doc)?;
doc.borrow_mut().body = body; doc.borrow_mut().body = body;
} }

View file

@ -75,7 +75,7 @@ impl Scope {
// Variables // Variables
self.variables self.variables
.extend(other.variables.drain().map(|(name, var)| (name, var))); .extend(other.variables.drain());
} }
false => { false => {
// References // References
@ -165,15 +165,15 @@ pub trait Document<'a>: core::fmt::Debug {
fn get_variable(&self, name: &str) -> Option<Rc<dyn Variable>> { fn get_variable(&self, name: &str) -> Option<Rc<dyn Variable>> {
match self.scope().borrow().variables.get(name) { match self.scope().borrow().variables.get(name) {
Some(variable) => { Some(variable) => {
return Some(variable.clone()); Some(variable.clone())
} }
// Continue search recursively // Continue search recursively
None => match self.parent() { None => match self.parent() {
Some(parent) => return parent.get_variable(name), Some(parent) => parent.get_variable(name),
// Not found // Not found
None => return None, None => None,
}, },
} }
} }
@ -189,27 +189,23 @@ pub trait Document<'a>: core::fmt::Debug {
scope: &RefCell<Scope>, scope: &RefCell<Scope>,
merge_as: Option<&String>, merge_as: Option<&String>,
) { ) {
match merge_as { if let Some(merge_as) = merge_as { self.scope().borrow_mut().merge(
Some(merge_as) => self.scope().borrow_mut().merge( &mut scope.borrow_mut(),
&mut *scope.borrow_mut(), merge_as,
merge_as, self.content().borrow().len(),
self.content().borrow().len(), ) }
),
_ => {}
}
// Content // Content
self.content() self.content()
.borrow_mut() .borrow_mut()
.extend((content.borrow_mut()).drain(..).map(|value| value)); .extend((content.borrow_mut()).drain(..));
} }
fn get_reference(&self, refname: &str) -> Option<ElemReference> { fn get_reference(&self, refname: &str) -> Option<ElemReference> {
self.scope() self.scope()
.borrow() .borrow()
.referenceable .referenceable
.get(refname) .get(refname).copied()
.and_then(|reference| Some(*reference))
} }
fn get_from_reference( fn get_from_reference(

View file

@ -20,8 +20,8 @@ pub struct LangDocument<'a> {
impl<'a> LangDocument<'a> { impl<'a> LangDocument<'a> {
pub fn new(source: Rc<dyn Source>, parent: Option<&'a dyn Document<'a>>) -> Self { pub fn new(source: Rc<dyn Source>, parent: Option<&'a dyn Document<'a>>) -> Self {
Self { Self {
source: source, source,
parent: parent, parent,
content: RefCell::new(Vec::new()), content: RefCell::new(Vec::new()),
scope: RefCell::new(Scope::new()), scope: RefCell::new(Scope::new()),
} }
@ -32,7 +32,7 @@ impl<'a> Document<'a> for LangDocument<'a> {
fn source(&self) -> Rc<dyn Source> { self.source.clone() } fn source(&self) -> Rc<dyn Source> { self.source.clone() }
fn parent(&self) -> Option<&'a dyn Document<'a>> { fn parent(&self) -> Option<&'a dyn Document<'a>> {
self.parent.and_then(|p| Some(p as &dyn Document<'a>)) self.parent.map(|p| p as &dyn Document<'a>)
} }
fn content(&self) -> &RefCell<Vec<Box<dyn Element>>> { &self.content } fn content(&self) -> &RefCell<Vec<Box<dyn Element>>> { &self.content }

View file

@ -92,13 +92,13 @@ impl Variable for PathVariable {
fn name(&self) -> &str { self.name.as_str() } fn name(&self) -> &str { self.name.as_str() }
fn from_string(&mut self, str: &str) -> Option<String> { fn from_string(&mut self, str: &str) -> Option<String> {
self.path = PathBuf::from(std::fs::canonicalize(str).unwrap()); self.path = std::fs::canonicalize(str).unwrap();
None None
} }
fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() } fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() }
fn parse<'a>(&self, state: &ParserState, location: Token, document: &'a dyn Document) { fn parse(&self, state: &ParserState, location: Token, document: &dyn Document) {
let source = Rc::new(VirtualSource::new( let source = Rc::new(VirtualSource::new(
location, location,
self.name().to_string(), self.name().to_string(),

View file

@ -85,7 +85,7 @@ impl Element for Blockquote {
if self.cite.is_some() || self.author.is_some() { if self.cite.is_some() || self.author.is_some() {
result += r#"<p class="blockquote-author">"#; result += r#"<p class="blockquote-author">"#;
let fmt_pair = FmtPair(compiler.target(), &self); let fmt_pair = FmtPair(compiler.target(), self);
match (self.author.is_some(), self.cite.is_some()) { match (self.author.is_some(), self.cite.is_some()) {
(true, true) => { (true, true) => {
let args = let args =
@ -215,10 +215,7 @@ impl Rule for BlockquoteRule {
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
.map_or(None, |m| {
Some((m.start(), Box::new([false; 0]) as Box<dyn Any>))
})
} }
fn on_match<'a>( fn on_match<'a>(
@ -331,7 +328,7 @@ impl Rule for BlockquoteRule {
); );
break; break;
} }
Ok(mut paragraph) => std::mem::replace(&mut paragraph.content, vec![]), Ok(mut paragraph) => std::mem::take(&mut paragraph.content),
}; };
// Get style // Get style
@ -376,7 +373,7 @@ mod blockquote_style {
use crate::impl_elementstyle; use crate::impl_elementstyle;
pub static STYLE_KEY: &'static str = "style.blockquote"; pub static STYLE_KEY: &str = "style.blockquote";
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
pub enum AuthorPos { pub enum AuthorPos {

View file

@ -123,8 +123,8 @@ impl Code {
} }
result += result +=
format!("<div class=\"code-block-content\"><table cellspacing=\"0\">").as_str(); "<div class=\"code-block-content\"><table cellspacing=\"0\">".to_string().as_str();
for (line_id, line) in self.code.split(|c| c == '\n').enumerate() { for (line_id, line) in self.code.split('\n').enumerate() {
result += "<tr><td class=\"code-block-gutter\">"; result += "<tr><td class=\"code-block-gutter\">";
// Line number // Line number
@ -137,7 +137,7 @@ impl Code {
Err(e) => { Err(e) => {
return Err(format!( return Err(format!(
"Error highlighting line `{line}`: {}", "Error highlighting line `{line}`: {}",
e.to_string() e
)) ))
} }
Ok(regions) => { Ok(regions) => {
@ -146,7 +146,7 @@ impl Code {
syntect::html::IncludeBackground::No, syntect::html::IncludeBackground::No,
) { ) {
Err(e) => { Err(e) => {
return Err(format!("Error highlighting code: {}", e.to_string())) return Err(format!("Error highlighting code: {}", e))
} }
Ok(highlighted) => { Ok(highlighted) => {
result += if highlighted.is_empty() { result += if highlighted.is_empty() {
@ -165,14 +165,14 @@ impl Code {
} else if self.block == CodeKind::MiniBlock { } else if self.block == CodeKind::MiniBlock {
result += "<div class=\"code-block\"><div class=\"code-block-content\"><table cellspacing=\"0\">"; result += "<div class=\"code-block\"><div class=\"code-block-content\"><table cellspacing=\"0\">";
for line in self.code.split(|c| c == '\n') { for line in self.code.split('\n') {
result += "<tr><td class=\"code-block-line\"><pre>"; result += "<tr><td class=\"code-block-line\"><pre>";
// Code // Code
match h.highlight_line(line, Code::get_syntaxes()) { match h.highlight_line(line, Code::get_syntaxes()) {
Err(e) => { Err(e) => {
return Err(format!( return Err(format!(
"Error highlighting line `{line}`: {}", "Error highlighting line `{line}`: {}",
e.to_string() e
)) ))
} }
Ok(regions) => { Ok(regions) => {
@ -181,7 +181,7 @@ impl Code {
syntect::html::IncludeBackground::No, syntect::html::IncludeBackground::No,
) { ) {
Err(e) => { Err(e) => {
return Err(format!("Error highlighting code: {}", e.to_string())) return Err(format!("Error highlighting code: {}", e))
} }
Ok(highlighted) => { Ok(highlighted) => {
result += if highlighted.is_empty() { result += if highlighted.is_empty() {
@ -203,7 +203,7 @@ impl Code {
return Err(format!( return Err(format!(
"Error highlighting line `{}`: {}", "Error highlighting line `{}`: {}",
self.code, self.code,
e.to_string() e
)) ))
} }
Ok(regions) => { Ok(regions) => {
@ -212,7 +212,7 @@ impl Code {
syntect::html::IncludeBackground::No, syntect::html::IncludeBackground::No,
) { ) {
Err(e) => { Err(e) => {
return Err(format!("Error highlighting code: {}", e.to_string())) return Err(format!("Error highlighting code: {}", e))
} }
Ok(highlighted) => result += highlighted.as_str(), Ok(highlighted) => result += highlighted.as_str(),
} }
@ -244,11 +244,10 @@ impl Cached for Code {
fn key(&self) -> <Self as Cached>::Key { fn key(&self) -> <Self as Cached>::Key {
let mut hasher = Sha512::new(); let mut hasher = Sha512::new();
hasher.input((self.block as usize).to_be_bytes().as_slice()); hasher.input((self.block as usize).to_be_bytes().as_slice());
hasher.input((self.line_offset as usize).to_be_bytes().as_slice()); hasher.input(self.line_offset.to_be_bytes().as_slice());
self.theme if let Some(theme) = self.theme
.as_ref() .as_ref() { hasher.input(theme.as_bytes()) }
.map(|theme| hasher.input(theme.as_bytes())); if let Some(name) = self.name.as_ref() { hasher.input(name.as_bytes()) }
self.name.as_ref().map(|name| hasher.input(name.as_bytes()));
hasher.input(self.language.as_bytes()); hasher.input(self.language.as_bytes());
hasher.input(self.code.as_bytes()); hasher.input(self.code.as_bytes());
@ -335,11 +334,11 @@ impl RegexRule for CodeRule {
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn on_regex_match<'a>( fn on_regex_match(
&self, &self,
index: usize, index: usize,
state: &ParserState, state: &ParserState,
document: &'a dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
@ -432,7 +431,7 @@ impl RegexRule for CodeRule {
} else { } else {
util::process_escaped('\\', "``", matches.get(3).unwrap().as_str()) util::process_escaped('\\', "``", matches.get(3).unwrap().as_str())
}; };
if code_content.bytes().last() == Some('\n' as u8) if code_content.bytes().last() == Some(b'\n')
// Remove newline // Remove newline
{ {
code_content.pop(); code_content.pop();
@ -453,8 +452,7 @@ impl RegexRule for CodeRule {
} }
let theme = document let theme = document
.get_variable("code.theme") .get_variable("code.theme").map(|var| var.to_string());
.and_then(|var| Some(var.to_string()));
if index == 0 if index == 0
// Block // Block
@ -553,8 +551,7 @@ impl RegexRule for CodeRule {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
let theme = ctx let theme = ctx
.document .document
.get_variable("code.theme") .get_variable("code.theme").map(|var| var.to_string());
.and_then(|var| Some(var.to_string()));
ctx.state.push( ctx.state.push(
ctx.document, ctx.document,
@ -584,8 +581,7 @@ impl RegexRule for CodeRule {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
let theme = ctx let theme = ctx
.document .document
.get_variable("code.theme") .get_variable("code.theme").map(|var| var.to_string());
.and_then(|var| Some(var.to_string()));
ctx.state.push( ctx.state.push(
ctx.document, ctx.document,
@ -622,8 +618,7 @@ impl RegexRule for CodeRule {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
let theme = ctx let theme = ctx
.document .document
.get_variable("code.theme") .get_variable("code.theme").map(|var| var.to_string());
.and_then(|var| Some(var.to_string()));
ctx.state.push( ctx.state.push(
ctx.document, ctx.document,

View file

@ -50,11 +50,11 @@ impl RegexRule for CommentRule {
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn on_regex_match<'a>( fn on_regex_match(
&self, &self,
_: usize, _: usize,
state: &ParserState, state: &ParserState,
document: &'a dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
@ -89,7 +89,7 @@ impl RegexRule for CommentRule {
}), }),
); );
return reports; reports
} }
} }

View file

@ -140,13 +140,10 @@ impl RuleState for CustomStyleState {
let paragraph = document.last_element::<Paragraph>().unwrap(); let paragraph = document.last_element::<Paragraph>().unwrap();
let paragraph_end = paragraph let paragraph_end = paragraph
.content .content
.last() .last().map(|last| (
.and_then(|last| {
Some((
last.location().source(), last.location().source(),
last.location().end() - 1..last.location().end(), last.location().end() - 1..last.location().end(),
)) ))
})
.unwrap(); .unwrap();
reports.push( reports.push(
@ -164,7 +161,7 @@ impl RuleState for CustomStyleState {
.with_label( .with_label(
Label::new(paragraph_end) Label::new(paragraph_end)
.with_order(1) .with_order(1)
.with_message(format!("Paragraph ends here")) .with_message("Paragraph ends here".to_string())
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_note("Styles cannot span multiple documents (i.e @import)") .with_note("Styles cannot span multiple documents (i.e @import)")
@ -172,11 +169,11 @@ impl RuleState for CustomStyleState {
); );
}); });
return reports; reports
} }
} }
static STATE_NAME: &'static str = "elements.custom_style"; static STATE_NAME: &str = "elements.custom_style";
#[auto_registry::auto_registry(registry = "rules", path = "crate::elements::customstyle")] #[auto_registry::auto_registry(registry = "rules", path = "crate::elements::customstyle")]
pub struct CustomStyleRule; pub struct CustomStyleRule;

View file

@ -63,10 +63,7 @@ impl Rule for ElemStyleRule {
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
.map_or(None, |m| {
Some((m.start(), Box::new([false; 0]) as Box<dyn Any>))
})
} }
fn on_match<'a>( fn on_match<'a>(
@ -93,7 +90,7 @@ impl Rule for ElemStyleRule {
.with_message("Empty Style Key") .with_message("Empty Style Key")
.with_label( .with_label(
Label::new((cursor.source.clone(), key.range())) Label::new((cursor.source.clone(), key.range()))
.with_message(format!("Expected a non-empty style key",)) .with_message("Expected a non-empty style key".to_string())
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.finish(), .finish(),
@ -135,9 +132,7 @@ impl Rule for ElemStyleRule {
.with_message("Invalid Style Value") .with_message("Invalid Style Value")
.with_label( .with_label(
Label::new((cursor.source.clone(), matches.get(0).unwrap().range())) Label::new((cursor.source.clone(), matches.get(0).unwrap().range()))
.with_message(format!( .with_message("Unable to parse json string after style key".to_string())
"Unable to parse json string after style key",
))
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.finish(), .finish(),

View file

@ -179,6 +179,6 @@ impl RegexRule for ImportRule {
); );
} }
return result; result
} }
} }

View file

@ -280,7 +280,7 @@ impl RuleState for LayoutState {
); );
} }
return reports; reports
} }
} }
@ -375,7 +375,7 @@ impl LayoutRule {
} }
} }
static STATE_NAME: &'static str = "elements.layout"; static STATE_NAME: &str = "elements.layout";
impl RegexRule for LayoutRule { impl RegexRule for LayoutRule {
fn name(&self) -> &'static str { "Layout" } fn name(&self) -> &'static str { "Layout" }
@ -649,7 +649,7 @@ impl RegexRule for LayoutRule {
}), }),
); );
return reports; reports
} }
// TODO: Add method to create new layouts // TODO: Add method to create new layouts
@ -746,7 +746,7 @@ impl RegexRule for LayoutRule {
to: Some("push".to_string()), to: Some("push".to_string()),
pos: 1, pos: 1,
name: Some("token".to_string()), name: Some("token".to_string()),
cause: Arc::new(mlua::Error::external(format!("Unable set next layout: No active layout found"))), cause: Arc::new(mlua::Error::external("Unable set next layout: No active layout found".to_string())),
}); });
return; return;
} }
@ -794,7 +794,7 @@ impl RegexRule for LayoutRule {
to: Some("push".to_string()), to: Some("push".to_string()),
pos: 1, pos: 1,
name: Some("token".to_string()), name: Some("token".to_string()),
cause: Arc::new(mlua::Error::external(format!("Unable set layout end: No active layout found"))), cause: Arc::new(mlua::Error::external("Unable set layout end: No active layout found".to_string())),
}); });
return; return;
} }

View file

@ -153,7 +153,7 @@ impl RegexRule for LinkRule {
); );
return reports; return reports;
} }
Ok(mut paragraph) => std::mem::replace(&mut paragraph.content, vec![]), Ok(mut paragraph) => std::mem::take(&mut paragraph.content),
} }
} }
_ => panic!("Empty link name"), _ => panic!("Empty link name"),
@ -176,7 +176,7 @@ impl RegexRule for LinkRule {
} }
let text_content = util::process_text(document, url.as_str()); let text_content = util::process_text(document, url.as_str());
if text_content.as_str().is_empty() { if text_content.is_empty() {
reports.push( reports.push(
Report::build(ReportKind::Error, token.source(), url.start()) Report::build(ReportKind::Error, token.source(), url.start())
.with_message("Empty link url") .with_message("Empty link url")
@ -207,7 +207,7 @@ impl RegexRule for LinkRule {
}), }),
); );
return reports; reports
} }
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
@ -238,7 +238,7 @@ impl RegexRule for LinkRule {
return; return;
} }
Ok(mut paragraph) => { Ok(mut paragraph) => {
std::mem::replace(&mut paragraph.content, vec![]) std::mem::take(&mut paragraph.content)
} }
}; };

View file

@ -244,7 +244,7 @@ impl ListRule {
} }
}); });
return parsed; parsed
} }
} }
@ -254,10 +254,7 @@ impl Rule for ListRule {
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
.map_or(None, |m| {
Some((m.start(), Box::new([false; 0]) as Box<dyn Any>))
})
} }
fn on_match<'a>( fn on_match<'a>(
@ -329,7 +326,7 @@ impl Rule for ListRule {
.get(2) .get(2)
.unwrap() .unwrap()
.as_str() .as_str()
.find(|c| c == '*' || c == '-') .find(['*', '-'])
== Some(0) == Some(0)
{ {
break; break;
@ -393,7 +390,7 @@ impl Rule for ListRule {
); );
break; break;
} }
Ok(mut paragraph) => std::mem::replace(&mut paragraph.content, vec![]), Ok(mut paragraph) => std::mem::take(&mut paragraph.content),
}; };
if let Some(previous_depth) = document if let Some(previous_depth) = document

View file

@ -158,14 +158,11 @@ impl Element for Medium {
let caption = self let caption = self
.caption .caption
.as_ref() .as_ref().map(|cap| format!(
.and_then(|cap| {
Some(format!(
" {}", " {}",
Compiler::sanitize(compiler.target(), cap.as_str()) Compiler::sanitize(compiler.target(), cap.as_str())
)) ))
}) .unwrap_or_default();
.unwrap_or(String::new());
result.push_str( result.push_str(
format!(r#"<p class="medium-refname">({refcount}){caption}</p>"#).as_str(), format!(r#"<p class="medium-refname">({refcount}){caption}</p>"#).as_str(),
@ -436,15 +433,13 @@ impl RegexRule for MediaRule {
.get("width", |_, value| -> Result<String, ()> { .get("width", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok() .ok().map(|(_, s)| s);
.and_then(|(_, s)| Some(s));
let caption = properties let caption = properties
.get("caption", |_, value| -> Result<String, ()> { .get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok() .ok().map(|(_, value)| value);
.and_then(|(_, value)| Some(value));
let description = match matches.get(4) { let description = match matches.get(4) {
Some(content) => { Some(content) => {

View file

@ -110,8 +110,7 @@ impl Rule for ParagraphRule {
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
self.re self.re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
.and_then(|m| Some((m.start(), Box::new([false; 0]) as Box<dyn Any>)))
} }
fn on_match( fn on_match(

View file

@ -2,7 +2,6 @@ use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use ariadne::ReportKind; use ariadne::ReportKind;
@ -245,8 +244,7 @@ impl RegexRule for ReferenceRule {
.get("caption", |_, value| -> Result<String, ()> { .get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok() .ok().map(|(_, s)| s);
.and_then(|(_, s)| Some(s));
if let Some(refdoc) = refdoc { if let Some(refdoc) = refdoc {
if refdoc.is_empty() { if refdoc.is_empty() {

View file

@ -172,7 +172,7 @@ impl RegexRule for ScriptRule {
Label::new((source.clone(), 0..source.content().len())) Label::new((source.clone(), 0..source.content().len()))
.with_message(format!( .with_message(format!(
"Kernel execution failed:\n{}", "Kernel execution failed:\n{}",
e.to_string() e
)) ))
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
@ -215,7 +215,7 @@ impl RegexRule for ScriptRule {
Label::new((source.clone(), 0..source.content().len())) Label::new((source.clone(), 0..source.content().len()))
.with_message(format!( .with_message(format!(
"Kernel evaluation failed:\n{}", "Kernel evaluation failed:\n{}",
e.to_string() e
)) ))
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
@ -263,7 +263,7 @@ impl RegexRule for ScriptRule {
Label::new((source.clone(), 0..source.content().len())) Label::new((source.clone(), 0..source.content().len()))
.with_message(format!( .with_message(format!(
"Kernel evaluation failed:\n{}", "Kernel evaluation failed:\n{}",
e.to_string() e
)) ))
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )

View file

@ -222,7 +222,7 @@ impl RegexRule for SectionRule {
.with_message(format!("`{}` previously defined here", .with_message(format!("`{}` previously defined here",
refname.as_str().fg(state.parser.colors().highlight))) refname.as_str().fg(state.parser.colors().highlight)))
.with_color(state.parser.colors().warning)) .with_color(state.parser.colors().warning))
.with_note(format!("Previous reference was overwritten")) .with_note("Previous reference was overwritten".to_string())
.finish()); .finish());
} }
Some(refname.as_str().to_string()) Some(refname.as_str().to_string())
@ -247,7 +247,7 @@ impl RegexRule for SectionRule {
"+".fg(state.parser.colors().info), "+".fg(state.parser.colors().info),
kind.as_str().fg(state.parser.colors().highlight))) kind.as_str().fg(state.parser.colors().highlight)))
.with_color(state.parser.colors().error)) .with_color(state.parser.colors().error))
.with_help(format!("Leave empty for a numbered listed section")) .with_help("Leave empty for a numbered listed section".to_string())
.finish()); .finish());
return result; return result;
} }
@ -321,7 +321,7 @@ impl RegexRule for SectionRule {
}), }),
); );
return result; result
} }
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
@ -331,7 +331,7 @@ impl RegexRule for SectionRule {
"push".to_string(), "push".to_string(),
lua.create_function( lua.create_function(
|_, (title, depth, kind, reference): (String, usize, Option<String>, Option<String>)| { |_, (title, depth, kind, reference): (String, usize, Option<String>, Option<String>)| {
let kind = match kind.as_ref().map(|s| s.as_str()).unwrap_or("") { let kind = match kind.as_deref().unwrap_or("") {
"*+" | "+*" => section_kind::NO_NUMBER | section_kind::NO_TOC, "*+" | "+*" => section_kind::NO_NUMBER | section_kind::NO_TOC,
"*" => section_kind::NO_NUMBER, "*" => section_kind::NO_NUMBER,
"+" => section_kind::NO_TOC, "+" => section_kind::NO_TOC,
@ -341,9 +341,7 @@ impl RegexRule for SectionRule {
to: Some("push".to_string()), to: Some("push".to_string()),
pos: 3, pos: 3,
name: Some("kind".to_string()), name: Some("kind".to_string()),
cause: Arc::new(mlua::Error::external(format!( cause: Arc::new(mlua::Error::external("Unknown section kind specified".to_string())),
"Unknown section kind specified"
))),
}) })
} }
}; };
@ -394,7 +392,7 @@ mod section_style {
use crate::impl_elementstyle; use crate::impl_elementstyle;
pub static STYLE_KEY: &'static str = "style.section"; pub static STYLE_KEY: &str = "style.section";
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
pub enum SectionLinkPos { pub enum SectionLinkPos {

View file

@ -99,13 +99,10 @@ impl RuleState for StyleState {
let paragraph = document.last_element::<Paragraph>().unwrap(); let paragraph = document.last_element::<Paragraph>().unwrap();
let paragraph_end = paragraph let paragraph_end = paragraph
.content .content
.last() .last().map(|last| (
.and_then(|last| {
Some((
last.location().source(), last.location().source(),
last.location().end() - 1..last.location().end(), last.location().end() - 1..last.location().end(),
)) ))
})
.unwrap(); .unwrap();
reports.push( reports.push(
@ -123,7 +120,7 @@ impl RuleState for StyleState {
.with_label( .with_label(
Label::new(paragraph_end) Label::new(paragraph_end)
.with_order(1) .with_order(1)
.with_message(format!("Paragraph ends here")) .with_message("Paragraph ends here".to_string())
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_note("Styles cannot span multiple documents (i.e @import)") .with_note("Styles cannot span multiple documents (i.e @import)")
@ -131,7 +128,7 @@ impl RuleState for StyleState {
); );
}); });
return reports; reports
} }
} }
@ -157,7 +154,7 @@ impl StyleRule {
} }
} }
static STATE_NAME: &'static str = "elements.style"; static STATE_NAME: &str = "elements.style";
impl RegexRule for StyleRule { impl RegexRule for StyleRule {
fn name(&self) -> &'static str { "Style" } fn name(&self) -> &'static str { "Style" }
@ -199,14 +196,14 @@ impl RegexRule for StyleRule {
Box::new(Style::new( Box::new(Style::new(
token.clone(), token.clone(),
index, index,
!style_state.toggled[index].is_some(), style_state.toggled[index].is_none(),
)), )),
); );
} else { } else {
panic!("Invalid state at `{STATE_NAME}`"); panic!("Invalid state at `{STATE_NAME}`");
} }
return vec![]; vec![]
} }
fn register_bindings<'lua>(&self, lua: &'lua mlua::Lua) -> Vec<(String, Function<'lua>)> { fn register_bindings<'lua>(&self, lua: &'lua mlua::Lua) -> Vec<(String, Function<'lua>)> {
@ -225,9 +222,7 @@ impl RegexRule for StyleRule {
to: Some("toggle".to_string()), to: Some("toggle".to_string()),
pos: 1, pos: 1,
name: Some("style".to_string()), name: Some("style".to_string()),
cause: Arc::new(mlua::Error::external(format!( cause: Arc::new(mlua::Error::external("Unknown style specified".to_string())),
"Unknown style specified"
))),
}) })
} }
}; };
@ -260,7 +255,7 @@ impl RegexRule for StyleRule {
Box::new(Style::new( Box::new(Style::new(
ctx.location.clone(), ctx.location.clone(),
kind, kind,
!style_state.toggled[kind].is_some(), style_state.toggled[kind].is_none(),
)), )),
); );
} else { } else {

View file

@ -114,10 +114,7 @@ impl FormattedTex {
} }
let mut result = String::new(); let mut result = String::new();
match process.stdout.unwrap().read_to_string(&mut result) { if let Err(e) = process.stdout.unwrap().read_to_string(&mut result) { panic!("Unable to read `latex2svg` stdout: {}", e) }
Err(e) => panic!("Unable to read `latex2svg` stdout: {}", e),
Ok(_) => {}
}
println!("Done!"); println!("Done!");
Ok(result) Ok(result)
@ -410,16 +407,14 @@ impl RegexRule for TexRule {
.get("caption", |_, value| -> Result<String, ()> { .get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok() .ok().map(|(_, value)| value);
.and_then(|(_, value)| Some(value));
// Environ // Environ
let tex_env = properties let tex_env = properties
.get("env", |_, value| -> Result<String, ()> { .get("env", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok() .ok().map(|(_, value)| value)
.and_then(|(_, value)| Some(value))
.unwrap(); .unwrap();
state.push( state.push(

View file

@ -26,8 +26,8 @@ pub struct Text {
impl Text { impl Text {
pub fn new(location: Token, content: String) -> Text { pub fn new(location: Token, content: String) -> Text {
Text { Text {
location: location, location,
content: content, content,
} }
} }
} }

View file

@ -67,7 +67,7 @@ impl VariableRule {
Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))), Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))),
Err(e) => Err(format!("Unable to canonicalize path `{}`: {}", Err(e) => Err(format!("Unable to canonicalize path `{}`: {}",
value.fg(colors.highlight), value.fg(colors.highlight),
e.to_string())) e))
} }
} }
_ => panic!("Unhandled variable kind"), _ => panic!("Unhandled variable kind"),
@ -83,7 +83,7 @@ impl VariableRule {
if name.contains("%") { if name.contains("%") {
return Err(format!("Name cannot contain '{}'", "%".fg(colors.info))); return Err(format!("Name cannot contain '{}'", "%".fg(colors.info)));
} }
return Ok(name); Ok(name)
} }
pub fn validate_value(original_value: &str) -> Result<String, String> { pub fn validate_value(original_value: &str) -> Result<String, String> {
@ -122,11 +122,11 @@ impl RegexRule for VariableRule {
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn on_regex_match<'a>( fn on_regex_match(
&self, &self,
_: usize, _: usize,
state: &ParserState, state: &ParserState,
document: &'a dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: regex::Captures, matches: regex::Captures,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
@ -180,7 +180,7 @@ impl RegexRule for VariableRule {
}; };
let var_name = match matches.get(2) { let var_name = match matches.get(2) {
Some(name) => match VariableRule::validate_name(&state.parser.colors(), name.as_str()) { Some(name) => match VariableRule::validate_name(state.parser.colors(), name.as_str()) {
Ok(var_name) => var_name, Ok(var_name) => var_name,
Err(msg) => { Err(msg) => {
result.push( result.push(
@ -228,7 +228,7 @@ impl RegexRule for VariableRule {
}; };
match self.make_variable( match self.make_variable(
&state.parser.colors(), state.parser.colors(),
token.clone(), token.clone(),
var_kind, var_kind,
var_name.to_string(), var_name.to_string(),
@ -256,7 +256,7 @@ impl RegexRule for VariableRule {
} }
} }
return result; result
} }
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
@ -335,7 +335,7 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Empty variable name") .with_message("Empty variable name")
.with_label( .with_label(
Label::new((token.source(), matches.get(0).unwrap().range())) Label::new((token.source(), matches.get(0).unwrap().range()))
.with_message(format!("Missing variable name for substitution")) .with_message("Missing variable name for substitution".to_string())
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.finish(), .finish(),
@ -350,7 +350,7 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Invalid variable name") .with_message("Invalid variable name")
.with_label( .with_label(
Label::new((token.source(), name.range())) Label::new((token.source(), name.range()))
.with_message(format!("Variable names contains leading spaces")) .with_message("Variable names contains leading spaces".to_string())
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_help("Remove leading spaces") .with_help("Remove leading spaces")
@ -366,9 +366,7 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Invalid variable name") .with_message("Invalid variable name")
.with_label( .with_label(
Label::new((token.source(), name.range())) Label::new((token.source(), name.range()))
.with_message(format!( .with_message("Variable names contains trailing spaces".to_string())
"Variable names contains trailing spaces"
))
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_help("Remove trailing spaces") .with_help("Remove trailing spaces")
@ -378,23 +376,20 @@ impl RegexRule for VariableSubstitutionRule {
return result; return result;
} }
// Invalid name // Invalid name
match VariableRule::validate_name(&state.parser.colors(), name.as_str()) { if let Err(msg) = VariableRule::validate_name(state.parser.colors(), name.as_str()) {
Err(msg) => { result.push(
result.push( Report::build(ReportKind::Error, token.source(), name.start())
Report::build(ReportKind::Error, token.source(), name.start()) .with_message("Invalid variable name")
.with_message("Invalid variable name") .with_label(
.with_label( Label::new((token.source(), name.range()))
Label::new((token.source(), name.range())) .with_message(msg)
.with_message(msg) .with_color(state.parser.colors().error),
.with_color(state.parser.colors().error), )
) .finish(),
.finish(), );
);
return result; return result;
} }
_ => {}
}
// Get variable // Get variable
match document.get_variable(name.as_str()) { match document.get_variable(name.as_str()) {
@ -422,6 +417,6 @@ impl RegexRule for VariableSubstitutionRule {
variable.parse(state, token, document); variable.parse(state, token, document);
return result; result
} }
} }

View file

@ -15,7 +15,7 @@ pub struct KernelContext<'a, 'b, 'c> {
} }
thread_local! { thread_local! {
pub static CTX: RefCell<Option<KernelContext<'static, 'static, 'static>>> = RefCell::new(None); pub static CTX: RefCell<Option<KernelContext<'static, 'static, 'static>>> = const { RefCell::new(None) };
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -249,7 +249,7 @@ fn main() -> ExitCode {
} }
}; };
let nav = navigation.compile(Target::HTML, &doc); let nav = navigation.compile(Target::HTML, doc);
let file = std::fs::File::create(output.clone() + "/" + out_path.as_str()).unwrap(); let file = std::fs::File::create(output.clone() + "/" + out_path.as_str()).unwrap();
let mut writer = BufWriter::new(file); let mut writer = BufWriter::new(file);
@ -285,5 +285,5 @@ fn main() -> ExitCode {
} }
} }
return ExitCode::SUCCESS; ExitCode::SUCCESS
} }

View file

@ -45,8 +45,7 @@ pub struct CustomStyleHolder {
impl CustomStyleHolder { impl CustomStyleHolder {
pub fn get(&self, style_name: &str) -> Option<Rc<dyn CustomStyle>> { pub fn get(&self, style_name: &str) -> Option<Rc<dyn CustomStyle>> {
self.custom_styles self.custom_styles
.get(style_name) .get(style_name).cloned()
.map(|style| style.clone())
} }
pub fn insert(&mut self, style: Rc<dyn CustomStyle>) { pub fn insert(&mut self, style: Rc<dyn CustomStyle>) {

View file

@ -120,7 +120,7 @@ impl Parser for LangParser {
))), ))),
); );
return (Box::new(doc), state); (Box::new(doc), state)
} }
fn parse_into<'p, 'a, 'doc>( fn parse_into<'p, 'a, 'doc>(
@ -164,7 +164,7 @@ impl Parser for LangParser {
} }
} }
return state; state
// State // State
//self.handle_reports(source.clone(), //self.handle_reports(source.clone(),
// self.state_mut().on_scope_end(&self, &document, super::state::Scope::DOCUMENT)); // self.state_mut().on_scope_end(&self, &document, super::state::Scope::DOCUMENT));

View file

@ -36,7 +36,7 @@ pub struct LayoutHolder {
impl LayoutHolder { impl LayoutHolder {
pub fn get(&self, layout_name: &str) -> Option<Rc<dyn LayoutType>> { pub fn get(&self, layout_name: &str) -> Option<Rc<dyn LayoutType>> {
self.layouts.get(layout_name).map(|layout| layout.clone()) self.layouts.get(layout_name).cloned()
} }
pub fn insert(&mut self, layout: Rc<dyn LayoutType>) { pub fn insert(&mut self, layout: Rc<dyn LayoutType>) {

View file

@ -89,8 +89,8 @@ impl SharedState {
// Default styles & layouts // Default styles & layouts
parser.rules().iter().for_each(|rule| { parser.rules().iter().for_each(|rule| {
rule.register_styles(&mut *s.styles.borrow_mut()); rule.register_styles(&mut s.styles.borrow_mut());
rule.register_layouts(&mut *s.layouts.borrow_mut()); rule.register_layouts(&mut s.layouts.borrow_mut());
}); });
s s
@ -198,7 +198,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
let mut escaped = false; let mut escaped = false;
'inner: loop { 'inner: loop {
let g = graphemes.next_back(); let g = graphemes.next_back();
if !g.is_some() || g.unwrap() != "\\" { if g.is_none() || g.unwrap() != "\\" {
break 'inner; break 'inner;
} }
@ -236,10 +236,10 @@ impl<'a, 'b> ParserState<'a, 'b> {
return (cursor.at(content.len()), None); return (cursor.at(content.len()), None);
} }
return ( (
cursor.at(next_pos), cursor.at(next_pos),
Some((winner, matches_borrow[winner].1.take().unwrap())), Some((winner, matches_borrow[winner].1.take().unwrap())),
); )
} }
/// Add an [`Element`] to the [`Document`] /// Add an [`Element`] to the [`Document`]
@ -262,7 +262,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
if doc.last_element::<Paragraph>().is_some_and(|_| true) { if doc.last_element::<Paragraph>().is_some_and(|_| true) {
self.parser self.parser
.handle_reports(self.shared.rule_state.borrow_mut().on_scope_end( .handle_reports(self.shared.rule_state.borrow_mut().on_scope_end(
&self, self,
doc, doc,
super::state::Scope::PARAGRAPH, super::state::Scope::PARAGRAPH,
)); ));
@ -368,10 +368,10 @@ pub trait Parser {
/// ///
/// This method must not be called if a [`ParserState`] for this parser exists. /// This method must not be called if a [`ParserState`] for this parser exists.
fn add_rule(&mut self, rule: Box<dyn Rule>) -> Result<(), String> { fn add_rule(&mut self, rule: Box<dyn Rule>) -> Result<(), String> {
if let Some(_) = self if self
.rules() .rules()
.iter() .iter()
.find(|other_rule| other_rule.name() == rule.name()) .any(|other_rule| other_rule.name() == rule.name())
{ {
return Err(format!( return Err(format!(
"Attempted to introduce duplicate rule: `{}`", "Attempted to introduce duplicate rule: `{}`",
@ -391,14 +391,11 @@ pub trait Parser {
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new(); let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
fn recurse_source(sources: &mut HashSet<Rc<dyn Source>>, source: Rc<dyn Source>) { fn recurse_source(sources: &mut HashSet<Rc<dyn Source>>, source: Rc<dyn Source>) {
sources.insert(source.clone()); sources.insert(source.clone());
match source.location() { if let Some(parent) = source.location() {
Some(parent) => { let parent_source = parent.source();
let parent_source = parent.source(); if sources.get(&parent_source).is_none() {
if sources.get(&parent_source).is_none() { recurse_source(sources, parent_source);
recurse_source(sources, parent_source);
}
} }
None => {}
} }
} }
@ -423,10 +420,8 @@ pub trait Parser {
if let Some(_s) = source.downcast_ref::<VirtualSource>() { if let Some(_s) = source.downcast_ref::<VirtualSource>() {
let start = location.start() let start = location.start()
+ (location.source().content().as_bytes()[location.start()] + if location.source().content().as_bytes()[location.start()]
== '\n' as u8) == b'\n' { 1 } else { 0 };
.then_some(1)
.unwrap_or(0);
report.labels.push( report.labels.push(
Label::new((location.source(), start..location.end())) Label::new((location.source(), start..location.end()))
.with_message("In evaluation of") .with_message("In evaluation of")

View file

@ -53,7 +53,7 @@ pub fn get_rule_registry() -> Vec<Box<dyn Rule>> {
} }
} }
let mut map = make_rules(); let mut map = make_rules();
let mut sorted_keys = map.iter().map(|(key, _)| *key).collect::<Vec<_>>(); let mut sorted_keys = map.keys().copied().collect::<Vec<_>>();
sorted_keys.sort_by(|l, r| cmp(&map, l, r)); sorted_keys.sort_by(|l, r| cmp(&map, l, r));
let mut owned = Vec::with_capacity(sorted_keys.len()); let mut owned = Vec::with_capacity(sorted_keys.len());
@ -136,18 +136,18 @@ impl<T: RegexRule + 'static> Rule for T {
self.regexes().iter().enumerate().for_each(|(id, re)| { self.regexes().iter().enumerate().for_each(|(id, re)| {
if let Some(m) = re.find_at(content.as_str(), cursor.pos) { if let Some(m) = re.find_at(content.as_str(), cursor.pos) {
found = found found = found
.and_then(|(f_pos, f_id)| { .map(|(f_pos, f_id)| {
if f_pos > m.start() { if f_pos > m.start() {
Some((m.start(), id)) (m.start(), id)
} else { } else {
Some((f_pos, f_id)) (f_pos, f_id)
} }
}) })
.or(Some((m.start(), id))); .or(Some((m.start(), id)));
} }
}); });
return found.map(|(pos, id)| (pos, Box::new(id) as Box<dyn Any>)); found.map(|(pos, id)| (pos, Box::new(id) as Box<dyn Any>))
} }
fn on_match<'a>( fn on_match<'a>(

View file

@ -24,7 +24,6 @@ impl core::fmt::Display for dyn Source {
} }
impl core::fmt::Debug for dyn Source { impl core::fmt::Debug for dyn Source {
// TODO
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Source{{{}}}", self.name()) write!(f, "Source{{{}}}", self.name())
} }
@ -55,10 +54,10 @@ impl SourceFile {
pub fn new(path: String, location: Option<Token>) -> Result<Self, String> { pub fn new(path: String, location: Option<Token>) -> Result<Self, String> {
match fs::read_to_string(&path) { match fs::read_to_string(&path) {
Err(_) => { Err(_) => {
return Err(String::from(format!( Err(format!(
"Unable to read file content: `{}`", "Unable to read file content: `{}`",
path path
))) ))
} }
Ok(content) => Ok(Self { Ok(content) => Ok(Self {
location, location,
@ -70,9 +69,9 @@ impl SourceFile {
pub fn with_content(path: String, content: String, location: Option<Token>) -> Self { pub fn with_content(path: String, content: String, location: Option<Token>) -> Self {
Self { Self {
location: location, location,
path: path, path,
content: content, content,
} }
} }
} }
@ -162,7 +161,7 @@ impl Token {
} }
pub fn source(&self) -> Rc<dyn Source> { pub fn source(&self) -> Rc<dyn Source> {
return self.source.clone(); self.source.clone()
} }
/// Construct Token from a range /// Construct Token from a range
@ -176,10 +175,10 @@ impl Token {
} }
pub fn start(&self) -> usize { pub fn start(&self) -> usize {
return self.range.start; self.range.start
} }
pub fn end(&self) -> usize { pub fn end(&self) -> usize {
return self.range.end; self.range.end
} }
} }

View file

@ -64,7 +64,7 @@ impl RuleStateHolder {
} }
pub fn get(&self, state_name: &str) -> Option<Rc<RefCell<dyn RuleState>>> { pub fn get(&self, state_name: &str) -> Option<Rc<RefCell<dyn RuleState>>> {
self.states.get(state_name).map(|state| state.clone()) self.states.get(state_name).cloned()
} }
pub fn on_scope_end( pub fn on_scope_end(
@ -88,6 +88,6 @@ impl RuleStateHolder {
} }
}); });
return reports; reports
} }
} }

View file

@ -38,7 +38,7 @@ impl StyleHolder {
/// NOTE: Will panic if a style is not defined for a given element /// NOTE: Will panic if a style is not defined for a given element
/// If you need to process user input, use [`is_registered`] /// If you need to process user input, use [`is_registered`]
pub fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> { pub fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> {
self.styles.get(style_key).map(|rc| rc.clone()).unwrap() self.styles.get(style_key).cloned().unwrap()
} }
/// Sets the [`style`] /// Sets the [`style`]
@ -50,17 +50,17 @@ impl StyleHolder {
#[macro_export] #[macro_export]
macro_rules! impl_elementstyle { macro_rules! impl_elementstyle {
($t:ty, $key:expr) => { ($t:ty, $key:expr) => {
impl crate::parser::style::ElementStyle for $t { impl $crate::parser::style::ElementStyle for $t {
fn key(&self) -> &'static str { $key } fn key(&self) -> &'static str { $key }
fn from_json( fn from_json(
&self, &self,
json: &str, json: &str,
) -> Result<std::rc::Rc<dyn crate::parser::style::ElementStyle>, String> { ) -> Result<std::rc::Rc<dyn $crate::parser::style::ElementStyle>, String> {
serde_json::from_str::<$t>(json) serde_json::from_str::<$t>(json)
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
.map(|obj| { .map(|obj| {
std::rc::Rc::new(obj) as std::rc::Rc<dyn crate::parser::style::ElementStyle> std::rc::Rc::new(obj) as std::rc::Rc<dyn $crate::parser::style::ElementStyle>
}) })
} }
@ -68,9 +68,9 @@ macro_rules! impl_elementstyle {
&self, &self,
lua: &mlua::Lua, lua: &mlua::Lua,
value: mlua::Value, value: mlua::Value,
) -> Result<std::rc::Rc<dyn crate::parser::style::ElementStyle>, mlua::Error> { ) -> Result<std::rc::Rc<dyn $crate::parser::style::ElementStyle>, mlua::Error> {
mlua::LuaSerdeExt::from_value::<$t>(lua, value).map(|obj| { mlua::LuaSerdeExt::from_value::<$t>(lua, value).map(|obj| {
std::rc::Rc::new(obj) as std::rc::Rc<dyn crate::parser::style::ElementStyle> std::rc::Rc::new(obj) as std::rc::Rc<dyn $crate::parser::style::ElementStyle>
}) })
} }
} }

View file

@ -36,7 +36,7 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
.last_element::<Paragraph>() .last_element::<Paragraph>()
.and_then(|par| { .and_then(|par| {
par.find_back(|e| e.kind() != ElemKind::Invisible) par.find_back(|e| e.kind() != ElemKind::Invisible)
.and_then(|e| Some(e.kind() == ElemKind::Inline)) .map(|e| e.kind() == ElemKind::Inline)
}) })
.unwrap_or(false) .unwrap_or(false)
{ {
@ -79,12 +79,12 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
} }
} }
return (out + g, Some(g)); (out + g, Some(g))
}) })
.0 .0
.to_string(); .to_string();
return processed; processed
} }
/// Processed a string and escapes a single token out of it /// Processed a string and escapes a single token out of it
@ -111,7 +111,7 @@ pub fn process_escaped<S: AsRef<str>>(escape: char, token: &'static str, content
escaped += 1; escaped += 1;
} else if escaped % 2 == 1 && token_it.peek().map_or(false, |p| *p == c) { } else if escaped % 2 == 1 && token_it.peek().map_or(false, |p| *p == c) {
let _ = token_it.next(); let _ = token_it.next();
if token_it.peek() == None { if token_it.peek().is_none() {
(0..(escaped / 2)).for_each(|_| processed.push(escape)); (0..(escaped / 2)).for_each(|_| processed.push(escape));
escaped = 0; escaped = 0;
token_it = token.chars().peekable(); token_it = token.chars().peekable();
@ -333,9 +333,8 @@ impl PropertyParser {
escaped = 0; escaped = 0;
in_name = true; in_name = true;
if let Err(e) = try_insert(&name, &value) { try_insert(&name, &value)?;
return Err(e);
}
name.clear(); name.clear();
value.clear(); value.clear();
} else { } else {
@ -361,9 +360,7 @@ impl PropertyParser {
return Err("Expected non empty property list.".to_string()); return Err("Expected non empty property list.".to_string());
} }
if let Err(e) = try_insert(&name, &value) { try_insert(&name, &value)?;
return Err(e);
}
if let Err(e) = self.properties.iter().try_for_each(|(key, prop)| { if let Err(e) = self.properties.iter().try_for_each(|(key, prop)| {
if !properties.properties.contains_key(key) { if !properties.properties.contains_key(key) {