slidevjs / slidev

Presentation Slides for Developers
https://sli.dev
MIT License
33.27k stars 1.35k forks source link

Allow (pre)parser extension #700

Closed twitwi closed 1 year ago

twitwi commented 2 years ago

Is your feature request related to a problem? Please describe. For some presentation that aggregate subslides, it takes a lot of space to even write the front matter with the two --- (one after the frontmatter, and one after the (empty) content) + the empty line. With a custom syntax for includes, I had in a previous system:

#@chunk: title.md
#@chunk: objectives.md
#@chunk: toc.md

Which now takes a lot of vertical boilerplate:

src: title.md
---

---
src: objectives.md
---

---
src: toc.md
---

---

There are other cases where a custom compact notation would be nice to have (e.g. open a slide at every # bla title, so no --- everywhere) (e.g. alternate syntax to open a slide with a specific layout, @cover(bg.jpg), etc). For some use cases, the solution below might be also simpler than adding rules to the markdownit parser (but the blocking point is really the things that happen before markdown parsing, so the split at ---).

Describe the solution you'd like A flexible, minimal-change solution would be to add an extension point to the parser, that addons and the user can customize. E.g. allow to call a (chain of) custom parsers for instance here https://github.com/slidevjs/slidev/blob/fb8054f376b3b71c594b349fa7339cf2e2344a7e/packages/parser/src/core.ts#L130 Things to consider without too much filtering:

Describe alternatives you've considered I could write a script (bash, python) that generates the actual md file...

antfu commented 2 years ago

Have you tried to write an inline Vite plugin to do the transformation? If that can't help, I am fine to expose some capability for such customization

twitwi commented 2 years ago

I'll have a look at what can be done with vite, it is still some tech I don't know very well.

twitwi commented 2 years ago

@antfu can vite plugins "intercept" a file read with fs as done in this case? https://github.com/slidevjs/slidev/blob/df066d434468160795e5718d22d08d450e2dd1a9/packages/parser/src/fs.ts#L9

I tried a simple plugin but it seems to be called with individual virtual 1.md 2.md ... files (but not the entry point).

antfu commented 2 years ago

I see. PR welcome to propose your interface in mind (or if you want to start with a more detailed API design first would also be great)

twitwi commented 2 years ago

I started thinking about it, I imagine a few callbacks from the parser to the plugin, do you prefer a style where there is an api with several methods or rather a single method with an kind of event type (i.e. the plugin implements a single method, that is a if (type == '') .... elif ....)?

For the "chain" aspect, where e.g. several (slidev) addons can each add a parser plugins and the user folder can also add parser plugins, I think the core of the solution is related to the same question with shortcuts https://github.com/slidevjs/slidev/issues/629 ... any suggestions on how you would do that best? I guess it is almost handled by https://github.com/slidevjs/slidev/blob/main/packages/slidev/node/plugins/setupClient.ts#L27 so I would update there. I PR'd a / chained_injections / that should be sufficient (no fine control on the order but I don't think it would be used a lot anyways) https://github.com/slidevjs/slidev/pull/702

twitwi commented 2 years ago

NB: The (chained) injection unfortunately runs in the client but the preparser is on the node side so it means I'll have to update the server extension code, i.e., https://github.com/slidevjs/slidev/blob/f0941ce770ff8879e5adff695dc4015cfbd4e5ef/packages/slidev/node/plugins/setupNode.ts#L19

twitwi commented 2 years ago

NB: the situation is even more tricky as:

I've come up with a somewhat convoluted solution where the node module injects an addon loader function into the parser that calls it when it has found the headmatter. I'll clean it a little and push it for feedback.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.