1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2004 Naba Kumar
5 * Copyright (C) 2006 Martin Stubenschrott <stubenschrott@gmx.net>: thankyou for
6 * the code of IComplete [which anyway here is heavily modified] and the ideas
8 * Copyright (C) 2006 Massimo Cora' <maxcvs@email.it>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <libgnomeui/gnome-stock-icons.h>
32 #include <glib/gi18n.h>
33 #include <libgnome/gnome-macros.h>
34 #include <libgnomevfs/gnome-vfs-utils.h>
35 #include <libanjuta/anjuta-utils.h>
36 #include <libanjuta/anjuta-debug.h>
37 #include <libanjuta/anjuta-status.h>
38 #include <tm_tagmanager.h>
39 #include "an_symbol_view.h"
40 #include "an_symbol_info.h"
41 #include "an_symbol_prefs.h"
43 #define MAX_STRING_LENGTH 256
44 #define TOOLTIP_TIMEOUT 1000 /* milliseconds */
47 struct _AnjutaSymbolViewPriv
49 TMWorkObject
*tm_project
;
50 const TMWorkspace
*tm_workspace
;
52 GtkTreeModel
*file_symbol_model
;
54 gboolean symbols_need_update
;
57 GdkRectangle tooltip_rect
;
58 GtkWidget
*tooltip_window
;
59 gulong tooltip_timeout
;
60 PangoLayout
*tooltip_layout
;
73 static gchar
*keywords
[] = {
133 static GtkTreeViewClass
*parent_class
;
135 /* Tooltip operations -- taken from gtodo/message_view */
138 tooltip_get_display_text (AnjutaSymbolView
* sv
)
144 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (sv
));
146 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(sv
),
147 sv
->priv
->tooltip_rect
.x
, sv
->priv
->tooltip_rect
.y
,
148 &path
, NULL
, NULL
, NULL
))
152 gtk_tree_model_get_iter (model
, &iter
, path
);
153 gtk_tree_model_get (model
, &iter
, NAME_COLUMN
, &text
, -1);
154 gtk_tree_path_free(path
);
162 tooltip_paint (GtkWidget
*widget
, GdkEventExpose
*event
, AnjutaSymbolView
* sv
)
167 tooltiptext
= tooltip_get_display_text (sv
);
170 tooltiptext
= g_strdup (_("No message details"));
172 pango_layout_set_markup (sv
->priv
->tooltip_layout
,
174 strlen (tooltiptext
));
175 pango_layout_set_wrap(sv
->priv
->tooltip_layout
, PANGO_WRAP_CHAR
);
176 pango_layout_set_width(sv
->priv
->tooltip_layout
, 600000);
177 style
= sv
->priv
->tooltip_window
->style
;
179 gtk_paint_flat_box (style
, sv
->priv
->tooltip_window
->window
,
180 GTK_STATE_NORMAL
, GTK_SHADOW_OUT
,
181 NULL
, sv
->priv
->tooltip_window
,
182 "tooltip", 0, 0, -1, -1);
184 gtk_paint_layout (style
, sv
->priv
->tooltip_window
->window
,
185 GTK_STATE_NORMAL
, TRUE
,
186 NULL
, sv
->priv
->tooltip_window
,
187 "tooltip", 4, 4, sv
->priv
->tooltip_layout
);
189 g_object_unref(layout);
196 tooltip_timeout (AnjutaSymbolView
* sv
)
198 gint scr_w
,scr_h
, w
, h
, x
, y
;
201 tooltiptext
= tooltip_get_display_text (sv
);
204 tooltiptext
= g_strdup (_("No file details"));
206 sv
->priv
->tooltip_window
= gtk_window_new (GTK_WINDOW_POPUP
);
207 sv
->priv
->tooltip_window
->parent
= GTK_WIDGET(sv
);
208 gtk_widget_set_app_paintable (sv
->priv
->tooltip_window
, TRUE
);
209 gtk_window_set_resizable (GTK_WINDOW(sv
->priv
->tooltip_window
), FALSE
);
210 gtk_widget_set_name (sv
->priv
->tooltip_window
, "gtk-tooltips");
211 g_signal_connect (G_OBJECT(sv
->priv
->tooltip_window
), "expose_event",
212 G_CALLBACK(tooltip_paint
), sv
);
213 gtk_widget_ensure_style (sv
->priv
->tooltip_window
);
215 sv
->priv
->tooltip_layout
=
216 gtk_widget_create_pango_layout (sv
->priv
->tooltip_window
, NULL
);
217 pango_layout_set_wrap (sv
->priv
->tooltip_layout
, PANGO_WRAP_CHAR
);
218 pango_layout_set_width (sv
->priv
->tooltip_layout
, 600000);
219 pango_layout_set_markup (sv
->priv
->tooltip_layout
, tooltiptext
,
220 strlen (tooltiptext
));
221 scr_w
= gdk_screen_width();
222 scr_h
= gdk_screen_height();
223 pango_layout_get_size (sv
->priv
->tooltip_layout
, &w
, &h
);
224 w
= PANGO_PIXELS(w
) + 8;
225 h
= PANGO_PIXELS(h
) + 8;
227 gdk_window_get_pointer (NULL
, &x
, &y
, NULL
);
228 if (GTK_WIDGET_NO_WINDOW (sv
))
229 y
+= GTK_WIDGET(sv
)->allocation
.y
;
234 x
-= (x
+ w
) - scr_w
;
238 if ((y
+ h
+ 4) > scr_h
)
243 g_object_unref(layout);
245 gtk_widget_set_size_request (sv
->priv
->tooltip_window
, w
, h
);
246 gtk_window_move (GTK_WINDOW (sv
->priv
->tooltip_window
), x
, y
);
247 gtk_widget_show (sv
->priv
->tooltip_window
);
248 g_free (tooltiptext
);
254 tooltip_motion_cb (GtkWidget
*tv
, GdkEventMotion
*event
, AnjutaSymbolView
* sv
)
258 if (sv
->priv
->tooltip_rect
.y
== 0 &&
259 sv
->priv
->tooltip_rect
.height
== 0 &&
260 sv
->priv
->tooltip_timeout
)
262 g_source_remove (sv
->priv
->tooltip_timeout
);
263 sv
->priv
->tooltip_timeout
= 0;
264 if (sv
->priv
->tooltip_window
) {
265 gtk_widget_destroy (sv
->priv
->tooltip_window
);
266 sv
->priv
->tooltip_window
= NULL
;
270 if (sv
->priv
->tooltip_timeout
) {
271 if (((int)event
->y
> sv
->priv
->tooltip_rect
.y
) &&
272 (((int)event
->y
- sv
->priv
->tooltip_rect
.height
)
273 < sv
->priv
->tooltip_rect
.y
))
278 g_source_remove (sv
->priv
->tooltip_timeout
);
279 sv
->priv
->tooltip_timeout
= 0;
282 /* We've left the cell. Remove the timeout and create a new one below */
283 if (sv
->priv
->tooltip_window
) {
284 gtk_widget_destroy (sv
->priv
->tooltip_window
);
285 sv
->priv
->tooltip_window
= NULL
;
287 g_source_remove (sv
->priv
->tooltip_timeout
);
288 sv
->priv
->tooltip_timeout
= 0;
291 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(sv
),
292 event
->x
, event
->y
, &path
,
295 gtk_tree_view_get_cell_area (GTK_TREE_VIEW (sv
),
296 path
, NULL
, &sv
->priv
->tooltip_rect
);
298 if (sv
->priv
->tooltip_rect
.y
!= 0 &&
299 sv
->priv
->tooltip_rect
.height
!= 0)
303 tooltiptext
= tooltip_get_display_text (sv
);
304 if (tooltiptext
== NULL
)
306 g_free (tooltiptext
);
308 sv
->priv
->tooltip_timeout
=
309 g_timeout_add (TOOLTIP_TIMEOUT
,
310 (GSourceFunc
) tooltip_timeout
, sv
);
312 gtk_tree_path_free (path
);
318 tooltip_leave_cb (GtkWidget
*w
, GdkEventCrossing
*e
, AnjutaSymbolView
* sv
)
320 if (sv
->priv
->tooltip_timeout
) {
321 g_source_remove (sv
->priv
->tooltip_timeout
);
322 sv
->priv
->tooltip_timeout
= 0;
324 if (sv
->priv
->tooltip_window
) {
325 gtk_widget_destroy (sv
->priv
->tooltip_window
);
326 g_object_unref (sv
->priv
->tooltip_layout
);
327 sv
->priv
->tooltip_window
= NULL
;
331 static void anjuta_symbol_view_add_children (AnjutaSymbolView
*sv
,
335 static void anjuta_symbol_view_refresh_tree (AnjutaSymbolView
*sv
);
338 destroy_tm_hash_value (gpointer data
)
340 AnjutaSymbolView
*sv
;
341 TMWorkObject
*tm_file
;
343 sv
= g_object_get_data (G_OBJECT (data
), "symbol_view");
344 tm_file
= g_object_get_data (G_OBJECT (data
), "tm_file");
346 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
349 if (tm_file
->parent
==
350 TM_WORK_OBJECT (sv
->priv
->tm_workspace
))
352 DEBUG_PRINT ("Removing tm_file");
353 tm_workspace_remove_object (tm_file
, TRUE
);
356 g_object_unref (G_OBJECT (data
));
360 on_remove_project_tm_files (gpointer key
, gpointer val
, gpointer data
)
362 AnjutaSymbolView
*sv
;
363 TMWorkObject
*tm_file
;
365 sv
= g_object_get_data (G_OBJECT (val
), "symbol_view");
366 tm_file
= g_object_get_data (G_OBJECT (val
), "tm_file");
368 g_return_val_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
), FALSE
);
369 g_return_val_if_fail (tm_file
!= NULL
, FALSE
);
372 TM_WORK_OBJECT (tm_file
)->parent
== sv
->priv
->tm_project
)
374 DEBUG_PRINT ("Removing tm_file");
375 if (sv
->priv
->file_symbol_model
== val
)
376 sv
->priv
->file_symbol_model
= NULL
;
384 on_treeview_row_search (GtkTreeModel
* model
, gint column
,
385 const gchar
* key
, GtkTreeIter
* iter
, gpointer data
)
387 DEBUG_PRINT ("Search key == '%s'", key
);
392 static AnjutaSymbolInfo
*
393 sv_current_symbol (AnjutaSymbolView
* sv
)
396 GtkTreeSelection
*selection
;
398 AnjutaSymbolInfo
*info
;
400 g_return_val_if_fail (GTK_IS_TREE_VIEW (sv
), FALSE
);
402 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (sv
));
403 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (sv
));
405 if (!gtk_tree_selection_get_selected (selection
, NULL
, &iter
))
408 gtk_tree_model_get (model
, &iter
, SVFILE_ENTRY_COLUMN
, &info
, -1);
413 on_symbol_view_refresh_idle (gpointer data
)
415 AnjutaSymbolView
*view
;
417 view
= ANJUTA_SYMBOL_VIEW (data
);
419 /* If symbols need update */
420 anjuta_symbol_view_refresh_tree (view
);
425 on_symbol_view_row_expanded (GtkTreeView
* view
,
426 GtkTreeIter
* iter
, GtkTreePath
*iter_path
,
427 AnjutaSymbolView
*sv
)
432 GList
*row_refs
, *row_ref_node
;
433 GtkTreeRowReference
*row_ref
;
437 AnjutaStatus *status;
439 status = anjuta_shell_get_status (ANJUTA_PLUGIN (fv)->shell, NULL);
440 anjuta_status_busy_push (status);
442 GtkTreeStore
*store
= GTK_TREE_STORE (gtk_tree_view_get_model (view
));
444 if (sv
->priv
->symbols_need_update
)
446 DEBUG_PRINT ("Update required requested");
447 g_idle_add (on_symbol_view_refresh_idle
, sv
);
451 if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store
), &child
, iter
))
453 /* Make sure the symbol children are not yet created */
454 gtk_tree_model_get (GTK_TREE_MODEL (store
), &child
,
455 SYMBOL_NODE
, &sym
, -1);
456 /* Symbol has been created, no need to create them again */
459 g_object_unref (sym
);
465 /* Has no children */
470 * Delete old children.
471 * Deleting multiple rows at one go is little tricky. We need to
472 * take row references before they are deleted
479 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (store
), &child
);
480 row_ref
= gtk_tree_row_reference_new (GTK_TREE_MODEL (store
), path
);
481 row_refs
= g_list_prepend (row_refs
, row_ref
);
482 gtk_tree_path_free (path
);
484 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store
), &child
));
486 /* Update with new info */
487 gtk_tree_model_get (GTK_TREE_MODEL (store
), iter
,
488 SYMBOL_NODE
, &sym
, -1);
491 anjuta_symbol_view_add_children (sv
, sym
, store
, iter
);
492 g_object_unref (sym
);
495 /* Delete the referenced rows */
496 row_ref_node
= row_refs
;
499 row_ref
= row_ref_node
->data
;
500 path
= gtk_tree_row_reference_get_path (row_ref
);
501 g_assert (path
!= NULL
);
502 gtk_tree_model_get_iter (GTK_TREE_MODEL (store
), &child
, path
);
503 gtk_tree_store_remove (store
, &child
);
504 gtk_tree_path_free (path
);
505 gtk_tree_row_reference_free (row_ref
);
506 row_ref_node
= g_list_next (row_ref_node
);
510 g_list_free (row_refs
);
512 /* anjuta_status_busy_pop (status); */
516 on_symbol_view_row_collapsed (GtkTreeView
* view
,
517 GtkTreeIter
* iter
, GtkTreePath
* path
)
522 sv_create (AnjutaSymbolView
* sv
)
525 GtkTreeViewColumn
*column
;
526 GtkCellRenderer
*renderer
;
527 GtkTreeSelection
*selection
;
529 /* Tree and his model */
530 store
= gtk_tree_store_new (COLUMNS_NB
,
533 ANJUTA_TYPE_SYMBOL_INFO
,
536 gtk_tree_view_set_model (GTK_TREE_VIEW (sv
), GTK_TREE_MODEL (store
));
537 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (sv
), FALSE
);
539 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (sv
));
540 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
542 /* search through the tree interactively */
543 gtk_tree_view_set_search_column (GTK_TREE_VIEW (sv
), NAME_COLUMN
);
545 /* FIXME: Implement on_tree_view_row_search
546 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (sv),
547 on_treeview_row_search,
550 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (sv
), TRUE
);
552 g_signal_connect (G_OBJECT (sv
), "row_expanded",
553 G_CALLBACK (on_symbol_view_row_expanded
), sv
);
554 g_signal_connect (G_OBJECT (sv
), "row_collapsed",
555 G_CALLBACK (on_symbol_view_row_collapsed
), sv
);
557 /* Tooltip signals */
558 g_signal_connect (G_OBJECT (sv
), "motion-notify-event",
559 G_CALLBACK (tooltip_motion_cb
), sv
);
560 g_signal_connect (G_OBJECT (sv
), "leave-notify-event",
561 G_CALLBACK (tooltip_leave_cb
), sv
);
563 g_object_unref (G_OBJECT (store
));
566 column
= gtk_tree_view_column_new ();
567 gtk_tree_view_column_set_sizing (column
,
568 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
569 gtk_tree_view_column_set_title (column
, _("Symbol"));
571 renderer
= gtk_cell_renderer_pixbuf_new ();
572 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
573 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
576 renderer
= gtk_cell_renderer_text_new ();
577 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
578 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
581 gtk_tree_view_append_column (GTK_TREE_VIEW (sv
), column
);
582 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (sv
), column
);
586 anjuta_symbol_view_clear (AnjutaSymbolView
* sv
)
589 AnjutaSymbolViewPriv
* priv
;
593 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
595 if (sv
->priv
->tm_project
)
597 tm_project_save (TM_PROJECT (sv
->priv
->tm_project
));
599 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (sv
));
602 /* clean out gtk_tree_store. We won't need it anymore */
603 gtk_tree_store_clear (GTK_TREE_STORE (model
));
605 if (sv
->priv
->symbols
)
607 tm_symbol_tree_free (sv
->priv
->symbols
);
608 sv
->priv
->symbols
= NULL
;
609 sv
->priv
->symbols_need_update
= FALSE
;
611 g_hash_table_foreach_remove (sv
->priv
->tm_files
,
612 on_remove_project_tm_files
,
614 if (sv
->priv
->tm_project
)
616 tm_project_free (sv
->priv
->tm_project
);
617 sv
->priv
->tm_project
= NULL
;
622 sv_assign_node_name (TMSymbol
* sym
, GString
* s
)
624 gboolean append_var_type
= TRUE
;
626 g_assert (sym
&& sym
->tag
&& s
);
627 g_string_assign (s
, sym
->tag
->name
);
629 switch (sym
->tag
->type
)
631 case tm_tag_function_t
:
632 case tm_tag_method_t
:
633 case tm_tag_prototype_t
:
634 if (sym
->tag
->atts
.entry
.arglist
)
635 g_string_append (s
, sym
->tag
->atts
.entry
.arglist
);
637 case tm_tag_macro_with_arg_t
:
638 if (sym
->tag
->atts
.entry
.arglist
)
639 g_string_append (s
, sym
->tag
->atts
.entry
.arglist
);
640 append_var_type
= FALSE
;
648 char *vt
= sym
->tag
->atts
.entry
.type_ref
[1];
651 if((vt
= strstr(vt
, "_fake_")))
657 g_string_append_printf (s
, " [%s",
658 sym
->tag
->atts
.entry
.type_ref
[1]);
659 i
= sym
->tag
->atts
.entry
.pointerOrder
;
661 g_string_append_printf (s
, "*");
662 g_string_append_printf (s
, "]");
669 g_string_append_printf (s
, " [%s",
670 sym
->tag
->atts
.entry
.type_ref
[1]);
671 i
= sym
->tag
->atts
.entry
.pointerOrder
;
673 g_string_append_printf (s
, "*");
674 g_string_append_printf (s
, "]");
681 mapping_function (GtkTreeView
* treeview
, GtkTreePath
* path
, gpointer data
)
684 GList
*map
= *((GList
**) data
);
686 str
= gtk_tree_path_to_string (path
);
687 map
= g_list_append (map
, str
);
688 *((GList
**) data
) = map
;
693 anjuta_symbol_view_get_tm_file (AnjutaSymbolView
* sv
, const gchar
* uri
)
696 TMSourceFile
*tm_file
;
698 g_return_val_if_fail (uri
!= NULL
, NULL
);
700 filename
= gnome_vfs_get_local_path_from_uri (uri
);
702 tm_file
= (TMSourceFile
*)tm_workspace_find_object (TM_WORK_OBJECT
703 (sv
->priv
->tm_workspace
), filename
,
713 anjuta_symbol_view_add_source (AnjutaSymbolView
* sv
, const gchar
*filename
)
715 if (!sv
->priv
->tm_project
)
717 tm_project_add_file (TM_PROJECT (sv
->priv
->tm_project
), filename
, TRUE
);
719 DEBUG_PRINT ("Project changed: Flagging refresh required");
721 sv
->priv
->symbols_need_update
= TRUE
;
723 for (tmp = app->text_editor_list; tmp; tmp = g_list_next(tmp))
725 te = TEXT_EDITOR (tmp->data);
726 if (te && !te->tm_file && (0 == strcmp(te->full_filename, filename)))
727 te->tm_file = tm_workspace_find_object(TM_WORK_OBJECT(app->tm_workspace)
731 /* sv_populate (sv); */
735 anjuta_symbol_view_remove_source (AnjutaSymbolView
*sv
, const gchar
*filename
)
737 TMWorkObject
*source_file
;
739 if (!sv
->priv
->tm_project
)
742 source_file
= tm_project_find_file (sv
->priv
->tm_project
, filename
, FALSE
);
747 tm_project_remove_object (TM_PROJECT (sv
->priv
->tm_project
),
750 DEBUG_PRINT ("Project changed: Flagging refresh required");
752 sv
->priv
->symbols_need_update
= TRUE
;
753 /* for (node = app->text_editor_list; node; node = g_list_next(node))
755 te = TEXT_EDITOR (node->data);
756 if (te && (source_file == te->tm_file))
763 g_warning ("Unable to find %s in project", full_fn);
767 void anjuta_symbol_view_update_source_from_buffer (AnjutaSymbolView
*sv
, const gchar
*uri
,
768 gchar
* text_buffer
, gint buffer_size
)
770 TMWorkObject
*tm_file
;
771 gchar
*filename
= NULL
;
776 g_return_if_fail(sv
!= NULL
);
777 if (uri
== NULL
|| text_buffer
== NULL
)
780 filename
= gnome_vfs_get_local_path_from_uri (uri
);
782 if (sv
->priv
->tm_workspace
== NULL
||
783 sv
->priv
->tm_project
== NULL
) {
784 DEBUG_PRINT ("workspace or project are null");
789 tm_workspace_find_object (TM_WORK_OBJECT
790 (sv
->priv
->tm_workspace
),
792 if (tm_file
== NULL
) {
793 DEBUG_PRINT ("tm_file is null");
797 timer
= g_timer_new ();
798 tm_source_file_buffer_update (tm_file
, (unsigned char *)text_buffer
, buffer_size
, TRUE
);
800 g_timer_stop (timer
);
801 g_timer_elapsed (timer
, &ms
);
803 DEBUG_PRINT ("updating took %d microseconds", (unsigned int)ms
);
805 if (sv
->priv
->tm_project
&&
806 TM_PROJECT(sv
->priv
->tm_project
)->work_object
.tags_array
)
808 DEBUG_PRINT ("total tags discovered AFTER buffer updating...: %d",
809 TM_PROJECT(sv
->priv
->tm_project
)->work_object
.tags_array
->len
);
815 anjuta_symbol_view_add_children (AnjutaSymbolView
*sv
, TMSymbol
*sym
,
819 if ((iter
== NULL
|| (tm_tag_function_t
!= sym
->tag
->type
&&
820 tm_tag_prototype_t
!= sym
->tag
->type
)) &&
821 (sym
->info
.children
) && (sym
->info
.children
->len
> 0))
825 AnjutaSymbolInfo
*sfile
;
828 DEBUG_PRINT ("Total nodes: %d", sym
->info
.children
->len
);
830 for (j
= 0; j
< sym
->info
.children
->len
; j
++)
832 TMSymbol
*sym1
= TM_SYMBOL (sym
->info
.children
->pdata
[j
]);
833 GtkTreeIter sub_iter
, child_iter
;
836 // if (!sym1 || ! sym1->tag || ! sym1->tag->atts.entry.file)
839 if (!sym1
|| ! sym1
->tag
)
842 type
= anjuta_symbol_info_get_node_type (sym1
, NULL
);
844 if (sv_none_t
== type
)
847 s
= g_string_sized_new (MAX_STRING_LENGTH
);
848 sv_assign_node_name (sym1
, s
);
850 if (sym
&& sym
->tag
&& sym
->tag
->atts
.entry
.scope
)
852 g_string_insert (s
, 0, "::");
853 g_string_insert (s
, 0, sym
->tag
->atts
.entry
.scope
);
855 sfile
= anjuta_symbol_info_new (sym1
, type
);
857 gtk_tree_store_append (store
, &sub_iter
, iter
);
858 gtk_tree_store_set (store
, &sub_iter
,
860 anjuta_symbol_info_get_pixbuf (type
),
862 SVFILE_ENTRY_COLUMN
, sfile
,
866 if (tm_tag_function_t
!= sym1
->tag
->type
&&
867 tm_tag_prototype_t
!= sym1
->tag
->type
&&
868 sym1
->info
.children
&& sym1
->info
.children
->len
> 0)
870 /* Append a dummy children node */
871 gtk_tree_store_append (store
, &child_iter
, &sub_iter
);
872 gtk_tree_store_set (store
, &child_iter
,
873 NAME_COLUMN
, _("Loading..."),
876 anjuta_symbol_info_free (sfile
);
877 g_string_free (s
, TRUE
);
883 anjuta_symbol_view_refresh_tree (AnjutaSymbolView
*sv
)
886 GList
*selected_items
= NULL
;
888 store
= GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (sv
)));
890 selected_items
= anjuta_symbol_view_get_node_expansion_states (sv
);
891 gtk_tree_store_clear (store
);
894 if (sv
->priv
->symbols
)
896 tm_symbol_tree_free (sv
->priv
->symbols
);
897 sv
->priv
->symbols
= NULL
;
899 /* Destroy file symbol models that belong to the project */
900 g_hash_table_foreach_remove (sv
->priv
->tm_files
,
901 on_remove_project_tm_files
,
903 if (!(sv
->priv
->symbols
=
904 tm_symbol_tree_new (sv
->priv
->tm_project
->tags_array
)))
907 sv
->priv
->symbols_need_update
= FALSE
;
909 DEBUG_PRINT ("Populating symbol view: Creating symbol view...");
911 if (!sv
->priv
->symbols
->info
.children
912 || (0 == sv
->priv
->symbols
->info
.children
->len
))
914 tm_symbol_tree_free (sv
->priv
->symbols
);
915 sv
->priv
->symbols
= NULL
;
918 anjuta_symbol_view_add_children (sv
, sv
->priv
->symbols
, store
, NULL
);
920 /* tm_symbol_tree_free (symbol_tree); */
921 anjuta_symbol_view_set_node_expansion_states (sv
, selected_items
);
925 anjuta_util_glist_strings_free (selected_items
);
928 /*------------------------------------------------------------------------------
929 * this function will add the symbol_tag entries on the GtkTreeStore
932 anjuta_symbol_view_open (AnjutaSymbolView
* sv
, const gchar
* root_dir
)
934 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
935 g_return_if_fail (root_dir
!= NULL
);
937 DEBUG_PRINT ("Populating symbol view: Loading tag database...");
939 /* make sure we clear anjuta_symbol_view from previous data */
940 anjuta_symbol_view_clear (sv
);
942 sv
->priv
->tm_project
= tm_project_new (root_dir
, NULL
, NULL
, FALSE
);
944 DEBUG_PRINT ("Populating symbol view: Creating symbol tree...");
946 if (sv
->priv
->tm_project
&&
947 sv
->priv
->tm_project
->tags_array
&&
948 (sv
->priv
->tm_project
->tags_array
->len
> 0))
950 anjuta_symbol_view_refresh_tree (sv
);
955 anjuta_symbol_view_finalize (GObject
* obj
)
957 AnjutaSymbolView
*sv
= ANJUTA_SYMBOL_VIEW (obj
);
958 DEBUG_PRINT ("Finalizing symbolview widget");
960 anjuta_symbol_view_clear (sv
);
962 if (sv
->priv
->tooltip_timeout
)
963 g_source_remove (sv
->priv
->tooltip_timeout
);
964 sv
->priv
->tooltip_timeout
= 0;
966 g_hash_table_destroy (sv
->priv
->tm_files
);
967 tm_workspace_free ((gpointer
) sv
->priv
->tm_workspace
);
969 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
973 anjuta_symbol_view_dispose (GObject
* obj
)
975 AnjutaSymbolView
*sv
= ANJUTA_SYMBOL_VIEW (obj
);
977 g_source_remove_by_user_data (sv
);
979 /* All file symbol refs would be freed when the hash table is distroyed */
980 sv
->priv
->file_symbol_model
= NULL
;
981 G_OBJECT_CLASS (parent_class
)->dispose (obj
);
984 /* Anjuta symbol view class */
986 anjuta_symbol_view_instance_init (GObject
* obj
)
988 AnjutaSymbolView
*sv
;
990 sv
= ANJUTA_SYMBOL_VIEW (obj
);
991 sv
->priv
= g_new0 (AnjutaSymbolViewPriv
, 1);
992 sv
->priv
->file_symbol_model
= NULL
;
993 sv
->priv
->symbols_need_update
= FALSE
;
994 sv
->priv
->tm_workspace
= tm_get_workspace ();
995 sv
->priv
->tm_files
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
997 destroy_tm_hash_value
);
999 /* let's create symbol_view tree and other gui stuff */
1004 anjuta_symbol_view_class_init (AnjutaSymbolViewClass
* klass
)
1006 AnjutaSymbolViewClass
*svc
;
1007 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1009 parent_class
= g_type_class_peek_parent (klass
);
1010 svc
= ANJUTA_SYMBOL_VIEW_CLASS (klass
);
1011 object_class
->finalize
= anjuta_symbol_view_finalize
;
1012 object_class
->dispose
= anjuta_symbol_view_dispose
;
1016 anjuta_symbol_view_get_type (void)
1018 static GType obj_type
= 0;
1022 static const GTypeInfo obj_info
= {
1023 sizeof (AnjutaSymbolViewClass
),
1024 (GBaseInitFunc
) NULL
,
1025 (GBaseFinalizeFunc
) NULL
,
1026 (GClassInitFunc
) anjuta_symbol_view_class_init
,
1027 (GClassFinalizeFunc
) NULL
,
1028 NULL
, /* class_data */
1029 sizeof (AnjutaSymbolViewClass
),
1030 0, /* n_preallocs */
1031 (GInstanceInitFunc
) anjuta_symbol_view_instance_init
,
1032 NULL
/* value_table */
1034 obj_type
= g_type_register_static (GTK_TYPE_TREE_VIEW
,
1042 anjuta_symbol_view_new (void)
1044 return gtk_widget_new (ANJUTA_TYPE_SYMBOL_VIEW
, NULL
);
1048 anjuta_symbol_view_update (AnjutaSymbolView
* sv
, GList
*source_files
)
1050 g_return_if_fail (sv
->priv
->tm_project
!= NULL
);
1052 if (sv
->priv
->tm_project
)
1054 g_hash_table_foreach_remove (sv
->priv
->tm_files
,
1055 on_remove_project_tm_files
,
1058 tm_project_sync (TM_PROJECT (sv
->priv
->tm_project
), source_files
);
1060 tm_project_autoscan (TM_PROJECT (sv
->priv
->tm_project
));
1061 tm_project_save (TM_PROJECT (sv
->priv
->tm_project
));
1062 anjuta_symbol_view_refresh_tree (sv
);
1067 anjuta_symbol_view_save (AnjutaSymbolView
* sv
)
1069 tm_project_save (TM_PROJECT (sv
->priv
->tm_project
));
1073 anjuta_symbol_view_get_node_expansion_states (AnjutaSymbolView
* sv
)
1076 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (sv
),
1077 mapping_function
, &map
);
1082 anjuta_symbol_view_set_node_expansion_states (AnjutaSymbolView
* sv
,
1083 GList
* expansion_states
)
1085 /* Restore expanded nodes */
1086 if (expansion_states
)
1089 GtkTreeModel
*model
;
1091 node
= expansion_states
;
1093 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (sv
));
1096 path
= gtk_tree_path_new_from_string (node
->data
);
1097 gtk_tree_view_expand_row (GTK_TREE_VIEW (sv
), path
,
1099 gtk_tree_path_free (path
);
1100 node
= g_list_next (node
);
1106 anjuta_symbol_view_get_current_symbol (AnjutaSymbolView
* sv
)
1108 AnjutaSymbolInfo
*info
;
1111 info
= sv_current_symbol (sv
);
1114 sym_name
= g_strdup (info
->sym_name
);
1115 anjuta_symbol_info_free (info
);
1120 anjuta_symbol_view_get_current_symbol_def (AnjutaSymbolView
* sv
,
1124 AnjutaSymbolInfo
*info
;
1126 g_return_val_if_fail (filename
!= NULL
, FALSE
);
1127 g_return_val_if_fail (line
!= NULL
, FALSE
);
1129 info
= sv_current_symbol (sv
);
1132 if (!info
->def
.name
)
1134 anjuta_symbol_info_free (info
);
1137 *filename
= g_strdup (info
->def
.name
);
1138 *line
= info
->def
.line
;
1139 anjuta_symbol_info_free (info
);
1144 anjuta_symbol_view_get_current_symbol_decl (AnjutaSymbolView
* sv
,
1148 AnjutaSymbolInfo
*info
;
1150 g_return_val_if_fail (filename
!= NULL
, FALSE
);
1151 g_return_val_if_fail (line
!= NULL
, FALSE
);
1153 info
= sv_current_symbol (sv
);
1156 if (!info
->decl
.name
)
1158 anjuta_symbol_info_free (info
);
1161 *filename
= g_strdup (info
->decl
.name
);
1162 *line
= info
->decl
.line
;
1163 anjuta_symbol_info_free (info
);
1168 anjuta_symbol_view_get_file_symbol_model (AnjutaSymbolView
* sv
)
1170 g_return_val_if_fail (sv
!= NULL
, NULL
);
1171 return sv
->priv
->file_symbol_model
;
1174 static GtkTreeModel
*
1175 create_file_symbols_model (AnjutaSymbolView
* sv
, TMWorkObject
* tm_file
,
1178 GtkTreeStore
*store
;
1181 store
= gtk_tree_store_new (N_COLS
, GDK_TYPE_PIXBUF
,
1182 G_TYPE_STRING
, G_TYPE_INT
);
1185 g_return_val_if_fail (tm_file
!= NULL
, NULL
);
1187 if ((tm_file
->tags_array
) && (tm_file
->tags_array
->len
> 0))
1192 /* let's parse every tag in the array */
1193 for (i
= 0; i
< tm_file
->tags_array
->len
; ++i
)
1197 tag
= TM_TAG (tm_file
->tags_array
->pdata
[i
]);
1200 if (tag
->type
& tag_types
)
1202 SVNodeType sv_type
=
1203 anjuta_symbol_info_get_node_type (NULL
, tag
);
1205 if ((NULL
!= tag
->atts
.entry
.scope
)
1206 && isalpha (tag
->atts
.entry
.scope
[0]))
1210 tag
->atts
.entry
.scope
,
1212 tag
->atts
.entry
.line
);
1215 g_strdup_printf ("%s [%ld]",
1220 * Appends a new row to tree_store. If parent is non-NULL, then it will
1221 * append the new row after the last child of parent, otherwise it will append
1222 * a row to the top level. iter will be changed to point to this new row. The
1223 * row will be empty after this function is called. To fill in values, you need
1224 * to call gtk_tree_store_set() or gtk_tree_store_set_value().
1226 gtk_tree_store_append (store
, &iter
, NULL
);
1228 /* filling the row */
1229 gtk_tree_store_set (store
, &iter
,
1231 anjuta_symbol_info_get_pixbuf (sv_type
),
1233 COL_LINE
, tag
->atts
.entry
.line
, -1);
1238 return GTK_TREE_MODEL (store
);
1242 anjuta_symbol_view_workspace_add_file (AnjutaSymbolView
* sv
,
1243 const gchar
* file_uri
)
1246 TMWorkObject
*tm_file
;
1247 GtkTreeModel
*store
= NULL
;
1249 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
1250 g_return_if_fail (file_uri
!= NULL
);
1252 uri
= gnome_vfs_get_local_path_from_uri (file_uri
);
1253 if (uri
== NULL
) return; /* Not a local path */
1255 store
= g_hash_table_lookup (sv
->priv
->tm_files
, uri
);
1258 DEBUG_PRINT ("Adding Symbol URI: %s", file_uri
);
1260 tm_workspace_find_object (TM_WORK_OBJECT
1261 (sv
->priv
->tm_workspace
),
1265 tm_file
= tm_source_file_new (uri
, TRUE
);
1267 tm_workspace_add_object (tm_file
);
1271 tm_source_file_update (TM_WORK_OBJECT (tm_file
), TRUE
,
1273 if (sv
->priv
->tm_project
&&
1274 TM_WORK_OBJECT (tm_file
)->parent
== sv
->priv
->tm_project
)
1276 DEBUG_PRINT ("Project changed: Flagging refresh required");
1277 sv
->priv
->symbols_need_update
= TRUE
;
1282 store
= create_file_symbols_model (sv
, tm_file
,
1284 g_object_set_data (G_OBJECT (store
), "tm_file",
1286 g_object_set_data (G_OBJECT (store
), "symbol_view",
1288 g_hash_table_insert (sv
->priv
->tm_files
,
1289 g_strdup (uri
), store
);
1293 sv
->priv
->file_symbol_model
= store
;
1297 anjuta_symbol_view_workspace_remove_file (AnjutaSymbolView
* sv
,
1298 const gchar
* file_uri
)
1302 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
1303 g_return_if_fail (file_uri
!= NULL
);
1305 DEBUG_PRINT ("Removing Symbol URI: %s", file_uri
);
1306 uri
= gnome_vfs_get_local_path_from_uri (file_uri
);
1307 if (uri
== NULL
) return; /* Not a local path */
1309 if (g_hash_table_lookup (sv
->priv
->tm_files
, uri
))
1310 g_hash_table_remove (sv
->priv
->tm_files
, uri
);
1317 anjuta_symbol_view_workspace_update_file (AnjutaSymbolView
* sv
,
1318 const gchar
* old_file_uri
,
1319 const gchar
* new_file_uri
)
1321 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
1322 g_return_if_fail (new_file_uri
!= NULL
);
1324 anjuta_symbol_view_workspace_remove_file (sv
, old_file_uri
);
1325 anjuta_symbol_view_workspace_add_file (sv
, new_file_uri
);
1328 TMWorkObject
*tm_file
;
1329 GtkTreeModel
*store
= NULL
;
1331 g_return_if_fail (ANJUTA_IS_SYMBOL_VIEW (sv
));
1332 g_return_if_fail (new_file_uri
!= NULL
);
1333 g_return_if_fail (strncmp (new_file_uri
, "file://", 7) == 0);
1337 /* Rename old uri to new one */
1341 g_return_if_fail (strncmp (old_file_uri
, "file://", 7) == 0);
1343 uri
= &old_file_uri
[7];
1345 g_hash_table_lookup_extended (sv
->priv
->tm_files
, uri
,
1346 (gpointer
*) & orig_key
,
1347 (gpointer
*) & store
);
1350 if (strcmp (old_file_uri
, new_file_uri
) != 0)
1352 DEBUG_PRINT ("Renaming Symbol URI: %s to %s",
1353 old_file_uri
, new_file_uri
);
1354 g_hash_table_steal (sv
->priv
->tm_files
, uri
);
1356 uri
= &new_file_uri
[7];
1357 g_hash_table_insert (sv
->priv
->tm_files
,
1358 g_strdup (uri
), store
);
1360 /* Update tm_file */
1362 g_object_get_data (G_OBJECT (store
),
1364 g_assert (tm_file
!= NULL
);
1365 tm_source_file_update (TM_WORK_OBJECT (tm_file
), TRUE
,
1370 /* Old uri not found. Just add the new one. */
1371 anjuta_symbol_view_workspace_add_file (sv
,
1377 /* No old uri to rename. Just add the new one. */
1378 anjuta_symbol_view_workspace_add_file (sv
, new_file_uri
);
1384 anjuta_symbol_view_workspace_get_line (AnjutaSymbolView
* sv
,
1387 g_return_val_if_fail (iter
!= NULL
, -1);
1388 if (sv
->priv
->file_symbol_model
)
1391 gtk_tree_model_get (GTK_TREE_MODEL
1392 (sv
->priv
->file_symbol_model
), iter
,
1393 COL_LINE
, &line
, -1);
1399 #define IS_DECLARATION(T) ((tm_tag_prototype_t == (T)) || (tm_tag_externvar_t == (T)) \
1400 || (tm_tag_typedef_t == (T)))
1403 anjuta_symbol_view_get_file_symbol (AnjutaSymbolView
* sv
,
1404 const gchar
* symbol
,
1405 gboolean prefer_definition
,
1406 const gchar
** const filename
,
1409 TMWorkObject
*tm_file
;
1413 TMTag
*tag
= NULL
, *local_tag
= NULL
, *global_tag
= NULL
;
1414 TMTag
*local_proto
= NULL
, *global_proto
= NULL
;
1416 g_return_val_if_fail (symbol
!= NULL
, FALSE
);
1418 /* Get the matching definition and declaration in the local file */
1419 if (sv
->priv
->file_symbol_model
!= NULL
)
1422 g_object_get_data (G_OBJECT
1423 (sv
->priv
->file_symbol_model
),
1425 if (tm_file
&& tm_file
->tags_array
1426 && tm_file
->tags_array
->len
> 0)
1428 for (i
= 0; i
< tm_file
->tags_array
->len
; ++i
)
1430 tag
= TM_TAG (tm_file
->tags_array
->pdata
[i
]);
1431 cmp
= strcmp (symbol
, tag
->name
);
1434 if (IS_DECLARATION (tag
->type
))
1444 /* Get the matching definition and declaration in the workspace */
1445 if (!(((prefer_definition
) && (local_tag
)) ||
1446 ((!prefer_definition
) && (local_proto
))))
1448 tags
= TM_WORK_OBJECT (tm_get_workspace ())->tags_array
;
1449 if (tags
&& (tags
->len
> 0))
1451 for (i
= 0; i
< tags
->len
; ++i
)
1453 tag
= TM_TAG (tags
->pdata
[i
]);
1454 if (tag
->atts
.entry
.file
)
1456 cmp
= strcmp (symbol
, tag
->name
);
1471 if (prefer_definition
)
1475 else if (global_tag
)
1477 else if (local_proto
)
1486 else if (global_proto
)
1497 g_strdup (tag
->atts
.entry
.file
->work_object
.
1499 *line
= tag
->atts
.entry
.line
;
1506 * for a given expression "myvar->getX().toFloat"
1507 * the function should just return "myvar"
1508 * and move the **expr pointer after the ident
1509 * returns NULL, if no identifier is found, and then the value of expr is undefined
1512 sv_scan_for_ident(const gchar
**expr
)
1514 static gchar ident
[1024];
1515 /* number of identified characters in the ident string */
1516 int valid_chars
= 0;
1519 while ((c
= **expr
) != '\0')
1521 if(valid_chars
== 0 && isspace(c
))
1526 // XXX: Namespace support
1527 else if(isalpha(c
) || c
== '_') // ???: || c == ':')
1529 ident
[valid_chars
] = c
;
1530 if (++valid_chars
== 1023)
1536 /* a digit may be part of an ident but not from the start */
1537 else if (isdigit(c
))
1541 ident
[valid_chars
] = c
;
1542 if (++valid_chars
== 1023)
1560 ident
[valid_chars
] = '\0';
1569 gchar
* sv_extract_type_qualifier_from_expr (const gchar
*string
, const gchar
*expr
)
1571 /* check with a regular expression for the type */
1574 regmatch_t pm
[8]; // 7 sub expression -> 8 matches
1575 memset (&pm
, -1, sizeof(pm
));
1577 * this regexp catches things like:
1578 * a) std::vector<char*> exp1[124] [12], *exp2, expr;
1579 * b) QClass* expr1, expr2, expr;
1580 * c) int a,b; char r[12] = "test, argument", q[2] = { 't', 'e' }, expr;
1582 * it CAN be fooled, if you really want it, but it should
1583 * work for 99% of all situations.
1587 * in 2 lines does not work, because //-comments would often bring wrong results
1590 #define STRING "\\\".*\\\""
1591 #define BRACKETEXPR "\\{.*\\}"
1592 #define IDENT "[a-zA-Z_][a-zA-Z0-9_]*"
1593 #define WS "[ \t\n]*"
1594 #define PTR "[\\*&]?\\*?"
1595 #define INITIALIZER "=(" WS IDENT WS ")|=(" WS STRING WS ")|=(" WS BRACKETEXPR WS ")" WS
1596 #define ARRAY WS "\\[" WS "[0-9]*" WS "\\]" WS
1599 gchar pattern
[512] =
1600 "(" IDENT
"\\>)" // the 'std' in example a)
1601 "(::" IDENT
")*" // ::vector
1602 "(" WS
"<[^>;]*>)?" // <char *>
1603 "(" WS PTR WS IDENT WS
"(" ARRAY
")*" "(" INITIALIZER
")?," WS
")*" // other variables for the same ident (string i,j,k;)
1604 "[ \t\\*&]*"; // check again for pointer/reference type
1606 /* must add a 'termination' symbol to the regexp, otherwise
1607 * 'exp' would match 'expr' */
1609 snprintf (regexp
, 512, "%s\\<%s\\>", pattern
, expr
);
1611 /* compile regular expression */
1612 gint error
= regcomp (&re
, regexp
, REG_EXTENDED
) ;
1614 g_warning ("regcomp failed");
1616 /* this call to regexec finds the first match on the line */
1617 error
= regexec (&re
, string
, 8, &pm
[0], 0) ;
1619 /* while matches found. We'll find the *last* occurrence of the expr. This will
1620 * guarantee us that it is the right one we want to use. I.e.
1625 * int func_1 (void) {
1630 * for (int i=0; i < 20; i++) {
1638 * Here the klass-> will be matched as YourClass [right], not the MyClass' ones [wrong]
1643 /* subString found between pm.rm_so and pm.rm_eo */
1644 /* only include the ::vector part in the indentifier, if the second subpattern matches at all */
1645 gint len
= (pm
[2].rm_so
!= -1 ? pm
[2].rm_eo
: pm
[1].rm_eo
) - pm
[1].rm_so
;
1648 res
= (gchar
*) malloc (len
+ 1);
1654 strncpy (res
, string
+ pm
[1].rm_so
, len
);
1657 string
+= pm
[0].rm_eo
;
1659 /* This call to regexec finds the next match */
1660 error
= regexec (&re
, string
, 8, &pm
[0], 0) ;
1667 /* if the proposed type is a keyword, we did something wrong, return NULL instead */
1670 while (keywords
[i
] != NULL
) {
1671 if (strcmp(res
, keywords
[i
]) == 0) {
1691 * for ident=getRect and klass="QWidget" return a tag of type QRect.
1695 sv_get_type_of_token (const gchar
* ident
, const gchar
* klass
, const TMTag
* local_scope_of_ident
,
1696 const TMTag
* local_declaration_type
)
1698 const GPtrArray
*tags_array
;
1699 TMTag
*klass_tag
= NULL
;
1702 /* if we have a variable and already found a local definition, just return it */
1703 if (local_declaration_type
!= NULL
&& strlen(local_declaration_type
->name
)) {
1704 return (TMTag
*)local_declaration_type
;
1707 /* if the identifier is this-> return the current class */
1708 if (!strcmp (ident
, "this")) {
1709 const GPtrArray
*tags_array
;
1710 TMTag
* scope_tag
= NULL
;
1713 scope_tag
= (TMTag
*)local_scope_of_ident
;
1715 if (scope_tag
== NULL
|| scope_tag
->atts
.entry
.scope
== NULL
)
1718 tags_array
= tm_workspace_find (scope_tag
->atts
.entry
.scope
,
1719 tm_tag_struct_t
| tm_tag_typedef_t
|tm_tag_union_t
| tm_tag_class_t
,
1722 if (tags_array
!= NULL
) {
1723 for (i
=0; i
< tags_array
->len
; i
++) {
1726 cur_tag
= (TMTag
*)g_ptr_array_index (tags_array
, i
);
1727 if ( strcmp (cur_tag
->name
, scope_tag
->atts
.entry
.scope
) == 0) {
1728 scope_tag
= cur_tag
;
1735 DEBUG_PRINT ("scope_tag [class] %s", scope_tag
->name
);
1739 /* ok, search the klass for the symbols in workspace */
1740 if (klass
== NULL
|| (strcmp("", klass
) == 0))
1743 tags_array
= tm_workspace_find_scope_members (NULL
, klass
, TRUE
, TRUE
);
1745 if (tags_array
!= NULL
)
1747 for (i
=0; i
< tags_array
->len
; i
++) {
1750 tmp_tag
= (TMTag
*)g_ptr_array_index (tags_array
, i
);
1752 /* store the klass_tag. It will be useful later */
1753 if (strcmp (tmp_tag
->name
, klass
) == 0) {
1754 klass_tag
= tmp_tag
;
1757 if (strcmp (tmp_tag
->name
, ident
) == 0 ) {
1763 /* checking for inherited members. We'll reach this point only if the right tag
1764 * hasn't been detected yet.
1766 GPtrArray
*inherited_tags_array
;
1768 inherited_tags_array
= anjuta_symbol_view_get_completable_members (klass_tag
, TRUE
);
1770 if (inherited_tags_array
!= NULL
)
1772 for (i
=0; i
< inherited_tags_array
->len
; i
++) {
1775 tmp_tag
= (TMTag
*)g_ptr_array_index (inherited_tags_array
, i
);
1776 DEBUG_PRINT ("parsing inherited member as %s ", tmp_tag
->name
);
1777 if ( (strcmp (tmp_tag
->name
, ident
) == 0) ) {
1778 const GPtrArray
*inherit_array
;
1780 TMTagAttrType attrs
[] = {
1784 inherit_array
= tm_workspace_find (tmp_tag
->atts
.entry
.type_ref
[1],
1785 tm_tag_class_t
, attrs
, FALSE
, TRUE
);
1787 if (inherit_array
== NULL
)
1791 for (j
=0; j
< inherit_array
->len
; j
++) {
1792 TMTag
*cur_tag
= (TMTag
*)g_ptr_array_index (inherit_array
, j
);
1794 if (strcmp(tmp_tag
->atts
.entry
.type_ref
[1], cur_tag
->name
) == 0 )
1801 g_ptr_array_free (inherited_tags_array
, TRUE
);
1804 DEBUG_PRINT ("returning NULL from get_type_of_token. ident %s", ident
);
1809 /*----------------------------------------------------------------------------
1810 * Lists the completable members given a klass_tag. I.e.: it returns all current
1811 * class members [private/protected/public] [or in case of a struct all its members]
1812 * and then it goes up for parents retrieving public/protected members.
1816 anjuta_symbol_view_get_completable_members (TMTag
* klass_tag
, gboolean include_parents
) {
1819 if (klass_tag
== NULL
)
1823 symbol_name
= klass_tag
->atts
.entry
.type_ref
[1];
1824 if (symbol_name
== NULL
)
1825 symbol_name
= klass_tag
->name
;
1827 DEBUG_PRINT ("get_completable_members --> scope of tag name %s is %s", klass_tag
->name
, klass_tag
->atts
.entry
.scope
);
1828 // FIXME: comment this
1829 tm_tag_print (klass_tag
, stdout
);
1831 switch (klass_tag
->type
) {
1832 case tm_tag_struct_t
:
1833 case tm_tag_typedef_t
:
1834 case tm_tag_union_t
:
1836 const GPtrArray
* tags_array
;
1837 GPtrArray
*completable_array
;
1839 /* we should list all members of our struct/typedef/union...*/
1840 tags_array
= tm_workspace_find_scope_members (NULL
, symbol_name
,
1842 if (tags_array
== NULL
) {
1843 DEBUG_PRINT ("returning NULL from struct-completable");
1847 DEBUG_PRINT ("returning NULL from struct-completable. Tags array len %d", tags_array
->len
);
1849 completable_array
= g_ptr_array_new ();
1850 for (i
=0; i
< tags_array
->len
; i
++)
1851 g_ptr_array_add (completable_array
, g_ptr_array_index (tags_array
, i
));
1853 return completable_array
;
1855 case tm_tag_class_t
:
1856 case tm_tag_member_t
:
1857 case tm_tag_method_t
:
1858 case tm_tag_prototype_t
:
1861 /* list all the public/protected members of super classes, if it's a class
1862 obviously and if there are some super classes */
1864 GPtrArray
*completable_array
;
1865 const GPtrArray
*tags_array
;
1869 DEBUG_PRINT ("completable: klass_tag is");
1870 tm_tag_print (klass_tag
, stdout
);
1872 // FIXME: this part needs an improvement!
1873 // It needs a search for symbols under a particular namespace. Infact right now
1874 // it cannot detect if a MyPrettyClass is defined under namespace1:: or under
1875 // namespace2::. It just looks for the symbols of klass/struct/.. name
1876 if (klass_tag
->atts
.entry
.scope
!= NULL
&&
1877 (tmp_str
=strstr(klass_tag
->atts
.entry
.scope
, "")) != NULL
) {
1878 DEBUG_PRINT ("scope with ::. FIXME");
1881 tags_array
= tm_workspace_find_scope_members (NULL
, symbol_name
,
1883 if (tags_array
== NULL
) {
1884 DEBUG_PRINT ("returning NULL from class&c-completable with symbol name %s [scope of klass_tag: %s]",
1885 symbol_name
, klass_tag
->atts
.entry
.scope
);
1889 completable_array
= g_ptr_array_new ();
1890 /* we *must* duplicate the contents of the tags_array coz it will be
1891 * overwritten the next call to tm_workspace_find_scope_members ().
1892 * Just the tag-pointers will be saved, not the entire struct behind them.
1894 for (i
=0; i
< tags_array
->len
; i
++)
1895 g_ptr_array_add (completable_array
, g_ptr_array_index (tags_array
, i
));
1897 /* should we go for parents [include_parents]? or is it a struct [inheritance == NULL]? */
1898 if (!include_parents
|| klass_tag
->atts
.entry
.inheritance
== NULL
)
1899 return completable_array
;
1901 DEBUG_PRINT ("parents from klass_tag [name] %s: %s", symbol_name
, klass_tag
->atts
.entry
.inheritance
);
1903 const GPtrArray
*parents_array
= tm_workspace_get_parents (symbol_name
);
1904 if (parents_array
== NULL
) {
1905 DEBUG_PRINT ("returning tags_array coz parents_array is null");
1906 return completable_array
;
1909 for (i
=0; i
< parents_array
->len
; i
++) {
1911 const GPtrArray
*tmp_parents_array
;
1912 TMTag
* cur_parent_tag
= g_ptr_array_index (parents_array
, i
);
1914 /* we don't need the members for the symbols_name's class. We
1915 already have them */
1916 if ( (strcmp(cur_parent_tag
->name
, symbol_name
) == 0) )
1919 if ( (tmp_parents_array
= tm_workspace_find_scope_members (NULL
,
1920 cur_parent_tag
->name
, TRUE
, TRUE
)) == NULL
) {
1924 gint length
= tmp_parents_array
->len
;
1925 for (j
= 0; j
< length
; j
++) {
1927 test_tag
= (TMTag
*)g_ptr_array_index (tmp_parents_array
, j
);
1929 if (test_tag
->atts
.entry
.access
== TAG_ACCESS_PUBLIC
||
1930 test_tag
->atts
.entry
.access
== TAG_ACCESS_PROTECTED
||
1931 test_tag
->atts
.entry
.access
== TAG_ACCESS_FRIEND
) {
1933 g_ptr_array_add (completable_array
, test_tag
);
1938 return completable_array
;
1941 case tm_tag_namespace_t
:
1943 const GPtrArray
*namespace_classes
;
1944 GPtrArray
*completable_array
= NULL
;
1947 DEBUG_PRINT ("we got a namespace!, %s", klass_tag
->name
);
1949 namespace_classes
= tm_workspace_find_namespace_members (NULL
, klass_tag
->name
, TRUE
);
1951 /* we *must* duplicate the contents of the tags_array coz it will be
1952 * overwritten the next call to tm_workspace_find_scope_members ().
1953 * Just the tag-pointers will be saved, not the entire struct behind them.
1955 completable_array
= g_ptr_array_new ();
1956 for (i
=0; i
< namespace_classes
->len
; i
++) {
1959 cur_tag
= (TMTag
*)g_ptr_array_index (namespace_classes
, i
);
1961 // tm_tag_print (cur_tag, stdout);
1962 g_ptr_array_add (completable_array
, cur_tag
);
1965 return completable_array
;
1973 /* local_declaration_type_str must be NOT NULL.
1977 sv_get_local_declaration_type (const gchar
*local_declaration_type_str
) {
1979 const GPtrArray
* loc_decl_tags_array
;
1980 TMTag
* local_declaration_type
= NULL
;
1982 g_return_val_if_fail (local_declaration_type_str
!= NULL
, NULL
);
1984 /* local_declaration_type_str != NULL */
1987 DEBUG_PRINT ("local_declaration_type_str is %s", local_declaration_type_str
);
1988 DEBUG_PRINT ("checking for :: [namespace scoping] inside it...");
1990 if ( (occurrence
=strstr(local_declaration_type_str
, "::")) == NULL
) {
1992 DEBUG_PRINT ("No, it hasn't..");
1994 loc_decl_tags_array
= tm_workspace_find (local_declaration_type_str
,
1995 tm_tag_struct_t
| tm_tag_typedef_t
|tm_tag_union_t
| tm_tag_class_t
,
1998 /* We should have a look at the tags_array for the correct tag. */
1999 if (loc_decl_tags_array
!= NULL
) {
2000 for (i
=0; i
< loc_decl_tags_array
->len
; i
++) {
2003 cur_tag
= (TMTag
*)g_ptr_array_index (loc_decl_tags_array
, i
);
2004 if ( strcmp(cur_tag
->name
, local_declaration_type_str
) == 0) {
2005 local_declaration_type
= cur_tag
;
2009 return local_declaration_type
;
2014 else { /* namespace string parsing */
2015 /* This is the case of
2018 * namespace1::namespace2::MyClass *myclass;
2024 * we should parse the "local_declaration_type_str" and retrieve the
2025 * TMTag of MyClass under namespace1::namespace2.
2029 gchar
**splitted_str
;
2030 const GPtrArray
*tmp_tags_array
;
2033 DEBUG_PRINT ("Yes, it has!");
2035 splitted_str
= g_strsplit (local_declaration_type_str
, "::", -1);
2037 DEBUG_PRINT ("Check for splitted_str[0] existence into workspace...");
2038 tmp_tags_array
= tm_workspace_find (splitted_str
[0],
2039 tm_tag_struct_t
| tm_tag_union_t
|
2040 tm_tag_typedef_t
| tm_tag_class_t
|
2041 tm_tag_macro_t
| tm_tag_macro_with_arg_t
|
2042 tm_tag_namespace_t
, NULL
, FALSE
, TRUE
);
2045 if (tmp_tags_array
== NULL
) {
2046 DEBUG_PRINT ("tmp_tags_array is NULL");
2047 g_strfreev (splitted_str
);
2052 /* ok, we can start from index 1 to check the correctness of expression */
2053 for (indx
=1; splitted_str
[indx
] != NULL
; indx
++) {
2055 gboolean found_end_node
;
2056 TMTag
*tmp_tag
= NULL
;
2058 DEBUG_PRINT ("===string %d is %s====", indx
, splitted_str
[indx
]);
2060 /* check the availability of namespace2 under the members of namespace1
2063 tmp_tags_array
= tm_workspace_find_namespace_members (NULL
, splitted_str
[indx
-1], TRUE
);
2065 if (tmp_tags_array
== NULL
) {
2066 local_declaration_type
= NULL
;
2071 for (i
=0; i
< tmp_tags_array
->len
; i
++) {
2074 cur_tag
= (TMTag
*)g_ptr_array_index (tmp_tags_array
, i
);
2075 DEBUG_PRINT ("cur_tag scanned to check scoping %d out of %d --> %s",
2076 i
, tmp_tags_array
->len
, cur_tag
->name
);
2077 if ( strcmp(cur_tag
->name
, splitted_str
[indx
]) == 0) {
2078 /* ok we found our tag */
2084 found_end_node
= FALSE
;
2085 if (tmp_tag
== NULL
)
2088 switch (tmp_tag
->type
) {
2089 case tm_tag_class_t
:
2091 case tm_tag_struct_t
:
2092 case tm_tag_typedef_t
:
2093 case tm_tag_union_t
:
2094 /* are we at the end of the splitted_str[] parsing? Or
2095 * have we just found a class/struct/etc but there's something more
2096 * left in the stack?
2098 if (splitted_str
[indx
+1] == NULL
) {
2099 found_end_node
= TRUE
;
2106 case tm_tag_namespace_t
:
2111 if (found_end_node
== TRUE
) {
2112 /* set the local declaration type*/
2113 local_declaration_type
= tmp_tag
;
2119 g_strfreev (splitted_str
);
2120 return local_declaration_type
;
2125 return local_declaration_type
;
2129 TMTag
* anjuta_symbol_view_get_type_of_expression(AnjutaSymbolView
* sv
,
2130 const gchar
* expr
, int expr_len
, const TMTag
*func_scope_tag
, gint
*access_method
)
2132 gchar
*ident
= NULL
;
2133 *access_method
= COMPLETION_ACCESS_NONE
;
2135 /* very basic stack implementation to keep track of tokens */
2136 const int max_items
= 30;
2137 const gchar
* stack
[max_items
];
2140 memset (stack
, 0, sizeof(stack
));
2142 /* skip nested brackets */
2143 int brackets
= 0, square_brackets
= 0;
2145 /* if the current position is within an identifier */
2146 gboolean in_ident
= FALSE
;
2148 /* if we extract the next string which looks like an identifier - only after: . -> and ( */
2149 gboolean extract_ident
= FALSE
;
2151 if (strlen(expr
) < 1)
2157 g_return_val_if_fail (func_scope_tag
!= NULL
, NULL
);
2159 /* check the access method */
2160 if (*access_method
== COMPLETION_ACCESS_NONE
) {
2161 switch (expr
[expr_len
-1]) {
2163 *access_method
= COMPLETION_ACCESS_DIRECT
;
2164 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_DIRECT;");
2167 if (expr
[expr_len
-2] == '-') {
2168 *access_method
= COMPLETION_ACCESS_POINTER
;
2169 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_POINTER;");
2173 if (expr
[expr_len
-2] == ':') {
2174 *access_method
= COMPLETION_ACCESS_STATIC
;
2175 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_STATIC;");
2179 *access_method
= COMPLETION_ACCESS_NONE
;
2183 const gchar
*start
= expr
+ expr_len
;
2184 while (--start
>= expr
)
2187 if (brackets
> 0 || square_brackets
> 0)
2191 else if (*start
== ')')
2193 else if (*start
== '[')
2195 else if (*start
== ']')
2200 if (isdigit(*start
))
2202 else if (isalpha(*start
) || *start
== '_')
2210 /* skip whitespace */
2221 /* continue searching to the left, if we
2222 * have a . or -> accessor */
2224 if (in_ident
&& extract_ident
)
2226 const gchar
*ident
= start
+1;
2227 if (num_stack
< max_items
) {
2228 stack
[num_stack
++] = ident
;
2234 extract_ident
= TRUE
;
2236 case '>': /* pointer access */
2237 if ((*start
== '>' && (start
-1 >= expr
&& (start
-1)[0] == '-')))
2239 if (in_ident
&& extract_ident
)
2241 const gchar
*ident
= start
+1;
2242 if (num_stack
< max_items
) {
2243 stack
[num_stack
++] = ident
;
2249 extract_ident
= TRUE
;
2258 case ':': /* static access */
2259 if ((*start
== ':' && (start
-1 >= expr
&& (start
-1)[0] == ':')))
2261 if (in_ident
&& extract_ident
)
2263 const gchar
*ident
= start
+1;
2264 if (num_stack
< max_items
) {
2265 stack
[num_stack
++] = ident
;
2271 extract_ident
= TRUE
;
2280 case '(': /* start of a function */
2288 extract_ident
= TRUE
;
2294 if (in_ident
) /* probably a cast - (const char*)str */
2319 /* ident is the leftmost token, stack[*] the ones to the right
2320 * Example: str.left(2,5).toUpper()
2322 * ident stack[1] stack[0]
2325 ident
= sv_scan_for_ident (&start
);
2329 DEBUG_PRINT("ident found: %s", ident
);
2331 TMTag
*tag_type
= NULL
, *old_type
= NULL
;
2333 /* for static access, parsing is done, just return the identifier.
2334 * If this isn't the case we should process something like
2335 * my_class_instance->getValue()->...->lastFunc()->
2336 * and try to get the correct type of lastFunc token, so that we can have
2337 * a completable list.
2339 if (*access_method
!= COMPLETION_ACCESS_STATIC
) {
2340 gchar
*local_declaration_type_str
;
2341 const TMTag
* local_scope_of_ident
;
2342 TMTag
* local_declaration_type
= NULL
;
2344 local_scope_of_ident
= func_scope_tag
;
2345 /* in a context like:
2354 * calling the following function should return the strings "MyClass".
2355 * FIXME: there would need a better regex which returns also the pointer
2356 * order of myclass, in this case should be "MyClass *", or better 1.
2359 local_declaration_type_str
= sv_extract_type_qualifier_from_expr (expr
, ident
);
2361 /* check between the scope and parents members if "ident" is present */
2362 if (local_declaration_type_str
== NULL
) {
2364 DEBUG_PRINT ("local_declaration_type_string is NULL, checking between its members "
2367 local_declaration_type
= sv_get_type_of_token (ident
, local_scope_of_ident
->atts
.entry
.scope
,
2368 local_scope_of_ident
, NULL
);
2369 if (local_declaration_type
) {
2370 DEBUG_PRINT ("found local_declaration_type->name %s",local_declaration_type
->name
);
2374 local_declaration_type
= sv_get_local_declaration_type (local_declaration_type_str
);
2378 if (local_declaration_type
== NULL
) {
2379 DEBUG_PRINT ("warning: local_declaration_type is NULL");
2382 DEBUG_PRINT ("local_declaration_type detected:");
2383 tm_tag_print (local_declaration_type
, stdout
);
2386 if (local_scope_of_ident
!= NULL
&& local_declaration_type
!= NULL
) {
2387 DEBUG_PRINT ("found local_scope_of_ident->name %s and local_declaration_type->name %s",
2388 local_scope_of_ident
->name
, local_declaration_type
->name
);
2392 /* if we have the start of a function/method, don't return the type
2393 * of this function, but class, which it is member of */
2394 tag_type
= sv_get_type_of_token (ident
, NULL
, local_scope_of_ident
, local_declaration_type
);
2397 DEBUG_PRINT ("type of token: %s : %s, var_type %s\n", ident
,
2398 tag_type
->name
, tag_type
->atts
.entry
.type_ref
[1]);
2400 DEBUG_PRINT ("WARNING: tag_type is null. cannot determine ident");
2403 while (tag_type
&& tag_type
->name
&& num_stack
> 0) {
2404 ident
= sv_scan_for_ident (&stack
[--num_stack
]);
2405 DEBUG_PRINT ("!!scanning for ident %s\n", ident
);
2407 old_type
= tag_type
;
2413 * We already parsed the "str" token. Now it's left() turn.
2414 * If we don't have the local_declaration_type nor the local_scope_of_ident let's find
2415 * the type of the member. Obviously we should also check the parent
2416 * classes if we don't find it in the old_type->name class.
2419 if (old_type
->atts
.entry
.type_ref
[1] == NULL
)
2420 tag_type
= sv_get_type_of_token (ident
, old_type
->name
,
2421 local_scope_of_ident
, NULL
);
2423 tag_type
= sv_get_type_of_token (ident
, old_type
->atts
.entry
.type_ref
[1],
2424 local_scope_of_ident
, NULL
);
2426 if (tag_type
!= NULL
) {
2427 DEBUG_PRINT ("tag_type of token: %s : [pointer order] %d\n",
2428 ident
, tag_type
->atts
.entry
.pointerOrder
);
2429 DEBUG_PRINT ("we have setted a completion of %s",
2430 *access_method
== COMPLETION_ACCESS_DIRECT
? "DIRECT ACCESS" : "POINTER ACCESS");
2431 tm_tag_print (tag_type
, stdout
);
2433 if (tag_type
->atts
.entry
.pointerOrder
>= 1) {
2434 /* we shouldn't permit a direct access on tags which are on
2435 * pointerOrder >=1. This means we can't complete with "."
2436 * on MyClass* variables */
2437 if (*access_method
== COMPLETION_ACCESS_DIRECT
) {
2438 DEBUG_PRINT ("completion not permitted. Pointer Order is wrong");
2442 else if (tag_type
->atts
.entry
.pointerOrder
== 0) {
2443 if (*access_method
== COMPLETION_ACCESS_POINTER
) {
2444 DEBUG_PRINT ("completion not permitted. Pointer Order is wrong");
2451 else { /* static member */
2452 /* just return the ident's tag */
2453 const GPtrArray
* tags_array
= NULL
;
2456 DEBUG_PRINT ("Gonna parsing static member section: ident %s", ident
);
2458 if (ident
!= NULL
) {
2459 tags_array
= tm_workspace_find (ident
,
2460 tm_tag_struct_t
| tm_tag_union_t
|
2461 tm_tag_typedef_t
| tm_tag_class_t
|
2462 tm_tag_macro_t
| tm_tag_macro_with_arg_t
|
2463 tm_tag_namespace_t
, NULL
, FALSE
, TRUE
);
2466 if (tags_array
== NULL
) {
2467 DEBUG_PRINT ("tags_array is NULL");
2474 /* check if stack has members or not. For an expression like
2475 * Gnome::Glade::Xml:: we have a stack of
2477 * stack[1] = Glade::Xml::
2480 //*/ DEBUG REMOVE ME
2481 for (i
=0; i
< num_stack
; i
++ ) {
2482 DEBUG_PRINT ("we have a stack[%d] = %s", i
, stack
[i
]);
2487 // probably an useless loop
2488 for (i
=0; i
< tags_array
->len
; i
++) {
2491 cur_tag
= (TMTag
*)g_ptr_array_index (tags_array
, i
);
2492 DEBUG_PRINT ("cur_tag scanned %d out of %d --> %s", i
, tags_array
->len
, cur_tag
->name
);
2493 if ( strcmp(cur_tag
->name
, ident
) == 0) {
2494 /* ok we found our tag */
2501 /* recursive expression parsing to check its correctness */
2502 if (tag_type
!= NULL
&& num_stack
> 0) {
2505 for (indx
=0; indx
< num_stack
; indx
++) {
2506 switch (tag_type
->type
) {
2507 case tm_tag_namespace_t
:
2509 const GPtrArray
* tags_array
= NULL
;
2511 /* get next ident in stack */
2512 gchar
* ident_to_check
;
2515 new_idents
= g_strsplit (stack
[num_stack
- indx
-1], ":", 0);
2517 ident_to_check
= new_idents
[0];
2518 if (ident_to_check
== NULL
) {
2519 g_strfreev (new_idents
);
2523 /* is our ident_to_check included into tag_type?
2524 * Or better, in our example, is Glade included into Gnome:: ?
2526 tags_array
= tm_workspace_find_namespace_members (NULL
,
2529 if (tags_array
== NULL
) {
2530 g_strfreev (new_idents
);
2535 for (i
=0; i
< tags_array
->len
; i
++) {
2538 cur_tag
= (TMTag
*)g_ptr_array_index (tags_array
, i
);
2539 DEBUG_PRINT ("cur_tag scanned to check correctness %d out of %d --> %s",
2540 i
, tags_array
->len
, cur_tag
->name
);
2541 if ( strcmp(cur_tag
->name
, ident_to_check
) == 0) {
2542 /* ok we found our tag */
2548 g_strfreev (new_idents
);