facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
54.17k stars 8.12k forks source link

Support asciidoc source code callouts in CodeBlock #10108

Open jaune162 opened 2 months ago

jaune162 commented 2 months ago

Have you read the Contributing Guidelines on issues?

Description

Example: https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/#literals-and-source-code

image

image

Has this been requested on Canny?

No response

Motivation

This feature is very useful for explaining the complex parts of the source code in the document

API design

No response

Have you tried building it?

No response

Self-service

baldram commented 1 month ago

That would be a really cool feature, and I'd definitely use something like that if it were so simple. Meanwhile, you could potentially do it with the Custom Magic Comments functionality (https://docusaurus.io/docs/3.0.1/markdown-features/code-blocks#custom-magic-comments), converting it to numbers with CSS.

jaune162 commented 1 month ago

This approach seems difficult to implement. I think there has two way to implement this feature.

  1. Eject a CodeBlock/Line swizzle
  2. a prism plugin

I think the latter is better,but I don't know how to register a Prism plugin in docusaurus config.

jaune162 commented 1 month ago

There is the simple implement. but just code-block

import React from 'react';
import clsx from 'clsx';
import type { Props } from '@theme/CodeBlock/Line';

import styles from './styles.module.css';
import type { TokenInputProps, TokenOutputProps } from 'prism-react-renderer';

export default function CodeBlockLine(
    {
        line,
        classNames,
        showLineNumbers,
        getLineProps,
        getTokenProps
    }: Props): JSX.Element {
    if (line.length === 1 && line[0]!.content === '\n') {
        line[0]!.content = '';
    }

    const lineProps = getLineProps({
        line,
        className: clsx(classNames, showLineNumbers && styles.codeLine)
    });

    const lineTokens = line.map((token, key) => {
        console.log(token, key);
        return (<span key={key} {...getCommentCalloutTokenProps({token, key}, getTokenProps)} />)
    });

    return (
        <span {...lineProps}>
              {showLineNumbers ? (
                  <>
                      <span className={styles.codeLineNumber}/>
                      <span className={styles.codeLineContent}>{lineTokens}</span>
                  </>
              ) : (
                  lineTokens
              )}
            <br/>
        </span>
    );
}

const commentCalloutRegex = /^(\/\/\s+)(<)(\d{1,2})(>)$/;

function getCommentCalloutTokenProps(input: TokenInputProps, original: Function): TokenOutputProps {
    if (input.token.types[0] === 'comment' && input.token.content.match(commentCalloutRegex)) {
        const matches = input.token.content.match(commentCalloutRegex)
        return {
            className: styles.commentCallout,
            children: matches[3]
        }
    } else {
        return original(input);
    }
}
.commentCallout {
  border-radius: 100%;
  display: inline-block;
  font-family: Roboto, sans-serif;
  font-size: 1rem;
  font-style: normal;
  color: white;
  background-color: black;
  border: 1px solid black;
  height: 1.25em;
  letter-spacing: -.25ex;
  line-height: 1.2;
  text-align: center;
  text-indent: -.25ex;
  width: 1.25em;
}

The follow code

public class A { // <1>

    public static void main(String[] args) { // <14>
        System.out.println("");
    }
}

Redner as:

image

But not elegant enough.

baldram commented 1 month ago
  1. a prism plugin

I think the latter is better,but I don't know how to register a Prism plugin in docusaurus config.

Hey @jaune162! I'm not really into frontend stuff, but I used Docusaurus for project documentation and made some tweaks, like adding magic comments. They're registered in the section where you can add the Prism plugin you mentioned.

I don't have any plugins set up, but I added an example line in my config to show how it would look.

image

There are repositories doing that, please see examples.

So, if option 2 is the way to go, it looks like it might be possible. What do you think?

jaune162 commented 1 month ago

@baldram Thanks. I will try it.

But there is no plugins option in the source code.

export type PrismConfig = {
  theme: PrismTheme;
  darkTheme?: PrismTheme;
  defaultLanguage?: string;
  additionalLanguages: string[];
  magicComments: MagicCommentConfig[];
};

I'm not sure is works.

baldram commented 1 month ago

@jaune162 Maybe in the repositories I found (some using Docusaurus 3.x), someone tried this, but it doesn't seem to work. 🤔 From the discussion here, it looks like it's nontrivial indeed, and people are hacking it in different ways. There's also a note for developers there.

slorber commented 1 month ago

Afaik the lib we use (prism-react-renderer) does not support Prism plugin.

stevemonaco commented 1 month ago

I implemented this using @jaune162 's approach overall with swizzle eject, but went a different direction. I wanted auto-counting and I wanted the callout indicators to always be on the left side.

I also needed to have callouts on lines where comments weren't possible (XML). asciidoc also has this issue. To work around this, I used magicComments and overrode the highlighting default:

magicComments: [
  {
    className: 'theme-code-block-callout-line',
    line: 'callout-this-line'
  }
]

The code-block starts off with:

```xml {1-5,8,11-13} showLineNumbers

And the result is:

image

Callouts outside of code blocks were created with a separate component and put into the doc like so:

<Callout id="1" /> `Window` is the root element consisting of the title bar, frame, and caption buttons drawn by the OS (by default).
stevemonaco commented 1 month ago

I'm going to detail some different designs / use cases that I stumbled into during the above implementation and might be considered by a feature implementer:

  1. Document Callout Trigger
    1. New Component (syntax?)
  2. Code Callout Trigger
    1. Comment
    2. Metadata string
  3. Code Callout Locations
    1. In-line (replace comment with callout indicator)
    2. Left margin
    3. Highlight+reuse the line count indicator itself as the Code Callout
  4. Labeling Code Callouts
    1. Manual (via comment content)
    2. Automatic numbering (via css count())
    3. Lettering instead of numbering?
  5. Automatic Number Count Roots
    1. Global (Starts at 1 and every callout increment in the document)
    2. Document (Starts at 1, increments only on document callouts)
    3. Global Code Block (Starts at 1, increments on every code block in document)
    4. Code Block (Resets to 1 in every code block)
    5. Callout Group Id (Each starts at 1)
  6. Callout Description
    1. Hyperlink anchor to/from Callouts (Code and Document) for quicker navigation
    2. Table integration for cleaner display
    3. Automatic numbering via number roots
baldram commented 1 month ago

I also needed to have callouts on lines where comments weren't possible (XML). asciidoc also has this issue

These are valid concerns.

To work around this, I used magicComments and overrode the highlighting default

In my case, the solution (inline comments) presented in the first comment will still be more convenient because the documents are not written manually. Code snippets are automatically extracted from the code based on appropriate markers. But it's not a big challenge. In this case, the parser generating the documentation will have to interpret the markers, remove them from the code, and replace them with the call as you showed.

I would probably feel better without auto-counting. It would be preferable if they could be specified explicitly (because, in practice, we will be marking individual lines anyway). However, this relies on different functionality that works the way it does, and we can't change that I guess. Besides, it's a very interesting approach.