1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * anjuta-language-provider.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <libanjuta/anjuta-debug.h>
23 #include <libanjuta/anjuta-utils.h>
24 #include <libanjuta/anjuta-language-provider.h>
25 #include <libanjuta/interfaces/ianjuta-document.h>
26 #include <libanjuta/interfaces/ianjuta-editor-assist.h>
27 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
28 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
29 #include <libanjuta/interfaces/ianjuta-editor-tip.h>
30 #include <libanjuta/interfaces/ianjuta-language-provider.h>
31 #include <libanjuta/interfaces/ianjuta-provider.h>
33 #define SCOPE_BRACE_JUMP_LIMIT 50
34 #define BRACE_SEARCH_LIMIT 500
36 G_DEFINE_TYPE (AnjutaLanguageProvider
, anjuta_language_provider
, G_TYPE_OBJECT
);
38 struct _AnjutaLanguageProviderPriv
{
40 IAnjutaEditorAssist
* iassist
;
41 IAnjutaEditorTip
* itip
;
44 IAnjutaIterable
* start_iter
;
48 * anjuta_language_provider_install:
50 * @ieditor: (type GObject): IAnjutaEditor object
51 * @settings: the settings
53 * Install the settings for AnjutaLanguageProvider
56 anjuta_language_provider_install (AnjutaLanguageProvider
*lang_prov
,
57 IAnjutaEditor
*ieditor
,
60 g_return_if_fail (lang_prov
->priv
->iassist
== NULL
);
62 if (IANJUTA_IS_EDITOR_ASSIST (ieditor
))
63 lang_prov
->priv
->iassist
= IANJUTA_EDITOR_ASSIST (ieditor
);
65 lang_prov
->priv
->iassist
= NULL
;
67 if (IANJUTA_IS_EDITOR_TIP (ieditor
))
68 lang_prov
->priv
->itip
= IANJUTA_EDITOR_TIP (ieditor
);
70 lang_prov
->priv
->itip
= NULL
;
72 lang_prov
->priv
->settings
= settings
;
76 anjuta_language_provider_uninstall (AnjutaLanguageProvider
*lang_prov
)
78 g_return_if_fail (lang_prov
->priv
->iassist
!= NULL
);
80 lang_prov
->priv
->iassist
= NULL
;
84 anjuta_language_provider_init (AnjutaLanguageProvider
*lang_prov
)
86 lang_prov
->priv
= g_new0 (AnjutaLanguageProviderPriv
, 1);
90 anjuta_language_provider_finalize (GObject
*object
)
92 AnjutaLanguageProvider
*lang_prov
;
94 lang_prov
= ANJUTA_LANGUAGE_PROVIDER (object
);
96 anjuta_language_provider_uninstall (lang_prov
);
97 g_free (lang_prov
->priv
);
99 G_OBJECT_CLASS (anjuta_language_provider_parent_class
)->finalize (object
);
103 anjuta_language_provider_class_init (AnjutaLanguageProviderClass
*klass
)
105 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
106 object_class
->finalize
= anjuta_language_provider_finalize
;
110 * anjuta_language_provider_find_next_brace:
111 * @iter: (type GObject): Iter to start searching at
113 * Returns: (type GObject): The position of the brace, if the next non-whitespace character is a
114 * opening brace, %NULL otherwise
116 static IAnjutaIterable
*
117 anjuta_language_provider_find_next_brace (IAnjutaIterable
* iter
)
119 IAnjutaIterable
* current_iter
= ianjuta_iterable_clone (iter
, NULL
);
123 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (current_iter
),
128 while (g_ascii_isspace (ch
) && ianjuta_iterable_next (current_iter
, NULL
));
130 g_object_unref (current_iter
);
135 * anjuta_language_provider_find_whitespace:
136 * @iter: (type GObject): Iter to start searching at
138 * Returns: %TRUE if the next character is a whitespace character,
142 anjuta_language_provider_find_whitespace (IAnjutaIterable
* iter
)
144 gchar ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
),
146 if (g_ascii_isspace (ch
) && ch
!= '\n'
147 && anjuta_language_provider_find_next_brace (iter
))
156 * anjuta_language_provider_is_character:
157 * @ch: character to check
158 * @context_characters: language-specific context characters
159 * the end is marked with a '0' character
161 * Returns: if the current character seperates a scope
164 anjuta_language_provider_is_character (gchar ch
, const gchar
* characters
)
168 if (g_ascii_isspace (ch
))
170 if (g_ascii_isalnum (ch
))
172 for (i
= 0; characters
[i
] != '0'; i
++)
174 if (ch
== characters
[i
])
182 * anjuta_language_provider_get_scope_context:
183 * @editor: (type GObject): current editor
184 * @iter: Current cursor position
185 * @scope_context_ch: language-specific context characters
186 * the end is marked with a '0' character
188 * Find the scope context for calltips
191 anjuta_language_provider_get_scope_context (IAnjutaEditor
* editor
,
192 IAnjutaIterable
*iter
,
193 const gchar
* scope_context_ch
)
195 IAnjutaIterable
* end
;
196 gchar ch
, *scope_chars
= NULL
;
197 gboolean out_of_range
= FALSE
;
198 gboolean scope_chars_found
= FALSE
;
200 end
= ianjuta_iterable_clone (iter
, NULL
);
201 ianjuta_iterable_next (end
, NULL
);
203 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0, NULL
);
207 if (anjuta_language_provider_is_character (ch
, scope_context_ch
))
208 scope_chars_found
= TRUE
;
211 if (!anjuta_util_jump_to_matching_brace (iter
, ch
,
212 SCOPE_BRACE_JUMP_LIMIT
))
220 if (!ianjuta_iterable_previous (iter
, NULL
))
225 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0, NULL
);
227 if (scope_chars_found
)
229 IAnjutaIterable
* begin
;
230 begin
= ianjuta_iterable_clone (iter
, NULL
);
232 ianjuta_iterable_next (begin
, NULL
);
233 scope_chars
= ianjuta_editor_get_text (editor
, begin
, end
, NULL
);
234 g_object_unref (begin
);
236 g_object_unref (end
);
241 * anjuta_language_provider_get_calltip_context:
242 * @itip: (type GObject): whether a tooltip is crrently shown
243 * @iter: (type GObject): current cursor position
244 * @scope_context_ch: language-specific context characters
245 * the end is marked with a '0' character
247 * Searches for a calltip context
249 * Returns: name of the method to show a calltip for or %NULL
252 anjuta_language_provider_get_calltip_context (AnjutaLanguageProvider
* lang_prov
,
253 IAnjutaEditorTip
* itip
,
254 IAnjutaIterable
* iter
,
255 const gchar
* scope_context_ch
)
258 gchar
*context
= NULL
;
260 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter
), 0, NULL
);
263 if (!anjuta_util_jump_to_matching_brace (iter
, ')', -1))
265 if (!ianjuta_iterable_previous (iter
, NULL
))
270 if (!anjuta_util_jump_to_matching_brace (iter
, ')', BRACE_SEARCH_LIMIT
))
274 /* Skip white spaces */
275 while (ianjuta_iterable_previous (iter
, NULL
)
276 && g_ascii_isspace (ianjuta_editor_cell_get_char
277 (IANJUTA_EDITOR_CELL (iter
), 0, NULL
)));
279 context
= anjuta_language_provider_get_scope_context (IANJUTA_EDITOR (itip
),
283 /* Point iter to the first character of the scope to align calltip correctly */
284 ianjuta_iterable_next (iter
, NULL
);
290 * anjuta_language_provider_get_pre_word:
292 * @editor: (type GObject): IAnjutaEditor object
293 * @iter: (type GObject): current cursor position
294 * @start_iter: (type GObject): return location for the start_iter (if a preword was found)
296 * Search for the current typed word
298 * Returns: (transfer full) (allow-none): The current word (needs to be freed)
299 * or %NULL if no word was found
302 anjuta_language_provider_get_pre_word (AnjutaLanguageProvider
* lang_prov
,
303 IAnjutaEditor
* editor
,
304 IAnjutaIterable
* iter
,
305 IAnjutaIterable
** start_iter
,
306 const gchar
* word_characters
)
308 IAnjutaIterable
*end
= ianjuta_iterable_clone (iter
, NULL
);
309 IAnjutaIterable
*begin
= ianjuta_iterable_clone (iter
, NULL
);
310 gchar ch
, *preword_chars
= NULL
;
311 gboolean out_of_range
= FALSE
;
312 gboolean preword_found
= FALSE
;
314 /* Cursor points after the current characters, move back */
315 ianjuta_iterable_previous (begin
, NULL
);
317 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin
), 0, NULL
);
319 while (ch
&& anjuta_language_provider_is_character (ch
, word_characters
))
321 preword_found
= TRUE
;
322 if (!ianjuta_iterable_previous (begin
, NULL
))
327 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin
), 0, NULL
);
333 ianjuta_iterable_next (begin
, NULL
);
334 preword_chars
= ianjuta_editor_get_text (editor
, begin
, end
, NULL
);
339 g_object_unref (begin
);
343 g_object_unref (end
);
344 return preword_chars
;
348 * anjuta_language_provider_calltip:
350 * @provider: (type GObject): IAnjutaLanguageProvider object
352 * Creates a calltip if there is something to show a tip for
353 * Calltips are queried async
355 * Returns: %TRUE if a calltips was queried, %FALSE otherwise
358 anjuta_language_provider_calltip (AnjutaLanguageProvider
* lang_prov
,
359 IAnjutaLanguageProvider
* provider
)
361 IAnjutaIterable
*iter
;
362 IAnjutaEditorTip
*tip
;
365 tip
= lang_prov
->priv
->itip
;
366 iter
= ianjuta_editor_get_position (IANJUTA_EDITOR (lang_prov
->priv
->iassist
),
368 ianjuta_iterable_previous (iter
, NULL
);
370 call_context
= ianjuta_language_provider_get_calltip_context (provider
,
374 DEBUG_PRINT ("Searching calltip for: %s", call_context
);
375 GList
*tips
= ianjuta_language_provider_get_calltip_cache (provider
,
381 if (!ianjuta_editor_tip_visible (tip
, NULL
))
382 ianjuta_editor_tip_show (tip
, tips
, iter
, NULL
);
387 if (ianjuta_editor_tip_visible (tip
, NULL
))
388 ianjuta_editor_tip_cancel (tip
, NULL
);
389 ianjuta_language_provider_new_calltip (provider
, call_context
, iter
,
393 g_free (call_context
);
398 if (ianjuta_editor_tip_visible (tip
, NULL
))
399 ianjuta_editor_tip_cancel (tip
, NULL
);
401 g_object_unref (iter
);
407 * anjuta_language_provider_none:
409 * @provider: (type GObject): IAnjutaLanguageProvider object
411 * Indicate that there is nothing to autocomplete
414 anjuta_language_provider_none (AnjutaLanguageProvider
* lang_prov
,
415 IAnjutaProvider
* provider
)
417 ianjuta_editor_assist_proposals (lang_prov
->priv
->iassist
, provider
, NULL
,
422 * anjuta_language_provider_activate:
424 * @iprov: (type GObject): IAnjutaProvider object
425 * @iter: (type GObject): the cursor
426 * @data: the ProposalData
428 * Complete the function name
431 anjuta_language_provider_activate (AnjutaLanguageProvider
* lang_prov
,
432 IAnjutaProvider
* iprov
,
433 IAnjutaIterable
* iter
,
436 AnjutaLanguageProposalData
*prop_data
;
438 IAnjutaEditor
*editor
= IANJUTA_EDITOR (lang_prov
->priv
->iassist
);
439 gboolean add_space_after_func
= FALSE
;
440 gboolean add_brace_after_func
= FALSE
;
441 gboolean add_closebrace_after_func
= FALSE
;
443 g_return_if_fail (data
!= NULL
);
445 assistance
= g_string_new (prop_data
->name
);
447 if (prop_data
->is_func
)
449 IAnjutaIterable
* next_brace
= anjuta_language_provider_find_next_brace (iter
);
450 add_space_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
451 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_SPACE_AFTER_FUNC
);
452 add_brace_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
453 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_BRACE_AFTER_FUNC
);
454 add_closebrace_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
455 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_CLOSEBRACE_AFTER_FUNC
);
457 if (add_space_after_func
458 && !anjuta_language_provider_find_whitespace (iter
))
459 g_string_append (assistance
, " ");
460 if (add_brace_after_func
&& !next_brace
)
461 g_string_append (assistance
, "(");
463 g_object_unref (next_brace
);
466 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (editor
), NULL
);
468 if (ianjuta_iterable_compare (iter
, lang_prov
->priv
->start_iter
, NULL
) != 0)
470 ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (editor
),
471 lang_prov
->priv
->start_iter
, iter
, FALSE
,
473 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (editor
),
474 assistance
->str
, -1, NULL
);
477 ianjuta_editor_insert (editor
, iter
, assistance
->str
, -1, NULL
);
479 if (add_brace_after_func
&& add_closebrace_after_func
)
481 IAnjutaIterable
*next_brace
;
482 IAnjutaIterable
*pos
= ianjuta_iterable_clone (iter
, NULL
);
484 ianjuta_iterable_set_position (pos
,
485 ianjuta_iterable_get_position (
486 lang_prov
->priv
->start_iter
, NULL
)
487 + strlen (assistance
->str
),
489 next_brace
= anjuta_language_provider_find_next_brace (pos
);
491 ianjuta_editor_insert (editor
, pos
, ")", -1, NULL
);
495 ianjuta_iterable_next (pos
, NULL
);
498 ianjuta_editor_goto_position (editor
, pos
, NULL
);
500 ianjuta_iterable_previous (pos
, NULL
);
501 if (!prop_data
->has_para
)
503 pos
= ianjuta_editor_get_position (editor
, NULL
);
504 ianjuta_iterable_next (pos
, NULL
);
505 ianjuta_editor_goto_position (editor
, pos
, NULL
);
508 g_object_unref (pos
);
511 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (editor
), NULL
);
513 /* Show calltip if we completed function */
514 if (add_brace_after_func
)
516 /* Check for calltip */
517 if (lang_prov
->priv
->itip
518 && g_settings_get_boolean (lang_prov
->priv
->settings
,
519 IANJUTA_LANGUAGE_PROVIDER_PREF_CALLTIP_ENABLE
))
521 anjuta_language_provider_calltip (
522 lang_prov
, IANJUTA_LANGUAGE_PROVIDER (iprov
));
525 g_string_free (assistance
, TRUE
);
529 * anjuta_language_provider_populate:
531 * @iprov: (type GObject): IAnjutaProvider object
532 * @cursor: (type GObject): the text iter where the provider should be populated
534 * Show completion for the context at position @iter. The provider should
535 * call anjuta_language_provider_proposals here to add proposals to the list.
538 anjuta_language_provider_populate (AnjutaLanguageProvider
* lang_prov
,
539 IAnjutaProvider
* iprov
,
540 IAnjutaIterable
* cursor
)
542 IAnjutaIterable
*start_iter
;
544 /* Check if this is a valid text region for completion */
545 IAnjutaEditorAttribute attrib
= ianjuta_editor_cell_get_attribute (
546 IANJUTA_EDITOR_CELL(cursor
), NULL
);
547 if (attrib
== IANJUTA_EDITOR_COMMENT
|| attrib
== IANJUTA_EDITOR_STRING
)
549 anjuta_language_provider_none (lang_prov
, iprov
);
553 /* Check for calltip */
554 if (g_settings_get_boolean (lang_prov
->priv
->settings
,
555 IANJUTA_LANGUAGE_PROVIDER_PREF_CALLTIP_ENABLE
))
557 anjuta_language_provider_calltip (lang_prov
,
558 IANJUTA_LANGUAGE_PROVIDER (iprov
));
561 /* Check if we actually want autocompletion at all */
562 if (!g_settings_get_boolean (lang_prov
->priv
->settings
,
563 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_ENABLE
))
565 anjuta_language_provider_none (lang_prov
, iprov
);
569 /* Execute language-specific part */
570 start_iter
= ianjuta_language_provider_populate_completions (
571 IANJUTA_LANGUAGE_PROVIDER (iprov
), cursor
, NULL
);
574 if (lang_prov
->priv
->start_iter
)
575 g_object_unref (lang_prov
->priv
->start_iter
);
576 lang_prov
->priv
->start_iter
= start_iter
;
580 /* Nothing to propose */
581 if (lang_prov
->priv
->start_iter
)
583 g_object_unref (lang_prov
->priv
->start_iter
);
584 lang_prov
->priv
->start_iter
= NULL
;
586 anjuta_language_provider_none (lang_prov
, iprov
);
590 * anjuta_language_provider_proposals:
592 * @iprov: (type GObject): IAnjutaProvider object
593 * @proposals: (element-type IAnjutaEditorAssistProposal): a list of IAnjutaProposals
594 * @pre_word: the word before the cursor
595 * @finished: whether is was the last call in an async operation
597 * Add the list of proposals for the current population. You can add
598 * proposals async as long as the last call sets finished to TRUE. That
599 * is usually called by the IAnjutaLanguageProvider after it was triggered by
600 * ianjuta_language_provider_populate_completions()
603 anjuta_language_provider_proposals (AnjutaLanguageProvider
* lang_prov
,
604 IAnjutaProvider
* iprov
,
606 const gchar
* pre_word
,
609 /* Hide if the only suggestion is exactly the typed word */
610 if (pre_word
&& proposals
&& g_list_length (proposals
) == 1)
612 IAnjutaEditorAssistProposal
* proposal
= proposals
->data
;
613 AnjutaLanguageProposalData
* data
= proposal
->data
;
614 if (g_str_equal (pre_word
, data
->name
))
618 ianjuta_editor_assist_proposals (lang_prov
->priv
->iassist
, iprov
, proposals
,
619 pre_word
, finished
, NULL
);
623 * anjuta_language_provider_get_start_iter:
626 * Returns: (transfer full): the start iter
629 anjuta_language_provider_get_start_iter (AnjutaLanguageProvider
* lang_prov
)
631 return lang_prov
->priv
->start_iter
;
634 /* Boxed type for poposal data */
635 static AnjutaLanguageProposalData
*
636 anjuta_language_proposal_data_copy (const AnjutaLanguageProposalData
*src
)
638 AnjutaLanguageProposalData
* cpy
= anjuta_language_proposal_data_new (g_strdup(src
->name
));
639 cpy
->info
= src
->info
? g_strdup(src
->info
) : NULL
;
640 cpy
->is_func
= src
->is_func
;
641 cpy
->has_para
= src
->has_para
;
642 cpy
->type
= src
->type
;
648 * anjuta_language_proposal_data_free:
649 * @data: a AnjutaLanguageProposalData
651 * Free the given proposal data
654 anjuta_language_proposal_data_free (AnjutaLanguageProposalData
*data
)
662 * anjuta_language_proposal_data_new:
663 * @name: Name of the object
665 * Returns: (transfer full): Creates a new AnjutaLanguageProposalData object
667 AnjutaLanguageProposalData
*
668 anjuta_language_proposal_data_new (gchar
* name
)
670 AnjutaLanguageProposalData
* data
= g_new0(AnjutaLanguageProposalData
, 1);
677 anjuta_language_proposal_data_get_type ()
679 static GType type_id
= 0;
682 type_id
= g_boxed_type_register_static ("AnjutaLanguageProposalData",
683 (GBoxedCopyFunc
) anjuta_language_proposal_data_copy
,
684 (GBoxedFreeFunc
) anjuta_language_proposal_data_free
);