diff --git a/Cargo.lock b/Cargo.lock index c68c2eae3a..7d07e8315d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9211,6 +9211,7 @@ dependencies = [ "gpui", "itertools 0.14.0", "language", + "log", "lsp", "project", "proto", diff --git a/crates/language_tools/Cargo.toml b/crates/language_tools/Cargo.toml index a10b7dc50b..d0ae293a4b 100644 --- a/crates/language_tools/Cargo.toml +++ b/crates/language_tools/Cargo.toml @@ -22,6 +22,7 @@ futures.workspace = true gpui.workspace = true itertools.workspace = true language.workspace = true +log.workspace = true lsp.workspace = true project.workspace = true proto.workspace = true diff --git a/crates/language_tools/src/language_tools.rs b/crates/language_tools/src/language_tools.rs index 45132b6ace..d6a006f47b 100644 --- a/crates/language_tools/src/language_tools.rs +++ b/crates/language_tools/src/language_tools.rs @@ -6,7 +6,6 @@ mod syntax_tree_view; #[cfg(test)] mod lsp_log_tests; -use client::AnyProtoClient; use gpui::{App, AppContext, Entity}; pub use lsp_log::{LogStore, LspLogToolbarItemView, LspLogView}; @@ -14,8 +13,8 @@ pub use syntax_tree_view::{SyntaxTreeToolbarItemView, SyntaxTreeView}; use ui::{Context, Window}; use workspace::{Item, ItemHandle, SplitDirection, Workspace}; -pub fn init(client: AnyProtoClient, cx: &mut App) { - lsp_log::init(client, true, cx); +pub fn init(cx: &mut App) { + lsp_log::init(true, cx); syntax_tree_view::init(cx); key_context_view::init(cx); } diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index ac33a02bcb..67281c1bdb 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -1,11 +1,9 @@ -use anyhow::Result; -use client::AnyProtoClient; use collections::{HashMap, VecDeque}; use copilot::Copilot; use editor::{Editor, EditorEvent, actions::MoveToEnd, scroll::Autoscroll}; use futures::{StreamExt, channel::mpsc}; use gpui::{ - AnyView, App, AsyncApp, Context, Corner, Entity, EventEmitter, FocusHandle, Focusable, Global, + AnyView, App, Context, Corner, Entity, EventEmitter, FocusHandle, Focusable, Global, IntoElement, ParentElement, Render, Styled, Subscription, WeakEntity, Window, actions, div, }; use itertools::Itertools; @@ -15,7 +13,6 @@ use lsp::{ MessageType, SetTraceParams, TraceValue, notification::SetTrace, }; use project::{Project, WorktreeId, lsp_store::LanguageServerLogType, search::SearchQuery}; -use proto::TypedEnvelope; use std::{any::TypeId, borrow::Cow, sync::Arc}; use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*}; use util::ResultExt as _; @@ -115,8 +112,7 @@ impl Message for RpcMessage { type Level = (); } -pub(super) struct LanguageServerState { - project: Option>, +pub struct LanguageServerState { name: Option, worktree_id: Option, kind: LanguageServerKind, @@ -155,7 +151,7 @@ impl LanguageServerKind { } } -struct LanguageServerRpcState { +pub struct LanguageServerRpcState { rpc_messages: VecDeque, last_message_kind: Option, } @@ -232,9 +228,7 @@ pub struct GlobalLogStore(pub WeakEntity); impl Global for GlobalLogStore {} -pub fn init(client: AnyProtoClient, store_logs: bool, cx: &mut App) { - client.add_entity_message_handler(handle_toggle_lsp_logs); - +pub fn init(store_logs: bool, cx: &mut App) { let log_store = cx.new(|cx| LogStore::new(store_logs, cx)); cx.set_global(GlobalLogStore(log_store.downgrade())); @@ -293,7 +287,6 @@ impl LogStore { Some(name), None, Some(server.clone()), - None, cx, ); } @@ -311,9 +304,9 @@ impl LogStore { cx.spawn(async move |this, cx| { while let Some((server_id, io_kind, message)) = io_rx.next().await { - if let Some(this) = this.upgrade() { - this.update(cx, |this, cx| { - this.on_io(server_id, io_kind, &message, cx); + if let Some(log_store) = this.upgrade() { + log_store.update(cx, |log_store, cx| { + log_store.on_io(server_id, io_kind, &message, cx); })?; } } @@ -324,6 +317,11 @@ impl LogStore { } pub fn add_project(&mut self, project: &Entity, cx: &mut Context) { + log::error!( + "?????????????? ssh: {} local: {}", + project.read(cx).is_via_ssh(), + project.read(cx).is_local() + ); let weak_project = project.downgrade(); let subscription_weak_project = weak_project.clone(); self.projects.insert( @@ -336,17 +334,15 @@ impl LogStore { .retain(|_, state| state.kind.project() != Some(&weak_project)); }), cx.subscribe(project, move |log_store, project, event, cx| { - let subscription_weak_project = project.downgrade(); - let server_kind = if project.read(cx).is_via_ssh() { - LanguageServerKind::Remote { - project: project.downgrade(), - } - } else { + let server_kind = if project.read(cx).is_local() { LanguageServerKind::Local { project: project.downgrade(), } + } else { + LanguageServerKind::Remote { + project: project.downgrade(), + } }; - match event { project::Event::LanguageServerAdded(id, name, worktree_id) => { log_store.add_language_server( @@ -359,7 +355,6 @@ impl LogStore { .lsp_store() .read(cx) .language_server_for_id(*id), - Some(subscription_weak_project), cx, ); } @@ -373,7 +368,6 @@ impl LogStore { None, None, None, - Some(subscription_weak_project), cx, ); match typ { @@ -401,24 +395,27 @@ impl LogStore { _ => {} } }), - cx.subscribe_self(move |_, e, cx| match e { - Event::NewServerLogEntry { id, kind, text } => { - subscription_weak_project - .update(cx, |project, cx| { - if let Some((client, project_id)) = - project.lsp_store().read(cx).downstream_client() - { - client - .send(proto::LanguageServerLog { - project_id, - language_server_id: id.to_proto(), - message: text.clone(), - log_type: Some(kind.to_proto()), - }) - .log_err(); - }; - }) - .ok(); + cx.subscribe(&cx.entity(), move |_, _, e, cx| { + log::error!("||??????????????????????????????????????||||||@@@@|| {e:?}"); + match e { + Event::NewServerLogEntry { id, kind, text } => { + subscription_weak_project + .update(cx, |project, cx| { + if let Some((client, project_id)) = + project.lsp_store().read(cx).downstream_client() + { + client + .send(proto::LanguageServerLog { + project_id, + language_server_id: id.to_proto(), + message: text.clone(), + log_type: Some(kind.to_proto()), + }) + .log_err(); + }; + }) + .ok(); + } } }), ], @@ -433,14 +430,13 @@ impl LogStore { self.language_servers.get_mut(&id) } - fn add_language_server( + pub fn add_language_server( &mut self, kind: LanguageServerKind, server_id: LanguageServerId, name: Option, worktree_id: Option, server: Option>, - project: Option>, cx: &mut Context, ) -> Option<&mut LanguageServerState> { let server_state = self.language_servers.entry(server_id).or_insert_with(|| { @@ -449,7 +445,6 @@ impl LogStore { name: None, worktree_id: None, kind, - project, rpc_state: None, log_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES), trace_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES), @@ -619,6 +614,8 @@ impl LogStore { message: message.trim().to_owned(), }); } + + log::error!("|||||||||| {message}"); cx.emit(Event::NewServerLogEntry { id: language_server_id, kind: LanguageServerLogType::Rpc { @@ -628,7 +625,7 @@ impl LogStore { }); } - fn remove_language_server(&mut self, id: LanguageServerId, cx: &mut Context) { + pub fn remove_language_server(&mut self, id: LanguageServerId, cx: &mut Context) { self.language_servers.remove(&id); cx.notify(); } @@ -662,7 +659,7 @@ impl LogStore { }) } - fn enable_rpc_trace_for_language_server( + pub fn enable_rpc_trace_for_language_server( &mut self, server_id: LanguageServerId, ) -> Option<&mut LanguageServerRpcState> { @@ -817,23 +814,6 @@ impl LogStore { } } -async fn handle_toggle_lsp_logs( - lsp_log: Entity, - envelope: TypedEnvelope, - mut cx: AsyncApp, -) -> Result<()> { - let server_id = LanguageServerId::from_proto(envelope.payload.server_id); - lsp_log.update(&mut cx, |lsp_log, _| { - // we do not support any other log toggling yet - if envelope.payload.enabled { - lsp_log.enable_rpc_trace_for_language_server(server_id); - } else { - lsp_log.disable_rpc_trace_for_language_server(server_id); - } - })?; - Ok(()) -} - impl LspLogView { pub fn new( project: Entity, @@ -875,48 +855,48 @@ impl LspLogView { cx.notify(); }); - let events_subscriptions = cx.subscribe_in( - &log_store, - window, - move |log_view, _, e, window, cx| match e { - Event::NewServerLogEntry { id, kind, text } => { - if log_view.current_server_id == Some(*id) - && LogKind::from_server_log_type(kind) == log_view.active_entry_kind - { - log_view.editor.update(cx, |editor, cx| { - editor.set_read_only(false); - let last_offset = editor.buffer().read(cx).len(cx); - let newest_cursor_is_at_end = - editor.selections.newest::(cx).start >= last_offset; - editor.edit( - vec![ - (last_offset..last_offset, text.as_str()), - (last_offset..last_offset, "\n"), - ], - cx, - ); - if text.len() > 1024 - && let Some((fold_offset, _)) = - text.char_indices().dropping(1024).next() - && fold_offset < text.len() - { - editor.fold_ranges( - vec![last_offset + fold_offset..last_offset + text.len()], - false, - window, + let events_subscriptions = + cx.subscribe_in(&log_store, window, move |log_view, _, e, window, cx| { + log::error!("||||||||@@@@|| {e:?}"); + match e { + Event::NewServerLogEntry { id, kind, text } => { + if log_view.current_server_id == Some(*id) + && LogKind::from_server_log_type(kind) == log_view.active_entry_kind + { + log_view.editor.update(cx, |editor, cx| { + editor.set_read_only(false); + let last_offset = editor.buffer().read(cx).len(cx); + let newest_cursor_is_at_end = + editor.selections.newest::(cx).start >= last_offset; + editor.edit( + vec![ + (last_offset..last_offset, text.as_str()), + (last_offset..last_offset, "\n"), + ], cx, ); - } + if text.len() > 1024 + && let Some((fold_offset, _)) = + text.char_indices().dropping(1024).next() + && fold_offset < text.len() + { + editor.fold_ranges( + vec![last_offset + fold_offset..last_offset + text.len()], + false, + window, + cx, + ); + } - if newest_cursor_is_at_end { - editor.request_autoscroll(Autoscroll::bottom(), cx); - } - editor.set_read_only(true); - }); + if newest_cursor_is_at_end { + editor.request_autoscroll(Autoscroll::bottom(), cx); + } + editor.set_read_only(true); + }); + } } } - }, - ); + }); let (editor, editor_subscriptions) = Self::editor_for_logs(String::new(), window, cx); let focus_handle = cx.focus_handle(); @@ -1207,7 +1187,7 @@ impl LspLogView { } if let Some(server_state) = log_store.language_servers.get(&server_id) { - if let Some(project) = &server_state.project { + if let LanguageServerKind::Remote { project } = &server_state.kind { project .update(cx, |project, cx| { if let Some((client, project_id)) = @@ -1937,6 +1917,7 @@ impl ServerInfo { } } +#[derive(Debug)] pub enum Event { NewServerLogEntry { id: LanguageServerId, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 9fd4eed641..b245e7f8a5 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1355,6 +1355,7 @@ impl Project { ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.settings_observer); ssh_proto.subscribe_to_entity(SSH_PROJECT_ID, &this.git_store); + ssh_proto.add_entity_message_handler(Self::handle_toggle_lsp_logs); ssh_proto.add_entity_message_handler(Self::handle_create_buffer_for_peer); ssh_proto.add_entity_message_handler(Self::handle_update_worktree); ssh_proto.add_entity_message_handler(Self::handle_update_project); @@ -4629,6 +4630,16 @@ impl Project { })? } + // TODO kb + async fn handle_toggle_lsp_logs( + _this: Entity, + _envelope: TypedEnvelope, + _cx: AsyncApp, + ) -> Result<()> { + log::error!("##########PPPPPPPPPPPPPPPproject##########################"); + Ok(()) + } + async fn handle_update_buffer_from_ssh( this: Entity, envelope: TypedEnvelope, diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index 30e7cbc9d9..5156dda246 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -1,5 +1,7 @@ use ::proto::{FromProto, ToProto}; use anyhow::{Context as _, Result, anyhow}; +use language_tools::lsp_log::{GlobalLogStore, LanguageServerKind}; +use lsp::LanguageServerId; use extension::ExtensionHostProxy; use extension_host::headless_host::HeadlessExtensionStore; @@ -65,6 +67,7 @@ impl HeadlessProject { settings::init(cx); language::init(cx); project::Project::init_settings(cx); + language_tools::lsp_log::init(false, cx); } pub fn new( @@ -80,7 +83,6 @@ impl HeadlessProject { ) -> Self { debug_adapter_extension::init(proxy.clone(), cx); languages::init(languages.clone(), node_runtime.clone(), cx); - language_tools::lsp_log::init(session.clone(), false, cx); let worktree_store = cx.new(|cx| { let mut store = WorktreeStore::local(true, fs.clone()); @@ -236,6 +238,7 @@ impl HeadlessProject { session.add_entity_request_handler(Self::handle_open_new_buffer); session.add_entity_request_handler(Self::handle_find_search_candidates); session.add_entity_request_handler(Self::handle_open_server_settings); + session.add_entity_message_handler(Self::handle_toggle_lsp_logs); session.add_entity_request_handler(BufferStore::handle_update_buffer); session.add_entity_message_handler(BufferStore::handle_close_buffer); @@ -299,11 +302,38 @@ impl HeadlessProject { fn on_lsp_store_event( &mut self, - _lsp_store: Entity, + lsp_store: Entity, event: &LspStoreEvent, cx: &mut Context, ) { match event { + LspStoreEvent::LanguageServerAdded(id, name, worktree_id) => { + let log_store = cx + .try_global::() + .and_then(|lsp_logs| lsp_logs.0.upgrade()); + if let Some(log_store) = log_store { + log_store.update(cx, |log_store, cx| { + log_store.add_language_server( + LanguageServerKind::Global, + *id, + Some(name.clone()), + *worktree_id, + lsp_store.read(cx).language_server_for_id(*id), + cx, + ); + }); + } + } + LspStoreEvent::LanguageServerRemoved(id) => { + let log_store = cx + .try_global::() + .and_then(|lsp_logs| lsp_logs.0.upgrade()); + if let Some(log_store) = log_store { + log_store.update(cx, |log_store, cx| { + log_store.remove_language_server(*id, cx); + }); + } + } LspStoreEvent::LanguageServerUpdate { language_server_id, name, @@ -500,6 +530,30 @@ impl HeadlessProject { }) } + async fn handle_toggle_lsp_logs( + _: Entity, + envelope: TypedEnvelope, + mut cx: AsyncApp, + ) -> Result<()> { + let server_id = LanguageServerId::from_proto(envelope.payload.server_id); + let lsp_logs = cx + .update(|cx| { + cx.try_global::() + .and_then(|lsp_logs| lsp_logs.0.upgrade()) + })? + .context("lsp logs store is missing")?; + + lsp_logs.update(&mut cx, |lsp_logs, _| { + // we do not support any other log toggling yet + if envelope.payload.enabled { + lsp_logs.enable_rpc_trace_for_language_server(server_id); + } else { + lsp_logs.disable_rpc_trace_for_language_server(server_id); + } + })?; + Ok(()) + } + async fn handle_open_server_settings( this: Entity, _: TypedEnvelope, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 9d45c8bef1..943984cf07 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -7425,6 +7425,7 @@ pub fn open_ssh_project_with_new_connection( cx, ) })?; + // TODO kb register here instead? open_ssh_project_inner( project, diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 6cacf0fcbd..e99c8b564b 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -5,7 +5,7 @@ use agent_ui::AgentPanel; use anyhow::{Context as _, Result}; use clap::{Parser, command}; use cli::FORCE_CLI_MODE_ENV_VAR_NAME; -use client::{AnyProtoClient, Client, ProxySettings, UserStore, parse_zed_link}; +use client::{Client, ProxySettings, UserStore, parse_zed_link}; use collab_ui::channel_view::ChannelView; use collections::HashMap; use crashes::InitCrashHandler; @@ -621,7 +621,7 @@ pub fn main() { toolchain_selector::init(cx); theme_selector::init(cx); settings_profile_selector::init(cx); - language_tools::init(AnyProtoClient::new(app_state.client.clone()), cx); + language_tools::init(cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx); notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx); collab_ui::init(&app_state, cx);