use bynk_ide::sequence::{
self, AltKind, HandlerOwner, MessageKind, ParticipantKind, SequenceModel,
};
use bynk_syntax::ast::{CommonsItem, Handler, SourceUnit};
pub fn sequence_model_at(
text: &str,
offset: usize,
info: Option<&bynk_ide::ContextSequenceInfo>,
) -> Option<SequenceModel> {
let tokens = bynk_syntax::lexer::tokenize(text).ok()?;
let (unit, _errs) = bynk_syntax::parser::parse_unit_with_recovery(&tokens, text);
let items: &[CommonsItem] = match unit.as_ref()? {
SourceUnit::Context(c) => &c.items,
SourceUnit::Adapter(a) => &a.items,
SourceUnit::Commons(_) | SourceUnit::Suite(_) => return None,
};
for item in items {
match item {
CommonsItem::Service(s) => {
if let Some(h) = handler_at(&s.handlers, offset) {
return Some(sequence::sequence_model(
h,
HandlerOwner::Service(&s.name.name),
&s.default_given,
s.default_by.as_ref(),
info,
));
}
}
CommonsItem::Agent(a) => {
if let Some(h) = handler_at(&a.handlers, offset) {
return Some(sequence::sequence_model(
h,
HandlerOwner::Agent(&a.name.name),
&[],
None,
info,
));
}
}
_ => {}
}
}
None
}
fn handler_at(handlers: &[Handler], offset: usize) -> Option<&Handler> {
handlers
.iter()
.find(|h| h.span.start <= offset && offset < h.span.end)
}
pub fn handler_lens_sites(text: &str) -> Vec<bynk_syntax::span::Span> {
let Ok(tokens) = bynk_syntax::lexer::tokenize(text) else {
return Vec::new();
};
let (unit, _errs) = bynk_syntax::parser::parse_unit_with_recovery(&tokens, text);
let Some(unit) = unit else {
return Vec::new();
};
let items: &[CommonsItem] = match &unit {
SourceUnit::Context(c) => &c.items,
SourceUnit::Adapter(a) => &a.items,
SourceUnit::Commons(_) | SourceUnit::Suite(_) => return Vec::new(),
};
let mut sites = Vec::new();
for item in items {
match item {
CommonsItem::Service(s) => sites.extend(s.handlers.iter().map(|h| h.span)),
CommonsItem::Agent(a) => sites.extend(a.handlers.iter().map(|h| h.span)),
_ => {}
}
}
sites
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SequenceModelParams {
pub text_document: tower_lsp::lsp_types::TextDocumentIdentifier,
pub position: tower_lsp::lsp_types::Position,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct WireSequenceModel {
pub participants: Vec<WireParticipant>,
pub messages: Vec<WireMessage>,
pub blocks: Vec<WireAltBlock>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct WireParticipant {
pub id: u32,
pub kind: &'static str,
pub name: String,
pub range: Option<tower_lsp::lsp_types::Range>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct WireMessage {
pub from: u32,
pub to: u32,
pub kind: &'static str,
pub label: String,
pub range: tower_lsp::lsp_types::Range,
pub block: Option<u32>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct WireAltBlock {
pub id: u32,
pub kind: &'static str,
pub branches: Vec<WireBranch>,
pub range: tower_lsp::lsp_types::Range,
pub parent: Option<u32>,
#[serde(rename = "parentBranch")]
pub parent_branch: Option<u32>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct WireBranch {
pub label: String,
#[serde(rename = "messageIds")]
pub message_ids: Vec<usize>,
pub reply: Option<String>,
}
fn participant_kind_str(k: ParticipantKind) -> &'static str {
match k {
ParticipantKind::Entry => "Entry",
ParticipantKind::Capability => "Capability",
ParticipantKind::Context => "Context",
ParticipantKind::Agent => "Agent",
ParticipantKind::Actor => "Actor",
}
}
fn message_kind_str(k: MessageKind) -> &'static str {
match k {
MessageKind::Call => "Call",
MessageKind::Return => "Return",
MessageKind::Send => "Send",
}
}
fn alt_kind_str(k: AltKind) -> &'static str {
match k {
AltKind::If => "If",
AltKind::Match => "Match",
AltKind::Collapsed => "Collapsed",
}
}
pub fn to_wire(model: &SequenceModel, text: &str) -> WireSequenceModel {
WireSequenceModel {
participants: model
.participants
.iter()
.map(|p| WireParticipant {
id: p.id,
kind: participant_kind_str(p.kind),
name: p.name.clone(),
range: p.span.map(|s| crate::position::span_to_range(text, s)),
})
.collect(),
messages: model
.messages
.iter()
.map(|m| WireMessage {
from: m.from,
to: m.to,
kind: message_kind_str(m.kind),
label: m.label.clone(),
range: crate::position::span_to_range(text, m.span),
block: m.block,
})
.collect(),
blocks: model
.blocks
.iter()
.map(|b| WireAltBlock {
id: b.id,
kind: alt_kind_str(b.kind),
branches: b
.branches
.iter()
.map(|br| WireBranch {
label: br.label.clone(),
message_ids: br.message_ids.clone(),
reply: br.reply.clone(),
})
.collect(),
range: crate::position::span_to_range(text, b.span),
parent: b.parent,
parent_branch: b.parent_branch,
})
.collect(),
}
}