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);
|
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)
|
||||||
|
|
Loading…
Reference in New Issue