1use yarig_macro::add_gen_core;
2
3use crate::{cfg::CfgAdoc, comp::comp_inst::RifInst, generator::casing::ToCasing, parser::remove_rif, rifgen::EnumDef};
4
5use super::{
6 casing::Casing,
7 gen_common::{GeneratorBase, GeneratorBaseSetting, GeneratorCore},
8 trait_doc::{CellKind, GeneratorDoc, LinkKind, TableKind}
9};
10
11#[add_gen_core("adoc")]
12pub struct GeneratorAdoc {
13 comp_fname: String,
15}
16
17impl GeneratorAdoc {
18
19 pub fn new(setting: GeneratorBaseSetting, cfg: CfgAdoc) -> Self {
20 let mut core = GeneratorCore::new(0,setting);
21 if let Some(split) = cfg.split {core.setting.split = split;}
22 if let Some(gen_inc) = cfg.gen_inc {
24 core.setting.gen_inc = gen_inc;
25 }
26 if let Some(casing) = cfg.casing {
27 core.setting.casing = casing;
28 }
29 GeneratorAdoc {
30 core,
31 comp_fname: "".to_owned(),
32 }
33 }
34}
35
36impl GeneratorDoc for GeneratorAdoc {
37 const HAS_LAYOUT : bool = false;
38 const SHOW_TYPE : bool = false;
39 const SHOW_RESET : bool = false;
40 const SHOW_SINGLE_REG : bool = false;
41 const SHOW_UNUSED : bool = true;
42
43 fn set_rif_info(&mut self, rif: &RifInst) {
44 self.comp_fname = rif.name(false);
45 }
46
47 fn write_rif_title(&mut self, idx_rif: (&str,usize), desc: &str) {
48 if idx_rif.1 > 0 && self.comp().is_rifmux {
50 self.write("=");
51 }
52 self.write("= ");
53 if idx_rif.1 == 0 || (!self.comp().is_rifmux && idx_rif.1 == 1) {
54 self.write("[[top]]");
55 }
56 self.write(&format!("[[{}]]", idx_rif.0));
57 if desc.is_empty() {
58 self.write(&idx_rif.0.to_casing(Casing::Title));
59 } else {
60 self.write(desc);
61 }
62 self.write("\n\n");
63 }
64
65 fn write_page_title(&mut self, idx_rif: (&str,usize), idx_page: (&str, usize), desc: (String, Option<String>)) {
66 if self.comp().cnt > 1 {
67 self.write(&format!("\n=== [[{}.{}]]", idx_rif.0, idx_page.0));
68 let name = self.sanitize(idx_page.0);
69 if desc.0.is_empty() {
70 self.write(&name);
71 } else {
72 self.write(&format!("{} ({name})", desc.0));
73 }
74 } else if !desc.0.is_empty() {
75 self.write(&self.sanitize(&desc.0));
76 self.write("\n");
77 }
78 if let Some(desc_detail) = desc.1 {
79 self.write_info(&self.sanitize(&desc_detail));
80 self.write("\n");
81 }
82 }
83
84 fn write_reg_title(&mut self, idx_rif: (&str,usize), _idx_page: (&str, usize), idx_reg: (&str, usize), desc: &str, base_addr: Option<u64>) {
85 self.write("\n");
86 if self.comp().is_rifmux {
87 self.write("=");
88 }
89 if self.comp().cnt > 1 {
90 self.write("=");
91 }
92 self.write("=== ");
93 self.write(&format!("[[{}.{}]]", idx_rif.0, idx_reg.0));
94 let name = self.sanitize(idx_reg.0);
95 if desc.is_empty() {
96 self.write(&name);
97 } else {
98 self.write(&format!("{desc} ({name})"));
99 }
100 if let Some(addr) = base_addr {
101 let w = ((self.addr_width()+3) >> 2) as usize;
102 self.write(&format!(" @ 0x{addr:0w$x}"));
103 }
104 self.write("\n");
105 }
106
107 fn write_reg_summary_header(&mut self, _rif: &RifInst) {
108 self.write("\n");
109 if self.comp().is_rifmux {
110 self.write("=");
111 }
112 self.write("== Address mapping\n");
113 }
114
115 fn write_table_title(&mut self, kind: TableKind, title: &str, id: &str) {
116 let caption = match kind {
117 TableKind::Page => {
118 if self.comp().cnt > 1 {
119 format!("{} registers address mapping", title.to_casing(Casing::Title))
120 } else {
121 "Registers address mapping".to_owned()
122 }
123 }
124 TableKind::Field => {
125 let regname = remove_rif(self.comp_name())
126 .to_casing(self.core.setting.casing);
127 format!("Register {regname}.{title}")
128 }
129 _ => self.sanitize(title)
130 };
131
132 self.write(".");
133 self.write(&caption);
134 self.write("\n[grid=rows,frame=none]\n");
135 self.write("[%header, cols=\"");
136 match kind {
137 TableKind::Rifmux => self.write("2,4,9"),
138 TableKind::RifInst => self.write("2,4,9"),
139 TableKind::Page => self.write("2,4,9"),
140 TableKind::RegInst => self.write("2,3,2,9"),
141 TableKind::Field => self.write("1,3,1,2,8"),
142 _ => self.write("}"),
143 }
144 self.write("\"]\n");
145 if !id.is_empty() {
146 self.write(&format!("[[{id}]]\n"));
147 }
148 self.write("|===\n");
149 }
150
151 fn write_table_footer(&mut self, _kind: TableKind) {
152 self.write("|===\n\n");
153 }
154
155 fn write_reg_detail_header(&mut self, _rif: &RifInst) {
156 self.write("\n");
157 if self.comp().is_rifmux {
158 self.write("=");
159 }
160 self.write("== Registers definition\n");
161 }
162
163 fn write_table_cell(&mut self, kind: (TableKind, CellKind), span: usize, txt: &str, id: &str, _tip: Option<String>) {
164 let txt = if kind.1!=CellKind::Desc {self.sanitize(txt)} else {txt.to_owned()};
166 if span > 1 {
167 self.write(&format!("{span}+a|{txt}"));
168 } else if kind.0==TableKind::FieldRsvd && txt.is_empty() {
169 match kind.1 {
170 CellKind::Inst => self.write("^|-"),
171 CellKind::Desc => self.write("e|Reserved"),
172 _s => {}
173 }
174 } else {
175 let has_link = kind.1==CellKind::Inst && !id.is_empty()
176 && (kind.0==TableKind::Rifmux || kind.0==TableKind::RifInst || kind.0==TableKind::Page);
177 if kind.1 == CellKind::Desc || has_link {
178 self.write("a");
179 }
180 self.write("|");
181 if has_link {
182 if self.setting().split && kind.0==TableKind::Rifmux {
184 self.write(&format!("xref:{}.adoc#{id}[{txt}]", self.comp_fname));
185 } else {
186 self.write(&format!("<<{id},{txt}>>"));
187 }
188 } else {
189 self.write(&txt);
190 }
191 }
192 self.write("\n");
193 }
194
195 fn enum_def_desc(&mut self, def: &EnumDef) -> String {
196 let mut desc = String::with_capacity(def.len() * 16);
197 desc.push_str("\n\n");
198 for entry in &def.values {
199 let entry_name = self.sanitize(&entry.name);
200 let entry_desc = self.sanitize(&entry.description.get(self.is_public()));
201 desc.push_str(&format!(" * {} - {entry_name} : {entry_desc}\n", entry.value));
202 }
203 desc
204 }
205
206 fn sanitize(&self, raw: &str) -> String {
207 let mut txt = String::with_capacity(raw.len());
208 for l in raw.split('\n') {
209 if !txt.is_empty() {
211 txt.push_str(" +\n");
212 }
213 let nb_spc = l.chars().take_while(|c| c.is_whitespace()).count();
215 txt.push_str(&" ".repeat(nb_spc));
216 if let Some(note) = l.strip_prefix("Note: ") {
218 txt.push_str("\nNOTE: ");
219 txt.push_str(note.trim());
220 }
221 else if let Some(note) = l.strip_prefix("Tip: ") {
222 txt.push_str("\nTIP: ");
223 txt.push_str(note.trim());
224 }
225 else if let Some(note) = l.strip_prefix("Important: ") {
226 txt.push_str("\nIMPORTANT: ");
227 txt.push_str(note.trim());
228 }
229 else if let Some(note) = l.strip_prefix("Note: ") {
230 txt.push_str("\nWARNING: ");
231 txt.push_str(note.trim());
232 }
233 else if let Some(note) = l.strip_prefix("Caution: ") {
234 txt.push_str("\nCAUTION: ");
235 txt.push_str(note.trim());
236 } else {
237 txt.push_str(l.trim());
238 }
239 }
240 txt
241 }
242
243 fn write_info(&mut self, info: &str) {
244 self.write(info);
245 self.write("\n\n");
246 }
247
248 fn add_link(&mut self, kind: LinkKind, id: &str) {
249 match kind {
250 LinkKind::Top => self.write(&format!("<<{id},Back to Top>>\n")),
251 LinkKind::Page => self.write(&format!("<<{id},Back to register summary>>\n")),
252 LinkKind::Field => {},
253 }
254 }
255
256}