14 static GtkEventBox* girara_completion_row_create(
const char*,
const char*,
bool);
15 static void girara_completion_row_set_color(girara_session_t*, GtkEventBox*,
int);
54 completion_element_free(girara_completion_element_t* element)
56 if (element == NULL) {
61 g_free(element->value);
62 g_free(element->description);
63 g_slice_free(girara_completion_element_t, element);
69 girara_completion_t *completion = g_slice_new(girara_completion_t);
76 girara_completion_group_t*
79 girara_completion_group_t*
group = g_slice_new(girara_completion_group_t);
81 group->value = name ? g_strdup(name) : NULL;
85 if (group->elements == NULL) {
86 g_slice_free(girara_completion_group_t, group);
96 g_return_if_fail(completion != NULL);
97 g_return_if_fail(group != NULL);
109 g_free(group->value);
111 g_slice_free(girara_completion_group_t, group);
117 g_return_if_fail(completion != NULL);
121 g_slice_free(girara_completion_t, completion);
127 g_return_if_fail(group != NULL);
128 g_return_if_fail(name != NULL);
130 girara_completion_element_t* new_element = g_slice_new(girara_completion_element_t);
132 new_element->value = g_strdup(name);
133 new_element->description = description ? g_strdup(description) : NULL;
141 g_return_val_if_fail(session != NULL,
false);
144 gchar *input = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
149 const size_t input_length = strlen(input);
151 if (input_length == 0 || input[0] !=
':') {
156 gchar** elements = NULL;
157 gint n_parameter = 0;
158 if (input_length > 1) {
159 if (g_shell_parse_argv(input + 1, &n_parameter, &elements, NULL) == FALSE) {
164 elements = g_try_malloc0(2 *
sizeof(
char*));
165 if (elements == NULL) {
169 elements[0] = g_strdup(
"");
172 if (n_parameter == 1 && input[input_length-1] ==
' ') {
179 gchar *current_command = (elements[0] != NULL && elements[0][0] !=
'\0') ? g_strdup(elements[0]) : NULL;
180 gchar *current_parameter = (elements[0] != NULL && elements[1] != NULL) ? g_strdup(elements[1]) : NULL;
182 size_t current_command_length = current_command ? strlen(current_command) : 0;
184 static GList* entries = NULL;
185 static GList* entries_current = NULL;
186 static char *previous_command = NULL;
187 static char *previous_parameter = NULL;
188 static bool command_mode =
true;
189 static size_t previous_length = 0;
191 const bool is_single_entry = (1 == g_list_length(entries));
201 (current_parameter && previous_parameter && strcmp(current_parameter, previous_parameter)) ||
202 (current_command && previous_command && strcmp(current_command, previous_command)) ||
203 (input_length != previous_length) ||
207 if (session->gtk.results != NULL) {
209 for (GList* element = entries; element; element = g_list_next(element)) {
210 girara_internal_completion_entry_t* entry = (girara_internal_completion_entry_t*) element->data;
213 gtk_widget_destroy(GTK_WIDGET(entry->widget));
214 g_free(entry->value);
215 g_slice_free(girara_internal_completion_entry_t, entry);
219 g_list_free(entries);
221 entries_current = NULL;
224 gtk_widget_destroy(GTK_WIDGET(session->gtk.results));
225 session->gtk.results = NULL;
231 g_free(previous_command);
232 previous_command = NULL;
234 g_free(previous_parameter);
235 previous_parameter = NULL;
237 g_strfreev(elements);
239 g_free(current_command);
240 g_free(current_parameter);
249 if (session->gtk.results == NULL) {
250 session->gtk.results = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
253 if (session->gtk.results == NULL) {
254 g_free(current_command);
255 g_free(current_parameter);
257 g_strfreev(elements);
261 if (n_parameter <= 1) {
267 if (current_command == NULL ||
268 (command->command != NULL && !strncmp(current_command, command->command, current_command_length)) ||
269 (command->abbr != NULL && !strncmp(current_command, command->abbr, current_command_length))
273 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
274 entry->group = FALSE;
275 entry->value = g_strdup(command->command);
276 entry->widget = girara_completion_row_create(command->command, command->description, FALSE);
278 entries = g_list_append(entries, entry);
281 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
287 if (n_parameter > 1 || g_list_length(entries) == 1) {
289 if (g_list_length(entries) == 1) {
290 girara_internal_completion_entry_t* entry = g_list_first(entries)->data;
293 command_mode =
false;
294 current_command = entry->value;
295 current_command_length = strlen(current_command);
298 gtk_widget_destroy(GTK_WIDGET(entry->widget));
300 entries = g_list_remove(entries, g_list_first(entries)->data);
301 g_slice_free(girara_internal_completion_entry_t, entry);
305 girara_command_t* command = NULL;
307 if ( (current_command != NULL && command_it->command != NULL && !strncmp(current_command, command_it->command, current_command_length)) ||
308 (current_command != NULL && command_it->abbr != NULL && !strncmp(current_command, command_it->abbr, current_command_length))
311 g_free(previous_command);
312 previous_command = g_strdup(command_it->command);
313 command = command_it;
318 if (command == NULL) {
319 g_free(current_command);
320 g_free(current_parameter);
322 g_strfreev(elements);
326 if (command->completion == NULL) {
327 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
328 entry->group = FALSE;
329 entry->value = g_strdup(command->command);
330 entry->widget = girara_completion_row_create(command->command, command->description, FALSE);
332 entries = g_list_append(entries, entry);
334 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
341 girara_completion_t *result = command->completion(session, current_parameter ? current_parameter :
"");
343 if (result == NULL || result->groups == NULL) {
344 g_free(current_command);
345 g_free(current_parameter);
347 g_strfreev(elements);
353 if (
group->value != NULL) {
354 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
356 entry->value = g_strdup(
group->value);
357 entry->widget = girara_completion_row_create(
group->value, NULL, TRUE);
359 entries = g_list_append(entries, entry);
361 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
365 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
366 entry->group = FALSE;
367 entry->value = g_strdup(element->value);
368 entry->widget = girara_completion_row_create(element->value, element->description, FALSE);
370 entries = g_list_append(entries, entry);
372 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
378 command_mode =
false;
382 if (entries != NULL) {
383 entries_current = (argument->n ==
GIRARA_NEXT) ? g_list_last(entries) : entries;
384 gtk_box_pack_start(session->private_data->gtk.bottom_box, GTK_WIDGET(session->gtk.results), FALSE, FALSE, 0);
385 gtk_widget_show(GTK_WIDGET(session->gtk.results));
390 unsigned int n_elements = g_list_length(entries);
391 if (entries != NULL && n_elements > 0) {
392 if (n_elements > 1) {
393 girara_completion_row_set_color(session, ((girara_internal_completion_entry_t *) entries_current->data)->widget,
GIRARA_NORMAL);
395 bool next_group = FALSE;
397 for (
unsigned int i = 0; i < n_elements; i++) {
399 GList* entry = g_list_next(entries_current);
401 entry = g_list_first(entries);
404 entries_current = entry;
406 GList* entry = g_list_previous(entries_current);
408 entry = g_list_last(entries);
411 entries_current = entry;
414 if (((girara_internal_completion_entry_t*) entries_current->data)->group) {
427 girara_completion_row_set_color(session, ((girara_internal_completion_entry_t *) entries_current->data)->widget,
GIRARA_HIGHLIGHT);
430 unsigned int n_completion_items = 15;
432 unsigned int uh = ceil( n_completion_items / 2);
433 unsigned int lh = floor(n_completion_items / 2);
435 unsigned int current_item = g_list_position(entries, entries_current);
437 GList* tmpentry = entries;
438 for (
unsigned int i = 0; i < n_elements; i++) {
440 (i >= (current_item - lh) && (i <= current_item + uh)) ||
441 (i < n_completion_items && current_item < lh) ||
442 (i >= (n_elements - n_completion_items) && (current_item >= (n_elements - uh)))
445 gtk_widget_show(GTK_WIDGET(((girara_internal_completion_entry_t*) tmpentry->data)->widget));
447 gtk_widget_hide(GTK_WIDGET(((girara_internal_completion_entry_t*) tmpentry->data)->widget));
450 tmpentry = g_list_next(tmpentry);
453 gtk_widget_hide(GTK_WIDGET(((girara_internal_completion_entry_t*) (g_list_nth(entries, 0))->data)->
widget));
458 char* escaped_value =
girara_escape_string(((girara_internal_completion_entry_t *) entries_current->data)->value);
459 if (command_mode ==
true) {
460 char* space = (n_elements == 1) ?
" " :
"";
461 temp = g_strconcat(
":", escaped_value, space, NULL);
463 temp = g_strconcat(
":", previous_command,
" ", escaped_value, NULL);
466 gtk_entry_set_text(session->gtk.inputbar_entry, temp);
467 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
468 g_free(escaped_value);
471 g_free(previous_command);
472 g_free(previous_parameter);
473 previous_command = g_strdup((command_mode) ? ((girara_internal_completion_entry_t*) entries_current->data)->value : current_command);
474 previous_parameter = g_strdup((command_mode) ? current_parameter : ((girara_internal_completion_entry_t*) entries_current->data)->value);
475 previous_length = strlen(temp);
479 g_free(current_command);
480 g_free(current_parameter);
482 g_strfreev(elements);
488 girara_completion_row_create(
const char* command,
const char* description,
bool group)
490 GtkBox *col = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
492 GtkEventBox *row = GTK_EVENT_BOX(gtk_event_box_new());
494 GtkLabel *show_command = GTK_LABEL(gtk_label_new(NULL));
495 GtkLabel *show_description = GTK_LABEL(gtk_label_new(NULL));
497 gtk_widget_set_halign(GTK_WIDGET(show_command), GTK_ALIGN_START);
498 gtk_widget_set_valign(GTK_WIDGET(show_command), GTK_ALIGN_START);
499 gtk_widget_set_halign(GTK_WIDGET(show_description), GTK_ALIGN_END);
500 gtk_widget_set_valign(GTK_WIDGET(show_description), GTK_ALIGN_START);
502 gtk_label_set_use_markup(show_command, TRUE);
503 gtk_label_set_use_markup(show_description, TRUE);
505 gtk_label_set_ellipsize(show_command, PANGO_ELLIPSIZE_END);
506 gtk_label_set_ellipsize(show_description, PANGO_ELLIPSIZE_END);
508 gchar* c = g_markup_printf_escaped(
FORMAT_COMMAND, command ? command :
"");
509 gchar* d = g_markup_printf_escaped(
FORMAT_DESCRIPTION, description ? description :
"");
510 gtk_label_set_markup(show_command, c);
511 gtk_label_set_markup(show_description, d);
515 const char*
class = group ==
true ?
"completion-group" :
"completion";
521 gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_command), TRUE, TRUE, 0);
522 gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_description), TRUE, TRUE, 0);
524 gtk_container_add(GTK_CONTAINER(row), GTK_WIDGET(col));
525 gtk_widget_show_all(GTK_WIDGET(row));
531 girara_completion_row_set_color(girara_session_t* session, GtkEventBox* row,
int mode)
533 g_return_if_fail(session != NULL);
534 g_return_if_fail(row != NULL);
536 GtkBox* col = GTK_BOX(gtk_bin_get_child(GTK_BIN(row)));
537 GList* items = gtk_container_get_children(GTK_CONTAINER(col));
538 GtkWidget* cmd = GTK_WIDGET(g_list_nth_data(items, 0));
539 GtkWidget* desc = GTK_WIDGET(g_list_nth_data(items, 1));
542 gtk_widget_set_state_flags(cmd, GTK_STATE_FLAG_SELECTED,
false);
543 gtk_widget_set_state_flags(desc, GTK_STATE_FLAG_SELECTED,
false);
544 gtk_widget_set_state_flags(GTK_WIDGET(row), GTK_STATE_FLAG_SELECTED,
false);
546 gtk_widget_unset_state_flags(cmd, GTK_STATE_FLAG_SELECTED);
547 gtk_widget_unset_state_flags(desc, GTK_STATE_FLAG_SELECTED);
548 gtk_widget_unset_state_flags(GTK_WIDGET(row), GTK_STATE_FLAG_SELECTED);
void girara_completion_group_free(girara_completion_group_t *group)
void girara_list_append(girara_list_t *list, void *data)
void(* girara_free_function_t)(void *data)
girara_list_t * girara_list_new2(girara_free_function_t gfree)
#define FORMAT_DESCRIPTION
girara_completion_t * girara_completion_init()
void girara_list_free(girara_list_t *list)
bool girara_isc_completion(girara_session_t *session, girara_argument_t *argument, girara_event_t *UNUSED(event), unsigned int UNUSED(t))
void girara_completion_add_group(girara_completion_t *completion, girara_completion_group_t *group)
HIDDEN void widget_add_class(GtkWidget *widget, const char *styleclass)
void girara_completion_group_add_element(girara_completion_group_t *group, const char *name, const char *description)
bool girara_setting_get(girara_session_t *session, const char *name, void *dest)
void girara_completion_free(girara_completion_t *completion)
char * girara_escape_string(const char *value)
girara_completion_group_t * girara_completion_group_create(girara_session_t *UNUSED(session), const char *name)
#define GIRARA_LIST_FOREACH_END(list, type, iter, data)
#define GIRARA_LIST_FOREACH(list, type, iter, data)