xC: fully synchronize input history with frontends

The missing parts were:

 - frontends to client
 - client to frontends after the initial sync
 - frontend to other frontends
This commit is contained in:
Přemysl Eric Janouch 2022-10-05 00:16:57 +02:00
parent 4b7258cba0
commit 26ed2dbc77
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 96 additions and 20 deletions

116
xC.c
View File

@ -228,11 +228,13 @@ struct input_vtable
/// Create a new input buffer
input_buffer_t (*buffer_new) (void *input);
/// Destroy an input buffer
void (*buffer_destroy) (void *input, input_buffer_t buffer);
void (*buffer_destroy) (void *input, input_buffer_t);
/// Switch to a different input buffer
void (*buffer_switch) (void *input, input_buffer_t buffer);
void (*buffer_switch) (void *input, input_buffer_t);
/// Return all history lines in the locale encoding
struct strv (*buffer_history) (void *input, input_buffer_t buffer);
struct strv (*buffer_get_history) (void *input, input_buffer_t);
/// Add a history line in the locale encoding
void (*buffer_add_history) (void *input, input_buffer_t, const char *);
/// Register a function that can be bound to character sequences
void (*register_fn) (void *input,
@ -260,7 +262,8 @@ struct input_vtable
#define INPUT_VTABLE(XX) \
XX (start) XX (stop) XX (prepare) XX (destroy) \
XX (hide) XX (show) XX (get_prompt) XX (set_prompt) XX (ding) \
XX (buffer_new) XX (buffer_destroy) XX (buffer_switch) XX (buffer_history) \
XX (buffer_new) XX (buffer_destroy) XX (buffer_switch) \
XX (buffer_get_history) XX (buffer_add_history) \
XX (register_fn) XX (bind) XX (bind_control) XX (bind_meta) \
XX (get_line) XX (clear_line) XX (insert) \
XX (on_tty_resized) XX (on_tty_readable)
@ -564,6 +567,7 @@ input_rl_buffer_switch (void *input, input_buffer_t input_buffer)
{
struct input_rl *self = input;
struct input_rl_buffer *buffer = input_buffer;
// There could possibly be occurences of the current undo list in some
// history entry. We either need to free the undo list, or move it
// somewhere else to load back later, as the buffer we're switching to
@ -587,8 +591,9 @@ input_rl_buffer_switch (void *input, input_buffer_t input_buffer)
}
static struct strv
input_rl_buffer_history (void *input, input_buffer_t input_buffer)
input_rl_buffer_get_history (void *input, input_buffer_t input_buffer)
{
(void) input;
struct input_rl_buffer *buffer = input_buffer;
HIST_ENTRY **p =
buffer->history ? buffer->history->entries : history_list();
@ -598,6 +603,25 @@ input_rl_buffer_history (void *input, input_buffer_t input_buffer)
return v;
}
static void
input_rl_buffer_add_history (void *input, input_buffer_t input_buffer,
const char *line)
{
(void) input;
struct input_rl_buffer *buffer = input_buffer;
// For inactive buffers, we'd have to either alloc_history_entry(),
// construe a timestamp, and manually insert it into saved HISTORY_STATEs,
// or temporarily switch histories.
if (!buffer->history)
{
bool at_end = history_offset == history_length;
add_history (line);
if (at_end)
next_history ();
}
}
static void
input_rl__buffer_destroy_wo_history (struct input_rl_buffer *self)
{
@ -1069,13 +1093,15 @@ input_el_buffer_switch (void *input, input_buffer_t input_buffer)
self->current = buffer;
el_wset (self->editline, EL_HIST, history, buffer->history);
// We only know how to reset the history position to be at the end.
input_el__start_over (self);
input_el__restore_buffer (self, buffer);
}
static struct strv
input_el_buffer_history (void *input, input_buffer_t input_buffer)
input_el_buffer_get_history (void *input, input_buffer_t input_buffer)
{
(void) input;
struct input_el_buffer *buffer = input_buffer;
struct strv v = strv_make ();
HistEventW ev;
@ -1096,6 +1122,26 @@ input_el_buffer_history (void *input, input_buffer_t input_buffer)
return v;
}
static void
input_el_buffer_add_history (void *input, input_buffer_t input_buffer,
const char *line)
{
(void) input;
struct input_el_buffer *buffer = input_buffer;
// When currently iterating history, this makes editline's internal
// history pointer wrongly point to a newer entry.
size_t len = mbstowcs (NULL, line, 0);
if (len++ != (size_t) -1)
{
wchar_t *wc = xcalloc (len, sizeof *wc);
wc[mbstowcs (wc, line, len)] = 0;
HistEventW ev;
(void) history_w (buffer->history, &ev, H_ENTER, wc);
free (wc);
}
}
static void
input_el_buffer_destroy (void *input, input_buffer_t input_buffer)
{
@ -2899,12 +2945,15 @@ relay_send (struct client *c)
}
static void
relay_broadcast (struct app_context *ctx)
relay_broadcast_except (struct app_context *ctx, struct client *exception)
{
LIST_FOR_EACH (struct client, c, ctx->clients)
relay_send (c);
if (c != exception)
relay_send (c);
}
#define relay_broadcast(ctx) relay_broadcast_except ((ctx), NULL)
static struct relay_event_message *
relay_prepare (struct app_context *ctx)
{
@ -3131,16 +3180,13 @@ relay_prepare_buffer_activate (struct app_context *ctx, struct buffer *buffer)
static void
relay_prepare_buffer_input (struct app_context *ctx, struct buffer *buffer,
const char *locale_input)
const char *input)
{
struct relay_event_message *m = relay_prepare (ctx);
struct relay_event_data_buffer_input *e = &m->data.buffer_input;
e->event = RELAY_EVENT_BUFFER_INPUT;
e->buffer_name = str_from_cstr (buffer->name);
char *input = iconv_xstrdup (ctx->term_to_utf8,
(char *) locale_input, -1, NULL);
e->text = str_from_cstr (input);
free (input);
}
static void
@ -15305,12 +15351,18 @@ on_pending_input (struct app_context *ctx)
poller_idle_reset (&ctx->input_event);
for (size_t i = 0; i < ctx->pending_input.len; i++)
{
char *input = iconv_xstrdup
(ctx->term_to_utf8, ctx->pending_input.vector[i], -1, NULL);
if (input)
process_input (ctx, ctx->current_buffer, input);
else
char *input = iconv_xstrdup (ctx->term_to_utf8,
ctx->pending_input.vector[i], -1, NULL);
if (!input)
{
print_error ("character conversion failed for: %s", "user input");
continue;
}
relay_prepare_buffer_input (ctx, ctx->current_buffer, input);
relay_broadcast (ctx);
process_input (ctx, ctx->current_buffer, input);
free (input);
}
strv_reset (&ctx->pending_input);
@ -15362,11 +15414,21 @@ static void
client_resync_buffer_input (struct client *c, struct buffer *buffer)
{
struct strv history =
CALL_ (c->ctx->input, buffer_history, buffer->input_data);
CALL_ (c->ctx->input, buffer_get_history, buffer->input_data);
for (size_t i = 0; i < history.len; i++)
{
relay_prepare_buffer_input (c->ctx, buffer, history.vector[i]);
char *input = iconv_xstrdup (c->ctx->term_to_utf8,
history.vector[i], -1, NULL);
if (!input)
{
print_error ("character conversion failed for: %s",
"user input history");
continue;
}
relay_prepare_buffer_input (c->ctx, buffer, input);
relay_send (c);
free (input);
}
strv_free (&history);
}
@ -15462,6 +15524,20 @@ out:
relay_send (c);
}
static void
client_process_buffer_input
(struct client *c, struct buffer *buffer, const char *input)
{
char *mb = iconv_xstrdup (c->ctx->term_from_utf8, (char *) input, -1, NULL);
CALL_ (c->ctx->input, buffer_add_history, buffer->input_data, mb);
free (mb);
relay_prepare_buffer_input (c->ctx, buffer, input);
relay_broadcast_except (c->ctx, c);
process_input (c->ctx, buffer, input);
}
static void
client_process_buffer_log
(struct client *c, uint32_t seq, struct buffer *buffer)
@ -15544,7 +15620,7 @@ client_process_message (struct client *c,
buffer_activate (c->ctx, buffer);
break;
case RELAY_COMMAND_BUFFER_INPUT:
process_input (c->ctx, buffer, m->data.buffer_input.text.str);
client_process_buffer_input (c, buffer, m->data.buffer_input.text.str);
break;
case RELAY_COMMAND_BUFFER_TOGGLE_UNIMPORTANT:
buffer_toggle_unimportant (c->ctx, buffer);