diff --git a/Cargo.lock b/Cargo.lock index 8a87cb9986..4f43215bc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9868,6 +9868,7 @@ dependencies = [ "serde_derive", "serde_json", "settings", + "shellexpand", "simplelog", "smallvec", "smol", diff --git a/assets/settings/default.json b/assets/settings/default.json index 126407a32d..fbc40b4756 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -384,11 +384,11 @@ // "next": "off" // 2. Use a bundled version of the next Next LS LSP server // "next": "on", - // 3. Use a locally running version of the next Next LS LSP server, - // on a specific port: + // 3. Use a local build of the next Next LS LSP server: // "next": { // "local": { - // "port": 4000 + // "path": "~/next-ls/bin/start", + // "arguments": ["--stdio"] // } // }, // diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index 587e6ed25a..d2ad8fac90 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -8,8 +8,8 @@ use gpui::{ ParentElement, Stack, }, platform::{CursorStyle, MouseButton}, - AnyElement, AppContext, Element, Entity, ModelContext, ModelHandle, View, ViewContext, - ViewHandle, WeakModelHandle, + AnyElement, AppContext, Element, Entity, ModelContext, ModelHandle, Subscription, View, + ViewContext, ViewHandle, WeakModelHandle, }; use language::{Buffer, LanguageServerId, LanguageServerName}; use lsp::IoKind; @@ -52,10 +52,12 @@ pub struct LspLogView { current_server_id: Option, is_showing_rpc_trace: bool, project: ModelHandle, + _log_store_subscription: Subscription, } pub struct LspLogToolbarItemView { log_view: Option>, + _log_view_subscription: Option, menu_open: bool, } @@ -346,12 +348,49 @@ impl LspLogView { .get(&project.downgrade()) .and_then(|project| project.servers.keys().copied().next()); let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "")); + let _log_store_subscription = cx.observe(&log_store, |this, store, cx| { + (|| -> Option<()> { + let project_state = store.read(cx).projects.get(&this.project.downgrade())?; + if let Some(current_lsp) = this.current_server_id { + if !project_state.servers.contains_key(¤t_lsp) { + if let Some(server) = project_state.servers.iter().next() { + if this.is_showing_rpc_trace { + this.show_rpc_trace_for_server(*server.0, cx) + } else { + this.show_logs_for_server(*server.0, cx) + } + } else { + this.current_server_id = None; + this.editor.update(cx, |editor, cx| { + editor.set_read_only(false); + editor.clear(cx); + editor.set_read_only(true); + }); + cx.notify(); + } + } + } else { + if let Some(server) = project_state.servers.iter().next() { + if this.is_showing_rpc_trace { + this.show_rpc_trace_for_server(*server.0, cx) + } else { + this.show_logs_for_server(*server.0, cx) + } + } + } + + Some(()) + })(); + + cx.notify(); + }); let mut this = Self { editor: Self::editor_for_buffer(project.clone(), buffer, cx), project, log_store, current_server_id: None, is_showing_rpc_trace: false, + _log_store_subscription, }; if let Some(server_id) = server_id { this.show_logs_for_server(server_id, cx); @@ -556,18 +595,22 @@ impl ToolbarItemView for LspLogToolbarItemView { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, - _: &mut ViewContext, + cx: &mut ViewContext, ) -> workspace::ToolbarItemLocation { self.menu_open = false; if let Some(item) = active_pane_item { if let Some(log_view) = item.downcast::() { self.log_view = Some(log_view.clone()); + self._log_view_subscription = Some(cx.observe(&log_view, |_, _, cx| { + cx.notify(); + })); return ToolbarItemLocation::PrimaryLeft { flex: Some((1., false)), }; } } self.log_view = None; + self._log_view_subscription = None; ToolbarItemLocation::Hidden } } @@ -697,6 +740,7 @@ impl LspLogToolbarItemView { Self { menu_open: false, log_view: None, + _log_view_subscription: None, } } diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index fb41f7a349..ab6844d2de 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -62,6 +62,7 @@ rpc = { path = "../rpc" } settings = { path = "../settings" } feature_flags = { path = "../feature_flags" } sum_tree = { path = "../sum_tree" } +shellexpand = "2.1.0" text = { path = "../text" } terminal_view = { path = "../terminal_view" } theme = { path = "../theme" } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 0d1c2a9d36..2a21e4035f 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -79,11 +79,12 @@ pub fn init( vec![Arc::new(elixir::ElixirLspAdapter)], ), elixir_next::ElixirNextSetting::On => todo!(), - elixir_next::ElixirNextSetting::Local { path } => language( + elixir_next::ElixirNextSetting::Local { path, arguments } => language( "elixir", tree_sitter_elixir::language(), vec![Arc::new(elixir_next::LocalNextLspAdapter { path: path.clone(), + arguments: arguments.clone(), })], ), } diff --git a/crates/zed/src/languages/elixir_next.rs b/crates/zed/src/languages/elixir_next.rs index a25ada92b8..9b12572ec3 100644 --- a/crates/zed/src/languages/elixir_next.rs +++ b/crates/zed/src/languages/elixir_next.rs @@ -5,7 +5,7 @@ use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind}; use schemars::JsonSchema; use serde_derive::{Deserialize, Serialize}; use settings::Setting; -use std::{any::Any, path::PathBuf, sync::Arc}; +use std::{any::Any, ops::Deref, path::PathBuf, sync::Arc}; #[derive(Clone, Serialize, Deserialize, JsonSchema)] pub struct ElixirSettings { @@ -17,7 +17,10 @@ pub struct ElixirSettings { pub enum ElixirNextSetting { Off, On, - Local { path: String }, + Local { + path: String, + arguments: Vec, + }, } #[derive(Clone, Serialize, Default, Deserialize, JsonSchema)] @@ -44,6 +47,7 @@ impl Setting for ElixirSettings { pub struct LocalNextLspAdapter { pub path: String, + pub arguments: Vec, } #[async_trait] @@ -69,9 +73,10 @@ impl LspAdapter for LocalNextLspAdapter { _: PathBuf, _: &dyn LspAdapterDelegate, ) -> Result { + let path = shellexpand::full(&self.path)?; Ok(LanguageServerBinary { - path: self.path.clone().into(), - arguments: vec!["--stdio".into()], + path: PathBuf::from(path.deref()), + arguments: self.arguments.iter().map(|arg| arg.into()).collect(), }) } @@ -80,19 +85,22 @@ impl LspAdapter for LocalNextLspAdapter { _: PathBuf, _: &dyn LspAdapterDelegate, ) -> Option { + let path = shellexpand::full(&self.path).ok()?; Some(LanguageServerBinary { - path: self.path.clone().into(), - arguments: vec!["--stdio".into()], + path: PathBuf::from(path.deref()), + arguments: self.arguments.iter().map(|arg| arg.into()).collect(), }) } async fn installation_test_binary(&self, _: PathBuf) -> Option { + let path = shellexpand::full(&self.path).ok()?; Some(LanguageServerBinary { - path: self.path.clone().into(), - arguments: vec!["--stdio".into()], + path: PathBuf::from(path.deref()), + arguments: self.arguments.iter().map(|arg| arg.into()).collect(), }) } + // TODO: async fn label_for_completion( &self, completion: &lsp::CompletionItem, @@ -147,6 +155,7 @@ impl LspAdapter for LocalNextLspAdapter { None } + // TODO: async fn label_for_symbol( &self, name: &str,