Clover 代码块高亮示例
在 Markdown 中使用 27 项代码块能力:注释、焦点、行状态、折叠、链接、标签页、占位符与在线运行。
starlight-codeblocks 在 Expressive Code 之上加了 27 项代码块能力。多数功能只有在代码块使用对应属性或注释指令时才启动,所以普通代码块不会受到影响;文件图标、颜色色块、词级 diff、智能 shell 复制和 API 自动链接则会对匹配的代码块自动生效。
下面按文档的分组逐项演示。每个代码块本身就是可交互的示例,行内说明文字里的语法写在反引号中,方便直接复制。
解释代码
行内提示
注释写在目标行末尾,或者单独写在目标行上一行。[!callout /文本/] 的箭头会指向该行第一次出现的这个文本。
const controller = new AbortController();让 controller.abort() 可以取消请求。const res = await fetch(url, { signal: controller.signal });注解
注释放在行尾,点击行尾的编号才展开说明,适合“大部分读者可以跳过”的长注释。
jobs: test: runs-on: ubuntu-latest使用 GitHub 托管的 Ubuntu runner。
steps: - uses: actions/checkout@v4先检出仓库,后续步骤才能读到源码。
- run: pnpm test- 使用 GitHub 托管的 Ubuntu runner。
- 先检出仓库,后续步骤才能读到源码。
侧边注解
在围栏行加 annotations="side",注释会排到代码右侧;窄屏会自动变成代码下方的编号列表。
with path.open() as fh: return list(csv.DictReader(fh))- Note 1, for line 1: 打开文件,退出缩进块时自动关闭。
- Note 2, for line 2: 每行变成一个以表头为键的字典。
脚注
和注解类似,但所有说明直接列在代码块下方;适合“每条说明都必须看到”的短代码块。
滚动讲解
<Scrollycoding> 让代码固定在视口中,右侧的步骤随页面滚动,每步聚焦对应行。只能写在 MDX 里。
import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);代码走查
<CodeWalkthrough> 把同一个文件的多个版本合成一个带步骤按钮的代码块,适合“先写骨架、再加功能”的教程。
import express from "express";
const app = express();app.listen(3000);import express from "express";
const app = express();app.get("/", (_req, res) => res.send("ok"));app.listen(3000);import express from "express";
const app = express();app.use(express.json());app.get("/", (_req, res) => res.send("ok"));app.listen(3000);代码提及
正文里的链接和代码块里的 [!mention 名称] 标签配对;鼠标移到链接上时,对应行会高亮。
下面的 终止条件 决定递归什么时候停止。
def factorial(n): if n == 0: return 1 return n * factorial(n - 1)标记代码
焦点
围栏行写 focus={4-7},或者在目标行写 [!code focus]。非焦点行会变模糊,鼠标悬停代码块或键盘聚焦时恢复清晰。
import { defineConfig } from "./lib.js";
export default defineConfig({ cache: { dir: ".cache", maxAge: 3600, }, retries: 2,});行状态
给整行加错误、警告、提示、成功状态,并可以附带一条消息。
Error:for name in sys.argv[1:]Error SyntaxError: expected ':' print(name)Warning:count = len(sys.argv)Warning Includes the script name[!code ++]、[!code --]、[!code highlight] 用于没有语义的行增删与高亮:
const cache = new Map();const cache = new Map([["max", 100]]);cache.set("ttl", 60);自定义状态可以在 codeblocks({ lineStates: { states: { todo: … } } }) 中注册,然后使用 todo={9} 或 [!code todo]。
波浪线
给一个词或表达式画波浪线,消息在悬停或键盘聚焦时出现。
import { join (Warning: join is declared but its value is never read.)Warningjoin is declared but its value is never read. } from "node:path";const config = await readFle (Error: Cannot find name readFle. Did you mean readFile?)ErrorCannot find name readFle. Did you mean readFile?("config.json");- Line 1, warning:
joinis declared but its value is never read. - Line 2, error: Cannot find name
readFle. Did you meanreadFile?
让代码更好读
隐藏行
把“运行时需要、理解时不需要”的行收进一条虚线标记。复制按钮仍然会复制它们。
const port = Number(process.env.PORT ?? 3000);createServer(handler).listen(port);可展开块
长文件先显示前几行,读者点按钮再看完整内容。expandable 使用站点默认行数(12 行),expandable={8} 可以按块指定。
import { createRouter } from "./router.js";
const router = createRouter();
router.get("/", home);router.get("/about", about);router.get("/posts", listPosts);router.get("/posts/:slug", showPost);router.post("/posts", createPost);router.put("/posts/:slug", updatePost);router.delete("/posts/:slug", deletePost);
export default router;可见空白
需要强调缩进或制表符时使用。whitespace 只显示行首空白,whitespace="all" 连词间和行尾的空白也显示。
def greet(name): if name: return f"Hello, {name}" return "Hello"彩色括号
按嵌套深度给 ()、[]、{} 循环上色;悬停任意括号会描出它的配对括号。
{ "users": [ { "id": 1, "roles": ["admin", "editor"] }, { "id": 2, "roles": ["viewer"] } ]}颜色色块
CSS 颜色前会出现对应颜色的小色块;悬停显示色值,点击可以复制。其他语言里,引号中的颜色值或 :、=、, 之后的颜色也会识别。
.button { color: #2563eb; background: rgb(15 23 42 / 0.9); border-color: oklch(0.72 0.15 250);}文件图标
代码块有 title 时自动根据文件名显示图标;icon="react" 可以手动指定,no-icon 或 icon=false 关闭。
export default function App() { return <main>Hello</main>;}行内代码高亮
在反引号内的代码末尾加 {:语言},行内代码会使用对应语言的语法颜色。后缀必须写在反引号里,否则 MDX 会把它当成表达式。
安装依赖:pnpm add starlight-codeblocks。计算长度:const total = items.length。
词级 diff
新增/删除行中真正变化的词会加深色块和下划线,适合一行里只改了一个词的情况。
const timeout = 5000;const timeout = options.timeout ?? 5000;链接代码
代码链接
用 [!link /文本/ 地址] 给代码中的一个词加链接,后面的文字会显示在悬停卡片里。
API 自动链接
Python 和 Nextflow 的库名会自动链接到官方文档,不需要在代码里写任何东西。下面的 os、Path 及其属性会变成链接。
行永久链接
给代码块一个唯一的 id,行号会变成链接,例如 #timeout-config-L3;按住 Shift 再点另一个行号可以选中范围。
export const DEFAULT_TIMEOUT = 5000;export const MAX_TIMEOUT = 30000;export const timeoutFor = (retries) => DEFAULT_TIMEOUT * (retries + 1);适应读者
代码标签页
:::code-tabs 把多个代码块合成一个带标签的块;sync 让同一页面中相同的键一起切换。
npm install starlight-codeblockspnpm add starlight-codeblocksyarn add starlight-codeblocks填空占位符
把需要读者替换的值写进 placeholder,每个匹配都会变成输入框,输入一次会同步到所有字段和复制内容。
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://api.example.com/workspaces/WORKSPACE_ID/runs复制与运行
智能 shell 复制
终端代码块里有提示符时,会自动出现 Copy commands 按钮,只复制命令,不复制提示符和输出。
$ uv tool install ruffResolved 1 package in 180ms$ ruff check src/ \ --fix在 Playground 打开
给代码块加 playground="typescript" 或 playground="rust",标题栏会出现跳转到在线 Playground 的按钮。
const sum = (values: number[]) => values.reduce((a, b) => a + b, 0);console.log(sum([1, 2, 3]));运行代码
runnable 让 JavaScript、TypeScript、Python 代码直接在页面里运行。JavaScript 使用内置运行时:
const values = [1520, 1610, 1480];const mean = values.reduce((a, b) => a + b, 0) / values.length;console.log(mean);Python 会在第一次点击时加载 Pyodide:
对于不能真正运行的命令,可以用 [!output] 预先写好输出,按钮会按行“播放”:
nextflow run hello.nf组合使用
多个特性可以叠加,但同一条说明最好只用一种注解方式。下面这个块同时使用了焦点、行内提示和行状态:
import { Worker } from "node:worker_threads";
const controller = new AbortController();用同一个 signal 控制所有请求。Note:const worker = new Worker("./worker.js", { signal: controller.signal });Note 传入 signal,便于统一取消worker.postMessage({ type: "start" });
export default worker;以上覆盖了 starlight-codeblocks 的全部功能分组。实际使用时不必一次打开所有能力:它们都按需启动,只有真正用到属性或指令的代码块才会加载对应的客户端脚本。
版权声明
本文由 XiaYe 创作,采用 CC BY-NC-SA 4.0 许可协议;转载请注明出处。
- 作者
- XiaYe
- 发布于
- 许可协议
- CC BY-NC-SA 4.0
分享这篇文章:
相关文章
评论
留下你的想法,或看看别人说了什么。