feat: support custom theme.

feat: support to set default theme color and css variable prefix options.
This commit is contained in:
HPCesia 2024-10-21 16:40:34 +08:00
parent b3068350db
commit c03510a8a7
3 changed files with 47 additions and 14 deletions

View File

@ -1,4 +1,6 @@
# Hexo-Highlight-Shiki
![NPM Version](https://img.shields.io/npm/v/hexo-highlighter-shiki?style=flat)
English丨[简体中文](README_zh-CN.md)
A hexo plugin to use [Shiki](https://github.com/shikijs/shiki) as code block highlighter.
@ -33,11 +35,15 @@ The complete configuration is as follows:
```yaml
shiki:
theme: one-dark-pro # see https://shiki.style/themes for supported themes.
line_number: false
strip_indent: true
tab_replace: " "
pre_style: true # Preserve the style of the <pre> tag, i.e., the theme's `background-color`.
line_number: false # default: false
strip_indent: true # default: true
tab_replace: " " # default: " "
pre_style: true # Preserve the style of the <pre> tag, i.e., the theme's `background-color`. default: true
default_color: light # Only take effect when using multiple themes. default: light
css_variable_prefix: --shiki- # Only take effect when using multiple themes. default: --shiki-
additional:
themes: # List of the TextMate theme json to be added.
- path/to/theme.json
langs: # List of the TextMate grammar json of languages to be added.
- path/to/lang_grammar.json
lang_alias: # List of the alias of languages.

View File

@ -1,4 +1,6 @@
# Hexo-Highlight-Shiki
![NPM Version](https://img.shields.io/npm/v/hexo-highlighter-shiki?style=flat)
[English](README.md)丨简体中文
一个使用 [Shiki](https://github.com/shikijs/shiki) 作为代码块高亮器的 Hexo 插件。
@ -31,15 +33,18 @@ shiki:
完整配置如下:
```yaml
shiki:
theme: "one-dark-pro" # Theme, see https://shiki.style/themes for supported themes.
theme: "one-dark-pro" # 主题,请参阅 https://shiki.style/themes 以获取支持的主题列表。
line_number: false
strip_indent: true
tab_replace: " "
pre_style: true # Preserve the style of the <pre> tag, i.e., the theme's `background-color`.
pre_style: true # 保留 <pre> 标签的样式,即主题的 `background-color`
default_color: light # 仅在同时使用多个主题时生效。默认值light
css_variable_prefix: --shiki- # 仅在同时使用多个主题时生效。默认值:--shiki-
additional:
langs: # List of the TextMate grammar json of languages to be added.
themes: # 要添加的主题的 TextMate 主题 json 列表。
langs: # 要添加的语言的 TextMate 语法 json 列表。
- path/to/lang_grammar.json
lang_alias: # List of the alias of languages.
lang_alias: # 语言的别名列表。
your_alias1: lang_name1
your_alias2: lang_name2
```

View File

@ -1,5 +1,5 @@
"use strict";
import { bundledLanguages, createHighlighter, ShikiTransformer } from "shiki";
import { bundledLanguages, bundledThemes, createHighlighter, ShikiTransformer } from "shiki";
import type Hexo from "hexo";
import { HighlightOptions } from "hexo/dist/extend/syntax_highlight";
import { stripIndent, htmlTag } from "hexo-util";
@ -13,22 +13,41 @@ export async function init(hexo: Hexo) {
strip_indent: true,
tab_replace: " ",
pre_style: true,
default_color: "light",
css_variable_prefix: "--shiki-",
additional: {
themes: [],
langs: [],
lang_alias: {},
},
},
hexo.config.shiki || {}
);
// 处理自定义语言 json
let additional_langs = [];
if (config.additional.langs)
for (const extra_lang of [].concat(config.additional.langs)) {
additional_langs.push(JSON.parse(readFileSync(extra_lang, "utf8")));
}
const langs = [...Object.keys(bundledLanguages), ...additional_langs];
// 处理自定义主题 json
let additional_themes = [];
if (config.additional.themes)
for (const extra_theme of [].concat(config.additional.themes)) {
additional_themes.push(JSON.parse(readFileSync(extra_theme, "utf8")));
}
const themes = additional_themes.concat(
(typeof config.theme === "string" ? [config.theme] : Object.values(config.theme)).filter(
(theme) => theme in bundledThemes
)
);
// 创建 highlighter
let highlighter_options = {
langs: langs,
themes: typeof config.theme === "string" ? [config.theme] : Object.values(config.theme),
themes: themes,
};
if (config.additional.lang_alias && Object.keys(config.additional.lang_alias).length > 0) {
highlighter_options["langAliases"] = config.additional.lang_alias;
@ -45,6 +64,7 @@ export async function init(hexo: Hexo) {
ansi: true,
}
);
const hexoHighlighter = (code: string, options: HighlightOptions) => {
var code = config.strip_indent ? (stripIndent(code) as string) : code;
code = config.tab_replace ? code.replace(/\t/g, config.tab_replace) : code;
@ -57,7 +77,7 @@ export async function init(hexo: Hexo) {
// 处理代码块语法高亮
let pre = "";
const transformer = (): ShikiTransformer => {
const transformerMarkedLine = (): ShikiTransformer => {
return {
line(node, line) {
if (options.mark && options.mark.includes(line)) {
@ -71,13 +91,15 @@ export async function init(hexo: Hexo) {
pre = highlighter.codeToHtml(code, {
lang,
theme: config.theme,
transformers: [transformer()],
transformers: [transformerMarkedLine()],
});
else
pre = highlighter.codeToHtml(code, {
lang,
themes: config.theme,
transformers: [transformer()],
transformers: [transformerMarkedLine()],
defaultColor: config.default_color,
cssVariablePrefix: config.css_variable_prefix,
});
// 删除多余内容
pre = pre.replace(/<pre[^>]*>/, (match) => {
@ -97,7 +119,7 @@ export async function init(hexo: Hexo) {
(options.line_number || true) && // 代码块中未设置不显示行号
(options.line_threshold || 0) < options.lines_length; // 代码行数超过阈值
if (show_line_number) {
const firstLine = options.firstLine || 1
const firstLine = options.firstLine || 1;
for (let i = firstLine, len = code.split("\n").length + firstLine; i < len; i++) {
numbers += htmlTag("span", { class: "line" }, `${i}`, false) + "<br>";
}