1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9pub type LspResult<T> = Result<T, LspError>;
11
12#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
14pub enum LspError {
15 #[error("Parse error: {0}")]
17 ParseError(String),
18
19 #[error("Invalid request: {0}")]
21 InvalidRequest(String),
22
23 #[error("Method not found: {0}")]
25 MethodNotFound(String),
26
27 #[error("Invalid parameters: {0}")]
29 InvalidParams(String),
30
31 #[error("Internal error: {0}")]
33 InternalError(String),
34
35 #[error("Server error: {0}")]
37 ServerError(String),
38
39 #[error("IO error: {0}")]
41 IoError(String),
42
43 #[error("Serialization error: {0}")]
45 SerializationError(String),
46
47 #[error("Timeout error: {0}")]
49 TimeoutError(String),
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum ServerState {
55 Initializing,
57 Initialized,
59 ShuttingDown,
61 ShutDown,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
67pub struct Position {
68 pub line: u32,
70 pub character: u32,
72}
73
74impl Position {
75 pub fn new(line: u32, character: u32) -> Self {
77 Self { line, character }
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
83pub struct Range {
84 pub start: Position,
86 pub end: Position,
88}
89
90impl Range {
91 pub fn new(start: Position, end: Position) -> Self {
93 Self { start, end }
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(rename_all = "PascalCase")]
100pub enum SymbolKind {
101 Function,
103 Type,
105 Variable,
107 Constant,
109 Module,
111 Class,
113 Interface,
115 Enum,
117 Trait,
119 Struct,
121 Method,
123 Property,
125 Field,
127 Parameter,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct Definition {
134 pub uri: String,
136 pub range: Range,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
142pub struct Reference {
143 pub uri: String,
145 pub range: Range,
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
151pub struct Symbol {
152 pub name: String,
154 pub kind: SymbolKind,
156 pub range: Range,
158 pub definition: Option<Definition>,
160 pub references: Vec<Reference>,
162 pub documentation: Option<String>,
164}
165
166impl Symbol {
167 pub fn new(name: String, kind: SymbolKind, range: Range) -> Self {
169 Self {
170 name,
171 kind,
172 range,
173 definition: None,
174 references: Vec::new(),
175 documentation: None,
176 }
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182#[serde(rename_all = "lowercase")]
183pub enum DiagnosticSeverity {
184 Error,
186 Warning,
188 Information,
190 Hint,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct Diagnostic {
197 pub range: Range,
199 pub severity: DiagnosticSeverity,
201 pub message: String,
203 pub code: Option<String>,
205 pub source: String,
207 pub related_information: Option<Vec<DiagnosticRelatedInformation>>,
209}
210
211impl Diagnostic {
212 pub fn new(range: Range, severity: DiagnosticSeverity, message: String) -> Self {
214 Self {
215 range,
216 severity,
217 message,
218 code: None,
219 source: "ricecoder-lsp".to_string(),
220 related_information: None,
221 }
222 }
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct DiagnosticRelatedInformation {
228 pub location: Location,
230 pub message: String,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct Location {
237 pub uri: String,
239 pub range: Range,
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
245#[serde(rename_all = "camelCase")]
246pub enum CodeActionKind {
247 QuickFix,
249 Refactor,
251 RefactorExtract,
253 RefactorInline,
255 RefactorRewrite,
257 Source,
259 SourceOrganizeImports,
261 SourceFixAll,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct TextEdit {
268 pub range: Range,
270 pub new_text: String,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct WorkspaceEdit {
277 pub changes: HashMap<String, Vec<TextEdit>>,
279}
280
281impl WorkspaceEdit {
282 pub fn new() -> Self {
284 Self {
285 changes: HashMap::new(),
286 }
287 }
288
289 pub fn add_edit(&mut self, uri: String, edit: TextEdit) {
291 self.changes.entry(uri).or_default().push(edit);
292 }
293}
294
295impl Default for WorkspaceEdit {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct CodeAction {
304 pub title: String,
306 pub kind: CodeActionKind,
308 pub edit: WorkspaceEdit,
310 pub diagnostics: Option<Vec<Diagnostic>>,
312}
313
314impl CodeAction {
315 pub fn new(title: String, kind: CodeActionKind, edit: WorkspaceEdit) -> Self {
317 Self {
318 title,
319 kind,
320 edit,
321 diagnostics: None,
322 }
323 }
324}
325
326#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
328#[serde(rename_all = "lowercase")]
329pub enum MarkupKind {
330 PlainText,
332 Markdown,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct MarkupContent {
339 pub kind: MarkupKind,
341 pub value: String,
343}
344
345impl MarkupContent {
346 pub fn plain_text(value: String) -> Self {
348 Self {
349 kind: MarkupKind::PlainText,
350 value,
351 }
352 }
353
354 pub fn markdown(value: String) -> Self {
356 Self {
357 kind: MarkupKind::Markdown,
358 value,
359 }
360 }
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct HoverInfo {
366 pub contents: MarkupContent,
368 pub range: Option<Range>,
370}
371
372impl HoverInfo {
373 pub fn new(contents: MarkupContent) -> Self {
375 Self {
376 contents,
377 range: None,
378 }
379 }
380
381 pub fn with_range(mut self, range: Range) -> Self {
383 self.range = Some(range);
384 self
385 }
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize)]
390pub struct SemanticInfo {
391 pub symbols: Vec<Symbol>,
393 pub imports: Vec<String>,
395 pub definitions: Vec<Definition>,
397 pub references: Vec<Reference>,
399}
400
401impl SemanticInfo {
402 pub fn new() -> Self {
404 Self {
405 symbols: Vec::new(),
406 imports: Vec::new(),
407 definitions: Vec::new(),
408 references: Vec::new(),
409 }
410 }
411}
412
413impl Default for SemanticInfo {
414 fn default() -> Self {
415 Self::new()
416 }
417}
418
419#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
421#[serde(rename_all = "lowercase")]
422pub enum Language {
423 Rust,
425 TypeScript,
427 Python,
429 Unknown,
431}
432
433impl Language {
434 pub fn from_extension(ext: &str) -> Self {
436 match ext.to_lowercase().as_str() {
437 "rs" => Language::Rust,
438 "ts" | "tsx" | "js" | "jsx" => Language::TypeScript,
439 "py" => Language::Python,
440 _ => Language::Unknown,
441 }
442 }
443
444 pub fn extensions(&self) -> &'static [&'static str] {
446 match self {
447 Language::Rust => &["rs"],
448 Language::TypeScript => &["ts", "tsx", "js", "jsx"],
449 Language::Python => &["py"],
450 Language::Unknown => &[],
451 }
452 }
453
454 pub fn as_str(&self) -> &'static str {
456 match self {
457 Language::Rust => "rust",
458 Language::TypeScript => "typescript",
459 Language::Python => "python",
460 Language::Unknown => "unknown",
461 }
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use super::*;
468
469 #[test]
470 fn test_position_creation() {
471 let pos = Position::new(10, 5);
472 assert_eq!(pos.line, 10);
473 assert_eq!(pos.character, 5);
474 }
475
476 #[test]
477 fn test_range_creation() {
478 let start = Position::new(0, 0);
479 let end = Position::new(1, 0);
480 let range = Range::new(start, end);
481 assert_eq!(range.start, start);
482 assert_eq!(range.end, end);
483 }
484
485 #[test]
486 fn test_symbol_creation() {
487 let range = Range::new(Position::new(0, 0), Position::new(0, 5));
488 let symbol = Symbol::new("test_fn".to_string(), SymbolKind::Function, range);
489 assert_eq!(symbol.name, "test_fn");
490 assert_eq!(symbol.kind, SymbolKind::Function);
491 }
492
493 #[test]
494 fn test_diagnostic_creation() {
495 let range = Range::new(Position::new(0, 0), Position::new(0, 5));
496 let diag = Diagnostic::new(range, DiagnosticSeverity::Error, "Test error".to_string());
497 assert_eq!(diag.severity, DiagnosticSeverity::Error);
498 assert_eq!(diag.message, "Test error");
499 }
500
501 #[test]
502 fn test_language_detection() {
503 assert_eq!(Language::from_extension("rs"), Language::Rust);
504 assert_eq!(Language::from_extension("ts"), Language::TypeScript);
505 assert_eq!(Language::from_extension("py"), Language::Python);
506 assert_eq!(Language::from_extension("unknown"), Language::Unknown);
507 }
508
509 #[test]
510 fn test_markup_content_plain_text() {
511 let content = MarkupContent::plain_text("Hello".to_string());
512 assert_eq!(content.kind, MarkupKind::PlainText);
513 assert_eq!(content.value, "Hello");
514 }
515
516 #[test]
517 fn test_markup_content_markdown() {
518 let content = MarkupContent::markdown("# Hello".to_string());
519 assert_eq!(content.kind, MarkupKind::Markdown);
520 assert_eq!(content.value, "# Hello");
521 }
522
523 #[test]
524 fn test_workspace_edit() {
525 let mut edit = WorkspaceEdit::new();
526 let text_edit = TextEdit {
527 range: Range::new(Position::new(0, 0), Position::new(0, 5)),
528 new_text: "new".to_string(),
529 };
530 edit.add_edit("file://test.rs".to_string(), text_edit);
531 assert_eq!(edit.changes.len(), 1);
532 }
533
534 #[test]
535 fn test_semantic_info() {
536 let info = SemanticInfo::new();
537 assert!(info.symbols.is_empty());
538 assert!(info.imports.is_empty());
539 }
540}