Compare commits
2 Commits
b082e82b62
...
9323089d66
Author | SHA1 | Date | |
---|---|---|---|
9323089d66 | |||
de7df1f60d |
190
xC.c
190
xC.c
@ -1448,7 +1448,7 @@ enum formatter_item_type
|
|||||||
FORMATTER_ITEM_ATTR, ///< Formatting attributes
|
FORMATTER_ITEM_ATTR, ///< Formatting attributes
|
||||||
FORMATTER_ITEM_FG_COLOR, ///< Foreground colour
|
FORMATTER_ITEM_FG_COLOR, ///< Foreground colour
|
||||||
FORMATTER_ITEM_BG_COLOR, ///< Background colour
|
FORMATTER_ITEM_BG_COLOR, ///< Background colour
|
||||||
FORMATTER_ITEM_SIMPLE, ///< Toggle mIRC formatting
|
FORMATTER_ITEM_SIMPLE, ///< Toggle IRC formatting
|
||||||
FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
|
FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2089,7 +2089,7 @@ struct app_context
|
|||||||
int *nick_palette; ///< A 256-colour palette for nicknames
|
int *nick_palette; ///< A 256-colour palette for nicknames
|
||||||
size_t nick_palette_len; ///< Number of entries in nick_palette
|
size_t nick_palette_len; ///< Number of entries in nick_palette
|
||||||
|
|
||||||
bool awaiting_mirc_escape; ///< Awaiting a mIRC attribute escape
|
bool awaiting_formatting_escape; ///< Awaiting an IRC formatting escape
|
||||||
bool in_bracketed_paste; ///< User is pasting some content
|
bool in_bracketed_paste; ///< User is pasting some content
|
||||||
struct str input_buffer; ///< Buffered pasted content
|
struct str input_buffer; ///< Buffered pasted content
|
||||||
|
|
||||||
@ -2961,6 +2961,7 @@ attr_printer_apply (struct attr_printer *self,
|
|||||||
|
|
||||||
attr_printer_reset (self);
|
attr_printer_reset (self);
|
||||||
|
|
||||||
|
// TEXT_MONOSPACE is unimplemented, for obvious reasons
|
||||||
if (text_attrs)
|
if (text_attrs)
|
||||||
attr_printer_tputs (self, tparm (set_attributes,
|
attr_printer_tputs (self, tparm (set_attributes,
|
||||||
0, // standout
|
0, // standout
|
||||||
@ -3122,7 +3123,7 @@ irc_to_utf8 (const char *text)
|
|||||||
// #l inserts a locale-encoded string
|
// #l inserts a locale-encoded string
|
||||||
//
|
//
|
||||||
// #S inserts a string from the server with unknown encoding
|
// #S inserts a string from the server with unknown encoding
|
||||||
// #m inserts a mIRC-formatted string (auto-resets at boundaries)
|
// #m inserts an IRC-formatted string (auto-resets at boundaries)
|
||||||
// #n cuts the nickname from a string and automatically colours it
|
// #n cuts the nickname from a string and automatically colours it
|
||||||
// #N is like #n but also appends userhost, if present
|
// #N is like #n but also appends userhost, if present
|
||||||
//
|
//
|
||||||
@ -3153,8 +3154,6 @@ formatter_add_item (struct formatter *self, struct formatter_item template_)
|
|||||||
FORMATTER_ADD_ITEM ((self), ATTR, .attribute = ATTR_RESET)
|
FORMATTER_ADD_ITEM ((self), ATTR, .attribute = ATTR_RESET)
|
||||||
#define FORMATTER_ADD_TEXT(self, text_) \
|
#define FORMATTER_ADD_TEXT(self, text_) \
|
||||||
FORMATTER_ADD_ITEM ((self), TEXT, .text = (text_))
|
FORMATTER_ADD_ITEM ((self), TEXT, .text = (text_))
|
||||||
#define FORMATTER_ADD_SIMPLE(self, attribute_) \
|
|
||||||
FORMATTER_ADD_ITEM ((self), SIMPLE, .attribute = TEXT_ ## attribute_)
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
@ -3225,6 +3224,82 @@ irc_parse_mirc_color (const char *s, uint8_t *fg, uint8_t *bg)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
struct irc_char_attrs
|
||||||
|
{
|
||||||
|
uint8_t fg, bg; ///< {Fore,back}ground colour or 99
|
||||||
|
uint8_t attributes; ///< TEXT_* flags, except TEXT_BLINK
|
||||||
|
uint8_t starts_at_boundary; ///< Possible to split here?
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_serialize_char_attrs (const struct irc_char_attrs *attrs, struct str *out)
|
||||||
|
{
|
||||||
|
soft_assert (attrs->fg < 100 && attrs->bg < 100);
|
||||||
|
|
||||||
|
if (attrs->fg != 99 || attrs->bg != 99)
|
||||||
|
{
|
||||||
|
str_append_printf (out, "\x03%u", attrs->fg);
|
||||||
|
if (attrs->bg != 99)
|
||||||
|
str_append_printf (out, ",%02u", attrs->bg);
|
||||||
|
}
|
||||||
|
if (attrs->attributes & TEXT_BOLD) str_append_c (out, '\x02');
|
||||||
|
if (attrs->attributes & TEXT_ITALIC) str_append_c (out, '\x1d');
|
||||||
|
if (attrs->attributes & TEXT_UNDERLINE) str_append_c (out, '\x1f');
|
||||||
|
if (attrs->attributes & TEXT_INVERSE) str_append_c (out, '\x16');
|
||||||
|
if (attrs->attributes & TEXT_CROSSED_OUT) str_append_c (out, '\x1e');
|
||||||
|
if (attrs->attributes & TEXT_MONOSPACE) str_append_c (out, '\x11');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
irc_parse_attribute (char c)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\x02' /* ^B */: return TEXT_BOLD;
|
||||||
|
case '\x11' /* ^Q */: return TEXT_MONOSPACE;
|
||||||
|
case '\x16' /* ^V */: return TEXT_INVERSE;
|
||||||
|
case '\x1d' /* ^] */: return TEXT_ITALIC;
|
||||||
|
case '\x1e' /* ^^ */: return TEXT_CROSSED_OUT;
|
||||||
|
case '\x1f' /* ^_ */: return TEXT_UNDERLINE;
|
||||||
|
case '\x0f' /* ^O */: return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The text needs to be NUL-terminated, and a valid UTF-8 string
|
||||||
|
static struct irc_char_attrs *
|
||||||
|
irc_analyze_text (const char *text, size_t len)
|
||||||
|
{
|
||||||
|
struct irc_char_attrs *attrs = xcalloc (len, sizeof *attrs),
|
||||||
|
blank = { .fg = 99, .bg = 99, .starts_at_boundary = true },
|
||||||
|
next = blank, cur = next;
|
||||||
|
|
||||||
|
for (size_t i = 0; i != len; cur = next)
|
||||||
|
{
|
||||||
|
const char *start = text;
|
||||||
|
hard_assert (utf8_decode (&text, len - i) >= 0);
|
||||||
|
|
||||||
|
int attribute = irc_parse_attribute (*start);
|
||||||
|
if (*start == '\x03')
|
||||||
|
text = irc_parse_mirc_color (text, &next.fg, &next.bg);
|
||||||
|
else if (attribute > 0)
|
||||||
|
next.attributes ^= attribute;
|
||||||
|
else if (attribute < 0)
|
||||||
|
next = blank;
|
||||||
|
|
||||||
|
while (start++ != text)
|
||||||
|
{
|
||||||
|
attrs[i++] = cur;
|
||||||
|
cur.starts_at_boundary = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
formatter_parse_mirc_color (struct formatter *self, const char *s)
|
formatter_parse_mirc_color (struct formatter *self, const char *s)
|
||||||
{
|
{
|
||||||
@ -3247,7 +3322,7 @@ formatter_parse_mirc_color (struct formatter *self, const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
formatter_parse_mirc (struct formatter *self, const char *s)
|
formatter_parse_message (struct formatter *self, const char *s)
|
||||||
{
|
{
|
||||||
FORMATTER_ADD_RESET (self);
|
FORMATTER_ADD_RESET (self);
|
||||||
|
|
||||||
@ -3261,25 +3336,16 @@ formatter_parse_mirc (struct formatter *self, const char *s)
|
|||||||
str_reset (&buf);
|
str_reset (&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (c)
|
int attribute = irc_parse_attribute (c);
|
||||||
{
|
if (c == '\x03')
|
||||||
case '\x02': FORMATTER_ADD_SIMPLE (self, BOLD); break;
|
|
||||||
case '\x11': /* monospace, N/A */ break;
|
|
||||||
case '\x1d': FORMATTER_ADD_SIMPLE (self, ITALIC); break;
|
|
||||||
case '\x1e': FORMATTER_ADD_SIMPLE (self, CROSSED_OUT); break;
|
|
||||||
case '\x1f': FORMATTER_ADD_SIMPLE (self, UNDERLINE); break;
|
|
||||||
case '\x16': FORMATTER_ADD_SIMPLE (self, INVERSE); break;
|
|
||||||
|
|
||||||
case '\x03':
|
|
||||||
s = formatter_parse_mirc_color (self, s);
|
s = formatter_parse_mirc_color (self, s);
|
||||||
break;
|
else if (attribute > 0)
|
||||||
case '\x0f':
|
FORMATTER_ADD_ITEM (self, SIMPLE, .attribute = attribute);
|
||||||
|
else if (attribute < 0)
|
||||||
FORMATTER_ADD_RESET (self);
|
FORMATTER_ADD_RESET (self);
|
||||||
break;
|
else
|
||||||
default:
|
|
||||||
str_append_c (&buf, c);
|
str_append_c (&buf, c);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (buf.len)
|
if (buf.len)
|
||||||
FORMATTER_ADD_TEXT (self, buf.str);
|
FORMATTER_ADD_TEXT (self, buf.str);
|
||||||
@ -3388,7 +3454,7 @@ restart:
|
|||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
tmp = irc_to_utf8 ((s = va_arg (*ap, char *)));
|
tmp = irc_to_utf8 ((s = va_arg (*ap, char *)));
|
||||||
formatter_parse_mirc (self, tmp);
|
formatter_parse_message (self, tmp);
|
||||||
free (tmp);
|
free (tmp);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -6220,7 +6286,7 @@ irc_is_highlight (struct server *s, const char *message)
|
|||||||
// Strip formatting from the message so that it doesn't interfere
|
// Strip formatting from the message so that it doesn't interfere
|
||||||
// with nickname detection (colour sequences in particular)
|
// with nickname detection (colour sequences in particular)
|
||||||
struct formatter f = formatter_make (s->ctx, NULL);
|
struct formatter f = formatter_make (s->ctx, NULL);
|
||||||
formatter_parse_mirc (&f, message);
|
formatter_parse_message (&f, message);
|
||||||
|
|
||||||
struct str stripped = str_make ();
|
struct str stripped = str_make ();
|
||||||
for (size_t i = 0; i < f.items_len; i++)
|
for (size_t i = 0; i < f.items_len; i++)
|
||||||
@ -8240,70 +8306,6 @@ irc_process_message (const struct irc_message *msg, struct server *s)
|
|||||||
// This is a rather basic algorithm; something like ICU with proper
|
// This is a rather basic algorithm; something like ICU with proper
|
||||||
// locale specification would be needed to make it work better.
|
// locale specification would be needed to make it work better.
|
||||||
|
|
||||||
struct irc_char_attrs
|
|
||||||
{
|
|
||||||
uint8_t fg, bg; ///< {Fore,back}ground colour or 99
|
|
||||||
uint8_t attributes; ///< TEXT_* flags, except TEXT_BLINK
|
|
||||||
uint8_t starts_at_boundary; ///< Possible to split here?
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
irc_serialize_char_attrs (const struct irc_char_attrs *attrs, struct str *out)
|
|
||||||
{
|
|
||||||
soft_assert (attrs->fg < 100 && attrs->bg < 100);
|
|
||||||
|
|
||||||
if (attrs->fg != 99 || attrs->bg != 99)
|
|
||||||
{
|
|
||||||
str_append_printf (out, "\x03%u", attrs->fg);
|
|
||||||
if (attrs->bg != 99)
|
|
||||||
str_append_printf (out, ",%02u", attrs->bg);
|
|
||||||
}
|
|
||||||
if (attrs->attributes & TEXT_BOLD) str_append_c (out, '\x02');
|
|
||||||
if (attrs->attributes & TEXT_ITALIC) str_append_c (out, '\x1d');
|
|
||||||
if (attrs->attributes & TEXT_UNDERLINE) str_append_c (out, '\x1f');
|
|
||||||
if (attrs->attributes & TEXT_INVERSE) str_append_c (out, '\x16');
|
|
||||||
if (attrs->attributes & TEXT_CROSSED_OUT) str_append_c (out, '\x1e');
|
|
||||||
if (attrs->attributes & TEXT_MONOSPACE) str_append_c (out, '\x11');
|
|
||||||
}
|
|
||||||
|
|
||||||
// The text needs to be NUL-terminated
|
|
||||||
// TODO: try to deduplicate analogous code in formatter_parse_mirc()
|
|
||||||
static struct irc_char_attrs *
|
|
||||||
irc_analyze_text (const char *text, size_t len)
|
|
||||||
{
|
|
||||||
struct irc_char_attrs *attrs = xcalloc (len, sizeof *attrs),
|
|
||||||
blank = { .fg = 99, .bg = 99, .starts_at_boundary = true },
|
|
||||||
next = blank, cur = next;
|
|
||||||
|
|
||||||
for (size_t i = 0; i != len; cur = next)
|
|
||||||
{
|
|
||||||
const char *start = text;
|
|
||||||
hard_assert (utf8_decode (&text, len - i) >= 0);
|
|
||||||
switch (*start)
|
|
||||||
{
|
|
||||||
case '\x02': next.attributes ^= TEXT_BOLD; break;
|
|
||||||
case '\x11': next.attributes ^= TEXT_MONOSPACE; break;
|
|
||||||
case '\x1d': next.attributes ^= TEXT_ITALIC; break;
|
|
||||||
case '\x1e': next.attributes ^= TEXT_CROSSED_OUT; break;
|
|
||||||
case '\x1f': next.attributes ^= TEXT_UNDERLINE; break;
|
|
||||||
case '\x16': next.attributes ^= TEXT_INVERSE; break;
|
|
||||||
|
|
||||||
case '\x03':
|
|
||||||
text = irc_parse_mirc_color (text, &next.fg, &next.bg);
|
|
||||||
break;
|
|
||||||
case '\x0f':
|
|
||||||
next = blank;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (start++ != text)
|
|
||||||
{
|
|
||||||
attrs[i++] = cur;
|
|
||||||
cur.starts_at_boundary = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
wrap_text_for_single_line (const char *text, struct irc_char_attrs *attrs,
|
wrap_text_for_single_line (const char *text, struct irc_char_attrs *attrs,
|
||||||
size_t text_len, size_t target_len, struct str *output)
|
size_t text_len, size_t target_len, struct str *output)
|
||||||
@ -8344,8 +8346,6 @@ wrap_text_for_single_line (const char *text, struct irc_char_attrs *attrs,
|
|||||||
return eaten;
|
return eaten;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
// In practice, this should never fail at all, although it's not guaranteed
|
// In practice, this should never fail at all, although it's not guaranteed
|
||||||
static bool
|
static bool
|
||||||
wrap_message (const char *message,
|
wrap_message (const char *message,
|
||||||
@ -13500,7 +13500,7 @@ on_insert_attribute (int count, int key, void *user_data)
|
|||||||
(void) key;
|
(void) key;
|
||||||
|
|
||||||
struct app_context *ctx = user_data;
|
struct app_context *ctx = user_data;
|
||||||
ctx->awaiting_mirc_escape = true;
|
ctx->awaiting_formatting_escape = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13534,7 +13534,7 @@ input_add_functions (void *user_data)
|
|||||||
XX ("toggle-unimportant", "Toggle junk msgs", on_toggle_unimportant)
|
XX ("toggle-unimportant", "Toggle junk msgs", on_toggle_unimportant)
|
||||||
XX ("edit-input", "Edit input", on_edit_input)
|
XX ("edit-input", "Edit input", on_edit_input)
|
||||||
XX ("redraw-screen", "Redraw screen", on_redraw_screen)
|
XX ("redraw-screen", "Redraw screen", on_redraw_screen)
|
||||||
XX ("insert-attribute", "mIRC formatting", on_insert_attribute)
|
XX ("insert-attribute", "IRC formatting", on_insert_attribute)
|
||||||
XX ("start-paste-mode", "Bracketed paste", on_start_paste_mode)
|
XX ("start-paste-mode", "Bracketed paste", on_start_paste_mode)
|
||||||
#undef XX
|
#undef XX
|
||||||
}
|
}
|
||||||
@ -14064,7 +14064,7 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_mirc_escape (const struct pollfd *fd, struct app_context *ctx)
|
process_formatting_escape (const struct pollfd *fd, struct app_context *ctx)
|
||||||
{
|
{
|
||||||
// There's no other way with libedit, as both el_getc() in a function
|
// There's no other way with libedit, as both el_getc() in a function
|
||||||
// handler and CC_ARGHACK would block execution
|
// handler and CC_ARGHACK would block execution
|
||||||
@ -14116,7 +14116,7 @@ error:
|
|||||||
CALL (ctx->input, ding);
|
CALL (ctx->input, ding);
|
||||||
done:
|
done:
|
||||||
str_reset (buf);
|
str_reset (buf);
|
||||||
ctx->awaiting_mirc_escape = false;
|
ctx->awaiting_formatting_escape = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BRACKETED_PASTE_LIMIT 102400 ///< How much text can be pasted
|
#define BRACKETED_PASTE_LIMIT 102400 ///< How much text can be pasted
|
||||||
@ -14212,8 +14212,8 @@ 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)
|
if (ctx->awaiting_formatting_escape)
|
||||||
process_mirc_escape (fd, ctx);
|
process_formatting_escape (fd, ctx);
|
||||||
else if (ctx->in_bracketed_paste)
|
else if (ctx->in_bracketed_paste)
|
||||||
process_bracketed_paste (fd, ctx);
|
process_bracketed_paste (fd, ctx);
|
||||||
else if (!ctx->quitting)
|
else if (!ctx->quitting)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user