static gboolean ide_ctags_completion_provider_match (GtkSourceCompletionProvider *provider, GtkSourceCompletionContext *context) { IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider; GtkSourceCompletionActivation activation; GtkTextIter iter; g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context)); if (!gtk_source_completion_context_get_iter (context, &iter)) return FALSE; activation = gtk_source_completion_context_get_activation (context); if (activation == GTK_SOURCE_COMPLETION_ACTIVATION_INTERACTIVE) { if (gtk_text_iter_starts_line (&iter) || !gtk_text_iter_backward_char (&iter) || g_unichar_isspace (gtk_text_iter_get_char (&iter))) return FALSE; } if (!g_settings_get_boolean (self->settings, "ctags-autocompletion")) return FALSE; if (ide_completion_provider_context_in_comment (context)) return FALSE; return TRUE; }
void ide_ctags_completion_provider_add_index (IdeCtagsCompletionProvider *self, IdeCtagsIndex *index) { GFile *file; gsize i; IDE_ENTRY; g_return_if_fail (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_return_if_fail (!index || IDE_IS_CTAGS_INDEX (index)); g_return_if_fail (self->indexes != NULL); file = ide_ctags_index_get_file (index); for (i = 0; i < self->indexes->len; i++) { IdeCtagsIndex *item = g_ptr_array_index (self->indexes, i); GFile *item_file = ide_ctags_index_get_file (item); if (g_file_equal (item_file, file)) { g_ptr_array_remove_index_fast (self->indexes, i); g_ptr_array_add (self->indexes, g_object_ref (index)); IDE_EXIT; } } g_ptr_array_add (self->indexes, g_object_ref (index)); IDE_EXIT; }
static GdkPixbuf * load_pixbuf (IdeCtagsCompletionProvider *self, GtkSourceCompletionContext *context, const gchar *icon_name, guint size) { GtkSourceCompletion *completion = NULL; GtkSourceCompletionInfo *window; GtkStyleContext *style_context; GtkIconTheme *icon_theme; GtkIconInfo *icon_info; GdkPixbuf *ret = NULL; gboolean was_symbolic; g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context)); g_object_get (context, "completion", &completion, NULL); window = gtk_source_completion_get_info_window (completion); style_context = gtk_widget_get_style_context (GTK_WIDGET (window)); icon_theme = gtk_icon_theme_get_default (); icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size, 0); if (icon_info != NULL) ret = gtk_icon_info_load_symbolic_for_context (icon_info, style_context, &was_symbolic, NULL); g_clear_object (&completion); g_clear_object (&icon_info); if (ret != NULL) g_hash_table_insert (self->icons, g_strdup (icon_name), ret); return ret; }
GdkPixbuf * ide_ctags_completion_provider_get_proposal_icon (IdeCtagsCompletionProvider *self, GtkSourceCompletionContext *context, const IdeCtagsIndexEntry *entry) { g_return_val_if_fail (IDE_IS_CTAGS_COMPLETION_PROVIDER (self), NULL); return get_pixbuf (self, context, entry); }
static void theme_changed_cb (IdeCtagsCompletionProvider *self, GParamSpec *pspec, GtkSettings *settings) { g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_assert (self->icons != NULL); g_hash_table_remove_all (self->icons); }
static void ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider, GtkSourceCompletionContext *context) { IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider; const gchar * const *allowed; g_autofree gchar *casefold = NULL; gint word_len; guint i; guint j; IDE_ENTRY; g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context)); g_clear_pointer (&self->current_word, g_free); self->current_word = ide_completion_provider_context_current_word (context); allowed = get_allowed_suffixes (context); if (self->results != NULL) { if (ide_completion_results_replay (self->results, self->current_word)) { ide_completion_results_present (self->results, provider, context); IDE_EXIT; } g_clear_pointer (&self->results, g_object_unref); } word_len = strlen (self->current_word); if (word_len < self->minimum_word_size) IDE_GOTO (word_too_small); casefold = g_utf8_casefold (self->current_word, -1); self->results = ide_completion_results_new (self->current_word); for (i = 0; i < self->indexes->len; i++) { g_autofree gchar *copy = g_strdup (self->current_word); IdeCtagsIndex *index = g_ptr_array_index (self->indexes, i); const IdeCtagsIndexEntry *entries = NULL; const gchar *last_name = NULL; guint tmp_len = word_len; gsize n_entries = 0; while (entries == NULL && *copy) { if (!(entries = ide_ctags_index_lookup_prefix (index, copy, &n_entries))) copy [--tmp_len] = '\0'; } if ((entries == NULL) || (n_entries == 0)) continue; for (j = 0; j < n_entries; j++) { const IdeCtagsIndexEntry *entry = &entries [j]; IdeCtagsCompletionItem *item; if (ide_str_equal0 (entry->name, last_name)) continue; last_name = entry->name; if (!ide_ctags_is_allowed (entry, allowed)) continue; item = ide_ctags_completion_item_new (self, entry); if (!ide_completion_item_match (IDE_COMPLETION_ITEM (item), self->current_word, casefold)) { g_object_unref (item); continue; } ide_completion_results_take_proposal (self->results, IDE_COMPLETION_ITEM (item)); } } ide_completion_results_present (self->results, provider, context); IDE_EXIT; word_too_small: gtk_source_completion_context_add_proposals (context, provider, NULL, TRUE); IDE_EXIT; }
static void ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider, GtkSourceCompletionContext *context) { IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider; g_autofree gchar *word = NULL; const IdeCtagsIndexEntry *entries; const gchar * const *allowed; g_autoptr(GPtrArray) ar = NULL; IdeCtagsIndexEntry *last = NULL; GtkSourceBuffer *buffer; gsize n_entries; GtkTextIter iter; GList *list = NULL; gsize i; gsize j; IDE_ENTRY; g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self)); g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context)); if (self->indexes->len == 0) IDE_GOTO (failure); if (!g_settings_get_boolean (self->settings, "ctags-autocompletion")) IDE_GOTO (failure); if (!gtk_source_completion_context_get_iter (context, &iter)) IDE_GOTO (failure); buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (&iter)); allowed = get_allowed_suffixes (buffer); word = get_word_to_cursor (&iter); if (ide_str_empty0 (word) || strlen (word) < self->minimum_word_size) IDE_GOTO (failure); if (strlen (word) < 3) IDE_GOTO (failure); ar = g_ptr_array_new (); IDE_TRACE_MSG ("Searching for %s", word); for (j = 0; j < self->indexes->len; j++) { IdeCtagsIndex *index = g_ptr_array_index (self->indexes, j); entries = ide_ctags_index_lookup_prefix (index, word, &n_entries); if ((entries == NULL) || (n_entries == 0)) continue; for (i = 0; i < n_entries; i++) { const IdeCtagsIndexEntry *entry = &entries [i]; if (is_allowed (entry, allowed)) g_ptr_array_add (ar, (gpointer)entry); } } g_ptr_array_sort (ar, sort_wrapper); for (i = ar->len; i > 0; i--) { GtkSourceCompletionProposal *item; IdeCtagsIndexEntry *entry = g_ptr_array_index (ar, i - 1); /* * NOTE: * * We walk backwards in this ptrarray so that we can use g_list_prepend() for O(1) access. * I think everyone agrees that using GList for passing completion data around was not * a great choice, but it is what we have to work with. */ /* * Ignore this item if the previous one looks really similar. * We take the first item instead of the last since the first item (when walking backwards) * tends to be more likely to be the one we care about (based on lexicographical * ordering. For example, something in "gtk-2.0" is less useful than "gtk-3.0". * * This is done here instead of during our initial object creation so that * we can merge items between different indexes. It often happens that the * same headers are included in multiple tags files. */ if ((last != NULL) && too_similar (entry, last)) continue; /* * NOTE: * * Autocompletion is very performance sensitive code. The smallest amount of * extra work has a very negative impact on interactivity. We are trying to * avoid a couple things here based on how completion works. * * 1) Avoiding referencing or copying things. * Since the provider will always outlive the completion item, we use * borrowed references for as much as we can. * 2) We delay the work of looking up icons until they are requested. * No sense in doing that work before hand. */ item = ide_ctags_completion_item_new (entry, self, context); list = g_list_prepend (list, item); last = entry; } failure: gtk_source_completion_context_add_proposals (context, provider, list, TRUE); g_list_free_full (list, g_object_unref); IDE_EXIT; }