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: The current word (needs to be freed) or NULL if no word was found
301 anjuta_language_provider_get_pre_word (AnjutaLanguageProvider
* lang_prov
,
302 IAnjutaEditor
* editor
,
303 IAnjutaIterable
* iter
,
304 IAnjutaIterable
** start_iter
,
305 const gchar
* word_characters
)
307 IAnjutaIterable
*end
= ianjuta_iterable_clone (iter
, NULL
);
308 IAnjutaIterable
*begin
= ianjuta_iterable_clone (iter
, NULL
);
309 gchar ch
, *preword_chars
= NULL
;
310 gboolean out_of_range
= FALSE
;
311 gboolean preword_found
= FALSE
;
313 /* Cursor points after the current characters, move back */
314 ianjuta_iterable_previous (begin
, NULL
);
316 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin
), 0, NULL
);
318 while (ch
&& anjuta_language_provider_is_character (ch
, word_characters
))
320 preword_found
= TRUE
;
321 if (!ianjuta_iterable_previous (begin
, NULL
))
326 ch
= ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin
), 0, NULL
);
332 ianjuta_iterable_next (begin
, NULL
);
333 preword_chars
= ianjuta_editor_get_text (editor
, begin
, end
, NULL
);
338 g_object_unref (begin
);
342 g_object_unref (end
);
343 return preword_chars
;
347 * anjuta_language_provider_calltip:
349 * @provider: (type GObject): IAnjutaLanguageProvider object
351 * Creates a calltip if there is something to show a tip for
352 * Calltips are queried async
354 * Returns: TRUE if a calltips was queried, FALSE otherwise
357 anjuta_language_provider_calltip (AnjutaLanguageProvider
* lang_prov
,
358 IAnjutaLanguageProvider
* provider
)
360 IAnjutaIterable
*iter
;
361 IAnjutaEditorTip
*tip
;
364 tip
= lang_prov
->priv
->itip
;
365 iter
= ianjuta_editor_get_position (IANJUTA_EDITOR (lang_prov
->priv
->iassist
),
367 ianjuta_iterable_previous (iter
, NULL
);
369 call_context
= ianjuta_language_provider_get_calltip_context (provider
,
373 DEBUG_PRINT ("Searching calltip for: %s", call_context
);
374 GList
*tips
= ianjuta_language_provider_get_calltip_cache (provider
,
380 if (!ianjuta_editor_tip_visible (tip
, NULL
))
381 ianjuta_editor_tip_show (tip
, tips
, iter
, NULL
);
386 if (ianjuta_editor_tip_visible (tip
, NULL
))
387 ianjuta_editor_tip_cancel (tip
, NULL
);
388 ianjuta_language_provider_new_calltip (provider
, call_context
, iter
,
392 g_free (call_context
);
397 if (ianjuta_editor_tip_visible (tip
, NULL
))
398 ianjuta_editor_tip_cancel (tip
, NULL
);
400 g_object_unref (iter
);
406 * anjuta_language_provider_none:
408 * @provider: (type GObject): IAnjutaLanguageProvider object
410 * Indicate that there is nothing to autocomplete
413 anjuta_language_provider_none (AnjutaLanguageProvider
* lang_prov
,
414 IAnjutaProvider
* provider
)
416 ianjuta_editor_assist_proposals (lang_prov
->priv
->iassist
, provider
, NULL
,
421 * anjuta_language_provider_activate:
423 * @iprov: (type GObject): IAnjutaProvider object
424 * @iter: (type GObject): the cursor
425 * @data: the ProposalData
427 * Complete the function name
430 anjuta_language_provider_activate (AnjutaLanguageProvider
* lang_prov
,
431 IAnjutaProvider
* iprov
,
432 IAnjutaIterable
* iter
,
435 AnjutaLanguageProposalData
*prop_data
;
437 IAnjutaEditor
*editor
= IANJUTA_EDITOR (lang_prov
->priv
->iassist
);
438 gboolean add_space_after_func
= FALSE
;
439 gboolean add_brace_after_func
= FALSE
;
440 gboolean add_closebrace_after_func
= FALSE
;
442 g_return_if_fail (data
!= NULL
);
444 assistance
= g_string_new (prop_data
->name
);
446 if (prop_data
->is_func
)
448 IAnjutaIterable
* next_brace
= anjuta_language_provider_find_next_brace (iter
);
449 add_space_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
450 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_SPACE_AFTER_FUNC
);
451 add_brace_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
452 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_BRACE_AFTER_FUNC
);
453 add_closebrace_after_func
= g_settings_get_boolean (lang_prov
->priv
->settings
,
454 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_CLOSEBRACE_AFTER_FUNC
);
456 if (add_space_after_func
457 && !anjuta_language_provider_find_whitespace (iter
))
458 g_string_append (assistance
, " ");
459 if (add_brace_after_func
&& !next_brace
)
460 g_string_append (assistance
, "(");
462 g_object_unref (next_brace
);
465 ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (editor
), NULL
);
467 if (ianjuta_iterable_compare (iter
, lang_prov
->priv
->start_iter
, NULL
) != 0)
469 ianjuta_editor_selection_set (IANJUTA_EDITOR_SELECTION (editor
),
470 lang_prov
->priv
->start_iter
, iter
, FALSE
,
472 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (editor
),
473 assistance
->str
, -1, NULL
);
476 ianjuta_editor_insert (editor
, iter
, assistance
->str
, -1, NULL
);
478 if (add_brace_after_func
&& add_closebrace_after_func
)
480 IAnjutaIterable
*next_brace
;
481 IAnjutaIterable
*pos
= ianjuta_iterable_clone (iter
, NULL
);
483 ianjuta_iterable_set_position (pos
,
484 ianjuta_iterable_get_position (
485 lang_prov
->priv
->start_iter
, NULL
)
486 + strlen (assistance
->str
),
488 next_brace
= anjuta_language_provider_find_next_brace (pos
);
490 ianjuta_editor_insert (editor
, pos
, ")", -1, NULL
);
494 ianjuta_iterable_next (pos
, NULL
);
497 ianjuta_editor_goto_position (editor
, pos
, NULL
);
499 ianjuta_iterable_previous (pos
, NULL
);
500 if (!prop_data
->has_para
)
502 pos
= ianjuta_editor_get_position (editor
, NULL
);
503 ianjuta_iterable_next (pos
, NULL
);
504 ianjuta_editor_goto_position (editor
, pos
, NULL
);
507 g_object_unref (pos
);
510 ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (editor
), NULL
);
512 /* Show calltip if we completed function */
513 if (add_brace_after_func
)
515 /* Check for calltip */
516 if (lang_prov
->priv
->itip
517 && g_settings_get_boolean (lang_prov
->priv
->settings
,
518 IANJUTA_LANGUAGE_PROVIDER_PREF_CALLTIP_ENABLE
))
520 anjuta_language_provider_calltip (
521 lang_prov
, IANJUTA_LANGUAGE_PROVIDER (iprov
));
524 g_string_free (assistance
, TRUE
);
528 * anjuta_language_provider_populate:
530 * @iprov: (type GObject): IAnjutaProvider object
531 * @cursor: (type GObject): the text iter where the provider should be populated
533 * Show completion for the context at position @iter. The provider should
534 * call ianjuta_editor_assist_proposals here to add proposals to the list.
537 anjuta_language_provider_populate (AnjutaLanguageProvider
* lang_prov
,
538 IAnjutaProvider
* iprov
,
539 IAnjutaIterable
* cursor
)
541 IAnjutaIterable
*start_iter
;
543 /* Check if this is a valid text region for completion */
544 IAnjutaEditorAttribute attrib
= ianjuta_editor_cell_get_attribute (
545 IANJUTA_EDITOR_CELL(cursor
), NULL
);
546 if (attrib
== IANJUTA_EDITOR_COMMENT
|| attrib
== IANJUTA_EDITOR_STRING
)
548 anjuta_language_provider_none (lang_prov
, iprov
);
552 /* Check for calltip */
553 if (g_settings_get_boolean (lang_prov
->priv
->settings
,
554 IANJUTA_LANGUAGE_PROVIDER_PREF_CALLTIP_ENABLE
))
556 anjuta_language_provider_calltip (lang_prov
,
557 IANJUTA_LANGUAGE_PROVIDER (iprov
));
560 /* Check if we actually want autocompletion at all */
561 if (!g_settings_get_boolean (lang_prov
->priv
->settings
,
562 IANJUTA_LANGUAGE_PROVIDER_PREF_AUTOCOMPLETE_ENABLE
))
564 anjuta_language_provider_none (lang_prov
, iprov
);
568 /* Execute language-specific part */
569 start_iter
= ianjuta_language_provider_populate_completions (
570 IANJUTA_LANGUAGE_PROVIDER (iprov
), cursor
, NULL
);
573 if (lang_prov
->priv
->start_iter
)
574 g_object_unref (lang_prov
->priv
->start_iter
);
575 lang_prov
->priv
->start_iter
= start_iter
;
579 /* Nothing to propose */
580 if (lang_prov
->priv
->start_iter
)
582 g_object_unref (lang_prov
->priv
->start_iter
);
583 lang_prov
->priv
->start_iter
= NULL
;
585 anjuta_language_provider_none (lang_prov
, iprov
);
589 * anjuta_language_provider_get_start_iter:
592 * Returns: (transfer full): the start iter
595 anjuta_language_provider_get_start_iter (AnjutaLanguageProvider
* lang_prov
)
597 return lang_prov
->priv
->start_iter
;
600 /* Boxed type for poposal data */
601 static AnjutaLanguageProposalData
*
602 anjuta_language_proposal_data_copy (const AnjutaLanguageProposalData
*src
)
604 AnjutaLanguageProposalData
* cpy
= anjuta_language_proposal_data_new (g_strdup(src
->name
));
605 cpy
->info
= src
->info
? g_strdup(src
->info
) : NULL
;
606 cpy
->is_func
= src
->is_func
;
607 cpy
->has_para
= src
->has_para
;
608 cpy
->type
= src
->type
;
614 * anjuta_language_proposal_data_free:
615 * @data: a AnjutaLanguageProposalData
617 * Free the given proposal data
620 anjuta_language_proposal_data_free (AnjutaLanguageProposalData
*data
)
628 * anjuta_language_proposal_data_new:
629 * @name: Name of the object
631 * Returns: Creates a new AnjutaLanguageProposalData object
633 AnjutaLanguageProposalData
*
634 anjuta_language_proposal_data_new (gchar
* name
)
636 AnjutaLanguageProposalData
* data
= g_new0(AnjutaLanguageProposalData
, 1);
643 anjuta_language_proposal_data_get_type ()
645 static GType type_id
= 0;
648 type_id
= g_boxed_type_register_static ("AnjutaLanguageProposalData",
649 (GBoxedCopyFunc
) anjuta_language_proposal_data_copy
,
650 (GBoxedFreeFunc
) anjuta_language_proposal_data_free
);