Compare commits
1 Commits
acp-thinki
...
dap-logs-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
701612786e |
@@ -84,19 +84,6 @@ impl ActivityIndicator {
|
||||
})
|
||||
.detach();
|
||||
|
||||
let mut status_events = languages.dap_server_binary_statuses();
|
||||
cx.spawn(async move |this, cx| {
|
||||
while let Some((name, status)) = status_events.next().await {
|
||||
this.update(cx, |this, cx| {
|
||||
this.statuses.retain(|s| s.name != name);
|
||||
this.statuses.push(ServerStatus { name, status });
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
cx.subscribe(
|
||||
&project.read(cx).lsp_store(),
|
||||
|_, _, event, cx| match event {
|
||||
|
||||
@@ -42,7 +42,7 @@ pub trait DapDelegate {
|
||||
fn toolchain_store(&self) -> Arc<dyn LanguageToolchainStore>;
|
||||
fn fs(&self) -> Arc<dyn Fs>;
|
||||
fn updated_adapters(&self) -> Arc<Mutex<HashSet<DebugAdapterName>>>;
|
||||
fn update_status(&self, dap_name: DebugAdapterName, status: DapStatus);
|
||||
fn output_to_console(&self, msg: String);
|
||||
fn which(&self, command: &OsStr) -> Option<PathBuf>;
|
||||
async fn shell_env(&self) -> collections::HashMap<String, String>;
|
||||
}
|
||||
@@ -442,25 +442,12 @@ pub trait DebugAdapter: 'static + Send + Sync {
|
||||
}
|
||||
|
||||
log::info!("Getting latest version of debug adapter {}", self.name());
|
||||
delegate.update_status(self.name(), DapStatus::CheckingForUpdate);
|
||||
|
||||
delegate.output_to_console(format!("Checking latest version of {}...", self.name()));
|
||||
if let Some(version) = self.fetch_latest_adapter_version(delegate).await.log_err() {
|
||||
log::info!("Installing latest version of debug adapter {}", self.name());
|
||||
delegate.update_status(self.name(), DapStatus::Downloading);
|
||||
match self.install_binary(version, delegate).await {
|
||||
Ok(_) => {
|
||||
delegate.update_status(self.name(), DapStatus::None);
|
||||
}
|
||||
Err(error) => {
|
||||
delegate.update_status(
|
||||
self.name(),
|
||||
DapStatus::Failed {
|
||||
error: error.to_string(),
|
||||
},
|
||||
);
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
delegate.output_to_console(format!("Installing {}...", version.tag_name));
|
||||
self.install_binary(version, delegate).await?;
|
||||
|
||||
delegate
|
||||
.updated_adapters()
|
||||
|
||||
@@ -104,7 +104,6 @@ pub struct LanguageRegistry {
|
||||
language_server_download_dir: Option<Arc<Path>>,
|
||||
executor: BackgroundExecutor,
|
||||
lsp_binary_status_tx: BinaryStatusSender,
|
||||
dap_binary_status_tx: BinaryStatusSender,
|
||||
}
|
||||
|
||||
struct LanguageRegistryState {
|
||||
@@ -269,7 +268,6 @@ 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());
|
||||
@@ -986,10 +984,6 @@ impl LanguageRegistry {
|
||||
self.lsp_binary_status_tx.send(server_name.0, status);
|
||||
}
|
||||
|
||||
pub fn update_dap_status(&self, server_name: LanguageServerName, status: BinaryStatus) {
|
||||
self.dap_binary_status_tx.send(server_name.0, status);
|
||||
}
|
||||
|
||||
pub fn next_language_server_id(&self) -> LanguageServerId {
|
||||
self.state.write().next_language_server_id()
|
||||
}
|
||||
@@ -1046,12 +1040,6 @@ impl LanguageRegistry {
|
||||
self.lsp_binary_status_tx.subscribe()
|
||||
}
|
||||
|
||||
pub fn dap_server_binary_statuses(
|
||||
&self,
|
||||
) -> mpsc::UnboundedReceiver<(SharedString, BinaryStatus)> {
|
||||
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 {
|
||||
|
||||
@@ -16,22 +16,20 @@ use collections::HashMap;
|
||||
use dap::{
|
||||
Capabilities, CompletionItem, CompletionsArguments, DapRegistry, DebugRequest,
|
||||
EvaluateArguments, EvaluateArgumentsContext, EvaluateResponse, Source, StackFrameId,
|
||||
adapters::{
|
||||
DapStatus, DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition, TcpArguments,
|
||||
},
|
||||
adapters::{DebugAdapterBinary, DebugAdapterName, DebugTaskDefinition, TcpArguments},
|
||||
client::SessionId,
|
||||
messages::Message,
|
||||
requests::{Completions, Evaluate},
|
||||
};
|
||||
use fs::Fs;
|
||||
use futures::future::{Shared, join_all};
|
||||
use futures::{
|
||||
StreamExt,
|
||||
channel::mpsc::{self, UnboundedSender},
|
||||
future::{Shared, join_all},
|
||||
};
|
||||
use gpui::{App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task};
|
||||
use http_client::HttpClient;
|
||||
use language::{
|
||||
BinaryStatus, Buffer, LanguageRegistry, LanguageToolchainStore,
|
||||
language_settings::InlayHintKind, range_from_lsp,
|
||||
};
|
||||
use lsp::LanguageServerName;
|
||||
use language::{Buffer, LanguageToolchainStore, language_settings::InlayHintKind, range_from_lsp};
|
||||
use node_runtime::NodeRuntime;
|
||||
|
||||
use remote::SshRemoteClient;
|
||||
@@ -78,7 +76,6 @@ pub struct LocalDapStore {
|
||||
node_runtime: NodeRuntime,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
environment: Entity<ProjectEnvironment>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
}
|
||||
|
||||
@@ -102,12 +99,13 @@ impl EventEmitter<DapStoreEvent> for DapStore {}
|
||||
impl DapStore {
|
||||
pub fn init(client: &AnyProtoClient, cx: &mut App) {
|
||||
static ADD_LOCATORS: Once = Once::new();
|
||||
client.add_entity_request_handler(Self::handle_run_debug_locator);
|
||||
client.add_entity_request_handler(Self::handle_get_debug_adapter_binary);
|
||||
ADD_LOCATORS.call_once(|| {
|
||||
DapRegistry::global(cx)
|
||||
.add_locator("cargo".into(), Arc::new(locators::cargo::CargoLocator {}))
|
||||
});
|
||||
client.add_entity_request_handler(Self::handle_run_debug_locator);
|
||||
client.add_entity_request_handler(Self::handle_get_debug_adapter_binary);
|
||||
client.add_entity_message_handler(Self::handle_log_to_debug_console);
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
@@ -115,7 +113,6 @@ impl DapStore {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
node_runtime: NodeRuntime,
|
||||
fs: Arc<dyn Fs>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
environment: Entity<ProjectEnvironment>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
worktree_store: Entity<WorktreeStore>,
|
||||
@@ -128,7 +125,6 @@ impl DapStore {
|
||||
http_client,
|
||||
node_runtime,
|
||||
toolchain_store,
|
||||
language_registry,
|
||||
});
|
||||
|
||||
Self::new(mode, breakpoint_store, worktree_store, cx)
|
||||
@@ -179,6 +175,8 @@ impl DapStore {
|
||||
pub fn get_debug_adapter_binary(
|
||||
&mut self,
|
||||
definition: DebugTaskDefinition,
|
||||
session_id: SessionId,
|
||||
console: UnboundedSender<String>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<DebugAdapterBinary>> {
|
||||
match &self.mode {
|
||||
@@ -196,7 +194,7 @@ impl DapStore {
|
||||
.get(&adapter.name())
|
||||
.and_then(|s| s.binary.as_ref().map(PathBuf::from));
|
||||
|
||||
let delegate = self.delegate(&worktree, cx);
|
||||
let delegate = self.delegate(&worktree, console, cx);
|
||||
let cwd: Arc<Path> = definition
|
||||
.cwd()
|
||||
.unwrap_or(worktree.read(cx).abs_path().as_ref())
|
||||
@@ -228,6 +226,7 @@ impl DapStore {
|
||||
}
|
||||
DapStoreMode::Ssh(ssh) => {
|
||||
let request = ssh.upstream_client.request(proto::GetDebugAdapterBinary {
|
||||
session_id: session_id.to_proto(),
|
||||
project_id: ssh.upstream_project_id,
|
||||
definition: Some(definition.to_proto()),
|
||||
});
|
||||
@@ -445,13 +444,15 @@ impl DapStore {
|
||||
};
|
||||
|
||||
let dap_store = cx.weak_entity();
|
||||
let console = session.update(cx, |session, cx| session.console_output(cx));
|
||||
let session_id = session.read(cx).session_id();
|
||||
|
||||
cx.spawn({
|
||||
let session = session.clone();
|
||||
async move |this, cx| {
|
||||
let mut binary = this
|
||||
.update(cx, |this, cx| {
|
||||
this.get_debug_adapter_binary(definition.clone(), cx)
|
||||
this.get_debug_adapter_binary(definition.clone(), session_id, console, cx)
|
||||
})?
|
||||
.await?;
|
||||
|
||||
@@ -522,7 +523,12 @@ impl DapStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delegate(&self, worktree: &Entity<Worktree>, cx: &mut App) -> DapAdapterDelegate {
|
||||
fn delegate(
|
||||
&self,
|
||||
worktree: &Entity<Worktree>,
|
||||
console: UnboundedSender<String>,
|
||||
cx: &mut App,
|
||||
) -> DapAdapterDelegate {
|
||||
let Some(local_store) = self.as_local() else {
|
||||
unimplemented!("Starting session on remote side");
|
||||
};
|
||||
@@ -530,9 +536,9 @@ impl DapStore {
|
||||
DapAdapterDelegate::new(
|
||||
local_store.fs.clone(),
|
||||
worktree.read(cx).id(),
|
||||
console,
|
||||
local_store.node_runtime.clone(),
|
||||
local_store.http_client.clone(),
|
||||
local_store.language_registry.clone(),
|
||||
local_store.toolchain_store.clone(),
|
||||
local_store.environment.update(cx, |env, cx| {
|
||||
env.get_worktree_environment(worktree.clone(), cx)
|
||||
@@ -802,22 +808,64 @@ impl DapStore {
|
||||
.definition
|
||||
.ok_or_else(|| anyhow!("missing definition"))?,
|
||||
)?;
|
||||
let (tx, mut rx) = mpsc::unbounded();
|
||||
let session_id = envelope.payload.session_id;
|
||||
cx.spawn({
|
||||
let this = this.clone();
|
||||
async move |cx| {
|
||||
while let Some(message) = rx.next().await {
|
||||
this.update(cx, |this, _| {
|
||||
if let Some((downstream, project_id)) = this.downstream_client.clone() {
|
||||
downstream
|
||||
.send(proto::LogToDebugConsole {
|
||||
project_id,
|
||||
session_id,
|
||||
message,
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
let binary = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.get_debug_adapter_binary(definition, cx)
|
||||
this.get_debug_adapter_binary(definition, SessionId::from_proto(session_id), tx, cx)
|
||||
})?
|
||||
.await?;
|
||||
Ok(binary.to_proto())
|
||||
}
|
||||
|
||||
async fn handle_log_to_debug_console(
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::LogToDebugConsole>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<()> {
|
||||
let session_id = SessionId::from_proto(envelope.payload.session_id);
|
||||
this.update(&mut cx, |this, cx| {
|
||||
let Some(session) = this.sessions.get(&session_id) else {
|
||||
return;
|
||||
};
|
||||
session.update(cx, |session, cx| {
|
||||
session
|
||||
.console_output(cx)
|
||||
.unbounded_send(envelope.payload.message)
|
||||
.ok();
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DapAdapterDelegate {
|
||||
fs: Arc<dyn Fs>,
|
||||
console: mpsc::UnboundedSender<String>,
|
||||
worktree_id: WorktreeId,
|
||||
node_runtime: NodeRuntime,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
updated_adapters: Arc<Mutex<HashSet<DebugAdapterName>>>,
|
||||
load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
|
||||
@@ -827,19 +875,19 @@ impl DapAdapterDelegate {
|
||||
pub fn new(
|
||||
fs: Arc<dyn Fs>,
|
||||
worktree_id: WorktreeId,
|
||||
status: mpsc::UnboundedSender<String>,
|
||||
node_runtime: NodeRuntime,
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
fs,
|
||||
console: status,
|
||||
worktree_id,
|
||||
http_client,
|
||||
node_runtime,
|
||||
toolchain_store,
|
||||
language_registry,
|
||||
load_shell_env_task,
|
||||
updated_adapters: Default::default(),
|
||||
}
|
||||
@@ -868,17 +916,8 @@ impl dap::adapters::DapDelegate for DapAdapterDelegate {
|
||||
self.updated_adapters.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 => BinaryStatus::None,
|
||||
DapStatus::Downloading => BinaryStatus::Downloading,
|
||||
DapStatus::Failed { error } => BinaryStatus::Failed { error },
|
||||
DapStatus::CheckingForUpdate => BinaryStatus::CheckingForUpdate,
|
||||
};
|
||||
|
||||
self.language_registry
|
||||
.update_dap_status(LanguageServerName(name), status);
|
||||
fn output_to_console(&self, msg: String) {
|
||||
self.console.unbounded_send(msg).ok();
|
||||
}
|
||||
|
||||
fn which(&self, command: &OsStr) -> Option<PathBuf> {
|
||||
|
||||
@@ -815,6 +815,33 @@ impl Session {
|
||||
self.is_session_terminated
|
||||
}
|
||||
|
||||
pub fn console_output(&mut self, cx: &mut Context<Self>) -> mpsc::UnboundedSender<String> {
|
||||
let (tx, mut rx) = mpsc::unbounded();
|
||||
|
||||
cx.spawn(async move |this, cx| {
|
||||
while let Some(output) = rx.next().await {
|
||||
this.update(cx, |this, _| {
|
||||
this.output_token.0 += 1;
|
||||
this.output.push_back(dap::OutputEvent {
|
||||
category: None,
|
||||
output,
|
||||
group: None,
|
||||
variables_reference: None,
|
||||
source: None,
|
||||
line: None,
|
||||
column: None,
|
||||
data: None,
|
||||
location_reference: None,
|
||||
});
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
pub fn is_local(&self) -> bool {
|
||||
matches!(self.mode, Mode::Running(_))
|
||||
}
|
||||
|
||||
@@ -894,7 +894,6 @@ impl Project {
|
||||
client.http_client(),
|
||||
node.clone(),
|
||||
fs.clone(),
|
||||
languages.clone(),
|
||||
environment.clone(),
|
||||
toolchain_store.read(cx).as_language_toolchain_store(),
|
||||
worktree_store.clone(),
|
||||
|
||||
@@ -559,6 +559,7 @@ message DapModuleId {
|
||||
|
||||
message GetDebugAdapterBinary {
|
||||
uint64 project_id = 1;
|
||||
uint64 session_id = 3;
|
||||
DebugTaskDefinition definition = 2;
|
||||
}
|
||||
|
||||
@@ -605,3 +606,9 @@ message SpawnInTerminal {
|
||||
map<string, string> env = 4;
|
||||
optional string cwd = 5;
|
||||
}
|
||||
|
||||
message LogToDebugConsole {
|
||||
uint64 project_id = 1;
|
||||
uint64 session_id = 2;
|
||||
string message = 3;
|
||||
}
|
||||
|
||||
@@ -384,7 +384,9 @@ message Envelope {
|
||||
LspExtGoToParentModuleResponse lsp_ext_go_to_parent_module_response = 344;
|
||||
LspExtCancelFlycheck lsp_ext_cancel_flycheck = 345;
|
||||
LspExtRunFlycheck lsp_ext_run_flycheck = 346;
|
||||
LspExtClearFlycheck lsp_ext_clear_flycheck = 347; // current max
|
||||
LspExtClearFlycheck lsp_ext_clear_flycheck = 347;
|
||||
|
||||
LogToDebugConsole log_to_debug_console = 348; // current max
|
||||
}
|
||||
|
||||
reserved 87 to 88;
|
||||
|
||||
@@ -305,6 +305,7 @@ messages!(
|
||||
(DebugAdapterBinary, Background),
|
||||
(RunDebugLocators, Background),
|
||||
(DebugRequest, Background),
|
||||
(LogToDebugConsole, Background),
|
||||
);
|
||||
|
||||
request_messages!(
|
||||
@@ -591,6 +592,7 @@ entity_messages!(
|
||||
ToggleBreakpoint,
|
||||
RunDebugLocators,
|
||||
GetDebugAdapterBinary,
|
||||
LogToDebugConsole,
|
||||
);
|
||||
|
||||
entity_messages!(
|
||||
|
||||
@@ -106,17 +106,18 @@ impl HeadlessProject {
|
||||
cx.new(|_| BreakpointStore::local(worktree_store.clone(), buffer_store.clone()));
|
||||
|
||||
let dap_store = cx.new(|cx| {
|
||||
DapStore::new_local(
|
||||
let mut dap_store = DapStore::new_local(
|
||||
http_client.clone(),
|
||||
node_runtime.clone(),
|
||||
fs.clone(),
|
||||
languages.clone(),
|
||||
environment.clone(),
|
||||
toolchain_store.read(cx).as_language_toolchain_store(),
|
||||
worktree_store.clone(),
|
||||
breakpoint_store.clone(),
|
||||
cx,
|
||||
)
|
||||
);
|
||||
dap_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
|
||||
dap_store
|
||||
});
|
||||
|
||||
let git_store = cx.new(|cx| {
|
||||
|
||||
Reference in New Issue
Block a user