xC: normalize BSD Editline's history behaviour

Now it's a realistically useful frontend.
This commit is contained in:
Přemysl Eric Janouch 2022-08-27 14:35:07 +02:00
parent 03d8ea4c5a
commit c0996fcbe7
Signed by: p
GPG Key ID: A0420B94F92B9493
4 changed files with 46 additions and 15 deletions

2
NEWS
View File

@ -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

View File

@ -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

View File

@ -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
--------------

53
xC.c
View File

@ -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;
}