mystical_runic/
lsp.rs

1//! Language Server Protocol support for v0.4.1 IDE Integration
2//! 
3//! Provides LSP-compatible structures and functionality for template editing
4
5
6/// LSP parsing result containing template analysis
7#[derive(Debug, Clone)]
8pub struct LspParseResult {
9    /// All variables found in the template
10    pub variables: Vec<String>,
11    /// All template blocks (if, for, etc.)
12    pub blocks: Vec<TemplateBlock>,
13    /// All filters used
14    pub filters: Vec<String>,
15    /// All macros defined or called
16    pub macros: Vec<String>,
17}
18
19/// Template block information for LSP
20#[derive(Debug, Clone)]
21pub struct TemplateBlock {
22    /// Type of block (if, for, macro, etc.)
23    pub block_type: String,
24    /// Starting line (1-based)
25    pub start_line: usize,
26    /// Starting column (1-based)
27    pub start_column: usize,
28    /// Ending line (1-based)
29    pub end_line: usize,
30    /// Ending column (1-based)
31    pub end_column: usize,
32    /// Block content/condition
33    pub content: String,
34}
35
36/// Completion item for auto-completion
37#[derive(Debug, Clone)]
38pub struct CompletionItem {
39    /// Display label for the completion
40    pub label: String,
41    /// Type of completion (variable, filter, directive, etc.)
42    pub completion_type: String,
43    /// Additional detail about the item
44    pub detail: String,
45    /// Documentation for the item
46    pub documentation: Option<String>,
47    /// Text to insert when completing
48    pub insert_text: Option<String>,
49}
50
51/// Syntax highlighting token
52#[derive(Debug, Clone)]
53pub struct SyntaxToken {
54    /// Token content
55    pub content: String,
56    /// Token type for highlighting
57    pub token_type: String,
58    /// Start position in document
59    pub start_position: usize,
60    /// End position in document
61    pub end_position: usize,
62    /// Line number (1-based)
63    pub line: usize,
64    /// Column number (1-based)
65    pub column: usize,
66}
67
68/// Diagnostic information for error squiggles
69#[derive(Debug, Clone)]
70pub struct Diagnostic {
71    /// Error/warning message
72    pub message: String,
73    /// Severity (error, warning, info, hint)
74    pub severity: String,
75    /// Line number (1-based)
76    pub line: usize,
77    /// Column number (1-based)
78    pub column: usize,
79    /// End line (1-based)
80    pub end_line: usize,
81    /// End column (1-based)
82    pub end_column: usize,
83    /// Error code if applicable
84    pub code: Option<String>,
85}
86
87/// Hover information for variables
88#[derive(Debug, Clone)]
89pub struct HoverInfo {
90    /// Variable name being hovered
91    pub variable_name: String,
92    /// Type of the variable
93    pub variable_type: String,
94    /// Current value as string
95    pub current_value: String,
96    /// Description/documentation
97    pub description: String,
98}
99
100/// Definition location information
101#[derive(Debug, Clone)]
102pub struct DefinitionInfo {
103    /// Type of definition (macro, variable, etc.)
104    pub definition_type: String,
105    /// Name of the defined item
106    pub name: String,
107    /// Line where defined (1-based)
108    pub line: usize,
109    /// Column where defined (1-based)
110    pub column: usize,
111    /// File path (if different)
112    pub file_path: Option<String>,
113}
114
115impl Default for LspParseResult {
116    fn default() -> Self {
117        Self::new()
118    }
119}
120
121impl LspParseResult {
122    /// Create new empty LSP parse result
123    pub fn new() -> Self {
124        Self {
125            variables: Vec::new(),
126            blocks: Vec::new(),
127            filters: Vec::new(),
128            macros: Vec::new(),
129        }
130    }
131    
132    /// Add a variable to the result
133    pub fn add_variable(&mut self, name: &str) {
134        if !self.variables.contains(&name.to_string()) {
135            self.variables.push(name.to_string());
136        }
137    }
138    
139    /// Add a template block to the result
140    pub fn add_block(&mut self, block: TemplateBlock) {
141        self.blocks.push(block);
142    }
143    
144    /// Add a filter to the result
145    pub fn add_filter(&mut self, name: &str) {
146        if !self.filters.contains(&name.to_string()) {
147            self.filters.push(name.to_string());
148        }
149    }
150}
151
152impl TemplateBlock {
153    /// Create a new template block
154    pub fn new(block_type: &str, start_line: usize, start_column: usize, content: &str) -> Self {
155        Self {
156            block_type: block_type.to_string(),
157            start_line,
158            start_column,
159            end_line: start_line, // Will be updated when block ends
160            end_column: start_column,
161            content: content.to_string(),
162        }
163    }
164}
165
166impl CompletionItem {
167    /// Create a new completion item
168    pub fn new(label: &str, completion_type: &str, detail: &str) -> Self {
169        Self {
170            label: label.to_string(),
171            completion_type: completion_type.to_string(),
172            detail: detail.to_string(),
173            documentation: None,
174            insert_text: None,
175        }
176    }
177    
178    /// Set documentation for the completion
179    pub fn with_documentation(mut self, doc: &str) -> Self {
180        self.documentation = Some(doc.to_string());
181        self
182    }
183    
184    /// Set custom insert text
185    pub fn with_insert_text(mut self, text: &str) -> Self {
186        self.insert_text = Some(text.to_string());
187        self
188    }
189}
190
191impl SyntaxToken {
192    /// Create a new syntax token
193    pub fn new(content: &str, token_type: &str, start_pos: usize, line: usize, column: usize) -> Self {
194        Self {
195            content: content.to_string(),
196            token_type: token_type.to_string(),
197            start_position: start_pos,
198            end_position: start_pos + content.len(),
199            line,
200            column,
201        }
202    }
203}
204
205impl Diagnostic {
206    /// Create a new diagnostic
207    pub fn new(message: &str, severity: &str, line: usize, column: usize) -> Self {
208        Self {
209            message: message.to_string(),
210            severity: severity.to_string(),
211            line,
212            column,
213            end_line: line,
214            end_column: column,
215            code: None,
216        }
217    }
218    
219    /// Set the range for the diagnostic
220    pub fn with_range(mut self, end_line: usize, end_column: usize) -> Self {
221        self.end_line = end_line;
222        self.end_column = end_column;
223        self
224    }
225    
226    /// Set an error code
227    pub fn with_code(mut self, code: &str) -> Self {
228        self.code = Some(code.to_string());
229        self
230    }
231}