rehype-pretty / rehype-pretty-code

Beautiful code blocks for Markdown or MDX.
https://rehype-pretty.pages.dev
MIT License
1.05k stars 64 forks source link

Shiki v1.0 #171

Closed atomiks closed 8 months ago

atomiks commented 9 months ago

Shikiji was merged back into Shiki. Tracking this so we can upgrade once v1.0 is out of beta: https://github.com/shikijs/shiki/releases

rusakovic commented 9 months ago

Hello.

Trying to update your great plugin from 0.6.0 to 0.12.6. And don't know if it's related to your latest update. The idea is to pass somehow raw code string to <pre> as a prop to have copy/paste functionality of raw code.

Now my current approach doesn't work. Maybe you could suggest your official approach. Thank you

I have such an implementation

// INFO: To get code string in <pre> html block in mdx-components
const preProcess = () => (tree) => {
  visit(tree, (node) => {
    if (node?.type === "element" && node?.tagName === "pre") {
      const [codeEl] = node.children;

      if (codeEl.tagName !== "code") return;

      node.__rawString__ = codeEl.children?.[0].value;
      console.log(
        "🚀 ~ file: contentlayer.config.js:85 ~ visit ~ node.__rawString__:",
        node.__rawString__
      );

      node.properties = { rawString: codeEl.children?.[0].value };
      console.log("🚀 ~ file: contentlayer.config.js:91 ~ visit ~ node:", node);
    }
  });
};

const postProcess = () => (tree) => {
  visit(tree, "element", (node) => {
    if (node?.type === "element" && node?.tagName === "pre") {
      console.log(
        "🚀 ~ file: contentlayer.config.js:96 ~ visit ~ node:",
        JSON.stringify(node, null, 4)
      );
      node.properties["__rawString__"] = node.__rawString__;
    }
  });
};

export default makeSource({
  contentDirPath: "./src/content",
  documentTypes: [Doc],
  mdx: {
    remarkPlugins: [remarkGfm],
    rehypePlugins: [
      // INFO: need to ensure that your preProcess is first in your array of plugins
      preProcess,
      rehypeSlug,
      [
        rehypePrettyCode,
        {
          theme: {
            light: "github-light",
            dark: "github-dark-dimmed",
          },
        },
      ],
      [
        rehypeAutolinkHeadings,

      // INFO: need to ensure that your postProcess is last in your array of plugins,
      postProcess,
    ],
  },
});

and in mdx-components

  pre: ({
    className,
    __rawString__,
    ...props
  }: React.HTMLAttributes<HTMLPreElement> & { __rawString__?: string }) => {
    console.log(
      "🚀 ~ file: mdx-components.tsx:167 ~ __rawString__:",
      __rawString__
    );
    return (
      <div className="relative">
        <pre
          data-theme="github-dark-dimmed github-light"
          className={ className}
          {...props}
        />
        {__rawString__ && (
          <CopyButton
            value={__rawString__}
            className={cn("absolute right-3 top-3")}
          />
        )}
      </div>
    );
  },

Update 1: This approach doesn't work with a new version https://claritydev.net/blog/copy-to-clipboard-button-nextjs-mdx-rehype

atomiks commented 9 months ago

I'm not 100% sure, but it may be related to not preserving properties on nodes after highlighting creates new nodes. There was another issue with code.data, which was fixed like so:

https://github.com/atomiks/rehype-pretty-code/blob/5535ddbb6e1774598ccef1e8c29a6c357305141a/src/index.ts#L61

Instead of this single manual check, we can iterate through all properties and re-apply them, including the pre.

Specifically, it's likely these are being blown away:

node.__rawString__ = codeEl.children?.[0].value;
node.properties = { rawString: codeEl.children?.[0].value };
zce commented 8 months ago

shiki v1.0 is released