Skip to content

Commit 630cac1

Browse files
authored
feat: add global functions to mdbook, allow documenting arguments and return values (#296)
1 parent 5f0a452 commit 630cac1

File tree

24 files changed

+1274
-190
lines changed

24 files changed

+1274
-190
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ exclude = ["crates/bevy_api_gen", "crates/macro_tests"]
100100
debug = 1
101101
opt-level = 1
102102

103+
[profile.dev-debug]
104+
inherits = "dev"
105+
debug = true
106+
opt-level = 0
107+
103108
[profile.dev.package."*"]
104109
debug = 0
105110
opt-level = 3

crates/bevy_mod_scripting_core/src/docgen/info.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,14 @@ impl FunctionArgInfo {
129129
}
130130
}
131131

132-
#[derive(Debug, Clone, PartialEq, Reflect)]
132+
#[derive(Debug, Clone, Reflect)]
133133
/// Information about a function return value.
134134
pub struct FunctionReturnInfo {
135135
/// The type of the return value.
136136
pub type_id: TypeId,
137+
/// The type information of the return value.
138+
#[reflect(ignore)]
139+
pub type_info: Option<ThroughTypeInfo>,
137140
}
138141

139142
impl Default for FunctionReturnInfo {
@@ -144,9 +147,10 @@ impl Default for FunctionReturnInfo {
144147

145148
impl FunctionReturnInfo {
146149
/// Create a new function return info for a specific type.
147-
pub fn new_for<T: 'static>() -> Self {
150+
pub fn new_for<T: TypedThrough + 'static>() -> Self {
148151
Self {
149152
type_id: TypeId::of::<T>(),
153+
type_info: Some(T::through_type_info()),
150154
}
151155
}
152156
}
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
//! Defines a visitor for function arguments of the `LAD` format.
2+
3+
use ladfile::ArgumentVisitor;
4+
5+
use crate::markdown::MarkdownBuilder;
6+
7+
pub(crate) struct MarkdownArgumentVisitor<'a> {
8+
ladfile: &'a ladfile::LadFile,
9+
buffer: MarkdownBuilder,
10+
}
11+
impl<'a> MarkdownArgumentVisitor<'a> {
12+
pub fn new(ladfile: &'a ladfile::LadFile) -> Self {
13+
let mut builder = MarkdownBuilder::new();
14+
builder.tight_inline().set_escape_mode(false);
15+
Self {
16+
ladfile,
17+
buffer: builder,
18+
}
19+
}
20+
21+
pub fn build(mut self) -> String {
22+
self.buffer.build()
23+
}
24+
}
25+
26+
impl ArgumentVisitor for MarkdownArgumentVisitor<'_> {
27+
fn visit_lad_type_id(&mut self, type_id: &ladfile::LadTypeId) {
28+
let mut buffer = String::new();
29+
30+
// Write identifier<Generic1TypeIdentifier, Generic2TypeIdentifier>
31+
buffer.push_str(&self.ladfile.get_type_identifier(type_id));
32+
if let Some(generics) = self.ladfile.get_type_generics(type_id) {
33+
buffer.push('<');
34+
for (i, generic) in generics.iter().enumerate() {
35+
if i > 0 {
36+
buffer.push_str(", ");
37+
}
38+
buffer.push_str(&self.ladfile.get_type_identifier(&generic.type_id));
39+
}
40+
buffer.push('>');
41+
}
42+
43+
self.buffer.text(buffer);
44+
}
45+
46+
fn walk_option(&mut self, inner: &ladfile::LadArgumentKind) {
47+
// Write Optional<inner>
48+
self.buffer.text("Optional<");
49+
self.visit(inner);
50+
self.buffer.text(">");
51+
}
52+
53+
fn walk_vec(&mut self, inner: &ladfile::LadArgumentKind) {
54+
// Write Vec<inner>
55+
self.buffer.text("Vec<");
56+
self.visit(inner);
57+
self.buffer.text(">");
58+
}
59+
60+
fn walk_hash_map(&mut self, key: &ladfile::LadArgumentKind, value: &ladfile::LadArgumentKind) {
61+
// Write HashMap<key, value>
62+
self.buffer.text("HashMap<");
63+
self.visit(key);
64+
self.buffer.text(", ");
65+
self.visit(value);
66+
self.buffer.text(">");
67+
}
68+
69+
fn walk_tuple(&mut self, inner: &[ladfile::LadArgumentKind]) {
70+
// Write (inner1, inner2, ...)
71+
self.buffer.text("(");
72+
for (idx, arg) in inner.iter().enumerate() {
73+
self.visit(arg);
74+
if idx < inner.len() - 1 {
75+
self.buffer.text(", ");
76+
}
77+
}
78+
self.buffer.text(")");
79+
}
80+
81+
fn walk_array(&mut self, inner: &ladfile::LadArgumentKind, size: usize) {
82+
// Write [inner; size]
83+
self.buffer.text("[");
84+
self.visit(inner);
85+
self.buffer.text("; ");
86+
self.buffer.text(size.to_string());
87+
self.buffer.text("]");
88+
}
89+
}
90+
91+
#[cfg(test)]
92+
mod test {
93+
use ladfile::LadArgumentKind;
94+
95+
use super::*;
96+
97+
fn setup_ladfile() -> ladfile::LadFile {
98+
// load test file from ../../../ladfile_builder/test_assets/
99+
let ladfile = ladfile::EXAMPLE_LADFILE;
100+
ladfile::parse_lad_file(ladfile).unwrap()
101+
}
102+
103+
#[test]
104+
fn test_visit_type_id() {
105+
let ladfile = setup_ladfile();
106+
107+
let first_type_id = ladfile.types.first().unwrap().0;
108+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
109+
110+
visitor.visit_lad_type_id(first_type_id);
111+
assert_eq!(visitor.buffer.build(), "EnumType");
112+
113+
visitor.buffer.clear();
114+
115+
let second_type_id = ladfile.types.iter().nth(1).unwrap().0;
116+
visitor.visit_lad_type_id(second_type_id);
117+
assert_eq!(visitor.buffer.build(), "StructType<usize>");
118+
}
119+
120+
#[test]
121+
fn test_visit_ref() {
122+
let ladfile = setup_ladfile();
123+
124+
let first_type_id = ladfile.types.first().unwrap().0;
125+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
126+
127+
visitor.visit(&LadArgumentKind::Ref(first_type_id.clone()));
128+
assert_eq!(visitor.buffer.build(), "EnumType");
129+
}
130+
131+
#[test]
132+
fn test_visit_mut() {
133+
let ladfile = setup_ladfile();
134+
135+
let first_type_id = ladfile.types.first().unwrap().0;
136+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
137+
138+
visitor.visit(&LadArgumentKind::Mut(first_type_id.clone()));
139+
assert_eq!(visitor.buffer.build(), "EnumType");
140+
}
141+
142+
#[test]
143+
fn test_visit_val() {
144+
let ladfile = setup_ladfile();
145+
146+
let first_type_id = ladfile.types.first().unwrap().0;
147+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
148+
149+
visitor.visit(&LadArgumentKind::Val(first_type_id.clone()));
150+
assert_eq!(visitor.buffer.build(), "EnumType");
151+
}
152+
153+
#[test]
154+
fn test_visit_option() {
155+
let ladfile = setup_ladfile();
156+
157+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
158+
159+
visitor.visit(&LadArgumentKind::Option(Box::new(
160+
LadArgumentKind::Primitive(ladfile::LadBMSPrimitiveKind::Bool),
161+
)));
162+
assert_eq!(visitor.buffer.build(), "Optional<bool>");
163+
}
164+
165+
#[test]
166+
fn test_visit_vec() {
167+
let ladfile = setup_ladfile();
168+
169+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
170+
171+
visitor.visit(&LadArgumentKind::Vec(Box::new(LadArgumentKind::Primitive(
172+
ladfile::LadBMSPrimitiveKind::Bool,
173+
))));
174+
assert_eq!(visitor.buffer.build(), "Vec<bool>");
175+
}
176+
177+
#[test]
178+
fn test_visit_hash_map() {
179+
let ladfile = setup_ladfile();
180+
181+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
182+
183+
visitor.visit(&LadArgumentKind::HashMap(
184+
Box::new(LadArgumentKind::Primitive(
185+
ladfile::LadBMSPrimitiveKind::Bool,
186+
)),
187+
Box::new(LadArgumentKind::Primitive(
188+
ladfile::LadBMSPrimitiveKind::String,
189+
)),
190+
));
191+
assert_eq!(visitor.buffer.build(), "HashMap<bool, String>");
192+
}
193+
194+
#[test]
195+
fn test_visit_tuple() {
196+
let ladfile = setup_ladfile();
197+
198+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
199+
200+
visitor.visit(&LadArgumentKind::Tuple(vec![
201+
LadArgumentKind::Primitive(ladfile::LadBMSPrimitiveKind::Bool),
202+
LadArgumentKind::Primitive(ladfile::LadBMSPrimitiveKind::String),
203+
]));
204+
assert_eq!(visitor.buffer.build(), "(bool, String)");
205+
}
206+
207+
#[test]
208+
fn test_visit_array() {
209+
let ladfile = setup_ladfile();
210+
211+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
212+
213+
visitor.visit(&LadArgumentKind::Array(
214+
Box::new(LadArgumentKind::Primitive(
215+
ladfile::LadBMSPrimitiveKind::Bool,
216+
)),
217+
5,
218+
));
219+
assert_eq!(visitor.buffer.build(), "[bool; 5]");
220+
}
221+
222+
#[test]
223+
fn test_visit_unknown() {
224+
let ladfile = setup_ladfile();
225+
226+
let mut visitor = MarkdownArgumentVisitor::new(&ladfile);
227+
228+
let first_type_id = ladfile.types.first().unwrap().0;
229+
230+
visitor.visit(&LadArgumentKind::Unknown(first_type_id.clone()));
231+
assert_eq!(visitor.buffer.build(), "EnumType");
232+
}
233+
}

