-
-
Notifications
You must be signed in to change notification settings - Fork 9k
Document how to use Prism Plugins / add Prism diff-highlight plugin #3318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
We use react-prism-renderer and it does not seem to support the ability to add such plugin, so unfortunately we can't support this unless they add support, but that seems not planned: |
Implemented diff-highlight compatible with docusaurus (prism-react-renderer) You need to swizzle in your docusaurus repo: yarn swizzle @docusaurus/theme-classic prism-include-languages
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
additionalLanguages: ["diff", "diff-ts"],
},
import siteConfig from "@generated/docusaurus.config";
import type * as PrismNamespace from "prismjs";
import { diffHighlight } from "./prism-diff-highlight";
import "./prism-diff-highlight.css";
const DIFF_LANGUAGE_REGEX = /^diff-([\w-]+)/i;
export default function prismIncludeLanguages(
PrismObject: typeof PrismNamespace
): void {
const {
themeConfig: { prism },
} = siteConfig;
const { additionalLanguages } = prism as { additionalLanguages: string[] };
// Prism components work on the Prism instance on the window, while prism-
// react-renderer uses its own Prism instance. We temporarily mount the
// instance onto window, import components to enhance it, then remove it to
// avoid polluting global namespace.
// You can mutate PrismObject: registering plugins, deleting languages... As
// long as you don't re-assign it
globalThis.Prism = PrismObject;
additionalLanguages.forEach((lang) => {
const langMatch = DIFF_LANGUAGE_REGEX.exec(lang);
if (!langMatch) {
require(`prismjs/components/prism-${lang}`); // not a language specific diff
} else {
if (!PrismObject.languages.diff) {
console.error(
"prism-include-languages:",
"You need to import 'diff' language first to use 'diff-xxxx' languages"
);
}
PrismObject.languages[lang] = PrismObject.languages.diff;
}
});
diffHighlight(PrismObject);
delete globalThis.Prism;
}
import { EnvConfig, PrismLib } from "prism-react-renderer";
import { TokenStream, Token } from "prismjs";
const LANGUAGE_REGEX = /^diff-([\w-]+)/i;
const tokenStreamToString = (tokenStream: TokenStream): string => {
const result: string[] = [];
const stack: TokenStream[] = [tokenStream];
while (stack.length > 0) {
const item = stack.pop();
if (typeof item === "string") {
result.push(item);
} else if (Array.isArray(item)) {
for (let i = item.length - 1; i >= 0; i--) {
stack.push(item[i]);
}
} else {
// If it's a Token, convert it to a string and push it
stack.push(item.content);
}
}
return result.join("");
};
export function diffHighlight(Prism: PrismLib) {
Prism.hooks.add("after-tokenize", function (env: EnvConfig) {
let diffLanguage;
let diffGrammar;
const language = env.language;
if (language !== "diff") {
const langMatch = LANGUAGE_REGEX.exec(language);
if (!langMatch) {
return; // not a language specific diff
}
diffLanguage = langMatch[1];
diffGrammar = Prism.languages[diffLanguage];
if (!diffGrammar) {
console.error(
"prism-diff-highlight:",
`You need to add language '${diffLanguage}' to use '${language}'`
);
return;
}
} else return;
const newTokens = [];
env.tokens.forEach((token) => {
if (typeof token === "string") {
newTokens.push(...Prism.tokenize(token, diffGrammar));
} else if (token.type === "unchanged") {
newTokens.push(
...Prism.tokenize(tokenStreamToString(token), diffGrammar)
);
} else if (["deleted-sign", "inserted-sign"].includes(token.type)) {
token.alias = [
token.type === "deleted-sign"
? "diff-highlight-deleted"
: "diff-highlight-inserted",
];
// diff parser always return "deleted" and "inserted" lines with content of type array
if (token.content.length > 1) {
const newTokenContent: Array<string | Token> = [];
// preserve prefixes and don't parse them again
// subTokens from diff parser are of type Token
(token.content as Array<string | Token>).forEach(
(subToken: Token) => {
if (subToken.type === "prefix") {
newTokenContent.push(subToken);
} else {
newTokenContent.push(
...Prism.tokenize(tokenStreamToString(subToken), diffGrammar)
);
}
}
);
token.content = newTokenContent;
}
newTokens.push(token);
} else if (token.type === "coord") {
newTokens.push(token);
}
});
console.log(newTokens);
env.tokens = newTokens;
});
}
code .token.diff-highlight-deleted {
background-color: rgba(255, 0, 0, .1);
}
code .token.diff-highlight-inserted {
background-color: rgba(0, 255, 128, .1);
}
code .token.coord {
font-weight: 700;
}
You can add whatever other language you want in additionalLanguages: ["diff", "diff-ts", "powershell", "diff-powershell"], NOTE FOR DEVS/INTERESTED PEOPLE: Prism plugins do not work with prism-react-renderer because they rely in other hooks that are not called. They only call hooks In theory every plugin could be re-implemented using those hooks to work with prism-react-renderer EDIT: Code Update using typescript |
I think you can write you own component to display $ npm install --save react-diff-view I am using version 3.2.1. (https://www.npmjs.com/package/react-diff-view) Create your component
import {Decoration, Diff, Hunk, parseDiff} from "react-diff-view";
import 'react-diff-view/style/index.css';
import './CustomDiff.css';
export default function CustomDiff({diffText}) {
const files = parseDiff(diffText);
return (
<div>
{files.map((
{hunks, newPath, oldPath}, i) =>
<Diff
renderToken={(token) => token.content}
key={i}
viewType="split"
diffType=""
hunks={hunks}
>
{
hunks => hunks.map(hunk => {
return <>
<Decoration key={'decoration-' + hunk.content}>
{`${oldPath}`}
</Decoration>
<Decoration key={'decoration-' + hunk.content}>
{`${newPath} - ${hunk.content}`}
</Decoration>
<Hunk key={hunk.content} hunk={hunk} />
</>
}
)}
</Diff>
)}
</div>
);
} Css for your component.
:root {
--ifm-table-border-width: 0px;
}
table {
display: table;
}
.diff-code {
font-size: 85%;
} How to use it in markdown? import CustomDiff from "@site/src/components/CustomDiff/CustomDiff";
<CustomDiff diffText={`
diff --git a/package.json b/package.json
--- a/package.json (revision c38f44524532d3a87986bfa4b9b8b82d8f0e29a0)
+++ b/package.json (revision 93e71e98e457dae88403cdf204a8f4a85f60cc42)
@@ -1,6 +1,6 @@
{
"name": "SSO-Admin-UI",
- "version": "1.0.0",
+ "version": "2.0.0-alpha.0",
"license": "MIT",
"scripts": {
"start": "ng serve -o -c=dev --port=8500 --baseHref=/",
`}
/> |
@Repraance nice, this works really well! Only problem I have with this CSS is that the |
π Documentation
Prism comes with the ability to use prism plugins to add extra functionalities β such as diff-highlight to combine the syntax highlighting of a language with the
diff
feature.It is currently unclear how to enable prism plugins.
I've tried playing with
swizzle
to extract the code-highlighting renderer, but failed to implement this feature.Cross-reference:
Have you read the Contributing Guidelines on issues?
Yes
The text was updated successfully, but these errors were encountered: