写作指南

本指南列出当前博客实际启用的全部写作功能。除了标准 Markdown,本站还启用了 GFM、KaTeX、Expressive Code 代码块增强,以及提示块、Wiki 链接、脚注、图片图注等自定义扩展。

Frontmatter

每篇文章开头需要 YAML 格式的元数据,样例:

---
title: LibTooling架构解析(一):从 ClangTool 到 CompileInstance
published: 2026-02-21
updated: 2026-03-01
description: 深入剖析 LibTooling 核心架构与各组件协作机制。
tags: [LLVM, Clang, LibTooling]
category: LLVM
draft: false
---
字段必填说明
title✓文章标题。同时用于页面标题、文章列表和 RSS
published✓发布日期,格式 YYYY-MM-DD
description文章摘要。用于 SEO 元标签(<meta description>)、Open Graph 预览卡片、RSS 摘要。不直接显示在页面上
updated最后修改日期。设置后会在页面 date 旁边显示斜体 “updated xxxx”
tags标签数组,用于标签页和相关文章推荐
category一级分类,一篇文章只能属于一个分类
draft设为 true 则文章不会生成页面,也不会出现在列表、RSS、搜索索引和站点地图中

注意:updated 建议在内容有实质性修订时更新,小修改不必改。

src/pages/ 下的独立 Markdown 页面(例如 about.md 和本页)需要在 frontmatter 中声明布局;src/content/posts/ 下的文章由文章模板统一渲染,不需要该字段:

layout: ../layouts/MarkdownLayout.astro

独立页面只使用 MarkdownLayout,不会显示右侧目录、阅读时间、相关文章和评论区;这些是文章模板自动生成的功能。

文章正文不要再写一级标题:文章模板会使用 title 渲染页面 <h1>,正文从 ## 开始即可。

基础 Markdown 与 GFM

站点启用了 GFM(remark-gfm)和 smartypants,以下语法可以直接使用:

