Menu

#189 Show methods as children of classes

closed
None
5
2008-11-10
2008-08-29
No

Hi there

Thanks for geany, I use it every day :-)

It would be nice to have methods in the symbol browser show up as children of the classes that they belong to.

E.g. for Python the display looks like this:

> Classes
& ClassOne
& ClassTwo
> Methods
& ClassOne.__init__
& ClassOne.addFoo
& ClassTwo.__init__
& ClassTwo.getBar
> Functions
...

It would be easier to read if the above were arranged as

> Classes
& ClassOne
* __init__
* addFoo
& ClassTwo
* __init__
* getBar
> Functions
...

Maybe it could be made cofigurable ?

Thanks!
Conrad

Discussion

  • rockstar1707

    rockstar1707 - 2008-09-25

    I vote for this as well. One of the reasons are long class names for example. I did some mockup of this, and it can be seen here:

    http://img220.imageshack.us/img220/1491/geanysymbolbrowserzy5.png

     
  • Nick Treleaven

    Nick Treleaven - 2008-09-25

    I'd like Geany to do this also. But I probably won't work on it for some time, as there are other things to do.

     
  • Nick Treleaven

    Nick Treleaven - 2008-09-25
    • labels: 790036 -->
    • milestone: 542696 -->
     
  • Conrad Steenberg

    Attached is a patch to do the above - please test.
    File Added: class_tree.diff

     
  • Conrad Steenberg

    Patch to place class members/methods under class name

     
  • Conrad Steenberg

    Patch against svn3011

     
  • Conrad Steenberg

    Attached is a new patch for svn 3011
    File Added: class_tree2.diff

     
  • Nick Treleaven

    Nick Treleaven - 2008-09-29
    • assigned_to: nobody --> ntrel
     
  • Nick Treleaven

    Nick Treleaven - 2008-09-29

    modified class_tree2.diff to use geany coding conventions

     
  • Nick Treleaven

    Nick Treleaven - 2008-09-29

    gnocci-man: Thanks for the patch. I've cleaned it up to use Geany coding conventions (described in HACKING), please see class-tree_nmt.diff.

    Your work is good so far, but we can't apply it yet because it doesn't handle some nested elements well, and many filetypes support nested classes (e.g. D, Python). This also applies for C++: a member function of a class in a namespace is not parsed correctly:

    namespace Name
    {
    class A
    {
    char member_of_A(int val);
    };
    }

    member_of_A is incorrectly shown as a function called 'A'.
    File Added: class-tree_nmt.diff

     
  • Conrad Steenberg

    Thanks for looking at the patch.

    Can you point me to the Python and C++ test files you use?

     
  • Nick Treleaven

    Nick Treleaven - 2008-10-01

    > Can you point me to the Python and C++ test files you use?

    For C++, just try the namespace example. You can also replace the namespace keyword with class to see a nested class example (e.g. for D but probably works for the C++ parser too).

    For python:

    class OuterClass():
    class NestedClass():
    nestedclassmember = "a value"
    def method_of_inner():
    """This is a method of NestedClass."""
    j = 3

    Neither of NestedClass's children are shown in the right place, and they are each named 'NestedClass'.

     
  • Nick Treleaven

    Nick Treleaven - 2008-10-01

    Just noticed another minor bug with the patch: with the Diff filetype, a file such as 'src/Makefile.am' is just shown as 'am' in the symbol list.

     
  • Conrad Steenberg

     
  • Conrad Steenberg

    New patch against 3028:
    - Fixed multi-level hierarchies
    - Fixed .diff issue
    File Added: class-tree3.diff

     
  • Nobody/Anonymous

    New patch against 3031
    - Works around C++ nested namespace tag bug.

    File upload seems to be disabled, so I'll paste it here:
    Index: src/symbols.c
    ===================================================================
    --- src/symbols.c (revision 3031)
    +++ src/symbols.c (working copy)
    @@ -841,17 +841,23 @@
    }

    +
    +
    gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
    {
    - GList *tmp;
    + GList *tmp, *skipped = NULL;
    const GList *tags;
    GtkTreeIter iter;
    static gint prev_sort_mode = SYMBOLS_SORT_BY_NAME;
    filetype_id ft_id;
    + gint num_parents = 0, do_skipped = FALSE, num_skipped=0;
    + GHashTable *parent_hash;
    + const gchar *separator;

    g_return_val_if_fail(doc != NULL, FALSE);

    ft_id = FILETYPE_ID(doc->file_type);
    + separator=symbols_get_context_separator(ft_id);

    if (sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
    sort_mode = prev_sort_mode;
    @@ -868,17 +874,22 @@
    gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree), NULL);
    /* Clear all contents */
    gtk_tree_store_clear(doc->priv->tag_store);
    + /* Create a hash table to keep track of parents */
    + parent_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
    + g_free);

    init_tag_list(doc);
    - for (tmp = (GList*)tags; tmp; tmp = g_list_next(tmp))
    +
    + for (tmp = (GList*)tags; tmp && num_skipped<20;)
    {
    - gchar buf[100];
    + gchar buf[100] = "", buf2[100] = "";
    const GeanySymbol *symbol = (GeanySymbol*)tmp->data;
    - GtkTreeIter *parent = NULL;
    + GtkTreeIter *parent = NULL, *parent_search = NULL, *parent_search_short = NULL;
    + GtkTreeIter *parent_icon = NULL, *child = NULL;
    GdkPixbuf *icon = NULL;
    + gint add_parent = FALSE, add_child = FALSE, skip = FALSE;
    + gchar *final_name = symbol->str, *child_name = NULL;

    - g_snprintf(buf, sizeof(buf), "%s [%d]", symbol->str, symbol->line);
    -
    switch (symbol->type)
    {
    case tm_tag_prototype_t:
    @@ -887,6 +898,9 @@
    {
    if (tv_iters.tag_function.stamp == -1) break;
    parent = &(tv_iters.tag_function);
    + parent_icon = &(tv_iters.tag_function);
    + if (ft_id!=GEANY_FILETYPES_DIFF)
    + add_child = TRUE;
    break;
    }
    case tm_tag_macro_t:
    @@ -900,6 +914,9 @@
    {
    if (tv_iters.tag_class.stamp == -1) break;
    parent = &(tv_iters.tag_class);
    + parent_icon = &(tv_iters.tag_class);
    + add_parent = TRUE;
    + add_child = TRUE;
    break;
    }
    case tm_tag_member_t:
    @@ -907,6 +924,9 @@
    {
    if (tv_iters.tag_member.stamp == -1) break;
    parent = &(tv_iters.tag_member);
    + parent_icon = &(tv_iters.tag_member);
    + add_parent = TRUE;
    + add_child = TRUE;
    break;
    }
    case tm_tag_typedef_t:
    @@ -926,12 +946,17 @@
    {
    if (tv_iters.tag_struct.stamp == -1) break;
    parent = &(tv_iters.tag_struct);
    + parent_icon = &(tv_iters.tag_struct);
    + add_parent = TRUE;
    + add_child = TRUE;
    break;
    }
    case tm_tag_variable_t:
    {
    if (tv_iters.tag_variable.stamp == -1) break;
    parent = &(tv_iters.tag_variable);
    + parent_icon = &(tv_iters.tag_variable);
    + add_child = TRUE;
    break;
    }
    case tm_tag_namespace_t:
    @@ -939,30 +964,111 @@
    {
    if (tv_iters.tag_namespace.stamp == -1) break;
    parent = &(tv_iters.tag_namespace);
    + parent_icon = &(tv_iters.tag_namespace);
    + add_child = TRUE;
    + add_parent = TRUE;
    break;
    }
    default:
    {
    if (tv_iters.tag_other.stamp == -1) break;
    parent = &(tv_iters.tag_other);
    + parent_icon = &(tv_iters.tag_variable);
    + add_child = TRUE;
    }
    }

    if (parent)
    - {
    - gtk_tree_model_get(GTK_TREE_MODEL(doc->priv->tag_store), parent,
    - SYMBOLS_COLUMN_ICON, &icon, -1);
    - gtk_tree_store_append(doc->priv->tag_store, &iter, parent);
    - gtk_tree_store_set(doc->priv->tag_store, &iter,
    - SYMBOLS_COLUMN_ICON, icon,
    - SYMBOLS_COLUMN_NAME, buf,
    - SYMBOLS_COLUMN_LINE, symbol->line, -1);
    + { /* Split the string to obtain parent child names */
    + gchar **name_elems = g_strsplit (symbol->str, separator, 10);
    + gchar *child_name = NULL;
    + gchar *parent_name = buf2;
    + gchar *end_ptr = parent_name;
    + gint ne; /* number of name_elements */

    + buf2[0]='\0';
    + parent_search_short=NULL;
    + for (ne=0; name_elems[ne]; ne++){
    + child_name=name_elems[ne];
    + if (name_elems[ne+1]){
    + if (ne>0)
    + end_ptr=g_stpcpy (end_ptr, separator);
    + end_ptr=g_stpcpy (end_ptr, name_elems[ne]);
    + parent_search_short =
    + (GtkTreeIter *)g_hash_table_lookup(parent_hash, (gpointer)name_elems[ne]);
    + }
    + }
    +
    + child = &iter;
    + if (!parent_icon)
    + parent_icon = parent;
    +
    + gtk_tree_model_get(GTK_TREE_MODEL(doc->priv->tag_store), parent_icon,
    + SYMBOLS_COLUMN_ICON, &icon, -1);
    + if (add_child)
    + {
    + if (parent_name)
    + {
    + parent_search = (GtkTreeIter *)g_hash_table_lookup(parent_hash, (gpointer)parent_name);
    + if (parent_search)
    + parent = parent_search;
    + else if (parent_search_short)
    + parent = parent_search_short;
    +
    + if (child_name)
    + final_name = child_name;
    + else
    + final_name = symbol->str;
    + }
    + if (ne>1 && !parent_search && !parent_search_short){ /* Want to add child but parent not found */
    + GList *newstart;
    + tmp = g_list_previous(tmp);
    + newstart = g_list_remove(tmp, (gconstpointer) symbol);
    + newstart = g_list_append(tmp, (gpointer) symbol);
    + skip = TRUE;
    + num_skipped++;
    + }
    + }
    +
    + if (!skip || do_skipped){
    + num_skipped=0;
    + if (add_parent)
    + {
    + GtkTreeIter *new_iter = g_new0(GtkTreeIter, 1);
    + g_hash_table_insert(parent_hash, symbol->str, new_iter);
    + child = new_iter;
    + num_parents++;
    + }
    +
    + g_snprintf(buf, sizeof(buf), "%s [%d]", final_name, symbol->line);
    + gtk_tree_store_append(doc->priv->tag_store, child, parent);
    + gtk_tree_store_set(doc->priv->tag_store, child,
    + SYMBOLS_COLUMN_ICON, icon,
    + SYMBOLS_COLUMN_NAME, buf,
    + SYMBOLS_COLUMN_LINE, symbol->line, -1);
    + }
    + else{ /* Put in skipped list */
    +/*
    + skipped = g_list_append(skipped, (gpointer)symbol);
    +*/
    + }
    +
    if (G_LIKELY(G_IS_OBJECT(icon)))
    g_object_unref(icon);
    + g_strfreev(name_elems);
    }
    +
    + if (! do_skipped && !g_list_next(tmp)){ /* Start adding skipped items */
    + do_skipped = TRUE;
    + tmp = g_list_first(skipped);
    + }
    + else
    + tmp = g_list_next(tmp);
    }
    +
    hide_empty_rows(doc->priv->tag_store);
    + g_hash_table_destroy(parent_hash);
    +
    /* Re-attach model to view */
    gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree),
    GTK_TREE_MODEL(doc->priv->tag_store));

     
  • Conrad Steenberg

    Attached patch against 3031
    - Works around C++ nested namespace tag bug.
    File Added: class-tree4.diff

     
  • Conrad Steenberg

    Class tree patch to work around C++ tags bug

     
  • Nick Treleaven

    Nick Treleaven - 2008-10-02

    Thanks for the new patch class-tree4.diff.

    I've applied it in a branch with minor changes here:
    https://geany.svn.sourceforge.net/svnroot/geany/branches/symbol-tree

    The bugs seem to fixed, thanks.

    I'm going to refactor some of symbols_recreate_tag_list(), so it's easier to understand.

     
  • Nick Treleaven

    Nick Treleaven - 2008-10-03

    I have some ideas to make the code more straightforward and robust:

    1. Replace the GeanySymbol list with a TMTag list. This avoids having to parse the parent name, avoiding possible bugs.

    2. Sort the tags by appearance before adding to the tree model. This ensures that parent items are added before children, and we can remove all the complex 'skipped' code. The model can then be sorted after all entries have been added (for the 'sort by name' case).

    3. Instead of looking for children for certain tags (e.g. class, etc), just see if the TMTag struct has a parent field. This should be much more flexible for filetypes that overload e.g. the tm_tag_class_t fields to mean something else.

    I'm happy to work on these changes over time. If you want to discuss them, the geany-devel list might be better than here.

     
  • Nick Treleaven

    Nick Treleaven - 2008-11-10

    Finished the code changes; now merged into SVN trunk. Thanks again for the original patch, gnocci-man.

     
  • Nick Treleaven

    Nick Treleaven - 2008-11-10
    • status: open --> closed
     

Log in to post a comment.