From 16d68a86ca75b73c53aa81fe6d3d36361cb35b99 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Fri, 6 Oct 2017 15:02:15 +0200 Subject: [PATCH] add two XSFuncs to manipulate command history entries it is possible to use Irssi::UI::Window::get_history_entries to save the history entries, load_history_entries to load entries into the command history and delete_history_entries to remove history entries (for example to remove history selectively) --- src/fe-common/core/command-history.c | 55 +++++++++++ src/fe-common/core/command-history.h | 2 + src/perl/ui/Window.xs | 139 +++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) diff --git a/src/fe-common/core/command-history.c b/src/fe-common/core/command-history.c index 5de76969..a6a800d3 100644 --- a/src/fe-common/core/command-history.c +++ b/src/fe-common/core/command-history.c @@ -168,6 +168,61 @@ HISTORY_REC *command_history_find_name(const char *name) return NULL; } +static int history_entry_after_time_sort(const HISTORY_ENTRY_REC *a, const HISTORY_ENTRY_REC *b) +{ + return a->time == b->time ? 1 : a->time - b->time; +} + +void command_history_load_entry(time_t history_time, HISTORY_REC *history, const char *text) +{ + HISTORY_ENTRY_REC *entry; + + g_return_if_fail(history != NULL); + g_return_if_fail(text != NULL); + + entry = g_new0(HISTORY_ENTRY_REC, 1); + entry->text = g_strdup(text); + entry->history = history; + entry->time = history_time; + + history->lines++; + + history_entries = g_list_insert_sorted(history_entries, entry, (GCompareFunc)history_entry_after_time_sort); +} + +static int history_entry_find_func(const HISTORY_ENTRY_REC *data, const HISTORY_ENTRY_REC *user_data) +{ + if ((user_data->time == -1 || (data->time == user_data->time)) && + (user_data->history == NULL || (data->history == user_data->history)) && + g_strcmp0(data->text, user_data->text) == 0) { + return 0; + } else { + return -1; + } +} + +gboolean command_history_delete_entry(time_t history_time, HISTORY_REC *history, const char *text) +{ + GList *link; + HISTORY_ENTRY_REC entry; + + g_return_val_if_fail(history != NULL, FALSE); + g_return_val_if_fail(text != NULL, FALSE); + + entry.text = text; + entry.history = history; + entry.time = history_time; + + link = g_list_find_custom(history_entries, &entry, (GCompareFunc)history_entry_find_func); + if (link != NULL) { + ((HISTORY_ENTRY_REC *)link->data)->history->lines--; + history_list_delete_link_and_destroy(link); + return TRUE; + } else { + return FALSE; + } +} + HISTORY_REC *command_history_current(WINDOW_REC *window) { HISTORY_REC *rec; diff --git a/src/fe-common/core/command-history.h b/src/fe-common/core/command-history.h index ddc8f5e6..dc4d46da 100644 --- a/src/fe-common/core/command-history.h +++ b/src/fe-common/core/command-history.h @@ -28,6 +28,8 @@ void command_history_init(void); void command_history_deinit(void); void command_history_add(HISTORY_REC *history, const char *text); +void command_history_load_entry(time_t time, HISTORY_REC *history, const char *text); +gboolean command_history_delete_entry(time_t history_time, HISTORY_REC *history, const char *text); GList *command_history_list_last(HISTORY_REC *history); GList *command_history_list_first(HISTORY_REC *history); diff --git a/src/perl/ui/Window.xs b/src/perl/ui/Window.xs index b8d68ad8..85e284bb 100644 --- a/src/perl/ui/Window.xs +++ b/src/perl/ui/Window.xs @@ -255,6 +255,145 @@ PPCODE: for (tmp = command_history_list_first(rec); tmp != NULL; tmp = command_history_list_next(rec, tmp)) XPUSHs(sv_2mortal(new_pv(((HISTORY_ENTRY_REC *)tmp->data)->text))); +void +window_get_history_entries(window) + Irssi::UI::Window window +PREINIT: + HISTORY_REC *rec; + HISTORY_ENTRY_REC *ent; + WINDOW_REC *win; + GList *tmp; + GSList *stmp; + HV *hv; +PPCODE: + rec = window == NULL ? NULL : command_history_current(window); + for (tmp = command_history_list_first(rec); tmp != NULL; tmp = command_history_list_next(rec, tmp)) { + hv = (HV*)sv_2mortal((SV*)newHV()); + ent = tmp->data; + hv_store(hv, "text", 4, newSVpv(ent->text, 0), 0); + hv_store(hv, "time", 4, newSViv(ent->time), 0); + if (ent->history == command_history_current(NULL)) { + hv_store(hv, "history", 7, newSV(0), 0); + hv_store(hv, "window", 6, newSV(0), 0); + } else { + if (ent->history->name == NULL) { + hv_store(hv, "history", 7, newSV(0), 0); + for (stmp = windows; stmp != NULL; stmp = stmp->next) { + win = stmp->data; + if (win->history == ent->history) { + hv_store(hv, "window", 6, newSViv(win->refnum), 0); + break; + } + } + } else { + hv_store(hv, "history", 7, new_pv(ent->history->name), 0); + hv_store(hv, "window", 6, newSV(0), 0); + } + } + XPUSHs(sv_2mortal(newRV_inc((SV*)hv))); + } + +void +window_load_history_entries(window, ...) + Irssi::UI::Window window +PREINIT: + HV *hv; + SV **sv; + HISTORY_REC *history; + WINDOW_REC *tmp; + const char *text; + long hist_time; + int i; +PPCODE: + for (i = 1; i < items; i++) { + if (!is_hvref(ST(i))) { + croak("Usage: Irssi::UI::Window::load_history_entries(window, hash...)"); + } + hv = hvref(ST(i)); + if (hv != NULL) { + tmp = NULL; + text = NULL; + hist_time = time(NULL); + history = command_history_current(NULL); + + sv = hv_fetch(hv, "text", 4, 0); + if (sv != NULL) text = SvPV_nolen(*sv); + sv = hv_fetch(hv, "time", 4, 0); + if (sv != NULL && SvOK(*sv)) hist_time = SvIV(*sv); + + if (window != NULL) { + history = command_history_current(window); + } else { + sv = hv_fetch(hv, "history", 7, 0); + if (sv != NULL && SvOK(*sv)) { + history = command_history_find_name(SvPV_nolen(*sv)); + } + + sv = hv_fetch(hv, "window", 6, 0); + if (sv != NULL && SvOK(*sv)) { + tmp = window_find_refnum(SvIV(*sv)); + if (tmp != NULL) { + history = tmp->history; + } + } + } + + if (text != NULL && history != NULL) { + command_history_load_entry(hist_time, history, text); + } + } + } + +void +window_delete_history_entries(window, ...) + Irssi::UI::Window window +PREINIT: + HV *hv; + SV **sv; + HISTORY_REC *history; + WINDOW_REC *tmp; + const char *text; + long hist_time; + int i; +PPCODE: + for (i = 1; i < items; i++) { + if (!is_hvref(ST(i))) { + croak("Usage: Irssi::UI::Window::delete_history_entries(window, hash...)"); + } + hv = hvref(ST(i)); + if (hv != NULL) { + tmp = NULL; + text = NULL; + hist_time = -1; + history = command_history_current(NULL); + + sv = hv_fetch(hv, "text", 4, 0); + if (sv != NULL) text = SvPV_nolen(*sv); + sv = hv_fetch(hv, "time", 4, 0); + if (sv != NULL && SvOK(*sv)) hist_time = SvIV(*sv); + + if (window != NULL) { + history = command_history_current(window); + } else { + sv = hv_fetch(hv, "history", 7, 0); + if (sv != NULL && SvOK(*sv)) { + history = command_history_find_name(SvPV_nolen(*sv)); + } + + sv = hv_fetch(hv, "window", 6, 0); + if (sv != NULL && SvOK(*sv)) { + tmp = window_find_refnum(SvIV(*sv)); + if (tmp != NULL) { + history = tmp->history; + } + } + } + + if (text != NULL && history != NULL) { + XPUSHs(boolSV(command_history_delete_entry(hist_time, history, text))); + } + } + } #******************************* MODULE = Irssi::UI::Window PACKAGE = Irssi::Windowitem PREFIX = window_item_