13 #if GTK_MAJOR_VERSION == 2
17 static GtkEventBox* girara_completion_row_create(girara_session_t*,
const char*,
const char*,
bool);
18 static void girara_completion_row_set_color(girara_session_t*, GtkEventBox*,
int);
57 completion_element_free(girara_completion_element_t* element)
59 if (element == NULL) {
64 g_free(element->value);
65 g_free(element->description);
66 g_slice_free(girara_completion_element_t, element);
70 escape(
const char*
value)
76 GString* str = g_string_new(
"");
77 while (*value !=
'\0') {
78 const char c = *value++;
79 if (strchr(
"\\ \t\"\'", c) != NULL) {
80 g_string_append_c(str,
'\\');
82 g_string_append_c(str, c);
85 return g_string_free(str, FALSE);
91 girara_completion_t *completion = g_slice_new(girara_completion_t);
98 girara_completion_group_t*
101 girara_completion_group_t*
group = g_slice_new(girara_completion_group_t);
103 group->value = name ? g_strdup(name) : NULL;
107 if (group->elements == NULL) {
108 g_slice_free(girara_completion_group_t, group);
118 g_return_if_fail(completion != NULL);
119 g_return_if_fail(group != NULL);
131 g_free(group->value);
133 g_slice_free(girara_completion_group_t, group);
139 g_return_if_fail(completion != NULL);
143 g_slice_free(girara_completion_t, completion);
149 g_return_if_fail(group != NULL);
150 g_return_if_fail(name != NULL);
152 girara_completion_element_t* new_element = g_slice_new(girara_completion_element_t);
154 new_element->value = g_strdup(name);
155 new_element->description = description ? g_strdup(description) : NULL;
163 g_return_val_if_fail(session != NULL,
false);
166 gchar *input = gtk_editable_get_chars(GTK_EDITABLE(session->gtk.inputbar_entry), 0, -1);
171 const size_t input_length = strlen(input);
173 if (input_length == 0 || input[0] !=
':') {
178 gchar** elements = NULL;
179 gint n_parameter = 0;
180 if (input_length > 1) {
181 if (g_shell_parse_argv(input + 1, &n_parameter, &elements, NULL) == FALSE) {
186 elements = g_malloc0(2 *
sizeof(
char*));
187 elements[0] = g_strdup(
"");
190 if (n_parameter == 1 && input[input_length-1] ==
' ') {
197 gchar *current_command = (elements[0] != NULL && elements[0][0] !=
'\0') ? g_strdup(elements[0]) : NULL;
198 gchar *current_parameter = (elements[0] != NULL && elements[1] != NULL) ? g_strdup(elements[1]) : NULL;
200 size_t current_command_length = current_command ? strlen(current_command) : 0;
202 static GList* entries = NULL;
203 static GList* entries_current = NULL;
204 static char *previous_command = NULL;
205 static char *previous_parameter = NULL;
206 static bool command_mode =
true;
207 static size_t previous_length = 0;
216 (current_parameter && previous_parameter && strcmp(current_parameter, previous_parameter)) ||
217 (current_command && previous_command && strcmp(current_command, previous_command)) ||
218 input_length != previous_length
221 if (session->gtk.results != NULL) {
223 for (GList* element = entries; element; element = g_list_next(element)) {
224 girara_internal_completion_entry_t* entry = (girara_internal_completion_entry_t*) element->data;
227 gtk_widget_destroy(GTK_WIDGET(entry->widget));
228 g_free(entry->value);
229 g_slice_free(girara_internal_completion_entry_t, entry);
233 g_list_free(entries);
235 entries_current = NULL;
238 gtk_widget_destroy(GTK_WIDGET(session->gtk.results));
239 session->gtk.results = NULL;
245 g_free(previous_command);
246 previous_command = NULL;
248 g_free(previous_parameter);
249 previous_parameter = NULL;
251 g_strfreev(elements);
253 g_free(current_command);
254 g_free(current_parameter);
263 if (session->gtk.results == NULL) {
264 #if GTK_MAJOR_VERSION == 2
265 session->gtk.results = GTK_BOX(gtk_vbox_new(FALSE, 0));
267 session->gtk.results = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
270 if (session->gtk.results == NULL) {
271 g_free(current_command);
272 g_free(current_parameter);
274 g_strfreev(elements);
278 if (n_parameter <= 1) {
284 if (current_command == NULL ||
285 (command->command != NULL && !strncmp(current_command, command->command, current_command_length)) ||
286 (command->abbr != NULL && !strncmp(current_command, command->abbr, current_command_length))
290 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
291 entry->group = FALSE;
292 entry->value = g_strdup(command->command);
293 entry->widget = girara_completion_row_create(session, command->command, command->description, FALSE);
295 entries = g_list_append(entries, entry);
298 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
304 if (n_parameter > 1 || g_list_length(entries) == 1) {
306 if (g_list_length(entries) == 1) {
307 girara_internal_completion_entry_t* entry = g_list_first(entries)->data;
310 command_mode =
false;
311 current_command = entry->value;
312 current_command_length = strlen(current_command);
315 gtk_widget_destroy(GTK_WIDGET(entry->widget));
317 entries = g_list_remove(entries, g_list_first(entries)->data);
318 g_slice_free(girara_internal_completion_entry_t, entry);
322 girara_command_t* command = NULL;
324 if ( (current_command != NULL && command_it->command != NULL && !strncmp(current_command, command_it->command, current_command_length)) ||
325 (current_command != NULL && command_it->abbr != NULL && !strncmp(current_command, command_it->abbr, current_command_length))
328 g_free(previous_command);
329 previous_command = g_strdup(command_it->command);
330 command = command_it;
335 if (command == NULL) {
336 g_free(current_command);
337 g_free(current_parameter);
339 g_strfreev(elements);
343 if (command->completion == NULL) {
344 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
345 entry->group = FALSE;
346 entry->value = g_strdup(command->command);
347 entry->widget = girara_completion_row_create(session, command->command, command->description, FALSE);
349 entries = g_list_append(entries, entry);
351 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
358 girara_completion_t *result = command->completion(session, current_parameter ? current_parameter :
"");
360 if (result == NULL || result->groups == NULL) {
361 g_free(current_command);
362 g_free(current_parameter);
364 g_strfreev(elements);
370 if (
group->value != NULL) {
371 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
373 entry->value = g_strdup(
group->value);
374 entry->widget = girara_completion_row_create(session,
group->value, NULL, TRUE);
376 entries = g_list_append(entries, entry);
378 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
382 girara_internal_completion_entry_t* entry = g_slice_new(girara_internal_completion_entry_t);
383 entry->group = FALSE;
384 entry->value = g_strdup(element->value);
385 entry->widget = girara_completion_row_create(session, element->value, element->description, FALSE);
387 entries = g_list_append(entries, entry);
389 gtk_box_pack_start(session->gtk.results, GTK_WIDGET(entry->widget), FALSE, FALSE, 0);
395 command_mode =
false;
399 if (entries != NULL) {
400 entries_current = (argument->n ==
GIRARA_NEXT) ? g_list_last(entries) : entries;
401 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.results), FALSE, FALSE, 0);
402 gtk_widget_show(GTK_WIDGET(session->gtk.results));
407 unsigned int n_elements = g_list_length(entries);
408 if (entries != NULL && n_elements > 0) {
409 if (n_elements > 1) {
410 girara_completion_row_set_color(session, ((girara_internal_completion_entry_t *) entries_current->data)->widget,
GIRARA_NORMAL);
412 bool next_group = FALSE;
414 for (
unsigned int i = 0; i < n_elements; i++) {
416 GList* entry = g_list_next(entries_current);
418 entry = g_list_first(entries);
421 entries_current = entry;
423 GList* entry = g_list_previous(entries_current);
425 entry = g_list_last(entries);
428 entries_current = entry;
431 if (((girara_internal_completion_entry_t*) entries_current->data)->group) {
444 girara_completion_row_set_color(session, ((girara_internal_completion_entry_t *) entries_current->data)->widget,
GIRARA_HIGHLIGHT);
447 unsigned int n_completion_items = 15;
449 unsigned int uh = ceil( n_completion_items / 2);
450 unsigned int lh = floor(n_completion_items / 2);
452 unsigned int current_item = g_list_position(entries, entries_current);
454 GList* tmpentry = entries;
455 for (
unsigned int i = 0; i < n_elements; i++) {
457 (i >= (current_item - lh) && (i <= current_item + uh)) ||
458 (i < n_completion_items && current_item < lh) ||
459 (i >= (n_elements - n_completion_items) && (current_item >= (n_elements - uh)))
462 gtk_widget_show(GTK_WIDGET(((girara_internal_completion_entry_t*) tmpentry->data)->widget));
464 gtk_widget_hide(GTK_WIDGET(((girara_internal_completion_entry_t*) tmpentry->data)->widget));
467 tmpentry = g_list_next(tmpentry);
470 gtk_widget_hide(GTK_WIDGET(((girara_internal_completion_entry_t*) (g_list_nth(entries, 0))->data)->
widget));
475 char* escaped_value = escape(((girara_internal_completion_entry_t *) entries_current->data)->value);
476 if (command_mode ==
true) {
477 char* space = (n_elements == 1) ?
" " :
"";
478 temp = g_strconcat(
":", escaped_value, space, NULL);
480 temp = g_strconcat(
":", previous_command,
" ", escaped_value, NULL);
483 gtk_entry_set_text(session->gtk.inputbar_entry, temp);
484 gtk_editable_set_position(GTK_EDITABLE(session->gtk.inputbar_entry), -1);
485 g_free(escaped_value);
488 g_free(previous_command);
489 g_free(previous_parameter);
490 previous_command = g_strdup((command_mode) ? ((girara_internal_completion_entry_t*) entries_current->data)->value : current_command);
491 previous_parameter = g_strdup((command_mode) ? current_parameter : ((girara_internal_completion_entry_t*) entries_current->data)->value);
492 previous_length = strlen(temp);
496 g_free(current_command);
497 g_free(current_parameter);
499 g_strfreev(elements);
505 girara_completion_row_create(girara_session_t* session,
const char* command,
const char* description,
bool group)
507 #if GTK_MAJOR_VERSION == 2
508 GtkBox *col = GTK_BOX(gtk_hbox_new(FALSE, 0));
510 GtkBox *col = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
513 GtkEventBox *row = GTK_EVENT_BOX(gtk_event_box_new());
515 GtkLabel *show_command = GTK_LABEL(gtk_label_new(NULL));
516 GtkLabel *show_description = GTK_LABEL(gtk_label_new(NULL));
518 gtk_misc_set_alignment(GTK_MISC(show_command), 0.0, 0.0);
519 gtk_misc_set_alignment(GTK_MISC(show_description), 0.0, 0.0);
522 gtk_misc_set_padding(GTK_MISC(show_command), 2, 4);
523 gtk_misc_set_padding(GTK_MISC(show_description), 2, 4);
525 gtk_misc_set_padding(GTK_MISC(show_command), 1, 1);
526 gtk_misc_set_padding(GTK_MISC(show_description), 1, 1);
529 gtk_label_set_use_markup(show_command, TRUE);
530 gtk_label_set_use_markup(show_description, TRUE);
532 gchar* c = g_markup_printf_escaped(
FORMAT_COMMAND, command ? command :
"");
533 gchar* d = g_markup_printf_escaped(
FORMAT_DESCRIPTION, description ? description :
"");
534 gtk_label_set_markup(show_command, c);
535 gtk_label_set_markup(show_description, d);
540 gtk_widget_override_color(GTK_WIDGET(show_command), GTK_STATE_NORMAL, &(session->style.completion_group_foreground));
541 gtk_widget_override_color(GTK_WIDGET(show_description), GTK_STATE_NORMAL, &(session->style.completion_group_foreground));
542 gtk_widget_override_background_color(GTK_WIDGET(row), GTK_STATE_NORMAL, &(session->style.completion_group_background));
544 gtk_widget_override_color(GTK_WIDGET(show_command), GTK_STATE_NORMAL, &(session->style.completion_foreground));
545 gtk_widget_override_color(GTK_WIDGET(show_description), GTK_STATE_NORMAL, &(session->style.completion_foreground));
546 gtk_widget_override_background_color(GTK_WIDGET(row), GTK_STATE_NORMAL, &(session->style.completion_background));
549 gtk_widget_override_font(GTK_WIDGET(show_command), session->style.font);
550 gtk_widget_override_font(GTK_WIDGET(show_description), session->style.font);
552 gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_command), TRUE, TRUE, 2);
553 gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_description), FALSE, FALSE, 2);
555 gtk_container_add(GTK_CONTAINER(row), GTK_WIDGET(col));
556 gtk_widget_show_all(GTK_WIDGET(row));
562 girara_completion_row_set_color(girara_session_t* session, GtkEventBox* row,
int mode)
564 g_return_if_fail(session != NULL);
565 g_return_if_fail(row != NULL);
567 GtkBox *col = GTK_BOX(gtk_bin_get_child(GTK_BIN(row)));
568 GList* items = gtk_container_get_children(GTK_CONTAINER(col));
569 GtkLabel *cmd = GTK_LABEL(g_list_nth_data(items, 0));
570 GtkLabel *desc = GTK_LABEL(g_list_nth_data(items, 1));
573 gtk_widget_override_color(GTK_WIDGET(cmd), GTK_STATE_NORMAL, &(session->style.completion_highlight_foreground));
574 gtk_widget_override_color(GTK_WIDGET(desc), GTK_STATE_NORMAL, &(session->style.completion_highlight_foreground));
575 gtk_widget_override_background_color(GTK_WIDGET(row), GTK_STATE_NORMAL, &(session->style.completion_highlight_background));
577 gtk_widget_override_color(GTK_WIDGET(cmd), GTK_STATE_NORMAL, &(session->style.completion_foreground));
578 gtk_widget_override_color(GTK_WIDGET(desc), GTK_STATE_NORMAL, &(session->style.completion_foreground));
579 gtk_widget_override_background_color(GTK_WIDGET(row), GTK_STATE_NORMAL, &(session->style.completion_background));