Updated Spanish translation
[anjuta.git] / libanjuta / anjuta-language-provider.c
blob3d06b60b440c952a05f62b6aaf73e8fb224be55f
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: The current word (needs to be freed) or NULL if no word was found
300 gchar*
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))
323 out_of_range = TRUE;
324 break;
326 ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin), 0, NULL);
329 if (preword_found)
331 if (!out_of_range)
332 ianjuta_iterable_next (begin, NULL);
333 preword_chars = ianjuta_editor_get_text (editor, begin, end, NULL);
334 *start_iter = begin;
336 else
338 g_object_unref (begin);
339 *start_iter = NULL;
342 g_object_unref (end);
343 return preword_chars;
347 * anjuta_language_provider_calltip:
348 * @lang_prov: Self
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
356 static gboolean
357 anjuta_language_provider_calltip (AnjutaLanguageProvider* lang_prov,
358 IAnjutaLanguageProvider* provider)
360 IAnjutaIterable *iter;
361 IAnjutaEditorTip *tip;
362 gchar *call_context;
364 tip = lang_prov->priv->itip;
365 iter = ianjuta_editor_get_position (IANJUTA_EDITOR (lang_prov->priv->iassist),
366 NULL);
367 ianjuta_iterable_previous (iter, NULL);
369 call_context = ianjuta_language_provider_get_calltip_context (provider,
370 iter, NULL);
371 if (call_context)
373 DEBUG_PRINT ("Searching calltip for: %s", call_context);
374 GList *tips = ianjuta_language_provider_get_calltip_cache (provider,
375 call_context,
376 NULL);
377 if (tips)
379 /* Continue tip */
380 if (!ianjuta_editor_tip_visible (tip, NULL))
381 ianjuta_editor_tip_show (tip, tips, iter, NULL);
383 else
385 /* New tip */
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,
389 NULL);
392 g_free (call_context);
393 return TRUE;
395 else
397 if (ianjuta_editor_tip_visible (tip, NULL))
398 ianjuta_editor_tip_cancel (tip, NULL);
400 g_object_unref (iter);
401 return FALSE;
406 * anjuta_language_provider_none:
407 * @lang_prov: Self
408 * @provider: (type GObject): IAnjutaLanguageProvider object
410 * Indicate that there is nothing to autocomplete
412 static void
413 anjuta_language_provider_none (AnjutaLanguageProvider* lang_prov,
414 IAnjutaProvider * provider)
416 ianjuta_editor_assist_proposals (lang_prov->priv->iassist, provider, NULL,
417 NULL, TRUE, NULL);
421 * anjuta_language_provider_activate:
422 * @lang_prov: Self
423 * @iprov: (type GObject): IAnjutaProvider object
424 * @iter: (type GObject): the cursor
425 * @data: the ProposalData
427 * Complete the function name
429 void
430 anjuta_language_provider_activate (AnjutaLanguageProvider* lang_prov,
431 IAnjutaProvider* iprov,
432 IAnjutaIterable* iter,
433 gpointer data)
435 AnjutaLanguageProposalData *prop_data;
436 GString *assistance;
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);
443 prop_data = data;
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, "(");
461 else
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,
471 NULL);
472 ianjuta_editor_selection_replace (IANJUTA_EDITOR_SELECTION (editor),
473 assistance->str, -1, NULL);
475 else
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),
487 NULL);
488 next_brace = anjuta_language_provider_find_next_brace (pos);
489 if (!next_brace)
490 ianjuta_editor_insert (editor, pos, ")", -1, NULL);
491 else
493 pos = next_brace;
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:
529 * @lang_prov: Self
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.
536 void
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);
549 return;
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);
565 return;
568 /* Execute language-specific part */
569 start_iter = ianjuta_language_provider_populate_completions (
570 IANJUTA_LANGUAGE_PROVIDER (iprov), cursor, NULL);
571 if (start_iter)
573 if (lang_prov->priv->start_iter)
574 g_object_unref (lang_prov->priv->start_iter);
575 lang_prov->priv->start_iter = start_iter;
576 return;
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:
590 * @lang_prov: Self
592 * Returns: (transfer full): the start iter
594 IAnjutaIterable*
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;
610 return cpy;
614 * anjuta_language_proposal_data_free:
615 * @data: a AnjutaLanguageProposalData
617 * Free the given proposal data
619 void
620 anjuta_language_proposal_data_free (AnjutaLanguageProposalData *data)
622 g_free (data->name);
623 g_free (data->info);
624 g_free (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);
637 data->name = name;
639 return data;
642 GType
643 anjuta_language_proposal_data_get_type ()
645 static GType type_id = 0;
647 if (!type_id)
648 type_id = g_boxed_type_register_static ("AnjutaLanguageProposalData",
649 (GBoxedCopyFunc) anjuta_language_proposal_data_copy,
650 (GBoxedFreeFunc) anjuta_language_proposal_data_free);
651 return type_id;