Skip to content

`resultBuilder` support for `swift-markdown`

License

Notifications You must be signed in to change notification settings

DoccZz/SwiftMarkdownBuilder

Repository files navigation

SwiftMarkdownBuilder

resultBuilder support for swift-markdown.

The default way to build Markdown in swift-markdown is to use varargs initializers, e.g. as in the example from the README.md:

let document = Document(
    Paragraph(
        Text("This is a "),
        Emphasis(
            Text("paragraph."))))

Wouldn't it be nice to be able to use a SwiftUI like "resultBuilder" syntax, like:

let document = Document {
  Paragraph {
    "This is a "
    "paragraph"
      .emphasis()
  }
}

And maybe even control structures like:

let document = Document {
  "Our Tasks:"
    .font(.largeTitle)
  
  List {
    ForEach(todos) { todo in
      Text(todo.title)
    }
  }
}

Or custom Markdown "views":

struct TOC: DynamicMarkdownBlock {
  let pages : [ Page ]
  
  var body: [ MarkdownBlock ] {
    "Table of Contents"
      .font(.title)
    
    ForEach(pages) { page in
      Paragraph {
        Text(page.title)
          .font(.title2)
        
        Text(page.abstract)
      }
    }
  }
}

That's what we play with here.

Maybe we can get it to a state suitable for a PR on swift-markdown itself.

Status

An experiment for curious people. Work in progress.

It is not entirely clear how useful this thing is. Is there really a usecase for building Markdown in Swift? 😃

A goal is/was to not come up with protocols/structures specific to the resultBuilders, but to directly attach to the ones provided by swift-markdown already.

If that would be internal to the Markdown module, a few hacky things could be dropped (i.e. because the API could be accessed).

The implementation also doesn't have to resort to the type-safyness attached to SwiftUI style setups, because the swift-markdown protocols do not use associated types. Also, it doesn't need two-way setups like Binding.

Things missing:

  • table stuff (needs an own builder for scoping the contents), but could be similar to the macOS SwiftUI table
  • List
  • conditionals
  • finish the ForEach
  • an Environment maybe
  • also add an HTML resultBuilder?
  • many more things?

Maybe more things from SwiftBlocksUI could be used (it generates Slack JSON block structures, but those are essentially just fancy markdown).

Usage in a Swift Package

Example Package.swift:

// swift-tools-version:5.3

import PackageDescription

let package = Package(
  name         : "MyWebsite",
  products     : [ .executable(name: "MyWebsite", targets: [ "MyWebsite" ]) ],
  dependencies : [
    .package(url: "https://github.com/DoccZz/SwiftMarkdownBuilder.git", from: "0.1.0")
  ],
  targets: [ 
    .target(name: "MyWebsite", dependencies: [ 
      .product(name: "MarkdownBuilder", package: "SwiftMarkdownBuilder") 
    ])
  ]
)

Who

SwiftMarkdownBuilder is brought to you by the Always Right Institute and ZeeZide. We like feedback, GitHub stars, cool contract work, presumably any form of praise you can think of.