1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2013 Carl-Anton Ingmarsson <carlantoni@gnome.org>
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/>.";
22 #include "anjuta-completion.h"
25 struct _AnjutaCompletionPrivate
28 gboolean items_sorted
;
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
;
41 gboolean case_sensitive
;
50 static GParamSpec
* properties
[PROP_LAST
];
52 G_DEFINE_TYPE (AnjutaCompletion
, anjuta_completion
, G_TYPE_OBJECT
);
55 const char* anjuta_completion_default_name_func (const void* item
)
57 return (const char*)item
;
61 anjuta_completion_item_sort_func (gconstpointer a
, gconstpointer b
,
64 AnjutaCompletion
* self
= ANJUTA_COMPLETION (user_data
);
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
);
75 return g_ascii_strcasecmp (name_a
, name_b
);
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
87 anjuta_completion_complete (AnjutaCompletion
* self
,
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
;
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
,
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
;)
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
));
154 /* Do a binary search to find the last match */
155 for (l
= first_match
, r
= end
; l
< r
;)
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
));
175 if (first_match
<= last_match
)
181 for (i
= first_match
; i
<= last_match
; i
++)
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)
192 if (self
->priv
->filter_func
&&
193 !self
->priv
->filter_func (item
, self
->priv
->filter_func_user_data
))
196 completions
= g_list_prepend (completions
, item
);
198 if (max_completions
> 0 && n_completions
== max_completions
)
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
;
212 anjuta_completion_clear_items (AnjutaCompletion
* self
)
214 if (self
->priv
->item_destroy_func
)
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.
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.
254 anjuta_completion_add_item (AnjutaCompletion
* self
,
257 g_ptr_array_add (self
->priv
->items
, item
);
259 self
->priv
->items_sorted
= FALSE
;
263 anjuta_completion_set_filter_func (AnjutaCompletion
* self
,
264 AnjutaCompletionFilterFunc filter_func
,
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.
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
;
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
;
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
)
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
]);
315 anjuta_completion_new (AnjutaCompletionNameFunc name_func
)
317 AnjutaCompletion
* self
;
319 self
= g_object_new (ANJUTA_TYPE_COMPLETION
, NULL
);
322 self
->priv
->name_func
= name_func
;
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 ();
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
);
350 anjuta_completion_get_property (GObject
* object
, guint prop_id
, GValue
* value
,
353 AnjutaCompletion
* self
= ANJUTA_COMPLETION (object
);
357 case PROP_CASE_SENSITIVE
:
358 g_value_set_boolean (value
,
359 anjuta_completion_get_case_sensitive (self
));
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
368 anjuta_completion_set_property (GObject
* object
, guint prop_id
,
369 const GValue
* value
, GParamSpec
* pspec
)
371 AnjutaCompletion
* self
= ANJUTA_COMPLETION (object
);
375 case PROP_CASE_SENSITIVE
:
376 anjuta_completion_set_case_sensitive (self
, g_value_get_boolean (value
));
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
));