summaryrefslogtreecommitdiff
path: root/src/ast/parser/headings.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast/parser/headings.rs')
-rw-r--r--src/ast/parser/headings.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/ast/parser/headings.rs b/src/ast/parser/headings.rs
new file mode 100644
index 0000000..260efa4
--- /dev/null
+++ b/src/ast/parser/headings.rs
@@ -0,0 +1,104 @@
+use std::mem::replace;
+
+use crate::ast::{
+ Line,
+ parser::{ParserInternalStatus, ParserMatchResult},
+};
+
+#[derive(Default)]
+struct HeadingTmp {
+ /// 当前输入的层级
+ lvl: u8,
+
+ /// 是否正在输入标题前缀
+ typing_heading_prefix: bool,
+
+ /// 是否正在输入标题内容
+ typing_heading_content: bool,
+
+ // 第一个 Sharp 符号的位置
+ first_sharp_col: Option<u16>,
+}
+
+pub(crate) fn proc(c: &char, inr: &mut ParserInternalStatus) -> ParserMatchResult {
+ // 如果本行在剔除开头所有字符后仍不为 # 开头,则说明本行无法用于标题解析
+ let lookback = inr.lookback.clone();
+ if !lookback.trim_start().starts_with('#') {
+ // 本行不是标题行,放弃整行的解析
+ return ParserMatchResult::Abort;
+ }
+
+ // 当前行
+ let row = inr.row;
+ let col = inr.col;
+
+ // 获得临时数据
+ let tmp = inr.get_tmp_or_init::<HeadingTmp>("headings_tmp");
+
+ // 如果是行首,则初始化 tmp 数据
+ if col == 0 {
+ tmp.lvl = 0;
+ tmp.typing_heading_prefix = false;
+ tmp.typing_heading_content = false;
+ tmp.first_sharp_col = None;
+ }
+
+ match c {
+ // 键入了 # 符号
+ '#' => {
+ // 如果正在输入标题前缀,则层级增加
+ if tmp.typing_heading_prefix {
+ tmp.lvl += 1;
+
+ // 如果层级大于 6 (6级标题)
+ if tmp.lvl > 6 {
+ // 语法异常,抛出
+ return ParserMatchResult::SyntaxError {
+ begin_col: tmp.first_sharp_col.unwrap_or(col),
+ begin_row: row,
+ end_col: col,
+ end_row: row,
+ msg: "Heading level cannot exceed 6".to_string(),
+ };
+ }
+ }
+ // 如果不在输入标题
+ else {
+ // 记录为正在输入前缀
+ tmp.typing_heading_prefix = true;
+
+ // 设置层级为 1
+ tmp.lvl = 1;
+
+ // 标记第一个 # 符号的位置
+ tmp.first_sharp_col = Some(col);
+ }
+ }
+ // 输入了空格
+ ' ' => {
+ // 如果正在输入标题前缀
+ if tmp.typing_heading_prefix {
+ // 标记为没输入前缀,并切换为正在输入内容
+ tmp.typing_heading_prefix = false;
+ tmp.typing_heading_content = true;
+ }
+ }
+ // 输入了换行
+ '\n' => {
+ // 如果正在输入标题内容
+ if tmp.typing_heading_content {
+ // 拿出所有 records_tokens
+ let tokens = replace(&mut inr.records_tokens, Vec::new());
+
+ // 建立标题行
+ let line = Line { row, tokens };
+
+ // 追加行
+ inr.records_lines.push(line);
+ }
+ }
+ _ => return ParserMatchResult::Sad,
+ }
+
+ ParserMatchResult::Done
+}