diff --git a/src/elements/blockquote.rs b/src/elements/blockquote.rs
index 364bfb3..bbfcee2 100644
--- a/src/elements/blockquote.rs
+++ b/src/elements/blockquote.rs
@@ -1,7 +1,6 @@
use core::fmt;
use std::any::Any;
use std::collections::HashMap;
-use std::ops::Range;
use std::rc::Rc;
use blockquote_style::AuthorPos::After;
diff --git a/src/elements/code.rs b/src/elements/code.rs
index cbb1230..5b656df 100644
--- a/src/elements/code.rs
+++ b/src/elements/code.rs
@@ -4,9 +4,6 @@ use std::rc::Rc;
use std::sync::Once;
use ariadne::Fmt;
-use ariadne::Label;
-use ariadne::Report;
-use ariadne::ReportKind;
use crypto::digest::Digest;
use crypto::sha2::Sha512;
use mlua::Function;
@@ -36,6 +33,8 @@ use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use crate::parser::util::{self};
use lazy_static::lazy_static;
+use crate::parser::reports::*;
+use crate::parser::reports::macros::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum CodeKind {
@@ -335,22 +334,21 @@ impl RegexRule for CodeRule {
document: &dyn Document,
token: Token,
matches: Captures,
- ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
+ ) -> Vec<Report> {
let mut reports = vec![];
let properties = match matches.get(1) {
None => match self.properties.default() {
Ok(properties) => properties,
Err(e) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid code")
- .with_label(
- Label::new((token.source().clone(), token.range.clone()))
- .with_message(format!("Code is missing properties: {e}"))
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Code Properties".into(),
+ span(
+ token.range.clone(),
+ format!("Code is missing properties: {e}")
+ )
);
return reports;
}
@@ -360,15 +358,14 @@ impl RegexRule for CodeRule {
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), props.start())
- .with_message("Invalid Code Properties")
- .with_label(
- Label::new((token.source().clone(), props.range()))
- .with_message(e)
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Code Properties".into(),
+ span(
+ props.range(),
+ e
+ )
);
return reports;
}
@@ -382,15 +379,14 @@ impl RegexRule for CodeRule {
Some(lang) => {
let code_lang = lang.as_str().trim_start().trim_end().to_string();
if code_lang.is_empty() {
- reports.push(
- Report::build(ReportKind::Error, token.source(), lang.start())
- .with_message("Missing Code Language")
- .with_label(
- Label::new((token.source().clone(), lang.range()))
- .with_message("No language specified")
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Missing Code Language".into(),
+ span(
+ lang.range(),
+ "No language specified".into()
+ )
);
return reports;
@@ -399,18 +395,17 @@ impl RegexRule for CodeRule {
.find_syntax_by_name(code_lang.as_str())
.is_none()
{
- reports.push(
- Report::build(ReportKind::Error, token.source(), lang.start())
- .with_message("Unknown Code Language")
- .with_label(
- Label::new((token.source().clone(), lang.range()))
- .with_message(format!(
- "Language `{}` cannot be found",
- code_lang.fg(state.parser.colors().info)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Unknown Code Language".into(),
+ span(
+ lang.range(),
+ format!(
+ "Language `{}` cannot be found",
+ code_lang.fg(state.parser.colors().info)
)
- .finish(),
+ )
);
return reports;
@@ -432,15 +427,14 @@ impl RegexRule for CodeRule {
}
if code_content.is_empty() {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Missing code content")
- .with_label(
- Label::new((token.source().clone(), token.range.clone()))
- .with_message("Code content cannot be empty")
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Empty Code Content".into(),
+ span(
+ token.range.clone(),
+ "Code content cannot be empty".into()
+ )
);
return reports;
}
@@ -464,34 +458,31 @@ impl RegexRule for CodeRule {
Err(e) => {
match e {
PropertyMapError::ParseError((prop, err)) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Code Property")
- .with_label(
- Label::new((token.source().clone(), token.start()+1..token.end()))
- .with_message(format!("Property `line_offset: {}` cannot be converted: {}",
- prop.fg(state.parser.colors().info),
- err.fg(state.parser.colors().error)))
- .with_color(state.parser.colors().warning))
- .finish());
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Code Property".into(),
+ span(
+ token.start()+1..token.end(),
+ format!("Property `line_offset: {}` cannot be converted: {}",
+ prop.fg(state.parser.colors().info),
+ err.fg(state.parser.colors().error))
+ )
+ );
return reports;
}
PropertyMapError::NotFoundError(err) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Code Property")
- .with_label(
- Label::new((
- token.source().clone(),
- token.start() + 1..token.end(),
- ))
- .with_message(format!(
- "Property `{}` doesn't exist",
- err.fg(state.parser.colors().info)
- ))
- .with_color(state.parser.colors().warning),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Code Property".into(),
+ span(
+ token.start()+1..token.end(),
+ format!(
+ "Property `{}` doesn't exist",
+ err.fg(state.parser.colors().info)
)
- .finish(),
+ )
);
return reports;
}
diff --git a/src/elements/comment.rs b/src/elements/comment.rs
index e063246..fc8f662 100644
--- a/src/elements/comment.rs
+++ b/src/elements/comment.rs
@@ -8,13 +8,12 @@ use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
use crate::parser::source::Token;
-use ariadne::Label;
-use ariadne::Report;
-use ariadne::ReportKind;
use regex::Captures;
use regex::Regex;
use std::ops::Range;
use std::rc::Rc;
+use crate::parser::reports::*;
+use crate::parser::reports::macros::*;
#[derive(Debug)]
pub struct Comment {
@@ -66,7 +65,7 @@ impl RegexRule for CommentRule {
document: &dyn Document,
token: Token,
matches: Captures,
- ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
+ ) -> Vec<Report> {
let mut reports = vec![];
let content = match matches.get(1) {
@@ -74,15 +73,14 @@ impl RegexRule for CommentRule {
Some(comment) => {
let trimmed = comment.as_str().trim_start().trim_end().to_string();
if trimmed.is_empty() {
- reports.push(
- Report::build(ReportKind::Warning, token.source(), comment.start())
- .with_message("Empty comment")
- .with_label(
- Label::new((token.source(), comment.range()))
- .with_message("Comment is empty")
- .with_color(state.parser.colors().warning),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Empty Comment".into(),
+ span(
+ comment.range(),
+ "Comment is empty".into()
+ )
);
}
diff --git a/src/elements/graphviz.rs b/src/elements/graphviz.rs
index c715dd7..b194641 100644
--- a/src/elements/graphviz.rs
+++ b/src/elements/graphviz.rs
@@ -11,9 +11,6 @@ use crate::parser::util::Property;
use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser;
use ariadne::Fmt;
-use ariadne::Label;
-use ariadne::Report;
-use ariadne::ReportKind;
use crypto::digest::Digest;
use crypto::sha2::Sha512;
use graphviz_rust::cmd::Format;
@@ -36,6 +33,8 @@ use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::util;
+use crate::parser::reports::*;
+use crate::parser::reports::macros::*;
#[derive(Debug)]
struct Graphviz {
@@ -204,25 +203,24 @@ impl RegexRule for GraphRule {
document: &dyn Document,
token: Token,
matches: Captures,
- ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
+ ) -> Vec<Report> {
let mut reports = vec![];
let graph_content = match matches.get(2) {
// Unterminated `[graph]`
None => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Unterminated Graph Code")
- .with_label(
- Label::new((token.source().clone(), token.range.clone()))
- .with_message(format!(
- "Missing terminating `{}` after first `{}`",
- "[/graph]".fg(state.parser.colors().info),
- "[graph]".fg(state.parser.colors().info)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Unterminamted Graph Code".into(),
+ span(
+ token.range.clone(),
+ format!(
+ "Missing terminating `{}` after first `{}`",
+ "[/graph]".fg(state.parser.colors().info),
+ "[graph]".fg(state.parser.colors().info)
)
- .finish(),
+ )
);
return reports;
}
@@ -230,19 +228,18 @@ impl RegexRule for GraphRule {
let processed = util::escape_text(
'\\',
"[/graph]",
- content.as_str().trim_start().trim_end(),
+ content.as_str(),
);
if processed.is_empty() {
- reports.push(
- Report::build(ReportKind::Error, token.source(), content.start())
- .with_message("Empty Graph Code")
- .with_label(
- Label::new((token.source().clone(), content.range()))
- .with_message("Graph code is empty")
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Empty Graph Code".into(),
+ span(
+ content.range(),
+ "Graph code is empty".into()
+ )
);
return reports;
}
@@ -255,15 +252,14 @@ impl RegexRule for GraphRule {
None => match self.properties.default() {
Ok(properties) => properties,
Err(e) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Graph")
- .with_label(
- Label::new((token.source().clone(), token.range.clone()))
- .with_message(format!("Graph is missing property: {e}"))
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Graph Properties".into(),
+ span(
+ token.range.clone(),
+ format!("Graph is missing property: {e}")
+ )
);
return reports;
}
@@ -273,15 +269,14 @@ impl RegexRule for GraphRule {
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) {
Err(e) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), props.start())
- .with_message("Invalid Graph Properties")
- .with_label(
- Label::new((token.source().clone(), props.range()))
- .with_message(e)
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Graph Properties".into(),
+ span(
+ props.range(),
+ e
+ )
);
return reports;
}
@@ -297,35 +292,30 @@ impl RegexRule for GraphRule {
Ok((_prop, kind)) => kind,
Err(e) => match e {
PropertyMapError::ParseError((prop, err)) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Graph Property")
- .with_label(
- Label::new((token.source().clone(), token.range.clone()))
- .with_message(format!(
- "Property `layout: {}` cannot be converted: {}",
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Graph Property".into(),
+ span(
+ token.range.clone(),
+ format!(
+ "Property `{}` cannot be converted: {}",
prop.fg(state.parser.colors().info),
err.fg(state.parser.colors().error)
- ))
- .with_color(state.parser.colors().warning),
- )
- .finish(),
+ )
+ )
);
return reports;
}
PropertyMapError::NotFoundError(err) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Graph Property")
- .with_label(
- Label::new((
- token.source().clone(),
- token.start() + 1..token.end(),
- ))
- .with_message(err)
- .with_color(state.parser.colors().warning),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Graph Property".into(),
+ span(
+ token.start() + 1..token.end(),
+ err
+ )
);
return reports;
}
@@ -340,21 +330,17 @@ impl RegexRule for GraphRule {
Ok((_, kind)) => kind,
Err(e) => match e {
PropertyMapError::NotFoundError(err) => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid Graph Property")
- .with_label(
- Label::new((
- token.source().clone(),
- token.start() + 1..token.end(),
- ))
- .with_message(format!(
- "Property `{}` is missing",
- err.fg(state.parser.colors().info)
- ))
- .with_color(state.parser.colors().warning),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Graph Property".into(),
+ span(
+ token.start() + 1..token.end(),
+ format!(
+ "Property `{}` is missing",
+ err.fg(state.parser.colors().info)
)
- .finish(),
+ )
);
return reports;
}
diff --git a/src/elements/import.rs b/src/elements/import.rs
index e469f2a..e417cc7 100644
--- a/src/elements/import.rs
+++ b/src/elements/import.rs
@@ -9,13 +9,12 @@ use crate::parser::source::Source;
use crate::parser::source::SourceFile;
use crate::parser::source::Token;
use ariadne::Fmt;
-use ariadne::Label;
-use ariadne::Report;
-use ariadne::ReportKind;
use regex::Captures;
use regex::Regex;
use std::ops::Range;
use std::rc::Rc;
+use crate::parser::reports::*;
+use crate::parser::reports::macros::*;
use super::paragraph::Paragraph;
@@ -57,65 +56,62 @@ impl RegexRule for ImportRule {
document: &'a dyn Document<'a>,
token: Token,
matches: Captures,
- ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
- let mut result = vec![];
+ ) -> Vec<Report> {
+ let mut reports = vec![];
// Path
let import_file = match matches.get(2) {
Some(name) => match ImportRule::validate_name(state.parser.colors(), name.as_str()) {
Err(msg) => {
- result.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Invalid name for import")
- .with_label(
- Label::new((token.source(), name.range()))
- .with_message(format!(
- "Import name `{}` is invalid. {msg}",
- name.as_str().fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Import Name".into(),
+ span(
+ name.range(),
+ format!(
+ "Import name `{}` is invalid. {msg}",
+ name.as_str().fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
- return result;
+ return reports;
}
Ok(filename) => {
let meta = match std::fs::metadata(filename.as_str()) {
Err(_) => {
- result.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Invalid import path")
- .with_label(
- Label::new((token.source(), name.range()))
- .with_message(format!(
- "Unable to access file `{}`",
- filename.fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Import Path".into(),
+ span(
+ name.range(),
+ format!(
+ "Unable to access file `{}`",
+ filename.fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
- return result;
+ return reports;
}
Ok(meta) => meta,
};
if !meta.is_file() {
- result.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Invalid import path")
- .with_label(
- Label::new((token.source(), name.range()))
- .with_message(format!(
- "Path `{}` is not a file!",
- filename.fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Import Path".into(),
+ span(
+ name.range(),
+ format!(
+ "Path `{}` is not a file!",
+ filename.fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
- return result;
+ return reports;
}
filename
@@ -130,21 +126,20 @@ impl RegexRule for ImportRule {
{
Ok(as_name) => as_name,
Err(msg) => {
- result.push(
- Report::build(ReportKind::Error, token.source(), as_name.start())
- .with_message("Invalid name for import as")
- .with_label(
- Label::new((token.source(), as_name.range()))
- .with_message(format!(
- "Canot import `{import_file}` as `{}`. {msg}",
- as_name.as_str().fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Import As".into(),
+ span(
+ as_name.range(),
+ format!(
+ "Canot import `{import_file}` as `{}`. {msg}",
+ as_name.as_str().fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
- return result;
+ return reports;
}
},
_ => "".to_string(),
@@ -153,17 +148,16 @@ impl RegexRule for ImportRule {
let import = match SourceFile::new(import_file, Some(token.clone())) {
Ok(import) => Rc::new(import),
Err(path) => {
- result.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Unable to read file content")
- .with_label(
- Label::new((token.source(), token.range))
- .with_message(format!("Failed to read content from path `{path}`"))
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Import File".into(),
+ span(
+ token.range.clone(),
+ format!("Failed to read content from path `{path}`")
+ )
);
- return result;
+ return reports;
}
};
@@ -212,6 +206,6 @@ impl RegexRule for ImportRule {
sems.add(path, tokens.import_path);
}
- result
+ reports
}
}
diff --git a/src/elements/layout.rs b/src/elements/layout.rs
index d4cc825..a2a352c 100644
--- a/src/elements/layout.rs
+++ b/src/elements/layout.rs
@@ -341,10 +341,10 @@ impl LayoutRule {
token: &Token,
layout_type: Rc<dyn LayoutType>,
properties: Option<Match>,
- ) -> Option<Box<dyn Any>> {
+ ) -> Result<Option<Box<dyn Any>>, ()> {
match properties {
None => match layout_type.parse_properties("") {
- Ok(props) => props,
+ Ok(props) => Ok(props),
Err(err) => {
report_err!(
&mut reports,
@@ -352,28 +352,28 @@ impl LayoutRule {
"Invalid Layout Properties".into(),
span(
token.range.clone(),
- format!("Layout is missing required property: {eee}")
+ format!("Layout is missing required property: {err}")
)
);
- None
+ Err(())
}
},
Some(props) => {
- let trimmed = props.as_str().trim_start().trim_end();
- let content = escape_text('\\', "]", trimmed);
+ let content = escape_text('\\', "]", props.as_str());
match layout_type.parse_properties(content.as_str()) {
Ok(props) => Ok(props),
Err(err) => {
- Err(
- Report::build(ReportKind::Error, token.source(), props.start())
- .with_message("Unable to parse layout properties")
- .with_label(
- Label::new((token.source(), props.range()))
- .with_message(err)
- .with_color(colors.error),
- )
- .finish(),
- )
+
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Layout Properties".into(),
+ span(
+ props.range(),
+ err
+ )
+ );
+ Err(())
}
}
}
@@ -399,7 +399,7 @@ impl RegexRule for LayoutRule {
document: &dyn Document,
token: Token,
matches: Captures,
- ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
+ ) -> Vec<Report> {
let mut reports = vec![];
let rule_state = LayoutRule::initialize_state(state);
@@ -409,18 +409,17 @@ impl RegexRule for LayoutRule {
{
match matches.get(2) {
None => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Missing Layout Name")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message(format!(
- "Missing layout name after `{}`",
- "#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Missing Layout Name".into(),
+ span(
+ token.range.clone(),
+ format!(
+ "Missing layout name after `{}`",
+ "#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
return reports;
}
@@ -429,35 +428,33 @@ impl RegexRule for LayoutRule {
if name.as_str().is_empty() || trimmed.is_empty()
// Empty name
{
- reports.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Empty Layout Name")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message(format!(
- "Empty layout name after `{}`",
- "#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Empty Layout Name".into(),
+ span(
+ name.range(),
+ format!(
+ "Empty layout name after `{}`",
+ "#+BEGIN_LAYOUT".fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
return reports;
} else if !name.as_str().chars().next().unwrap().is_whitespace()
// Missing space
{
- reports.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Invalid Layout Name")
- .with_label(
- Label::new((token.source(), name.range()))
- .with_message(format!(
- "Missing a space before layout name `{}`",
- name.as_str().fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid Layout Name".into(),
+ span(
+ name.range(),
+ format!(
+ "Missing a space before layout name `{}`",
+ name.as_str().fg(state.parser.colors().highlight)
)
- .finish(),
+ )
);
return reports;
}
@@ -465,18 +462,18 @@ impl RegexRule for LayoutRule {
// Get layout
let layout_type = match state.shared.layouts.borrow().get(trimmed) {
None => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), name.start())
- .with_message("Unknown Layout")
- .with_label(
- Label::new((token.source(), name.range()))
- .with_message(format!(
- "Cannot find layout `{}`",
- trimmed.fg(state.parser.colors().highlight)
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Unknown Layout".into(),
+ span(
+ name.range(),
+ format!(
+ "Cannot find layout `{}`",
+ trimmed.fg(state.parser.colors().highlight)
)
- .finish(),
+ )
+
);
return reports;
}
@@ -485,16 +482,13 @@ impl RegexRule for LayoutRule {
// Parse properties
let properties = match LayoutRule::parse_properties(
- state.parser.colors(),
+ &mut reports,
&token,
layout_type.clone(),
matches.get(1),
) {
Ok(props) => props,
- Err(rep) => {
- reports.push(rep);
- return reports;
- }
+ Err(()) => return reports,
};
state.push(
@@ -548,15 +542,14 @@ impl RegexRule for LayoutRule {
let (tokens, layout_type) = match layout_state.stack.last_mut() {
None => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid #+LAYOUT_NEXT")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message("No active layout found".to_string())
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid #+LAYOUT_NEXT".into(),
+ span(
+ token.range.clone(),
+ "No active layout found".into()
+ )
);
return reports;
}
@@ -566,35 +559,31 @@ impl RegexRule for LayoutRule {
if layout_type.expects().end < tokens.len()
// Too many blocks
{
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Unexpected #+LAYOUT_NEXT")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message(format!(
- "Layout expects a maximum of {} blocks, currently at {}",
- layout_type.expects().end.fg(state.parser.colors().info),
- tokens.len().fg(state.parser.colors().info),
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Unexpected #+LAYOUT_NEXT".into(),
+ span(
+ token.range.clone(),
+ format!(
+ "Layout expects a maximum of {} blocks, currently at {}",
+ layout_type.expects().end.fg(state.parser.colors().info),
+ tokens.len().fg(state.parser.colors().info),
)
- .finish(),
+ )
);
return reports;
}
// Parse properties
let properties = match LayoutRule::parse_properties(
- state.parser.colors(),
+ &mut reports,
&token,
layout_type.clone(),
matches.get(1),
) {
Ok(props) => props,
- Err(rep) => {
- reports.push(rep);
- return reports;
- }
+ Err(rep) => return reports,
};
if let Some((sems, tokens)) =
@@ -630,15 +619,14 @@ impl RegexRule for LayoutRule {
let (tokens, layout_type) = match layout_state.stack.last_mut() {
None => {
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Invalid #+LAYOUT_END")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message("No active layout found".to_string())
- .with_color(state.parser.colors().error),
- )
- .finish(),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Invalid #+LAYOUT_NEXT".into(),
+ span(
+ token.range.clone(),
+ "No active layout found".into()
+ )
);
return reports;
}
@@ -648,35 +636,31 @@ impl RegexRule for LayoutRule {
if layout_type.expects().start > tokens.len()
// Not enough blocks
{
- reports.push(
- Report::build(ReportKind::Error, token.source(), token.start())
- .with_message("Unexpected #+LAYOUT_END")
- .with_label(
- Label::new((token.source(), token.range.clone()))
- .with_message(format!(
- "Layout expects a minimum of {} blocks, currently at {}",
- layout_type.expects().start.fg(state.parser.colors().info),
- tokens.len().fg(state.parser.colors().info),
- ))
- .with_color(state.parser.colors().error),
+ report_err!(
+ &mut reports,
+ token.source(),
+ "Unexpected #+LAYOUT_NEXT".into(),
+ span(
+ token.range.clone(),
+ format!(
+ "Layout expects a minimum of {} blocks, currently at {}",
+ layout_type.expects().start.fg(state.parser.colors().info),
+ tokens.len().fg(state.parser.colors().info),
)
- .finish(),
+ )
);
return reports;
}
// Parse properties
let properties = match LayoutRule::parse_properties(
- state.parser.colors(),
+ &mut reports,
&token,
layout_type.clone(),
matches.get(1),
) {
Ok(props) => props,
- Err(rep) => {
- reports.push(rep);
- return reports;
- }
+ Err(rep) => return reports,
};
let layout_type = layout_type.clone();
diff --git a/src/elements/list.rs b/src/elements/list.rs
index 045a591..480c840 100644
--- a/src/elements/list.rs
+++ b/src/elements/list.rs
@@ -1,7 +1,6 @@
use std::any::Any;
use std::cell::Ref;
use std::collections::HashMap;
-use std::ops::Range;
use std::rc::Rc;
use crate::compiler::compiler::Compiler;
@@ -429,6 +428,7 @@ impl Rule for ListRule {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::parser::source::Source;
use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text;
use crate::parser::langparser::LangParser;
diff --git a/src/elements/paragraph.rs b/src/elements/paragraph.rs
index de34324..f31979a 100644
--- a/src/elements/paragraph.rs
+++ b/src/elements/paragraph.rs
@@ -1,8 +1,5 @@
use std::any::Any;
-use std::ops::Range;
-use std::rc::Rc;
-use ariadne::Report;
use regex::Regex;
use crate::compiler::compiler::Compiler;
@@ -17,6 +14,7 @@ use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
use crate::parser::source::Source;
use crate::parser::source::Token;
+use crate::parser::reports::*;
// TODO: Full refactor
// Problem is that document parsed from other sources i.e by variables
@@ -132,7 +130,7 @@ impl Rule for ParagraphRule {
document: &dyn Document,
cursor: Cursor,
_match_data: Box<dyn Any>,
- ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
+ ) -> (Cursor, Vec<Report>) {
let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) {
None => panic!("Unknown error"),
Some(capture) => cursor.at(capture.get(0).unwrap().end() - 1),
@@ -152,6 +150,8 @@ impl Rule for ParagraphRule {
#[cfg(test)]
mod tests {
+ use super::*;
+ use std::rc::Rc;
use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text;
use crate::parser::langparser::LangParser;
@@ -159,7 +159,6 @@ mod tests {
use crate::parser::source::SourceFile;
use crate::validate_document;
- use super::*;
#[test]
fn parse() {
diff --git a/src/elements/raw.rs b/src/elements/raw.rs
index cfa190e..24c2370 100644
--- a/src/elements/raw.rs
+++ b/src/elements/raw.rs
@@ -272,6 +272,8 @@ impl RegexRule for RawRule {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::parser::source::Source;
+ use std::rc::Rc;
use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text;
use crate::parser::langparser::LangParser;
diff --git a/src/elements/script.rs b/src/elements/script.rs
index 9a05338..4172027 100644
--- a/src/elements/script.rs
+++ b/src/elements/script.rs
@@ -15,7 +15,6 @@ use ariadne::Fmt;
use mlua::Lua;
use regex::Captures;
use regex::Regex;
-use std::ops::Range;
use std::rc::Rc;
use crate::parser::reports::*;
use crate::parser::reports::macros::*;
@@ -140,7 +139,7 @@ impl RegexRule for ScriptRule {
"Invalid Kernel Code".into(),
span(
script_range,
- "Kernel code is empty".into(),
+ "Kernel code is empty".into()
)
);
return reports;
diff --git a/src/elements/variable.rs b/src/elements/variable.rs
index 1fd7f7a..65b3541 100644
--- a/src/elements/variable.rs
+++ b/src/elements/variable.rs
@@ -353,7 +353,7 @@ impl RegexRule for VariableSubstitutionRule {
"Empty Variable Name".into(),
span(
name.range(),
- "Missing variable name for substitution".into(),
+ "Missing variable name for substitution".into()
)
);
@@ -367,7 +367,7 @@ impl RegexRule for VariableSubstitutionRule {
"Invalid Variable Name".into(),
span(
name.range(),
- "Variable names contains leading spaces".into(),
+ "Variable names contains leading spaces".into()
),
help("Remove leading spaces".into())
);
@@ -382,7 +382,7 @@ impl RegexRule for VariableSubstitutionRule {
"Invalid Variable Name".into(),
span(
name.range(),
- "Variable names contains trailing spaces".into(),
+ "Variable names contains trailing spaces".into()
),
help("Remove trailing spaces".into())
);
diff --git a/src/main.rs b/src/main.rs
index b47bb03..3dc9690 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -41,7 +41,7 @@ fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
- slet mut opts = Options::new();
+ let mut opts = Options::new();
opts.optopt("i", "input", "Input path", "PATH");
opts.optopt("o", "output", "Output path", "PATH");
opts.optopt("d", "database", "Cache database location", "PATH");
diff --git a/src/parser/parser.rs b/src/parser/parser.rs
index 519af86..8a88b29 100644
--- a/src/parser/parser.rs
+++ b/src/parser/parser.rs
@@ -434,7 +434,8 @@ pub trait Parser {
/// Handles the reports produced by parsing. The default is to output them
/// to stderr, but you are free to modify it.
fn handle_reports(&self, reports: Vec<Report>) {
- todo!(); // TODO
+ Report::reports_to_stdout(self.colors(), reports);
+ //todo!(); // TODO
/*
for mut report in reports {
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
diff --git a/src/parser/reports.rs b/src/parser/reports.rs
index 419b19b..ba9184c 100644
--- a/src/parser/reports.rs
+++ b/src/parser/reports.rs
@@ -1,35 +1,35 @@
-use std::{ops::Range, rc::Rc};
+use std::collections::HashMap;
+use std::ops::Range;
+use std::rc::Rc;
-use super::{parser::Parser, source::{Source, SourcePosition, Token}};
+use super::parser::ReportColors;
+use super::source::Source;
+use super::source::SourcePosition;
+use super::source::Token;
#[derive(Debug)]
-pub enum ReportKind
-{
+pub enum ReportKind {
Error,
Warning,
}
-impl Into<ariadne::ReportKind<'static>> for &ReportKind
-{
- fn into(self) -> ariadne::ReportKind<'static> {
- match self
- {
+impl Into<ariadne::ReportKind<'static>> for &ReportKind {
+ fn into(self) -> ariadne::ReportKind<'static> {
+ match self {
ReportKind::Error => ariadne::ReportKind::Error,
ReportKind::Warning => ariadne::ReportKind::Warning,
}
- }
+ }
}
#[derive(Debug)]
-pub struct ReportSpan
-{
+pub struct ReportSpan {
pub token: Token,
- pub message: String
+ pub message: String,
}
#[derive(Debug)]
-pub struct Report
-{
+pub struct Report {
pub kind: ReportKind,
pub source: Rc<dyn Source>,
pub message: String,
@@ -38,65 +38,72 @@ pub struct Report
pub spans: Vec<ReportSpan>,
}
-impl Report
-{
- fn ariadne_format(fmt: &str, parser: &dyn Parser) -> String
- {
- // TODO: Colors
- return fmt.to_string();
- }
-
- fn ariadne_color(kind: &ReportKind, parser: &dyn Parser) -> ariadne::Color
- {
- match kind
- {
- ReportKind::Error => parser.colors().error,
- ReportKind::Warning => parser.colors().warning,
+impl Report {
+ fn ariadne_color(kind: &ReportKind, colors: &ReportColors) -> ariadne::Color {
+ match kind {
+ ReportKind::Error => colors.error,
+ ReportKind::Warning => colors.warning,
}
}
- pub fn to_ariadne(self, parser: &dyn Parser) -> ariadne::Report<'static, (Rc<dyn Source>, Range<usize>)>
- {
+ pub fn to_ariadne(
+ self,
+ colors: &ReportColors,
+ ) -> (
+ ariadne::Report<'static, (Rc<dyn Source>, Range<usize>)>,
+ impl ariadne::Cache<Rc<dyn Source>>,
+ ) {
+ let mut cache = HashMap::new();
let source = self.source.original_position(0).0;
let mut start = usize::MAX;
- for span in &self.spans
- {
+ for span in &self.spans {
let (osource, opos) = span.token.source().original_position(span.token.start());
- if &osource == &source && opos < start
- {
+ if &osource == &source && opos < start {
start = opos;
}
}
- if start == usize::MAX
- {
+ if start == usize::MAX {
start = 0;
}
+ cache.insert(source.clone(), source.content().clone());
let mut builder = ariadne::Report::build((&self.kind).into(), self.source, start)
- .with_message(Self::ariadne_format(self.message.as_str(), parser));
+ .with_message(self.message);
- for span in self.spans
- {
+ for span in self.spans {
+ cache.insert(span.token.source(), span.token.source().content().clone());
builder = builder.with_label(
- ariadne::Label::new((span.token.source(), span.token.range))
- .with_message(Self::ariadne_format(span.message.as_str(), parser))
- .with_color(Self::ariadne_color(&self.kind, parser))
- )
+ ariadne::Label::new(span.token.source().original_range(span.token.range))
+ .with_message(span.message)
+ .with_color(Self::ariadne_color(&self.kind, colors)),
+ )
+ }
+ if let Some(help) = &self.help {
+ builder.set_help(help);
+ }
+ if let Some(note) = &self.note {
+ builder.set_note(note);
}
- builder.finish()
+ (builder.finish(), ariadne::sources(cache))
+ }
+
+ pub fn reports_to_stdout(colors: &ReportColors, mut reports: Vec<Report>) {
+ reports.drain(..).for_each(|report| {
+ let (report, cache) = report.to_ariadne(colors);
+ report.eprint(cache).unwrap();
+ });
}
}
-pub mod macros
-{
+pub mod macros {
pub use super::*;
-#[macro_export]
+ #[macro_export]
macro_rules! report_label {
($r:expr,) => {{ }};
- ($r:expr, span($source:expr, $range:expr, $message:expr), $(, $($tail:tt)*)?) => {{
+ ($r:expr, span($source:expr, $range:expr, $message:expr) $(, $($tail:tt)*)?) => {{
$r.spans.push(ReportSpan {
- token: crate::parser::source::Token::Token::new($range, $source),
+ token: crate::parser::source::Token::new($range, $source),
message: $message,
});
report_label!($r, $($($tail)*)?);
@@ -152,34 +159,3 @@ pub mod macros
pub use crate::*;
}
-
-#[cfg(test)]
-mod tests
-{
- use crate::parser::source::SourceFile;
- use super::*;
-
- #[test]
- fn te()
- {
- let source = Rc::new(SourceFile::with_content(
- "".to_string(),
- r#"
-Sit
- Lorem
- Ipsum
-Dolor
- "#
- .to_string(),
- None,
- ));
-
- let mut reports = vec![];
- //let la = report_label!(source.clone(), 5..9, "Msg".into());
- report_err!(&mut reports, source.clone(), "Some message".into(),
- span(5..9, "Msg".into()),
- span(5..9, "Another".into()),
- );
- println!("Report = {reports:#?}");
- }
-}
diff --git a/src/server.rs b/src/server.rs
index a47e5d7..33e2101 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -14,7 +14,6 @@ use parser::parser::ParseMode;
use parser::parser::Parser;
use parser::parser::ParserState;
use parser::source::SourceFile;
-use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::Client;
use tower_lsp::LanguageServer;
@@ -65,7 +64,7 @@ impl Backend {
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
- async fn initialize(&self, _params: InitializeParams) -> Result<InitializeResult> {
+ async fn initialize(&self, _params: InitializeParams) -> tower_lsp::jsonrpc::Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
@@ -118,7 +117,7 @@ impl LanguageServer for Backend {
.await;
}
- async fn shutdown(&self) -> Result<()> { Ok(()) }
+ async fn shutdown(&self) -> tower_lsp::jsonrpc::Result<()> { Ok(()) }
async fn did_open(&self, params: DidOpenTextDocumentParams) {
self.client
@@ -139,7 +138,7 @@ impl LanguageServer for Backend {
.await
}
- async fn completion(&self, _params: CompletionParams) -> Result<Option<CompletionResponse>> {
+ async fn completion(&self, _params: CompletionParams) -> tower_lsp::jsonrpc::Result<Option<CompletionResponse>> {
//let uri = params.text_document_position.text_document.uri;
//let position = params.text_document_position.position;
let completions = || -> Option<Vec<CompletionItem>> {
@@ -153,7 +152,7 @@ impl LanguageServer for Backend {
async fn semantic_tokens_full(
&self,
params: SemanticTokensParams,
- ) -> Result<Option<SemanticTokensResult>> {
+ ) -> tower_lsp::jsonrpc::Result<Option<SemanticTokensResult>> {
let uri = params.text_document.uri.to_string();
self.client
.log_message(MessageType::LOG, "semantic_token_full")