degesch: now we do formatting with M-m
This commit is contained in:
parent
06a24bd252
commit
e4cbd6cf3f
169
degesch.c
169
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)
|
||||
|
Loading…
Reference in New Issue
Block a user