1use bynk_ide::sequence::{
17 self, AltKind, HandlerOwner, MessageKind, ParticipantKind, SequenceModel,
18};
19use bynk_syntax::ast::{CommonsItem, Handler, SourceUnit};
20
21pub fn sequence_model_at(
28 text: &str,
29 offset: usize,
30 info: Option<&bynk_ide::ContextSequenceInfo>,
31) -> Option<SequenceModel> {
32 let tokens = bynk_syntax::lexer::tokenize(text).ok()?;
33 let (unit, _errs) = bynk_syntax::parser::parse_unit_with_recovery(&tokens, text);
34 let items: &[CommonsItem] = match unit.as_ref()? {
35 SourceUnit::Context(c) => &c.items,
36 SourceUnit::Adapter(a) => &a.items,
37 SourceUnit::Commons(_) | SourceUnit::Suite(_) => return None,
38 };
39 for item in items {
40 match item {
41 CommonsItem::Service(s) => {
42 if let Some(h) = handler_at(&s.handlers, offset) {
43 return Some(sequence::sequence_model(
44 h,
45 HandlerOwner::Service(&s.name.name),
46 &s.default_given,
49 s.default_by.as_ref(),
50 info,
51 ));
52 }
53 }
54 CommonsItem::Agent(a) => {
55 if let Some(h) = handler_at(&a.handlers, offset) {
56 return Some(sequence::sequence_model(
57 h,
58 HandlerOwner::Agent(&a.name.name),
59 &[],
62 None,
63 info,
64 ));
65 }
66 }
67 _ => {}
68 }
69 }
70 None
71}
72
73fn handler_at(handlers: &[Handler], offset: usize) -> Option<&Handler> {
74 handlers
75 .iter()
76 .find(|h| h.span.start <= offset && offset < h.span.end)
77}
78
79pub fn handler_lens_sites(text: &str) -> Vec<bynk_syntax::span::Span> {
87 let Ok(tokens) = bynk_syntax::lexer::tokenize(text) else {
88 return Vec::new();
89 };
90 let (unit, _errs) = bynk_syntax::parser::parse_unit_with_recovery(&tokens, text);
91 let Some(unit) = unit else {
92 return Vec::new();
93 };
94 let items: &[CommonsItem] = match &unit {
95 SourceUnit::Context(c) => &c.items,
96 SourceUnit::Adapter(a) => &a.items,
97 SourceUnit::Commons(_) | SourceUnit::Suite(_) => return Vec::new(),
98 };
99 let mut sites = Vec::new();
100 for item in items {
101 match item {
102 CommonsItem::Service(s) => sites.extend(s.handlers.iter().map(|h| h.span)),
103 CommonsItem::Agent(a) => sites.extend(a.handlers.iter().map(|h| h.span)),
104 _ => {}
105 }
106 }
107 sites
108}
109
110#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct SequenceModelParams {
123 pub text_document: tower_lsp::lsp_types::TextDocumentIdentifier,
124 pub position: tower_lsp::lsp_types::Position,
125}
126
127#[derive(Debug, Clone, serde::Serialize)]
132pub struct WireSequenceModel {
133 pub participants: Vec<WireParticipant>,
134 pub messages: Vec<WireMessage>,
135 pub blocks: Vec<WireAltBlock>,
136}
137
138#[derive(Debug, Clone, serde::Serialize)]
139pub struct WireParticipant {
140 pub id: u32,
141 pub kind: &'static str,
142 pub name: String,
143 pub range: Option<tower_lsp::lsp_types::Range>,
144}
145
146#[derive(Debug, Clone, serde::Serialize)]
147pub struct WireMessage {
148 pub from: u32,
149 pub to: u32,
150 pub kind: &'static str,
151 pub label: String,
152 pub range: tower_lsp::lsp_types::Range,
153 pub block: Option<u32>,
154}
155
156#[derive(Debug, Clone, serde::Serialize)]
157pub struct WireAltBlock {
158 pub id: u32,
159 pub kind: &'static str,
160 pub branches: Vec<WireBranch>,
161 pub range: tower_lsp::lsp_types::Range,
162 pub parent: Option<u32>,
163 #[serde(rename = "parentBranch")]
164 pub parent_branch: Option<u32>,
165}
166
167#[derive(Debug, Clone, serde::Serialize)]
168pub struct WireBranch {
169 pub label: String,
170 #[serde(rename = "messageIds")]
171 pub message_ids: Vec<usize>,
172 pub reply: Option<String>,
175}
176
177fn participant_kind_str(k: ParticipantKind) -> &'static str {
178 match k {
179 ParticipantKind::Entry => "Entry",
180 ParticipantKind::Capability => "Capability",
181 ParticipantKind::Context => "Context",
182 ParticipantKind::Agent => "Agent",
183 ParticipantKind::Actor => "Actor",
184 }
185}
186
187fn message_kind_str(k: MessageKind) -> &'static str {
188 match k {
189 MessageKind::Call => "Call",
190 MessageKind::Return => "Return",
191 MessageKind::Send => "Send",
192 MessageKind::StateWrite => "StateWrite",
193 }
194}
195
196fn alt_kind_str(k: AltKind) -> &'static str {
197 match k {
198 AltKind::If => "If",
199 AltKind::Match => "Match",
200 AltKind::Collapsed => "Collapsed",
201 }
202}
203
204pub fn to_wire(model: &SequenceModel, text: &str) -> WireSequenceModel {
205 WireSequenceModel {
206 participants: model
207 .participants
208 .iter()
209 .map(|p| WireParticipant {
210 id: p.id,
211 kind: participant_kind_str(p.kind),
212 name: p.name.clone(),
213 range: p.span.map(|s| crate::position::span_to_range(text, s)),
214 })
215 .collect(),
216 messages: model
217 .messages
218 .iter()
219 .map(|m| WireMessage {
220 from: m.from,
221 to: m.to,
222 kind: message_kind_str(m.kind),
223 label: m.label.clone(),
224 range: crate::position::span_to_range(text, m.span),
225 block: m.block,
226 })
227 .collect(),
228 blocks: model
229 .blocks
230 .iter()
231 .map(|b| WireAltBlock {
232 id: b.id,
233 kind: alt_kind_str(b.kind),
234 branches: b
235 .branches
236 .iter()
237 .map(|br| WireBranch {
238 label: br.label.clone(),
239 message_ids: br.message_ids.clone(),
240 reply: br.reply.clone(),
241 })
242 .collect(),
243 range: crate::position::span_to_range(text, b.span),
244 parent: b.parent,
245 parent_branch: b.parent_branch,
246 })
247 .collect(),
248 }
249}