From e4cbd6cf3f983a5bb2e3517f6ca4bec243c09937 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Tue, 12 May 2015 03:48:52 +0200
Subject: 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)
--
cgit v1.2.3-70-g09d2