Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ module.exports = {
routeBasePath: "/",
sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/codewars/docs/edit/master/",
beforeDefaultRemarkPlugins: [createHighlighter({ theme: "nord" })],
beforeDefaultRemarkPlugins: [
createHighlighter({
themes: ["github-dark-dimmed", "github-light"],
}),
],
},
blog: false,
theme: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"postcss-nested": "^5.0.5",
"postcss-preset-env": "^6.7.0",
"prettier": "^2.2.1",
"shiki": "^0.9.3",
"shiki": "^0.10.1",
"tailwindcss": "^2.2.2",
"unist-util-visit": "^2.0.3"
}
Expand Down
14 changes: 14 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,17 @@ html[data-theme="dark"] .DocSearch {
var(--ifm-color-emphasis-100) 100%
);
}

html[data-theme="dark"] pre.github-light {
display: none;
}

html[data-theme="light"] pre.github-dark-dimmed {
display: none;
}

html[data-theme="light"] pre.github-light {
outline-style: solid;
outline-width: 1px;
outline-color: #d1d5db;
}
262 changes: 99 additions & 163 deletions src/remark/shiki/index.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,15 @@
const fs = require("fs");
const path = require("path");

const { getHighlighter, BUNDLED_LANGUAGES } = require("shiki");
const { getHighlighter } = require("shiki");
const visit = require("unist-util-visit");

const syntaxPath = (name) =>
path.resolve(__dirname, `./languages/${name}.tmLanguage.json`);

const langs = new Set([
"asm",
"c",
"clojure",
"cobol",
"coffee",
"cpp",
"crystal",
"csharp",
"css",
"d",
"dart",
"elixir",
"elm",
"erlang",
"fsharp",
"go",
"groovy",
"haskell",
"html",
"java",
"javascript",
"json",
"jsonc",
"jsx",
"julia",
"kotlin",
"latex",
"lisp",
"lua",
"markdown",
"mdx",
"nim",
"objc",
"ocaml",
"pascal",
"perl",
"php",
"powershell",
"prolog",
"purescript",
"python",
"r",
"raku",
"ruby",
"rust",
"scala",
"shell",
"solidity",
"sql",
"swift",
"toml",
"tsx",
"typescript",
"vb",
"yaml",
]);