功能写法
标题## 二级标题、### 三级标题,最多到 ######
粗体 / 斜体**粗体**、*斜体*
删除线~~删除线~~
行内代码用一对反引号包裹,例如 code
链接[链接文字](https://example.com)
自动链接<https://example.com>
引用> 引用内容
无序列表- 项目 或 * 项目
有序列表1. 项目
任务列表- [ ] 未完成、- [x] 已完成
分隔线---
表格标准 GFM 表格,支持对齐
原生 HTML直接嵌入 <kbd>、<details> 等标签
转义\*、\_、\$ 等

标题会自动生成锚点 id,并出现在文章页右侧目录中;目录默认提取 h1 到 h3(可在 src/config.ts 的 tocConfig 中调整)。鼠标悬停在标题上会显示 # 锚点,点击即可跳转到该小节。

站点启用了 smartypants,正文中的直引号、--、... 会被转换为弯引号、破折号和省略号;代码块与行内代码中的字符不受影响。

表格

标准 GFM 表格,支持左/中/右对齐:

| 左对齐 | 居中 | 右对齐 |
| :--- | :---: | ---: |
| a | b | c |

移动端表格会横向滚动,不会撑破正文宽度。

代码块

基础用法

使用三反引号围栏代码块,并标注语言:

```cpp
auto matcher = clang::ast_matchers::functionDecl().bind("fn");
```

Expressive Code 会自动完成:

  • Shiki 语法高亮(主题为 github-light,深色模式会自动适配)
  • 行号显示(默认开启;bash、sh、shellsession 默认关闭)
  • 右上角复制按钮(终端框架复制时会自动去掉 # 开头的注释行)
  • 无标题且非终端框架时,右上角显示语言徽章(悬停时隐藏)
  • 自动换行(默认开启,可关闭)

代码块选项

选项写在语言标识之后,用空格分隔;值中如果有空格,需要用引号包起来:

选项说明示例
title显示文件名或标题title="src/main.cpp"
frame框架样式:auto、code、terminal、noneframe="terminal"
showLineNumbers是否显示行号showLineNumbers=false
startLineNumber起始行号startLineNumber=10
wrap是否自动换行wrap=false
preserveIndent自动换行时保留原缩进preserveIndent=false
hangingIndent折行部分的额外缩进列数hangingIndent=2
collapse折叠指定行范围collapse={5-12}
collapseStyle折叠样式collapseStyle="collapsible-start"

组合示例:

```cpp title="src/main.cpp" frame="code" showLineNumbers=true startLineNumber=1 wrap=true
int main() {
return 0;
}
```
  • frame="auto" 是默认值:终端语言使用终端框架,其余语言使用编辑器框架。
  • frame="code" 强制使用编辑器框架。
  • frame="terminal" 强制显示终端窗口样式;bash、sh、console、zsh 等终端语言会自动使用终端框架,也可以手动指定。
  • frame="none" 去掉外框,适合非常短的代码片段。
  • wrap=false 会关闭自动换行,超长行改为横向滚动。
  • preserveIndent=false 会让折行部分从第一列开始;hangingIndent 可以给折行部分增加额外缩进。

代码块前 4 行中如果有一行是文件名注释,Expressive Code 会自动把它提取为标题,并从代码中移除该行。例如:

src/main.cpp
```cpp
int main() {
return 0;
}
```

会显示标题 src/main.cpp,代码从 int main() 开始。支持 //、#、<!-- --> 和 /* */ 形式的注释。

文字高亮与行标记

Expressive Code 支持三种文字标记,分别对应黄色高亮、绿色插入和红色删除:

类型效果行标记写法文字标记写法
mark黄色高亮mark={2-3}mark="TODO"
ins绿色插入ins={5}ins="newValue"
del红色删除del={7}del="oldValue"

行标记示例:

```cpp mark={2-3} ins={5} del={7}
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 5;
int f = 6;
int g = 7;
```
  • 标记范围从代码块内的第一行开始计算,与 startLineNumber 无关。
  • 多个范围用逗号分隔,例如 mark={1,3-5};也可以重复写多个同名选项。
  • 文字标记会匹配该行中所有出现位置,并用 <mark>、<ins>、<del> 内联标出。字符串和正则都支持,例如 mark=/TODO|FIXME/。
  • 行标记可以带自定义标签,标签显示在左侧行号槽中:
```cpp mark={"重点":2-3}
int a = 1;
int b = 2;
int c = 3;
```

ins 和 del 同样支持 {"标签":行范围} 写法。标记颜色由 astro.config.ts 中的 styleOverrides.textMarkers 控制;深色模式下代码区会整体反色适配。

Diff 代码块

使用 diff 语言并保留 +/- 前缀即可显示增删行:

```diff lang="cpp"
- int x = 1;
+ int x = 2;
int y = 3;
```

+ 行显示为绿色插入,- 行显示为红色删除,未标记的行保持普通样式。lang="cpp" 会让 Expressive Code 继续使用 C++ 语法高亮,而不是按纯 diff 文本处理。

如果不想把语言写成 diff,也可以给任意语言加上 useDiffSyntax:

```cpp useDiffSyntax
+ int added = 1;
- int removed = 2;
int same = 3;
```

+/- 后需要一个空格;代码块的公共缩进会被自动移除。

折叠长代码

使用 collapse 折叠指定行范围(按代码块内行号,从 1 开始):

```cpp collapse={5-12}
// 第 1 行
// 第 2 行
// 第 3 行
// 第 4 行
// 第 5 行
// ... 被折叠
// 第 12 行
```

默认的 github 样式只显示一行 N collapsed lines 摘要,展开后不能再次折叠。若需要反复展开/折叠,可以指定:

  • collapseStyle="collapsible-start":折叠摘要保留在代码上方
  • collapseStyle="collapsible-end":折叠摘要保留在代码下方
  • collapseStyle="collapsible-auto":根据折叠区域位置自动选择

多个折叠范围用逗号分隔,例如 collapse={2-4,8-10}。折叠摘要默认会按代码的最小缩进对齐,设置 collapsePreserveIndent=false 可以关闭这一行为。

数学公式

使用 KaTeX 渲染。$...$ 是行内公式,$$...$$ 是块级公式:

行内:$\mathbf{A} \in \mathbb{R}^{m \times n}$
块级:
$$
\sum_{i=1}^{n} \lambda_i \mathbf{v}_i = \mathbf{0}
$$

块级公式建议单独成段,移动端可以横向滚动。需要显示美元符号本身时使用 \$ 转义。

提示块(Admonition)

使用 remark-directive 容器语法,支持五种类型:

:::note
这是普通注释。
:::
:::tip
这是技巧提示。
:::
:::important
这是重要说明。
:::
:::caution
这是注意事项。
:::
:::warning
这是警告信息。
:::
:::note[自定义标题]
带自定义标题的注释块。
:::

省略方括号时显示类型名的大写形式(NOTE、TIP、IMPORTANT、CAUTION、WARNING);[自定义标题] 可以覆盖默认标题,标题内也支持行内格式。提示块类型名请使用小写,块内部可以继续使用列表、代码块、公式、链接等 Markdown。

渲染效果:

自定义标题

提示块内可以包含 粗体、行内代码、列表和代码块。

Wiki 链接

使用 [[...]] 语法引用站内其他文章,路径相对于 src/content/posts/,不需要写 .md 扩展名:

详见 [[LLVM/Cores/write_a_pass]] 中的说明。

支持自定义显示文字:

详见 [[LLVM/Cores/write_a_pass|如何编写 Pass]]。

如果文件名在站内唯一,也可以省略目录:

参见 [[write_a_pass]]。

链接目标不存在时,原文会保持为普通文本,不会生成链接。建议优先写完整路径,避免文件名重复导致歧义。代码块和行内代码中的 [[...]] 不会被解析。

脚注

在正文中使用 [^标识符] 添加脚注引用,在文末或其他位置用 [^标识符]: 定义内容:

Clang Tooling 的核心抽象是 FrontendAction[^1] 和 ASTConsumer[^consumer]。
[^1]: FrontendAction 定义了在编译各阶段触发的回调接口。
[^consumer]: ASTConsumer 是 Clang AST 的入口点,通过 `HandleTranslationUnit()` 方法接收完整 AST。

脚注定义可以出现在文章任意位置,渲染时会统一排布在文章底部;点击 ↩ 可以回到引用位置。标识符可以使用数字或单词,但不能包含 ]。

图片与图注

![图片描述](path/to/image.png)
  • 图片单独成段时,alt 文本会自动作为图注显示在图片下方。
  • alt 同时用于无障碍描述和图片加载失败时的替代文本,务必填写。
  • 点击图片可以打开灯箱查看大图;点击背景、关闭按钮或按 Esc 退出。
  • 图注取自 alt,不是 Markdown 图片的 title。

本地图片建议放在文章同级目录下的 images/ 子目录中,通过相对路径引用:

![架构图](images/architecture.png)

Astro 会在构建时处理本地图片并生成优化后的资源;远程图片也可以直接使用 URL。

目录、锚点与自动生成内容

以下内容由文章模板自动生成,不需要在 Markdown 中手动维护:

功能说明
右侧目录文章页自动提取 h1–h3,可通过 src/config.ts 的 tocConfig 调整范围
标题锚点文章页标题自动生成 id;悬停显示 #,点击跳转到对应小节
阅读时间按正文去空白字符数除以 400 估算(最少 1 分钟),显示在发布日期旁
上一篇 / 下一篇按 published 日期排序自动生成
相关文章按共享 tags 数量选取最多 3 篇
评论文章底部自动加载 Giscus,按页面路径关联讨论
搜索构建时通过 Pagefind 生成全文索引
RSS/rss.xml 自动生成,description 作为摘要,草稿会被排除
站点地图构建时通过 sitemap 集成自动生成

内容组织

目录结构

文章按主题分目录存放于 src/content/posts/:

src/content/posts/
├── LLVM/
│ ├── clang/LibTooling1.md
│ ├── Cores/write_a_pass.md
│ └── Tools/vscode+clangd.md
├── PPA/1-数据流分析/
│ └── 1.0-数据流分析.md
├── AEM/1-矩阵分析/
│ └── ...
└── PL/C_Cpp/Templates/CRTP.md

文章路径即页面 URL:/posts/llvm/cores/write_a_pass/

站点会按 Astro 的 glob loader 规则生成 slug:字母转为小写,中文、数字、下划线和连字符保留,点号、加号等特殊字符会被移除,空格会转为连字符。为避免链接失效,文件名建议只使用小写字母、数字、-、_ 和中文,不要使用 #、?、% 等 URL 特殊字符。

图片存放

文章图片放在文章同级目录下的 images/ 子目录中,通过相对路径引用:

![架构图](images/architecture.png)

草稿与发布

将 frontmatter 中的 draft 设为 true 后,文章不会生成页面,也不会出现在首页、归档、分类/标签页、RSS、搜索索引和站点地图中。发布前改为 false 或删除该字段即可(默认为 false)。

完整示例

---
title: 一个完整的示例
published: 2026-11-13
description: 展示本站常用写作功能的组合方式。
tags: [LLVM, Clang]
category: LLVM
draft: false
---
## 背景
这里是一段普通正文,可以包含 **粗体**、*斜体*、`行内代码` 和 [外部链接](https://llvm.org)。
:::tip[提示]
提示块内可以放列表、公式和代码。
:::
## 代码
```cpp title="src/main.cpp" mark={2} ins={3}
int main() {
int value = 1;
return value;
}
```
## 公式
行内公式:$E = mc^2$。
$$
\int_0^1 x^2 \, dx = \frac{1}{3}
$$
## 参考
更多内容见 [[LLVM/Cores/write_a_pass]]。[^1]
[^1]: 这是一条脚注。