mirror of https://github.com/helix-editor/helix
115 lines
3.4 KiB
Rust
115 lines
3.4 KiB
Rust
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)
|
|
}
|
|
}
|