pngwn / MDsveX

A markdown preprocessor for Svelte.
https://mdsvex.pngwn.io
MIT License
2.44k stars 102 forks source link

Option to render fence blocks caught by codeParse #52

Open dimfeld opened 4 years ago

dimfeld commented 4 years ago

So that, for example, writing js exec-render instead of js exec at the start of a fence would both add the code into the scripts section, as it does now, but also render it into the document, saving the effort of writing the code block twice.

I think something like a -render suffix, as shown above, is the way to go, instead of a plugin or front-matter option. This way the author can control rendering for each block, instead of it being all or nothing. What do you think?

I'm happy to submit a PR if you like this idea. Thanks!

pngwn commented 4 years ago

js exec blocks are being removed entirely in a rewrite and replaced with plain svelte script blocks. I don't think this belongs as a core part of the library as it adds special syntax (almost all of which has been removed in the next version). I'll have a think about this and see what the best way would be to implement it in the new version.

rixo commented 4 years ago

I would love this too!

My use case is documenting a tool by writing some sort of self-describing document.

Here's some example of what I currently do (the new syntax is awesome :+1:) :

## Setup

Start by importing **all the things**...

```html
<script>
  import { View } from 'svench'
  import Child from './Child.svelte'
</script>
```

<script>
  import { View } from 'svench'
  import Child from './Child.svelte'
</script>

## Usage

Then, by all mean, _use it_!

```html
<View>
  <Child />
</View>
```

<View>
  <Child />
</View>

I would love to do something like this instead:

## Setup

Start by importing **all the things**...

```html exec print
<script>
  import { View } from 'svench'
  import Child from './Child.svelte'
</script>
```

## Usage

Then, by all mean, _use it_!

```html exec print
<View>
  <Child />
</View>
```

I totally understand that fenced exec might be frowned upon, and any syntax would do... The goal is really to remove the duplicated code.

Maybe this would work better with the new syntax:

<script print>
  // ...
</script>

But it wouldn't work at all for anything else than <script> and <style>... And this is also desirable:

```html printex:after
<MyComponent ... />
```

(just trying alternative syntax, for inspiration)

If a good syntax can be found, that would be huge to be able to eliminate the duplicated code. Executing docs... Feels a bit like literate programming. Or a mirror of it? Anyway, even with some clumsy syntax, that would be worth it for me, because the dup code is really a bit of a meh to do this sort of things.

Otherwise... Well, it's already great :) Thanks!

pngwn commented 4 years ago

I can understand this completely, documentation is one of the things that mdsvex really makes sense for and I've considered this use-case myself. I've been thinking whether or not it could be achieved using components and a preprocessor (not sure about that) or perhaps as a remark or rehype plugin (it almost definitely can be, that is essentially what mdsvex is) or if it does indeed need some first-class support from mdsvex itself.

If I can get the docs finished, I'll be able to get the beta into general release and I can think more carefully on this.

Executable code blocks kind of make sense in this context since you also want to 'print' the code. I feel like this would be pretty straightforward with a remark or rehype plugin (albeit a very mdsvex specific one), I look at it more closely depending on how productive my weekend is.

rmunn commented 3 years ago

Disclaimer: Although this is written on April 1st, this is not a joke.

I've thought about how to do this, and the idea I came up with (which I haven't found the time to implement yet) was to use the https://github.com/remarkjs/remark-directive plugin, which lets you specify Markdown "directives" (see https://talk.commonmark.org/t/generic-directives-plugins-syntax/444 for details) with triple-colon syntax, like this:

:::directive-name [inline-content] { directive parameters can go here }
Block content goes here

* Block content can
* include further Markdown,
* like this list.

A triple-colon on a line by itself ends the block
:::

There are also single-colon directives (treated as inline Markdown) and double-colon directives (for things that don't contain further Markdown content, e.g. :: youtube[dQw4w9WgXcQ] might turn into a link to https://www.youtube.com/watch?v=dQw4w9WgXcQ or an embedded <video> element in the result, but either way there would be no further contents inside the link or <video> element). But triple-colon directives are what is relevant here.

According to the remark-directive README, it only handles parsing the directives. Further processing of the directive is left up to a further plugin (which someone would need to write), and the directive can be processed however the plugin wants, probably by matching the directive name and doing something appropriate. What I'm thinking is that a remark plugin could be written, and the mdsvex docs link to it, that would add an example directive. The processing of the example directive would be to duplicate its contents: the first copy would be wrapped in a <pre> block (or maybe a <code> block so that appropriate syntax highlighting can be added by another Remark plugin), and the second copy would be rendered as Markdown, or compiled as Svelte code, as appropriate. (Perhaps the language of the example would be specified in the parameters, e.g. ::: example [svelte]).

I don't have any code to show, and this is as far as I've gotten with this idea since my other projects are taking up all my time for now. But I wanted to document this idea so others could run with it.

pngwn commented 3 years ago

Had similar thoughts, incidentally generic directives will be supported out of the box in v1. Not saying that it how it should be implemented but it is one way of achieving it.

janosh commented 2 years ago

I've been thinking whether or not it could be achieved using components and a preprocessor (not sure about that)

It can definitely be done with a preprocessor. In fact there's a nice explanatory video by @bluwy how to do exactly this:

https://youtu.be/glp4iEBTkvQ?t=1363

rmunn commented 2 years ago

See https://github.com/mattjennings/mdsvexamples for one approach that seems to have worked.

pngwn commented 2 years ago

Will be added as a core plugin either in 1.0 or just after.