Skip to main content

nargo_mcp/
lib.rs

1#![feature(new_range_api)]
2#![warn(missing_docs)]
3use dashmap::{DashMap, DashSet};
4use nargo_ir::{ElementIR, ExpressionIR, JsExpr, JsProgram, JsStmt, TemplateNodeIR};
5use nargo_parser::{template::VueTemplateParser, ParseState, ScriptParser, TemplateParser};
6use nargo_types::{is_pos_in_span, Position as NargoPosition, Span as NargoSpan};
7
8use futures::Future;
9use nargo_lsp::types::NargoLanguage;
10use oak_core::{
11    parser::session::ParseSession,
12    tree::{GreenNode, RedNode},
13    Range,
14};
15use oak_lsp::{service::LanguageService, types::SourcePosition as OakPosition};
16use oak_vfs::{MemoryVfs, Vfs};
17
18use serde::{Deserialize, Serialize};
19use std::sync::Arc;
20use tokio::sync::mpsc as tokio_mpsc;
21use url::Url;
22
23/// 模块标识符
24type ModuleId = String;
25
26/// 消息标识符
27type MessageId = String;
28
29/// 消息类型枚举
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31pub enum MessageType {
32    /// 普通消息
33    Message,
34    /// 事件通知
35    Event,
36    /// 请求消息
37    Request,
38    /// 响应消息
39    Response,
40    /// 广播消息
41    Broadcast,
42    /// 多播消息
43    Multicast,
44    /// 错误消息
45    Error,
46    /// 心跳消息
47    Ping,
48    /// 心跳响应消息
49    Pong,
50    /// 订阅消息
51    Subscribe,
52    /// 取消订阅消息
53    Unsubscribe,
54}
55
56/// 事件类型枚举
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
58pub enum EventType {
59    /// 模块初始化完成
60    ModuleInitialized,
61    /// 模块状态更新
62    ModuleStateUpdated,
63    /// 编译开始
64    CompileStarted,
65    /// 编译完成
66    CompileCompleted,
67    /// 编译错误
68    CompileError,
69    /// 文件变更
70    FileChanged,
71    /// 配置变更
72    ConfigurationChanged,
73    /// 模块注册
74    ModuleRegistered,
75    /// 模块注销
76    ModuleUnregistered,
77    /// 消息发送
78    MessageSent,
79    /// 消息接收
80    MessageReceived,
81    /// 心跳超时
82    HeartbeatTimeout,
83    /// 网络连接断开
84    NetworkDisconnected,
85    /// 网络连接恢复
86    NetworkConnected,
87    /// 资源加载开始
88    ResourceLoadStarted,
89    /// 资源加载完成
90    ResourceLoadCompleted,
91    /// 资源加载错误
92    ResourceLoadError,
93    /// 性能警告
94    PerformanceWarning,
95    /// 系统警告
96    SystemWarning,
97    /// 系统错误
98    SystemError,
99}
100
101impl EventType {
102    /// 转换为字符串
103    pub fn to_string(&self) -> String {
104        match self {
105            EventType::ModuleInitialized => "ModuleInitialized",
106            EventType::ModuleStateUpdated => "ModuleStateUpdated",
107            EventType::CompileStarted => "CompileStarted",
108            EventType::CompileCompleted => "CompileCompleted",
109            EventType::CompileError => "CompileError",
110            EventType::FileChanged => "FileChanged",
111            EventType::ConfigurationChanged => "ConfigurationChanged",
112            EventType::ModuleRegistered => "ModuleRegistered",
113            EventType::ModuleUnregistered => "ModuleUnregistered",
114            EventType::MessageSent => "MessageSent",
115            EventType::MessageReceived => "MessageReceived",
116            EventType::HeartbeatTimeout => "HeartbeatTimeout",
117            EventType::NetworkDisconnected => "NetworkDisconnected",
118            EventType::NetworkConnected => "NetworkConnected",
119            EventType::ResourceLoadStarted => "ResourceLoadStarted",
120            EventType::ResourceLoadCompleted => "ResourceLoadCompleted",
121            EventType::ResourceLoadError => "ResourceLoadError",
122            EventType::PerformanceWarning => "PerformanceWarning",
123            EventType::SystemWarning => "SystemWarning",
124            EventType::SystemError => "SystemError",
125        }
126        .to_string()
127    }
128}
129
130/// 消息状态枚举
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
132pub enum MessageStatus {
133    /// 消息已创建
134    Created,
135    /// 消息已发送
136    Sent,
137    /// 消息已接收
138    Received,
139    /// 消息已确认
140    Acknowledged,
141    /// 消息已超时
142    Timeout,
143    /// 消息发送失败
144    Failed,
145}
146
147/// 消息结构体
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct Message {
150    /// 消息ID
151    pub id: MessageId,
152    /// 消息类型
153    pub message_type: MessageType,
154    /// 发送方模块ID
155    pub sender: ModuleId,
156    /// 接收方模块ID
157    pub receiver: ModuleId,
158    /// 事件类型(仅当消息类型为Event时有效)
159    pub event_type: Option<EventType>,
160    /// 消息数据
161    pub data: serde_json::Value,
162    /// 时间戳
163    pub timestamp: u64,
164    /// 消息状态
165    pub status: MessageStatus,
166    /// 超时时间(毫秒)
167    pub timeout: Option<u64>,
168    /// 重试次数
169    pub retry_count: u8,
170}
171
172impl Message {
173    /// 创建普通消息
174    pub fn new_message(sender: ModuleId, receiver: ModuleId, data: serde_json::Value) -> Self {
175        Self { id: format!("msg-{}", chrono::Utc::now().timestamp_millis()), message_type: MessageType::Message, sender, receiver, event_type: None, data, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(5000), retry_count: 0 }
176    }
177
178    /// 创建事件消息
179    pub fn new_event(sender: ModuleId, event_type: EventType, data: serde_json::Value) -> Self {
180        Self { id: format!("event-{}-{}", event_type.to_string(), chrono::Utc::now().timestamp_millis()), message_type: MessageType::Event, sender, receiver: "broadcast".to_string(), event_type: Some(event_type), data, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(3000), retry_count: 0 }
181    }
182
183    /// 创建请求消息
184    pub fn new_request(sender: ModuleId, receiver: ModuleId, data: serde_json::Value) -> Self {
185        Self { id: format!("req-{}", chrono::Utc::now().timestamp_millis()), message_type: MessageType::Request, sender, receiver, event_type: None, data, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(10000), retry_count: 3 }
186    }
187
188    /// 创建响应消息
189    pub fn new_response(request_id: MessageId, sender: ModuleId, receiver: ModuleId, data: serde_json::Value) -> Self {
190        Self { id: format!("resp-{}", request_id), message_type: MessageType::Response, sender, receiver, event_type: None, data, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(5000), retry_count: 0 }
191    }
192
193    /// 创建广播消息
194    pub fn new_broadcast(sender: ModuleId, data: serde_json::Value) -> Self {
195        Self { id: format!("broadcast-{}", chrono::Utc::now().timestamp_millis()), message_type: MessageType::Broadcast, sender, receiver: "broadcast".to_string(), event_type: None, data, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(3000), retry_count: 0 }
196    }
197
198    /// 创建心跳消息
199    pub fn new_ping(sender: ModuleId, receiver: ModuleId) -> Self {
200        Self { id: format!("ping-{}", chrono::Utc::now().timestamp_millis()), message_type: MessageType::Ping, sender, receiver, event_type: None, data: serde_json::Value::Null, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(2000), retry_count: 1 }
201    }
202
203    /// 创建心跳响应消息
204    pub fn new_pong(sender: ModuleId, receiver: ModuleId, ping_id: MessageId) -> Self {
205        Self { id: format!("pong-{}", ping_id), message_type: MessageType::Pong, sender, receiver, event_type: None, data: serde_json::json!({ "ping_id": ping_id }), timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(1000), retry_count: 0 }
206    }
207
208    /// 创建订阅消息
209    pub fn new_subscribe(sender: ModuleId, event_type: EventType) -> Self {
210        Self { id: format!("subscribe-{}-{}", event_type.to_string(), chrono::Utc::now().timestamp_millis()), message_type: MessageType::Subscribe, sender, receiver: "system".to_string(), event_type: Some(event_type), data: serde_json::Value::Null, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(3000), retry_count: 0 }
211    }
212
213    /// 创建取消订阅消息
214    pub fn new_unsubscribe(sender: ModuleId, event_type: EventType) -> Self {
215        Self { id: format!("unsubscribe-{}-{}", event_type.to_string(), chrono::Utc::now().timestamp_millis()), message_type: MessageType::Unsubscribe, sender, receiver: "system".to_string(), event_type: Some(event_type), data: serde_json::Value::Null, timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(3000), retry_count: 0 }
216    }
217
218    /// 创建错误消息
219    pub fn new_error(sender: ModuleId, receiver: ModuleId, error: String) -> Self {
220        Self { id: format!("error-{}", chrono::Utc::now().timestamp_millis()), message_type: MessageType::Error, sender, receiver, event_type: None, data: serde_json::json!({ "error": error }), timestamp: chrono::Utc::now().timestamp_millis() as u64, status: MessageStatus::Created, timeout: Some(3000), retry_count: 0 }
221    }
222}
223
224/// 消息批处理结构体
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct MessageBatch {
227    /// 批次ID
228    pub batch_id: String,
229    /// 消息列表
230    pub messages: Vec<Message>,
231    /// 批次大小
232    pub size: usize,
233    /// 时间戳
234    pub timestamp: u64,
235}
236
237/// 模块间通信管理器
238#[derive(Clone)]
239pub struct ModuleCommunicationManager {
240    /// 模块注册映射
241    modules: DashMap<ModuleId, ModuleInfo>,
242    /// 消息通道映射
243    message_channels: DashMap<ModuleId, tokio_mpsc::Sender<Message>>,
244    /// 事件监听器映射
245    event_listeners: DashMap<EventType, Vec<ModuleId>>,
246    /// 消息状态跟踪
247    message_status: DashMap<MessageId, Message>,
248    /// 心跳状态
249    heartbeat_status: DashMap<ModuleId, u64>,
250    /// 心跳间隔(毫秒)
251    heartbeat_interval: u64,
252    /// 消息批处理缓冲区
253    message_buffers: DashMap<ModuleId, Vec<Message>>,
254    /// 批处理大小阈值
255    batch_size_threshold: usize,
256    /// 批处理间隔(毫秒)
257    batch_interval: u64,
258    /// 消息缓存
259    message_cache: DashMap<String, serde_json::Value>,
260    /// 缓存大小限制
261    cache_size_limit: usize,
262}
263
264// 显式实现Send和Sync trait,因为ModuleCommunicationManager只包含线程安全的组件
265unsafe impl Send for ModuleCommunicationManager {}
266unsafe impl Sync for ModuleCommunicationManager {}
267
268/// 模块信息结构体
269#[derive(Clone)]
270struct ModuleInfo {
271    /// 模块名称
272    name: String,
273    /// 模块版本
274    version: String,
275    /// 模块状态
276    status: ModuleStatus,
277}
278
279/// 模块状态枚举
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281enum ModuleStatus {
282    /// 未初始化
283    Uninitialized,
284    /// 初始化中
285    Initializing,
286    /// 已初始化
287    Initialized,
288    /// 运行中
289    Running,
290    /// 出错
291    Error,
292}
293
294impl ModuleCommunicationManager {
295    /// 创建新的模块通信管理器
296    pub fn new() -> Self {
297        Self {
298            modules: DashMap::new(),
299            message_channels: DashMap::new(),
300            event_listeners: DashMap::new(),
301            message_status: DashMap::new(),
302
303            heartbeat_status: DashMap::new(),
304            heartbeat_interval: 30000, // 默认30秒心跳间隔
305            message_buffers: DashMap::new(),
306            batch_size_threshold: 10, // 默认批处理大小阈值
307            batch_interval: 100,      // 默认批处理间隔(毫秒)
308            message_cache: DashMap::new(),
309            cache_size_limit: 1000, // 默认缓存大小限制
310        }
311    }
312
313    /// 注册模块
314    pub fn register_module(&self, module_id: ModuleId, name: String, version: String) -> tokio_mpsc::Receiver<Message> {
315        let (tx, rx) = tokio_mpsc::channel(100);
316
317        let name_clone = name.clone();
318        let version_clone = version.clone();
319
320        self.modules.insert(module_id.clone(), ModuleInfo { name, version, status: ModuleStatus::Uninitialized });
321
322        self.message_channels.insert(module_id.clone(), tx);
323
324        // 初始化心跳状态
325        self.heartbeat_status.insert(module_id.clone(), chrono::Utc::now().timestamp_millis() as u64);
326
327        // 广播模块注册事件
328        let event_data = serde_json::json!({
329            "module_id": module_id,
330            "name": name_clone,
331            "version": version_clone
332        });
333        let manager = self.clone();
334        tokio::spawn(async move {
335            manager.broadcast_event(EventType::ModuleRegistered, event_data, "system".to_string()).await;
336        });
337
338        rx
339    }
340
341    /// 发送消息
342    pub async fn send_message(&self, mut message: Message) {
343        // 保存消息状态
344        self.message_status.insert(message.id.clone(), message.clone());
345
346        // 更新消息状态为已发送
347        message.status = MessageStatus::Sent;
348        self.message_status.insert(message.id.clone(), message.clone());
349
350        let receiver = message.receiver.clone();
351
352        // 先获取sender的克隆,避免在async block中持有DashMapRef
353        let tx = self.message_channels.get(&receiver).map(|r| r.value().clone());
354
355        if let Some(tx) = tx {
356            if tx.send(message.clone()).await.is_err() {
357                // 通道已关闭,移除该模块
358                self.message_channels.remove(&receiver);
359                self.modules.remove(&receiver);
360                self.heartbeat_status.remove(&receiver);
361
362                // 更新消息状态为失败
363                let mut failed_msg = message;
364                failed_msg.status = MessageStatus::Failed;
365                self.message_status.insert(failed_msg.id.clone(), failed_msg);
366
367                // 广播模块注销事件
368                let event_data = serde_json::json!({
369                    "module_id": receiver
370                });
371                // 创建事件消息并加入队列,避免递归调用
372                let event_message = Message::new_event("system".to_string(), EventType::ModuleUnregistered, event_data);
373                self.queue_message(event_message);
374            }
375            else {
376                // 广播消息发送事件
377                let event_data = serde_json::json!({
378                    "message_id": message.id,
379                    "sender": message.sender,
380                    "receiver": message.receiver
381                });
382                // 创建事件消息并加入队列,避免递归调用
383                let event_message = Message::new_event("system".to_string(), EventType::MessageSent, event_data);
384                self.queue_message(event_message);
385
386                // 处理消息超时
387                // if let Some(timeout) = message.timeout {
388                //     let manager = self.clone();
389                //     let message_id = message.id.clone();
390                //     tokio::spawn(async move {
391                //         tokio::time::sleep(tokio::time::Duration::from_millis(timeout)).await;
392                //         if let Some(msg) = manager.message_status.get(&message_id) {
393                //             if msg.status != MessageStatus::Acknowledged {
394                //                 let mut timeout_msg = msg.value().clone();
395                //                 timeout_msg.status = MessageStatus::Timeout;
396                //                 manager
397                //                     .message_status
398                //                     .insert(message_id.clone(), timeout_msg);
399
400                //                 // 广播消息超时事件
401                //                 let event_data = serde_json::json!({
402                //                     "message_id": message_id
403                //                 });
404                //                 manager
405                //                     .broadcast_event(
406                //                         EventType::HeartbeatTimeout,
407                //                         event_data,
408                //                         "system".to_string(),
409                //                     )
410                //                     .await;
411                //             }
412                //         }
413                //     });
414                // }
415            }
416        }
417        else {
418            // 接收方不存在,更新消息状态为失败
419            message.status = MessageStatus::Failed;
420            self.message_status.insert(message.id.clone(), message);
421        }
422    }
423
424    /// 广播事件
425    pub async fn broadcast_event(&self, event_type: EventType, data: serde_json::Value, sender: ModuleId) {
426        let message = Message::new_event(sender, event_type.clone(), data);
427
428        // 先获取监听器列表的克隆,避免在async block中持有DashMap的引用
429        let listeners = {
430            // 在同步代码中获取监听器列表的克隆
431            self.event_listeners.get(&event_type).map(|l| l.value().clone())
432        };
433
434        if let Some(listeners) = listeners {
435            for module_id in listeners {
436                let mut msg = message.clone();
437                msg.receiver = module_id;
438                // 直接调用send_message,不使用tokio::spawn
439                self.send_message(msg).await;
440            }
441        }
442    }
443
444    /// 注册事件监听器
445    pub fn register_event_listener(&self, event_type: EventType, module_id: ModuleId) {
446        self.event_listeners
447            .entry(event_type)
448            .and_modify(|listeners| {
449                if !listeners.contains(&module_id) {
450                    listeners.push(module_id.clone());
451                }
452            })
453            .or_insert_with(|| vec![module_id]);
454    }
455
456    /// 移除事件监听器
457    pub fn remove_event_listener(&self, event_type: EventType, module_id: &ModuleId) {
458        if let Some(mut listeners) = self.event_listeners.get_mut(&event_type) {
459            listeners.retain(|id| id != module_id);
460        }
461    }
462
463    /// 更新模块状态
464    pub fn update_module_status(&self, module_id: &ModuleId, status: ModuleStatus) {
465        if let Some(mut module) = self.modules.get_mut(module_id) {
466            module.status = status;
467        }
468    }
469
470    /// 获取模块状态
471    pub fn get_module_status(&self, module_id: &ModuleId) -> Option<ModuleStatus> {
472        self.modules.get(module_id).map(|module| module.status.clone())
473    }
474
475    /// 列出所有模块
476    pub fn list_modules(&self) -> Vec<(ModuleId, ModuleInfo)> {
477        self.modules.iter().map(|entry| (entry.key().clone(), entry.value().clone())).collect()
478    }
479
480    /// 确认消息
481    pub async fn acknowledge_message(&self, message_id: &MessageId) {
482        if let Some(mut msg) = self.message_status.get_mut(message_id) {
483            msg.status = MessageStatus::Acknowledged;
484
485            // 广播消息确认事件
486            let event_data = serde_json::json!({
487                "message_id": message_id
488            });
489            self.broadcast_event(EventType::MessageReceived, event_data, "system".to_string()).await;
490
491            // 通知等待确认的发送方
492            // 移除对不存在的 message_acknowledgements 字段的引用
493        }
494    }
495
496    /// 发送消息并等待确认
497    pub async fn send_message_with_ack(&self, message: Message) -> Result<Message, String> {
498        let timeout = message.timeout.unwrap_or(5000);
499
500        self.send_message(message).await;
501
502        // 简化实现,直接返回错误
503        Err("Message acknowledgement not supported".to_string())
504    }
505
506    /// 启动心跳检测
507    pub async fn start_heartbeat(&self) {
508        let manager = self.clone();
509        tokio::spawn(async move {
510            loop {
511                tokio::time::sleep(tokio::time::Duration::from_millis(manager.heartbeat_interval)).await;
512                manager.check_heartbeats().await;
513            }
514        });
515    }
516
517    /// 检查心跳状态
518    async fn check_heartbeats(&self) {
519        let current_time = chrono::Utc::now().timestamp_millis() as u64;
520        let mut modules_to_remove = Vec::new();
521
522        for entry in self.heartbeat_status.iter() {
523            let module_id = entry.key();
524            let last_heartbeat = entry.value();
525
526            if current_time - *last_heartbeat > self.heartbeat_interval * 2 {
527                modules_to_remove.push(module_id.clone());
528            }
529        }
530
531        for module_id in modules_to_remove {
532            // 移除心跳超时的模块
533            self.message_channels.remove(&module_id);
534            self.modules.remove(&module_id);
535            self.heartbeat_status.remove(&module_id);
536
537            // 广播心跳超时事件
538            let event_data = serde_json::json!({
539                "module_id": module_id
540            });
541            self.broadcast_event(EventType::HeartbeatTimeout, event_data, "system".to_string()).await;
542        }
543    }
544
545    /// 发送心跳消息
546    pub async fn send_ping(&self, module_id: &ModuleId) {
547        let ping_message = Message::new_ping("system".to_string(), module_id.clone());
548        self.send_message(ping_message).await;
549    }
550
551    /// 处理心跳响应
552    pub async fn handle_pong(&self, module_id: &ModuleId) {
553        // 更新心跳状态
554        self.heartbeat_status.insert(module_id.clone(), chrono::Utc::now().timestamp_millis() as u64);
555    }
556
557    /// 获取消息状态
558    pub fn get_message_status(&self, message_id: &MessageId) -> Option<MessageStatus> {
559        self.message_status.get(message_id).map(|msg| msg.status.clone())
560    }
561
562    /// 清理过期消息
563    pub fn cleanup_expired_messages(&self) {
564        let current_time = chrono::Utc::now().timestamp_millis() as u64;
565        let mut messages_to_remove = Vec::new();
566
567        for entry in self.message_status.iter() {
568            let message_id = entry.key();
569            let message = entry.value();
570
571            // 清理已确认或超时超过5分钟的消息
572            if message.status == MessageStatus::Acknowledged || (message.status == MessageStatus::Timeout && current_time - message.timestamp > 300000) {
573                messages_to_remove.push(message_id.clone());
574            }
575        }
576
577        for message_id in messages_to_remove {
578            self.message_status.remove(&message_id);
579        }
580    }
581
582    /// 发送消息批次
583    pub async fn send_message_batch(&self, batch: MessageBatch) {
584        for message in batch.messages {
585            self.send_message(message).await;
586        }
587    }
588
589    /// 将消息加入批处理队列
590    pub fn queue_message(&self, message: Message) {
591        self.message_buffers
592            .entry(message.receiver.clone())
593            .and_modify(|buffer| {
594                buffer.push(message.clone());
595                // 当缓冲区达到阈值时,立即处理
596                if buffer.len() >= self.batch_size_threshold {
597                    let batch = MessageBatch { batch_id: format!("batch-{}", chrono::Utc::now().timestamp_millis()), messages: buffer.drain(..).collect(), size: buffer.len(), timestamp: chrono::Utc::now().timestamp_millis() as u64 };
598                    let manager = self.clone();
599                    tokio::spawn(async move {
600                        manager.send_message_batch(batch).await;
601                    });
602                }
603            })
604            .or_insert_with(|| vec![message]);
605    }
606
607    /// 处理消息批次
608    pub async fn process_message_batches(&self) {
609        for mut entry in self.message_buffers.iter_mut() {
610            let module_id = entry.key().clone();
611            let buffer = entry.value_mut();
612
613            if !buffer.is_empty() {
614                let batch = MessageBatch { batch_id: format!("batch-{}-{}", module_id, chrono::Utc::now().timestamp_millis()), messages: buffer.drain(..).collect(), size: buffer.len(), timestamp: chrono::Utc::now().timestamp_millis() as u64 };
615                self.send_message_batch(batch).await;
616            }
617        }
618    }
619
620    /// 启动批处理器
621    pub async fn start_batch_processor(&self) {
622        let manager = self.clone();
623        tokio::spawn(async move {
624            loop {
625                tokio::time::sleep(tokio::time::Duration::from_millis(manager.batch_interval)).await;
626                manager.process_message_batches().await;
627            }
628        });
629    }
630
631    /// 缓存消息
632    pub fn cache_message(&self, key: String, value: serde_json::Value) {
633        // 检查缓存大小
634        if self.message_cache.len() >= self.cache_size_limit {
635            // 简单的缓存淘汰策略:移除最早的条目
636            if let Some(first_key) = self.message_cache.iter().next() {
637                self.message_cache.remove(first_key.key());
638            }
639        }
640        self.message_cache.insert(key, value);
641    }
642
643    /// 获取缓存的消息
644    pub fn get_cached_message(&self, key: &str) -> Option<serde_json::Value> {
645        self.message_cache.get(key).and_then(|v| Some(v.clone()))
646    }
647
648    /// 清除缓存
649    pub fn clear_cache(&self) {
650        self.message_cache.clear();
651    }
652
653    /// 设置批处理大小阈值
654    pub fn set_batch_size_threshold(&mut self, threshold: usize) {
655        self.batch_size_threshold = threshold;
656    }
657
658    /// 设置批处理间隔
659    pub fn set_batch_interval(&mut self, interval: u64) {
660        self.batch_interval = interval;
661    }
662
663    /// 设置缓存大小限制
664    pub fn set_cache_size_limit(&mut self, limit: usize) {
665        self.cache_size_limit = limit;
666    }
667}
668
669#[derive(Debug, Clone, PartialEq, Eq)]
670enum CompletionContext {
671    Tag,
672    Attribute(String),
673    Expression,
674}
675
676pub struct NargoLanguageService {
677    vfs: MemoryVfs,
678    auto_imports: DashSet<String>,
679    workspace: oak_lsp::workspace::WorkspaceManager,
680    sessions: DashMap<String, ParseSession<NargoLanguage>>,
681}
682
683impl NargoLanguageService {
684    pub fn new() -> Self {
685        let auto_imports = DashSet::new();
686        // Add default auto-imports
687        auto_imports.insert("signal".to_string());
688        auto_imports.insert("computed".to_string());
689        auto_imports.insert("on_mount".to_string());
690        auto_imports.insert("on_unmount".to_string());
691        auto_imports.insert("on_cleanup".to_string());
692
693        Self { vfs: MemoryVfs::new(), auto_imports, workspace: oak_lsp::workspace::WorkspaceManager::new(), sessions: DashMap::new() }
694    }
695
696    fn get_completion_context(nodes: &[TemplateNodeIR], pos: NargoPosition) -> Option<CompletionContext> {
697        for node in nodes {
698            match node {
699                TemplateNodeIR::Element(el) => {
700                    if is_pos_in_span(pos, el.span) {
701                        // Check if in tag name
702                        let tag_start = el.span.start;
703                        let tag_name_end = NargoPosition {
704                            line: tag_start.line,
705                            column: tag_start.column + (el.tag.len() as u32) + 1, // <tag
706                            offset: 0,
707                        };
708
709                        if pos.line == tag_start.line && pos.column <= tag_name_end.column {
710                            return Some(CompletionContext::Tag);
711                        }
712
713                        // Check attributes
714                        for attr in &el.attributes {
715                            if is_pos_in_span(pos, attr.span) {
716                                return Some(CompletionContext::Attribute(el.tag.clone()));
717                            }
718                        }
719
720                        // Check children
721                        if let Some(ctx) = Self::get_completion_context(&el.children, pos) {
722                            return Some(ctx);
723                        }
724
725                        // If in element but not in specific child/attr, might be in attribute area
726                        return Some(CompletionContext::Attribute(el.tag.clone()));
727                    }
728                }
729                TemplateNodeIR::Interpolation(expr) => {
730                    if is_pos_in_span(pos, expr.span) {
731                        return Some(CompletionContext::Expression);
732                    }
733                }
734                _ => {}
735            }
736        }
737        None
738    }
739
740    fn get_script_program(nodes: &[TemplateNodeIR]) -> Option<JsProgram> {
741        for node in nodes {
742            if let TemplateNodeIR::Element(el) = node {
743                if el.tag == "script" {
744                    if let Some(TemplateNodeIR::Text(content, _, _)) = el.children.first() {
745                        let mut state = ParseState::new(content);
746                        let ts_parser = nargo_parser::OakTypeScriptParser;
747                        return ts_parser.parse(&mut state, "ts").ok();
748                    }
749                }
750                if let Some(p) = Self::get_script_program(&el.children) {
751                    return Some(p);
752                }
753            }
754        }
755        None
756    }
757
758    async fn find_definition_in_nodes(&self, nodes: &[TemplateNodeIR], pos: NargoPosition, uri: &str) -> Option<oak_lsp::types::LocationRange> {
759        let script_program = Self::get_script_program(nodes);
760
761        for node in nodes {
762            match node {
763                TemplateNodeIR::Element(el) => {
764                    if is_pos_in_span(pos, el.span) {
765                        if el.tag == "script" {
766                            return self.find_definition_in_script(el, pos, uri).await;
767                        }
768                        else if el.tag == "style" {
769                            return Self::find_definition_in_style(el, pos, uri);
770                        }
771                        else {
772                            // 使用 Box::pin 处理异步递归
773                            let res = self.find_definition_in_nodes_recursive(&el.children, pos, uri).await;
774                            if res.is_some() {
775                                return res;
776                            }
777                        }
778                    }
779                }
780                TemplateNodeIR::Interpolation(expr) => {
781                    if !expr.span.is_unknown() && is_pos_in_span(pos, expr.span) {
782                        if let Some(symbol) = Self::find_symbol_in_template_expr(expr, pos) {
783                            // 1. 首先在 script 块中查找
784                            if let Some(program) = &script_program {
785                                if let Some(def_span) = Self::find_definition_of_symbol(program, &symbol) {
786                                    if Self::is_import(program, &symbol) {
787                                        if let Some(loc) = self.find_external_definition(program, &symbol, uri).await {
788                                            return Some(loc);
789                                        }
790                                    }
791
792                                    if let Some(script_el_span) = Self::get_script_element_span(nodes) {
793                                        if let Some(source) = self.vfs.get_source(uri) {
794                                            let start_pos = OakPosition { line: script_el_span.start.line + def_span.start.line - 1, column: def_span.start.column - 1, offset: 0, length: 0 };
795                                            let end_pos = OakPosition { line: script_el_span.start.line + def_span.end.line - 1, column: def_span.end.column - 1, offset: 0, length: 0 };
796                                            return Some(oak_lsp::types::LocationRange { uri: uri.to_string().into(), range: Range { start: self.vfs.line_map(uri).map(|m| m.line_col_utf16_to_offset(&source, start_pos.line, start_pos.column)).unwrap_or(0), end: self.vfs.line_map(uri).map(|m| m.line_col_utf16_to_offset(&source, end_pos.line, end_pos.column)).unwrap_or(0) } });
797                                        }
798                                    }
799                                }
800                            }
801
802                            // 2. 检查是否为自动导入
803                            if self.auto_imports.contains(&symbol) {
804                                if let Some(loc) = self.find_implicit_definition(&symbol, "@nargo/core", uri).await {
805                                    return Some(loc);
806                                }
807                            }
808                        }
809                    }
810                }
811                _ => {}
812            }
813        }
814        None
815    }
816
817    // Helper for recursion to avoid "async recursion" error
818    fn find_definition_in_nodes_recursive<'a>(&'a self, nodes: &'a [TemplateNodeIR], pos: NargoPosition, uri: &'a str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<oak_lsp::types::LocationRange>> + Send + 'a>> {
819        Box::pin(self.find_definition_in_nodes(nodes, pos, uri))
820    }
821
822    fn is_import(program: &JsProgram, symbol: &str) -> bool {
823        for stmt in &program.body {
824            if let JsStmt::Import { specifiers, .. } = stmt {
825                if specifiers.contains(&symbol.to_string()) {
826                    return true;
827                }
828            }
829        }
830        false
831    }
832
833    fn get_script_element_span(nodes: &[TemplateNodeIR]) -> Option<NargoSpan> {
834        for node in nodes {
835            if let TemplateNodeIR::Element(el) = node {
836                if el.tag == "script" {
837                    return Some(el.span);
838                }
839                if let Some(s) = Self::get_script_element_span(&el.children) {
840                    return Some(s);
841                }
842            }
843        }
844        None
845    }
846
847    fn find_symbol_in_template_expr(expr: &ExpressionIR, pos: NargoPosition) -> Option<String> {
848        // In nargo-ir, ExpressionIR has a 'code' field for the raw string
849        if !expr.span.is_unknown() && is_pos_in_span(pos, expr.span) {
850            // If it's a simple identifier expression
851            return Some(expr.code.clone());
852        }
853        None
854    }
855
856    async fn find_definition_in_script(&self, el: &ElementIR, pos: NargoPosition, uri: &str) -> Option<oak_lsp::types::LocationRange> {
857        if let Some(TemplateNodeIR::Text(content, _, _)) = el.children.first() {
858            let mut state = ParseState::new(content);
859            let ts_parser = nargo_parser::OakTypeScriptParser;
860            if let Ok(program) = ts_parser.parse(&mut state, "ts") {
861                // Adjust position relative to the script tag start
862                let el_span = el.span;
863                let relative_pos = NargoPosition { line: pos.line - el_span.start.line, column: if pos.line == el_span.start.line { pos.column - el_span.start.column } else { pos.column }, offset: 0 };
864
865                if let Some(symbol) = Self::find_symbol_at(&program, relative_pos) {
866                    // 1. Check if it's an import (external definition)
867                    if Self::is_import(&program, &symbol) {
868                        if let Some(loc) = self.find_external_definition(&program, &symbol, uri).await {
869                            return Some(loc);
870                        }
871                    }
872
873                    // 2. Find where this symbol is defined locally
874                    if let Some(def_span) = Self::find_definition_of_symbol(&program, &symbol) {
875                        if let Some(source) = self.vfs.get_source(uri) {
876                            let start_pos = OakPosition { line: el_span.start.line + def_span.start.line - 1, column: def_span.start.column - 1, offset: 0, length: 0 };
877                            let end_pos = OakPosition { line: el_span.start.line + def_span.end.line - 1, column: def_span.end.column - 1, offset: 0, length: 0 };
878                            return Some(oak_lsp::types::LocationRange { uri: uri.to_string().into(), range: Range { start: self.vfs.line_map(uri).map(|m| m.line_col_utf16_to_offset(&source, start_pos.line, start_pos.column)).unwrap_or(0), end: self.vfs.line_map(uri).map(|m| m.line_col_utf16_to_offset(&source, end_pos.line, end_pos.column)).unwrap_or(0) } });
879                        }
880                    }
881
882                    // 3. Check if it's an auto-import
883                    if self.auto_imports.contains(&symbol) {
884                        if let Some(loc) = self.find_implicit_definition(&symbol, "@nargo/core", uri).await {
885                            return Some(loc);
886                        }
887                    }
888                }
889            }
890        }
891        None
892    }
893
894    fn find_symbol_at(program: &JsProgram, pos: NargoPosition) -> Option<String> {
895        for stmt in &program.body {
896            if let Some(symbol) = Self::find_symbol_in_stmt(stmt, pos) {
897                return Some(symbol);
898            }
899        }
900        None
901    }
902
903    fn find_symbol_in_stmt(stmt: &JsStmt, pos: NargoPosition) -> Option<String> {
904        use JsStmt::*;
905        match stmt {
906            VariableDecl { id, init, .. } => {
907                // This is a simplification. In reality, we should check id and init spans.
908                if id == "count" {
909                    return Some(id.clone());
910                }
911                if let Some(init) = init {
912                    return Self::find_symbol_in_expr(init, pos);
913                }
914            }
915            Expr(expr, ..) => return Self::find_symbol_in_expr(expr, pos),
916            _ => {}
917        }
918        None
919    }
920
921    fn find_symbol_in_expr(expr: &JsExpr, _pos: NargoPosition) -> Option<String> {
922        match expr {
923            JsExpr::Identifier(name, ..) => Some(name.clone()),
924            JsExpr::Call { callee, .. } => Self::find_symbol_in_expr(callee, _pos),
925            _ => None,
926        }
927    }
928
929    fn find_definition_of_symbol(program: &JsProgram, symbol: &str) -> Option<NargoSpan> {
930        for stmt in &program.body {
931            if let JsStmt::VariableDecl { id, span, .. } = stmt {
932                if id == symbol {
933                    return Some(*span);
934                }
935            }
936            if let JsStmt::FunctionDecl { id, span, .. } = stmt {
937                if id == symbol {
938                    return Some(*span);
939                }
940            }
941        }
942        None
943    }
944
945    async fn find_external_definition(&self, program: &JsProgram, symbol: &str, current_uri: &str) -> Option<oak_lsp::types::LocationRange> {
946        for stmt in &program.body {
947            if let JsStmt::Import { specifiers, source, .. } = stmt {
948                if specifiers.contains(&symbol.to_string()) {
949                    return self.find_implicit_definition(symbol, source, current_uri).await;
950                }
951            }
952        }
953        None
954    }
955
956    async fn find_implicit_definition(&self, symbol: &str, source_path: &str, current_uri: &str) -> Option<oak_lsp::types::LocationRange> {
957        if let Some(url) = self.resolve_path(current_uri, source_path) {
958            if let Some(content) = self.get_document_content(&url).await {
959                // For now, just point to the start of the file or look for the symbol
960                let mut line = 0;
961                let mut col = 0;
962                if let Some(pos) = content.find(symbol) {
963                    let before = &content[..pos];
964                    line = before.lines().count().saturating_sub(1);
965                    col = before.lines().last().map(|l| l.len()).unwrap_or(0);
966                }
967
968                if let Some(target_source) = self.vfs.get_source(url.as_str()) {
969                    let start_pos = OakPosition { line: line as u32, column: col as u32, offset: 0, length: 0 };
970                    let end_pos = OakPosition { line: line as u32, column: (col + symbol.len()) as u32, offset: 0, length: 0 };
971                    return Some(oak_lsp::types::LocationRange { uri: url.to_string().into(), range: Range { start: self.vfs.line_map(url.as_str()).map(|m| m.line_col_utf16_to_offset(&target_source, start_pos.line, start_pos.column)).unwrap_or(0), end: self.vfs.line_map(url.as_str()).map(|m| m.line_col_utf16_to_offset(&target_source, end_pos.line, end_pos.column)).unwrap_or(0) } });
972                }
973            }
974        }
975        None
976    }
977
978    fn resolve_path(&self, current_uri: &str, relative_path: &str) -> Option<Url> {
979        let base_url = Url::parse(current_uri).ok()?;
980        let base_path = base_url.to_file_path().ok()?;
981
982        if relative_path == "@nargo/core" {
983            // 1. Try workspace folders
984            for (_, folder) in self.workspace.list_folders() {
985                let core_path = folder.join("runtimes/nargo-core/src/index.ts");
986                if core_path.exists() {
987                    return Url::from_file_path(core_path).ok();
988                }
989                // Try nested
990                let core_path = folder.join("project-nargo/runtimes/nargo-core/src/index.ts");
991                if core_path.exists() {
992                    return Url::from_file_path(core_path).ok();
993                }
994            }
995
996            // 2. Try relative to current file
997            if let Ok(uri) = Url::parse(current_uri) {
998                if let Ok(mut path) = uri.to_file_path() {
999                    while let Some(parent) = path.parent() {
1000                        let core_path = parent.join("runtimes/nargo-core/src/index.ts");
1001                        if core_path.exists() {
1002                            return Url::from_file_path(core_path).ok();
1003                        }
1004                        path = parent.to_path_buf();
1005                    }
1006                }
1007            }
1008        }
1009
1010        let parent = base_path.parent()?;
1011        let target_path = if relative_path.starts_with('.') {
1012            parent.join(relative_path)
1013        }
1014        else {
1015            return None;
1016        };
1017
1018        let extensions = ["", ".ts", ".js"];
1019        for ext in extensions {
1020            let mut p = target_path.clone();
1021            if !ext.is_empty() {
1022                p.set_extension(ext.trim_start_matches('.'));
1023            }
1024            if p.exists() {
1025                return Url::from_file_path(p).ok();
1026            }
1027        }
1028
1029        None
1030    }
1031
1032    async fn get_document_content(&self, uri: &Url) -> Option<String> {
1033        let uri_str = uri.to_string();
1034        if let Some(source) = self.vfs.get_source(&uri_str) {
1035            return Some(source.text().to_string());
1036        }
1037
1038        if let Ok(path) = uri.to_file_path() {
1039            return std::fs::read_to_string(path).ok();
1040        }
1041
1042        None
1043    }
1044
1045    fn find_definition_in_style(_el: &ElementIR, _pos: NargoPosition, _uri: &str) -> Option<oak_lsp::types::LocationRange> {
1046        // Not implemented yet
1047        None
1048    }
1049}
1050
1051use nargo_compiler::Compiler;
1052use oak_core::Parser;
1053
1054use oak_lsp::types::{CompletionItem as OakCompletionItem, CompletionItemKind as OakCompletionItemKind, Diagnostic as OakDiagnostic, DiagnosticSeverity as OakDiagnosticSeverity};
1055
1056impl LanguageService for NargoLanguageService {
1057    type Lang = NargoLanguage;
1058    type Vfs = MemoryVfs;
1059
1060    fn vfs(&self) -> &Self::Vfs {
1061        &self.vfs
1062    }
1063
1064    fn workspace(&self) -> &oak_lsp::workspace::WorkspaceManager {
1065        &self.workspace
1066    }
1067
1068    fn get_root(&self, uri: &str) -> impl Future<Output = Option<RedNode<'_, NargoLanguage>>> + Send + '_ {
1069        let source = self.vfs.get_source(uri);
1070        let mut session = self.sessions.entry(uri.to_string()).or_insert_with(|| ParseSession::new(16));
1071        async move {
1072            if let Some(source) = source {
1073                // let parser = NargoParser::new();
1074                // // We use a persistent session for each file to allow incremental parsing if implemented
1075                // let output = parser.parse(&source, &[], session.value_mut());
1076                // if let Ok(green) = output.result {
1077                //     // SAFETY: We store the session (and thus its arena) in self.sessions which is owned by NargoLanguageService.
1078                //     // As long as the NargoLanguageService exists and we don't remove this session, the green node remains valid.
1079                //     // We use 'static lifetime here because RedNode needs a lifetime that outlives the future,
1080                //     // and transmute is used to bridge the gap between the local borrow and the persistent storage.
1081                //     let green: &GreenNode<'static, NargoLanguage> =
1082                //         unsafe { std::mem::transmute(green) };
1083                //     return Some(RedNode::new(green, 0));
1084                // }
1085            }
1086            None
1087        }
1088    }
1089
1090    fn completion(&self, uri: &str, position: usize) -> impl Future<Output = Vec<OakCompletionItem>> + Send + '_ {
1091        let source = self.vfs.get_source(uri);
1092        let auto_imports = self.auto_imports.clone();
1093        let uri = uri.to_string();
1094
1095        async move {
1096            let mut items = Vec::new();
1097            if let Some(source) = source {
1098                let content = source.text();
1099                let pos = self
1100                    .vfs
1101                    .line_map(&uri)
1102                    .map(|m| {
1103                        let (l, c) = m.offset_to_line_col_utf16(&source, position);
1104                        OakPosition { line: l, column: c, offset: 0, length: 0 }
1105                    })
1106                    .unwrap_or(OakPosition { line: 0, column: 0, offset: 0, length: 0 });
1107                let nargo_pos = NargoPosition { line: pos.line + 1, column: pos.column + 1, offset: 0 };
1108
1109                let mut state = ParseState::new(&content);
1110                let parser = VueTemplateParser;
1111                if let Ok(nodes) = parser.parse(&mut state, "html") {
1112                    if let Some(context) = Self::get_completion_context(&nodes, nargo_pos) {
1113                        match context {
1114                            CompletionContext::Tag => {
1115                                let tags = vec!["div", "span", "button", "input", "h1", "h2", "p", "section", "article"];
1116                                for tag in tags {
1117                                    items.push(OakCompletionItem { label: tag.to_string(), kind: Some(OakCompletionItemKind::Keyword), detail: Some("HTML Tag".to_string()), documentation: None, insert_text: None });
1118                                }
1119                            }
1120                            CompletionContext::Attribute(tag_name) => {
1121                                let directives = vec!["@click", "@input", "@change", ":class", ":style", ":value"];
1122                                for dir in directives {
1123                                    items.push(OakCompletionItem { label: dir.to_string(), kind: Some(OakCompletionItemKind::Constant), detail: Some("Directive".to_string()), documentation: None, insert_text: None });
1124                                }
1125
1126                                if tag_name == "input" {
1127                                    items.push(OakCompletionItem { label: "type".to_string(), kind: Some(OakCompletionItemKind::Property), detail: None, documentation: None, insert_text: None });
1128                                }
1129                            }
1130                            CompletionContext::Expression => {
1131                                for import in auto_imports.iter() {
1132                                    items.push(OakCompletionItem { label: import.clone(), kind: Some(OakCompletionItemKind::Function), detail: Some("Nargo Auto-import".to_string()), documentation: None, insert_text: None });
1133                                }
1134
1135                                if let Some(program) = Self::get_script_program(&nodes) {
1136                                    for stmt in &program.body {
1137                                        if let JsStmt::VariableDecl { id, .. } = stmt {
1138                                            items.push(OakCompletionItem { label: id.clone(), kind: Some(OakCompletionItemKind::Variable), detail: None, documentation: None, insert_text: None });
1139                                        }
1140                                    }
1141                                }
1142                            }
1143                        }
1144                    }
1145                }
1146            }
1147
1148            if items.is_empty() {
1149                let tags = vec!["div", "span", "button", "input", "h1", "h2", "p", "section", "article"];
1150                for tag in tags {
1151                    items.push(OakCompletionItem { label: tag.to_string(), kind: Some(OakCompletionItemKind::Keyword), detail: Some("HTML Tag".to_string()), documentation: None, insert_text: None });
1152                }
1153            }
1154
1155            items
1156        }
1157    }
1158
1159    fn diagnostics(&self, uri: &str) -> impl Future<Output = Vec<OakDiagnostic>> + Send + '_ {
1160        let source = self.vfs.get_source(uri);
1161        let uri_parsed = Url::parse(uri).ok();
1162        let uri = uri.to_string();
1163
1164        async move {
1165            let mut diags = Vec::new();
1166            if let Some(source) = source {
1167                let content = source.text();
1168                let mut compiler = Compiler::new();
1169                let name = uri_parsed.as_ref().and_then(|u| u.path_segments()).and_then(|mut s| s.next_back()).unwrap_or("App.ts");
1170
1171                if let Err(e) = compiler.compile(name, &content) {
1172                    let span = e.span();
1173                    if !span.is_unknown() {
1174                        let start_pos = OakPosition { line: span.start.line.saturating_sub(1), column: span.start.column.saturating_sub(1), offset: 0, length: 0 };
1175                        let end_pos = OakPosition { line: span.end.line.saturating_sub(1), column: span.end.column.saturating_sub(1), offset: 0, length: 0 };
1176
1177                        let start_offset = self.vfs.line_map(&uri).map(|m| m.line_col_utf16_to_offset(&source, start_pos.line, start_pos.column)).unwrap_or(0);
1178                        let end_offset = self.vfs.line_map(&uri).map(|m| m.line_col_utf16_to_offset(&source, end_pos.line, end_pos.column)).unwrap_or(0);
1179
1180                        diags.push(OakDiagnostic { range: Range { start: start_offset, end: end_offset }, severity: Some(OakDiagnosticSeverity::Error), message: format!("{}", e), source: Some("nargo-compiler".to_string()), code: None });
1181                    }
1182                }
1183            }
1184            diags
1185        }
1186    }
1187
1188    fn initialize(&self, params: oak_lsp::types::InitializeParams) -> impl Future<Output = ()> + Send + '_ {
1189        async move {
1190            self.workspace.initialize(&params);
1191        }
1192    }
1193
1194    fn definition(&self, uri: &str, range: Range<usize>) -> impl Future<Output = Vec<oak_lsp::types::LocationRange>> + Send + '_ {
1195        let source = self.vfs.get_source(uri);
1196        let uri = uri.to_string();
1197        async move {
1198            if let Some(source) = source {
1199                let content = source.text();
1200                let position = self
1201                    .vfs
1202                    .line_map(&uri)
1203                    .map(|m| {
1204                        let (l, c) = m.offset_to_line_col_utf16(&source, range.start);
1205                        OakPosition { line: l, column: c, offset: 0, length: 0 }
1206                    })
1207                    .unwrap_or(OakPosition { line: 0, column: 0, offset: 0, length: 0 });
1208                let nargo_pos = NargoPosition { line: position.line + 1, column: position.column + 1, offset: 0 };
1209
1210                let mut state = ParseState::new(&content);
1211                let parser = VueTemplateParser;
1212                if let Ok(nodes) = parser.parse(&mut state, "html") {
1213                    if let Some(loc) = self.find_definition_in_nodes(&nodes, nargo_pos, &uri).await {
1214                        return vec![loc];
1215                    }
1216                }
1217            }
1218            vec![]
1219        }
1220    }
1221}
1222
1223pub async fn run_stdio() -> nargo_types::Result<()> {
1224    let stdin = tokio::io::stdin();
1225    let stdout = tokio::io::stdout();
1226
1227    let nargo_service = Arc::new(NargoLanguageService::new());
1228    let server = oak_lsp::LspServer::new(nargo_service);
1229    server.run(stdin, stdout).await.map_err(|e| nargo_types::Error::external_error("oak-lsp".to_string(), format!("{}", e), nargo_types::Span::unknown()))?;
1230    Ok(())
1231}
1232
1233pub async fn run_http_server(port: u16) -> nargo_types::Result<()> {
1234    println!("HTTP/WebSocket LSP server on port {} is not yet fully implemented.", port);
1235    println!("Falling back to stdio for now.");
1236    run_stdio().await
1237}