diff --git a/crates/debugger_ui/src/attach_modal.rs b/crates/debugger_ui/src/attach_modal.rs index 662a98c82075cd6e936988959c855eadb5138092..3e3bc3ec27c3d1dbf0bacd445b883a50370d5b6f 100644 --- a/crates/debugger_ui/src/attach_modal.rs +++ b/crates/debugger_ui/src/attach_modal.rs @@ -1,8 +1,10 @@ use dap::{DapRegistry, DebugRequest}; use fuzzy::{StringMatch, StringMatchCandidate}; -use gpui::{AppContext, DismissEvent, Entity, EventEmitter, Focusable, Render}; +use gpui::{AppContext, DismissEvent, Entity, EventEmitter, Focusable, Render, Task}; use gpui::{Subscription, WeakEntity}; use picker::{Picker, PickerDelegate}; +use project::Project; +use rpc::proto; use task::ZedDebugConfig; use util::debug_panic; @@ -56,29 +58,28 @@ impl AttachModal { pub fn new( definition: ZedDebugConfig, workspace: WeakEntity, + project: Entity, modal: bool, window: &mut Window, cx: &mut Context, ) -> Self { - let mut processes: Box<[_]> = System::new_all() - .processes() - .values() - .map(|process| { - let name = process.name().to_string_lossy().into_owned(); - Candidate { - name: name.into(), - pid: process.pid().as_u32(), - command: process - .cmd() - .iter() - .map(|s| s.to_string_lossy().to_string()) - .collect::>(), - } - }) - .collect(); - processes.sort_by_key(|k| k.name.clone()); - let processes = processes.into_iter().collect(); - Self::with_processes(workspace, definition, processes, modal, window, cx) + let processes_task = get_processes_for_project(&project, cx); + + let modal = Self::with_processes(workspace, definition, Arc::new([]), modal, window, cx); + + cx.spawn_in(window, async move |this, cx| { + let processes = processes_task.await; + this.update_in(cx, |modal, window, cx| { + modal.picker.update(cx, |picker, cx| { + picker.delegate.candidates = processes; + picker.refresh(window, cx); + }); + })?; + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + + modal } pub(super) fn with_processes( @@ -332,6 +333,57 @@ impl PickerDelegate for AttachModalDelegate { } } +fn get_processes_for_project(project: &Entity, cx: &mut App) -> Task> { + let project = project.read(cx); + + if let Some(remote_client) = project.remote_client() { + let proto_client = remote_client.read(cx).proto_client(); + cx.spawn(async move |_cx| { + let response = proto_client + .request(proto::GetProcesses { + project_id: proto::REMOTE_SERVER_PROJECT_ID, + }) + .await + .unwrap_or_else(|_| proto::GetProcessesResponse { + processes: Vec::new(), + }); + + let mut processes: Vec = response + .processes + .into_iter() + .map(|p| Candidate { + pid: p.pid, + name: p.name.into(), + command: p.command, + }) + .collect(); + + processes.sort_by_key(|k| k.name.clone()); + Arc::from(processes.into_boxed_slice()) + }) + } else { + let mut processes: Box<[_]> = System::new_all() + .processes() + .values() + .map(|process| { + let name = process.name().to_string_lossy().into_owned(); + Candidate { + name: name.into(), + pid: process.pid().as_u32(), + command: process + .cmd() + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::>(), + } + }) + .collect(); + processes.sort_by_key(|k| k.name.clone()); + let processes = processes.into_iter().collect(); + Task::ready(processes) + } +} + #[cfg(any(test, feature = "test-support"))] pub(crate) fn _process_names(modal: &AttachModal, cx: &mut Context) -> Vec { modal.picker.read_with(cx, |picker, _| { diff --git a/crates/debugger_ui/src/new_process_modal.rs b/crates/debugger_ui/src/new_process_modal.rs index 68770bc8b15fbf95824de167dbc8d7fada2b5075..ee6289187ba990d5bbaa040631a1c32619857e53 100644 --- a/crates/debugger_ui/src/new_process_modal.rs +++ b/crates/debugger_ui/src/new_process_modal.rs @@ -20,7 +20,7 @@ use gpui::{ }; use itertools::Itertools as _; use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMatch}; -use project::{DebugScenarioContext, TaskContexts, TaskSourceKind, task_store::TaskStore}; +use project::{DebugScenarioContext, Project, TaskContexts, TaskSourceKind, task_store::TaskStore}; use settings::Settings; use task::{DebugScenario, RevealTarget, ZedDebugConfig}; use theme::ThemeSettings; @@ -88,8 +88,10 @@ impl NewProcessModal { })?; workspace.update_in(cx, |workspace, window, cx| { let workspace_handle = workspace.weak_handle(); + let project = workspace.project().clone(); workspace.toggle_modal(window, cx, |window, cx| { - let attach_mode = AttachMode::new(None, workspace_handle.clone(), window, cx); + let attach_mode = + AttachMode::new(None, workspace_handle.clone(), project, window, cx); let debug_picker = cx.new(|cx| { let delegate = @@ -940,6 +942,7 @@ impl AttachMode { pub(super) fn new( debugger: Option, workspace: WeakEntity, + project: Entity, window: &mut Window, cx: &mut Context, ) -> Entity { @@ -950,7 +953,7 @@ impl AttachMode { stop_on_entry: Some(false), }; let attach_picker = cx.new(|cx| { - let modal = AttachModal::new(definition.clone(), workspace, false, window, cx); + let modal = AttachModal::new(definition.clone(), workspace, project, false, window, cx); window.focus(&modal.focus_handle(cx)); modal diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index c6f9c9f1342336c36ab8dfd0ec70a24ff6564476..e3cb5ebbce0ceb87a7197f19a133bbb92a572085 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -546,3 +546,17 @@ message LogToDebugConsole { uint64 session_id = 2; string message = 3; } + +message GetProcesses { + uint64 project_id = 1; +} + +message GetProcessesResponse { + repeated ProcessInfo processes = 1; +} + +message ProcessInfo { + uint32 pid = 1; + string name = 2; + repeated string command = 3; +} diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index 4133b4b5eea6f14e2c9359f7318f192a8566d809..3763671a7a1f29949194d61c70866f96ca6ad972 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -399,7 +399,10 @@ message Envelope { LspQueryResponse lsp_query_response = 366; ToggleLspLogs toggle_lsp_logs = 367; - UpdateUserSettings update_user_settings = 368; // current max + UpdateUserSettings update_user_settings = 368; + + GetProcesses get_processes = 369; + GetProcessesResponse get_processes_response = 370; // current max } reserved 87 to 88; diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index 8f4e836b20ae5bae43617e10391f75c3a069a82f..3c98ae62e7a4b1489c071a0ac673d23b394c28d5 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -102,6 +102,8 @@ messages!( (GetPathMetadata, Background), (GetPathMetadataResponse, Background), (GetPermalinkToLine, Foreground), + (GetProcesses, Background), + (GetProcessesResponse, Background), (GetPermalinkToLineResponse, Foreground), (GetProjectSymbols, Background), (GetProjectSymbolsResponse, Background), @@ -485,6 +487,7 @@ request_messages!( (GetDefaultBranch, GetDefaultBranchResponse), (GitClone, GitCloneResponse), (ToggleLspLogs, Ack), + (GetProcesses, GetProcessesResponse), ); lsp_messages!( @@ -610,6 +613,7 @@ entity_messages!( ActivateToolchain, ActiveToolchain, GetPathMetadata, + GetProcesses, CancelLanguageServerWork, RegisterBufferWithLanguageServers, GitShow, diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index f55826631b46b4f9eaaa17d8a9f4b0603a07fcc3..7fb5ac8498c67863783b1944c912f0ad9767fed5 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -32,6 +32,7 @@ use std::{ path::{Path, PathBuf}, sync::{Arc, atomic::AtomicUsize}, }; +use sysinfo::System; use util::ResultExt; use worktree::Worktree; @@ -230,6 +231,7 @@ impl HeadlessProject { session.add_request_handler(cx.weak_entity(), Self::handle_get_path_metadata); session.add_request_handler(cx.weak_entity(), Self::handle_shutdown_remote_server); session.add_request_handler(cx.weak_entity(), Self::handle_ping); + session.add_request_handler(cx.weak_entity(), Self::handle_get_processes); session.add_entity_request_handler(Self::handle_add_worktree); session.add_request_handler(cx.weak_entity(), Self::handle_remove_worktree); @@ -719,6 +721,34 @@ impl HeadlessProject { log::debug!("Received ping from client"); Ok(proto::Ack {}) } + + async fn handle_get_processes( + _this: Entity, + _envelope: TypedEnvelope, + _cx: AsyncApp, + ) -> Result { + let mut processes = Vec::new(); + let system = System::new_all(); + + for (_pid, process) in system.processes() { + let name = process.name().to_string_lossy().into_owned(); + let command = process + .cmd() + .iter() + .map(|s| s.to_string_lossy().to_string()) + .collect::>(); + + processes.push(proto::ProcessInfo { + pid: process.pid().as_u32(), + name, + command, + }); + } + + processes.sort_by_key(|p| p.name.clone()); + + Ok(proto::GetProcessesResponse { processes }) + } } fn prompt_to_proto(