mq_edit/document/
document_type.rs1use miette::Result;
2use mq_markdown::Markdown;
3
4use crate::document::{FileType, LineMap};
5
6#[derive(Debug, Clone)]
8pub enum DocumentType {
9 Markdown {
11 ast: Markdown,
13 line_map: LineMap,
15 },
16 Code {
18 language: String,
20 },
21 PlainText,
23}
24
25impl DocumentType {
26 pub fn new_markdown(content: &str) -> Result<Self> {
28 let ast = Markdown::from_markdown_str(content)
29 .map_err(|e| miette::miette!("Failed to parse markdown: {}", e))?;
30 let line_map = LineMap::from_markdown(&ast);
31
32 Ok(Self::Markdown { ast, line_map })
33 }
34
35 pub fn new_code(language: String) -> Self {
37 Self::Code { language }
38 }
39
40 pub fn new_plain_text() -> Self {
42 Self::PlainText
43 }
44
45 pub fn file_type(&self) -> FileType {
47 match self {
48 Self::Markdown { .. } => FileType::Markdown,
49 Self::Code { language } => FileType::Code(language.clone()),
50 Self::PlainText => FileType::PlainText,
51 }
52 }
53
54 pub fn markdown_ast(&self) -> Option<&Markdown> {
56 match self {
57 Self::Markdown { ast, .. } => Some(ast),
58 _ => None,
59 }
60 }
61
62 pub fn line_map(&self) -> Option<&LineMap> {
64 match self {
65 Self::Markdown { line_map, .. } => Some(line_map),
66 _ => None,
67 }
68 }
69
70 pub fn language(&self) -> Option<&str> {
72 match self {
73 Self::Code { language } => Some(language.as_str()),
74 _ => None,
75 }
76 }
77
78 pub fn rebuild(&mut self, content: &str) -> Result<()> {
83 match self {
84 Self::Markdown { ast, line_map } => {
85 let new_ast = Markdown::from_markdown_str(content)
86 .map_err(|e| miette::miette!("Failed to reparse markdown: {}", e))?;
87 *ast = new_ast;
88 *line_map = LineMap::from_markdown(ast);
89 Ok(())
90 }
91 Self::Code { .. } | Self::PlainText => {
92 Ok(())
94 }
95 }
96 }
97
98 pub fn has_ast(&self) -> bool {
100 matches!(self, Self::Markdown { .. })
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_markdown_document_creation() {
110 let doc = DocumentType::new_markdown("# Hello World").unwrap();
111 assert!(doc.has_ast());
112 assert!(doc.markdown_ast().is_some());
113 assert!(doc.line_map().is_some());
114 assert_eq!(doc.file_type(), FileType::Markdown);
115 }
116
117 #[test]
118 fn test_code_document_creation() {
119 let doc = DocumentType::new_code("rust".to_string());
120 assert!(!doc.has_ast());
121 assert_eq!(doc.language(), Some("rust"));
122 assert_eq!(doc.file_type(), FileType::Code("rust".to_string()));
123 }
124
125 #[test]
126 fn test_plain_text_document_creation() {
127 let doc = DocumentType::new_plain_text();
128 assert!(!doc.has_ast());
129 assert_eq!(doc.file_type(), FileType::PlainText);
130 }
131
132 #[test]
133 fn test_markdown_rebuild() {
134 let mut doc = DocumentType::new_markdown("# Title").unwrap();
135 doc.rebuild("## Subtitle").unwrap();
136 assert!(doc.markdown_ast().is_some());
137 }
138}