feat(lsp): add LSP provision progress messages to toast notifications

This commit is contained in:
asepharyana
2026-07-12 15:19:13 +07:00
parent c36c819304
commit b20bb95ada
2 changed files with 38 additions and 0 deletions
+18
View File
@@ -331,6 +331,24 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
let _ = crate::app::review::process_pending_lessons(&rt.session_dir, &state.memory_dir); let _ = crate::app::review::process_pending_lessons(&rt.session_dir, &state.memory_dir);
} }
// Drain LSP provision progress messages into toast notifications.
// Collect messages under the lock, then push toasts outside it to avoid
// a borrow-conflict with state.push_toast (which also accesses state).
let pending: Vec<String> = state.lsp_provision_msgs.lock()
.ok()
.map(|mut q| q.drain(..).collect())
.unwrap_or_default();
for msg in &pending {
let kind = if msg.contains("not available") || msg.contains("failed") {
ToastKind::Warning
} else if msg.contains("connected") || msg.contains("") {
ToastKind::Success
} else {
ToastKind::Info
};
state.push_toast(Toast::new(kind, msg.clone()));
}
let events: Vec<TurnEvent> = { let events: Vec<TurnEvent> = {
if let Ok(mut q) = state.turn_events.lock() { if let Ok(mut q) = state.turn_events.lock() {
q.drain(..).collect() q.drain(..).collect()
+20
View File
@@ -68,6 +68,9 @@ pub struct AppStateRest {
pub workflow_engine: WorkflowEngine, pub workflow_engine: WorkflowEngine,
pub mcp_manager: McpManager, pub mcp_manager: McpManager,
pub lsp_manager: Arc<Mutex<LspManager>>, pub lsp_manager: Arc<Mutex<LspManager>>,
/// Shared queue: provisioner thread pushes status updates,
/// drained into toasts on each Tick.
pub lsp_provision_msgs: Arc<Mutex<VecDeque<String>>>,
pub dirty: bool, pub dirty: bool,
pub quit: bool, pub quit: bool,
} }
@@ -119,6 +122,7 @@ impl AppStateRest {
session_runtime: Some(SessionRuntime::new(session_dir.clone())), session_runtime: Some(SessionRuntime::new(session_dir.clone())),
workflow_engine: WorkflowEngine::new(), workflow_engine: WorkflowEngine::new(),
mcp_manager: McpManager::new(), mcp_manager: McpManager::new(),
lsp_provision_msgs: Arc::new(Mutex::new(VecDeque::new())),
lsp_manager: Arc::new(Mutex::new(LspManager::new())), lsp_manager: Arc::new(Mutex::new(LspManager::new())),
sessions: Vec::new(), sessions: Vec::new(),
transcript_cache: TranscriptCache::new(200), transcript_cache: TranscriptCache::new(200),
@@ -145,19 +149,35 @@ impl AppStateRest {
// logged rather than surfaced, since editing still works without LSP. // logged rather than surfaced, since editing still works without LSP.
if state.settings.lsp_auto_provision { if state.settings.lsp_auto_provision {
let lsp_mgr = state.lsp_manager.clone(); let lsp_mgr = state.lsp_manager.clone();
let msg_queue = state.lsp_provision_msgs.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
use crate::app::lsp::provisioner::{self, ProvisionResult}; use crate::app::lsp::provisioner::{self, ProvisionResult};
fn push_msg(q: &Arc<Mutex<VecDeque<String>>>, msg: String) {
if let Ok(mut q) = q.lock() {
q.push_back(msg);
}
}
push_msg(&msg_queue, "LSP: provisioning servers...".to_string());
let results = provisioner::provision_all(); let results = provisioner::provision_all();
push_msg(&msg_queue, "LSP: connecting servers...".to_string());
let connected = provisioner::auto_connect(&lsp_mgr, &results); let connected = provisioner::auto_connect(&lsp_mgr, &results);
for name in &connected { for name in &connected {
tracing::info!("LSP: {} connected", name); tracing::info!("LSP: {} connected", name);
push_msg(&msg_queue, format!("LSP: {} connected ✓", name));
} }
for r in &results { for r in &results {
if let ProvisionResult::Failed { language, server_name, reason, .. } = r { if let ProvisionResult::Failed { language, server_name, reason, .. } = r {
tracing::warn!("LSP {} ({}): {}", server_name, language, reason); tracing::warn!("LSP {} ({}): {}", server_name, language, reason);
push_msg(&msg_queue, format!("LSP: {} ({}) ✗ - {}", server_name, language, reason));
} }
} }
if connected.is_empty() {
push_msg(&msg_queue, "LSP: no servers available — install manually or check prerequisites".to_string());
} else {
push_msg(&msg_queue, format!("LSP: {} server(s) connected", connected.len()));
}
}); });
} }