Skip to main content

cooklang_language_server/
document.rs

1use cooklang::error::SourceDiag;
2use cooklang::{CooklangParser, Extensions, Recipe};
3use tower_lsp::lsp_types::Url;
4
5use crate::utils::line_index::LineIndex;
6
7/// Represents a parsed Cooklang document
8#[derive(Debug)]
9pub struct Document {
10    pub uri: Url,
11    pub version: i32,
12    pub content: String,
13    pub line_index: LineIndex,
14    pub parse_result: Option<ParseResult>,
15    /// Errors from parsing, stored even if parse completely failed
16    pub parse_errors: Vec<SourceDiag>,
17    /// Warnings from parsing
18    pub parse_warnings: Vec<SourceDiag>,
19}
20
21#[derive(Debug, Clone)]
22pub struct ParseResult {
23    pub recipe: Recipe,
24}
25
26impl Document {
27    pub fn new(uri: Url, version: i32, content: String) -> Self {
28        let line_index = LineIndex::new(&content);
29        let mut doc = Self {
30            uri,
31            version,
32            content,
33            line_index,
34            parse_result: None,
35            parse_errors: Vec::new(),
36            parse_warnings: Vec::new(),
37        };
38        doc.reparse();
39        doc
40    }
41
42    pub fn update(&mut self, version: i32, content: String) {
43        self.version = version;
44        self.content = content;
45        self.line_index = LineIndex::new(&self.content);
46        self.reparse();
47    }
48
49    fn reparse(&mut self) {
50        let parser = CooklangParser::new(Extensions::all(), Default::default());
51        let result = parser.parse(&self.content);
52
53        // Get errors and warnings from the report
54        let report = result.report();
55        self.parse_errors = report.errors().cloned().collect();
56        self.parse_warnings = report.warnings().cloned().collect();
57
58        // Get the recipe output if available
59        self.parse_result = result
60            .output()
61            .cloned()
62            .map(|recipe| ParseResult { recipe });
63    }
64}