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 }
193}
194
195fn alt_kind_str(k: AltKind) -> &'static str {
196 match k {
197 AltKind::If => "If",
198 AltKind::Match => "Match",
199 AltKind::Collapsed => "Collapsed",
200 }
201}
202
203pub fn to_wire(model: &SequenceModel, text: &str) -> WireSequenceModel {
204 WireSequenceModel {
205 participants: model
206 .participants
207 .iter()
208 .map(|p| WireParticipant {
209 id: p.id,
210 kind: participant_kind_str(p.kind),
211 name: p.name.clone(),
212 range: p.span.map(|s| crate::position::span_to_range(text, s)),
213 })
214 .collect(),
215 messages: model
216 .messages
217 .iter()
218 .map(|m| WireMessage {
219 from: m.from,
220 to: m.to,
221 kind: message_kind_str(m.kind),
222 label: m.label.clone(),
223 range: crate::position::span_to_range(text, m.span),
224 block: m.block,
225 })
226 .collect(),
227 blocks: model
228 .blocks
229 .iter()
230 .map(|b| WireAltBlock {
231 id: b.id,
232 kind: alt_kind_str(b.kind),
233 branches: b
234 .branches
235 .iter()
236 .map(|br| WireBranch {
237 label: br.label.clone(),
238 message_ids: br.message_ids.clone(),
239 reply: br.reply.clone(),
240 })
241 .collect(),
242 range: crate::position::span_to_range(text, b.span),
243 parent: b.parent,
244 parent_branch: b.parent_branch,
245 })
246 .collect(),
247 }
248}