Extending DocC with additional metadata to provide alternate displays for code blocks

(prototype/pre-pitch question)

I've been trying to sort out how to provide more annotation for a code block in order to allow some additional options to present it.

Specifically, I'd like to annotate that a specific code block (the triple backtick) get presented with line numbers, a copy-to-clipboard button, etc. The markdown syntax allows for stashing on a syntax highlighting hint after the triple-backtick, and I'm not sure how else to reasonably confer this that fits within what how DocC does its work today.

I've been tempted to lean into creating a custom directive (and all the data stitching through to docc-render that will entail) to support this. My "off the top" is something akin to:

@codeblock(copyToClipboard=true, language=swift) { 
  func doSomething() -> String {
    print("hello world")
  }
}

or

@codeblock(copyToClipboard=true) {
```swift
func doSomething() -> String {
    print("hello world")
}
```
}

Are there other mechanisms that would align well with DocC in terms of how it feels, extending markdown in useful ways to provide metadata to the renderer to allow for more display customization?

2 Likes
  • Line numbers is good

  • and how to handle line breaks (wrapping or no) and at what width that happens?

  • How does one pick their color scheme?

  • Could one provide an alternate parser for langs DocC doesn't support yet?

This is a little (a lot) beyond what you're asking for, but Is there a path towards endusers being able to add completely custom directives? I ask because I'd like to create some custom semantic blocks (citations, for example), rather than just formatting blocks.

It'd be

struct myWidget:DCDeclaration {
      let name:String
      let count:Int

     var body: some DCDeclaration {
             //Something here
     }
}

And then later in a .md

@myWidget(name="pretty widget", count="5")

I haven't watched it all but this probably triggered some of my thinking:

Also one can use a custom number of back ticks in Discourse

```
"I can use three ticks inside because I used 4 to start"
```
1 Like

Oh, that's brilliant! Thank you!

1 Like

I implemented a version of adding a copy-to-clipboard button using the triple-backtick syntax. You’d add the copy button like this:

```swift, copy
func doSomething() -> String {     
    print("hello world")
} 
```

Those PRs can be found here:

4 Likes

This is going to be super useful, thank you @DebugSteven! For the copy-code functionality, did we also consider enabling this by default rather than making it opt-in? It would be nice to attach some screenshots of the proposed UI :slight_smile:

+1 for enable copy to pasteboard support by default instead of opt-in for code block.

And we may considering adding an opt-out support for disabling copy pasteboard if some use case is risen with solid reason.

I am working with @DebugSteven to set this up (unsurprisingly, I suppose) - and we did indeed think about both a global option (using a new directive within @Metadata) and a page level option (using a directive inside @Option), but as we explored the use cases, there were a couple of places where we didn’t want the automatic copy-to-clipboard. - In particular, when showing tutorial flows of ā€œcommand you enterā€ and the following ā€œresults you might seeā€ kind of setup. In those cases, we don’t want to copy the results, but we do with the command.

Maybe that’s rare enough that it would make sense to enable a page-level-all-blocks-copy with @Options and then disable it in the places we don’t want it, but that seemed overly complicated, so we shied away from it.

If there’s sufficient desire to see this broadly enabled by default, we can certainly keep the simplicity by always enabling the copy and disabling it in specific nodes to get the functionality we’re after. As a starting position, that didn’t seem warranted due to the significant change that it imposes in everyone’s content, but we’re certainly game to flip this out.

In the associated Docc-Render PR, Marcus pointed out a way to make the visual effects a bit more effective, so we’re looking at that - but in the meantime, I’ll get an animated gif of work we did earlier while prototyping this (meaning the visuals of the end result may not be exact to what this displays), and have it up shortly.

The piece that I’d like to call out specifically, and something we want to build on, is the annotation that an author can make (currently, to enable) following the normal triple backticks. For most of our packages, the default language is swift, so in those cases:

```copy

and it also supports defining the language, with the additional annotation after a comma:

```yaml, copy

Wrangled a little screencast from Jesse into an animated gif, that hopefully will display nicely here in the forums:

CopyToClipboard

The places we’ve seen where you may not want copy-to-clip automatically enabled:

  1. command-line example output that just doesn’t have any value to copying. Leaving the copy to clipboard on doesn’t ā€œhurtā€ exactly, as a reader can just select and copy anyway, but it doesn’t add any value and may send a visual message (that you should copy this stuff) that isn’t intended.

  2. the copy-to-clipboard symbol can overlay content that you might not want - especially for those instances where you’re using a code block as an inexpensive diagram replacement:

extra-wide-diagram

And one issue we’ve spotted with the initial work is for single-line blocks. In some cases, you may still want a one-liner you can copy to clipboard, but the overlaid icon we’re displaying is slightly larger than default height for a single line, resulting in a bit of scrolling/interaction that doesn’t look great. We’re exploring what alternatives might be available for this use case, but suggestions very welcome

single-line

My one feedback is that the button for copying should always be visible. Mouseover buttons are far less discoverable and don’t really work on mobile.

2 Likes

My concern is that appending , copy after swift might break compatibility with standard Markdown parsers, potentially making the .docc Markdown files less portable across commonly used Markdown tools and viewers.

To minimize disruption, I’d suggest scoping this kind of non-standard syntax behind an @xx directive or similar mechanism, so that it remains internal and doesn’t affect general Markdown rendering.

That said, this also brings up a broader question: do we intend for .docc Markdown files to remain compatible with standard Markdown viewers? If so, we might want to avoid introducing syntax that deviates from widely supported Markdown conventions.

Additionally, taking inspiration from forums.swift.org, it might be worth exploring support for richer UI controls beyond just a ā€œCopyā€ button—such as a ā€œFullscreenā€ view for code blocks, which can greatly improve readability for long code samples.


Screenshot is taken from this topic: Why is `self` considered used-after-consume in coroutine accessors?

That’s a really good point. The parsing after the triple-back-tick setup was a bit of inspiration we took from how Rust is doing some of their additional annotations for docs, but yes - it means that other systems may render is awkwardly. One of the benefits of it is that it’s really light for authors to add, where DocC directives - while not hard - are more unwieldy, and their use in general within DocC content (aside from tutorials) has been notably curtailed from what it might have been. Not completely, but from what I’ve seen, there’s an emphasis on going as much with ā€œstock Markdownā€ - or closer variations to it - as possible.

As for the broader question of do we constrain the DocC markdown content to some set of ā€œpureā€ Markdown, that’s already been answered: ā€œnoā€ - there’s already a DocC dialect of markdown in that DocC support term lists, where something like GH flavored markdown does not.

I agree that’s super interesting, but also significantly broader in scope of impact and implementation, so at the moment I’m not aiming at trying to tackle anything that dramatically changes the layout of the page or the composition of how it’s all laid out. Not to say that anyone else shouldn’t, Its just not what I’m after at the moment.

While ```yaml,copy creates a situation where syntax highlighting is lost in a non-DocC renderer, using a directive means that the directive is just pasted wholesale into the rendered output, which i would consider to be even more disruptive.

As @Joseph_Heck said, DocC has already diverged from GitHub-Flavored Markdown with the introduction of term-definition lists, with column alignment markers in tables, and even with directives in the first place. (Tables themselves are already an extension from basic Markdown!) Expecting Markdown to be interoperable is already an uphill battle once you try to get past the modest feature set from the original Markdown.pl implementation. Adding extra information to the language tag in a fenced code block feels like the least-invasive option for simple configuration flags like this.

2 Likes

I’d also say that aligning with rust means that its more likely tools with understand this syntax instead of design yet another bespoke flavor.