Revision: 1310 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1310&view=re... Author: colombanw Date: 2010-04-26 23:03:10 +0000 (Mon, 26 Apr 2010)
Log Message: ----------- GeanyGenDoc: Support automatic documentation of children
Allow a rule to request for automatic generation of its children documentation. This is useful for fragmented documentation styles such as Doxygen not to need to manually generate documentation for each children of i.e. a structure.
Modified Paths: -------------- trunk/geanygendoc/src/ggd-doc-setting.c trunk/geanygendoc/src/ggd-doc-setting.h trunk/geanygendoc/src/ggd-file-type-loader.c trunk/geanygendoc/src/ggd-tag-utils.c trunk/geanygendoc/src/ggd-tag-utils.h trunk/geanygendoc/src/ggd.c
Modified: trunk/geanygendoc/src/ggd-doc-setting.c =================================================================== --- trunk/geanygendoc/src/ggd-doc-setting.c 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd-doc-setting.c 2010-04-26 23:03:10 UTC (rev 1310) @@ -49,6 +49,7 @@ setting->policy = GGD_POLICY_KEEP; setting->merge_children = FALSE; setting->matches = tm_tag_max_t; + setting->autodoc_children = FALSE;
/*g_debug ("New setting matching '%s'", match);*/
@@ -107,13 +108,15 @@ g_return_if_fail (setting != NULL);
fprintf (stream, " %s [%p]:\n" - " template: %p\n" - " position: %u\n" - " policy: %u\n", + " template: %p\n" + " position: %u\n" + " policy: %u\n" + " auto-doc-children: %s\n", setting->match, (gpointer)setting, (gpointer)setting->template, setting->position, - setting->policy); + setting->policy, + setting->autodoc_children ? "True" : "False"); }
/**
Modified: trunk/geanygendoc/src/ggd-doc-setting.h =================================================================== --- trunk/geanygendoc/src/ggd-doc-setting.h 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd-doc-setting.h 2010-04-26 23:03:10 UTC (rev 1310) @@ -70,6 +70,7 @@ GgdPolicy policy; gboolean merge_children; TMTagType matches; + gboolean autodoc_children; };
Modified: trunk/geanygendoc/src/ggd-file-type-loader.c =================================================================== --- trunk/geanygendoc/src/ggd-file-type-loader.c 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd-file-type-loader.c 2010-04-26 23:03:10 UTC (rev 1310) @@ -51,6 +51,7 @@ * string ::= ( """ .* """ | "'" .* "'" ) * constant ::= [_A-Z][_A-Z0-9]+ * integer ::= [0-9]+ + * boolean ::= ( "True" | "False" ) * setting_value ::= ( string | constant | integer ) * setting ::= "setting-name" "=" setting_value ";" * setting_list ::= ( "{" setting* "}" | setting ) @@ -65,11 +66,12 @@ * "typedef" | "union" | "variable" | "extern" | * "define" | "macro" | "file" ) * matches ::= type ( "|" type )* - * doctype_subsetting ::= ( "template" "=" string | - * "position" "=" position | - * "policy" "=" policy | - * "children" "=" children | - * "matches" "=" matches ) ";" + * doctype_subsetting ::= ( "template" "=" string | + * "position" "=" position | + * "policy" "=" policy | + * "children" "=" children | + * "matches" "=" matches | + * "auto_doc_children" "=" boolean ) ";" * match ::= type ( "." type )* * doctype_setting ::= ( match "=" "{" doctype_subsetting* "}" | * match "." doctype_subsetting ) @@ -97,6 +99,39 @@ return q; }
+/* reads a boolean (True or False) */ +static gboolean +ggd_file_type_read_boolean (GScanner *scanner, + gboolean *value_) +{ + gboolean success = FALSE; + + if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER) { + g_scanner_unexp_token (scanner, G_TOKEN_IDENTIFIER, + _("boolean value"), NULL, NULL, NULL, TRUE); + } else { + const gchar *bool_str = scanner->value.v_identifier; + gboolean value = FALSE; + + success = TRUE; + if (strcmp (bool_str, "TRUE") == 0 || + strcmp (bool_str, "True") == 0) { + value = TRUE; + } else if (strcmp (bool_str, "FALSE") == 0 || + strcmp (bool_str, "False") == 0) { + value = FALSE; + } else { + g_scanner_error (scanner, _("invalid boolean value "%s""), bool_str); + success = FALSE; + } + if (success && value_) { + *value_ = value; + } + } + + return success; +} + /* reads #GgdDocSetting:template */ static gboolean ggd_file_type_read_setting_template (GScanner *scanner, @@ -239,6 +274,14 @@ return success; }
+/* reads #GgdDocSetting:autodoc_children */ +static gboolean +ggd_file_type_read_setting_auto_doc_children (GScanner *scanner, + GgdDocSetting *setting) +{ + return ggd_file_type_read_boolean (scanner, &setting->autodoc_children); +} + /* dispatches read of value of doctype subsetting @name */ static gboolean ggd_file_type_read_setting_value (GScanner *scanner, @@ -251,11 +294,12 @@ gboolean (*handler) (GScanner *scanner, GgdDocSetting *setting); } settings_table[] = { - { "template", ggd_file_type_read_setting_template }, - { "position", ggd_file_type_read_setting_position }, - { "policy", ggd_file_type_read_setting_policy }, - { "children", ggd_file_type_read_setting_children }, - { "matches", ggd_file_type_read_setting_matches } + { "template", ggd_file_type_read_setting_template }, + { "position", ggd_file_type_read_setting_position }, + { "policy", ggd_file_type_read_setting_policy }, + { "children", ggd_file_type_read_setting_children }, + { "matches", ggd_file_type_read_setting_matches }, + { "auto_doc_children", ggd_file_type_read_setting_auto_doc_children } }; gboolean success = FALSE; gboolean found = FALSE;
Modified: trunk/geanygendoc/src/ggd-tag-utils.c =================================================================== --- trunk/geanygendoc/src/ggd-tag-utils.c 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd-tag-utils.c 2010-04-26 23:03:10 UTC (rev 1310) @@ -96,6 +96,42 @@ }
/** + * ggd_tag_sort_by_line_to_list: + * @tags: A #GPtrArray of #TMTag<!-- -->s + * @direction: Sort direction: %GGD_SORT_ASC for an ascending sort or + * %GGD_SORT_DESC for a descending sort. + * + * Creates a sorted list of tags from a #GPtrArray of #TMTag<!-- -->s. The list + * is sorted by the tags' line position. The sort direction depend on + * @direction. + * + * <note><para>The tags are not copied; you must then not free the array' items + * if you still want to use the returned list.</para></note> + * + * Returns: A newly created list of tags that should be freed with + * g_list_free(). + */ +GList * +ggd_tag_sort_by_line_to_list (const GPtrArray *tags, + gint direction) +{ + GList *children = NULL; + guint i; + TMTag *el; + + g_return_val_if_fail (tags != NULL, NULL); + g_return_val_if_fail (direction != 0, NULL); + + GGD_PTR_ARRAY_FOR (tags, i, el) { + children = g_list_insert_sorted_with_data (children, el, + tag_cmp_by_line, + GINT_TO_POINTER (direction)); + } + + return children; +} + +/** * ggd_tag_find_from_line: * @tags: A #GPtrArray of TMTag<!-- -->s * @line: Line for which find the tag @@ -429,17 +465,19 @@ * @tags: Array of tags that contains @parent * @parent: Tag for which get children * @depth: Maximum depth for children to be found (< 0 means infinite) + * @filter: A logical OR of the TMTagType<!-- -->s to match * - * Finds children tags of a #TMTag. + * Finds children tags of a #TMTag that matches @matches. * <note><para>The returned list of children is sorted in the order they appears * in the source file (by their lines positions)</para></note> * * Returns: The list of children found for @parent */ GList * -ggd_tag_find_children (const GPtrArray *tags, - const TMTag *parent, - gint depth) +ggd_tag_find_children_filtered (const GPtrArray *tags, + const TMTag *parent, + gint depth, + TMTagType filter) { GList *children = NULL; guint i; @@ -455,7 +493,8 @@ fake_scope = g_strdup (parent->name); } GGD_PTR_ARRAY_FOR (tags, i, el) { - if (scope_child_matches (fake_scope, el->atts.entry.scope, depth)) { + if (scope_child_matches (fake_scope, el->atts.entry.scope, depth) && + el->type & filter) { children = g_list_insert_sorted_with_data (children, el, tag_cmp_by_line, GINT_TO_POINTER (GGD_SORT_ASC)); @@ -465,3 +504,23 @@
return children; } + +/** + * ggd_tag_find_children: + * @tags: Array of tags that contains @parent + * @parent: Tag for which get children + * @depth: Maximum depth for children to be found (< 0 means infinite) + * + * Finds children tags of a #TMTag. + * <note><para>The returned list of children is sorted in the order they appears + * in the source file (by their lines positions)</para></note> + * + * Returns: The list of children found for @parent + */ +GList * +ggd_tag_find_children (const GPtrArray *tags, + const TMTag *parent, + gint depth) +{ + return ggd_tag_find_children_filtered (tags, parent, depth, tm_tag_max_t); +}
Modified: trunk/geanygendoc/src/ggd-tag-utils.h =================================================================== --- trunk/geanygendoc/src/ggd-tag-utils.h 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd-tag-utils.h 2010-04-26 23:03:10 UTC (rev 1310) @@ -41,11 +41,17 @@
void ggd_tag_sort_by_line (GPtrArray *tags, gint direction); +GList *ggd_tag_sort_by_line_to_list (const GPtrArray *tags, + gint direction); TMTag *ggd_tag_find_from_line (const GPtrArray *tags, gulong line); TMTag *ggd_tag_find_at_current_pos (GeanyDocument *doc); TMTag *ggd_tag_find_parent (const GPtrArray *tags, const TMTag *child); +GList *ggd_tag_find_children_filtered (const GPtrArray *tags, + const TMTag *parent, + gint depth, + TMTagType filter); GList *ggd_tag_find_children (const GPtrArray *tags, const TMTag *parent, gint depth);
Modified: trunk/geanygendoc/src/ggd.c =================================================================== --- trunk/geanygendoc/src/ggd.c 2010-04-25 21:16:59 UTC (rev 1309) +++ trunk/geanygendoc/src/ggd.c 2010-04-26 23:03:10 UTC (rev 1310) @@ -371,10 +371,100 @@ return setting; }
+/* + * get_config: + * @doc: A #GeanyDocument for which get the configuration + * @doc_type: A documentation type identifier + * @file_type_: Return location for the corresponding #GgdFileType, or %NULL + * @doc_type_: Return location for the corresponding #GgdDocType, or %NULL + * + * Gets the configuration for a document and a documentation type. + * + * Returns: %TRUE on success, %FALSE otherwise. + */ +static gboolean +get_config (GeanyDocument *doc, + const gchar *doc_type, + GgdFileType **file_type_, + GgdDocType **doc_type_) +{ + gboolean success = FALSE; + GgdFileType *ft; + + ft = ggd_file_type_manager_get_file_type (doc->file_type->id); + if (ft) { + GgdDocType *doctype; + + doctype = ggd_file_type_get_doc (ft, doc_type); + if (! doctype) { + msgwin_status_add (_("No documentation type "%s" for language "%s""), + doc_type, doc->file_type->name); + } else { + if (file_type_) *file_type_ = ft; + if (doc_type_) *doc_type_ = doctype; + success = TRUE; + } + } + + return success; +} + +/* + * insert_multiple_comments: + * @doc: A #GeanyDocument in which insert comments + * @filetype: The #GgdFileType to use + * @doctype: The #GgdDocType to use + * @sorted_tag_list: A list of tag to document. This list must be sorted by + * tag's line. + * + * Tries to insert the documentation for all tags listed in @sorted_tag_list, + * taking care of settings and duplications. + * + * Returns: %TRUE on success, %FALSE otherwise. + */ +static gboolean +insert_multiple_comments (GeanyDocument *doc, + GgdFileType *filetype, + GgdDocType *doctype, + GList *sorted_tag_list) +{ + gboolean success = FALSE; + GList *node; + GPtrArray *tag_array; + ScintillaObject *sci = doc->editor->sci; + GHashTable *tag_done_table; /* keeps the list of documented tags. + * Useful since documenting a tag might + * actually document another one */ + + success = TRUE; + tag_array = doc->tm_file->tags_array; + tag_done_table = g_hash_table_new (NULL, NULL); + sci_start_undo_action (sci); + for (node = sorted_tag_list; node; node = node->next) { + GgdDocSetting *setting; + const TMTag *tag = node->data; + + setting = get_setting_from_tag (doctype, tag_array, tag, &tag); + if (setting && ! g_hash_table_lookup (tag_done_table, tag)) { + if (! do_insert_comment (sci, tag_array, tag, filetype, setting)) { + success = FALSE; + break; + } else { + g_hash_table_insert (tag_done_table, (gpointer)tag, (gpointer)tag); + } + } + } + sci_end_undo_action (sci); + g_hash_table_destroy (tag_done_table); + + return success; +} + /** * ggd_insert_comment: * @doc: The document in which insert the comment * @line: SCI's line for which generate a comment. Usually the current line. + * @doc_type: Documentation type identifier * * Tries to insert a comment in a #GeanyDocument. * @@ -390,34 +480,32 @@ const gchar *doc_type) { gboolean success = FALSE; - ScintillaObject *sci; const TMTag *tag; GPtrArray *tag_array; + GgdFileType *filetype; + GgdDocType *doctype;
- sci = doc->editor->sci; + g_return_val_if_fail (DOC_VALID (doc), FALSE); + tag_array = doc->tm_file->tags_array; tag = ggd_tag_find_from_line (tag_array, line + 1 /* it is a SCI line */); if (! tag || (tag->type & tm_tag_file_t)) { msgwin_status_add (_("No valid tag for line %d"), line); } else { - GgdFileType *ft; - - ft = ggd_file_type_manager_get_file_type (doc->file_type->id); - if (ft) { - GgdDocType *doctype; + if (get_config (doc, doc_type, &filetype, &doctype)) { + GgdDocSetting *setting; + GList *tag_list = NULL;
- doctype = ggd_file_type_get_doc (ft, doc_type); - if (! doctype) { - msgwin_status_add (_("No documentation type "%s" for language "%s""), - doc_type, doc->file_type->name); - } else { - GgdDocSetting *setting; - - setting = get_setting_from_tag (doctype, tag_array, tag, &tag); - if (setting) { - success = do_insert_comment (sci, tag_array, tag, ft, setting); - } + setting = get_setting_from_tag (doctype, tag_array, tag, &tag); + if (setting->autodoc_children) { + tag_list = ggd_tag_find_children_filtered (tag_array, tag, 0, + setting->matches); } + /* we assume that a parent always comes before any children, then simply add + * it at the end */ + tag_list = g_list_append (tag_list, (gpointer)tag); + success = insert_multiple_comments (doc, filetype, doctype, tag_list); + g_list_free (tag_list); } }
@@ -438,50 +526,21 @@ const gchar *doc_type) { gboolean success = FALSE; - GgdFileType *ft; + GgdFileType *filetype; + GgdDocType *doctype;
g_return_val_if_fail (DOC_VALID (doc), FALSE);
- ft = ggd_file_type_manager_get_file_type (doc->file_type->id); - if (ft) { - GgdDocType *doctype; + if (get_config (doc, doc_type, &filetype, &doctype)) { + GList *tag_list;
- doctype = ggd_file_type_get_doc (ft, doc_type); - if (! doctype) { - msgwin_status_add (_("No documentation type "%s" for language "%s""), - doc_type, doc->file_type->name); - } else { - GPtrArray *tag_array; - ScintillaObject *sci = doc->editor->sci; - const TMTag *tag; - guint i; - GHashTable *tag_done_table; /* keeps the list of documented tags. - * Useful since documenting a tag might - * actually document another one */ - - success = TRUE; - tag_array = doc->tm_file->tags_array; - tag_done_table = g_hash_table_new (NULL, NULL); - /* sort the tags to be sure to insert by the end of the document, then we - * don't modify the element's position of tags we'll work on */ - ggd_tag_sort_by_line (tag_array, GGD_SORT_DESC); - sci_start_undo_action (sci); - GGD_PTR_ARRAY_FOR (tag_array, i, tag) { - GgdDocSetting *setting; - - setting = get_setting_from_tag (doctype, tag_array, tag, &tag); - if (setting && ! g_hash_table_lookup (tag_done_table, tag)) { - if (! do_insert_comment (sci, tag_array, tag, ft, setting)) { - success = FALSE; - break; - } else { - g_hash_table_insert (tag_done_table, (gpointer)tag, (gpointer)tag); - } - } - } - sci_end_undo_action (sci); - g_hash_table_destroy (tag_done_table); - } + /* get a sorted list of tags to be sure to insert by the end of the + * document, then we don't modify the element's position of tags we'll work + * on */ + tag_list = ggd_tag_sort_by_line_to_list (doc->tm_file->tags_array, + GGD_SORT_DESC); + success = insert_multiple_comments (doc, filetype, doctype, tag_list); + g_list_free (tag_list); }
return success;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
plugins-commits@lists.geany.org