Updated Spanish translation
[anjuta.git] / libanjuta / anjuta-language-provider.c
blobeb673eb703b11e166ca8daa50244464d336f2b63
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
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
20 #include <ctype.h>
21 #include <string.h>
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 {
39 GSettings* settings;
40 IAnjutaEditorAssist* iassist;
41 IAnjutaEditorTip* itip;
43 /* Autocompletion */
44 IAnjutaIterable* start_iter;
47 /**
48 * anjuta_language_provider_install:
49 * @lang_prov: Self
50 * @ieditor: (type GObject): IAnjutaEditor object
51 * @settings: the settings
53 * Install the settings for AnjutaLanguageProvider
55 void
56 anjuta_language_provider_install (AnjutaLanguageProvider *lang_prov,
57 IAnjutaEditor *ieditor,
58 GSettings* settings)
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);
64 else
65 lang_prov->priv->iassist = NULL;
67 if (IANJUTA_IS_EDITOR_TIP (ieditor))
68 lang_prov->priv->itip = IANJUTA_EDITOR_TIP (ieditor);
69 else
70 lang_prov->priv->itip = NULL;
72 lang_prov->priv->settings = settings;
75 static void
76 anjuta_language_provider_uninstall (AnjutaLanguageProvider *lang_prov)
78 g_return_if_fail (lang_prov->priv->iassist != NULL);
80 lang_prov->priv->iassist = NULL;
83 static void
84 anjuta_language_provider_init (AnjutaLanguageProvider *lang_prov)
86 lang_prov->priv = g_new0 (AnjutaLanguageProviderPriv, 1);
89 static void
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);
102 static void
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);
120 gchar ch;
123 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (current_iter),
124 0, NULL);
125 if (ch == '(')
126 return current_iter;
128 while (g_ascii_isspace (ch) && ianjuta_iterable_next (current_iter, NULL));
130 g_object_unref (current_iter);
131 return NULL;
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,
139 * %FALSE otherwise
141 static gboolean
142 anjuta_language_provider_find_whitespace (IAnjutaIterable* iter)
144 gchar ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter),
145 0, NULL);
146 if (g_ascii_isspace (ch) && ch != '\n'
147 && anjuta_language_provider_find_next_brace (iter))
149 return TRUE;
151 else
152 return FALSE;
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
163 static gboolean
164 anjuta_language_provider_is_character (gchar ch, const gchar* characters)
166 int i;
168 if (g_ascii_isspace (ch))
169 return FALSE;
170 if (g_ascii_isalnum (ch))
171 return TRUE;
172 for (i = 0; characters[i] != '0'; i++)
174 if (ch == characters[i])
175 return TRUE;
178 return FALSE;
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
190 static gchar*
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);
205 while (ch)
207 if (anjuta_language_provider_is_character (ch, scope_context_ch))
208 scope_chars_found = TRUE;
209 else if (ch == ')')
211 if (!anjuta_util_jump_to_matching_brace (iter, ch,
212 SCOPE_BRACE_JUMP_LIMIT))
214 out_of_range = TRUE;
215 break;
218 else
219 break;
220 if (!ianjuta_iterable_previous (iter, NULL))
222 out_of_range = TRUE;
223 break;
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);
231 if (!out_of_range)
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);
237 return scope_chars;
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
251 gchar*
252 anjuta_language_provider_get_calltip_context (AnjutaLanguageProvider* lang_prov,
253 IAnjutaEditorTip* itip,
254 IAnjutaIterable* iter,
255 const gchar* scope_context_ch)
257 gchar ch;
258 gchar *context = NULL;
260 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
261 if (ch == ')')
263 if (!anjuta_util_jump_to_matching_brace (iter, ')', -1))
264 return NULL;
265 if (!ianjuta_iterable_previous (iter, NULL))
266 return NULL;
268 if (ch != '(')
270 if (!anjuta_util_jump_to_matching_brace (iter, ')', BRACE_SEARCH_LIMIT))
271 return NULL;
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),
280 iter,
281 scope_context_ch);
283 /* Point iter to the first character of the scope to align calltip correctly */
284 ianjuta_iterable_next (iter, NULL);
286 return context;
290 * anjuta_language_provider_get_pre_word:
291 * @lang_prov: Self
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
301 gchar*
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))
324 out_of_range = TRUE;
325 break;
327 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin), 0, NULL);
330 if (preword_found)
332 if (!out_of_range)
333 ianjuta_iterable_next (begin, NULL);
334 preword_chars = ianjuta_editor_get_text (editor, begin, end, NULL);
335 *start_iter = begin;
337 else
339 g_object_unref (begin);
340 *start_iter = NULL;
343 g_object_unref (end);
344 return preword_chars;
348 * anjuta_language_provider_calltip:
349 * @lang_prov: Self
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
357 static gboolean
358 anjuta_language_provider_calltip (AnjutaLanguageProvider* lang_prov,
359 IAnjutaLanguageProvider* provider)
361 IAnjutaIterable *iter;
362 IAnjutaEditorTip *tip;
363 gchar *call_context;
365 tip = lang_prov->priv->itip;
366 iter = ianjuta_editor_get_position (IANJUTA_EDITOR (lang_prov->priv->iassist),
367 NULL);
368 ianjuta_iterable_previous (iter, NULL);
370 call_context = ianjuta_language_provider_get_calltip_context (provider,
371 iter, NULL);
372 if (call_context)
374 DEBUG_PRINT ("Searching calltip for: %s", call_context);
375 GList *tips = ianjuta_language_provider_get_calltip_cache (provider,
376 call_context,
377 NULL);
378 if (tips)
380 /* Continue tip */
381 if (!ianjuta_editor_tip_visible (tip, NULL))
382 ianjuta_editor_tip_show (tip, tips, iter, NULL);
384 else
386 /* New tip */
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,
390 NULL);
393 g_free (call_context);
394 return TRUE;
396 else
398 if (ianjuta_editor_tip_visible (tip, NULL))
399 ianjuta_editor_tip_cancel (tip, NULL);
401 g_object_unref (iter);
402 return FALSE;
407 * anjuta_language_provider_none:
408 * @lang_prov: Self
409 * @provider: (type GObject): IAnjutaLanguageProvider object
411 * Indicate that there is nothing to autocomplete
413 static void
414 anjuta_language_provider_none (AnjutaLanguageProvider* lang_prov,
415 IAnjutaProvider * provider)
417 ianjuta_editor_assist_proposals (lang_prov->priv->iassist, provider, NULL,
418 NULL, TRUE, NULL);
422 * anjuta_language_provider_activate:
423 * @lang_prov: Self
424 * @iprov: (type GObject): IAnjutaProvider object
425 * @iter: (type GObject): the cursor
426 * @data: the ProposalData
428 * Complete the function name
430 void
431 anjuta_language_provider_activate (AnjutaLanguageProvider* lang_prov,
432 IAnjutaProvider* iprov,
433 IAnjutaIterable* iter,
434 gpointer data)
436 AnjutaLanguageProposalData *prop_data;
437 GString *assistance;
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);
444 prop_data = data;
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, "(");
462 else
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,
472 NULL);
473 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (editor),
474 assistance->str, -1, NULL);
476 else
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),
488 NULL);
489 next_brace = anjuta_language_provider_find_next_brace (pos);
490 if (!next_brace)
491 ianjuta_editor_insert (editor, pos, ")", -1, NULL);
492 else
494 pos = next_brace;
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:
530 * @lang_prov: Self
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.
537 void
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);
550 return;
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);
566 return;
569 /* Execute language-specific part */
570 start_iter = ianjuta_language_provider_populate_completions (
571 IANJUTA_LANGUAGE_PROVIDER (iprov), cursor, NULL);
572 if (start_iter)
574 if (lang_prov->priv->start_iter)
575 g_object_unref (lang_prov->priv->start_iter);
576 lang_prov->priv->start_iter = start_iter;
577 return;
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:
591 * @lang_prov: Self
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()
602 void
603 anjuta_language_provider_proposals (AnjutaLanguageProvider* lang_prov,
604 IAnjutaProvider* iprov,
605 GList* proposals,
606 const gchar* pre_word,
607 gboolean finished)
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))
615 proposals = NULL;
618 ianjuta_editor_assist_proposals (lang_prov->priv->iassist, iprov, proposals,
619 pre_word, finished, NULL);
623 * anjuta_language_provider_get_start_iter:
624 * @lang_prov: Self
626 * Returns: (transfer full): the start iter
628 IAnjutaIterable*
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;
644 return cpy;
648 * anjuta_language_proposal_data_free:
649 * @data: a AnjutaLanguageProposalData
651 * Free the given proposal data
653 void
654 anjuta_language_proposal_data_free (AnjutaLanguageProposalData *data)
656 g_free (data->name);
657 g_free (data->info);
658 g_free (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);
671 data->name = name;
673 return data;
676 GType
677 anjuta_language_proposal_data_get_type ()
679 static GType type_id = 0;
681 if (!type_id)
682 type_id = g_boxed_type_register_static ("AnjutaLanguageProposalData",
683 (GBoxedCopyFunc) anjuta_language_proposal_data_copy,
684 (GBoxedFreeFunc) anjuta_language_proposal_data_free);
685 return type_id;