summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2022-08-27 14:35:07 +0200
committerPřemysl Eric Janouch <p@janouch.name>2022-08-27 15:06:27 +0200
commitc0996fcbe75bd9003476337434ffc205749c3bdf (patch)
treea5b4bc510fe5062599cf54f2ba662bb938292550
parent03d8ea4c5ae9d33fc0bb06040b66bae02bd9eae6 (diff)
downloadxK-c0996fcbe75bd9003476337434ffc205749c3bdf.tar.gz
xK-c0996fcbe75bd9003476337434ffc205749c3bdf.tar.xz
xK-c0996fcbe75bd9003476337434ffc205749c3bdf.zip
xC: normalize BSD Editline's history behaviour
Now it's a realistically useful frontend.
-rw-r--r--NEWS2
-rw-r--r--README.adoc3
-rw-r--r--xC.adoc3
-rw-r--r--xC.c53
4 files changed, 46 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index c7a05c6..207ec9b 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ Unreleased
* xC: improved pager integration capabilities
+ * xC: normalized editline's history behaviour, making it a viable frontend
+
* xC: made it show WALLOPS messages, as PRIVMSG for the server buffer
* xD: implemented WALLOPS, choosing to make it target even non-operators
diff --git a/README.adoc b/README.adoc
index 7112a41..9d61d8c 100644
--- a/README.adoc
+++ b/README.adoc
@@ -77,9 +77,6 @@ Runtime dependencies: openssl +
Additionally for 'xC': curses, libffi, lua >= 5.3 (optional),
readline >= 6.0 or libedit >= 2013-07-12
-Avoid libedit if you can, in general it works but at the moment history is
-acting up and I have no clue about fixing it.
-
$ git clone --recursive https://git.janouch.name/p/xK.git
$ mkdir xK/build
$ cd xK/build
diff --git a/xC.adoc b/xC.adoc
index ba5c4c4..b2caa6d 100644
--- a/xC.adoc
+++ b/xC.adoc
@@ -114,8 +114,7 @@ _/usr/share/xC/plugins/_::
Bugs
----
-The editline (libedit) frontend is more of a proof of concept that mostly seems
-to work but exhibits bugs that are not our fault.
+The editline (libedit) frontend may exhibit some unexpected behaviour.
Reporting bugs
--------------
diff --git a/xC.c b/xC.c
index 535fbd9..ab51fae 100644
--- a/xC.c
+++ b/xC.c
@@ -761,6 +761,7 @@ struct input_el
{
struct input super; ///< Parent class
EditLine *editline; ///< The EditLine object
+ FILE *null; ///< Output redirect
bool active; ///< Are we a thing?
char *prompt; ///< The prompt we use
@@ -778,12 +779,12 @@ input_el__redisplay (void *input)
// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
// so we bind redisplay somewhere else in app_editline_init()
struct input_el *self = input;
- char x[] = { 'q' & 31, 0 };
- el_push (self->editline, x);
+ wchar_t x[] = { L'q' & 31, 0 };
+ el_wpush (self->editline, x);
// We have to do this or it gets stuck and nothing is done
- int count = 0;
- (void) el_wgets (self->editline, &count);
+ int dummy_count = 0;
+ (void) el_wgets (self->editline, &dummy_count);
}
static char *
@@ -1026,18 +1027,50 @@ input_el__restore (struct input_el *self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// XXX: Editline keeping its own history position (look for "eventno" there).
+// Invoking ed-next-history through our bind from app_editline_init() seems
+// like the only viable hack to get consistent history behaviour.
+static void
+input_el__bottom (struct input_el *self)
+{
+ // First, we need to redirect output to avoid ringing the terminal bell.
+ FILE *out = NULL;
+ el_wget (self->editline, EL_GETFP, 1, &out);
+ el_wset (self->editline, EL_SETFP, 1, self->null);
+
+ // Invoke hist_get() to make the history pointer's cursor match "eventno".
+ int down = 1, dummy_count = 0;
+ el_wpush (self->editline, L"\x1bn");
+ (void) el_wgets (self->editline, &dummy_count);
+
+ // It doesn't seem like we can just retrieve the position.
+ HistEventW ev;
+ while (!history_w (self->current->history, &ev, H_PREV))
+ down++;
+ while (down--)
+ {
+ el_wpush (self->editline, L"\x1bn");
+ (void) el_wgets (self->editline, &dummy_count);
+ }
+
+ el_wset (self->editline, EL_SETFP, 1, out);
+}
+
static void
input_el_buffer_switch (void *input, input_buffer_t input_buffer)
{
struct input_el *self = input;
struct input_el_buffer *buffer = input_buffer;
+ if (!self->active)
+ return;
if (self->current)
input_el__save_buffer (self, self->current);
- input_el__restore_buffer (self, buffer);
- el_wset (self->editline, EL_HIST, history, buffer->history);
self->current = buffer;
+ el_wset (self->editline, EL_HIST, history, buffer->history);
+ input_el__bottom (self);
+ input_el__restore_buffer (self, buffer);
}
static void
@@ -1111,7 +1144,7 @@ input_el_on_tty_readable (void *input)
if (!buf || count-- <= 0)
return;
- if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in editline */)
+ if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in el_wgets() */)
{
el_deletestr (self->editline, 1);
input_el__redisplay (self);
@@ -1131,6 +1164,7 @@ input_el_destroy (void *input)
free (iter->help);
ffi_closure_free (iter);
}
+ fclose (self->null);
free (self->prompt);
free (self);
}
@@ -1144,6 +1178,7 @@ input_el_new (void)
{
struct input_el *self = xcalloc (1, sizeof *self);
self->super.vtable = &input_el_vtable;
+ self->null = fopen ("/dev/null", "w");
return &self->super;
}
@@ -13908,13 +13943,10 @@ on_editline_return (EditLine *editline, int key)
wchar_t *line = calloc (sizeof *info->buffer, len + 1);
memcpy (line, info->buffer, sizeof *info->buffer * len);
- // XXX: Editline seems to remember its position in history,
- // so it's not going to work as you'd expect it to
if (*line)
{
HistEventW ev;
history_w (self->current->history, &ev, H_ENTER, line);
- print_debug ("history: %d %ls", ev.num, ev.str);
}
free (line);
@@ -13926,6 +13958,7 @@ on_editline_return (EditLine *editline, int key)
el_cursor (editline, len - point);
el_wdeletestr (editline, len);
+ input_el__bottom (self);
return CC_REFRESH;
}