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>
5  *
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.
10  *
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.
15  *
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
19  */
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>
32 
33 #define SCOPE_BRACE_JUMP_LIMIT 50
34 #define BRACE_SEARCH_LIMIT 500
35 
36 G_DEFINE_TYPE (AnjutaLanguageProvider, anjuta_language_provider, G_TYPE_OBJECT);
37 
38 struct _AnjutaLanguageProviderPriv {
39 	GSettings* settings;
40 	IAnjutaEditorAssist* iassist;
41 	IAnjutaEditorTip* itip;
42 
43 	/* Autocompletion */
44 	IAnjutaIterable* start_iter;
45 };
46 
47 /**
48  * anjuta_language_provider_install:
49  * @lang_prov: Self
50  * @ieditor: (type GObject): IAnjutaEditor object
51  * @settings: the settings
52  *
53  * Install the settings for AnjutaLanguageProvider
54  */
55 void
anjuta_language_provider_install(AnjutaLanguageProvider * lang_prov,IAnjutaEditor * ieditor,GSettings * settings)56 anjuta_language_provider_install (AnjutaLanguageProvider *lang_prov,
57                                   IAnjutaEditor *ieditor,
58                                   GSettings* settings)
59 {
60 	g_return_if_fail (lang_prov->priv->iassist == NULL);
61 
62 	if (IANJUTA_IS_EDITOR_ASSIST (ieditor))
63 		lang_prov->priv->iassist = IANJUTA_EDITOR_ASSIST (ieditor);
64 	else
65 		lang_prov->priv->iassist = NULL;
66 
67 	if (IANJUTA_IS_EDITOR_TIP (ieditor))
68 		lang_prov->priv->itip = IANJUTA_EDITOR_TIP (ieditor);
69 	else
70 		lang_prov->priv->itip = NULL;
71 
72 	lang_prov->priv->settings = settings;
73 }
74 
75 static void
anjuta_language_provider_uninstall(AnjutaLanguageProvider * lang_prov)76 anjuta_language_provider_uninstall (AnjutaLanguageProvider *lang_prov)
77 {
78 	g_return_if_fail (lang_prov->priv->iassist != NULL);
79 
80 	lang_prov->priv->iassist = NULL;
81 }
82 
83 static void
anjuta_language_provider_init(AnjutaLanguageProvider * lang_prov)84 anjuta_language_provider_init (AnjutaLanguageProvider *lang_prov)
85 {
86 	lang_prov->priv = g_new0 (AnjutaLanguageProviderPriv, 1);
87 }
88 
89 static void
anjuta_language_provider_finalize(GObject * object)90 anjuta_language_provider_finalize (GObject *object)
91 {
92 	AnjutaLanguageProvider *lang_prov;
93 
94 	lang_prov = ANJUTA_LANGUAGE_PROVIDER (object);
95 
96 	anjuta_language_provider_uninstall (lang_prov);
97 	g_free (lang_prov->priv);
98 
99 	G_OBJECT_CLASS (anjuta_language_provider_parent_class)->finalize (object);
100 }
101 
102 static void
anjuta_language_provider_class_init(AnjutaLanguageProviderClass * klass)103 anjuta_language_provider_class_init (AnjutaLanguageProviderClass *klass)
104 {
105 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
106 	object_class->finalize = anjuta_language_provider_finalize;
107 }
108 
109 /**
110  * anjuta_language_provider_find_next_brace:
111  * @iter: (type GObject): Iter to start searching at
112  *
113  * Returns: (type GObject): The position of the brace, if the next non-whitespace character is a
114  * opening brace, %NULL otherwise
115  */
116 static IAnjutaIterable*
anjuta_language_provider_find_next_brace(IAnjutaIterable * iter)117 anjuta_language_provider_find_next_brace (IAnjutaIterable* iter)
118 {
119 	IAnjutaIterable* current_iter = ianjuta_iterable_clone (iter, NULL);
120 	gchar ch;
121 	do
122 	{
123 		ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (current_iter),
124 		                                   0, NULL);
125 		if (ch == '(')
126 			return current_iter;
127 	}
128 	while (g_ascii_isspace (ch) && ianjuta_iterable_next (current_iter, NULL));
129 
130 	g_object_unref (current_iter);
131 	return NULL;
132 }
133 
134 /**
135  * anjuta_language_provider_find_whitespace:
136  * @iter: (type GObject): Iter to start searching at
137  *
138  * Returns: %TRUE if the next character is a whitespace character,
139  * %FALSE otherwise
140  */
141 static gboolean
anjuta_language_provider_find_whitespace(IAnjutaIterable * iter)142 anjuta_language_provider_find_whitespace (IAnjutaIterable* iter)
143 {
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))
148 	{
149 		return TRUE;
150 	}
151 	else
152 		return FALSE;
153 }
154 
155 /**
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
160  *
161  * Returns: if the current character seperates a scope
162  */
163 static gboolean
anjuta_language_provider_is_character(gchar ch,const gchar * characters)164 anjuta_language_provider_is_character (gchar ch, const gchar* characters)
165 {
166 	int i;
167 
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++)
173 	{
174 		if (ch == characters[i])
175 			return TRUE;
176 	}
177 
178 	return FALSE;
179 }
180 
181 /**
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
187  *
188  * Find the scope context for calltips
189  */
190 static gchar*
anjuta_language_provider_get_scope_context(IAnjutaEditor * editor,IAnjutaIterable * iter,const gchar * scope_context_ch)191 anjuta_language_provider_get_scope_context (IAnjutaEditor* editor,
192                                             IAnjutaIterable *iter,
193                                             const gchar* scope_context_ch)
194 {
195 	IAnjutaIterable* end;
196 	gchar ch, *scope_chars = NULL;
197 	gboolean out_of_range = FALSE;
198 	gboolean scope_chars_found = FALSE;
199 
200 	end = ianjuta_iterable_clone (iter, NULL);
201 	ianjuta_iterable_next (end, NULL);
202 
203 	ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
204 
205 	while (ch)
206 	{
207 		if (anjuta_language_provider_is_character (ch, scope_context_ch))
208 			scope_chars_found = TRUE;
209 		else if (ch == ')')
210 		{
211 			if (!anjuta_util_jump_to_matching_brace (iter, ch,
212 						                             SCOPE_BRACE_JUMP_LIMIT))
213 			{
214 				out_of_range = TRUE;
215 				break;
216 			}
217 		}
218 		else
219 			break;
220 		if (!ianjuta_iterable_previous (iter, NULL))
221 		{
222 			out_of_range = TRUE;
223 			break;
224 		}
225 		ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
226 	}
227 	if (scope_chars_found)
228 	{
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);
235 	}
236 	g_object_unref (end);
237 	return scope_chars;
238 }
239 
240 /**
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
246  *
247  * Searches for a calltip context
248  *
249  * Returns: name of the method to show a calltip for or %NULL
250  */
251 gchar*
anjuta_language_provider_get_calltip_context(AnjutaLanguageProvider * lang_prov,IAnjutaEditorTip * itip,IAnjutaIterable * iter,const gchar * scope_context_ch)252 anjuta_language_provider_get_calltip_context (AnjutaLanguageProvider* lang_prov,
253                                               IAnjutaEditorTip* itip,
254 		                                      IAnjutaIterable* iter,
255                                               const gchar* scope_context_ch)
256 {
257 	gchar ch;
258 	gchar *context = NULL;
259 
260 	ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0, NULL);
261 	if (ch == ')')
262 	{
263 		if (!anjuta_util_jump_to_matching_brace (iter, ')', -1))
264 			return NULL;
265 		if (!ianjuta_iterable_previous (iter, NULL))
266 			return NULL;
267 	}
268 	if (ch != '(')
269 	{
270 		if (!anjuta_util_jump_to_matching_brace (iter, ')', BRACE_SEARCH_LIMIT))
271 			return NULL;
272 	}
273 
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)));
278 
279 	context = anjuta_language_provider_get_scope_context (IANJUTA_EDITOR (itip),
280 			                                          iter,
281 													  scope_context_ch);
282 
283 	/* Point iter to the first character of the scope to align calltip correctly */
284 	ianjuta_iterable_next (iter, NULL);
285 
286 	return context;
287 }
288 
289 /**
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)
295  *
296  * Search for the current typed word
297  *
298  * Returns: (transfer full) (allow-none): The current word (needs to be freed)
299  * or %NULL if no word was found
300  */
301 gchar*
anjuta_language_provider_get_pre_word(AnjutaLanguageProvider * lang_prov,IAnjutaEditor * editor,IAnjutaIterable * iter,IAnjutaIterable ** start_iter,const gchar * word_characters)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)
307 {
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;
313 
314 	/* Cursor points after the current characters, move back */
315 	ianjuta_iterable_previous (begin, NULL);
316 
317 	ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin), 0, NULL);
318 
319 	while (ch && anjuta_language_provider_is_character (ch, word_characters))
320 	{
321 		preword_found = TRUE;
322 		if (!ianjuta_iterable_previous (begin, NULL))
323 		{
324 			out_of_range = TRUE;
325 			break;
326 		}
327 		ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (begin), 0, NULL);
328 	}
329 
330 	if (preword_found)
331 	{
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;
336 	}
337 	else
338 	{
339 		g_object_unref (begin);
340 		*start_iter = NULL;
341 	}
342 
343 	g_object_unref (end);
344 	return preword_chars;
345 }
346 
347 /**
348  * anjuta_language_provider_calltip:
349  * @lang_prov: Self
350  * @provider: (type GObject): IAnjutaLanguageProvider object
351  *
352  * Creates a calltip if there is something to show a tip for
353  * Calltips are queried async
354  *
355  * Returns: %TRUE if a calltips was queried, %FALSE otherwise
356  */
357 static gboolean
anjuta_language_provider_calltip(AnjutaLanguageProvider * lang_prov,IAnjutaLanguageProvider * provider)358 anjuta_language_provider_calltip (AnjutaLanguageProvider* lang_prov,
359                                   IAnjutaLanguageProvider* provider)
360 {
361 	IAnjutaIterable *iter;
362 	IAnjutaEditorTip *tip;
363 	gchar *call_context;
364 
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);
369 
370 	call_context = ianjuta_language_provider_get_calltip_context (provider,
371 	                                                              iter, NULL);
372 	if (call_context)
373 	{
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)
379 		{
380 			/* Continue tip */
381 			if (!ianjuta_editor_tip_visible (tip, NULL))
382 				ianjuta_editor_tip_show (tip, tips, iter, NULL);
383 		}
384 		else
385 		{
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);
391 		}
392 
393 		g_free (call_context);
394 		return TRUE;
395 	}
396 	else
397 	{
398 		if (ianjuta_editor_tip_visible (tip, NULL))
399 			ianjuta_editor_tip_cancel (tip, NULL);
400 
401 		g_object_unref (iter);
402 		return FALSE;
403 	}
404 }
405 
406 /**
407  * anjuta_language_provider_none:
408  * @lang_prov: Self
409  * @provider: (type GObject): IAnjutaLanguageProvider object
410  *
411  * Indicate that there is nothing to autocomplete
412  */
413 static void
anjuta_language_provider_none(AnjutaLanguageProvider * lang_prov,IAnjutaProvider * provider)414 anjuta_language_provider_none (AnjutaLanguageProvider* lang_prov,
415                                IAnjutaProvider * provider)
416 {
417 	ianjuta_editor_assist_proposals (lang_prov->priv->iassist, provider, NULL,
418 	                                 NULL, TRUE, NULL);
419 }
420 
421 /**
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
427  *
428  * Complete the function name
429  */
430 void
anjuta_language_provider_activate(AnjutaLanguageProvider * lang_prov,IAnjutaProvider * iprov,IAnjutaIterable * iter,gpointer data)431 anjuta_language_provider_activate (AnjutaLanguageProvider* lang_prov,
432                                    IAnjutaProvider* iprov,
433                                    IAnjutaIterable* iter,
434                                    gpointer data)
435 {
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;
442 
443 	g_return_if_fail (data != NULL);
444 	prop_data = data;
445 	assistance = g_string_new (prop_data->name);
446 
447 	if (prop_data->is_func)
448 	{
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);
456 
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);
464 	}
465 
466 	ianjuta_document_begin_undo_action (IANJUTA_DOCUMENT (editor), NULL);
467 
468 	if (ianjuta_iterable_compare (iter, lang_prov->priv->start_iter, NULL) != 0)
469 	{
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);
475 	}
476 	else
477 		ianjuta_editor_insert (editor, iter, assistance->str, -1, NULL);
478 
479 	if (add_brace_after_func && add_closebrace_after_func)
480 	{
481 		IAnjutaIterable *next_brace;
482 		IAnjutaIterable *pos = ianjuta_iterable_clone (iter, NULL);
483 
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
493 		{
494 			pos = next_brace;
495 			ianjuta_iterable_next (pos, NULL);
496 		}
497 
498 		ianjuta_editor_goto_position (editor, pos, NULL);
499 
500 		ianjuta_iterable_previous (pos, NULL);
501 		if (!prop_data->has_para)
502 		{
503 			pos = ianjuta_editor_get_position (editor, NULL);
504 			ianjuta_iterable_next (pos, NULL);
505 			ianjuta_editor_goto_position (editor, pos, NULL);
506 		}
507 
508 		g_object_unref (pos);
509 	}
510 
511 	ianjuta_document_end_undo_action (IANJUTA_DOCUMENT (editor), NULL);
512 
513 	/* Show calltip if we completed function */
514 	if (add_brace_after_func)
515 	{
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))
520 		{
521 			anjuta_language_provider_calltip (
522 				                lang_prov, IANJUTA_LANGUAGE_PROVIDER (iprov));
523 		}
524 	}
525 	g_string_free (assistance, TRUE);
526 }
527 
528 /**
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
533  *
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.
536  */
537 void
anjuta_language_provider_populate(AnjutaLanguageProvider * lang_prov,IAnjutaProvider * iprov,IAnjutaIterable * cursor)538 anjuta_language_provider_populate (AnjutaLanguageProvider* lang_prov,
539                                    IAnjutaProvider* iprov,
540                                    IAnjutaIterable* cursor)
541 {
542 	IAnjutaIterable *start_iter;
543 
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)
548 	{
549 		anjuta_language_provider_none (lang_prov, iprov);
550 		return;
551 	}
552 
553 	/* Check for calltip */
554 	if (g_settings_get_boolean (lang_prov->priv->settings,
555 	                            IANJUTA_LANGUAGE_PROVIDER_PREF_CALLTIP_ENABLE))
556 	{
557 		anjuta_language_provider_calltip (lang_prov,
558 		                                  IANJUTA_LANGUAGE_PROVIDER (iprov));
559 	}
560 
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))
564 	{
565 		anjuta_language_provider_none (lang_prov, iprov);
566 		return;
567 	}
568 
569 	/* Execute language-specific part */
570 	start_iter = ianjuta_language_provider_populate_completions (
571 	                     IANJUTA_LANGUAGE_PROVIDER (iprov), cursor, NULL);
572 	if (start_iter)
573 	{
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;
578 	}
579 
580 	/* Nothing to propose */
581 	if (lang_prov->priv->start_iter)
582 	{
583 		g_object_unref (lang_prov->priv->start_iter);
584 		lang_prov->priv->start_iter = NULL;
585 	}
586 	anjuta_language_provider_none (lang_prov, iprov);
587 }
588 
589 /**
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
596  *
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()
601  */
602 void
anjuta_language_provider_proposals(AnjutaLanguageProvider * lang_prov,IAnjutaProvider * iprov,GList * proposals,const gchar * pre_word,gboolean finished)603 anjuta_language_provider_proposals (AnjutaLanguageProvider* lang_prov,
604                                     IAnjutaProvider* iprov,
605                                     GList* proposals,
606                                     const gchar* pre_word,
607                                     gboolean finished)
608 {
609 	/* Hide if the only suggestion is exactly the typed word */
610 	if (pre_word && proposals && g_list_length (proposals) == 1)
611 	{
612 		IAnjutaEditorAssistProposal* proposal = proposals->data;
613 		AnjutaLanguageProposalData* data = proposal->data;
614 		if (g_str_equal (pre_word, data->name))
615 			proposals = NULL;
616 	}
617 
618 	ianjuta_editor_assist_proposals (lang_prov->priv->iassist, iprov, proposals,
619 	                                 pre_word, finished, NULL);
620 }
621 
622 /**
623  * anjuta_language_provider_get_start_iter:
624  * @lang_prov: Self
625  *
626  * Returns: (transfer full): the start iter
627  */
628 IAnjutaIterable*
anjuta_language_provider_get_start_iter(AnjutaLanguageProvider * lang_prov)629 anjuta_language_provider_get_start_iter (AnjutaLanguageProvider* lang_prov)
630 {
631 	return lang_prov->priv->start_iter;
632 }
633 
634 /* Boxed type for poposal data */
635 static AnjutaLanguageProposalData*
anjuta_language_proposal_data_copy(const AnjutaLanguageProposalData * src)636 anjuta_language_proposal_data_copy (const AnjutaLanguageProposalData *src)
637 {
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;
643 
644 	return cpy;
645 }
646 
647 /**
648  * anjuta_language_proposal_data_free:
649  * @data: a AnjutaLanguageProposalData
650  *
651  * Free the given proposal data
652  */
653 void
anjuta_language_proposal_data_free(AnjutaLanguageProposalData * data)654 anjuta_language_proposal_data_free (AnjutaLanguageProposalData *data)
655 {
656 	g_free (data->name);
657 	g_free (data->info);
658 	g_free (data);
659 }
660 
661 /**
662  * anjuta_language_proposal_data_new:
663  * @name: Name of the object
664  *
665  * Returns: (transfer full): Creates a new AnjutaLanguageProposalData object
666  */
667 AnjutaLanguageProposalData*
anjuta_language_proposal_data_new(gchar * name)668 anjuta_language_proposal_data_new (gchar* name)
669 {
670 	AnjutaLanguageProposalData* data = g_new0(AnjutaLanguageProposalData, 1);
671 	data->name = name;
672 
673 	return data;
674 }
675 
676 GType
anjuta_language_proposal_data_get_type()677 anjuta_language_proposal_data_get_type ()
678 {
679 	static GType type_id = 0;
680 
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;
686 }
687 
688