2008-04-12 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / plugins / symbol-browser / an_symbol_view.c
blobdc72d05e0ce481a2e7981cc7fdbdb9c8962a7ff8
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * an_symbol_view.c
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
7 * for autocompletion
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
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <string.h>
29 #include <ctype.h>
30 #include <regex.h>
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;
51 GHashTable *tm_files;
52 GtkTreeModel *file_symbol_model;
53 TMSymbol *symbols;
54 gboolean symbols_need_update;
56 /* Tooltips */
57 GdkRectangle tooltip_rect;
58 GtkWidget *tooltip_window;
59 gulong tooltip_timeout;
60 PangoLayout *tooltip_layout;
63 enum
65 PIXBUF_COLUMN,
66 NAME_COLUMN,
67 SVFILE_ENTRY_COLUMN,
68 SYMBOL_NODE,
69 COLUMNS_NB
73 static gchar *keywords[] = {
74 "asm",
75 "auto",
76 "bool",
77 "break",
78 "case",
79 "catch",
80 "class",
81 "const",
82 "const_cast",
83 "continue",
84 "default",
85 "delete",
86 "do",
87 "dynamic_cast",
88 "else",
89 "enum",
90 "explicit",
91 "export",
92 "extern",
93 "false",
94 "for",
95 "friend",
96 "goto",
97 "if",
98 "inline",
99 "mutable",
100 "namespace",
101 "new",
102 "operator",
103 "private",
104 "protected",
105 "public",
106 "register",
107 "reinterpret_cast",
108 "return",
109 "signed",
110 "sizeof",
111 "static",
112 "static_cast",
113 "struct",
114 "switch",
115 "template",
116 "this",
117 "throw",
118 "true",
119 "try",
120 "typedef",
121 "typeid",
122 "typename",
123 "union",
124 "unsigned",
125 "using",
126 "virtual",
127 "volatile",
128 "while",
129 NULL
133 static GtkTreeViewClass *parent_class;
135 /* Tooltip operations -- taken from gtodo/message_view */
137 static gchar *
138 tooltip_get_display_text (AnjutaSymbolView * sv)
140 GtkTreePath *path;
141 GtkTreeIter iter;
142 GtkTreeModel *model;
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))
150 gchar *text;
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);
156 return text;
158 return NULL;
161 static void
162 tooltip_paint (GtkWidget *widget, GdkEventExpose *event, AnjutaSymbolView * sv)
164 GtkStyle *style;
165 gchar *tooltiptext;
167 tooltiptext = tooltip_get_display_text (sv);
169 if (!tooltiptext)
170 tooltiptext = g_strdup (_("No message details"));
172 pango_layout_set_markup (sv->priv->tooltip_layout,
173 tooltiptext,
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);
191 g_free(tooltiptext);
192 return;
195 static gboolean
196 tooltip_timeout (AnjutaSymbolView * sv)
198 gint scr_w,scr_h, w, h, x, y;
199 gchar *tooltiptext;
201 tooltiptext = tooltip_get_display_text (sv);
203 if (!tooltiptext)
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;
231 x -= ((w >> 1) + 4);
233 if ((x + w) > scr_w)
234 x -= (x + w) - scr_w;
235 else if (x < 0)
236 x = 0;
238 if ((y + h + 4) > scr_h)
239 y = y - h;
240 else
241 y = y + 6;
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);
250 return FALSE;
253 static gboolean
254 tooltip_motion_cb (GtkWidget *tv, GdkEventMotion *event, AnjutaSymbolView * sv)
256 GtkTreePath *path;
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;
268 return FALSE;
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))
274 return FALSE;
276 if(event->y == 0)
278 g_source_remove (sv->priv->tooltip_timeout);
279 sv->priv->tooltip_timeout = 0;
280 return FALSE;
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,
293 NULL, NULL, NULL))
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)
301 gchar *tooltiptext;
303 tooltiptext = tooltip_get_display_text (sv);
304 if (tooltiptext == NULL)
305 return FALSE;
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);
314 return FALSE;
317 static void
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,
332 TMSymbol *sym,
333 GtkTreeStore *store,
334 GtkTreeIter *iter);
335 static void anjuta_symbol_view_refresh_tree (AnjutaSymbolView *sv);
337 static void
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));
347 if (tm_file)
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));
359 static gboolean
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);
371 if (tm_file &&
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;
377 return TRUE;
379 return FALSE;
382 #if 0
383 static gboolean
384 on_treeview_row_search (GtkTreeModel * model, gint column,
385 const gchar * key, GtkTreeIter * iter, gpointer data)
387 DEBUG_PRINT ("Search key == '%s'", key);
388 return FALSE;
390 #endif
392 static AnjutaSymbolInfo *
393 sv_current_symbol (AnjutaSymbolView * sv)
395 GtkTreeModel *model;
396 GtkTreeSelection *selection;
397 GtkTreeIter iter;
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))
406 return NULL;
408 gtk_tree_model_get (model, &iter, SVFILE_ENTRY_COLUMN, &info, -1);
409 return info;
412 static gboolean
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);
421 return FALSE;
424 static void
425 on_symbol_view_row_expanded (GtkTreeView * view,
426 GtkTreeIter * iter, GtkTreePath *iter_path,
427 AnjutaSymbolView *sv)
429 // GdkPixbuf *pix;
430 // gchar *full_path;
431 GtkTreeIter child;
432 GList *row_refs, *row_ref_node;
433 GtkTreeRowReference *row_ref;
434 GtkTreePath *path;
435 TMSymbol *sym;
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);
448 return;
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 */
457 if (sym)
459 g_object_unref (sym);
460 return;
463 else
465 /* Has no children */
466 return;
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
474 * Get row references
476 row_refs = NULL;
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);
489 if (sym)
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;
497 while (row_ref_node)
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);
508 if (row_refs)
510 g_list_free (row_refs);
512 /* anjuta_status_busy_pop (status); */
515 static void
516 on_symbol_view_row_collapsed (GtkTreeView * view,
517 GtkTreeIter * iter, GtkTreePath * path)
521 static void
522 sv_create (AnjutaSymbolView * sv)
524 GtkTreeStore *store;
525 GtkTreeViewColumn *column;
526 GtkCellRenderer *renderer;
527 GtkTreeSelection *selection;
529 /* Tree and his model */
530 store = gtk_tree_store_new (COLUMNS_NB,
531 GDK_TYPE_PIXBUF,
532 G_TYPE_STRING,
533 ANJUTA_TYPE_SYMBOL_INFO,
534 G_TYPE_POINTER);
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,
548 NULL, NULL);
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));
565 /* Columns */
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",
574 PIXBUF_COLUMN);
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",
579 NAME_COLUMN);
581 gtk_tree_view_append_column (GTK_TREE_VIEW (sv), column);
582 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (sv), column);
585 void
586 anjuta_symbol_view_clear (AnjutaSymbolView * sv)
588 GtkTreeModel *model;
589 AnjutaSymbolViewPriv* priv;
591 priv = sv->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));
600 if (model)
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,
613 sv);
614 if (sv->priv->tm_project)
616 tm_project_free (sv->priv->tm_project);
617 sv->priv->tm_project = NULL;
621 static void
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);
636 break;
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;
641 break;
643 default:
644 break;
646 if (append_var_type)
648 char *vt = sym->tag->atts.entry.type_ref[1];
649 if (vt)
651 if((vt = strstr(vt, "_fake_")))
653 char backup = *vt;
654 int i;
655 *vt = '\0';
657 g_string_append_printf (s, " [%s",
658 sym->tag->atts.entry.type_ref[1]);
659 i = sym->tag->atts.entry.pointerOrder;
660 for (; i > 0; i--)
661 g_string_append_printf (s, "*");
662 g_string_append_printf (s, "]");
664 *vt = backup;
666 else
668 int i;
669 g_string_append_printf (s, " [%s",
670 sym->tag->atts.entry.type_ref[1]);
671 i = sym->tag->atts.entry.pointerOrder;
672 for (; i > 0; i--)
673 g_string_append_printf (s, "*");
674 g_string_append_printf (s, "]");
680 static void
681 mapping_function (GtkTreeView * treeview, GtkTreePath * path, gpointer data)
683 gchar *str;
684 GList *map = *((GList **) data);
686 str = gtk_tree_path_to_string (path);
687 map = g_list_append (map, str);
688 *((GList **) data) = map;
692 TMSourceFile *
693 anjuta_symbol_view_get_tm_file (AnjutaSymbolView * sv, const gchar * uri)
695 gchar *filename;
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,
704 FALSE);
706 g_free (filename);
707 return tm_file;
712 void
713 anjuta_symbol_view_add_source (AnjutaSymbolView * sv, const gchar *filename)
715 if (!sv->priv->tm_project)
716 return;
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)
728 , filename, FALSE);
731 /* sv_populate (sv); */
734 void
735 anjuta_symbol_view_remove_source (AnjutaSymbolView *sv, const gchar *filename)
737 TMWorkObject *source_file;
739 if (!sv->priv->tm_project)
740 return;
742 source_file = tm_project_find_file (sv->priv->tm_project, filename, FALSE);
743 if (source_file)
745 /* GList *node;
746 TextEditor *te; */
747 tm_project_remove_object (TM_PROJECT (sv->priv->tm_project),
748 source_file);
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))
757 te->tm_file = NULL;
759 sv_populate (sv);
762 /* else
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;
773 GTimer *timer;
774 gulong ms;
776 g_return_if_fail(sv != NULL);
777 if (uri == NULL || text_buffer == NULL)
778 return;
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");
785 return;
788 tm_file =
789 tm_workspace_find_object (TM_WORK_OBJECT
790 (sv->priv->tm_workspace),
791 filename, FALSE);
792 if (tm_file == NULL) {
793 DEBUG_PRINT ("tm_file is null");
794 return;
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);
814 static void
815 anjuta_symbol_view_add_children (AnjutaSymbolView *sv, TMSymbol *sym,
816 GtkTreeStore *store,
817 GtkTreeIter *iter)
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))
823 unsigned int j;
824 SVNodeType type;
825 AnjutaSymbolInfo *sfile;
827 if (iter == NULL)
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;
834 GString *s;
836 // if (!sym1 || ! sym1->tag || ! sym1->tag->atts.entry.file)
837 // continue;
839 if (!sym1 || ! sym1->tag)
840 continue;
842 type = anjuta_symbol_info_get_node_type (sym1, NULL);
844 if (sv_none_t == type)
845 continue;
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,
859 PIXBUF_COLUMN,
860 anjuta_symbol_info_get_pixbuf (type),
861 NAME_COLUMN, s->str,
862 SVFILE_ENTRY_COLUMN, sfile,
863 SYMBOL_NODE, sym1,
864 -1);
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..."),
874 -1);
876 anjuta_symbol_info_free (sfile);
877 g_string_free (s, TRUE);
882 static void
883 anjuta_symbol_view_refresh_tree (AnjutaSymbolView *sv)
885 GtkTreeStore *store;
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);
893 /* Clear symbols */
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,
902 sv);
903 if (!(sv->priv->symbols =
904 tm_symbol_tree_new (sv->priv->tm_project->tags_array)))
905 goto clean_leave;
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;
916 goto clean_leave;
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);
923 clean_leave:
924 if (selected_items)
925 anjuta_util_glist_strings_free (selected_items);
928 /*------------------------------------------------------------------------------
929 * this function will add the symbol_tag entries on the GtkTreeStore
931 void
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);
954 static void
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);
968 g_free (sv->priv);
969 G_OBJECT_CLASS (parent_class)->finalize (obj);
972 static void
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 */
985 static void
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,
996 g_free,
997 destroy_tm_hash_value);
999 /* let's create symbol_view tree and other gui stuff */
1000 sv_create (sv);
1003 static void
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;
1015 GType
1016 anjuta_symbol_view_get_type (void)
1018 static GType obj_type = 0;
1020 if (!obj_type)
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,
1035 "AnjutaSymbolView",
1036 &obj_info, 0);
1038 return obj_type;
1041 GtkWidget *
1042 anjuta_symbol_view_new (void)
1044 return gtk_widget_new (ANJUTA_TYPE_SYMBOL_VIEW, NULL);
1047 void
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,
1056 sv);
1057 if (source_files)
1058 tm_project_sync (TM_PROJECT (sv->priv->tm_project), source_files);
1059 else
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);
1066 void
1067 anjuta_symbol_view_save (AnjutaSymbolView * sv)
1069 tm_project_save (TM_PROJECT (sv->priv->tm_project));
1072 GList *
1073 anjuta_symbol_view_get_node_expansion_states (AnjutaSymbolView * sv)
1075 GList *map = NULL;
1076 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (sv),
1077 mapping_function, &map);
1078 return map;
1081 void
1082 anjuta_symbol_view_set_node_expansion_states (AnjutaSymbolView * sv,
1083 GList * expansion_states)
1085 /* Restore expanded nodes */
1086 if (expansion_states)
1088 GtkTreePath *path;
1089 GtkTreeModel *model;
1090 GList *node;
1091 node = expansion_states;
1093 model = gtk_tree_view_get_model (GTK_TREE_VIEW (sv));
1094 while (node)
1096 path = gtk_tree_path_new_from_string (node->data);
1097 gtk_tree_view_expand_row (GTK_TREE_VIEW (sv), path,
1098 FALSE);
1099 gtk_tree_path_free (path);
1100 node = g_list_next (node);
1105 gchar *
1106 anjuta_symbol_view_get_current_symbol (AnjutaSymbolView * sv)
1108 AnjutaSymbolInfo *info;
1109 gchar *sym_name;
1111 info = sv_current_symbol (sv);
1112 if (!info)
1113 return NULL;
1114 sym_name = g_strdup (info->sym_name);
1115 anjuta_symbol_info_free (info);
1116 return sym_name;
1119 gboolean
1120 anjuta_symbol_view_get_current_symbol_def (AnjutaSymbolView * sv,
1121 gchar ** filename,
1122 gint * line)
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);
1130 if (!info)
1131 return FALSE;
1132 if (!info->def.name)
1134 anjuta_symbol_info_free (info);
1135 return FALSE;
1137 *filename = g_strdup (info->def.name);
1138 *line = info->def.line;
1139 anjuta_symbol_info_free (info);
1140 return TRUE;
1143 gboolean
1144 anjuta_symbol_view_get_current_symbol_decl (AnjutaSymbolView * sv,
1145 gchar ** filename,
1146 gint * line)
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);
1154 if (!info)
1155 return FALSE;
1156 if (!info->decl.name)
1158 anjuta_symbol_info_free (info);
1159 return FALSE;
1161 *filename = g_strdup (info->decl.name);
1162 *line = info->decl.line;
1163 anjuta_symbol_info_free (info);
1164 return TRUE;
1167 GtkTreeModel *
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,
1176 guint tag_types)
1178 GtkTreeStore *store;
1179 GtkTreeIter iter;
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))
1189 TMTag *tag;
1190 guint i;
1192 /* let's parse every tag in the array */
1193 for (i = 0; i < tm_file->tags_array->len; ++i)
1195 gchar *tag_name;
1197 tag = TM_TAG (tm_file->tags_array->pdata[i]);
1198 if (tag == NULL)
1199 continue;
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]))
1207 tag_name =
1208 g_strdup_printf
1209 ("%s::%s [%ld]",
1210 tag->atts.entry.scope,
1211 tag->name,
1212 tag->atts.entry.line);
1213 else
1214 tag_name =
1215 g_strdup_printf ("%s [%ld]",
1216 tag->name,
1217 tag->atts.
1218 entry.line);
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,
1230 COL_PIX,
1231 anjuta_symbol_info_get_pixbuf (sv_type),
1232 COL_NAME, tag_name,
1233 COL_LINE, tag->atts.entry.line, -1);
1234 g_free (tag_name);
1238 return GTK_TREE_MODEL (store);
1241 void
1242 anjuta_symbol_view_workspace_add_file (AnjutaSymbolView * sv,
1243 const gchar * file_uri)
1245 gchar *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);
1256 if (!store)
1258 DEBUG_PRINT ("Adding Symbol URI: %s", file_uri);
1259 tm_file =
1260 tm_workspace_find_object (TM_WORK_OBJECT
1261 (sv->priv->tm_workspace),
1262 uri, FALSE);
1263 if (!tm_file)
1265 tm_file = tm_source_file_new (uri, TRUE);
1266 if (tm_file)
1267 tm_workspace_add_object (tm_file);
1269 else
1271 tm_source_file_update (TM_WORK_OBJECT (tm_file), TRUE,
1272 FALSE, 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;
1280 if (tm_file)
1282 store = create_file_symbols_model (sv, tm_file,
1283 tm_tag_max_t);
1284 g_object_set_data (G_OBJECT (store), "tm_file",
1285 tm_file);
1286 g_object_set_data (G_OBJECT (store), "symbol_view",
1287 sv);
1288 g_hash_table_insert (sv->priv->tm_files,
1289 g_strdup (uri), store);
1292 g_free (uri);
1293 sv->priv->file_symbol_model = store;
1296 void
1297 anjuta_symbol_view_workspace_remove_file (AnjutaSymbolView * sv,
1298 const gchar * file_uri)
1300 gchar *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);
1311 g_free (uri);
1315 // FIXME
1316 void
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);
1323 if (old_file_uri)
1324 anjuta_symbol_view_workspace_remove_file (sv, old_file_uri);
1325 anjuta_symbol_view_workspace_add_file (sv, new_file_uri);
1326 #if 0
1327 const gchar *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);
1335 if (old_file_uri)
1337 /* Rename old uri to new one */
1338 gchar *orig_key;
1339 gboolean success;
1341 g_return_if_fail (strncmp (old_file_uri, "file://", 7) == 0);
1343 uri = &old_file_uri[7];
1344 success =
1345 g_hash_table_lookup_extended (sv->priv->tm_files, uri,
1346 (gpointer *) & orig_key,
1347 (gpointer *) & store);
1348 if (success)
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);
1355 g_free (orig_key);
1356 uri = &new_file_uri[7];
1357 g_hash_table_insert (sv->priv->tm_files,
1358 g_strdup (uri), store);
1360 /* Update tm_file */
1361 tm_file =
1362 g_object_get_data (G_OBJECT (store),
1363 "tm_file");
1364 g_assert (tm_file != NULL);
1365 tm_source_file_update (TM_WORK_OBJECT (tm_file), TRUE,
1366 FALSE, TRUE);
1368 else
1370 /* Old uri not found. Just add the new one. */
1371 anjuta_symbol_view_workspace_add_file (sv,
1372 new_file_uri);
1375 else
1377 /* No old uri to rename. Just add the new one. */
1378 anjuta_symbol_view_workspace_add_file (sv, new_file_uri);
1380 #endif
1383 gint
1384 anjuta_symbol_view_workspace_get_line (AnjutaSymbolView * sv,
1385 GtkTreeIter * iter)
1387 g_return_val_if_fail (iter != NULL, -1);
1388 if (sv->priv->file_symbol_model)
1390 gint line;
1391 gtk_tree_model_get (GTK_TREE_MODEL
1392 (sv->priv->file_symbol_model), iter,
1393 COL_LINE, &line, -1);
1394 return line;
1396 return -1;
1399 #define IS_DECLARATION(T) ((tm_tag_prototype_t == (T)) || (tm_tag_externvar_t == (T)) \
1400 || (tm_tag_typedef_t == (T)))
1402 gboolean
1403 anjuta_symbol_view_get_file_symbol (AnjutaSymbolView * sv,
1404 const gchar * symbol,
1405 gboolean prefer_definition,
1406 const gchar ** const filename,
1407 gint * line)
1409 TMWorkObject *tm_file;
1410 GPtrArray *tags;
1411 guint i;
1412 int cmp;
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)
1421 tm_file =
1422 g_object_get_data (G_OBJECT
1423 (sv->priv->file_symbol_model),
1424 "tm_file");
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);
1432 if (0 == cmp)
1434 if (IS_DECLARATION (tag->type))
1435 local_proto = tag;
1436 else
1437 local_tag = tag;
1439 else if (cmp < 0)
1440 break;
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);
1457 if (cmp == 0)
1459 if (IS_DECLARATION
1460 (tag->type))
1461 global_proto = tag;
1462 else
1463 global_tag = tag;
1465 else if (cmp < 0)
1466 break;
1471 if (prefer_definition)
1473 if (local_tag)
1474 tag = local_tag;
1475 else if (global_tag)
1476 tag = global_tag;
1477 else if (local_proto)
1478 tag = local_proto;
1479 else
1480 tag = global_proto;
1482 else
1484 if (local_proto)
1485 tag = local_proto;
1486 else if (global_proto)
1487 tag = global_proto;
1488 else if (local_tag)
1489 tag = local_tag;
1490 else
1491 tag = global_tag;
1494 if (tag)
1496 *filename =
1497 g_strdup (tag->atts.entry.file->work_object.
1498 file_name);
1499 *line = tag->atts.entry.line;
1500 return TRUE;
1502 return FALSE;
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
1511 static gchar*
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;
1518 gchar c;
1519 while ((c = **expr) != '\0')
1521 if(valid_chars == 0 && isspace(c))
1523 (*expr)++;
1524 continue;
1526 // XXX: Namespace support
1527 else if(isalpha(c) || c == '_') // ???: || c == ':')
1529 ident[valid_chars] = c;
1530 if (++valid_chars == 1023)
1532 ident[1023] = '\0';
1533 return ident;
1536 /* a digit may be part of an ident but not from the start */
1537 else if (isdigit(c))
1539 if (valid_chars)
1541 ident[valid_chars] = c;
1542 if (++valid_chars == 1023)
1544 ident[1023] = '\0';
1545 return ident;
1548 else
1549 return NULL;
1552 else
1553 break;
1555 (*expr)++;
1558 if (valid_chars)
1560 ident[valid_chars] = '\0';
1561 return ident;
1563 else
1564 return NULL;
1568 static
1569 gchar* sv_extract_type_qualifier_from_expr (const gchar *string, const gchar *expr )
1571 /* check with a regular expression for the type */
1572 regex_t re;
1573 gint i;
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.
1585 * QString
1586 * var;
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
1598 gchar *res = NULL;
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' */
1608 gchar regexp[512];
1609 snprintf (regexp, 512, "%s\\<%s\\>", pattern, expr);
1611 /* compile regular expression */
1612 gint error = regcomp (&re, regexp, REG_EXTENDED) ;
1613 if (error)
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.
1622 * given:
1625 * int func_1 (void) {
1627 * MyClass *klass;
1630 * for (int i=0; i < 20; i++) {
1631 * YourClass *klass;
1633 * klass->
1636 * / ... /
1638 * Here the klass-> will be matched as YourClass [right], not the MyClass' ones [wrong]
1641 while (error == 0)
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;
1646 if (res)
1647 free (res);
1648 res = (gchar*) malloc (len + 1);
1649 if (!res)
1651 regfree (&re);
1652 return NULL;
1654 strncpy (res, string + pm[1].rm_so, len);
1655 res[len] = '\0';
1657 string += pm[0].rm_eo;
1659 /* This call to regexec finds the next match */
1660 error = regexec (&re, string, 8, &pm[0], 0) ;
1662 regfree(&re);
1664 if (!res)
1665 return NULL;
1667 /* if the proposed type is a keyword, we did something wrong, return NULL instead */
1669 i=0;
1670 while (keywords[i] != NULL) {
1671 if (strcmp(res, keywords[i]) == 0) {
1672 return NULL;
1674 i++;
1677 return res;
1682 /* Sample class:
1683 * class QWidget {
1684 * public:
1685 * QWidget();
1686 * [..]
1687 * QRect getRect();
1689 * };
1691 * for ident=getRect and klass="QWidget" return a tag of type QRect.
1693 * */
1694 static TMTag*
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;
1700 gint i;
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;
1711 gint i;
1713 scope_tag = (TMTag*)local_scope_of_ident;
1715 if (scope_tag == NULL || scope_tag->atts.entry.scope == NULL)
1716 return 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,
1720 NULL, FALSE, TRUE);
1722 if (tags_array != NULL) {
1723 for (i=0; i < tags_array ->len; i++) {
1724 TMTag *cur_tag;
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;
1729 break;
1734 if (scope_tag)
1735 DEBUG_PRINT ("scope_tag [class] %s", scope_tag->name);
1736 return scope_tag;;
1739 /* ok, search the klass for the symbols in workspace */
1740 if (klass == NULL || (strcmp("", klass) == 0))
1741 return NULL;
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++) {
1748 TMTag *tmp_tag;
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 ) {
1758 return tmp_tag;
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++) {
1773 TMTag *tmp_tag;
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[] = {
1781 tm_tag_attr_type_t
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)
1788 continue;
1790 gint j;
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 )
1795 return cur_tag;
1798 return tmp_tag;
1801 g_ptr_array_free (inherited_tags_array, TRUE);
1804 DEBUG_PRINT ("returning NULL from get_type_of_token. ident %s", ident);
1805 return NULL;
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.
1815 GPtrArray*
1816 anjuta_symbol_view_get_completable_members (TMTag* klass_tag, gboolean include_parents) {
1817 gchar *symbol_name;
1819 if (klass_tag == NULL)
1820 return 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;
1838 gint i;
1839 /* we should list all members of our struct/typedef/union...*/
1840 tags_array = tm_workspace_find_scope_members (NULL, symbol_name,
1841 TRUE, TRUE);
1842 if (tags_array == NULL) {
1843 DEBUG_PRINT ("returning NULL from struct-completable");
1844 return NULL;
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;
1866 gchar* tmp_str;
1867 gint i;
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,
1882 TRUE, TRUE);
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);
1886 return NULL;
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++) {
1910 gint j;
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) )
1917 continue;
1919 if ( (tmp_parents_array = tm_workspace_find_scope_members (NULL,
1920 cur_parent_tag->name, TRUE, TRUE)) == NULL) {
1921 continue;
1924 gint length = tmp_parents_array->len;
1925 for (j = 0; j < length; j++) {
1926 TMTag *test_tag;
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;
1945 gint i;
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++) {
1957 TMTag *cur_tag;
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;
1967 default:
1968 return NULL;
1970 return NULL;
1973 /* local_declaration_type_str must be NOT NULL.
1976 static TMTag *
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 */
1985 gchar *occurrence;
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 ) {
1991 gint i;
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,
1996 NULL, FALSE, TRUE);
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++) {
2001 TMTag *cur_tag;
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;
2006 break;
2009 return local_declaration_type;
2011 else
2012 return NULL;
2014 else { /* namespace string parsing */
2015 /* This is the case of
2016 * void foo_func() {
2018 * namespace1::namespace2::MyClass *myclass;
2020 * 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;
2031 gint indx;
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);
2048 return NULL;
2052 /* ok, we can start from index 1 to check the correctness of expression */
2053 for (indx=1; splitted_str[indx] != NULL; indx++) {
2054 gint i;
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
2061 * and so on
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;
2067 break;
2071 for (i=0; i < tmp_tags_array->len; i++) {
2072 TMTag *cur_tag;
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 */
2079 tmp_tag = cur_tag;
2080 break;
2084 found_end_node = FALSE;
2085 if (tmp_tag == NULL)
2086 break;
2088 switch (tmp_tag->type) {
2089 case tm_tag_class_t:
2090 case tm_tag_enum_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;
2100 break;
2102 else {
2103 continue;
2106 case tm_tag_namespace_t:
2107 default:
2108 continue;
2111 if (found_end_node == TRUE) {
2112 /* set the local declaration type*/
2113 local_declaration_type = tmp_tag;
2114 break;
2119 g_strfreev (splitted_str);
2120 return local_declaration_type;
2124 /* never reached */
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];
2138 int num_stack = 0;
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)
2152 return FALSE;
2154 if (!expr_len)
2155 return FALSE;
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]) {
2162 case '.':
2163 *access_method = COMPLETION_ACCESS_DIRECT;
2164 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_DIRECT;");
2165 break;
2166 case '>':
2167 if (expr[expr_len-2] == '-') {
2168 *access_method = COMPLETION_ACCESS_POINTER;
2169 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_POINTER;");
2171 break;
2172 case ':':
2173 if (expr[expr_len-2] == ':') {
2174 *access_method = COMPLETION_ACCESS_STATIC;
2175 DEBUG_PRINT ("access_method = COMPLETION_ACCESS_STATIC;");
2177 break;
2178 default:
2179 *access_method = COMPLETION_ACCESS_NONE;
2183 const gchar *start = expr + expr_len;
2184 while (--start >= expr )
2186 /* skip brackets */
2187 if (brackets > 0 || square_brackets > 0)
2189 if (*start == '(')
2190 --brackets;
2191 else if (*start == ')')
2192 ++brackets;
2193 else if (*start == '[')
2194 --square_brackets;
2195 else if (*start == ']')
2196 ++square_brackets;
2197 continue;
2199 /* identifier */
2200 if (isdigit(*start))
2201 in_ident = FALSE;
2202 else if (isalpha(*start) || *start == '_')
2204 in_ident = TRUE;
2206 else
2208 switch (*start)
2210 /* skip whitespace */
2211 case ' ':
2212 case '\t':
2213 if (in_ident)
2214 goto extract;
2215 else
2217 in_ident = FALSE;
2218 continue;
2221 /* continue searching to the left, if we
2222 * have a . or -> accessor */
2223 case '.':
2224 if (in_ident && extract_ident)
2226 const gchar *ident = start+1;
2227 if (num_stack < max_items) {
2228 stack[num_stack++] = ident;
2230 else
2231 return FALSE;
2233 in_ident = FALSE;
2234 extract_ident = TRUE;
2235 continue;
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;
2245 else
2246 return FALSE;
2248 in_ident = FALSE;
2249 extract_ident = TRUE;
2250 --start;
2251 continue;
2253 else
2255 start++;
2256 goto extract;
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;
2267 else
2268 return FALSE;
2270 in_ident = FALSE;
2271 extract_ident = TRUE;
2272 --start;
2273 continue;
2275 else
2277 start++;
2278 goto extract;
2280 case '(': /* start of a function */
2281 if (extract_ident)
2283 start++;
2284 goto extract;
2286 else
2288 extract_ident = TRUE;
2289 in_ident = FALSE;
2290 break;
2293 case ')':
2294 if (in_ident) /* probably a cast - (const char*)str */
2296 start++;
2297 goto extract;
2299 brackets++;
2300 break;
2302 case ']':
2303 if (in_ident)
2305 start++;
2306 goto extract;
2308 square_brackets++;
2309 break;
2311 default:
2312 start++;
2313 goto extract;
2318 extract:
2319 /* ident is the leftmost token, stack[*] the ones to the right
2320 * Example: str.left(2,5).toUpper()
2321 * ^^^ ^^^^ ^^^^^^^
2322 * ident stack[1] stack[0]
2325 ident = sv_scan_for_ident (&start);
2326 if (!ident)
2327 return FALSE;
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:
2346 * void foo_func() {
2348 * MyClass *myclass;
2350 * myclass->
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 "
2365 "if it's a class");
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);
2373 else {
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");
2381 else {
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);
2396 if (tag_type!=NULL)
2397 DEBUG_PRINT ("type of token: %s : %s, var_type %s\n", ident,
2398 tag_type->name, tag_type->atts.entry.type_ref[1]);
2399 else
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;
2409 /* Example:
2410 * String str;
2411 * str->left(param1)
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);
2422 else
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");
2439 tag_type = NULL;
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");
2445 tag_type = NULL;
2451 else { /* static member */
2452 /* just return the ident's tag */
2453 const GPtrArray * tags_array = NULL;
2454 gint i;
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");
2468 return NULL;
2474 /* check if stack has members or not. For an expression like
2475 * Gnome::Glade::Xml:: we have a stack of
2476 * stack[0] = Xml::
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]);
2484 //*/
2487 // probably an useless loop
2488 for (i=0; i < tags_array->len; i++) {
2489 TMTag *cur_tag;
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 */
2495 tag_type = cur_tag;
2496 break;
2501 /* recursive expression parsing to check its correctness */
2502 if (tag_type != NULL && num_stack > 0) {
2503 gint indx;
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;
2513 gchar **new_idents;
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);
2520 break;
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,
2527 tag_type->name,
2528 TRUE);
2529 if (tags_array == NULL) {
2530 g_strfreev (new_idents);
2531 break;
2534 gint i;
2535 for (i=0; i < tags_array->len; i++) {
2536 TMTag *cur_tag;
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 */
2543 tag_type = cur_tag;
2544 break;
2548 g_strfreev (new_idents);
2549 break;
2551 default:
2552 break;
2558 return tag_type;