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.rs114
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)
+ }
+}