saibotsivad / blockdown

A Markdown-like syntax that supports defining blocks of text.
https://blockdown.md/
Other
5 stars 0 forks source link

Proposal: add an inline delimiter for Markdown blocks #8

Closed saibotsivad closed 7 months ago

saibotsivad commented 3 years ago

I've been enjoying using this syntax for a while now, but one thing that's been really limiting is that the specs are only for block-level elements, but I would like inline-level elements in my text.

This proposal hopes to solve the original problem (clear, concise delimiters) but for inline text.

Why?

A typical Markdown blog post might look like this:

Some exciting words.

Suppose that you want to include blinking text in the middle on the word exciting?

You might be tempted to write something like:

Some <span class="blink">exciting</span> words.

But then you would need to use HTML tools, do a search for span.blink, and then do whatever rules are needed.

Sounds doable but... if only there was a better way... 🤔

Proposal

The exact syntax is up for discussion, but I'm proposing to add an inline element using a similar style:

Some [[blink|exciting]] words.

Where the inline element is [[name#id|metadata]] (similar structure but slightly different encapsulation).

This would only be available to blocks that are explicitly delimited with the name md or markdown, so e.g. this would not work:

---
title: My Post
---
Some [[blink|exciting]] words.

But this would:

---
title: My Post
---!md
Some [[blink|exciting]] words.

Multi-Line Metadata

Similar to block-level delimiters, I propose adding multi-line inline delimiters:

words [[name#id|
  metadata
]] more words
Renddslow commented 3 years ago

I certainly love the idea of inline blockdown. I do wonder if we could run with a different syntax. This syntax borrows from the Wiki-link syntax which itself is used by Roam. As a Roam user, I could see this conflicting

saibotsivad commented 3 years ago

Yeah, that's a good point, that's probably already got a lot of external context that would be confusing.

Note to my future self / other readers: Wikipedia links are like [[target|display text]].

Taking a page from Wikipedia, "templates" is conceptually pretty close, and those use curly braces, e.g. {{template|params}} so translated to blockdown-like syntax it would be:

---
title: My Post
---!md
Some {{blink|exciting}} words.

And multi-line would be:

words {{name#id|
  metadata
}} more words
saibotsivad commented 3 years ago

As I was thinking of the API, if I consider a blockdown file like this, with the curly-braces style:

---!md#thing1[foo=bar]
Some {{blink#thing2|exciting}} words.

More {{marquee#thing3|foo=bar}} fun.

If the inline parts are a new property, we'd keep backwards compatibility, so maybe like:

const blocks = [
  {
    name: 'markdown',
    id: 'thing1',
    metadata: 'foo=bar',
    // "content" is as before, with the non-parsed text
    content: 'Some {{blink#thing2|exciting}} words.\n\nMore {{marquee#thing3|foo=bar}} fun.',
    // some new property has the parsed text
    parts: [
      {
        type: 'text',
        content: 'Some '
      },
      {
        type: 'template',
        name: 'blink',
        id: 'thing2',
        metadata: 'exciting'
      },
      {
        type: 'text',
        content: ' words.\n\nMore '
      },
      {
        type: 'template',
        name: 'marquee',
        id: 'thing3',
        metadata: 'foo=bar'
      },
      {
        type: 'text',
        content: ' fun.'
      }
    ]
  }
]
saibotsivad commented 3 years ago

One last thing: the part that I'm not as confident about is that, block-level syntax is pretty straightforward with markdown->anything conversion, but inline can be really finicky: for example does the transform happen before the document is converted to HTML, or after?

One sort-of-weird way would be a pre-and-post processing step, so translate each inline "template" to some sort of unique marker $UNIQUE_ID and then after processing the Markdown, do a search+replace.

With the API as proposed you could definitely do that, but I'm sure I'd want it wrapped up in some other helper function:

import { readFileSync } from 'fs'
import { parse } from '@saibotsivad/blockdown'
const { blocks } = parse(readFileSync('./path/to/file.md', 'utf8'))

// your thing that turns blockdown blocks into HTML or whatever
const processBlockdownBlocks = ({ name, id, metadata }) => {}
// your thing that turns inline templates into HTML or whatever
const processInlineTemplate = ({ name, id, metadata }) => {}

const mapBack = {}
// pre-process to convert templates to unique ids
blocks.forEach((block, blockIndex) => {
    if (block.parts) {
        const preLines = []
        block.parts.forEach((part, partIndex) => {
            if (part.type === 'text') preLines.push(part.content)
            else {
                const key = [ blockIndex, partIndex ].join(':')
                mapBack[key] = part
                preLines.push(`UNIQUEID(${key})`)
            }
        })
        block.content = preLines.join('')
    }
})
// then you'd convert markdown blocks to HTML blocks or whatever
const htmlSections = blocks
    .map(processBlockdownBlocks)
    // and finally post-process
    .map(html => html.replace(/UNIQUEID\((\d+:\d+)\)/g, (match, key) => {
        const part = mapBack[key]
        // run the part through your template engine
        return processInlineTemplate(part)
    }))

Maybe I'll run with this and see what happens.

saibotsivad commented 3 years ago

Made a little demo-type thing here: https://svelte.dev/repl/4c7639fae3dc486ebf796fb1499ead21?version=3.44.0

saibotsivad commented 7 months ago

It's been a few years and I'm actually about to implement some tooling that will use an inline delimiter, so I have an interest in resolving this discussion, but several years of using Blockdown in many projects has led me to this ultimate decision:

Inline delimiters are a Markdown implementation concern, not a Blockdown concern.

So far the Blockdown syntax is not concerned with which implementation of Markdown you choose. Want to use Snarkdown? Remark? Showdown? Marked? Want to use Markdown based on CommonMark but with more stuff? Blockdown doesn't care!

You can, in fact, use Blockdown syntax without using any Markdown at all. (I do it from time to time in some private projects.)

It would be really painful to bake in a Markdown-specific implementation detail in the very basic Blockdown syntax, so... I'm not gonna do it.