degesch: now we do formatting with M-m

This commit is contained in:
Přemysl Eric Janouch 2015-05-12 03:48:52 +02:00
parent 06a24bd252
commit e4cbd6cf3f
1 changed files with 121 additions and 48 deletions

169
degesch.c
View File

@ -246,6 +246,16 @@ input_bind_control (struct input *self, char key, const char *function_name)
input_bind (self, keyseq, 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); static int app_readline_init (void);
@ -543,6 +553,16 @@ input_erase (struct input *self)
input_redisplay (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 static void
@ -1129,6 +1149,10 @@ struct app_context
iconv_t latin1_to_utf8; ///< ISO Latin 1 to UTF-8 iconv_t latin1_to_utf8; ///< ISO Latin 1 to UTF-8
struct input input; ///< User interface 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; *g_ctx;
@ -4213,39 +4237,6 @@ irc_process_message (const struct irc_message *msg,
irc_process_numeric (s, msg, numeric); 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 --------------------------------------------- // --- Message autosplitting magic ---------------------------------------------
// This is the most basic acceptable algorithm; something like ICU with proper // 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 int fixed_part = strlen (a.command) + 1 + strlen (a.target) + 1 + 1
+ strlen (a.prefix) + strlen (a.suffix); + strlen (a.prefix) + strlen (a.suffix);
// XXX: this may screw up the formatting if we do split the message // We might also want to preserve attributes across splits but
char *formatted = add_mirc_formatting (a.message); // that would make this code a lot more complicated
struct str_vector lines; struct str_vector lines;
str_vector_init (&lines); str_vector_init (&lines);
struct error *e = NULL; 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_send_error (s->ctx,
buffer ? buffer : s->buffer, "%s", e->message); 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]); a.logger (s, &a, buffer, lines.vector[i]);
} }
end: end:
free (formatted);
str_vector_free (&lines); str_vector_free (&lines);
} }
@ -5826,6 +5816,13 @@ jump_to_buffer (struct app_context *ctx, int n)
return true; return true;
} }
static void
await_mirc_escape (struct app_context *ctx)
{
ctx->awaiting_mirc_escape = true;
ctx->char_buf_len = 0;
}
static void static void
bind_common_keys (struct app_context *ctx) 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++) for (int i = 0; i <= 9; i++)
input_bind_meta (self, '0' + i, "goto-buffer"); input_bind_meta (self, '0' + i, "goto-buffer");
input_bind_meta (self, 'm', "insert-attribute");
if (key_f5) if (key_f5)
input_bind (self, key_f5, "previous-buffer"); input_bind (self, key_f5, "previous-buffer");
if (key_f6) if (key_f6)
@ -5893,6 +5892,17 @@ on_readline_redraw_screen (int count, int key)
return 0; 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 static int
on_readline_return (int count, int key) 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 // our dear user could potentionally rig things up in a way that might
// result in some funny unspecified behaviour // result in some funny unspecified behaviour
rl_add_defun ("previous-buffer", on_readline_previous_buffer, -1); rl_add_defun ("previous-buffer", on_readline_previous_buffer, -1);
rl_add_defun ("next-buffer", on_readline_next_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 ("goto-buffer", on_readline_goto_buffer, -1);
rl_add_defun ("redraw-screen", on_readline_redraw_screen, -1); rl_add_defun ("redraw-screen", on_readline_redraw_screen, -1);
rl_add_defun ("send-line", on_readline_return, -1); rl_add_defun ("insert-attribute", on_readline_insert_attribute, -1);
rl_add_defun ("send-line", on_readline_return, -1);
bind_common_keys (ctx); bind_common_keys (ctx);
@ -6029,6 +6040,16 @@ on_editline_redraw_screen (EditLine *editline, int key)
return CC_NORM; 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 static unsigned char
on_editline_complete (EditLine *editline, int key) 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; static const struct { const char *name; const char *help;
unsigned char (*func) (EditLine *, int); } x[] = unsigned char (*func) (EditLine *, int); } x[] =
{ {
{ "goto-buffer", "Go to buffer", on_editline_goto_buffer }, { "goto-buffer", "Go to buffer", on_editline_goto_buffer },
{ "previous-buffer", "Previous buffer", on_editline_previous_buffer }, { "previous-buffer", "Previous buffer", on_editline_previous_buffer },
{ "next-buffer", "Next buffer", on_editline_next_buffer }, { "next-buffer", "Next buffer", on_editline_next_buffer },
{ "redraw-screen", "Redraw screen", on_editline_redraw_screen }, { "redraw-screen", "Redraw screen", on_editline_redraw_screen },
{ "send-line", "Send line", on_editline_return }, { "insert-attribute", "mIRC formatting", on_editline_insert_attribute },
{ "complete", "Complete word", on_editline_complete }, { "send-line", "Send line", on_editline_return },
{ "complete", "Complete word", on_editline_complete },
}; };
for (size_t i = 0; i < N_ELEMENTS (x); i++) 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); 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 static void
on_tty_readable (const struct pollfd *fd, struct app_context *ctx) 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)) if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents); 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? // XXX: this may loop for a bit: stop the event or eat the input?
// (This prevents a segfault when the input has been stopped.) // (This prevents a segfault when the input has been stopped.)
if (ctx->input.active) if (ctx->input.active)