diff --git a/crates/language_tools/src/language_tools.rs b/crates/language_tools/src/language_tools.rs index c784a67313a904df34c9f2ae071ed5b0e4c11751..aa1672806417493c0c5a877a28fc7906f3da6ff8 100644 --- a/crates/language_tools/src/language_tools.rs +++ b/crates/language_tools/src/language_tools.rs @@ -14,7 +14,7 @@ use ui::{Context, Window}; use workspace::{Item, ItemHandle, SplitDirection, Workspace}; pub fn init(cx: &mut App) { - lsp_log_view::init(true, cx); + lsp_log_view::init(false, cx); syntax_tree_view::init(cx); key_context_view::init(cx); } diff --git a/crates/language_tools/src/lsp_log_view.rs b/crates/language_tools/src/lsp_log_view.rs index e54411f1d43a6e99352b8ef4dfc48cca423badb6..b1f1e5c4f62b4c14b88cdd3de27a1624c7c7158f 100644 --- a/crates/language_tools/src/lsp_log_view.rs +++ b/crates/language_tools/src/lsp_log_view.rs @@ -16,6 +16,7 @@ use project::{ lsp_store::log_store::{self, Event, LanguageServerKind, LogKind, LogStore, Message}, search::SearchQuery, }; +use proto::toggle_lsp_logs::LogType; use std::{any::TypeId, borrow::Cow, sync::Arc}; use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*}; use util::ResultExt as _; @@ -111,8 +112,8 @@ actions!( ] ); -pub fn init(store_logs: bool, cx: &mut App) { - let log_store = log_store::init(store_logs, cx); +pub fn init(on_headless_host: bool, cx: &mut App) { + let log_store = log_store::init(on_headless_host, cx); log_store.update(cx, |_, cx| { Copilot::global(cx).map(|copilot| { @@ -266,6 +267,19 @@ impl LspLogView { window.focus(&log_view.editor.focus_handle(cx)); }); + cx.on_release(|log_view, cx| { + log_view.log_store.update(cx, |log_store, cx| { + for (server_id, state) in &log_store.language_servers { + if let Some(log_kind) = state.toggled_log_kind { + if let Some(log_type) = log_type(log_kind) { + send_toggle_log_message(state, *server_id, false, log_type, cx); + } + } + } + }); + }) + .detach(); + let mut lsp_log_view = Self { focus_handle, editor, @@ -436,6 +450,12 @@ impl LspLogView { cx.notify(); } self.editor.read(cx).focus_handle(cx).focus(window); + self.log_store.update(cx, |log_store, cx| { + let state = log_store.get_language_server_state(server_id)?; + state.toggled_log_kind = Some(LogKind::Logs); + send_toggle_log_message(state, server_id, true, LogType::Log, cx); + Some(()) + }); } fn update_log_level( @@ -472,8 +492,8 @@ impl LspLogView { ) { let trace_level = self .log_store - .update(cx, |this, _| { - Some(this.get_language_server_state(server_id)?.trace_level) + .update(cx, |log_store, _| { + Some(log_store.get_language_server_state(server_id)?.trace_level) }) .unwrap_or(TraceValue::Messages); let log_contents = self @@ -487,6 +507,12 @@ impl LspLogView { let (editor, editor_subscriptions) = Self::editor_for_logs(log_contents, window, cx); self.editor = editor; self.editor_subscriptions = editor_subscriptions; + self.log_store.update(cx, |log_store, cx| { + let state = log_store.get_language_server_state(server_id)?; + state.toggled_log_kind = Some(LogKind::Trace); + send_toggle_log_message(state, server_id, true, LogType::Trace, cx); + Some(()) + }); cx.notify(); } self.editor.read(cx).focus_handle(cx).focus(window); @@ -551,24 +577,7 @@ impl LspLogView { } if let Some(server_state) = log_store.language_servers.get(&server_id) { - if let LanguageServerKind::Remote { project } = &server_state.kind { - project - .update(cx, |project, cx| { - if let Some((client, project_id)) = - project.lsp_store().read(cx).upstream_client() - { - client - .send(proto::ToggleLspLogs { - project_id, - log_type: proto::toggle_lsp_logs::LogType::Rpc as i32, - server_id: server_id.to_proto(), - enabled, - }) - .log_err(); - } - }) - .ok(); - } + send_toggle_log_message(server_state, server_id, enabled, LogType::Rpc, cx); }; }); if !enabled && Some(server_id) == self.current_server_id { @@ -644,6 +653,49 @@ impl LspLogView { self.editor_subscriptions = editor_subscriptions; cx.notify(); self.editor.read(cx).focus_handle(cx).focus(window); + self.log_store.update(cx, |log_store, cx| { + let state = log_store.get_language_server_state(server_id)?; + if let Some(log_kind) = state.toggled_log_kind.take() { + if let Some(log_type) = log_type(log_kind) { + send_toggle_log_message(state, server_id, false, log_type, cx); + } + }; + Some(()) + }); + } +} + +fn log_type(log_kind: LogKind) -> Option { + match log_kind { + LogKind::Rpc => Some(LogType::Rpc), + LogKind::Trace => Some(LogType::Trace), + LogKind::Logs => Some(LogType::Log), + LogKind::ServerInfo => None, + } +} + +fn send_toggle_log_message( + server_state: &log_store::LanguageServerState, + server_id: LanguageServerId, + enabled: bool, + log_type: LogType, + cx: &mut App, +) { + if let LanguageServerKind::Remote { project } = &server_state.kind { + project + .update(cx, |project, cx| { + if let Some((client, project_id)) = project.lsp_store().read(cx).upstream_client() { + client + .send(proto::ToggleLspLogs { + project_id, + log_type: log_type as i32, + server_id: server_id.to_proto(), + enabled, + }) + .log_err(); + } + }) + .ok(); } } diff --git a/crates/language_tools/src/lsp_log_view_tests.rs b/crates/language_tools/src/lsp_log_view_tests.rs index bfd093e3db1c1bc0dc04b111d2072339f1314b8e..d572c4375ed09997dc57d6c58e6c90f3e55775b6 100644 --- a/crates/language_tools/src/lsp_log_view_tests.rs +++ b/crates/language_tools/src/lsp_log_view_tests.rs @@ -53,7 +53,7 @@ async fn test_lsp_log_view(cx: &mut TestAppContext) { }, ); - let log_store = cx.new(|cx| LogStore::new(true, cx)); + let log_store = cx.new(|cx| LogStore::new(false, cx)); log_store.update(cx, |store, cx| store.add_project(&project, cx)); let _rust_buffer = project diff --git a/crates/project/src/lsp_store/log_store.rs b/crates/project/src/lsp_store/log_store.rs index 1fbdb494a303b47bea181c5046e51f3c0b21c5c1..67a20dd6cd8b2f5d6ca48d7790fc0b2e60aff370 100644 --- a/crates/project/src/lsp_store/log_store.rs +++ b/crates/project/src/lsp_store/log_store.rs @@ -21,8 +21,8 @@ const SERVER_LOGS: &str = "Server Logs"; const SERVER_TRACE: &str = "Server Trace"; const SERVER_INFO: &str = "Server Info"; -pub fn init(store_logs: bool, cx: &mut App) -> Entity { - let log_store = cx.new(|cx| LogStore::new(store_logs, cx)); +pub fn init(on_headless_host: bool, cx: &mut App) -> Entity { + let log_store = cx.new(|cx| LogStore::new(on_headless_host, cx)); cx.set_global(GlobalLogStore(log_store.clone())); log_store } @@ -43,7 +43,7 @@ pub enum Event { impl EventEmitter for LogStore {} pub struct LogStore { - store_logs: bool, + on_headless_host: bool, projects: HashMap, ProjectState>, pub copilot_log_subscription: Option, pub language_servers: HashMap, @@ -138,6 +138,7 @@ pub struct LanguageServerState { pub trace_level: TraceValue, pub log_level: MessageType, io_logs_subscription: Option, + pub toggled_log_kind: Option, } impl std::fmt::Debug for LanguageServerState { @@ -151,6 +152,7 @@ impl std::fmt::Debug for LanguageServerState { .field("rpc_state", &self.rpc_state) .field("trace_level", &self.trace_level) .field("log_level", &self.log_level) + .field("toggled_log_kind", &self.toggled_log_kind) .finish_non_exhaustive() } } @@ -226,14 +228,14 @@ impl LogKind { } impl LogStore { - pub fn new(store_logs: bool, cx: &mut Context) -> Self { + pub fn new(on_headless_host: bool, cx: &mut Context) -> Self { let (io_tx, mut io_rx) = mpsc::unbounded(); let log_store = Self { projects: HashMap::default(), language_servers: HashMap::default(), copilot_log_subscription: None, - store_logs, + on_headless_host, io_tx, }; cx.spawn(async move |log_store, cx| { @@ -351,12 +353,26 @@ impl LogStore { } } } - crate::Event::ToggleLspLogs { server_id, enabled } => { - // we do not support any other log toggling yet - if *enabled { - log_store.enable_rpc_trace_for_language_server(*server_id); - } else { - log_store.disable_rpc_trace_for_language_server(*server_id); + crate::Event::ToggleLspLogs { + server_id, + enabled, + toggled_log_kind, + } => { + if let Some(server_state) = + log_store.get_language_server_state(*server_id) + { + if *enabled { + server_state.toggled_log_kind = Some(*toggled_log_kind); + } else { + server_state.toggled_log_kind = None; + } + } + if LogKind::Rpc == *toggled_log_kind { + if *enabled { + log_store.enable_rpc_trace_for_language_server(*server_id); + } else { + log_store.disable_rpc_trace_for_language_server(*server_id); + } } } _ => {} @@ -395,6 +411,7 @@ impl LogStore { trace_level: TraceValue::Off, log_level: MessageType::LOG, io_logs_subscription: None, + toggled_log_kind: None, } }); @@ -425,7 +442,7 @@ impl LogStore { message: &str, cx: &mut Context, ) -> Option<()> { - let store_logs = self.store_logs; + let store_logs = !self.on_headless_host; let language_server_state = self.get_language_server_state(id)?; let log_lines = &mut language_server_state.log_messages; @@ -464,7 +481,7 @@ impl LogStore { verbose_info: Option, cx: &mut Context, ) -> Option<()> { - let store_logs = self.store_logs; + let store_logs = !self.on_headless_host; let language_server_state = self.get_language_server_state(id)?; let log_lines = &mut language_server_state.trace_messages; @@ -530,7 +547,7 @@ impl LogStore { message: &str, cx: &mut Context<'_, Self>, ) { - let store_logs = self.store_logs; + let store_logs = !self.on_headless_host; let Some(state) = self .get_language_server_state(language_server_id) .and_then(|state| state.rpc_state.as_mut()) @@ -673,6 +690,7 @@ impl LogStore { } fn emit_event(&mut self, e: Event, cx: &mut Context) { + let on_headless_host = self.on_headless_host; match &e { Event::NewServerLogEntry { id, kind, text } => { if let Some(state) = self.get_language_server_state(*id) { @@ -686,14 +704,18 @@ impl LogStore { } .and_then(|lsp_store| lsp_store.read(cx).downstream_client()); if let Some((client, project_id)) = downstream_client { - client - .send(proto::LanguageServerLog { - project_id, - language_server_id: id.to_proto(), - message: text.clone(), - log_type: Some(kind.to_proto()), - }) - .ok(); + if on_headless_host + || Some(LogKind::from_server_log_type(kind)) == state.toggled_log_kind + { + client + .send(proto::LanguageServerLog { + project_id, + language_server_id: id.to_proto(), + message: text.clone(), + log_type: Some(kind.to_proto()), + }) + .ok(); + } } } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 68e04cfd3bec25638964e8fccd675279c450795d..8c289c935cd2bc4ebb919d171f0a9e4f0334b334 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -33,7 +33,7 @@ mod yarn; use dap::inline_value::{InlineValueLocation, VariableLookupKind, VariableScope}; -use crate::git_store::GitStore; +use crate::{git_store::GitStore, lsp_store::log_store::LogKind}; pub use git_store::{ ConflictRegion, ConflictSet, ConflictSetSnapshot, ConflictSetUpdate, git_traversal::{ChildEntriesGitIter, GitEntry, GitEntryRef, GitTraversal}, @@ -285,6 +285,7 @@ pub enum Event { ToggleLspLogs { server_id: LanguageServerId, enabled: bool, + toggled_log_kind: LogKind, }, Toast { notification_id: SharedString, @@ -4719,10 +4720,19 @@ impl Project { envelope: TypedEnvelope, mut cx: AsyncApp, ) -> Result<()> { + let toggled_log_kind = + match proto::toggle_lsp_logs::LogType::from_i32(envelope.payload.log_type) + .context("invalid log type")? + { + proto::toggle_lsp_logs::LogType::Log => LogKind::Logs, + proto::toggle_lsp_logs::LogType::Trace => LogKind::Trace, + proto::toggle_lsp_logs::LogType::Rpc => LogKind::Rpc, + }; project.update(&mut cx, |_, cx| { cx.emit(Event::ToggleLspLogs { server_id: LanguageServerId::from_proto(envelope.payload.server_id), enabled: envelope.payload.enabled, + toggled_log_kind, }) })?; Ok(()) diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index c81a69c2b308d2623ada78b1f38df80f96f8fe14..f55826631b46b4f9eaaa17d8a9f4b0603a07fcc3 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -67,7 +67,7 @@ impl HeadlessProject { settings::init(cx); language::init(cx); project::Project::init_settings(cx); - log_store::init(false, cx); + log_store::init(true, cx); } pub fn new( @@ -546,7 +546,9 @@ impl HeadlessProject { .context("lsp logs store is missing")?; lsp_logs.update(&mut cx, |lsp_logs, _| { - // we do not support any other log toggling yet + // RPC logs are very noisy and we need to toggle it on the headless server too. + // The rest of the logs for the ssh project are very important to have toggled always, + // to e.g. send language server error logs to the client before anything is toggled. if envelope.payload.enabled { lsp_logs.enable_rpc_trace_for_language_server(server_id); } else {