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, /// 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, /// A stream of incoming messages from all debuggers pub incoming: SelectAll>, } 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, config: &DebugAdapterConfig, ) -> Result { 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) } }