satteri_plugin_api/
context.rs1use crate::commands::{Command, NewNode};
2use crate::data::{DataMap, DataValue, TypedDataMap};
3use satteri_arena::Arena;
4
5pub struct PluginContext<'a> {
7 arena: &'a Arena,
8 pub(crate) data_map: &'a mut DataMap,
9 pub(crate) typed_data: &'a mut TypedDataMap,
10 commands: Vec<Command>,
11 diagnostics: Vec<Diagnostic>,
12}
13
14#[derive(Debug, Clone)]
15pub struct Diagnostic {
16 pub message: String,
17 pub node_id: Option<u32>,
18 pub severity: Severity,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum Severity {
23 Error,
24 Warning,
25 Info,
26}
27
28impl<'a> PluginContext<'a> {
29 pub(crate) fn new(
30 arena: &'a Arena,
31 data_map: &'a mut DataMap,
32 typed_data: &'a mut TypedDataMap,
33 ) -> Self {
34 Self {
35 arena,
36 data_map,
37 typed_data,
38 commands: Vec::new(),
39 diagnostics: Vec::new(),
40 }
41 }
42
43 pub fn arena(&self) -> &Arena {
46 self.arena
47 }
48
49 pub fn extract_text(&self, node_id: u32) -> String {
51 use satteri_mdast::codec::decode_string_ref_data;
52 use satteri_mdast::MdastNodeType;
53 let node = self.arena.get_node(node_id);
54 if node.node_type == MdastNodeType::Text as u8
55 || node.node_type == MdastNodeType::InlineCode as u8
56 {
57 let data = self.arena.get_type_data(node_id);
58 if !data.is_empty() {
59 let string_ref = decode_string_ref_data(data);
60 return self.arena.get_str(string_ref).to_string();
61 }
62 return String::new();
63 }
64 let children = self.arena.get_children(node_id).to_vec();
65 children
66 .iter()
67 .map(|&child_id| self.extract_text(child_id))
68 .collect::<Vec<_>>()
69 .join("")
70 }
71
72 pub fn set_data(&mut self, node_id: u32, key: &str, value: DataValue) {
75 self.data_map.set(node_id, key, value);
76 }
77
78 pub fn get_data(&self, node_id: u32, key: &str) -> Option<&DataValue> {
79 self.data_map.get(node_id, key)
80 }
81
82 pub fn set_typed_data<T: std::any::Any + Send + Sync>(&mut self, node_id: u32, value: T) {
85 self.typed_data.set(node_id, value);
86 }
87
88 pub fn get_typed_data<T: std::any::Any + Send + Sync>(&self, node_id: u32) -> Option<&T> {
89 self.typed_data.get(node_id)
90 }
91
92 pub fn replace_node(&mut self, node_id: u32, new_node: NewNode) {
95 self.commands.push(Command::Replace { node_id, new_node });
96 }
97
98 pub fn remove_node(&mut self, node_id: u32) {
99 self.commands.push(Command::Remove { node_id });
100 }
101
102 pub fn insert_before(&mut self, node_id: u32, new_node: NewNode) {
103 self.commands
104 .push(Command::InsertBefore { node_id, new_node });
105 }
106
107 pub fn insert_after(&mut self, node_id: u32, new_node: NewNode) {
108 self.commands
109 .push(Command::InsertAfter { node_id, new_node });
110 }
111
112 pub fn wrap_node(&mut self, node_id: u32, parent_node: NewNode) {
113 self.commands.push(Command::Wrap {
114 node_id,
115 parent_node,
116 });
117 }
118
119 pub fn prepend_child(&mut self, node_id: u32, child_node: NewNode) {
120 self.commands.push(Command::PrependChild {
121 node_id,
122 child_node,
123 });
124 }
125
126 pub fn append_child(&mut self, node_id: u32, child_node: NewNode) {
127 self.commands.push(Command::AppendChild {
128 node_id,
129 child_node,
130 });
131 }
132
133 pub fn report(&mut self, message: impl Into<String>, node_id: Option<u32>, severity: Severity) {
136 self.diagnostics.push(Diagnostic {
137 message: message.into(),
138 node_id,
139 severity,
140 });
141 }
142
143 pub fn error(&mut self, message: impl Into<String>, node_id: Option<u32>) {
144 self.report(message, node_id, Severity::Error);
145 }
146
147 pub fn warn(&mut self, message: impl Into<String>, node_id: Option<u32>) {
148 self.report(message, node_id, Severity::Warning);
149 }
150
151 pub(crate) fn take_commands(self) -> (Vec<Command>, Vec<Diagnostic>) {
154 (self.commands, self.diagnostics)
155 }
156}