readable errors

This commit is contained in:
Mark
2026-03-24 23:19:02 +01:00
parent da22776f24
commit deac3524a3
3 changed files with 82 additions and 19 deletions

View File

@@ -37,7 +37,7 @@ fn main() {
let specs = &args[2..];
let src = || std::fs::read_to_string(&args[0]).unwrap();
match args[1].to_lowercase().trim() {
"html" => println!(
"html" => print!(
"{}",
to::html::page(&parse(&src()).unwrap(), specs, &mut to::html::State::new())
),
@@ -122,7 +122,13 @@ const BODY_REGEX = new RegExp("<bo"+"dy>.*<\\/bo"+"dy>", "misv");
}
buf1[i] = src();
let src = unsafe { &*((&buf1[i]) as *const String) };
buf2[i] = Some(parse(src).unwrap());
buf2[i] = Some(match parse(src) {
Ok(v) => v,
Err(e) => {
eprintln!("{}", e.display(src));
continue;
}
});
let doc = unsafe { &*(buf2[i].as_ref().unwrap() as *const Document<'_>) };
i += 1;
let mut http =

View File

@@ -1,3 +1,5 @@
use std::fmt::Display;
use crate::doc::{Component, Document, Section, Text};
pub fn parse<'a>(mut src: &'a str) -> Result<Document<'a>, ParseError<'a>> {
@@ -6,6 +8,8 @@ pub fn parse<'a>(mut src: &'a str) -> Result<Document<'a>, ParseError<'a>> {
Ok(doc)
}
#[derive(Debug)]
pub struct ParseErrorPlus<'a>(ParseErr<'a>, usize, &'a str);
#[derive(Debug)]
pub struct ParseError<'a>(ParseErr<'a>, usize);
#[derive(Debug)]
@@ -20,7 +24,7 @@ pub enum ParseErr<'a> {
MissingClosing(char),
InvalidBacktickBracketCountSpecifier,
InvalidBacktickModifier,
SubsectionNotAllowedHere,
SubdocumentNotAllowedHere,
FileTitleWithLink,
r#__Zzzz(&'a str),
}
@@ -371,7 +375,7 @@ fn parse_sections<'a>(
// => section hashes
Some(' ' | '\n') | None => {
if !document {
return Err(ParseError(ParseErr::SubsectionNotAllowedHere, pos));
return Err(ParseError(ParseErr::SubdocumentNotAllowedHere, pos));
}
src.reset_to(pos);
match parse_document(src.get(), depth + 1)
@@ -517,3 +521,67 @@ impl<'a, 'b> Parser<'a, 'b> {
}
}
}
impl<'a> ParseError<'a> {
pub fn display(self, src: &'a str) -> ParseErrorPlus<'a> {
ParseErrorPlus(self.0, self.1, src)
}
}
impl<'a> Display for ParseErrorPlus<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ln = self
.2
.char_indices()
.take_while(|(i, _)| *i <= self.1)
.filter(|(_, c)| *c == '\n')
.count();
write!(f, "Line {}: {}", ln + 1, self.0)
}
}
impl<'a> Display for ParseErr<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseErr::InvalidSectionHash => write!(
f,
"this section hash isn't valid, if you want a title, add a space after your hashtags"
),
ParseErr::InvalidHeadingDepth => write!(f, "this heading depth isn't allowed here"),
ParseErr::BracketsAtStartOfSectionWithNoLinebreakAfter => write!(
f,
"brackets at the start of a section must be on their own line"
),
ParseErr::BracketedSectionNotTerminated => {
write!(f, "this bracketed section isn't terminated anywhere")
}
ParseErr::BracketedSectionTerminatedByTooManyBrackets => write!(
f,
"this bracketed section is terminated by more brackets than expected"
),
ParseErr::IncompleteBacktick => {
write!(
f,
"incomplete backtick, there needs to be something here (or escape the backtick: ``)"
)
}
ParseErr::MissingClosing(c) => {
write!(f, "couldn't find an appropriate closing {c} bracket")
}
ParseErr::InvalidBacktickBracketCountSpecifier => write!(
f,
"invalid backtick bracket count between ` and the next ascii symbol"
),
ParseErr::InvalidBacktickModifier => write!(
f,
"invalid backtick modifier between ` and the next bracket"
),
ParseErr::SubdocumentNotAllowedHere => {
write!(f, "found a subdocument where it isn't allowed")
}
ParseErr::FileTitleWithLink => write!(
f,
"file title (title at the start of the file) cannot have a link"
),
ParseErr::__Zzzz(_) => unreachable!(),
}
}
}

View File

@@ -7,15 +7,13 @@ use crate::{
pub struct State<'a> {
pub head_to_body: &'a str,
cache_docs: BTreeMap<&'a Document<'a>, String>,
cache_secs: BTreeMap<&'a Section<'a>, String>,
cache: BTreeMap<&'a Section<'a>, String>,
}
impl<'a> State<'a> {
pub fn new() -> Self {
State {
head_to_body: "</head>\n<body>",
cache_docs: Default::default(),
cache_secs: Default::default(),
cache: Default::default(),
}
}
}
@@ -254,11 +252,6 @@ fn doc_to_impl<'a>(
out: &mut String,
doc_args: &mut DocArgs<'a, '_>,
) {
if let Some(prev) = doc_args.state.cache_docs.get(doc) {
out.push_str(prev);
return;
}
let out_start = out.len();
let depth = doc_args.depth;
let end_at = doc_args.max_len.map(|len| out.len() + len);
for d in depth..=doc.depth {
@@ -285,7 +278,7 @@ fn doc_to_impl<'a>(
out.push_str(&format!("</span>{a}</div>\n"));
}
for section in &doc.sections {
if let Some(prev) = doc_args.state.cache_secs.get(section) {
if let Some(prev) = doc_args.state.cache.get(section) {
out.push_str(prev);
continue;
}
@@ -385,16 +378,12 @@ fn doc_to_impl<'a>(
out.push_str("</div>\n");
doc_args
.state
.cache_secs
.cache
.insert(section, out[section_start..].to_owned());
}
for _ in depth..=doc.depth {
out.push_str("</div>\n");
}
doc_args
.state
.cache_docs
.insert(doc, out[out_start..].to_owned());
}
fn text_to<'a: 'b, 'b>(