Skip to content
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

Allow rules to provide a "priority" (integer), for sorting rule order? #24

Open
chrisjsewell opened this issue Jun 23, 2023 · 3 comments

Comments

@chrisjsewell
Copy link
Member

Currently, it can be a bit confusing to understand in which order rules will be applied, and how they are "inter-connected"

For example, if you have a plugin like:

pub fn add(md: &mut MarkdownIt) {
    md.add_rule::<MyRule1>()
        .before::<MyRule2>()
        .after::<MyRule3>();
        .before_all();
}

For RST, in docutils, they have the rough equivalence (for core rules) of transforms, that specify a priority by which they are sorted: https://docutils.sourceforge.io/docs/ref/transforms.html#transform-priority-range-categories
and, building on this, sphinx then allows transform plugins: https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.add_transform

It feels this might be an easier way to deal with rule ordering?

@rlidwka
Copy link
Collaborator

rlidwka commented Jun 23, 2023

Currently, it can be a bit confusing to understand in which order rules will be applied, and how they are "inter-connected"

In which they will be applied - you can find out with debug-print:

dbg!(&md.block);
compiled: [
    (
        0,
        markdown_it::plugins::cmark::block::code::CodeScanner,
    ),
    (
        1,
        markdown_it::plugins::cmark::block::fence::FenceScanner,
    ),
    (
        2,
        markdown_it::plugins::cmark::block::blockquote::BlockquoteScanner,
    ),
    (
        3,
        markdown_it::plugins::cmark::block::hr::HrScanner,
    ),
    (
        4,
        markdown_it::plugins::cmark::block::list::ListScanner,
    ),
    (
        5,
        markdown_it::plugins::cmark::block::reference::ReferenceScanner,
    ),
    (
        6,
        markdown_it::plugins::cmark::block::heading::HeadingScanner,
    ),
    (
        7,
        markdown_it::plugins::cmark::block::lheading::LHeadingScanner,
    ),
    (
        8,
        markdown_it::plugins::cmark::block::paragraph::ParagraphScanner,
    ),
],

how they are inter-connected - should be mentioned in comments for each particular rule

@rlidwka
Copy link
Collaborator

rlidwka commented Jun 23, 2023

It feels this might be an easier way to deal with rule ordering?

Easier - absolutely. But it hides actual dependencies between rules. So instead of asking "what order they are executed in", you are gonna be asking "why are they executed in that particular order". And that's harder question to answer.

Current plan - make labels (e.g. First, Early, Middle, Late, Last) running sequentially. And make rules execute within one of these labels. Would that be sufficient?

.before() and .after() should still be there, but be exceptionally rare.

@chrisjsewell
Copy link
Member Author

Current plan - make labels (e.g. First, Early, Middle, Late, Last) running sequentially. And make rules execute within one of these labels. Would that be sufficient?

I think that it's definitely an improvement thanks, although maybe I'm still partial to the priority integers

But it hides actual dependencies between rules

I guess maybe it comes down to scaling, I think actual dependencies are maybe more rigorous, but a lot less scalable than simple priority integers...

If you have a few plugins, and particularly in the same package (as here), then yes it is nice to be able to specifically set "this rule should come before this other rule", i.e. hard-dependencies
But, if I have for example ruleA in packageA and ruleB in packageB, I don't want to have to start making hard dependencies between the packages, just to ensure that ruleA runs before ruleB, i.e. actually exporting packageA into packageB in the Cargo.toml.

Then, if you have, let's say, ~10 or more different plugin packages, this becomes even more complex and confusing; if you have to set up hard-dependencies between all of them.
Plus, what happens if new plugins are introduced? Do you have to go back and add even more hard-dependencies to the old plugins?

I would call priority integers more of a soft dependency, because you can choose it with a hard-dependency in mind (i.e. you choose the number to be greater than another rules), but it is not strictly tied to that dependent rule

There is also the question of idempotence in the ordering of plugin additions.
At present, it can really make a difference for the rule ordering, whether pluginA is added before pluginB.
But if you have a priority number (assuming no rules have exactly the same number), then the rule ordering is completely independent of the order the plugins are loaded.

In Sphinx, I frequently use/create many extensions (see e.g. https://github.com/executablebooks/MyST-Parser/blob/5f03f5c65b3b8e9333f8c34ef63773d95bf35e2f/docs/conf.py#L30),
and there has rarely ever been a time when I have had issues with incompatibilities between them and/or in the order that I load the extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants