Skip to main content

easydoc_reader/view/
mod.rs

1//! 面向 LLM 的文档视图模式。
2//!
3//! 提供四种视图模式,将 [`DocumentContent`] 转换为针对不同场景优化的纯文本表示:
4//!
5//! - [`ViewMode::Plain`] -- 纯文本,段落以换行分隔。
6//! - [`ViewMode::Annotated`] -- 结构化标注(`[段落 3]`、`[表格 2: 3行x4列]` 等)。
7//! - [`ViewMode::Outline`] -- 仅标题,Markdown 风格 `#` / `##`。
8//! - [`ViewMode::Stats`] -- 块计数和字数统计。
9//!
10//! 无直接 Java 对应,是 easydoc-rust 自创的辅助功能。
11
12mod annotated;
13mod outline;
14mod plain;
15mod render;
16mod stats;
17mod view_mode;
18
19pub use render::render_view;
20pub use view_mode::ViewMode;
21
22// ===========================================================================
23// Tests
24// ===========================================================================
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29    use easydoc_core::{
30        DocumentBlock, DocumentContent, DocumentTable, DocumentTableCell, DocumentTableRow,
31        DocumentTextRun,
32    };
33
34    fn sample_content() -> DocumentContent {
35        DocumentContent {
36            blocks: vec![
37                DocumentBlock::Heading {
38                    level: 1,
39                    runs: vec![DocumentTextRun {
40                        text: "Title".into(),
41                        ..DocumentTextRun::default()
42                    }],
43                },
44                DocumentBlock::Paragraph(vec![DocumentTextRun {
45                    text: "Hello World".into(),
46                    ..DocumentTextRun::default()
47                }]),
48                DocumentBlock::Table(DocumentTable {
49                    rows: vec![DocumentTableRow {
50                        cells: vec![
51                            DocumentTableCell {
52                                blocks: vec![DocumentBlock::Paragraph(vec![DocumentTextRun {
53                                    text: "A".into(),
54                                    ..DocumentTextRun::default()
55                                }])],
56                                column_span: 1,
57                                row_span: 1,
58                            },
59                            DocumentTableCell {
60                                blocks: vec![DocumentBlock::Paragraph(vec![DocumentTextRun {
61                                    text: "B".into(),
62                                    ..DocumentTextRun::default()
63                                }])],
64                                column_span: 1,
65                                row_span: 1,
66                            },
67                        ],
68                        is_header: true,
69                    }],
70                }),
71            ],
72            ..DocumentContent::default()
73        }
74    }
75
76    #[test]
77    fn render_plain() {
78        let content = sample_content();
79        let result = render_view(&content, &ViewMode::Plain).unwrap();
80        assert!(result.contains("Title"));
81        assert!(result.contains("Hello World"));
82    }
83
84    #[test]
85    fn render_annotated() {
86        let content = sample_content();
87        let result = render_view(&content, &ViewMode::Annotated).unwrap();
88        assert!(result.contains("[标题1]"));
89        assert!(result.contains("[段落"));
90        assert!(result.contains("[表格"));
91    }
92
93    #[test]
94    fn render_outline() {
95        let content = sample_content();
96        let result = render_view(&content, &ViewMode::Outline { max_level: 3 }).unwrap();
97        assert!(result.contains("# Title"));
98    }
99
100    #[test]
101    fn render_stats() {
102        let content = sample_content();
103        let result = render_view(&content, &ViewMode::Stats).unwrap();
104        assert!(result.contains("段落数:"));
105        assert!(result.contains("表格数:"));
106    }
107
108    #[test]
109    fn view_mode_debug_clone_eq() {
110        let mode = ViewMode::Annotated;
111        let mode2 = mode.clone();
112        assert_eq!(mode, mode2);
113        assert!(format!("{mode:?}").contains("Annotated"));
114    }
115
116    #[test]
117    fn outline_max_level_filters() {
118        let content = DocumentContent {
119            blocks: vec![
120                DocumentBlock::Heading {
121                    level: 1,
122                    runs: vec![DocumentTextRun {
123                        text: "H1".into(),
124                        ..DocumentTextRun::default()
125                    }],
126                },
127                DocumentBlock::Heading {
128                    level: 2,
129                    runs: vec![DocumentTextRun {
130                        text: "H2".into(),
131                        ..DocumentTextRun::default()
132                    }],
133                },
134                DocumentBlock::Heading {
135                    level: 3,
136                    runs: vec![DocumentTextRun {
137                        text: "H3".into(),
138                        ..DocumentTextRun::default()
139                    }],
140                },
141            ],
142            ..DocumentContent::default()
143        };
144        let result = render_view(&content, &ViewMode::Outline { max_level: 2 }).unwrap();
145        assert!(result.contains("# H1"));
146        assert!(result.contains("## H2"));
147        assert!(!result.contains("H3"));
148    }
149}