From e4cbd6cf3f983a5bb2e3517f6ca4bec243c09937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Tue, 12 May 2015 03:48:52 +0200 Subject: [PATCH] degesch: now we do formatting with M-m --- degesch.c | 169 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 48 deletions(-) diff --git a/degesch.c b/degesch.c index 4dc2f2c..6aaf971 100644 --- a/degesch.c +++ b/degesch.c @@ -246,6 +246,16 @@ input_bind_control (struct input *self, char key, const char *function_name) input_bind (self, keyseq, function_name); } +static void +input_insert_c (struct input *self, int c) +{ + char s[2] = { c, 0 }; + rl_insert_text (s); + + if (self->prompt_shown) + rl_redisplay (); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static int app_readline_init (void); @@ -543,6 +553,16 @@ input_erase (struct input *self) input_redisplay (self); } +static void +input_insert_c (struct input *self, int c) +{ + char s[2] = { c, 0 }; + el_insertstr (self->editline, s); + + if (self->prompt_shown) + input_redisplay (self); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void @@ -1129,6 +1149,10 @@ struct app_context iconv_t latin1_to_utf8; ///< ISO Latin 1 to UTF-8 struct input input; ///< User interface + + bool awaiting_mirc_escape; ///< Awaiting a mIRC attribute escape + char char_buf[MB_LEN_MAX + 1]; ///< Buffered multibyte char + size_t char_buf_len; ///< How much of an MB char is buffered } *g_ctx; @@ -4213,39 +4237,6 @@ irc_process_message (const struct irc_message *msg, irc_process_numeric (s, msg, numeric); } -// --- mIRC formatting --------------------------------------------------------- - -// Out user interface doesn't give us much of a choice with entering it. - -static char * -add_mirc_formatting (const char *text) -{ - struct str output; - str_init (&output); - - for (; *text; text++) - { - char c = *text; - if (c != '\\') - { - str_append_c (&output, c); - continue; - } - - switch (text[1]) - { - case 'b': c = '\x02'; text++; break; - case 'c': c = '\x03'; text++; break; - case 'i': c = '\x1d'; text++; break; - case '_': c = '\x1f'; text++; break; - case 'v': c = '\x16'; text++; break; - case 'o': c = '\x0f'; text++; break; - } - str_append_c (&output, c); - } - return str_steal (&output); -} - // --- Message autosplitting magic --------------------------------------------- // This is the most basic acceptable algorithm; something like ICU with proper @@ -4381,13 +4372,13 @@ send_autosplit_message (struct server *s, struct send_autosplit_args a) int fixed_part = strlen (a.command) + 1 + strlen (a.target) + 1 + 1 + strlen (a.prefix) + strlen (a.suffix); - // XXX: this may screw up the formatting if we do split the message - char *formatted = add_mirc_formatting (a.message); + // We might also want to preserve attributes across splits but + // that would make this code a lot more complicated struct str_vector lines; str_vector_init (&lines); struct error *e = NULL; - if (!irc_autosplit_message (s, formatted, fixed_part, &lines, &e)) + if (!irc_autosplit_message (s, a.message, fixed_part, &lines, &e)) { buffer_send_error (s->ctx, buffer ? buffer : s->buffer, "%s", e->message); @@ -4402,7 +4393,6 @@ send_autosplit_message (struct server *s, struct send_autosplit_args a) a.logger (s, &a, buffer, lines.vector[i]); } end: - free (formatted); str_vector_free (&lines); } @@ -5826,6 +5816,13 @@ jump_to_buffer (struct app_context *ctx, int n) return true; } +static void +await_mirc_escape (struct app_context *ctx) +{ + ctx->awaiting_mirc_escape = true; + ctx->char_buf_len = 0; +} + static void bind_common_keys (struct app_context *ctx) { @@ -5837,6 +5834,8 @@ bind_common_keys (struct app_context *ctx) for (int i = 0; i <= 9; i++) input_bind_meta (self, '0' + i, "goto-buffer"); + input_bind_meta (self, 'm', "insert-attribute"); + if (key_f5) input_bind (self, key_f5, "previous-buffer"); if (key_f6) @@ -5893,6 +5892,17 @@ on_readline_redraw_screen (int count, int key) return 0; } +static int +on_readline_insert_attribute (int count, int key) +{ + (void) count; + (void) key; + + struct app_context *ctx = g_ctx; + await_mirc_escape (ctx); + return 0; +} + static int on_readline_return (int count, int key) { @@ -5957,11 +5967,12 @@ app_readline_init (void) // our dear user could potentionally rig things up in a way that might // result in some funny unspecified behaviour - rl_add_defun ("previous-buffer", on_readline_previous_buffer, -1); - rl_add_defun ("next-buffer", on_readline_next_buffer, -1); - rl_add_defun ("goto-buffer", on_readline_goto_buffer, -1); - rl_add_defun ("redraw-screen", on_readline_redraw_screen, -1); - rl_add_defun ("send-line", on_readline_return, -1); + rl_add_defun ("previous-buffer", on_readline_previous_buffer, -1); + rl_add_defun ("next-buffer", on_readline_next_buffer, -1); + rl_add_defun ("goto-buffer", on_readline_goto_buffer, -1); + rl_add_defun ("redraw-screen", on_readline_redraw_screen, -1); + rl_add_defun ("insert-attribute", on_readline_insert_attribute, -1); + rl_add_defun ("send-line", on_readline_return, -1); bind_common_keys (ctx); @@ -6029,6 +6040,16 @@ on_editline_redraw_screen (EditLine *editline, int key) return CC_NORM; } +static unsigned char +on_editline_insert_attribute (EditLine *editline, int key) +{ + (void) editline; + (void) key; + + await_mirc_escape (g_ctx); + return CC_NORM; +} + static unsigned char on_editline_complete (EditLine *editline, int key) { @@ -6121,12 +6142,13 @@ app_editline_init (struct input *self) static const struct { const char *name; const char *help; unsigned char (*func) (EditLine *, int); } x[] = { - { "goto-buffer", "Go to buffer", on_editline_goto_buffer }, - { "previous-buffer", "Previous buffer", on_editline_previous_buffer }, - { "next-buffer", "Next buffer", on_editline_next_buffer }, - { "redraw-screen", "Redraw screen", on_editline_redraw_screen }, - { "send-line", "Send line", on_editline_return }, - { "complete", "Complete word", on_editline_complete }, + { "goto-buffer", "Go to buffer", on_editline_goto_buffer }, + { "previous-buffer", "Previous buffer", on_editline_previous_buffer }, + { "next-buffer", "Next buffer", on_editline_next_buffer }, + { "redraw-screen", "Redraw screen", on_editline_redraw_screen }, + { "insert-attribute", "mIRC formatting", on_editline_insert_attribute }, + { "send-line", "Send line", on_editline_return }, + { "complete", "Complete word", on_editline_complete }, }; for (size_t i = 0; i < N_ELEMENTS (x); i++) el_set (self->editline, EL_ADDFN, x[i].name, x[i].help, x[i].func); @@ -6375,6 +6397,51 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx) } } +static void +process_mirc_escape (const struct pollfd *fd, struct app_context *ctx) +{ + // There's no other way with libedit, as both el_getc() in a function + // handler and CC_ARGHACK would block execution + if (read (fd->fd, ctx->char_buf + ctx->char_buf_len, 1) != 1) + goto error; + + mbstate_t state; + memset (&state, 0, sizeof state); + + size_t len = mbrlen (ctx->char_buf, ++ctx->char_buf_len, &state); + + // Illegal sequence + if (len == (size_t) -1) + goto error; + + // Incomplete multibyte character + if (len == (size_t) -2) + return; + + if (ctx->char_buf_len != 1) + goto error; + switch (ctx->char_buf[0]) + { + case 'b': input_insert_c (&ctx->input, '\x02'); break; + case 'c': input_insert_c (&ctx->input, '\x03'); break; + case 'i': + case ']': input_insert_c (&ctx->input, '\x1d'); break; + case 'u': + case '_': input_insert_c (&ctx->input, '\x1f'); break; + case 'v': input_insert_c (&ctx->input, '\x16'); break; + case 'o': input_insert_c (&ctx->input, '\x0f'); break; + + default: + goto error; + } + goto done; + +error: + input_ding (&ctx->input); +done: + ctx->awaiting_mirc_escape = false; +} + static void on_tty_readable (const struct pollfd *fd, struct app_context *ctx) { @@ -6383,6 +6450,12 @@ on_tty_readable (const struct pollfd *fd, struct app_context *ctx) if (fd->revents & ~(POLLIN | POLLHUP | POLLERR)) print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents); + if (ctx->awaiting_mirc_escape) + { + process_mirc_escape (fd, ctx); + return; + } + // XXX: this may loop for a bit: stop the event or eat the input? // (This prevents a segfault when the input has been stopped.) if (ctx->input.active)