-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement try_run and error propagation #19
base: master
Are you sure you want to change the base?
Conversation
This commit adds a Result<> to all walk callbacks. In order to use this, you should change all `Node::walk_*` methods in your code the following way: ```rust // replace this: node.walk(|node, _| { dbg!(node); }); // with this (unwrap is safe here because walk only // returns error when your function does): node.walk(|node, _| { dbg!(node); Ok(()) }).unwrap(); ```
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #19 +/- ##
==========================================
- Coverage 94.12% 94.07% -0.06%
==========================================
Files 57 57
Lines 2453 2685 +232
==========================================
+ Hits 2309 2526 +217
- Misses 144 159 +15
☔ View full report in Codecov by Sentry. |
This looks really cool! Wanted to clarify something from my comment in #11: At least in my case, even if there are some errors in my plugins, it may not stop us from rendering something. The node itself could render its error into the HTML, but it's still nice to be able to know in the return type that an error occurred. Also, there could be multiple errors in the document, and it would be nice to get them all in one pass. This unfortunately doesn't really fit into the Rust This may be a bit of a specialized use case, so I understand if it's something you'd not want to add to the library - there's ways around it using the old Thanks for all your work on this library! |
That use-case is already supported with Note that there's a bug currently with inline rules, which I just fixed in use markdown_it::parser::block::{BlockRule, BlockState};
use markdown_it::parser::core::CoreRule;
use markdown_it::parser::extset::NodeExt;
use markdown_it::parser::inline::{InlineRule, InlineState};
use markdown_it::{MarkdownIt, Node};
#[derive(Debug, Default)]
struct NodeErrors(Vec<anyhow::Error>);
impl NodeExt for NodeErrors {}
struct MyInlineRule;
impl InlineRule for MyInlineRule {
const MARKER: char = '@';
fn run(state: &mut InlineState) -> Option<(Node, usize)> {
let err = state.node.ext.get_or_insert_default::<NodeErrors>();
err.0.push(anyhow::anyhow!("inline error"));
None
}
}
struct MyBlockRule;
impl BlockRule for MyBlockRule {
fn run(state: &mut BlockState) -> Option<(Node, usize)> {
let err = state.node.ext.get_or_insert_default::<NodeErrors>();
err.0.push(anyhow::anyhow!("block error"));
None
}
}
struct MyCoreRule;
impl CoreRule for MyCoreRule {
fn run(root: &mut Node, _md: &MarkdownIt) {
let err = root.ext.get_or_insert_default::<NodeErrors>();
err.0.push(anyhow::anyhow!("core error"));
}
}
fn main() {
let md = &mut markdown_it::MarkdownIt::new();
markdown_it::plugins::cmark::add(md);
md.inline.add_rule::<MyInlineRule>();
md.block.add_rule::<MyBlockRule>();
md.add_rule::<MyCoreRule>();
let text1 = r#"*hello @world*"#;
let ast = md.parse(text1);
println!("parsed as:");
println!("{}", ast.render());
println!("errors:");
ast.walk(|node, _| {
if let Some(errors) = node.ext.get::<NodeErrors>() {
for error in errors.0.iter() {
println!(" - {error:?}");
}
}
});
} Of course the problem with that approach is that errors are not standardized, i.e. two plugins from different authors would report errors in different ways. |
This PR addresses specifically the need to terminate parsing early. I don't know if there is such a need, and if this is the best approach. Maybe we can use a single parse() function and report errors via function like |
Makes perfect sense 👍 I hadn't thought about using a
Yeah I'm not sure about the best option myself either. Maybe someone has that specific use case and they could comment here? Apologies if my comment ended up causing extra work! Should have been more explicit originally. |
see discussion in #11
This PR adds a new function
MarkdownIt::try_parse()
, which propagates errors from user plugins.As an example of one such error,
syntect
plugin now reports non-existent language tag intry_parse()
(but still returns correct output when runningparse()
):