From 26ed2dbc77dea089f769180940d452353826eee7 Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Wed, 5 Oct 2022 00:16:57 +0200 Subject: 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 --- xC.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 20 deletions(-) diff --git a/xC.c b/xC.c index dd4dc0c..200d159 100644 --- a/xC.c +++ b/xC.c @@ -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); -- cgit v1.2.3-70-g09d2