Initial German translation of the build tutorial
[anjuta.git] / plugins / parser-cxx / parser-cxx-assist.c
blob424128c3e810fbb73e626dfe205b4e80d0188905
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-completion.h>
29 #include <libanjuta/anjuta-debug.h>
30 #include <libanjuta/anjuta-language-provider.h>
31 #include <libanjuta/anjuta-utils.h>
32 #include <libanjuta/interfaces/ianjuta-file.h>
33 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
34 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
35 #include <libanjuta/interfaces/ianjuta-editor-tip.h>
36 #include <libanjuta/interfaces/ianjuta-language-provider.h>
37 #include <libanjuta/interfaces/ianjuta-symbol-manager.h>
38 #include "parser-cxx-assist.h"
39 #include "cxxparser/engine-parser.h"
41 #define BRACE_SEARCH_LIMIT 500
42 #define SCOPE_CONTEXT_CHARACTERS "_.:>-0"
43 #define WORD_CHARACTER "_0"
45 static void iprovider_iface_init(IAnjutaProviderIface* iface);
46 static void ilanguage_provider_iface_init(IAnjutaLanguageProviderIface* iface);
48 G_DEFINE_TYPE_WITH_CODE (ParserCxxAssist,
49 parser_cxx_assist,
50 G_TYPE_OBJECT,
51 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_PROVIDER,
52 iprovider_iface_init)
53 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_LANGUAGE_PROVIDER,
54 ilanguage_provider_iface_init))
56 struct _ParserCxxAssistPriv {
57 GSettings* settings;
58 IAnjutaEditorAssist* iassist;
59 IAnjutaEditorTip* itip;
60 AnjutaLanguageProvider* lang_prov;
62 const gchar* editor_filename;
64 /* Calltips */
65 gchar* calltip_context;
66 IAnjutaIterable* calltip_iter;
67 GList* tips;
69 gint async_calltip_file;
70 gint async_calltip_system;
71 gint async_calltip_project;
73 IAnjutaSymbolQuery *calltip_query_file;
74 IAnjutaSymbolQuery *calltip_query_system;
75 IAnjutaSymbolQuery *calltip_query_project;
77 /* Autocompletion */
78 AnjutaCompletion* completion_cache;
79 gchar* pre_word;
80 gboolean member_completion;
81 gboolean autocompletion;
83 gint async_file_id;
84 gint async_system_id;
85 gint async_project_id;
87 IAnjutaSymbolQuery *ac_query_file;
88 IAnjutaSymbolQuery *ac_query_system;
89 IAnjutaSymbolQuery *ac_query_project;
91 /* Member autocompletion */
92 IAnjutaSymbolQuery *query_members;
94 /* Sync query */
95 IAnjutaSymbolQuery *sync_query_file;
96 IAnjutaSymbolQuery *sync_query_system;
97 IAnjutaSymbolQuery *sync_query_project;
101 * parser_cxx_assist_proposal_new:
102 * @symbol: IAnjutaSymbol to create the proposal for
104 * Creates a new IAnjutaEditorAssistProposal for symbol
106 * Returns: a newly allocated IAnjutaEditorAssistProposal
108 static IAnjutaEditorAssistProposal*
109 parser_cxx_assist_proposal_new (IAnjutaSymbol* symbol)
111 IAnjutaEditorAssistProposal* proposal = g_new0 (IAnjutaEditorAssistProposal, 1);
112 AnjutaLanguageProposalData* data =
113 anjuta_language_proposal_data_new (g_strdup (ianjuta_symbol_get_string (symbol, IANJUTA_SYMBOL_FIELD_NAME, NULL)));
114 data->type = ianjuta_symbol_get_sym_type (symbol, NULL);
115 switch (data->type)
117 case IANJUTA_SYMBOL_TYPE_PROTOTYPE:
118 case IANJUTA_SYMBOL_TYPE_FUNCTION:
119 case IANJUTA_SYMBOL_TYPE_METHOD:
120 case IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG:
121 proposal->label = g_strdup_printf ("%s()", data->name);
122 data->is_func = TRUE;
123 break;
124 default:
125 proposal->label = g_strdup (data->name);
126 data->is_func = FALSE;
128 data->has_para = FALSE;
129 if (data->is_func)
131 const gchar* signature = ianjuta_symbol_get_string (symbol,
132 IANJUTA_SYMBOL_FIELD_SIGNATURE,
133 NULL);
134 if (g_strcmp0 (signature, "(void)") || g_strcmp0 (signature, "()"))
135 data->has_para = TRUE;
139 proposal->data = data;
140 /* Icons are lifetime object of the symbol-db so we can cast here */
141 proposal->icon = (GdkPixbuf*) ianjuta_symbol_get_icon (symbol, NULL);
142 return proposal;
146 * parser_cxx_assist_proposal_free:
147 * @proposal: the proposal to free
149 * Frees the proposal
151 static void
152 parser_cxx_assist_proposal_free (IAnjutaEditorAssistProposal* proposal)
154 AnjutaLanguageProposalData* data = proposal->data;
155 anjuta_language_proposal_data_free (data);
156 g_free (proposal->label);
157 g_free (proposal);
161 * anjuta_propsal_completion_func:
162 * @item: an IAnjutaEditorAssistProposal
164 * Returns: the name of the completion func
166 static const gchar*
167 anjuta_proposal_completion_func (const void* item)
169 const IAnjutaEditorAssistProposal* proposal = item;
170 AnjutaLanguageProposalData* prop_data = proposal->data;
172 return prop_data->name;
176 * parser_cxx_assist_add_completions_from_symbols:
177 * @assist: self
178 * @symbols: Symbol iteration
180 * Add completions to the completions cache from @symbols.
183 static void
184 parser_cxx_assist_add_completions_from_symbols (ParserCxxAssist* assist,
185 IAnjutaIterable* symbols)
187 if (!symbols)
188 return;
191 IAnjutaSymbol* symbol = IANJUTA_SYMBOL (symbols);
192 IAnjutaEditorAssistProposal* proposal = parser_cxx_assist_proposal_new (symbol);
194 anjuta_completion_add_item (assist->priv->completion_cache, proposal);
196 while (ianjuta_iterable_next (symbols, NULL));
200 * parser_cxx_assist_update_pre_word:
201 * @assist: self
202 * @pre_word: new pre_word
204 * Updates the current pre_word
206 static void
207 parser_cxx_assist_update_pre_word (ParserCxxAssist* assist,
208 const gchar* pre_word)
210 g_free (assist->priv->pre_word);
211 if (pre_word == NULL)
212 pre_word = "";
213 assist->priv->pre_word = g_strdup (pre_word);
217 * parser_cxx_assist_is_expression_separator:
218 * @c: character to check
219 * @skip_braces: whether to skip closing braces
220 * @iter: current cursor position
222 * Checks if a character seperates a C/C++ expression. It can skip brances
223 * because they might not really end the expression
225 * Returns: TRUE if the characters seperates an expression, FALSE otherwise
227 static gboolean
228 parser_cxx_assist_is_expression_separator (gchar c,
229 gboolean skip_braces,
230 IAnjutaIterable* iter)
232 IAnjutaEditorAttribute attrib = ianjuta_editor_cell_get_attribute (
233 IANJUTA_EDITOR_CELL(iter), NULL);
234 int i;
235 const gchar separators[] = {',', ';', '\n', '\r', '\t', '(',
236 '{', '}', '=', '<', '\v', '!',
237 '&', '%', '*', '[', ']', '?', '/',
238 '+', 0};
240 if (attrib == IANJUTA_EDITOR_STRING ||
241 attrib == IANJUTA_EDITOR_COMMENT)
243 return FALSE;
246 if (c == ')' && skip_braces)
248 anjuta_util_jump_to_matching_brace (iter, c, BRACE_SEARCH_LIMIT);
249 return TRUE;
251 else if (c == ')' && !skip_braces)
252 return FALSE;
254 for (i = 0; separators[i] != 0; i++)
256 if (separators[i] == c)
257 return TRUE;
260 return FALSE;
264 * parser_cxx_assist_parse_expression:
265 * @assist: self,
266 * @iter: current cursor position
267 * @start_iter: return location for the start of the completion
269 * Returns: An iter of a list of IAnjutaSymbols or NULL
271 static IAnjutaIterable*
272 parser_cxx_assist_parse_expression (ParserCxxAssist* assist, IAnjutaIterable* iter, IAnjutaIterable** start_iter)
274 IAnjutaEditor* editor = IANJUTA_EDITOR (assist->priv->iassist);
275 IAnjutaIterable* res = NULL;
276 IAnjutaIterable* cur_pos = ianjuta_iterable_clone (iter, NULL);
277 gboolean op_start = FALSE;
278 gboolean ref_start = FALSE;
279 gchar* stmt = NULL;
281 /* Cursor points after the current characters, move back */
282 ianjuta_iterable_previous (cur_pos, NULL);
284 /* Search for a operator in the current line */
287 gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL(cur_pos),
288 0, NULL);
290 if (parser_cxx_assist_is_expression_separator(ch, FALSE, iter)) {
291 break;
294 if (ch == '.' || (op_start && ch == '-') || (ref_start && ch == ':'))
296 /* Found an operator, get the statement and the pre_word */
297 IAnjutaIterable* pre_word_start = ianjuta_iterable_clone (cur_pos,
298 NULL);
299 IAnjutaIterable* pre_word_end = ianjuta_iterable_clone (iter, NULL);
300 IAnjutaIterable* stmt_end = ianjuta_iterable_clone (pre_word_start,
301 NULL);
304 /* we need to pass to the parser all the statement included the last
305 * operator, being it "." or "->" or "::"
306 * Increase the end bound of the statement.
308 ianjuta_iterable_next (stmt_end, NULL);
309 if (op_start == TRUE || ref_start == TRUE)
310 ianjuta_iterable_next (stmt_end, NULL);
313 /* Move one character forward so we have the start of the pre_word
314 * and not the last operator */
315 ianjuta_iterable_next (pre_word_start, NULL);
316 /* If this is a two character operator, skip the second character */
317 if (op_start)
319 ianjuta_iterable_next (pre_word_start, NULL);
322 parser_cxx_assist_update_pre_word (assist, ianjuta_editor_get_text (
323 editor,
324 pre_word_start,
325 pre_word_end,
326 NULL));
328 /* Try to get the name of the variable */
329 while (ianjuta_iterable_previous (cur_pos, NULL))
331 gchar word_ch = ianjuta_editor_cell_get_char (
332 IANJUTA_EDITOR_CELL(cur_pos), 0, NULL);
334 if (parser_cxx_assist_is_expression_separator(word_ch, FALSE,
335 cur_pos))
336 break;
338 ianjuta_iterable_next (cur_pos, NULL);
339 stmt = ianjuta_editor_get_text (editor,
340 cur_pos, stmt_end, NULL);
341 *start_iter = pre_word_start;
342 g_object_unref (stmt_end);
343 g_object_unref (pre_word_end);
344 break;
346 else if (ch == '>')
347 op_start = TRUE;
348 else if (ch == ':')
349 ref_start = TRUE;
350 else
352 op_start = FALSE;
353 ref_start = FALSE;
356 while (ianjuta_iterable_previous (cur_pos, NULL));
358 if (stmt)
360 gint lineno;
361 gchar *above_text;
362 IAnjutaIterable* start;
364 if (!assist->priv->editor_filename)
366 g_free (stmt);
367 return NULL;
370 start = ianjuta_editor_get_start_position (editor, NULL);
371 above_text = ianjuta_editor_get_text (editor, start, iter, NULL);
372 g_object_unref (start);
374 lineno = ianjuta_editor_get_lineno (editor, NULL);
376 /* the parser works even for the "Gtk::" like expressions, so it
377 * shouldn't be created a specific case to handle this.
379 res = engine_parser_process_expression (stmt,
380 above_text,
381 assist->priv->editor_filename,
382 lineno);
383 g_free (stmt);
385 g_object_unref (cur_pos);
386 return res;
390 * parser_cxx_assist_cancel_queries:
391 * @assist: self
393 * Abort all async operations
395 static void
396 parser_cxx_assist_cancel_queries (ParserCxxAssist* assist)
398 ianjuta_symbol_query_cancel (assist->priv->ac_query_file, NULL);
399 ianjuta_symbol_query_cancel (assist->priv->ac_query_project, NULL);
400 ianjuta_symbol_query_cancel (assist->priv->ac_query_system, NULL);
401 assist->priv->async_file_id = 0;
402 assist->priv->async_project_id = 0;
403 assist->priv->async_system_id = 0;
407 * parser_cxx_assist_clear_completion_cache:
408 * @assist: self
410 * Clear the completion cache, aborting all async operations
412 static void
413 parser_cxx_assist_clear_completion_cache (ParserCxxAssist* assist)
415 parser_cxx_assist_cancel_queries (assist);
416 anjuta_completion_clear (assist->priv->completion_cache);
417 assist->priv->member_completion = FALSE;
418 assist->priv->autocompletion = FALSE;
422 * parser_cxx_assist_populate_real:
423 * @assist: self
424 * @finished: TRUE if no more proposals are expected, FALSE otherwise
426 * Really invokes the completion interfaces and adds completions.
427 * Might be called from an async context
429 static void
430 parser_cxx_assist_populate_real (ParserCxxAssist* assist, gboolean finished)
432 g_assert (assist->priv->pre_word != NULL);
433 GList* proposals = anjuta_completion_complete (assist->priv->completion_cache,
434 assist->priv->pre_word,
435 -1);
436 anjuta_language_provider_proposals (assist->priv->lang_prov,
437 IANJUTA_PROVIDER(assist), proposals,
438 assist->priv->pre_word, finished);
439 g_list_free (proposals);
443 * parser_cxx_assist_create_member_completion_cache
444 * @assist: self
445 * @cursor: Current cursor position
447 * Create the completion_cache for member completion if possible
449 * Returns: the iter where a completion cache was build, NULL otherwise
451 static IAnjutaIterable*
452 parser_cxx_assist_create_member_completion_cache (ParserCxxAssist* assist,
453 IAnjutaIterable* cursor)
455 IAnjutaIterable* symbol = NULL;
456 IAnjutaIterable* start_iter = NULL;
457 symbol = parser_cxx_assist_parse_expression (assist, cursor, &start_iter);
459 if (symbol)
461 /* Query symbol children */
462 IAnjutaIterable *children =
463 ianjuta_symbol_query_search_members (assist->priv->query_members,
464 IANJUTA_SYMBOL(symbol),
465 NULL);
467 g_object_unref (symbol);
468 if (children)
470 parser_cxx_assist_add_completions_from_symbols (assist, children);
472 parser_cxx_assist_populate_real (assist, TRUE);
473 g_object_unref (children);
474 return start_iter;
477 else if (start_iter)
478 g_object_unref (start_iter);
479 return NULL;
483 * on_symbol_search_complete:
484 * @search_id: id of this search
485 * @symbols: the returned symbols
486 * @assist: self
488 * Called by the async search method when it found symbols
490 static void
491 on_symbol_search_complete (IAnjutaSymbolQuery *query, IAnjutaIterable* symbols,
492 ParserCxxAssist* assist)
494 if (query == assist->priv->ac_query_file)
495 assist->priv->async_file_id = 0;
496 else if (query == assist->priv->ac_query_project)
497 assist->priv->async_project_id = 0;
498 else if (query == assist->priv->ac_query_system)
499 assist->priv->async_system_id = 0;
500 else
501 g_assert_not_reached ();
503 parser_cxx_assist_add_completions_from_symbols (assist, symbols);
505 gboolean running = assist->priv->async_system_id
506 || assist->priv->async_file_id
507 || assist->priv->async_project_id;
508 if (!running)
509 parser_cxx_assist_populate_real (assist, TRUE);
513 * parser_cxx_assist_create_autocompletion_cache:
514 * @assist: self
515 * @cursor: Current cursor position
517 * Create completion cache for autocompletion. This is done async.
519 * Returns: the iter where a preword was detected, NULL otherwise
521 static IAnjutaIterable*
522 parser_cxx_assist_create_autocompletion_cache (ParserCxxAssist* assist,
523 IAnjutaIterable* cursor)
525 IAnjutaIterable* start_iter;
526 gchar* pre_word = anjuta_language_provider_get_pre_word (
527 assist->priv->lang_prov,
528 IANJUTA_EDITOR (assist->priv->iassist),
529 cursor, &start_iter, WORD_CHARACTER);
530 if (!pre_word || strlen (pre_word) <= 3)
532 if (start_iter)
533 g_object_unref (start_iter);
534 return NULL;
536 else
538 gchar *pattern = g_strconcat (pre_word, "%", NULL);
540 parser_cxx_assist_update_pre_word (assist, pre_word);
542 if (IANJUTA_IS_FILE (assist->priv->iassist))
544 GFile *file = ianjuta_file_get_file (
545 IANJUTA_FILE (assist->priv->iassist), NULL);
546 if (file != NULL)
548 assist->priv->async_file_id = 1;
549 ianjuta_symbol_query_search_file (assist->priv->ac_query_file,
550 pattern, file, NULL);
551 g_object_unref (file);
554 /* This will avoid duplicates of FUNCTION and PROTOTYPE */
555 assist->priv->async_project_id = 1;
556 ianjuta_symbol_query_search (assist->priv->ac_query_project, pattern,
557 NULL);
558 assist->priv->async_system_id = 1;
559 ianjuta_symbol_query_search (assist->priv->ac_query_system, pattern,
560 NULL);
561 g_free (pre_word);
562 g_free (pattern);
564 return start_iter;
569 * parser_cxx_assist_get_calltip_context:
570 * @self: Self
571 * @iter: current cursor position
572 * @e: Error propagation
574 * Searches for a calltip context
576 * Returns: name of the method to show a calltip for or NULL
578 static gchar*
579 parser_cxx_assist_get_calltip_context (IAnjutaLanguageProvider *self,
580 IAnjutaIterable *iter,
581 GError** e)
583 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
584 gchar* calltip_context;
585 calltip_context = anjuta_language_provider_get_calltip_context (
586 assist->priv->lang_prov, assist->priv->itip, iter,
587 SCOPE_CONTEXT_CHARACTERS);
588 return calltip_context;
592 * parser_cxx_assist_create_calltips:
593 * @iter: List of symbols
594 * @merge: list of calltips to merge or NULL
596 * Create a list of Calltips (string) from a list of symbols
598 * A newly allocated GList* with newly allocated strings
600 static GList*
601 parser_cxx_assist_create_calltips (IAnjutaIterable* iter, GList* merge)
603 GList* tips = merge;
604 if (iter)
608 IAnjutaSymbol* symbol = IANJUTA_SYMBOL (iter);
609 const gchar* name = ianjuta_symbol_get_string (
610 symbol,IANJUTA_SYMBOL_FIELD_NAME, NULL);
611 if (name != NULL)
613 const gchar* args = ianjuta_symbol_get_string (
614 symbol,
615 IANJUTA_SYMBOL_FIELD_SIGNATURE,
616 NULL);
617 const gchar* rettype = ianjuta_symbol_get_string (
618 symbol,
619 IANJUTA_SYMBOL_FIELD_RETURNTYPE,
620 NULL);
621 gchar* print_args;
622 gchar* separator;
623 gchar* white_name;
624 gint white_count = 0;
626 if (!rettype)
627 rettype = "";
628 else
629 white_count += strlen(rettype) + 1;
631 white_count += strlen(name) + 1;
633 white_name = g_strnfill (white_count, ' ');
634 separator = g_strjoin (NULL, ", \n", white_name, NULL);
635 gchar** argv;
636 if (!args)
637 args = "()";
639 argv = g_strsplit (args, ",", -1);
640 print_args = g_strjoinv (separator, argv);
641 gchar* tip = g_strdup_printf ("%s %s %s", rettype, name,
642 print_args);
644 if (!g_list_find_custom (tips, tip, (GCompareFunc) strcmp))
645 tips = g_list_append (tips, tip);
647 g_strfreev (argv);
648 g_free (print_args);
649 g_free (separator);
650 g_free (white_name);
652 else
653 break;
655 while (ianjuta_iterable_next (iter, NULL));
657 return tips;
661 * on_calltip_search_complete:
662 * @search_id: id of this search
663 * @symbols: the returned symbols
664 * @assist: self
666 * Called by the async search method when it found calltips
668 static void
669 on_calltip_search_complete (IAnjutaSymbolQuery *query, IAnjutaIterable* symbols,
670 ParserCxxAssist* assist)
672 assist->priv->tips = parser_cxx_assist_create_calltips (symbols,
673 assist->priv->tips);
674 if (query == assist->priv->calltip_query_file)
675 assist->priv->async_calltip_file = 0;
676 else if (query == assist->priv->calltip_query_project)
677 assist->priv->async_calltip_project = 0;
678 else if (query == assist->priv->calltip_query_system)
679 assist->priv->async_calltip_system = 0;
680 else
681 g_assert_not_reached ();
682 gboolean running = assist->priv->async_calltip_system
683 || assist->priv->async_calltip_file
684 || assist->priv->async_calltip_project;
686 DEBUG_PRINT ("Calltip search finished with %d items",
687 g_list_length (assist->priv->tips));
689 if (!running && assist->priv->tips)
691 ianjuta_editor_tip_show (IANJUTA_EDITOR_TIP(assist->priv->itip),
692 assist->priv->tips, assist->priv->calltip_iter,
693 NULL);
698 * parser_cxx_assist_query_calltip:
699 * @self: Self
700 * @call_context: name of method/function
701 * e: Error propagation
703 * Starts an async query for the calltip
705 static void
706 parser_cxx_assist_query_calltip (ParserCxxAssist* assist,
707 const gchar *call_context,
708 IAnjutaIterable* calltip_iter)
710 /* Search file */
711 if (IANJUTA_IS_FILE (assist->priv->itip))
713 GFile *file = ianjuta_file_get_file (IANJUTA_FILE (assist->priv->itip),
714 NULL);
716 if (file != NULL)
718 assist->priv->async_calltip_file = 1;
719 ianjuta_symbol_query_search_file (assist->priv->calltip_query_file,
720 call_context, file, NULL);
721 g_object_unref (file);
725 /* Search Project */
726 assist->priv->async_calltip_project = 1;
727 ianjuta_symbol_query_search (assist->priv->calltip_query_project,
728 call_context, NULL);
730 /* Search system */
731 assist->priv->async_calltip_system = 1;
732 ianjuta_symbol_query_search (assist->priv->calltip_query_system,
733 call_context, NULL);
737 * parser_cxx_assist_create_calltip_context:
738 * @assist: self
739 * @call_context: The context (method/function name)
740 * @position: iter where to show calltips
742 * Create the calltip context
744 static void
745 parser_cxx_assist_create_calltip_context (ParserCxxAssist* assist,
746 const gchar* call_context,
747 IAnjutaIterable* position)
749 assist->priv->calltip_context = g_strdup (call_context);
750 assist->priv->calltip_iter = position;
754 * parser_cxx_assist_clear_calltip_context:
755 * @self: Self
756 * @e: Error propagation
758 * Clears the calltip context and brings it back into a save state
760 static void
761 parser_cxx_assist_clear_calltip_context (ParserCxxAssist* assist)
763 ianjuta_symbol_query_cancel (assist->priv->calltip_query_file, NULL);
764 ianjuta_symbol_query_cancel (assist->priv->calltip_query_project, NULL);
765 ianjuta_symbol_query_cancel (assist->priv->calltip_query_system, NULL);
767 assist->priv->async_calltip_file = 0;
768 assist->priv->async_calltip_project = 0;
769 assist->priv->async_calltip_system = 0;
771 g_list_foreach (assist->priv->tips, (GFunc) g_free, NULL);
772 g_list_free (assist->priv->tips);
773 assist->priv->tips = NULL;
775 g_free (assist->priv->calltip_context);
776 assist->priv->calltip_context = NULL;
778 if (assist->priv->calltip_iter)
779 g_object_unref (assist->priv->calltip_iter);
780 assist->priv->calltip_iter = NULL;
784 * parser_cxx_assist_cancelled:
785 * @iassist: IAnjutaEditorAssist that emitted the signal
786 * @assist: ParserCxxAssist object
788 * Stop any autocompletion queries when the cancelled signal was received
790 static void
791 parser_cxx_assist_cancelled (IAnjutaEditorAssist* iassist,
792 ParserCxxAssist* assist)
794 parser_cxx_assist_cancel_queries (assist);
797 static GList*
798 parser_cxx_assist_get_calltip_cache (IAnjutaLanguageProvider* self,
799 gchar* call_context,
800 GError** e)
802 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
803 if (!g_strcmp0 (call_context, assist->priv->calltip_context))
805 DEBUG_PRINT ("Calltip was found in the cache.");
806 return assist->priv->tips;
808 else
810 DEBUG_PRINT ("Calltip is not available in the cache!");
811 return NULL;
815 static void
816 parser_cxx_assist_new_calltip (IAnjutaLanguageProvider* self,
817 gchar* call_context,
818 IAnjutaIterable* cursor,
819 GError** e)
821 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
822 parser_cxx_assist_clear_calltip_context (assist);
823 parser_cxx_assist_create_calltip_context (assist, call_context, cursor);
824 parser_cxx_assist_query_calltip (assist, call_context, cursor);
827 static IAnjutaIterable*
828 parser_cxx_assist_populate_completions (IAnjutaLanguageProvider* self,
829 IAnjutaIterable* cursor,
830 GError** e)
832 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
833 IAnjutaIterable* start_iter = NULL;
835 /* Check if completion was in progress */
836 if (assist->priv->member_completion || assist->priv->autocompletion)
838 gchar* pre_word = anjuta_language_provider_get_pre_word (
839 assist->priv->lang_prov,
840 IANJUTA_EDITOR (assist->priv->iassist),
841 cursor, &start_iter, WORD_CHARACTER);
842 DEBUG_PRINT ("Preword: %s", pre_word);
843 if (pre_word && g_str_has_prefix (pre_word, assist->priv->pre_word))
845 DEBUG_PRINT ("Continue autocomplete for %s", pre_word);
847 /* Great, we just continue the current completion */
848 parser_cxx_assist_update_pre_word (assist, pre_word);
849 parser_cxx_assist_populate_real (assist, TRUE);
850 g_free (pre_word);
851 return start_iter;
853 g_free (pre_word);
856 parser_cxx_assist_clear_completion_cache (assist);
858 /* Check for member completion */
859 start_iter = parser_cxx_assist_create_member_completion_cache (assist,
860 cursor);
861 if (start_iter)
862 assist->priv->member_completion = TRUE;
863 else
865 start_iter = parser_cxx_assist_create_autocompletion_cache (assist,
866 cursor);
867 if (start_iter)
868 assist->priv->autocompletion = TRUE;
871 return start_iter;
875 * parser_cxx_assist_install:
876 * @assist: ParserCxxAssist object
877 * @ieditor: Editor to install support for
878 * @iparser: Parser to install support for
880 * Returns: Registers provider for editor
882 static void
883 parser_cxx_assist_install (ParserCxxAssist *assist,
884 IAnjutaEditor *ieditor)
886 g_return_if_fail (assist->priv->iassist == NULL);
888 if (IANJUTA_IS_EDITOR_ASSIST (ieditor))
890 assist->priv->iassist = IANJUTA_EDITOR_ASSIST (ieditor);
891 ianjuta_editor_assist_add (IANJUTA_EDITOR_ASSIST (ieditor),
892 IANJUTA_PROVIDER(assist), NULL);
893 g_signal_connect (ieditor, "cancelled",
894 G_CALLBACK (parser_cxx_assist_cancelled), assist);
896 else
897 assist->priv->iassist = NULL;
899 if (IANJUTA_IS_EDITOR_TIP (ieditor))
900 assist->priv->itip = IANJUTA_EDITOR_TIP (ieditor);
901 else
902 assist->priv->itip = NULL;
904 if (IANJUTA_IS_FILE (assist->priv->iassist))
906 GFile *file = ianjuta_file_get_file (
907 IANJUTA_FILE (assist->priv->iassist), NULL);
908 if (file != NULL)
910 assist->priv->editor_filename = g_file_get_path (file);
911 g_object_unref (file);
917 * parser_cxx_assist_uninstall:
918 * @self: ParserCxxAssist object
920 * Returns: Unregisters provider
922 static void
923 parser_cxx_assist_uninstall (ParserCxxAssist *assist)
925 g_return_if_fail (assist->priv->iassist != NULL);
927 g_signal_handlers_disconnect_by_func (assist->priv->iassist,
928 parser_cxx_assist_cancelled, assist);
929 ianjuta_editor_assist_remove (assist->priv->iassist, IANJUTA_PROVIDER(assist), NULL);
930 assist->priv->iassist = NULL;
933 static void
934 parser_cxx_assist_init (ParserCxxAssist *assist)
936 ParserCxxAssistPriv* priv;
938 assist->priv = priv = g_new0 (ParserCxxAssistPriv, 1);
940 priv->completion_cache = anjuta_completion_new (anjuta_proposal_completion_func);
941 anjuta_completion_set_item_destroy_func (priv->completion_cache,
942 (GDestroyNotify)parser_cxx_assist_proposal_free);
945 static void
946 parser_cxx_assist_finalize (GObject *object)
948 ParserCxxAssist *assist = PARSER_CXX_ASSIST (object);
949 ParserCxxAssistPriv* priv = assist->priv;
951 parser_cxx_assist_uninstall (assist);
952 parser_cxx_assist_clear_calltip_context (assist);
955 g_object_unref (priv->completion_cache);
956 g_free (priv->pre_word);
958 if (priv->calltip_query_file)
959 g_object_unref (priv->calltip_query_file);
960 priv->calltip_query_file = NULL;
962 if (priv->calltip_query_system)
963 g_object_unref (priv->calltip_query_system);
964 priv->calltip_query_system = NULL;
966 if (priv->calltip_query_project)
967 g_object_unref (priv->calltip_query_project);
968 priv->calltip_query_project = NULL;
970 if (priv->ac_query_file)
971 g_object_unref (priv->ac_query_file);
972 priv->ac_query_file = NULL;
974 if (priv->ac_query_system)
975 g_object_unref (priv->ac_query_system);
976 priv->ac_query_system = NULL;
978 if (priv->ac_query_project)
979 g_object_unref (priv->ac_query_project);
980 priv->ac_query_project = NULL;
982 if (priv->query_members)
983 g_object_unref (priv->query_members);
984 priv->query_members = NULL;
986 if (priv->sync_query_file)
987 g_object_unref (priv->sync_query_file);
988 priv->sync_query_file = NULL;
990 if (priv->sync_query_system)
991 g_object_unref (priv->sync_query_system);
992 priv->sync_query_system = NULL;
994 if (priv->sync_query_project)
995 g_object_unref (priv->sync_query_project);
996 priv->sync_query_project = NULL;
998 engine_parser_deinit ();
1000 g_free (assist->priv);
1001 G_OBJECT_CLASS (parser_cxx_assist_parent_class)->finalize (object);
1004 static void
1005 parser_cxx_assist_class_init (ParserCxxAssistClass *klass)
1007 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1009 object_class->finalize = parser_cxx_assist_finalize;
1012 ParserCxxAssist *
1013 parser_cxx_assist_new (IAnjutaEditor *ieditor,
1014 IAnjutaSymbolManager *isymbol_manager,
1015 GSettings* settings)
1017 ParserCxxAssist *assist;
1018 static IAnjutaSymbolField calltip_fields[] = {
1019 IANJUTA_SYMBOL_FIELD_ID,
1020 IANJUTA_SYMBOL_FIELD_NAME,
1021 IANJUTA_SYMBOL_FIELD_RETURNTYPE,
1022 IANJUTA_SYMBOL_FIELD_SIGNATURE
1024 static IAnjutaSymbolField ac_fields[] = {
1025 IANJUTA_SYMBOL_FIELD_ID,
1026 IANJUTA_SYMBOL_FIELD_NAME,
1027 IANJUTA_SYMBOL_FIELD_KIND,
1028 IANJUTA_SYMBOL_FIELD_TYPE,
1029 IANJUTA_SYMBOL_FIELD_ACCESS,
1030 IANJUTA_SYMBOL_FIELD_SIGNATURE
1033 if (!IANJUTA_IS_EDITOR_ASSIST (ieditor) && !IANJUTA_IS_EDITOR_TIP (ieditor))
1035 /* No assistance is available with the current editor */
1036 return NULL;
1038 assist = g_object_new (TYPE_PARSER_CXX_ASSIST, NULL);
1039 assist->priv->settings = settings;
1041 /* Create call tip queries */
1042 /* Calltip in file */
1043 assist->priv->calltip_query_file =
1044 ianjuta_symbol_manager_create_query (isymbol_manager,
1045 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1046 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1047 NULL);
1048 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_file,
1049 G_N_ELEMENTS (calltip_fields),
1050 calltip_fields, NULL);
1051 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_file,
1052 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1053 IANJUTA_SYMBOL_TYPE_FUNCTION |
1054 IANJUTA_SYMBOL_TYPE_METHOD |
1055 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1056 TRUE, NULL);
1057 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_file,
1058 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1059 NULL);
1060 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_file,
1061 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1062 g_signal_connect_object (assist->priv->calltip_query_file, "async-result",
1063 G_CALLBACK (on_calltip_search_complete), assist, 0);
1064 /* Calltip in project */
1065 assist->priv->calltip_query_project =
1066 ianjuta_symbol_manager_create_query (isymbol_manager,
1067 IANJUTA_SYMBOL_QUERY_SEARCH,
1068 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1069 NULL);
1070 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_project,
1071 G_N_ELEMENTS (calltip_fields),
1072 calltip_fields, NULL);
1073 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_project,
1074 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1075 IANJUTA_SYMBOL_TYPE_METHOD |
1076 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1077 TRUE, NULL);
1078 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_project,
1079 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1080 NULL);
1081 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_project,
1082 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1083 g_signal_connect_object (assist->priv->calltip_query_project, "async-result",
1084 G_CALLBACK (on_calltip_search_complete), assist, 0);
1085 /* Calltip in system */
1086 assist->priv->calltip_query_system =
1087 ianjuta_symbol_manager_create_query (isymbol_manager,
1088 IANJUTA_SYMBOL_QUERY_SEARCH,
1089 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1090 NULL);
1091 ianjuta_symbol_query_set_fields (assist->priv->calltip_query_system,
1092 G_N_ELEMENTS (calltip_fields),
1093 calltip_fields, NULL);
1094 ianjuta_symbol_query_set_filters (assist->priv->calltip_query_system,
1095 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1096 IANJUTA_SYMBOL_TYPE_METHOD |
1097 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1098 TRUE, NULL);
1099 ianjuta_symbol_query_set_file_scope (assist->priv->calltip_query_system,
1100 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1101 NULL);
1102 ianjuta_symbol_query_set_mode (assist->priv->calltip_query_system,
1103 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1104 g_signal_connect_object (assist->priv->calltip_query_system, "async-result",
1105 G_CALLBACK (on_calltip_search_complete), assist, 0);
1107 /* Create autocomplete queries */
1108 /* AC in file */
1109 assist->priv->ac_query_file =
1110 ianjuta_symbol_manager_create_query (isymbol_manager,
1111 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1112 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1113 NULL);
1114 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_file,
1115 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1116 ianjuta_symbol_query_set_fields (assist->priv->ac_query_file,
1117 G_N_ELEMENTS (ac_fields),
1118 ac_fields, NULL);
1119 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_file,
1120 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1121 NULL);
1122 ianjuta_symbol_query_set_mode (assist->priv->ac_query_file,
1123 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1124 g_signal_connect_object (assist->priv->ac_query_file, "async-result",
1125 G_CALLBACK (on_symbol_search_complete), assist, 0);
1126 /* AC in project */
1127 assist->priv->ac_query_project =
1128 ianjuta_symbol_manager_create_query (isymbol_manager,
1129 IANJUTA_SYMBOL_QUERY_SEARCH,
1130 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1131 NULL);
1132 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_project,
1133 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1134 ianjuta_symbol_query_set_fields (assist->priv->ac_query_project,
1135 G_N_ELEMENTS (ac_fields),
1136 ac_fields, NULL);
1137 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_project,
1138 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1139 NULL);
1140 ianjuta_symbol_query_set_mode (assist->priv->ac_query_project,
1141 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1142 g_signal_connect_object (assist->priv->ac_query_project, "async-result",
1143 G_CALLBACK (on_symbol_search_complete), assist, 0);
1144 /* AC in system */
1145 assist->priv->ac_query_system =
1146 ianjuta_symbol_manager_create_query (isymbol_manager,
1147 IANJUTA_SYMBOL_QUERY_SEARCH,
1148 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1149 NULL);
1150 ianjuta_symbol_query_set_group_by (assist->priv->ac_query_system,
1151 IANJUTA_SYMBOL_FIELD_NAME, NULL);
1152 ianjuta_symbol_query_set_fields (assist->priv->ac_query_system,
1153 G_N_ELEMENTS (ac_fields),
1154 ac_fields, NULL);
1155 ianjuta_symbol_query_set_file_scope (assist->priv->ac_query_system,
1156 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1157 NULL);
1158 ianjuta_symbol_query_set_mode (assist->priv->ac_query_system,
1159 IANJUTA_SYMBOL_QUERY_MODE_ASYNC, NULL);
1160 g_signal_connect_object (assist->priv->ac_query_system, "async-result",
1161 G_CALLBACK (on_symbol_search_complete), assist, 0);
1163 /* Members autocompletion */
1164 assist->priv->query_members =
1165 ianjuta_symbol_manager_create_query (isymbol_manager,
1166 IANJUTA_SYMBOL_QUERY_SEARCH_MEMBERS,
1167 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1168 NULL);
1169 ianjuta_symbol_query_set_fields (assist->priv->query_members,
1170 G_N_ELEMENTS (ac_fields),
1171 ac_fields, NULL);
1173 /* Create sync queries */
1174 /* Sync query in file */
1175 assist->priv->sync_query_file =
1176 ianjuta_symbol_manager_create_query (isymbol_manager,
1177 IANJUTA_SYMBOL_QUERY_SEARCH_FILE,
1178 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1179 NULL);
1180 ianjuta_symbol_query_set_fields (assist->priv->sync_query_file,
1181 G_N_ELEMENTS (calltip_fields),
1182 calltip_fields, NULL);
1183 ianjuta_symbol_query_set_filters (assist->priv->sync_query_file,
1184 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1185 IANJUTA_SYMBOL_TYPE_FUNCTION |
1186 IANJUTA_SYMBOL_TYPE_METHOD |
1187 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1188 TRUE, NULL);
1189 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_file,
1190 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE,
1191 NULL);
1192 /* Sync query in project */
1193 assist->priv->sync_query_project =
1194 ianjuta_symbol_manager_create_query (isymbol_manager,
1195 IANJUTA_SYMBOL_QUERY_SEARCH,
1196 IANJUTA_SYMBOL_QUERY_DB_PROJECT,
1197 NULL);
1198 ianjuta_symbol_query_set_fields (assist->priv->sync_query_project,
1199 G_N_ELEMENTS (calltip_fields),
1200 calltip_fields, NULL);
1201 ianjuta_symbol_query_set_filters (assist->priv->sync_query_project,
1202 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1203 IANJUTA_SYMBOL_TYPE_METHOD |
1204 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1205 TRUE, NULL);
1206 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_project,
1207 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1208 NULL);
1209 /* Sync query in system */
1210 assist->priv->sync_query_system =
1211 ianjuta_symbol_manager_create_query (isymbol_manager,
1212 IANJUTA_SYMBOL_QUERY_SEARCH,
1213 IANJUTA_SYMBOL_QUERY_DB_SYSTEM,
1214 NULL);
1215 ianjuta_symbol_query_set_fields (assist->priv->sync_query_system,
1216 G_N_ELEMENTS (calltip_fields),
1217 calltip_fields, NULL);
1218 ianjuta_symbol_query_set_filters (assist->priv->sync_query_system,
1219 IANJUTA_SYMBOL_TYPE_PROTOTYPE |
1220 IANJUTA_SYMBOL_TYPE_METHOD |
1221 IANJUTA_SYMBOL_TYPE_MACRO_WITH_ARG,
1222 TRUE, NULL);
1223 ianjuta_symbol_query_set_file_scope (assist->priv->sync_query_system,
1224 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC,
1225 NULL);
1227 /* Install support */
1228 parser_cxx_assist_install (assist, ieditor);
1229 assist->priv->lang_prov = g_object_new (ANJUTA_TYPE_LANGUAGE_PROVIDER, NULL);
1230 anjuta_language_provider_install (assist->priv->lang_prov, ieditor, settings);
1231 engine_parser_init (isymbol_manager);
1233 return assist;
1236 static void
1237 parser_cxx_assist_activate (IAnjutaProvider* self,
1238 IAnjutaIterable* iter,
1239 gpointer data,
1240 GError** e)
1242 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1243 anjuta_language_provider_activate (assist->priv->lang_prov, self, iter,
1244 data);
1247 static void
1248 parser_cxx_assist_populate (IAnjutaProvider* self,
1249 IAnjutaIterable* cursor,
1250 GError** e)
1252 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1253 anjuta_language_provider_populate (assist->priv->lang_prov, self, cursor);
1256 static const gchar*
1257 parser_cxx_assist_get_name (IAnjutaProvider* self,
1258 GError** e)
1260 return _("C/C++");
1263 static IAnjutaIterable*
1264 parser_cxx_assist_get_start_iter (IAnjutaProvider* self,
1265 GError** e)
1267 ParserCxxAssist* assist = PARSER_CXX_ASSIST (self);
1268 return anjuta_language_provider_get_start_iter (assist->priv->lang_prov);
1271 static void
1272 iprovider_iface_init (IAnjutaProviderIface* iface)
1274 iface->activate = parser_cxx_assist_activate;
1275 iface->populate = parser_cxx_assist_populate;
1276 iface->get_name = parser_cxx_assist_get_name;
1277 iface->get_start_iter = parser_cxx_assist_get_start_iter;
1280 static void
1281 ilanguage_provider_iface_init (IAnjutaLanguageProviderIface* iface)
1283 iface->get_calltip_cache = parser_cxx_assist_get_calltip_cache;
1284 iface->get_calltip_context = parser_cxx_assist_get_calltip_context;
1285 iface->new_calltip = parser_cxx_assist_new_calltip;
1286 iface->populate_completions = parser_cxx_assist_populate_completions;