const languages = BUNDLED_LANGUAGES.filter((lang) => {
return (
langs.has(lang.id) ||
(lang.aliases && lang.aliases.some((id) => langs.has(id)))
const grammar = (name) =>
JSON.parse(
fs.readFileSync(
path.resolve(__dirname, `./languages/${name}.tmLanguage.json`)
)
);
});

// Remap language id to match Shiki.
const remapLanguageId = (id) => {
Expand All @@ -86,113 +26,109 @@ const remapLanguageId = (id) => {
// Use shiki for syntax highlighting.
// TODO Decoration. Like Docusaurus builtin, or https://github.com/shikijs/shiki/issues/5
// or https://github.com/andrewbranch/gatsby-remark-vscode#line-highlighting
const createHighlighter = ({ theme = "nord" } = {}) => {
const createHighlighter = ({ themes = ["nord"] } = {}) => {
// Reuse the same instance
const highlighterPromise = getHighlighter({
theme,
langs: languages.concat([
// See languages/README.md for sources.
// TODO Open PR upstream
{
id: "fortran",
scopeName: "source.fortran.free",
path: syntaxPath("fortran"),
},
{
id: "idris",
scopeName: "source.idris",
path: syntaxPath("idris"),
},
{
id: "haxe",
scopeName: "source.hx",
path: syntaxPath("haxe"),
},
{
id: "racket",
scopeName: "source.racket",
path: syntaxPath("racket"),
},

// TODO Remove these after a new shiki is released
{
id: "nim",
scopeName: "source.nim",
path: syntaxPath("nim"),
},
{
id: "r",
scopeName: "source.r",
path: syntaxPath("r"),
},
{
id: "raku",
scopeName: "source.perl.6",
path: syntaxPath("raku"),
},
]),
});
const highlighterPromise = getHighlighter({ themes }).then(
async (highlighter) => {
const langs = [
// See languages/README.md for sources.
{
id: "factor",
scopeName: "source.factor",
grammar: grammar("factor"),
},
{
id: "fortran",
scopeName: "source.fortran.free",
grammar: grammar("fortran"),
},
{
id: "idris",
scopeName: "source.idris",
grammar: grammar("idris"),
},
{
id: "haxe",
scopeName: "source.hx",
grammar: grammar("haxe"),
},
{
id: "racket",
scopeName: "source.racket",
grammar: grammar("racket"),
},
];
for (const lang of langs) await highlighter.loadLanguage(lang);
return highlighter;
}
);

return () => async (tree) => {
const highlighter = await highlighterPromise;
const fg = highlighter.getForegroundColor();
const bg = highlighter.getBackgroundColor();

visit(tree, "code", (node) => {
// const meta = node.meta;
const lang = node.lang || "text";
const code = node.value;
let tokenLines = null;
try {
tokenLines = highlighter.codeToThemedTokens(
code,
remapLanguageId(lang)
);
} catch (e) {
if (/^No language registration for/.test(e.message)) {
console.warn(`shiki: ${e.message}`);
console.warn(`shiki: Falling back to "text"`);
tokenLines = highlighter.codeToThemedTokens(code, "text");
} else {
throw e;
}
}

let html = `<pre class="${theme}" style="background-color: ${bg}">`;
html += `<code class="language-${lang}">`;
for (const line of tokenLines) {
html += `<span>`;
for (const token of line) {
const css = [`color: ${token.color || fg}`];
switch (token.fontStyle) {
case -1: // NotSet
case 0: // None
break;
case 1: // Italic
css.push(`font-style: italic`);
break;
case 2: // Bold
css.push(`font-weight: bold`);
break;
case 4: // Underline
css.push(`text-decoration: underline`);
break;
}
const content = escapeHtml(token.content);
html += `<span style="${css.join("; ")}">${content}</span>`;
}
html += `</span>\n`;
}

html = html.replace(/\n*$/, ""); // get rid of trailing new lines
html += `</code></pre>`;

node.value = html;
node.value = themes
.map((theme) =>
codeToHtml(highlighter, node.value, node.lang || "text", theme)
)
.join("");
node.type = "html";
});
};
};

const codeToHtml = (highlighter, code, lang, theme) => {
let tokenLines = null;
try {
tokenLines = highlighter.codeToThemedTokens(
code,
remapLanguageId(lang),
theme
);
} catch (e) {
if (/^No language registration for/.test(e.message)) {
console.warn(`shiki: ${e.message}`);
console.warn(`shiki: Falling back to "text"`);
tokenLines = highlighter.codeToThemedTokens(code, "text", theme);
} else {
throw e;
}
}

const fg = highlighter.getForegroundColor(theme);
const bg = highlighter.getBackgroundColor(theme);

let html = `<pre class="${theme}" style="background-color: ${bg}">`;
html += `<code class="language-${lang}">`;
for (const line of tokenLines) {
html += `<span>`;
for (const token of line) {
const css = [`color: ${token.color || fg}`];
switch (token.fontStyle) {
case -1: // NotSet
case 0: // None
break;
case 1: // Italic
css.push(`font-style: italic`);
break;
case 2: // Bold
css.push(`font-weight: bold`);
break;
case 4: // Underline
css.push(`text-decoration: underline`);
break;
}
const content = escapeHtml(token.content);
html += `<span style="${css.join("; ")}">${content}</span>`;
}
html += `</span>\n`;
}

html = html.replace(/\n*$/, ""); // get rid of trailing new lines
html += `</code></pre>`;
return html;
};

module.exports = { createHighlighter };

const HTML_ESCAPES = Object.freeze({
Expand Down
9 changes: 1 addition & 8 deletions src/remark/shiki/languages/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
Additional languages for shiki.

- Factor https://github.com/DexterHaslem/vscode-factor
- Fortran https://github.com/krvajal/vscode-fortran-support
- Haxe https://github.com/vshaxe/haxe-TmLanguage
- Idris https://github.com/zjhmale/vscode-idris
- Racket https://github.com/pouyakary/vscode-racket

## Included in unreleased version

These should be removed when a new version of shiki is released.

- Nim https://github.com/pragmagic/vscode-nim
- R https://github.com/Ikuyadeu/vscode-R
- Raku https://github.com/Raku/atom-language-perl6
Loading