mdformat 0.1.6

A formatter for markdown source code.
# 修复有序列表中缩进代码块导致编号重置的问题

## 问题描述

当有序列表项之间包含缩进的代码块时,列表编号会错误地重新从 1 开始,而不是继续递增。

**示例:**
```markdown
1. aaa
  ```c
  int a = 0;
  ```


2. bbb

3. ccc
```

当前会被格式化为:
```markdown
1. aaa
  ```c
  int a = 0;
  ```


1. bbb  ← 错误:应该是 2

2. ccc  ← 错误:应该是 3
```

## 根本原因

在 `format_lists` 函数(src/main.rs:318)中,当遇到非列表的非空行时会清空 `list_stack`。缩进的内容(如代码块内的代码行)被误认为是"非列表内容",导致列表上下文被清除。

## 解决方案

修改 `format_lists` 函数的逻辑,使其能够识别并正确处理缩进的内容:
- **空行**:保持 list_stack(已实现)
- **缩进内容**(以空格开头的行):保持 list_stack,视为列表项的续行内容
- **非缩进的非空行**:清空 list_stack,表示列表结束

## 待办任务

- [x] 设计并添加测试用例
  - [x] 测试有序列表中间包含缩进代码块
  - [x] 测试有序列表中间包含缩进的普通文本
  - [x] 测试有序列表中间包含多个缩进元素
  - [x] 测试嵌套列表中的缩进代码块
- [x] 修复 `format_lists` 函数的逻辑
- [x] 运行所有测试,确保没有破坏现有功能
- [x] 验证修复效果

## 实现细节

### 测试用例设计

1. **基本场景**:有序列表 + 缩进代码块 + 有序列表
2. **复杂场景**:多层嵌套列表 + 缩进代码块
3. **混合场景**:有序列表 + 缩进文本 + 缩进代码块

### 代码修改

修改 `format_lists` 函数中的非列表行处理逻辑(约318行):

```rust
} else {
    // Non-list line
    if line.is_empty() {
        // Empty line: might be a separator within the same list, keep list_stack
        result.push(line.clone());
    } else if line.starts_with(' ') || line.starts_with('\t') {
        // Indented content: part of the list item (code blocks, continued text, etc.)
        // Keep list_stack intact
        result.push(line.clone());
    } else {
        // Real non-list content (text, heading, code, etc.): end the list
        list_stack.clear();
        result.push(line.clone());
    }
}
```

## 验证计划

1. 运行新增的测试用例
2. 运行所有现有测试:`cargo test`
3. 手动测试用户提供的示例
4. 测试边界情况

## 评审

### 修复总结

本次修复成功解决了有序列表中缩进代码块导致编号重置的问题。修改涉及两个核心函数:

#### 1. `format_lists` 函数(src/main.rs:312-326)

**修改内容:**
在处理非列表行时,增加了对缩进内容的判断:

```rust
} else {
    // Non-list line
    if line.is_empty() {
        // Empty line: might be a separator within the same list, keep list_stack
        result.push(line.clone());
    } else if line.starts_with(' ') || line.starts_with('\t') {
        // Indented content: part of the list item (code blocks, continued text, etc.)
        // Keep list_stack intact
        result.push(line.clone());
    } else {
        // Real non-list content (text, heading, code, etc.): end the list
        list_stack.clear();
        result.push(line.clone());
    }
}
```

**修复逻辑:**
- 空行:保持列表栈不变(原有逻辑)
- 缩进内容(以空格或制表符开头):保持列表栈不变,视为列表项的续行内容(**新增**- 非缩进非空行:清空列表栈,表示列表结束(原有逻辑)

#### 2. `format_lines` 函数(src/main.rs:139-225)

**修改内容:**
- 添加了 `prev_line` 变量来跟踪前一行的内容
- 修改了 `LineState::List` 的处理逻辑:

```rust
LineState::List => {
    if prev_line_state != LineState::List && prev_line_state != LineState::Empty {
        // Don't add blank line if previous line is indented content (part of list)
        if !(prev_line_state == LineState::Normal && prev_line.starts_with(' ')) {
            ret.push(String::new());
        }
    }
    ret.push(format_line(line));
}
```

**修复逻辑:**
在列表项之前添加空行时,检查前一行是否是缩进的 Normal 行。如果是,说明前一行是列表项的续行内容(如缩进的代码块),不应该插入空行。

### 测试覆盖

新增了 `test_ordered_list_with_indented_code_block` 测试函数,包含 5 个测试用例:

1. **基本场景**:有序列表 + 缩进代码块
2. **缩进文本**:有序列表 + 缩进的普通文本
3. **多个缩进元素**:有序列表 + 多种缩进内容
4. **嵌套列表**:嵌套列表 + 缩进代码块
5. **列表分隔**:有序列表 + 缩进代码块 + 非缩进文本(应重置编号)

### 测试结果

- ✅ 所有 10 个单元测试通过
- ✅ 所有 6 个集成测试通过
- ✅ 用户提供的示例验证成功

### 影响范围

- 修改了 2 个核心函数
- 新增了 1 个测试函数(5 个测试用例)
- 没有破坏任何现有功能
- 完全向后兼容