diff --git a/examples/object_subclass/author.rs b/examples/object_subclass/author.rs index be6e3bcc8f5a..cbb7008cd938 100644 --- a/examples/object_subclass/author.rs +++ b/examples/object_subclass/author.rs @@ -28,6 +28,10 @@ mod imp { /// # Setter /// /// You can change the surname of the author too if you want. + /// + /// # Notify + /// + /// Explicitly send a notification that the surname has changed. #[property(get, set)] surname: RefCell, } diff --git a/glib-macros/src/lib.rs b/glib-macros/src/lib.rs index ca6328b48aaa..0099d6e47365 100644 --- a/glib-macros/src/lib.rs +++ b/glib-macros/src/lib.rs @@ -1348,6 +1348,8 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream { /// /// Doc comments preceding a `#[property]` attribute will be copied to the generated getter and setter methods. You can specify different comments by the getter and setter by using `# Getter` and `# Setter` headings. The text under the header will be copied to the respective method. /// +/// You can also use a `# Notify` heading in order to set the public documentation of the automatically-generated `notify_$property` method. +/// /// ## Extension trait /// You can choose to move the method definitions to a trait by using `#[properties(wrapper_type = super::MyType, ext_trait = MyTypePropertiesExt)]`. /// The trait name is optional, and defaults to `MyTypePropertiesExt`, where `MyType` is extracted from the wrapper type. @@ -1433,6 +1435,10 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream { /// /// # Setter /// /// /// /// This is the comment for the setter of the `extra_comments` field. +/// /// +/// /// # Notify +/// /// +/// /// Sometimes you want to notify explicitly and here's where you explain that. /// #[property(get, set)] /// extra_comments: RefCell, /// } diff --git a/glib-macros/src/properties.rs b/glib-macros/src/properties.rs index 51a4c81671ef..0b771c702df4 100644 --- a/glib-macros/src/properties.rs +++ b/glib-macros/src/properties.rs @@ -578,6 +578,9 @@ fn arrange_property_comments(comments: &[Attribute]) -> (Vec<&Attribute>, Vec<&A let mut getter = vec![]; let mut setter = vec![]; let mut saw_section = false; + // This one we throw away as we're only looking for getter and setter + // comments here but we don't want to mix them up. + let mut notify = vec![]; // We start with no tags so if the programmer doesn't split the comments we can still arrange them. let mut current_section = &mut untagged; @@ -598,6 +601,7 @@ fn arrange_property_comments(comments: &[Attribute]) -> (Vec<&Attribute>, Vec<&A current_section = &mut setter; saw_section = true; } + "# Notify" => current_section = &mut notify, _ => current_section.push(attr), } } @@ -613,6 +617,29 @@ fn arrange_property_comments(comments: &[Attribute]) -> (Vec<&Attribute>, Vec<&A (getter, setter) } +fn extract_notify_docs(comments: &[Attribute]) -> Vec<&Attribute> { + let mut docs = vec![]; + let mut in_section = false; + for attr in comments { + if let syn::Meta::NameValue(meta) = &attr.meta { + if let syn::Expr::Lit(expr) = &meta.value { + if let syn::Lit::Str(lit_str) = &expr.lit { + match lit_str.value().trim() { + "# Notify" => { + in_section = true; + } + "# Getter" | "# Setter" => in_section = false, + _ if in_section => docs.push(attr), + _ => {} + } + } + } + } + } + + docs +} + fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec { let crate_ident = crate_ident_new(); let defs = props.iter().filter(|p| !p.is_overriding()).map(|p| { @@ -695,7 +722,9 @@ fn expand_impl_notify_prop(wrapper_type: &syn::Path, props: &[PropDesc]) -> Vec< let fn_ident = format_ident!("notify_{}", name_to_ident(&name)); let span = p.attrs_span; let enum_ident = name_to_enum_ident(name.value()); + let docs = extract_notify_docs(&p.comments); parse_quote_spanned!(span=> + #(#docs)* #[allow(dead_code)] pub fn #fn_ident(&self) { self.notify_by_pspec(