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 {
44 self.arena
45 }
46
47 pub fn extract_text(&self, node_id: u32) -> String {
49 use satteri_ast::mdast::codec::decode_string_ref_data;
50 use satteri_ast::mdast::MdastNodeType;
51 let node = self.arena.get_node(node_id);
52 if node.node_type == MdastNodeType::Text as u8
53 || node.node_type == MdastNodeType::InlineCode as u8
54 {
55 let data = self.arena.get_type_data(node_id);
56 if !data.is_empty() {
57 let string_ref = decode_string_ref_data(data);
58 return self.arena.get_str(string_ref).to_string();
59 }
60 return String::new();
61 }
62 let children = self.arena.get_children(node_id).to_vec();
63 children
64 .iter()
65 .map(|&child_id| self.extract_text(child_id))
66 .collect::<Vec<_>>()
67 .join("")
68 }
69
70 pub fn set_data(&mut self, node_id: u32, key: &str, value: DataValue) {
71 self.data_map.set(node_id, key, value);
72 }
73
74 pub fn get_data(&self, node_id: u32, key: &str) -> Option<&DataValue> {
75 self.data_map.get(node_id, key)
76 }
77
78 pub fn set_typed_data<T: std::any::Any + Send + Sync>(&mut self, node_id: u32, value: T) {
79 self.typed_data.set(node_id, value);
80 }
81
82 pub fn get_typed_data<T: std::any::Any + Send + Sync>(&self, node_id: u32) -> Option<&T> {
83 self.typed_data.get(node_id)
84 }
85
86 pub fn replace_node(&mut self, node_id: u32, new_node: NewNode) {
87 self.commands.push(Command::Replace { node_id, new_node });
88 }
89
90 pub fn remove_node(&mut self, node_id: u32) {
91 self.commands.push(Command::Remove { node_id });
92 }
93
94 pub fn insert_before(&mut self, node_id: u32, new_node: NewNode) {
95 self.commands
96 .push(Command::InsertBefore { node_id, new_node });
97 }
98
99 pub fn insert_after(&mut self, node_id: u32, new_node: NewNode) {
100 self.commands
101 .push(Command::InsertAfter { node_id, new_node });
102 }
103
104 pub fn wrap_node(&mut self, node_id: u32, parent_node: NewNode) {
105 self.commands.push(Command::Wrap {
106 node_id,
107 parent_node,
108 });
109 }
110
111 pub fn prepend_child(&mut self, node_id: u32, child_node: NewNode) {
112 self.commands.push(Command::PrependChild {
113 node_id,
114 child_node,
115 });
116 }
117
118 pub fn append_child(&mut self, node_id: u32, child_node: NewNode) {
119 self.commands.push(Command::AppendChild {
120 node_id,
121 child_node,
122 });
123 }
124
125 pub fn report(&mut self, message: impl Into<String>, node_id: Option<u32>, severity: Severity) {
126 self.diagnostics.push(Diagnostic {
127 message: message.into(),
128 node_id,
129 severity,
130 });
131 }
132
133 pub fn error(&mut self, message: impl Into<String>, node_id: Option<u32>) {
134 self.report(message, node_id, Severity::Error);
135 }
136
137 pub fn warn(&mut self, message: impl Into<String>, node_id: Option<u32>) {
138 self.report(message, node_id, Severity::Warning);
139 }
140
141 pub(crate) fn take_commands(self) -> (Vec<Command>, Vec<Diagnostic>) {
142 (self.commands, self.diagnostics)
143 }
144}