diff options
Diffstat (limited to 'src/gui/gui-color.c')
-rw-r--r-- | src/gui/gui-color.c | 479 |
1 files changed, 469 insertions, 10 deletions
diff --git a/src/gui/gui-color.c b/src/gui/gui-color.c index cbebc317a..bf5538897 100644 --- a/src/gui/gui-color.c +++ b/src/gui/gui-color.c @@ -674,25 +674,30 @@ gui_color_decode (const char *string, const char *replacement) { if (ptr_string[1] == GUI_COLOR_EXTENDED_CHAR) { - if (ptr_string[2] && ptr_string[3] - && ptr_string[4] && ptr_string[5] - && ptr_string[6]) + ptr_string += 2; + if (ptr_string[0] && ptr_string[1] + && ptr_string[2] && ptr_string[3] + && ptr_string[4]) { - ptr_string += 7; + ptr_string += 5; } } else { - if (ptr_string[1] && ptr_string[2]) - ptr_string += 3; + ptr_string++; + if (ptr_string[0] && ptr_string[1]) + ptr_string += 2; } } break; case GUI_COLOR_EXTENDED_CHAR: - if ((isdigit (ptr_string[1])) && (isdigit (ptr_string[2])) - && (isdigit (ptr_string[3])) && (isdigit (ptr_string[4])) - && (isdigit (ptr_string[5]))) - ptr_string += 6; + ptr_string++; + if ((isdigit (ptr_string[0])) && (isdigit (ptr_string[1])) + && (isdigit (ptr_string[2])) && (isdigit (ptr_string[3])) + && (isdigit (ptr_string[4]))) + { + ptr_string += 5; + } break; case GUI_COLOR_EMPHASIS_CHAR: ptr_string++; @@ -1005,6 +1010,460 @@ gui_color_decode_ansi (const char *string, int keep_colors) } /* + * Adds an ANSI color code with a WeeChat attribute flag. + */ + +void +gui_color_add_ansi_flag (char **output, int flag) +{ + switch (flag) + { + case GUI_COLOR_EXTENDED_BOLD_FLAG: + string_dyn_concat (output, "\x1B[1m"); + break; + case GUI_COLOR_EXTENDED_REVERSE_FLAG: + string_dyn_concat (output, "\x1B[7m"); + break; + case GUI_COLOR_EXTENDED_ITALIC_FLAG: + string_dyn_concat (output, "\x1B[3m"); + break; + case GUI_COLOR_EXTENDED_UNDERLINE_FLAG: + string_dyn_concat (output, "\x1B[4m"); + break; + case GUI_COLOR_EXTENDED_KEEPATTR_FLAG: + /* nothing to do here (really? not sure) */ + break; + } +} + +/* + * Converts a WeeChat color number to an ANSI color number. + * + * Returns -1 if the color is not found. + */ + +int +gui_color_weechat_to_ansi (int color) +{ + const char *ptr_color_name; + int i; + + ptr_color_name = gui_color_search_index (color); + if (!ptr_color_name) + return -1; + + for (i = 0; i < 16; i++) + { + if (strcmp (gui_color_ansi[i], ptr_color_name) == 0) + return i; + } + + /* color not found */ + return -1; +} + +/* + * Replaces WeeChat colors by ANSI colors. + * + * Note: result must be freed after use. + */ + +char * +gui_color_encode_ansi (const char *string) +{ + const unsigned char *ptr_string; + char **out, str_concat[128], str_color[8], *error; + int flag, color, length, ansi_color, fg, bg, attrs; + + if (!string) + return NULL; + + out = string_dyn_alloc (((strlen (string) * 3) / 2) + 1); + + ptr_string = (unsigned char *)string; + while (ptr_string && ptr_string[0]) + { + switch (ptr_string[0]) + { + case GUI_COLOR_COLOR_CHAR: + ptr_string++; + switch (ptr_string[0]) + { + case GUI_COLOR_FG_CHAR: + ptr_string++; + if (ptr_string[0] == GUI_COLOR_EXTENDED_CHAR) + { + ptr_string++; + while ((flag = gui_color_attr_get_flag (ptr_string[0])) > 0) + { + gui_color_add_ansi_flag (out, flag); + ptr_string++; + } + if (ptr_string[0] && ptr_string[1] && ptr_string[2] + && ptr_string[3] && ptr_string[4]) + { + memcpy (str_color, ptr_string, 5); + str_color[5] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[38;5;%dm", + color); + string_dyn_concat (out, str_concat); + } + ptr_string += 5; + } + } + else + { + while ((flag = gui_color_attr_get_flag (ptr_string[0])) > 0) + { + gui_color_add_ansi_flag (out, flag); + ptr_string++; + } + if (ptr_string[0] && ptr_string[1]) + { + memcpy (str_color, ptr_string, 2); + str_color[2] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + ansi_color = gui_color_weechat_to_ansi (color); + if (ansi_color >= 0) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[%dm", + (ansi_color < 8) ? + ansi_color + 30 : ansi_color - 8 + 90); + string_dyn_concat (out, str_concat); + } + } + ptr_string += 2; + } + } + break; + case GUI_COLOR_BG_CHAR: + ptr_string++; + if (ptr_string[0] == GUI_COLOR_EXTENDED_CHAR) + { + ptr_string++; + if (ptr_string[0] && ptr_string[1] && ptr_string[2] + && ptr_string[3] && ptr_string[4]) + { + memcpy (str_color, ptr_string, 5); + str_color[5] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[48;5;%dm", + color); + string_dyn_concat (out, str_concat); + } + ptr_string += 5; + } + } + else + { + if (ptr_string[0] && ptr_string[1]) + { + memcpy (str_color, ptr_string, 2); + str_color[2] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + ansi_color = gui_color_weechat_to_ansi (color); + if (ansi_color >= 0) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[%dm", + (ansi_color < 8) ? + ansi_color + 40 : ansi_color - 8 + 100); + string_dyn_concat (out, str_concat); + } + } + ptr_string += 2; + } + } + break; + case GUI_COLOR_FG_BG_CHAR: + ptr_string++; + if (ptr_string[0] == GUI_COLOR_EXTENDED_CHAR) + { + ptr_string++; + while ((flag = gui_color_attr_get_flag (ptr_string[0])) > 0) + { + gui_color_add_ansi_flag (out, flag); + ptr_string++; + } + if (ptr_string[0] && ptr_string[1] && ptr_string[2] + && ptr_string[3] && ptr_string[4]) + { + memcpy (str_color, ptr_string, 5); + str_color[5] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[38;5;%dm", + color); + string_dyn_concat (out, str_concat); + } + ptr_string += 5; + } + } + else + { + while ((flag = gui_color_attr_get_flag (ptr_string[0])) > 0) + { + gui_color_add_ansi_flag (out, flag); + ptr_string++; + } + if (ptr_string[0] && ptr_string[1]) + { + memcpy (str_color, ptr_string, 2); + str_color[2] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + ansi_color = gui_color_weechat_to_ansi (color); + if (ansi_color >= 0) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[%dm", + (ansi_color < 8) ? + ansi_color + 30 : ansi_color - 8 + 90); + string_dyn_concat (out, str_concat); + } + } + ptr_string += 2; + } + } + /* + * note: the comma is an old separator not used any + * more (since WeeChat 2.6), but we still use it here + * so in case of/upgrade this will not break colors in + * old messages + */ + if ((ptr_string[0] == ',') || (ptr_string[0] == '~')) + { + if (ptr_string[1] == GUI_COLOR_EXTENDED_CHAR) + { + ptr_string += 2; + if (ptr_string[0] && ptr_string[1] + && ptr_string[2] && ptr_string[3] + && ptr_string[4]) + { + memcpy (str_color, ptr_string, 5); + str_color[5] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[48;5;%dm", + color); + string_dyn_concat (out, str_concat); + } + ptr_string += 5; + } + } + else + { + ptr_string++; + if (ptr_string[0] && ptr_string[1]) + { + memcpy (str_color, ptr_string, 2); + str_color[2] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + ansi_color = gui_color_weechat_to_ansi (color); + if (ansi_color >= 0) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[%dm", + (ansi_color < 8) ? + ansi_color + 40 : ansi_color - 8 + 100); + string_dyn_concat (out, str_concat); + } + } + ptr_string += 2; + } + } + } + break; + case GUI_COLOR_EXTENDED_CHAR: + ptr_string++; + if ((isdigit (ptr_string[0])) && (isdigit (ptr_string[1])) + && (isdigit (ptr_string[2])) && (isdigit (ptr_string[3])) + && (isdigit (ptr_string[4]))) + { + memcpy (str_color, ptr_string, 5); + str_color[5] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0]) + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[38;5;%dm", + color); + string_dyn_concat (out, str_concat); + } + ptr_string += 5; + } + break; + case GUI_COLOR_EMPHASIS_CHAR: + ptr_string++; + break; + case GUI_COLOR_BAR_CHAR: + ptr_string++; + switch (ptr_string[0]) + { + case GUI_COLOR_BAR_FG_CHAR: + case GUI_COLOR_BAR_BG_CHAR: + case GUI_COLOR_BAR_DELIM_CHAR: + case GUI_COLOR_BAR_START_INPUT_CHAR: + case GUI_COLOR_BAR_START_INPUT_HIDDEN_CHAR: + case GUI_COLOR_BAR_MOVE_CURSOR_CHAR: + case GUI_COLOR_BAR_START_ITEM: + case GUI_COLOR_BAR_START_LINE_ITEM: + ptr_string++; + break; + } + break; + case GUI_COLOR_RESET_CHAR: + ptr_string++; + string_dyn_concat (out, "\x1B[39m\x1B[49m"); + break; + default: + if (isdigit (ptr_string[0]) && isdigit (ptr_string[1])) + { + memcpy (str_color, ptr_string, 2); + str_color[2] = '\0'; + error = NULL; + color = (int)strtol (str_color, &error, 10); + if (error && !error[0] + && (color >= 0) + && (color < GUI_COLOR_NUM_COLORS)) + { + fg = gui_color[color]->foreground; + bg = gui_color[color]->background; + attrs = gui_color_get_extended_flags ( + gui_color[color]->attributes); + string_dyn_concat (out, "\x1B[0m"); + if (attrs & GUI_COLOR_EXTENDED_BOLD_FLAG) + string_dyn_concat (out, "\x1B[1m"); + if (attrs & GUI_COLOR_EXTENDED_REVERSE_FLAG) + string_dyn_concat (out, "\x1B[7m"); + if (attrs & GUI_COLOR_EXTENDED_ITALIC_FLAG) + string_dyn_concat (out, "\x1B[3m"); + if (attrs & GUI_COLOR_EXTENDED_UNDERLINE_FLAG) + string_dyn_concat (out, "\x1B[4m"); + if ((fg > 0) && (fg & GUI_COLOR_EXTENDED_FLAG)) + fg &= GUI_COLOR_EXTENDED_MASK; + if ((bg > 0) && (bg & GUI_COLOR_EXTENDED_FLAG)) + bg &= GUI_COLOR_EXTENDED_MASK; + if (fg < 0) + { + string_dyn_concat (out, "\x1B[39m"); + } + else + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[38;5;%dm", + fg); + string_dyn_concat (out, str_concat); + } + if (bg < 0) + { + string_dyn_concat (out, "\x1B[49m"); + } + else + { + snprintf (str_concat, sizeof (str_concat), + "\x1B[48;5;%dm", + bg); + string_dyn_concat (out, str_concat); + } + } + ptr_string += 2; + } + break; + } + break; + case GUI_COLOR_SET_ATTR_CHAR: + ptr_string++; + if (ptr_string[0]) + { + switch (ptr_string[0]) + { + case GUI_COLOR_ATTR_BOLD_CHAR: + string_dyn_concat (out, "\x1B[1m"); + break; + case GUI_COLOR_ATTR_REVERSE_CHAR: + string_dyn_concat (out, "\x1B[7m"); + break; + case GUI_COLOR_ATTR_ITALIC_CHAR: + string_dyn_concat (out, "\x1B[3m"); + break; + case GUI_COLOR_ATTR_UNDERLINE_CHAR: + string_dyn_concat (out, "\x1B[4m"); + break; + } + ptr_string++; + } + break; + case GUI_COLOR_REMOVE_ATTR_CHAR: + ptr_string++; + if (ptr_string[0]) + { + switch (ptr_string[0]) + { + case GUI_COLOR_ATTR_BOLD_CHAR: + string_dyn_concat (out, "\x1B[21m"); + break; + case GUI_COLOR_ATTR_REVERSE_CHAR: + string_dyn_concat (out, "\x1B[27m"); + break; + case GUI_COLOR_ATTR_ITALIC_CHAR: + string_dyn_concat (out, "\x1B[23m"); + break; + case GUI_COLOR_ATTR_UNDERLINE_CHAR: + string_dyn_concat (out, "\x1B[24m"); + break; + } + ptr_string++; + } + break; + case GUI_COLOR_RESET_CHAR: + string_dyn_concat (out, "\x1B[0m"); + ptr_string++; + break; + default: + length = utf8_char_size ((char *)ptr_string); + if (length == 0) + length = 1; + memcpy (str_concat, ptr_string, length); + str_concat[length] = '\0'; + string_dyn_concat (out, str_concat); + ptr_string += length; + break; + } + } + + return string_dyn_free (out, 0); +} + +/* * Emphasizes a string or regular expression in a string (which can contain * colors). * |