Show supplementary language servers in the logs panel

Kirill Bulatov created

Change summary

crates/copilot/src/copilot.rs              | 11 ++++--
crates/language_tools/src/lsp_log.rs       | 36 +++++++++++++++++------
crates/language_tools/src/lsp_log_tests.rs |  9 +++++
crates/project/src/project.rs              | 23 ++++++++++++---
4 files changed, 59 insertions(+), 20 deletions(-)

Detailed changes

crates/copilot/src/copilot.rs 🔗

@@ -11,8 +11,8 @@ use gpui::{
 };
 use language::{
     language_settings::{all_language_settings, language_settings},
-    point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
-    ToPointUtf16,
+    point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language,
+    LanguageServerName, PointUtf16, ToPointUtf16,
 };
 use log::{debug, error};
 use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId};
@@ -130,6 +130,7 @@ impl CopilotServer {
 }
 
 struct RunningCopilotServer {
+    name: LanguageServerName,
     lsp: Arc<LanguageServer>,
     sign_in_status: SignInStatus,
     registered_buffers: HashMap<usize, RegisteredBuffer>,
@@ -361,6 +362,7 @@ impl Copilot {
             http: http.clone(),
             node_runtime,
             server: CopilotServer::Running(RunningCopilotServer {
+                name: LanguageServerName(Arc::from("copilot")),
                 lsp: Arc::new(server),
                 sign_in_status: SignInStatus::Authorized,
                 registered_buffers: Default::default(),
@@ -439,6 +441,7 @@ impl Copilot {
                 match server {
                     Ok((server, status)) => {
                         this.server = CopilotServer::Running(RunningCopilotServer {
+                            name: LanguageServerName(Arc::from("copilot")),
                             lsp: server,
                             sign_in_status: SignInStatus::SignedOut,
                             registered_buffers: Default::default(),
@@ -576,9 +579,9 @@ impl Copilot {
         cx.foreground().spawn(start_task)
     }
 
-    pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
+    pub fn language_server(&self) -> Option<(&LanguageServerName, &Arc<LanguageServer>)> {
         if let CopilotServer::Running(server) = &self.server {
-            Some(&server.lsp)
+            Some((&server.name, &server.lsp))
         } else {
             None
         }

crates/language_tools/src/lsp_log.rs 🔗

@@ -13,7 +13,7 @@ use gpui::{
 };
 use language::{Buffer, LanguageServerId, LanguageServerName};
 use lsp::IoKind;
-use project::{search::SearchQuery, Project, Worktree};
+use project::{search::SearchQuery, Project};
 use std::{borrow::Cow, sync::Arc};
 use theme::{ui, Theme};
 use workspace::{
@@ -70,7 +70,7 @@ enum MessageKind {
 pub(crate) struct LogMenuItem {
     pub server_id: LanguageServerId,
     pub server_name: LanguageServerName,
-    pub worktree: ModelHandle<Worktree>,
+    pub worktree_root_name: String,
     pub rpc_trace_enabled: bool,
     pub rpc_trace_selected: bool,
     pub logs_selected: bool,
@@ -203,7 +203,6 @@ impl LogStore {
                 }
             })
         });
-
         Some(server_state.log_buffer.clone())
     }
 
@@ -410,7 +409,7 @@ impl LspLogView {
                 Some(LogMenuItem {
                     server_id,
                     server_name: language_server_name,
-                    worktree,
+                    worktree_root_name: worktree.read(cx).root_name().to_string(),
                     rpc_trace_enabled: state.rpc_state.is_some(),
                     rpc_trace_selected: self.is_showing_rpc_trace
                         && self.current_server_id == Some(server_id),
@@ -418,6 +417,24 @@ impl LspLogView {
                         && self.current_server_id == Some(server_id),
                 })
             })
+            .chain(
+                self.project
+                    .read(cx)
+                    .supplementary_language_servers()
+                    .filter_map(|(&server_id, (name, _))| {
+                        let state = state.servers.get(&server_id)?;
+                        Some(LogMenuItem {
+                            server_id,
+                            server_name: name.clone(),
+                            worktree_root_name: "supplementary".to_string(),
+                            rpc_trace_enabled: state.rpc_state.is_some(),
+                            rpc_trace_selected: self.is_showing_rpc_trace
+                                && self.current_server_id == Some(server_id),
+                            logs_selected: !self.is_showing_rpc_trace
+                                && self.current_server_id == Some(server_id),
+                        })
+                    }),
+            )
             .collect::<Vec<_>>();
         rows.sort_by_key(|row| row.server_id);
         rows.dedup_by_key(|row| row.server_id);
@@ -635,7 +652,7 @@ impl View for LspLogToolbarItemView {
                                     Self::render_language_server_menu_item(
                                         row.server_id,
                                         row.server_name,
-                                        row.worktree,
+                                        &row.worktree_root_name,
                                         row.rpc_trace_enabled,
                                         row.logs_selected,
                                         row.rpc_trace_selected,
@@ -767,15 +784,14 @@ impl LspLogToolbarItemView {
         cx: &mut ViewContext<Self>,
     ) -> impl Element<Self> {
         enum ToggleMenu {}
-        MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, cx| {
+        MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, _| {
             let label: Cow<str> = current_server
                 .and_then(|row| {
-                    let worktree = row.worktree.read(cx);
                     Some(
                         format!(
                             "{} ({}) - {}",
                             row.server_name.0,
-                            worktree.root_name(),
+                            row.worktree_root_name,
                             if row.rpc_trace_selected {
                                 RPC_MESSAGES
                             } else {
@@ -800,7 +816,7 @@ impl LspLogToolbarItemView {
     fn render_language_server_menu_item(
         id: LanguageServerId,
         name: LanguageServerName,
-        worktree: ModelHandle<Worktree>,
+        worktree_root_name: &str,
         rpc_trace_enabled: bool,
         logs_selected: bool,
         rpc_trace_selected: bool,
@@ -814,7 +830,7 @@ impl LspLogToolbarItemView {
             .with_child({
                 let style = &theme.toolbar_dropdown_menu.section_header;
                 Label::new(
-                    format!("{} ({})", name.0, worktree.read(cx).root_name()),
+                    format!("{} ({})", name.0, worktree_root_name),
                     style.text.clone(),
                 )
                 .contained()

crates/language_tools/src/lsp_log_tests.rs 🔗

@@ -77,7 +77,14 @@ async fn test_lsp_logs(cx: &mut TestAppContext) {
             &[LogMenuItem {
                 server_id: language_server.server.server_id(),
                 server_name: LanguageServerName("the-rust-language-server".into()),
-                worktree: project.read(cx).worktrees(cx).next().unwrap(),
+                worktree_root_name: project
+                    .read(cx)
+                    .worktrees(cx)
+                    .next()
+                    .unwrap()
+                    .read(cx)
+                    .root_name()
+                    .to_string(),
                 rpc_trace_enabled: false,
                 rpc_trace_selected: false,
                 logs_selected: true,

crates/project/src/project.rs 🔗

@@ -108,7 +108,8 @@ pub struct Project {
     active_entry: Option<ProjectEntryId>,
     buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
     languages: Arc<LanguageRegistry>,
-    supplementary_language_servers: HashMap<LanguageServerId, Arc<LanguageServer>>,
+    supplementary_language_servers:
+        HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
     language_servers: HashMap<LanguageServerId, LanguageServerState>,
     language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
     language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
@@ -7951,10 +7952,22 @@ impl Project {
             })
     }
 
+    pub fn supplementary_language_servers(
+        &self,
+    ) -> impl '_
+           + Iterator<
+        Item = (
+            &LanguageServerId,
+            &(LanguageServerName, Arc<LanguageServer>),
+        ),
+    > {
+        self.supplementary_language_servers.iter()
+    }
+
     pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
         if let LanguageServerState::Running { server, .. } = self.language_servers.get(&id)? {
             Some(server.clone())
-        } else if let Some(server) = self.supplementary_language_servers.get(&id) {
+        } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
             Some(Arc::clone(server))
         } else {
             None
@@ -8023,13 +8036,13 @@ fn subscribe_for_copilot_events(
         copilot,
         |project, copilot, copilot_event, cx| match copilot_event {
             copilot::Event::CopilotReady => {
-                if let Some(copilot_server) = copilot.read(cx).language_server() {
+                if let Some((name, copilot_server)) = copilot.read(cx).language_server() {
                     let new_server_id = copilot_server.server_id();
                     if let hash_map::Entry::Vacant(v) =
                         project.supplementary_language_servers.entry(new_server_id)
                     {
-                        v.insert(Arc::clone(copilot_server));
-                        cx.emit(Event::LanguageServerAdded(new_server_id))
+                        v.insert((name.clone(), Arc::clone(copilot_server)));
+                        cx.emit(Event::LanguageServerAdded(new_server_id));
                     }
                 }
             }