Skip to content

Commit

Permalink
Show DAP status in activity bar (#54)
Browse files Browse the repository at this point in the history
* Begin integrating languages with DAP

* Add dap status type to activity indicator

Co-authored-by: Remco Smits <djsmits12@gmail.com>

* Show dap status to users

* Change Status enum to use ServerStatus struct in activity indicator

---------

Co-authored-by: Remco Smits <djsmits12@gmail.com>
  • Loading branch information
Anthony-Eid and RemcoSmitsDev authored Oct 27, 2024
1 parent ddaf150 commit d279afa
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 12 deletions.
29 changes: 23 additions & 6 deletions crates/activity_indicator/src/activity_indicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ actions!(activity_indicator, [ShowErrorMessage]);

pub enum Event {
ShowError {
lsp_name: LanguageServerName,
server_name: LanguageServerName,
error: String,
},
}

pub struct ActivityIndicator {
statuses: Vec<LspStatus>,
statuses: Vec<ServerStatus>,
project: Model<Project>,
auto_updater: Option<Model<AutoUpdater>>,
context_menu_handle: PopoverMenuHandle<ContextMenu>,
}

struct LspStatus {
struct ServerStatus {
name: LanguageServerName,
status: LanguageServerBinaryStatus,
}
Expand Down Expand Up @@ -63,13 +63,27 @@ impl ActivityIndicator {
while let Some((name, status)) = status_events.next().await {
this.update(&mut cx, |this, cx| {
this.statuses.retain(|s| s.name != name);
this.statuses.push(LspStatus { name, status });
this.statuses.push(ServerStatus { name, status });
cx.notify();
})?;
}
anyhow::Ok(())
})
.detach();

let mut status_events = languages.dap_server_binary_statuses();
cx.spawn(|this, mut cx| async move {
while let Some((name, status)) = status_events.next().await {
this.update(&mut cx, |this, cx| {
this.statuses.retain(|s| s.name != name);
this.statuses.push(ServerStatus { name, status });
cx.notify();
})?;
}
anyhow::Ok(())
})
.detach();

cx.observe(&project, |_, _, cx| cx.notify()).detach();

if let Some(auto_updater) = auto_updater.as_ref() {
Expand All @@ -85,7 +99,10 @@ impl ActivityIndicator {
});

cx.subscribe(&this, move |_, _, event, cx| match event {
Event::ShowError { lsp_name, error } => {
Event::ShowError {
server_name: lsp_name,
error,
} => {
let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx));
let project = project.clone();
let error = error.clone();
Expand Down Expand Up @@ -127,7 +144,7 @@ impl ActivityIndicator {
self.statuses.retain(|status| {
if let LanguageServerBinaryStatus::Failed { error } = &status.status {
cx.emit(Event::ShowError {
lsp_name: status.name.clone(),
server_name: status.name.clone(),
error: error.clone(),
});
false
Expand Down
11 changes: 11 additions & 0 deletions crates/dap/src/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ use std::{
};
use task::DebugAdapterConfig;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DapStatus {
None,
CheckingForUpdate,
Downloading,
Failed { error: String },
}

pub trait DapDelegate {
fn http_client(&self) -> Option<Arc<dyn HttpClient>>;
fn node_runtime(&self) -> Option<NodeRuntime>;
fn fs(&self) -> Arc<dyn Fs>;
fn cached_binaries(&self) -> Arc<Mutex<HashMap<DebugAdapterName, DebugAdapterBinary>>>;
fn update_status(&self, dap_name: DebugAdapterName, status: DapStatus);
}

#[derive(PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -189,6 +198,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
}

log::info!("Getting latest version of debug adapter {}", self.name());
delegate.update_status(self.name(), DapStatus::CheckingForUpdate);
let version = self.fetch_latest_adapter_version(delegate).await.ok();

let mut binary = self.get_installed_binary(delegate, config).await;
Expand All @@ -209,6 +219,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
return Ok(binary);
}

delegate.update_status(self.name(), DapStatus::Downloading);
self.install_binary(version, delegate).await?;
binary = self.get_installed_binary(delegate, config).await;
}
Expand Down
36 changes: 36 additions & 0 deletions crates/language/src/language_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub struct LanguageRegistry {
language_server_download_dir: Option<Arc<Path>>,
executor: BackgroundExecutor,
lsp_binary_status_tx: LspBinaryStatusSender,
dap_binary_status_tx: DapBinaryStatusSender,
}

struct LanguageRegistryState {
Expand Down Expand Up @@ -222,6 +223,7 @@ impl LanguageRegistry {
}),
language_server_download_dir: None,
lsp_binary_status_tx: Default::default(),
dap_binary_status_tx: Default::default(),
executor,
};
this.add(PLAIN_TEXT.clone());
Expand Down Expand Up @@ -875,6 +877,14 @@ impl LanguageRegistry {
self.lsp_binary_status_tx.send(server_name, status);
}

pub fn update_dap_status(
&self,
server_name: LanguageServerName,
status: LanguageServerBinaryStatus,
) {
self.dap_binary_status_tx.send(server_name, status);
}

pub fn next_language_server_id(&self) -> LanguageServerId {
self.state.write().next_language_server_id()
}
Expand Down Expand Up @@ -930,6 +940,12 @@ impl LanguageRegistry {
self.lsp_binary_status_tx.subscribe()
}

pub fn dap_server_binary_statuses(
&self,
) -> mpsc::UnboundedReceiver<(LanguageServerName, LanguageServerBinaryStatus)> {
self.dap_binary_status_tx.subscribe()
}

pub async fn delete_server_container(&self, name: LanguageServerName) {
log::info!("deleting server container");
let Some(dir) = self.language_server_download_dir(&name) else {
Expand Down Expand Up @@ -1039,6 +1055,26 @@ impl LanguageRegistryState {
}
}

#[derive(Clone, Default)]
struct DapBinaryStatusSender {
txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, LanguageServerBinaryStatus)>>>>,
}

impl DapBinaryStatusSender {
fn subscribe(
&self,
) -> mpsc::UnboundedReceiver<(LanguageServerName, LanguageServerBinaryStatus)> {
let (tx, rx) = mpsc::unbounded();
self.txs.lock().push(tx);
rx
}

fn send(&self, name: LanguageServerName, status: LanguageServerBinaryStatus) {
let mut txs = self.txs.lock();
txs.retain(|tx| tx.unbounded_send((name.clone(), status.clone())).is_ok());
}
}

impl LspBinaryStatusSender {
fn subscribe(
&self,
Expand Down
28 changes: 25 additions & 3 deletions crates/project/src/dap_store.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::ProjectPath;
use anyhow::{anyhow, Context as _, Result};
use collections::HashSet;
use dap::adapters::{DebugAdapterBinary, DebugAdapterName};
use dap::adapters::{DapStatus, DebugAdapterBinary, DebugAdapterName};
use dap::client::{DebugAdapterClient, DebugAdapterClientId};
use dap::messages::{Message, Response};
use dap::requests::{
Expand All @@ -23,9 +23,11 @@ use dap::{
};
use dap_adapters::build_adapter;
use fs::Fs;
use gpui::{EventEmitter, Model, ModelContext, Task};
use gpui::{EventEmitter, Model, ModelContext, SharedString, Task};
use http_client::HttpClient;
use language::{Buffer, BufferSnapshot};
use language::{
Buffer, BufferSnapshot, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName,
};
use node_runtime::NodeRuntime;
use serde_json::{json, Value};
use settings::WorktreeId;
Expand Down Expand Up @@ -73,6 +75,7 @@ pub struct DapStore {
active_debug_line: Option<(ProjectPath, DebugPosition)>,
http_client: Option<Arc<dyn HttpClient>>,
node_runtime: Option<NodeRuntime>,
languages: Arc<LanguageRegistry>,
fs: Arc<dyn Fs>,
}

Expand All @@ -83,6 +86,7 @@ impl DapStore {
http_client: Option<Arc<dyn HttpClient>>,
node_runtime: Option<NodeRuntime>,
fs: Arc<dyn Fs>,
_languages: Arc<LanguageRegistry>,
cx: &mut ModelContext<Self>,
) -> Self {
cx.on_app_quit(Self::shutdown_clients).detach();
Expand All @@ -96,6 +100,7 @@ impl DapStore {
next_client_id: Default::default(),
http_client,
node_runtime,
languages: _languages,
fs,
}
}
Expand Down Expand Up @@ -248,6 +253,7 @@ impl DapStore {
self.node_runtime.clone(),
self.fs.clone(),
self.cached_binaries.clone(),
self.languages.clone(),
);
let start_client_task = cx.spawn(|this, mut cx| async move {
let dap_store = this.clone();
Expand Down Expand Up @@ -1234,6 +1240,7 @@ pub struct DapAdapterDelegate {
http_client: Option<Arc<dyn HttpClient>>,
node_runtime: Option<NodeRuntime>,
cached_binaries: Arc<Mutex<HashMap<DebugAdapterName, DebugAdapterBinary>>>,
languages: Arc<LanguageRegistry>,
}

impl DapAdapterDelegate {
Expand All @@ -1242,12 +1249,14 @@ impl DapAdapterDelegate {
node_runtime: Option<NodeRuntime>,
fs: Arc<dyn Fs>,
cached_binaries: Arc<Mutex<HashMap<DebugAdapterName, DebugAdapterBinary>>>,
languages: Arc<LanguageRegistry>,
) -> Self {
Self {
fs,
http_client,
node_runtime,
cached_binaries,
languages,
}
}
}
Expand All @@ -1268,4 +1277,17 @@ impl dap::adapters::DapDelegate for DapAdapterDelegate {
fn cached_binaries(&self) -> Arc<Mutex<HashMap<DebugAdapterName, DebugAdapterBinary>>> {
self.cached_binaries.clone()
}

fn update_status(&self, dap_name: DebugAdapterName, status: dap::adapters::DapStatus) {
let name = SharedString::from(dap_name.to_string());
let status = match status {
DapStatus::None => LanguageServerBinaryStatus::None,
DapStatus::Downloading => LanguageServerBinaryStatus::Downloading,
DapStatus::Failed { error } => LanguageServerBinaryStatus::Failed { error },
DapStatus::CheckingForUpdate => LanguageServerBinaryStatus::CheckingForUpdate,
};

self.languages
.update_dap_status(LanguageServerName(name), status);
}
}
13 changes: 11 additions & 2 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ impl Project {
Some(client.http_client()),
Some(node.clone()),
fs.clone(),
languages.clone(),
cx,
)
});
Expand Down Expand Up @@ -786,6 +787,7 @@ impl Project {
Some(client.http_client()),
Some(node.clone()),
fs.clone(),
languages.clone(),
cx,
)
});
Expand Down Expand Up @@ -944,8 +946,15 @@ impl Project {
BufferStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
})?;

let dap_store =
cx.new_model(|cx| DapStore::new(Some(client.http_client()), None, fs.clone(), cx))?;
let dap_store = cx.new_model(|cx| {
DapStore::new(
Some(client.http_client()),
None,
fs.clone(),
languages.clone(),
cx,
)
})?;

let lsp_store = cx.new_model(|cx| {
let mut lsp_store = LspStore::new_remote(
Expand Down
3 changes: 2 additions & 1 deletion crates/remote_server/src/headless_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ impl HeadlessProject {
store
});

let dap_store = cx.new_model(|cx| DapStore::new(None, None, fs.clone(), cx));
let dap_store =
cx.new_model(|cx| DapStore::new(None, None, fs.clone(), languages.clone(), cx));
let buffer_store = cx.new_model(|cx| {
let mut buffer_store =
BufferStore::local(worktree_store.clone(), dap_store.clone(), cx);
Expand Down

0 comments on commit d279afa

Please sign in to comment.