Skip to content

Commit c5c697c

Browse files
authored
Class, Method and Property documentation (#12)
1 parent a3bede0 commit c5c697c

File tree

8 files changed

+186
-33
lines changed

8 files changed

+186
-33
lines changed

derive/src/attribute_ops.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,20 +246,21 @@ enum ExpEasingOpts {
246246
}
247247

248248
#[derive(FromField, Debug)]
249-
#[darling(forward_attrs(export, prop))]
249+
#[darling(forward_attrs(export, prop, doc))]
250250
pub struct FieldOpts {
251251
pub ident: Option<syn::Ident>,
252252
pub attrs: Vec<syn::Attribute>,
253253
pub vis: syn::Visibility,
254254
pub ty: syn::Type,
255255
}
256256

257-
#[derive(FromDeriveInput)]
258-
#[darling(supports(struct_any), attributes(script))]
257+
#[derive(FromDeriveInput, Debug)]
258+
#[darling(supports(struct_any), attributes(script), forward_attrs(doc))]
259259
pub struct GodotScriptOpts {
260260
pub ident: syn::Ident,
261261
pub data: Data<util::Ignored, FieldOpts>,
262262
pub base: Option<syn::Ident>,
263+
pub attrs: Vec<syn::Attribute>,
263264
}
264265

265266
#[derive(FromAttributes, Debug)]

derive/src/impl_attribute.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use proc_macro2::TokenStream;
2-
use quote::{quote, quote_spanned};
2+
use quote::{quote, quote_spanned, ToTokens};
33
use syn::{parse_macro_input, spanned::Spanned, FnArg, ImplItem, ItemImpl, ReturnType, Type};
44

55
use crate::{
@@ -59,6 +59,7 @@ pub fn godot_script_impl(
5959
exported: false,
6060
hint: #property_hints::PROPERTY_HINT_NONE,
6161
hint_string: "",
62+
description: "",
6263
},
6364
},
6465

@@ -94,6 +95,15 @@ pub fn godot_script_impl(
9495
quote!(#godot_types::engine::global::MethodFlags::METHOD_FLAG_NORMAL)
9596
};
9697

98+
let description = fnc.attrs.iter()
99+
.filter(|attr| attr.path().is_ident("doc"))
100+
.map(|attr| attr.meta.require_name_value().unwrap().value.to_token_stream())
101+
.reduce(|mut acc, ident| {
102+
acc.extend(quote!(, "\n", ));
103+
acc.extend(ident);
104+
acc
105+
});
106+
97107
let metadata = quote_spanned! {
98108
fnc.span() =>
99109
::godot_rust_script::RustScriptMethodDesc {
@@ -105,8 +115,10 @@ pub fn godot_script_impl(
105115
exported: false,
106116
hint: #property_hints::PROPERTY_HINT_NONE,
107117
hint_string: "",
118+
description: "",
108119
},
109120
flags: #method_flag,
121+
description: concat!(#description),
110122
},
111123
};
112124

derive/src/lib.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod type_paths;
55
use attribute_ops::{FieldOpts, GodotScriptOpts};
66
use darling::{FromAttributes, FromDeriveInput};
77
use proc_macro2::TokenStream;
8-
use quote::{quote, quote_spanned};
8+
use quote::{quote, quote_spanned, ToTokens};
99
use syn::{parse_macro_input, spanned::Spanned, DeriveInput};
1010
use type_paths::{godot_types, string_name_ty, variant_ty};
1111

@@ -58,13 +58,31 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
5858
ops.hint(field.ident.span())?
5959
};
6060

61+
let description = field
62+
.attrs
63+
.iter()
64+
.filter(|attr| attr.path().is_ident("doc"))
65+
.map(|attr| {
66+
attr.meta
67+
.require_name_value()
68+
.unwrap()
69+
.value
70+
.to_token_stream()
71+
})
72+
.reduce(|mut acc, comment| {
73+
acc.extend(quote!(, "\n", ));
74+
acc.extend(comment);
75+
acc
76+
});
77+
6178
let item = quote! {
6279
::godot_rust_script::RustScriptPropDesc {
6380
name: #name,
6481
ty: #ty,
6582
exported: #exported,
6683
hint: #hint,
6784
hint_string: #hint_string,
85+
description: concat!(#description),
6886
},
6987
};
7088

@@ -82,6 +100,23 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
82100
let properties_state_impl = derive_property_states_export(public_fields);
83101
let default_impl = derive_default_with_base(&fields);
84102

103+
let description = opts
104+
.attrs
105+
.iter()
106+
.filter(|attr| attr.path().is_ident("doc"))
107+
.map(|attr| {
108+
attr.meta
109+
.require_name_value()
110+
.unwrap()
111+
.value
112+
.to_token_stream()
113+
})
114+
.reduce(|mut acc, lit| {
115+
acc.extend(quote!(,"\n",));
116+
acc.extend(lit);
117+
acc
118+
});
119+
85120
let output = quote! {
86121
impl ::godot_rust_script::GodotScript for #script_type_ident {
87122
#get_fields_impl
@@ -104,6 +139,7 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
104139
::godot_rust_script::register_script_class!(
105140
#script_type_ident,
106141
#base_class,
142+
concat!(#description),
107143
vec![
108144
#field_metadata
109145
]

rust-script/src/library.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121

2222
#[macro_export]
2323
macro_rules! register_script_class {
24-
($class_name:ty, $base_name:ty, $props:expr) => {
24+
($class_name:ty, $base_name:ty, $desc:expr, $props:expr) => {
2525
$crate::private_export::plugin_add! {
2626
__SCRIPT_REGISTRY in crate;
2727
$crate::RegistryItem::Entry($crate::RustScriptEntry {
@@ -31,6 +31,7 @@ macro_rules! register_script_class {
3131
$props
3232
},
3333
create_data: $crate::create_default_data_struct::<$class_name>,
34+
description: $desc,
3435
})
3536
}
3637
};
@@ -86,6 +87,7 @@ pub struct RustScriptEntry {
8687
pub base_type_name: &'static str,
8788
pub properties: fn() -> Vec<RustScriptPropDesc>,
8889
pub create_data: fn(Gd<Object>) -> RemoteGodotScript_TO<'static, RBox<()>>,
90+
pub description: &'static str,
8991
}
9092

9193
#[derive(Debug)]
@@ -105,6 +107,7 @@ pub struct RustScriptPropDesc {
105107
pub exported: bool,
106108
pub hint: PropertyHint,
107109
pub hint_string: &'static str,
110+
pub description: &'static str,
108111
}
109112

110113
impl RustScriptPropDesc {
@@ -122,6 +125,7 @@ impl RustScriptPropDesc {
122125
},
123126
hint: self.hint.ord(),
124127
hint_string: self.hint_string.into(),
128+
description: RStr::from_str(self.description),
125129
}
126130
}
127131
}
@@ -131,6 +135,7 @@ pub struct RustScriptMethodDesc {
131135
pub return_type: RustScriptPropDesc,
132136
pub arguments: Vec<RustScriptPropDesc>,
133137
pub flags: MethodFlags,
138+
pub description: &'static str,
134139
}
135140

136141
impl RustScriptMethodDesc {
@@ -146,6 +151,7 @@ impl RustScriptMethodDesc {
146151
.into_iter()
147152
.map(|arg| arg.into_property_info(class_name))
148153
.collect(),
154+
description: RStr::from_str(self.description),
149155
}
150156
}
151157
}
@@ -188,13 +194,15 @@ pub fn assemble_metadata<'a>(
188194
.collect();
189195

190196
let create_data = class.create_data;
197+
let description = class.description;
191198

192199
RemoteScriptMetaData::new(
193200
class.class_name.into(),
194201
class.base_type_name.into(),
195202
props,
196203
methods,
197204
create_data,
205+
description.into(),
198206
)
199207
})
200208
.collect()

rust-script/src/runtime/metadata.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::rc::Rc;
1+
use std::{ops::Deref, rc::Rc};
22

33
use abi_stable::std_types::RBox;
44
use godot::{
@@ -19,9 +19,12 @@ use crate::{
1919
pub struct ScriptMetaData {
2020
class_name: ClassName,
2121
base_type_name: StringName,
22+
properties_documented: Vec<Documented<PropertyInfo>>,
2223
properties: Rc<Vec<PropertyInfo>>,
24+
methods_documented: Vec<Documented<MethodInfo>>,
2325
methods: Rc<Vec<MethodInfo>>,
2426
create_data: CreateScriptInstanceData_TO<'static, RBox<()>>,
27+
description: &'static str,
2528
}
2629

2730
impl ScriptMetaData {
@@ -41,19 +44,39 @@ impl ScriptMetaData {
4144
self.properties.clone()
4245
}
4346

47+
pub fn properties_documented(&self) -> &[Documented<PropertyInfo>] {
48+
&self.properties_documented
49+
}
50+
4451
pub fn methods(&self) -> Rc<Vec<MethodInfo>> {
4552
self.methods.clone()
4653
}
54+
55+
pub fn methods_documented(&self) -> &[Documented<MethodInfo>] {
56+
&self.methods_documented
57+
}
58+
59+
pub fn description(&self) -> &'static str {
60+
self.description
61+
}
4762
}
4863

4964
impl From<RemoteScriptMetaData> for ScriptMetaData {
5065
fn from(value: RemoteScriptMetaData) -> Self {
5166
Self {
5267
class_name: ClassName::from_ascii_cstr(value.class_name.as_str().as_bytes()),
53-
base_type_name: StringName::from(value.base_type_name.as_str()),
68+
base_type_name: StringName::from(&value.base_type_name.as_str()),
69+
properties_documented: value
70+
.properties
71+
.clone()
72+
.into_iter()
73+
.map(Into::into)
74+
.collect(),
5475
properties: Rc::new(value.properties.into_iter().map(Into::into).collect()),
76+
methods_documented: value.methods.clone().into_iter().map(Into::into).collect(),
5577
methods: Rc::new(value.methods.into_iter().map(Into::into).collect()),
5678
create_data: value.create_data,
79+
description: value.description.as_str(),
5780
}
5881
}
5982
}
@@ -162,6 +185,55 @@ impl ToMethodDoc for MethodInfo {
162185
}
163186
}
164187

188+
impl<T: ToMethodDoc> ToMethodDoc for Documented<T> {
189+
fn to_method_doc(&self) -> Dictionary {
190+
self.inner
191+
.to_method_doc()
192+
.apply(|dict| dict.set("description", self.description))
193+
}
194+
}
195+
196+
#[derive(Debug)]
197+
pub struct Documented<T> {
198+
inner: T,
199+
description: &'static str,
200+
}
201+
202+
impl From<crate::script_registry::RemoteScriptPropertyInfo> for Documented<PropertyInfo> {
203+
fn from(value: crate::script_registry::RemoteScriptPropertyInfo) -> Self {
204+
Self {
205+
description: value.description.as_str(),
206+
inner: value.into(),
207+
}
208+
}
209+
}
210+
211+
impl From<crate::script_registry::RemoteScriptMethodInfo> for Documented<MethodInfo> {
212+
fn from(value: crate::script_registry::RemoteScriptMethodInfo) -> Self {
213+
Self {
214+
description: value.description.as_str(),
215+
inner: value.into(),
216+
}
217+
}
218+
}
219+
220+
impl<T> Deref for Documented<T> {
221+
type Target = T;
222+
223+
fn deref(&self) -> &Self::Target {
224+
&self.inner
225+
}
226+
}
227+
228+
impl<T: Clone> Clone for Documented<T> {
229+
fn clone(&self) -> Self {
230+
Self {
231+
inner: self.inner.clone(),
232+
description: self.description,
233+
}
234+
}
235+
}
236+
165237
pub trait ToArgumentDoc {
166238
fn to_argument_doc(&self) -> Dictionary;
167239
}
@@ -175,6 +247,14 @@ impl ToArgumentDoc for PropertyInfo {
175247
}
176248
}
177249

250+
impl<T: ToArgumentDoc> ToArgumentDoc for Documented<T> {
251+
fn to_argument_doc(&self) -> Dictionary {
252+
self.inner.to_argument_doc().apply(|dict| {
253+
dict.set("description", self.description);
254+
})
255+
}
256+
}
257+
178258
pub trait ToPropertyDoc {
179259
fn to_property_doc(&self) -> Dictionary;
180260
}
@@ -189,3 +269,11 @@ impl ToPropertyDoc for PropertyInfo {
189269
})
190270
}
191271
}
272+
273+
impl<T: ToPropertyDoc> ToPropertyDoc for Documented<T> {
274+
fn to_property_doc(&self) -> Dictionary {
275+
self.inner
276+
.to_property_doc()
277+
.apply(|dict| dict.set("description", self.description))
278+
}
279+
}

rust-script/src/runtime/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ macro_rules! setup {
5252
}
5353
};
5454
}
55-
55+
5656
#[cfg(not(all(feature = "hot-reload", debug_assertions)))]
5757
#[macro_export]
5858
macro_rules! setup {

0 commit comments

Comments
 (0)