Updated Czech translation
[anjuta.git] / libanjuta / anjuta-completion.c
blob533a1df013b67f5b06d4f072df7f8b8e0aa7b0aa
1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-completion.c
4 * Copyright (C) 2013 Carl-Anton Ingmarsson <carlantoni@gnome.org>
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.";
20 #include <string.h>
22 #include "anjuta-completion.h"
25 struct _AnjutaCompletionPrivate
27 GPtrArray* items;
28 gboolean items_sorted;
30 char* last_complete;
31 gint last_complete_start;
32 gint last_complete_end;
34 AnjutaCompletionNameFunc name_func;
35 GDestroyNotify item_destroy_func;
37 AnjutaCompletionFilterFunc filter_func;
38 void* filter_func_user_data;
40 /* Properties */
41 gboolean case_sensitive;
44 enum
46 PROP_0,
47 PROP_CASE_SENSITIVE,
48 PROP_LAST
50 static GParamSpec* properties[PROP_LAST];
52 G_DEFINE_TYPE (AnjutaCompletion, anjuta_completion, G_TYPE_OBJECT);
54 static inline
55 const char* anjuta_completion_default_name_func (const void* item)
57 return (const char*)item;
60 static gint
61 anjuta_completion_item_sort_func (gconstpointer a, gconstpointer b,
62 void* user_data)
64 AnjutaCompletion* self = ANJUTA_COMPLETION (user_data);
66 const char* name_a;
67 const char* name_b;
69 name_a = self->priv->name_func (*(const void**)a);
70 name_b = self->priv->name_func (*(const void**)b);
72 if (self->priv->case_sensitive)
73 return strcmp (name_a, name_b);
74 else
75 return g_ascii_strcasecmp (name_a, name_b);
78 /**
79 * anjuta_completion_complete:
80 * @self: A #AnjutaCompletion
81 * @prefix: The prefix to complete against.
83 * Returns: (transfer container): The list of completions that matched
84 * @prefix.
86 GList*
87 anjuta_completion_complete (AnjutaCompletion* self,
88 const char* prefix,
89 gint max_completions)
92 gint start, end;
93 gint l, r;
94 gint (*ncmp_func)(const char* s1, const char* s2, gsize n);
95 gint first_match, last_match;
96 GList* completions = NULL;
98 g_return_val_if_fail (ANJUTA_IS_COMPLETION (self), NULL);
99 g_return_val_if_fail (prefix, NULL);
101 /* Start from old completion if possible */
102 if (self->priv->last_complete &&
103 self->priv->items_sorted &&
104 g_str_has_prefix (prefix, self->priv->last_complete))
106 start = self->priv->last_complete_start;
107 end = self->priv->last_complete_end;
109 else
111 start = 0;
112 end = self->priv->items->len - 1;
115 /* Free last complete */
116 if (self->priv->last_complete)
118 g_free (self->priv->last_complete);
119 self->priv->last_complete = NULL;
122 /* Sort the items if they're not already sorted */
123 if (!self->priv->items_sorted)
125 g_ptr_array_sort_with_data (self->priv->items, anjuta_completion_item_sort_func,
126 self);
127 self->priv->items_sorted = TRUE;
130 ncmp_func = self->priv->case_sensitive ? strncmp : g_ascii_strncasecmp;
132 /* Do a binary search to find the first match */
133 for (l = start, r = end; l < r;)
135 gint mid;
136 void* item;
137 const char* name;
138 gint cmp;
140 mid = l + (r - l) / 2;
141 item = g_ptr_array_index (self->priv->items, mid);
142 name = self->priv->name_func (item);
144 cmp = ncmp_func (prefix, name, strlen (prefix));
145 if (cmp > 0)
146 l = mid + 1;
147 else if (cmp < 0)
148 r = mid - 1;
149 else
150 r = mid;
152 first_match = l;
154 /* Do a binary search to find the last match */
155 for (l = first_match, r = end; l < r;)
157 gint mid;
158 void* item;
159 const char* name;
160 gint cmp;
162 mid = l + ((r - l) / 2) + 1;
163 item = g_ptr_array_index (self->priv->items, mid);
164 name = self->priv->name_func (item);
166 cmp = ncmp_func (prefix, name, strlen (prefix));
167 if (cmp == 0)
168 l = mid;
169 else
170 r = mid - 1;
173 last_match = r;
175 if (first_match <= last_match)
177 gint i;
178 gint n_completions;
180 n_completions = 0;
181 for (i = first_match; i <= last_match; i++)
183 void* item;
184 const char* name;
186 item = g_ptr_array_index (self->priv->items, i);
187 name = self->priv->name_func (item);
189 if (ncmp_func (prefix, name, strlen (prefix)) != 0)
190 break;
192 if (self->priv->filter_func &&
193 !self->priv->filter_func (item, self->priv->filter_func_user_data))
194 continue;
196 completions = g_list_prepend (completions, item);
197 n_completions++;
198 if (max_completions > 0 && n_completions == max_completions)
199 break;
201 completions = g_list_reverse (completions);
204 self->priv->last_complete = g_strdup (prefix);
205 self->priv->last_complete_start = first_match;
206 self->priv->last_complete_end = last_match;
208 return completions;
211 static void
212 anjuta_completion_clear_items (AnjutaCompletion* self)
214 if (self->priv->item_destroy_func)
216 gint i;
218 for (i = 0; i < self->priv->items->len; i++)
220 void* item = g_ptr_array_index (self->priv->items, i);
222 self->priv->item_destroy_func (item);
225 g_ptr_array_unref (self->priv->items);
227 g_free (self->priv->last_complete);
228 self->priv->last_complete = NULL;
232 * anjuta_completion_clear:
233 * @self: a #AnjutaCompletion
235 * Clear all items added to the completion.
237 void
238 anjuta_completion_clear (AnjutaCompletion* self)
240 g_return_if_fail (ANJUTA_IS_COMPLETION (self));
242 anjuta_completion_clear_items (self);
243 self->priv->items = g_ptr_array_new ();
247 * anjuta_completion_add_item:
248 * @self: a #AnjutaCompletion
249 * @item: the item to be added.
251 * Add an item to the completion.
253 void
254 anjuta_completion_add_item (AnjutaCompletion* self,
255 void* item)
257 g_ptr_array_add (self->priv->items, item);
259 self->priv->items_sorted = FALSE;
262 void
263 anjuta_completion_set_filter_func (AnjutaCompletion* self,
264 AnjutaCompletionFilterFunc filter_func,
265 void* user_data)
267 g_return_if_fail (ANJUTA_IS_COMPLETION (self));
269 self->priv->filter_func = filter_func;
270 self->priv->filter_func_user_data = user_data;
274 * anjuta_completion_set_item_destroy_func:
275 * @self: a #AnjutaCompletion
276 * @item_destroy_func: (allow-none): the function to be called on
277 * the added items when the #AnjutaCompletion object is destroyed.
279 void
280 anjuta_completion_set_item_destroy_func (AnjutaCompletion* self,
281 GDestroyNotify item_destroy_func)
283 g_return_if_fail (ANJUTA_IS_COMPLETION (self));
285 self->priv->item_destroy_func = item_destroy_func;
288 gboolean
289 anjuta_completion_get_case_sensitive (AnjutaCompletion* self)
291 g_return_val_if_fail (ANJUTA_IS_COMPLETION (self), FALSE);
293 return self->priv->case_sensitive;
296 void
297 anjuta_completion_set_case_sensitive (AnjutaCompletion* self,
298 gboolean case_sensitive)
300 g_return_if_fail (ANJUTA_IS_COMPLETION (self));
302 if (self->priv->case_sensitive == case_sensitive)
303 return;
305 g_free (self->priv->last_complete);
306 self->priv->last_complete = NULL;
308 self->priv->items_sorted = FALSE;
310 self->priv->case_sensitive = case_sensitive;
311 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CASE_SENSITIVE]);
314 AnjutaCompletion*
315 anjuta_completion_new (AnjutaCompletionNameFunc name_func)
317 AnjutaCompletion* self;
319 self = g_object_new (ANJUTA_TYPE_COMPLETION, NULL);
321 if (name_func)
322 self->priv->name_func = name_func;
324 return self;
327 static void
328 anjuta_completion_init (AnjutaCompletion* self)
330 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ANJUTA_TYPE_COMPLETION,
331 AnjutaCompletionPrivate);
333 self->priv->name_func = anjuta_completion_default_name_func;
334 self->priv->case_sensitive = TRUE;
336 self->priv->items = g_ptr_array_new ();
339 static void
340 anjuta_completion_finalize (GObject *object)
342 AnjutaCompletion* self = ANJUTA_COMPLETION (object);
344 anjuta_completion_clear_items (self);
346 G_OBJECT_CLASS (anjuta_completion_parent_class)->finalize (object);
349 static void
350 anjuta_completion_get_property (GObject* object, guint prop_id, GValue* value,
351 GParamSpec* pspec)
353 AnjutaCompletion* self = ANJUTA_COMPLETION (object);
355 switch (prop_id)
357 case PROP_CASE_SENSITIVE:
358 g_value_set_boolean (value,
359 anjuta_completion_get_case_sensitive (self));
360 break;
362 default:
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
367 static void
368 anjuta_completion_set_property (GObject* object, guint prop_id,
369 const GValue* value, GParamSpec* pspec)
371 AnjutaCompletion* self = ANJUTA_COMPLETION (object);
373 switch (prop_id)
375 case PROP_CASE_SENSITIVE:
376 anjuta_completion_set_case_sensitive (self, g_value_get_boolean (value));
377 break;
379 default:
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
384 static void
385 anjuta_completion_class_init (AnjutaCompletionClass *klass)
387 GObjectClass* object_class = G_OBJECT_CLASS (klass);
389 object_class->get_property = anjuta_completion_get_property;
390 object_class->set_property = anjuta_completion_set_property;
391 object_class->finalize = anjuta_completion_finalize;
393 properties[PROP_CASE_SENSITIVE] =
394 g_param_spec_boolean ("case-sensitive", "Case sensitive", "Case sensitive",
395 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
397 g_object_class_install_properties (object_class, PROP_LAST, properties);
398 g_type_class_add_private (klass, sizeof (AnjutaCompletionPrivate));