feat(lsp): add LSP provision progress messages to toast notifications
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
// 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> = {
|
||||
if let Ok(mut q) = state.turn_events.lock() {
|
||||
q.drain(..).collect()
|
||||
|
||||
@@ -68,6 +68,9 @@ pub struct AppStateRest {
|
||||
pub workflow_engine: WorkflowEngine,
|
||||
pub mcp_manager: McpManager,
|
||||
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 quit: bool,
|
||||
}
|
||||
@@ -119,6 +122,7 @@ impl AppStateRest {
|
||||
session_runtime: Some(SessionRuntime::new(session_dir.clone())),
|
||||
workflow_engine: WorkflowEngine::new(),
|
||||
mcp_manager: McpManager::new(),
|
||||
lsp_provision_msgs: Arc::new(Mutex::new(VecDeque::new())),
|
||||
lsp_manager: Arc::new(Mutex::new(LspManager::new())),
|
||||
sessions: Vec::new(),
|
||||
transcript_cache: TranscriptCache::new(200),
|
||||
@@ -145,19 +149,35 @@ impl AppStateRest {
|
||||
// logged rather than surfaced, since editing still works without LSP.
|
||||
if state.settings.lsp_auto_provision {
|
||||
let lsp_mgr = state.lsp_manager.clone();
|
||||
let msg_queue = state.lsp_provision_msgs.clone();
|
||||
std::thread::spawn(move || {
|
||||
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();
|
||||
push_msg(&msg_queue, "LSP: connecting servers...".to_string());
|
||||
let connected = provisioner::auto_connect(&lsp_mgr, &results);
|
||||
for name in &connected {
|
||||
tracing::info!("LSP: {} connected", name);
|
||||
push_msg(&msg_queue, format!("LSP: {} connected ✓", name));
|
||||
}
|
||||
for r in &results {
|
||||
if let ProvisionResult::Failed { language, server_name, reason, .. } = r {
|
||||
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()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user