1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2007 Naba Kumar <naba@gnome.org>
5 * Johannes Schmid <jhs@gnome.org>
7 * anjuta is free software.
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)
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.
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
,
50 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_PROVIDER
,
52 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_LANGUAGE_PROVIDER
,
53 ilanguage_provider_iface_init
))
55 struct _ParserCxxAssistPriv
{
57 IAnjutaEditorAssist
* iassist
;
58 IAnjutaEditorTip
* itip
;
59 AnjutaLanguageProvider
* lang_prov
;
61 const gchar
* editor_filename
;
64 gchar
* calltip_context
;
65 IAnjutaIterable
* calltip_iter
;
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
;
77 GCompletion
*completion_cache
;
79 gboolean member_completion
;
80 gboolean autocompletion
;
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
;
94 IAnjutaSymbolQuery
*sync_query_file
;
95 IAnjutaSymbolQuery
*sync_query_system
;
96 IAnjutaSymbolQuery
*sync_query_project
;
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
);
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
;
124 proposal
->label
= g_strdup (data
->name
);
125 data
->is_func
= FALSE
;
127 data
->has_para
= FALSE
;
130 const gchar
* signature
= ianjuta_symbol_get_string (symbol
,
131 IANJUTA_SYMBOL_FIELD_SIGNATURE
,
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
);
145 * parser_cxx_assist_proposal_free:
146 * @proposal: the proposal to free
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
);
160 * anjuta_propsal_completion_func:
161 * @data: an IAnjutaEditorAssistProposal
163 * Returns: the name of the completion func
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()
184 parser_cxx_assist_create_completion_from_symbols (IAnjutaIterable
* symbols
)
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
));
203 * parser_cxx_assist_update_pre_word:
205 * @pre_word: new pre_word
207 * Updates the current pre_word
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
)
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
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
);
238 const gchar separators
[] = {',', ';', '\n', '\r', '\t', '(',
239 '{', '}', '=', '<', '\v', '!',
240 '&', '%', '*', '[', ']', '?', '/',
243 if (attrib
== IANJUTA_EDITOR_STRING
||
244 attrib
== IANJUTA_EDITOR_COMMENT
)
249 if (c
== ')' && skip_braces
)
251 anjuta_util_jump_to_matching_brace (iter
, c
, BRACE_SEARCH_LIMIT
);
254 else if (c
== ')' && !skip_braces
)
257 for (i
= 0; separators
[i
] != 0; i
++)
259 if (separators
[i
] == c
)
267 * parser_cxx_assist_parse_expression:
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
;
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
),
293 if (parser_cxx_assist_is_expression_separator(ch
, FALSE
, iter
)) {
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
,
302 IAnjutaIterable
* pre_word_end
= ianjuta_iterable_clone (iter
, NULL
);
303 IAnjutaIterable
* stmt_end
= ianjuta_iterable_clone (pre_word_start
,
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 */
322 ianjuta_iterable_next (pre_word_start
, NULL
);
325 parser_cxx_assist_update_pre_word (assist
, ianjuta_editor_get_text (
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
,
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
);
359 while (ianjuta_iterable_previous (cur_pos
, NULL
));
365 IAnjutaIterable
* start
;
367 if (!assist
->priv
->editor_filename
)
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
,
384 assist
->priv
->editor_filename
,
388 g_object_unref (cur_pos
);
393 * parser_cxx_assist_create_completion_cache:
396 * Create a new completion_cache object
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:
410 * Abort all async operations
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:
427 * Clear the completion cache, aborting all async operations
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:
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
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
,
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
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
);
483 /* Query symbol children */
484 IAnjutaIterable
*children
=
485 ianjuta_symbol_query_search_members (assist
->priv
->query_members
,
486 IANJUTA_SYMBOL(symbol
),
489 g_object_unref (symbol
);
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
);
504 g_object_unref (start_iter
);
509 * on_symbol_search_complete:
510 * @search_id: id of this search
511 * @symbols: the returned symbols
514 * Called by the async search method when it found symbols
517 on_symbol_search_complete (IAnjutaSymbolQuery
*query
, IAnjutaIterable
* symbols
,
518 ParserCxxAssist
* assist
)
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;
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
;
537 parser_cxx_assist_populate_real (assist
, TRUE
);
538 g_list_free (proposals
);
542 * parser_cxx_assist_create_autocompletion_cache:
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)
562 g_object_unref (start_iter
);
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
);
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
,
588 assist
->priv
->async_system_id
= 1;
589 ianjuta_symbol_query_search (assist
->priv
->ac_query_system
, pattern
,
599 * parser_cxx_assist_get_calltip_context:
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
609 parser_cxx_assist_get_calltip_context (IAnjutaLanguageProvider
*self
,
610 IAnjutaIterable
*iter
,
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
631 parser_cxx_assist_create_calltips (IAnjutaIterable
* iter
, GList
* merge
)
638 IAnjutaSymbol
* symbol
= IANJUTA_SYMBOL (iter
);
639 const gchar
* name
= ianjuta_symbol_get_string (
640 symbol
,IANJUTA_SYMBOL_FIELD_NAME
, NULL
);
643 const gchar
* args
= ianjuta_symbol_get_string (
645 IANJUTA_SYMBOL_FIELD_SIGNATURE
,
647 const gchar
* rettype
= ianjuta_symbol_get_string (
649 IANJUTA_SYMBOL_FIELD_RETURNTYPE
,
654 gint white_count
= 0;
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
);
669 argv
= g_strsplit (args
, ",", -1);
670 print_args
= g_strjoinv (separator
, argv
);
671 gchar
* tip
= g_strdup_printf ("%s %s %s", rettype
, name
,
674 if (!g_list_find_custom (tips
, tip
, (GCompareFunc
) strcmp
))
675 tips
= g_list_append (tips
, tip
);
685 while (ianjuta_iterable_next (iter
, NULL
));
691 * on_calltip_search_complete:
692 * @search_id: id of this search
693 * @symbols: the returned symbols
696 * Called by the async search method when it found calltips
699 on_calltip_search_complete (IAnjutaSymbolQuery
*query
, IAnjutaIterable
* symbols
,
700 ParserCxxAssist
* assist
)
702 assist
->priv
->tips
= parser_cxx_assist_create_calltips (symbols
,
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;
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
,
728 * parser_cxx_assist_query_calltip:
730 * @call_context: name of method/function
731 * e: Error propagation
733 * Starts an async query for the calltip
736 parser_cxx_assist_query_calltip (ParserCxxAssist
* assist
,
737 const gchar
*call_context
,
738 IAnjutaIterable
* calltip_iter
)
741 if (IANJUTA_IS_FILE (assist
->priv
->itip
))
743 GFile
*file
= ianjuta_file_get_file (IANJUTA_FILE (assist
->priv
->itip
),
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
);
756 assist
->priv
->async_calltip_project
= 1;
757 ianjuta_symbol_query_search (assist
->priv
->calltip_query_project
,
761 assist
->priv
->async_calltip_system
= 1;
762 ianjuta_symbol_query_search (assist
->priv
->calltip_query_system
,
767 * parser_cxx_assist_create_calltip_context:
769 * @call_context: The context (method/function name)
770 * @position: iter where to show calltips
772 * Create the calltip context
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:
786 * @e: Error propagation
788 * Clears the calltip context and brings it back into a save state
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
821 parser_cxx_assist_cancelled (IAnjutaEditorAssist
* iassist
,
822 ParserCxxAssist
* assist
)
824 parser_cxx_assist_cancel_queries (assist
);
828 parser_cxx_assist_get_calltip_cache (IAnjutaLanguageProvider
* self
,
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
;
840 DEBUG_PRINT ("Calltip is not available in the cache!");
846 parser_cxx_assist_new_calltip (IAnjutaLanguageProvider
* self
,
848 IAnjutaIterable
* cursor
,
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
,
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
);
887 parser_cxx_assist_clear_completion_cache (assist
);
889 /* Check for member completion */
890 start_iter
= parser_cxx_assist_create_member_completion_cache (assist
,
893 assist
->priv
->member_completion
= TRUE
;
896 start_iter
= parser_cxx_assist_create_autocompletion_cache (assist
,
899 assist
->priv
->autocompletion
= TRUE
;
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
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
);
928 assist
->priv
->iassist
= NULL
;
930 if (IANJUTA_IS_EDITOR_TIP (ieditor
))
931 assist
->priv
->itip
= IANJUTA_EDITOR_TIP (ieditor
);
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
);
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
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
;
965 parser_cxx_assist_init (ParserCxxAssist
*assist
)
967 assist
->priv
= g_new0 (ParserCxxAssistPriv
, 1);
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
);
1028 parser_cxx_assist_class_init (ParserCxxAssistClass
*klass
)
1030 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
1032 object_class
->finalize
= parser_cxx_assist_finalize
;
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 */
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
,
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
,
1080 ianjuta_symbol_query_set_file_scope (assist
->priv
->calltip_query_file
,
1081 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE
,
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
,
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
,
1101 ianjuta_symbol_query_set_file_scope (assist
->priv
->calltip_query_project
,
1102 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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
,
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
,
1122 ianjuta_symbol_query_set_file_scope (assist
->priv
->calltip_query_system
,
1123 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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 */
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
,
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
),
1142 ianjuta_symbol_query_set_file_scope (assist
->priv
->ac_query_file
,
1143 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE
,
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
);
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
,
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
),
1160 ianjuta_symbol_query_set_file_scope (assist
->priv
->ac_query_project
,
1161 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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
);
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
,
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
),
1178 ianjuta_symbol_query_set_file_scope (assist
->priv
->ac_query_system
,
1179 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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
,
1192 ianjuta_symbol_query_set_fields (assist
->priv
->query_members
,
1193 G_N_ELEMENTS (ac_fields
),
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
,
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
,
1212 ianjuta_symbol_query_set_file_scope (assist
->priv
->sync_query_file
,
1213 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PRIVATE
,
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
,
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
,
1229 ianjuta_symbol_query_set_file_scope (assist
->priv
->sync_query_project
,
1230 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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
,
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
,
1246 ianjuta_symbol_query_set_file_scope (assist
->priv
->sync_query_system
,
1247 IANJUTA_SYMBOL_QUERY_SEARCH_FS_PUBLIC
,
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
);
1260 parser_cxx_assist_activate (IAnjutaProvider
* self
,
1261 IAnjutaIterable
* iter
,
1265 ParserCxxAssist
* assist
= PARSER_CXX_ASSIST (self
);
1266 anjuta_language_provider_activate (assist
->priv
->lang_prov
, self
, iter
,
1271 parser_cxx_assist_populate (IAnjutaProvider
* self
,
1272 IAnjutaIterable
* cursor
,
1275 ParserCxxAssist
* assist
= PARSER_CXX_ASSIST (self
);
1276 anjuta_language_provider_populate (assist
->priv
->lang_prov
, self
, cursor
);
1280 parser_cxx_assist_get_name (IAnjutaProvider
* self
,
1286 static IAnjutaIterable
*
1287 parser_cxx_assist_get_start_iter (IAnjutaProvider
* self
,
1290 ParserCxxAssist
* assist
= PARSER_CXX_ASSIST (self
);
1291 return anjuta_language_provider_get_start_iter (assist
->priv
->lang_prov
);
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
;
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
;