libanjuta, language-support-*: Introspection from bgo#680466
[anjuta.git] / plugins / parser-cxx / parser-cxx-assist.c
blob3ace1653a1b35dfeebbdf30c47913f4908c80b53
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * parser-cxx-assist.c
4 * Copyright (C) 2007 Naba Kumar <naba@gnome.org>
5 * Johannes Schmid <jhs@gnome.org>
6 *
7 * anjuta is free software.
8 *
9 * You may redistribute it and/or modify it under the terms of the
10 * GNU General Public License, as published by the Free Software
11 * Foundation; either version 2 of the License, or (at your option)
12 * any later version.
14 * anjuta is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with anjuta. If not, write to:
21 * The Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02110-1301, USA.
26 #include <ctype.h>
27 #include <string.h>
28 #include <libanjuta/anjuta-debug.h>
29 #include <libanjuta/anjuta-language-provider.h>
30 #include <libanjuta/anjuta-utils.h>
31 #include <libanjuta/interfaces/ianjuta-file.h>
32 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
33 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
34 #include <libanjuta/interfaces/ianjuta-editor-tip.h>
35 #include <libanjuta/interfaces/ianjuta-language-provider.h>
36 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
37 #include "parser-cxx-assist.h"
38 #include "cxxparser/engine-parser.h"
40 #define BRACE_SEARCH_LIMIT 500
41 #define SCOPE_CONTEXT_CHARACTERS "_.:>-0"
42 #define WORD_CHARACTER "_0"
44 static void iprovider_iface_init(IAnjutaProviderIface* iface);
45 static void ilanguage_provider_iface_init(IAnjutaLanguageProviderIface* iface);
47 G_DEFINE_TYPE_WITH_CODE (ParserCxxAssist,
48 parser_cxx_assist,
49 G_TYPE_OBJECT,
50 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_PROVIDER,
51 iprovider_iface_init)
52 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_LANGUAGE_PROVIDER,
53 ilanguage_provider_iface_init))
55 struct _ParserCxxAssistPriv {
56 GSettings* settings;
57 IAnjutaEditorAssist* iassist;
58 IAnjutaEditorTip* itip;
59 AnjutaLanguageProvider* lang_prov;
61 const gchar* editor_filename;
63 /* Calltips */
64 gchar* calltip_context;
65 IAnjutaIterable* calltip_iter;
66 GList* tips;
68 gint async_calltip_file;
69 gint async_calltip_system;
70 gint async_calltip_project;
72 IAnjutaSymbolQuery *calltip_query_file;
73 IAnjutaSymbolQuery *calltip_query_system;
74 IAnjutaSymbolQuery *calltip_query_project;
76 /* Autocompletion */
77 GCompletion *completion_cache;
78 gchar* pre_word;
79 gboolean member_completion;
80 gboolean autocompletion;
82 gint async_file_id;
83 gint async_system_id;
84 gint async_project_id;
86 IAnjutaSymbolQuery *ac_query_file;
87 IAnjutaSymbolQuery *ac_query_system;
88 IAnjutaSymbolQuery *ac_query_project;
90 /* Member autocompletion */
91 IAnjutaSymbolQuery *query_members;
93 /* Sync query */
94 IAnjutaSymbolQuery *sync_query_file;
95 IAnjutaSymbolQuery *sync_query_system;
96 IAnjutaSymbolQuery *sync_query_project;
99 /**
100 * parser_cxx_assist_proposal_new:
101 * @symbol: IAnjutaSymbol to create the proposal for
103 * Creates a new IAnjutaEditorAssistProposal for symbol
105 * Returns: a newly allocated IAnjutaEditorAssistProposal
107 static IAnjutaEditorAssistProposal*
108 parser_cxx_assist_proposal_new (IAnjutaSymbol* symbol)
110 IAnjutaEditorAssistProposal* proposal = g_new0 (IAnjutaEditorAssistProposal, 1);
111 AnjutaLanguageProposalData* data =
112 anjuta_language_proposal_data_new (g_strdup (ianjuta_symbol_get_string (symbol, IANJUTA_SYMBOL_FIELD_NAME, NULL)));
113 data->type = ianjuta_symbol_get_sym_type (symbol, NULL);
114 switch (data->type)
116 case IANJUTA_SYMBOL_TYPE_PROTOTYPE:
117 case IANJUTA_SYMBOL_TYPE_FUNCTION:
118 case IANJUTA_SYMBOL_TYPE_METHOD:
119 case IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG:
120 proposal->label = g_strdup_printf ("%s()", data->name);
121 data->is_func = TRUE;
122 break;
123 default:
124 proposal->label = g_strdup (data->name);
125 data->is_func = FALSE;
127 data->has_para = FALSE;
128 if (data->is_func)
130 const gchar* signature = ianjuta_symbol_get_string (symbol,
131 IANJUTA_SYMBOL_FIELD_SIGNATURE,
132 NULL);
133 if (g_strcmp0 (signature, "(void)") || g_strcmp0 (signature, "()"))
134 data->has_para = TRUE;
138 proposal->data = data;
139 /* Icons are lifetime object of the symbol-db so we can cast here */
140 proposal->icon = (GdkPixbuf*) ianjuta_symbol_get_icon (symbol, NULL);
141 return proposal;
145 * parser_cxx_assist_proposal_free:
146 * @proposal: the proposal to free
148 * Frees the proposal
150 static void
151 parser_cxx_assist_proposal_free (IAnjutaEditorAssistProposal* proposal)
153 AnjutaLanguageProposalData* data = proposal->data;
154 anjuta_language_proposal_data_free (data);
155 g_free (proposal->label);
156 g_free (proposal);
160 * anjuta_propsal_completion_func:
161 * @data: an IAnjutaEditorAssistProposal
163 * Returns: the name of the completion func
165 static gchar*
166 anjuta_proposal_completion_func (gpointer data)
168 IAnjutaEditorAssistProposal* proposal = data;
169 AnjutaLanguageProposalData* prop_data = proposal->data;
171 return prop_data->name;
175 * parser_cxx_assist_create_completion_from_symbols:
176 * @symbols: Symbol iteration
178 * Create a list of IAnjutaEditorAssistProposals from a list of symbols
180 * Returns: a newly allocated GList of newly allocated proposals. Free
181 * with cpp_java_assist_proposal_free()
183 static GList*
184 parser_cxx_assist_create_completion_from_symbols (IAnjutaIterable* symbols)
186 GList* list = NULL;
188 if (!symbols)
189 return NULL;
192 IAnjutaSymbol* symbol = IANJUTA_SYMBOL (symbols);
193 IAnjutaEditorAssistProposal* proposal = parser_cxx_assist_proposal_new (symbol);
195 list = g_list_append (list, proposal);
197 while (ianjuta_iterable_next (symbols, NULL));
199 return list;
203 * parser_cxx_assist_update_pre_word:
204 * @assist: self
205 * @pre_word: new pre_word
207 * Updates the current pre_word
209 static void
210 parser_cxx_assist_update_pre_word (ParserCxxAssist* assist,
211 const gchar* pre_word)
213 g_free (assist->priv->pre_word);
214 if (pre_word == NULL)
215 pre_word = "";
216 assist->priv->pre_word = g_strdup (pre_word);
220 * parser_cxx_assist_is_expression_separator:
221 * @c: character to check
222 * @skip_braces: whether to skip closing braces
223 * @iter: current cursor position
225 * Checks if a character seperates a C/C++ expression. It can skip brances
226 * because they might not really end the expression
228 * Returns: TRUE if the characters seperates an expression, FALSE otherwise
230 static gboolean
231 parser_cxx_assist_is_expression_separator (gchar c,
232 gboolean skip_braces,
233 IAnjutaIterable* iter)
235 IAnjutaEditorAttribute attrib = ianjuta_editor_cell_get_attribute (
236 IANJUTA_EDITOR_CELL(iter), NULL);
237 int i;
238 const gchar separators[] = {',', ';', '\n', '\r', '\t', '(',
239 '{', '}', '=', '<', '\v', '!',
240 '&', '%', '*', '[', ']', '?', '/',
241 '+', 0};
243 if (attrib == IANJUTA_EDITOR_STRING ||
244 attrib == IANJUTA_EDITOR_COMMENT)
246 return FALSE;
249 if (c == ')' && skip_braces)
251 anjuta_util_jump_to_matching_brace (iter, c, BRACE_SEARCH_LIMIT);
252 return TRUE;
254 else if (c == ')' && !skip_braces)
255 return FALSE;
257 for (i = 0; separators[i] != 0; i++)
259 if (separators[i] == c)
260 return TRUE;
263 return FALSE;
267 * parser_cxx_assist_parse_expression:
268 * @assist: self,
269 * @iter: current cursor position
270 * @start_iter: return location for the start of the completion
272 * Returns: An iter of a list of IAnjutaSymbols or NULL
274 static IAnjutaIterable*
275 parser_cxx_assist_parse_expression (ParserCxxAssist* assist, IAnjutaIterable* iter, IAnjutaIterable** start_iter)
277 IAnjutaEditor* editor = IANJUTA_EDITOR (assist->priv->iassist);
278 IAnjutaIterable* res = NULL;
279 IAnjutaIterable* cur_pos = ianjuta_iterable_clone (iter, NULL);
280 gboolean op_start = FALSE;
281 gboolean ref_start = FALSE;
282 gchar* stmt = NULL;
284 /* Cursor points after the current characters, move back */
285 ianjuta_iterable_previous (cur_pos, NULL);
287 /* Search for a operator in the current line */
290 gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL(cur_pos),
291 0, NULL);
293 if (parser_cxx_assist_is_expression_separator(ch, FALSE, iter)) {
294 break;
297 if (ch == '.' || (op_start && ch == '-') || (ref_start && ch == ':'))
299 /* Found an operator, get the statement and the pre_word */
300 IAnjutaIterable* pre_word_start = ianjuta_iterable_clone (cur_pos,
301 NULL);
302 IAnjutaIterable* pre_word_end = ianjuta_iterable_clone (iter, NULL);
303 IAnjutaIterable* stmt_end = ianjuta_iterable_clone (pre_word_start,
304 NULL);
307 /* we need to pass to the parser all the statement included the last
308 * operator, being it "." or "->" or "::"
309 * Increase the end bound of the statement.
311 ianjuta_iterable_next (stmt_end, NULL);
312 if (op_start == TRUE || ref_start == TRUE)
313 ianjuta_iterable_next (stmt_end, NULL);
316 /* Move one character forward so we have the start of the pre_word
317 * and not the last operator */
318 ianjuta_iterable_next (pre_word_start, NULL);
319 /* If this is a two character operator, skip the second character */
320 if (op_start)
322 ianjuta_iterable_next (pre_word_start, NULL);
325 parser_cxx_assist_update_pre_word (assist, ianjuta_editor_get_text (
326 editor,
327 pre_word_start,
328 pre_word_end,
329 NULL));
331 /* Try to get the name of the variable */
332 while (ianjuta_iterable_previous (cur_pos, NULL))
334 gchar word_ch = ianjuta_editor_cell_get_char (
335 IANJUTA_EDITOR_CELL(cur_pos), 0, NULL);
337 if (parser_cxx_assist_is_expression_separator(word_ch, FALSE,
338 cur_pos))
339 break;
341 ianjuta_iterable_next (cur_pos, NULL);
342 stmt = ianjuta_editor_get_text (editor,
343 cur_pos, stmt_end, NULL);
344 *start_iter = pre_word_start;
345 g_object_unref (stmt_end);
346 g_object_unref (pre_word_end);
347 break;
349 else if (ch == '>')
350 op_start = TRUE;
351 else if (ch == ':')
352 ref_start = TRUE;
353 else
355 op_start = FALSE;
356 ref_start = FALSE;
359 while (ianjuta_iterable_previous (cur_pos, NULL));
361 if (stmt)
363 gint lineno;
364 gchar *above_text;
365 IAnjutaIterable* start;
367 if (!assist->priv->editor_filename)
369 g_free (stmt);
370 return NULL;
373 start = ianjuta_editor_get_start_position (editor, NULL);
374 above_text = ianjuta_editor_get_text (editor, start, iter, NULL);
375 g_object_unref (start);
377 lineno = ianjuta_editor_get_lineno (editor, NULL);
379 /* the parser works even for the "Gtk::" like expressions, so it
380 * shouldn't be created a specific case to handle this.
382 res = engine_parser_process_expression (stmt,
383 above_text,
384 assist->priv->editor_filename,
385 lineno);
386 g_free (stmt);
388 g_object_unref (cur_pos);
389 return res;
392 /**
393 * parser_cxx_assist_create_completion_cache:
394 * @assist: self
396 * Create a new completion_cache object
398 static void
399 parser_cxx_assist_create_completion_cache (ParserCxxAssist* assist)
401 g_assert (assist->priv->completion_cache == NULL);
402 assist->priv->completion_cache =
403 g_completion_new (anjuta_proposal_completion_func);
407 * parser_cxx_assist_cancel_queries:
408 * @assist: self
410 * Abort all async operations
412 static void
413 parser_cxx_assist_cancel_queries (ParserCxxAssist* assist)
415 ianjuta_symbol_query_cancel (assist->priv->ac_query_file, NULL);
416 ianjuta_symbol_query_cancel (assist->priv->ac_query_project, NULL);
417 ianjuta_symbol_query_cancel (assist->priv->ac_query_system, NULL);
418 assist->priv->async_file_id = 0;
419 assist->priv->async_project_id = 0;
420 assist->priv->async_system_id = 0;
424 * parser_cxx_assist_clear_completion_cache:
425 * @assist: self
427 * Clear the completion cache, aborting all async operations
429 static void
430 parser_cxx_assist_clear_completion_cache (ParserCxxAssist* assist)
432 parser_cxx_assist_cancel_queries (assist);
433 if (assist->priv->completion_cache)
435 g_list_foreach (assist->priv->completion_cache->items,
436 (GFunc) parser_cxx_assist_proposal_free, NULL);
437 g_completion_free (assist->priv->completion_cache);
439 assist->priv->completion_cache = NULL;
440 assist->priv->member_completion = FALSE;
441 assist->priv->autocompletion = FALSE;
445 * parser_cxx_assist_populate_real:
446 * @assist: self
447 * @finished: TRUE if no more proposals are expected, FALSE otherwise
449 * Really invokes the completion interfaces and adds completions.
450 * Might be called from an async context
452 static void
453 parser_cxx_assist_populate_real (ParserCxxAssist* assist, gboolean finished)
455 g_assert (assist->priv->pre_word != NULL);
456 GList* proposals = g_completion_complete (assist->priv->completion_cache,
457 assist->priv->pre_word,
458 NULL);
459 ianjuta_editor_assist_proposals (assist->priv->iassist,
460 IANJUTA_PROVIDER(assist), proposals,
461 assist->priv->pre_word, finished, NULL);
465 * parser_cxx_assist_create_member_completion_cache
466 * @assist: self
467 * @cursor: Current cursor position
469 * Create the completion_cache for member completion if possible
471 * Returns: the iter where a completion cache was build, NULL otherwise
473 static IAnjutaIterable*
474 parser_cxx_assist_create_member_completion_cache (ParserCxxAssist* assist,
475 IAnjutaIterable* cursor)
477 IAnjutaIterable* symbol = NULL;
478 IAnjutaIterable* start_iter = NULL;
479 symbol = parser_cxx_assist_parse_expression (assist, cursor, &start_iter);
481 if (symbol)
483 /* Query symbol children */
484 IAnjutaIterable *children =
485 ianjuta_symbol_query_search_members (assist->priv->query_members,
486 IANJUTA_SYMBOL(symbol),
487 NULL);
489 g_object_unref (symbol);
490 if (children)
492 GList* proposals =
493 parser_cxx_assist_create_completion_from_symbols (children);
494 parser_cxx_assist_create_completion_cache (assist);
495 g_completion_add_items (assist->priv->completion_cache, proposals);
497 parser_cxx_assist_populate_real (assist, TRUE);
498 g_list_free (proposals);
499 g_object_unref (children);
500 return start_iter;
503 else if (start_iter)
504 g_object_unref (start_iter);
505 return NULL;
509 * on_symbol_search_complete:
510 * @search_id: id of this search
511 * @symbols: the returned symbols
512 * @assist: self
514 * Called by the async search method when it found symbols
516 static void
517 on_symbol_search_complete (IAnjutaSymbolQuery *query, IAnjutaIterable* symbols,
518 ParserCxxAssist* assist)
520 GList* proposals;
521 proposals = parser_cxx_assist_create_completion_from_symbols (symbols);
523 if (query == assist->priv->ac_query_file)
524 assist->priv->async_file_id = 0;
525 else if (query == assist->priv->ac_query_project)
526 assist->priv->async_project_id = 0;
527 else if (query == assist->priv->ac_query_system)
528 assist->priv->async_system_id = 0;
529 else
530 g_assert_not_reached ();
532 g_completion_add_items (assist->priv->completion_cache, proposals);
533 gboolean running = assist->priv->async_system_id
534 || assist->priv->async_file_id
535 || assist->priv->async_project_id;
536 if (!running)
537 parser_cxx_assist_populate_real (assist, TRUE);
538 g_list_free (proposals);
542 * parser_cxx_assist_create_autocompletion_cache:
543 * @assist: self
544 * @cursor: Current cursor position
546 * Create completion cache for autocompletion. This is done async.
548 * Returns: the iter where a preword was detected, NULL otherwise
550 static IAnjutaIterable*
551 parser_cxx_assist_create_autocompletion_cache (ParserCxxAssist* assist,
552 IAnjutaIterable* cursor)
554 IAnjutaIterable* start_iter;
555 gchar* pre_word = anjuta_language_provider_get_pre_word (
556 assist->priv->lang_prov,
557 IANJUTA_EDITOR (assist->priv->iassist),
558 cursor, &start_iter, WORD_CHARACTER);
559 if (!pre_word || strlen (pre_word) <= 3)
561 if (start_iter)
562 g_object_unref (start_iter);
563 return NULL;
565 else
567 gchar *pattern = g_strconcat (pre_word, "%", NULL);
569 parser_cxx_assist_create_completion_cache (assist);
570 parser_cxx_assist_update_pre_word (assist, pre_word);
572 if (IANJUTA_IS_FILE (assist->priv->iassist))
574 GFile *file = ianjuta_file_get_file (
575 IANJUTA_FILE (assist->priv->iassist), NULL);
576 if (file != NULL)
578 assist->priv->async_file_id = 1;
579 ianjuta_symbol_query_search_file (assist->priv->ac_query_file,
580 pattern, file, NULL);
581 g_object_unref (file);
584 /* This will avoid duplicates of FUNCTION and PROTOTYPE */
585 assist->priv->async_project_id = 1;
586 ianjuta_symbol_query_search (assist->priv->ac_query_project, pattern,
587 NULL);
588 assist->priv->async_system_id = 1;
589 ianjuta_symbol_query_search (assist->priv->ac_query_system, pattern,
590 NULL);
591 g_free (pre_word);
592 g_free (pattern);
594 return start_iter;
599 * parser_cxx_assist_get_calltip_context:
600 * @self: Self
601 * @iter: current cursor position
602 * @e: Error propagation
604 * Searches for a calltip context
606 * Returns: name of the method to show a calltip for or NULL
608 static gchar*
609 parser_cxx_assist_get_calltip_context (IAnjutaLanguageProvider *self,
610 IAnjutaIterable *iter,
611 GError** e)
613 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
614 gchar* calltip_context;
615 calltip_context = anjuta_language_provider_get_calltip_context (
616 assist->priv->lang_prov, assist->priv->itip, iter,
617 SCOPE_CONTEXT_CHARACTERS);
618 return calltip_context;
622 * parser_cxx_assist_create_calltips:
623 * @iter: List of symbols
624 * @merge: list of calltips to merge or NULL
626 * Create a list of Calltips (string) from a list of symbols
628 * A newly allocated GList* with newly allocated strings
630 static GList*
631 parser_cxx_assist_create_calltips (IAnjutaIterable* iter, GList* merge)
633 GList* tips = merge;
634 if (iter)
638 IAnjutaSymbol* symbol = IANJUTA_SYMBOL (iter);
639 const gchar* name = ianjuta_symbol_get_string (
640 symbol,IANJUTA_SYMBOL_FIELD_NAME, NULL);
641 if (name != NULL)
643 const gchar* args = ianjuta_symbol_get_string (
644 symbol,
645 IANJUTA_SYMBOL_FIELD_SIGNATURE,
646 NULL);
647 const gchar* rettype = ianjuta_symbol_get_string (
648 symbol,
649 IANJUTA_SYMBOL_FIELD_RETURNTYPE,
650 NULL);
651 gchar* print_args;
652 gchar* separator;
653 gchar* white_name;
654 gint white_count = 0;
656 if (!rettype)
657 rettype = "";
658 else
659 white_count += strlen(rettype) + 1;
661 white_count += strlen(name) + 1;
663 white_name = g_strnfill (white_count, ' ');
664 separator = g_strjoin (NULL, ", \n", white_name, NULL);
665 gchar** argv;
666 if (!args)
667 args = "()";
669 argv = g_strsplit (args, ",", -1);
670 print_args = g_strjoinv (separator, argv);
671 gchar* tip = g_strdup_printf ("%s %s %s", rettype, name,
672 print_args);
674 if (!g_list_find_custom (tips, tip, (GCompareFunc) strcmp))
675 tips = g_list_append (tips, tip);
677 g_strfreev (argv);
678 g_free (print_args);
679 g_free (separator);
680 g_free (white_name);
682 else
683 break;
685 while (ianjuta_iterable_next (iter, NULL));
687 return tips;
691 * on_calltip_search_complete:
692 * @search_id: id of this search
693 * @symbols: the returned symbols
694 * @assist: self
696 * Called by the async search method when it found calltips
698 static void
699 on_calltip_search_complete (IAnjutaSymbolQuery *query, IAnjutaIterable* symbols,
700 ParserCxxAssist* assist)
702 assist->priv->tips = parser_cxx_assist_create_calltips (symbols,
703 assist->priv->tips);
704 if (query == assist->priv->calltip_query_file)
705 assist->priv->async_calltip_file = 0;
706 else if (query == assist->priv->calltip_query_project)
707 assist->priv->async_calltip_project = 0;
708 else if (query == assist->priv->calltip_query_system)
709 assist->priv->async_calltip_system = 0;
710 else
711 g_assert_not_reached ();
712 gboolean running = assist->priv->async_calltip_system
713 || assist->priv->async_calltip_file
714 || assist->priv->async_calltip_project;
716 DEBUG_PRINT ("Calltip search finished with %d items",
717 g_list_length (assist->priv->tips));
719 if (!running && assist->priv->tips)
721 ianjuta_editor_tip_show (IANJUTA_EDITOR_TIP(assist->priv->itip),
722 assist->priv->tips, assist->priv->calltip_iter,
723 NULL);
728 * parser_cxx_assist_query_calltip:
729 * @self: Self
730 * @call_context: name of method/function
731 * e: Error propagation
733 * Starts an async query for the calltip
735 static void
736 parser_cxx_assist_query_calltip (ParserCxxAssist* assist,
737 const gchar *call_context,
738 IAnjutaIterable* calltip_iter)
740 /* Search file */
741 if (IANJUTA_IS_FILE (assist->priv->itip))
743 GFile *file = ianjuta_file_get_file (IANJUTA_FILE (assist->priv->itip),
744 NULL);
746 if (file != NULL)
748 assist->priv->async_calltip_file = 1;
749 ianjuta_symbol_query_search_file (assist->priv->calltip_query_file,
750 call_context, file, NULL);
751 g_object_unref (file);
755 /* Search Project */
756 assist->priv->async_calltip_project = 1;
757 ianjuta_symbol_query_search (assist->priv->calltip_query_project,
758 call_context, NULL);
760 /* Search system */
761 assist->priv->async_calltip_system = 1;
762 ianjuta_symbol_query_search (assist->priv->calltip_query_system,
763 call_context, NULL);
767 * parser_cxx_assist_create_calltip_context:
768 * @assist: self
769 * @call_context: The context (method/function name)
770 * @position: iter where to show calltips
772 * Create the calltip context
774 static void
775 parser_cxx_assist_create_calltip_context (ParserCxxAssist* assist,
776 const gchar* call_context,
777 IAnjutaIterable* position)
779 assist->priv->calltip_context = g_strdup (call_context);
780 assist->priv->calltip_iter = position;
784 * parser_cxx_assist_clear_calltip_context:
785 * @self: Self
786 * @e: Error propagation
788 * Clears the calltip context and brings it back into a save state
790 static void
791 parser_cxx_assist_clear_calltip_context (ParserCxxAssist* assist)
793 ianjuta_symbol_query_cancel (assist->priv->calltip_query_file, NULL);
794 ianjuta_symbol_query_cancel (assist->priv->calltip_query_project, NULL);
795 ianjuta_symbol_query_cancel (assist->priv->calltip_query_system, NULL);
797 assist->priv->async_calltip_file = 0;
798 assist->priv->async_calltip_project = 0;
799 assist->priv->async_calltip_system = 0;
801 g_list_foreach (assist->priv->tips, (GFunc) g_free, NULL);
802 g_list_free (assist->priv->tips);
803 assist->priv->tips = NULL;
805 g_free (assist->priv->calltip_context);
806 assist->priv->calltip_context = NULL;
808 if (assist->priv->calltip_iter)
809 g_object_unref (assist->priv->calltip_iter);
810 assist->priv->calltip_iter = NULL;
814 * parser_cxx_assist_cancelled:
815 * @iassist: IAnjutaEditorAssist that emitted the signal
816 * @assist: ParserCxxAssist object
818 * Stop any autocompletion queries when the cancelled signal was received
820 static void
821 parser_cxx_assist_cancelled (IAnjutaEditorAssist* iassist,
822 ParserCxxAssist* assist)
824 parser_cxx_assist_cancel_queries (assist);
827 static GList*
828 parser_cxx_assist_get_calltip_cache (IAnjutaLanguageProvider* self,
829 gchar* call_context,
830 GError** e)
832 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
833 if (!g_strcmp0 (call_context, assist->priv->calltip_context))
835 DEBUG_PRINT ("Calltip was found in the cache.");
836 return assist->priv->tips;
838 else
840 DEBUG_PRINT ("Calltip is not available in the cache!");
841 return NULL;
845 static void
846 parser_cxx_assist_new_calltip (IAnjutaLanguageProvider* self,
847 gchar* call_context,
848 IAnjutaIterable* cursor,
849 GError** e)
851 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
852 parser_cxx_assist_clear_calltip_context (assist);
853 parser_cxx_assist_create_calltip_context (assist, call_context, cursor);
854 parser_cxx_assist_query_calltip (assist, call_context, cursor);
857 static IAnjutaIterable*
858 parser_cxx_assist_populate_completions (IAnjutaLanguageProvider* self,
859 IAnjutaIterable* cursor,
860 GError** e)
862 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
863 IAnjutaIterable* start_iter = NULL;
865 /* Check if completion was in progress */
866 if (assist->priv->member_completion || assist->priv->autocompletion)
868 g_assert (assist->priv->completion_cache != NULL);
869 gchar* pre_word = anjuta_language_provider_get_pre_word (
870 assist->priv->lang_prov,
871 IANJUTA_EDITOR (assist->priv->iassist),
872 cursor, &start_iter, WORD_CHARACTER);
873 DEBUG_PRINT ("Preword: %s", pre_word);
874 if (pre_word && g_str_has_prefix (pre_word, assist->priv->pre_word))
876 DEBUG_PRINT ("Continue autocomplete for %s", pre_word);
878 /* Great, we just continue the current completion */
879 parser_cxx_assist_update_pre_word (assist, pre_word);
880 parser_cxx_assist_populate_real (assist, TRUE);
881 g_free (pre_word);
882 return start_iter;
884 g_free (pre_word);
887 parser_cxx_assist_clear_completion_cache (assist);
889 /* Check for member completion */
890 start_iter = parser_cxx_assist_create_member_completion_cache (assist,
891 cursor);
892 if (start_iter)
893 assist->priv->member_completion = TRUE;
894 else
896 start_iter = parser_cxx_assist_create_autocompletion_cache (assist,
897 cursor);
898 if (start_iter)
899 assist->priv->autocompletion = TRUE;
902 return start_iter;
906 * parser_cxx_assist_install:
907 * @assist: ParserCxxAssist object
908 * @ieditor: Editor to install support for
909 * @iparser: Parser to install support for
911 * Returns: Registers provider for editor
913 static void
914 parser_cxx_assist_install (ParserCxxAssist *assist,
915 IAnjutaEditor *ieditor)
917 g_return_if_fail (assist->priv->iassist == NULL);
919 if (IANJUTA_IS_EDITOR_ASSIST (ieditor))
921 assist->priv->iassist = IANJUTA_EDITOR_ASSIST (ieditor);
922 ianjuta_editor_assist_add (IANJUTA_EDITOR_ASSIST (ieditor),
923 IANJUTA_PROVIDER(assist), NULL);
924 g_signal_connect (ieditor, "cancelled",
925 G_CALLBACK (parser_cxx_assist_cancelled), assist);
927 else
928 assist->priv->iassist = NULL;
930 if (IANJUTA_IS_EDITOR_TIP (ieditor))
931 assist->priv->itip = IANJUTA_EDITOR_TIP (ieditor);
932 else
933 assist->priv->itip = NULL;
935 if (IANJUTA_IS_FILE (assist->priv->iassist))
937 GFile *file = ianjuta_file_get_file (
938 IANJUTA_FILE (assist->priv->iassist), NULL);
939 if (file != NULL)
941 assist->priv->editor_filename = g_file_get_path (file);
942 g_object_unref (file);
948 * parser_cxx_assist_uninstall:
949 * @self: ParserCxxAssist object
951 * Returns: Unregisters provider
953 static void
954 parser_cxx_assist_uninstall (ParserCxxAssist *assist)
956 g_return_if_fail (assist->priv->iassist != NULL);
958 g_signal_handlers_disconnect_by_func (assist->priv->iassist,
959 parser_cxx_assist_cancelled, assist);
960 ianjuta_editor_assist_remove (assist->priv->iassist, IANJUTA_PROVIDER(assist), NULL);
961 assist->priv->iassist = NULL;
964 static void
965 parser_cxx_assist_init (ParserCxxAssist *assist)
967 assist->priv = g_new0 (ParserCxxAssistPriv, 1);
970 static void
971 parser_cxx_assist_finalize (GObject *object)
973 ParserCxxAssist *assist = PARSER_CXX_ASSIST (object);
974 ParserCxxAssistPriv* priv = assist->priv;
976 parser_cxx_assist_uninstall (assist);
977 parser_cxx_assist_clear_completion_cache (assist);
978 parser_cxx_assist_clear_calltip_context (assist);
981 if (priv->calltip_query_file)
982 g_object_unref (priv->calltip_query_file);
983 priv->calltip_query_file = NULL;
985 if (priv->calltip_query_system)
986 g_object_unref (priv->calltip_query_system);
987 priv->calltip_query_system = NULL;
989 if (priv->calltip_query_project)
990 g_object_unref (priv->calltip_query_project);
991 priv->calltip_query_project = NULL;
993 if (priv->ac_query_file)
994 g_object_unref (priv->ac_query_file);
995 priv->ac_query_file = NULL;
997 if (priv->ac_query_system)
998 g_object_unref (priv->ac_query_system);
999 priv->ac_query_system = NULL;
1001 if (priv->ac_query_project)
1002 g_object_unref (priv->ac_query_project);
1003 priv->ac_query_project = NULL;
1005 if (priv->query_members)
1006 g_object_unref (priv->query_members);
1007 priv->query_members = NULL;
1009 if (priv->sync_query_file)
1010 g_object_unref (priv->sync_query_file);
1011 priv->sync_query_file = NULL;
1013 if (priv->sync_query_system)
1014 g_object_unref (priv->sync_query_system);
1015 priv->sync_query_system = NULL;
1017 if (priv->sync_query_project)
1018 g_object_unref (priv->sync_query_project);
1019 priv->sync_query_project = NULL;
1021 engine_parser_deinit ();
1023 g_free (assist->priv);
1024 G_OBJECT_CLASS (parser_cxx_assist_parent_class)->finalize (object);
1027 static void
1028 parser_cxx_assist_class_init (ParserCxxAssistClass *klass)
1030 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1032 object_class->finalize = parser_cxx_assist_finalize;
1035 ParserCxxAssist *
1036 parser_cxx_assist_new (IAnjutaEditor *ieditor,
1037 IAnjutaSymbolManager *isymbol_manager,
1038 GSettings* settings)
1040 ParserCxxAssist *assist;
1041 static IAnjutaSymbolField calltip_fields[] = {
1042 IANJUTA_SYMBOL_FIELD_ID,
1043 IANJUTA_SYMBOL_FIELD_NAME,
1044 IANJUTA_SYMBOL_FIELD_RETURNTYPE,
1045 IANJUTA_SYMBOL_FIELD_SIGNATURE
1047 static IAnjutaSymbolField ac_fields[] = {
1048 IANJUTA_SYMBOL_FIELD_ID,
1049 IANJUTA_SYMBOL_FIELD_NAME,
1050 IANJUTA_SYMBOL_FIELD_KIND,
1051 IANJUTA_SYMBOL_FIELD_TYPE,
1052 IANJUTA_SYMBOL_FIELD_ACCESS,
1053 IANJUTA_SYMBOL_FIELD_SIGNATURE
1056 if (!IANJUTA_IS_EDITOR_ASSIST (ieditor) && !IANJUTA_IS_EDITOR_TIP (ieditor))
1058 /* No assistance is available with the current editor */
1059 return NULL;
1061 assist = g_object_new (TYPE_PARSER_CXX_ASSIST, NULL);
1062 assist->priv->settings = settings;
1064 /* Create call tip queries */
1065 /* Calltip in file */
1066 assist->priv->calltip_query_file =
1067 ianjuta_symbol_manager_create_query (isymbol_manager,
1068 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1069 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1070 NULL);
1071 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_file,
1072 G_N_ELEMENTS (calltip_fields),
1073 calltip_fields, NULL);
1074 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_file,
1075 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1076 IANJUTA_SYMBOL_TYPE_FUNCTION |
1077 IANJUTA_SYMBOL_TYPE_METHOD |
1078 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1079 TRUE, NULL);
1080 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_file,
1081 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1082 NULL);
1083 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_file,
1084 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1085 g_signal_connect (assist->priv->calltip_query_file, "async-result",
1086 G_CALLBACK (on_calltip_search_complete), assist);
1087 /* Calltip in project */
1088 assist->priv->calltip_query_project =
1089 ianjuta_symbol_manager_create_query (isymbol_manager,
1090 IANJUTA_SYMBOL_QUERY_SEARCH,
1091 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1092 NULL);
1093 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_project,
1094 G_N_ELEMENTS (calltip_fields),
1095 calltip_fields, NULL);
1096 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_project,
1097 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1098 IANJUTA_SYMBOL_TYPE_METHOD |
1099 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1100 TRUE, NULL);
1101 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_project,
1102 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1103 NULL);
1104 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_project,
1105 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1106 g_signal_connect (assist->priv->calltip_query_project, "async-result",
1107 G_CALLBACK (on_calltip_search_complete), assist);
1108 /* Calltip in system */
1109 assist->priv->calltip_query_system =
1110 ianjuta_symbol_manager_create_query (isymbol_manager,
1111 IANJUTA_SYMBOL_QUERY_SEARCH,
1112 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1113 NULL);
1114 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_system,
1115 G_N_ELEMENTS (calltip_fields),
1116 calltip_fields, NULL);
1117 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_system,
1118 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1119 IANJUTA_SYMBOL_TYPE_METHOD |
1120 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1121 TRUE, NULL);
1122 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_system,
1123 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1124 NULL);
1125 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_system,
1126 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1127 g_signal_connect (assist->priv->calltip_query_system, "async-result",
1128 G_CALLBACK (on_calltip_search_complete), assist);
1130 /* Create autocomplete queries */
1131 /* AC in file */
1132 assist->priv->ac_query_file =
1133 ianjuta_symbol_manager_create_query (isymbol_manager,
1134 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1135 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1136 NULL);
1137 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_file,
1138 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1139 ianjuta_symbol_query_set_fields (assist->priv->ac_query_file,
1140 G_N_ELEMENTS (ac_fields),
1141 ac_fields, NULL);
1142 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_file,
1143 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1144 NULL);
1145 ianjuta_symbol_query_set_mode (assist->priv->ac_query_file,
1146 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1147 g_signal_connect (assist->priv->ac_query_file, "async-result",
1148 G_CALLBACK (on_symbol_search_complete), assist);
1149 /* AC in project */
1150 assist->priv->ac_query_project =
1151 ianjuta_symbol_manager_create_query (isymbol_manager,
1152 IANJUTA_SYMBOL_QUERY_SEARCH,
1153 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1154 NULL);
1155 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_project,
1156 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1157 ianjuta_symbol_query_set_fields (assist->priv->ac_query_project,
1158 G_N_ELEMENTS (ac_fields),
1159 ac_fields, NULL);
1160 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_project,
1161 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1162 NULL);
1163 ianjuta_symbol_query_set_mode (assist->priv->ac_query_project,
1164 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1165 g_signal_connect (assist->priv->ac_query_project, "async-result",
1166 G_CALLBACK (on_symbol_search_complete), assist);
1167 /* AC in system */
1168 assist->priv->ac_query_system =
1169 ianjuta_symbol_manager_create_query (isymbol_manager,
1170 IANJUTA_SYMBOL_QUERY_SEARCH,
1171 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1172 NULL);
1173 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_system,
1174 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1175 ianjuta_symbol_query_set_fields (assist->priv->ac_query_system,
1176 G_N_ELEMENTS (ac_fields),
1177 ac_fields, NULL);
1178 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_system,
1179 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1180 NULL);
1181 ianjuta_symbol_query_set_mode (assist->priv->ac_query_system,
1182 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1183 g_signal_connect (assist->priv->ac_query_system, "async-result",
1184 G_CALLBACK (on_symbol_search_complete), assist);
1186 /* Members autocompletion */
1187 assist->priv->query_members =
1188 ianjuta_symbol_manager_create_query (isymbol_manager,
1189 IANJUTA_SYMBOL_QUERY_SEARCH_MEMBERS,
1190 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1191 NULL);
1192 ianjuta_symbol_query_set_fields (assist->priv->query_members,
1193 G_N_ELEMENTS (ac_fields),
1194 ac_fields, NULL);
1196 /* Create sync queries */
1197 /* Sync query in file */
1198 assist->priv->sync_query_file =
1199 ianjuta_symbol_manager_create_query (isymbol_manager,
1200 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1201 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1202 NULL);
1203 ianjuta_symbol_query_set_fields (assist->priv->sync_query_file,
1204 G_N_ELEMENTS (calltip_fields),
1205 calltip_fields, NULL);
1206 ianjuta_symbol_query_set_filters (assist->priv->sync_query_file,
1207 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1208 IANJUTA_SYMBOL_TYPE_FUNCTION |
1209 IANJUTA_SYMBOL_TYPE_METHOD |
1210 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1211 TRUE, NULL);
1212 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_file,
1213 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1214 NULL);
1215 /* Sync query in project */
1216 assist->priv->sync_query_project =
1217 ianjuta_symbol_manager_create_query (isymbol_manager,
1218 IANJUTA_SYMBOL_QUERY_SEARCH,
1219 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1220 NULL);
1221 ianjuta_symbol_query_set_fields (assist->priv->sync_query_project,
1222 G_N_ELEMENTS (calltip_fields),
1223 calltip_fields, NULL);
1224 ianjuta_symbol_query_set_filters (assist->priv->sync_query_project,
1225 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1226 IANJUTA_SYMBOL_TYPE_METHOD |
1227 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1228 TRUE, NULL);
1229 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_project,
1230 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1231 NULL);
1232 /* Sync query in system */
1233 assist->priv->sync_query_system =
1234 ianjuta_symbol_manager_create_query (isymbol_manager,
1235 IANJUTA_SYMBOL_QUERY_SEARCH,
1236 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1237 NULL);
1238 ianjuta_symbol_query_set_fields (assist->priv->sync_query_system,
1239 G_N_ELEMENTS (calltip_fields),
1240 calltip_fields, NULL);
1241 ianjuta_symbol_query_set_filters (assist->priv->sync_query_system,
1242 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1243 IANJUTA_SYMBOL_TYPE_METHOD |
1244 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1245 TRUE, NULL);
1246 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_system,
1247 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1248 NULL);
1250 /* Install support */
1251 parser_cxx_assist_install (assist, ieditor);
1252 assist->priv->lang_prov = g_object_new (ANJUTA_TYPE_LANGUAGE_PROVIDER, NULL);
1253 anjuta_language_provider_install (assist->priv->lang_prov, ieditor, settings);
1254 engine_parser_init (isymbol_manager);
1256 return assist;
1259 static void
1260 parser_cxx_assist_activate (IAnjutaProvider* self,
1261 IAnjutaIterable* iter,
1262 gpointer data,
1263 GError** e)
1265 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1266 anjuta_language_provider_activate (assist->priv->lang_prov, self, iter,
1267 data);
1270 static void
1271 parser_cxx_assist_populate (IAnjutaProvider* self,
1272 IAnjutaIterable* cursor,
1273 GError** e)
1275 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1276 anjuta_language_provider_populate (assist->priv->lang_prov, self, cursor);
1279 static const gchar*
1280 parser_cxx_assist_get_name (IAnjutaProvider* self,
1281 GError** e)
1283 return _("C/C++");
1286 static IAnjutaIterable*
1287 parser_cxx_assist_get_start_iter (IAnjutaProvider* self,
1288 GError** e)
1290 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1291 return anjuta_language_provider_get_start_iter (assist->priv->lang_prov);
1294 static void
1295 iprovider_iface_init (IAnjutaProviderIface* iface)
1297 iface->activate = parser_cxx_assist_activate;
1298 iface->populate = parser_cxx_assist_populate;
1299 iface->get_name = parser_cxx_assist_get_name;
1300 iface->get_start_iter = parser_cxx_assist_get_start_iter;
1303 static void
1304 ilanguage_provider_iface_init (IAnjutaLanguageProviderIface* iface)
1306 iface->get_calltip_cache = parser_cxx_assist_get_calltip_cache;
1307 iface->get_calltip_context = parser_cxx_assist_get_calltip_context;
1308 iface->new_calltip = parser_cxx_assist_new_calltip;
1309 iface->populate_completions = parser_cxx_assist_populate_completions;