Skip to repository content136 lines · 4.6 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T07:08:48.245Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
mindmap.rs
1use anyhow::Result;
2use quick_xml::events::{BytesStart, Event};
3
4use super::{AccentStackEntry, NodeTracker};
5
6pub(super) struct MindmapAccents {
7 section_classes: Vec<String>,
8 section_g_stack: Vec<AccentStackEntry>,
9 nodes: NodeTracker,
10 current_text_section: Option<usize>,
11}
12
13impl MindmapAccents {
14 pub(super) fn new() -> Self {
15 Self {
16 section_classes: Vec::new(),
17 section_g_stack: Vec::new(),
18 nodes: NodeTracker::default(),
19 current_text_section: None,
20 }
21 }
22
23 pub(super) fn process_event<'a>(&mut self, event: Event<'a>) -> Result<Event<'a>> {
24 match &event {
25 Event::Start(e) if e.name().as_ref() == b"g" => {
26 if super::is_foreign_object_fallback_group(e)? {
27 self.section_g_stack.push(AccentStackEntry::none());
28 return Ok(event);
29 }
30
31 let section_idx = self.parse_section_class(e)?;
32 if let Some(idx) = section_idx {
33 let tracks_node = if let Some((tx, ty)) = super::parse_translate(e) {
34 self.nodes.start_node(tx, ty, 0.0, idx);
35 true
36 } else {
37 false
38 };
39 self.section_g_stack
40 .push(AccentStackEntry::accent(idx, tracks_node));
41 } else {
42 self.section_g_stack.push(AccentStackEntry::none());
43 }
44 Ok(event)
45 }
46
47 Event::End(e) if e.name().as_ref() == b"g" => {
48 if let Some(entry) = self.section_g_stack.pop() {
49 if entry.tracks_node() {
50 self.nodes.maybe_finish_node();
51 }
52 }
53 Ok(event)
54 }
55
56 Event::Start(e) | Event::Empty(e)
57 if matches!(
58 e.name().as_ref(),
59 b"path" | b"rect" | b"circle" | b"polygon" | b"ellipse"
60 ) =>
61 {
62 if e.name().as_ref() == b"path" {
63 self.nodes.update_half_height(e);
64 }
65 Ok(event)
66 }
67
68 Event::Start(e) | Event::Empty(e)
69 if e.name().as_ref() == b"text" || e.name().as_ref() == b"tspan" =>
70 {
71 let section_idx = self.current_section_accent().or_else(|| {
72 if e.name().as_ref() == b"text" {
73 self.nodes.lookup_accent(e)
74 } else {
75 None
76 }
77 });
78
79 if e.name().as_ref() == b"text" {
80 self.current_text_section = section_idx;
81 }
82
83 let idx = section_idx.or(self.current_text_section);
84
85 if let Some(idx) = idx {
86 if let Some(class_name) = self.section_class_name(idx) {
87 return super::add_to_event(&event, e, class_name);
88 }
89 }
90
91 Ok(event)
92 }
93
94 Event::End(e) if e.name().as_ref() == b"text" => {
95 self.current_text_section = None;
96 Ok(event)
97 }
98
99 _ => Ok(event),
100 }
101 }
102
103 fn parse_section_class(&mut self, e: &BytesStart<'_>) -> Result<Option<usize>> {
104 let class_attr = match e.try_get_attribute("class")? {
105 Some(attr) => attr,
106 None => return Ok(None),
107 };
108 let class = class_attr.unescape_value()?;
109 let is_root = class.split_whitespace().any(|t| t == "section-root");
110
111 for token in class.split_whitespace() {
112 if let Some(rest) = token.strip_prefix("section-") {
113 if rest == "-1" || rest.parse::<u32>().is_ok() {
114 let class_name = if is_root {
115 "section-root section--1".to_string()
116 } else {
117 format!("section-{rest}")
118 };
119 let idx = self.section_classes.len();
120 self.section_classes.push(class_name);
121 return Ok(Some(idx));
122 }
123 }
124 }
125 Ok(None)
126 }
127
128 fn current_section_accent(&self) -> Option<usize> {
129 super::current_stack_accent(&self.section_g_stack)
130 }
131
132 fn section_class_name(&self, idx: usize) -> Option<&str> {
133 self.section_classes.get(idx).map(|s| s.as_str())
134 }
135}
136