Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-dap/src/registry.rs')
| -rw-r--r-- | helix-dap/src/registry.rs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/helix-dap/src/registry.rs b/helix-dap/src/registry.rs new file mode 100644 index 00000000..a6937020 --- /dev/null +++ b/helix-dap/src/registry.rs @@ -0,0 +1,114 @@ +use crate::{Client, Payload, Result, StackFrame}; +use futures_executor::block_on; +use futures_util::stream::SelectAll; +use helix_core::syntax::config::DebugAdapterConfig; +use slotmap::SlotMap; +use std::fmt; +use tokio_stream::wrappers::UnboundedReceiverStream; + +/// The resgistry is a struct that manages and owns multiple debugger clients +/// This holds the responsibility of managing the lifecycle of each client +/// plus showing the heirarcihical nature betweeen them +pub struct Registry { + inner: SlotMap<DebugAdapterId, Client>, + /// The active debugger client + /// + /// TODO: You can have multiple active debuggers, so the concept of a single active debugger + /// may need to be changed + current_client_id: Option<DebugAdapterId>, + /// A stream of incoming messages from all debuggers + pub incoming: SelectAll<UnboundedReceiverStream<(DebugAdapterId, Payload)>>, +} + +impl Registry { + /// Creates a new DebuggerService instance + pub fn new() -> Self { + Self { + inner: SlotMap::with_key(), + current_client_id: None, + incoming: SelectAll::new(), + } + } + + pub fn start_client( + &mut self, + socket: Option<std::net::SocketAddr>, + config: &DebugAdapterConfig, + ) -> Result<DebugAdapterId> { + self.inner.try_insert_with_key(|id| { + let result = match socket { + Some(socket) => block_on(Client::tcp(socket, id)), + None => block_on(Client::process( + &config.transport, + &config.command, + config.args.iter().map(|arg| arg.as_str()).collect(), + config.port_arg.as_deref(), + id, + )), + }; + + let (mut client, receiver) = result?; + self.incoming.push(UnboundedReceiverStream::new(receiver)); + + client.config = Some(config.clone()); + block_on(client.initialize(config.name.clone()))?; + client.quirks = config.quirks.clone(); + + Ok(client) + }) + } + + pub fn remove_client(&mut self, id: DebugAdapterId) { + self.inner.remove(id); + } + + pub fn get_client(&self, id: DebugAdapterId) -> Option<&Client> { + self.inner.get(id) + } + + pub fn get_client_mut(&mut self, id: DebugAdapterId) -> Option<&mut Client> { + self.inner.get_mut(id) + } + + pub fn get_active_client(&self) -> Option<&Client> { + self.current_client_id.and_then(|id| self.get_client(id)) + } + + pub fn get_active_client_mut(&mut self) -> Option<&mut Client> { + self.current_client_id + .and_then(|id| self.get_client_mut(id)) + } + + pub fn set_active_client(&mut self, id: DebugAdapterId) { + if self.get_client(id).is_some() { + self.current_client_id = Some(id); + } else { + self.current_client_id = None; + } + } + + pub fn unset_active_client(&mut self) { + self.current_client_id = None; + } + + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.get_active_client() + .and_then(|debugger| debugger.current_stack_frame()) + } +} + +impl Default for Registry { + fn default() -> Self { + Self::new() + } +} + +slotmap::new_key_type! { + pub struct DebugAdapterId; +} + +impl fmt::Display for DebugAdapterId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} |