crates/lad_backends/mdbook_lad_preprocessor/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![allow(missing_docs)]
33

44
use mdbook::{errors::Error, preprocess::Preprocessor};
5+
mod argument_visitor;
56
mod markdown;
67
mod sections;
78

@@ -31,6 +32,10 @@ impl Preprocessor for LADPreprocessor {
3132

3233
if !is_lad_chapter {
3334
log::debug!("Skipping non-LAD chapter: {:?}", chapter.source_path);
35+
log::trace!(
36+
"Non-LAD chapter: {}",
37+
serde_json::to_string_pretty(&chapter).unwrap_or_default()
38+
);
3439
return;
3540
}
3641

@@ -45,7 +50,10 @@ impl Preprocessor for LADPreprocessor {
4550
}
4651
};
4752

48-
log::debug!("Parsed LAD file: {:?}", lad);
53+
log::debug!(
54+
"Parsed LAD file: {}",
55+
serde_json::to_string_pretty(&lad).unwrap_or_default()
56+
);
4957

5058
let sections = sections::lad_file_to_sections(&lad, Some(chapter_title));
5159

@@ -58,7 +66,11 @@ impl Preprocessor for LADPreprocessor {
5866
None,
5967
);
6068

61-
log::debug!("New chapter: {:?}", new_chapter);
69+
// serialize chapter to json
70+
log::debug!(
71+
"New chapter: {}",
72+
serde_json::to_string_pretty(&new_chapter).unwrap_or_default()
73+
);
6274

6375
*chapter = new_chapter;
6476
}

0 commit comments

Comments
 (0)