Skip to main content

stynx_code_tools/infrastructure/
lsp_tool.rs

1use stynx_code_errors::AppResult;
2use stynx_code_types::{PermissionLevel, Tool};
3use serde_json::{Value, json};
4
5pub struct LSPTool;
6
7impl LSPTool {
8    pub fn new() -> Self {
9        Self
10    }
11}
12
13#[async_trait::async_trait]
14impl Tool for LSPTool {
15    fn name(&self) -> &str {
16        "lsp"
17    }
18
19    fn description(&self) -> &str {
20        "Perform LSP operations such as diagnostics, hover, goto definition, references, and code actions."
21    }
22
23    fn input_schema(&self) -> Value {
24        json!({
25            "type": "object",
26            "properties": {
27                "operation": {
28                    "type": "string",
29                    "description": "LSP operation: \"diagnostics\", \"hover\", \"goto_definition\", \"references\", or \"code_actions\"",
30                    "enum": ["diagnostics", "hover", "goto_definition", "references", "code_actions"]
31                },
32                "file_path": {
33                    "type": "string",
34                    "description": "Path to the file for the LSP operation"
35                },
36                "line": {
37                    "type": "integer",
38                    "description": "Line number (0-indexed) for position-based operations"
39                },
40                "character": {
41                    "type": "integer",
42                    "description": "Character offset (0-indexed) for position-based operations"
43                }
44            },
45            "required": ["operation", "file_path"]
46        })
47    }
48
49    fn permission_level(&self) -> PermissionLevel {
50        PermissionLevel::ReadOnly
51    }
52
53    fn is_lsp(&self) -> bool { true }
54    fn is_read_only(&self, _input: &Value) -> bool { true }
55    fn is_concurrent_safe(&self, _input: &Value) -> bool { true }
56
57    async fn execute(&self, input: Value) -> AppResult<String> {
58        let operation = input
59            .get("operation")
60            .and_then(|v| v.as_str())
61            .ok_or_else(|| stynx_code_errors::AppError::Tool("missing 'operation' field".into()))?;
62
63        let file_path = input
64            .get("file_path")
65            .and_then(|v| v.as_str())
66            .ok_or_else(|| stynx_code_errors::AppError::Tool("missing 'file_path' field".into()))?;
67
68        let line = input.get("line").and_then(|v| v.as_u64());
69        let character = input.get("character").and_then(|v| v.as_u64());
70
71        tracing::info!(operation, file_path, ?line, ?character, "LSP operation (stub)");
72
73        Ok(format!(
74            "LSP server not running. Operation '{operation}' on '{file_path}' cannot be performed.\n\
75             Hint: LSP integration will be available in Phase 4."
76        ))
77    }
78}