diff --git a/doc/en/weechat_plugin_api.en.txt b/doc/en/weechat_plugin_api.en.txt index a57636d20..6d2fb9bb4 100644 --- a/doc/en/weechat_plugin_api.en.txt +++ b/doc/en/weechat_plugin_api.en.txt @@ -9132,12 +9132,12 @@ List of modifiers used by WeeChat and plugins: | irc_color_decode | "1" to keep colors, "0" to remove colors | Any string | - String with WeeChat color codes, or without color + String with IRC colors converted to WeeChat colors (or IRC colors removed) | irc_color_encode | "1" to keep colors, "0" to remove colors | Any string | - String with IRC color codes, or without color + String with IRC colors (or IRC colors removed) | irc_command_auth + _(WeeChat ≥ 0.4.1)_ | @@ -9175,6 +9175,12 @@ List of modifiers used by WeeChat and plugins: fit in 512 bytes) | New content of message +| color_decode_ansi + + _(WeeChat ≥ 0.4.4)_ | + "1" to keep colors, "0" to remove colors | + Any string | + String with ANSI colors converted to WeeChat colors (or ANSI colors removed) + | bar_condition_yyy ^(2)^ | String with window pointer ("0x123..") | Empty string | diff --git a/doc/fr/weechat_plugin_api.fr.txt b/doc/fr/weechat_plugin_api.fr.txt index 20ecc200a..1cc76476f 100644 --- a/doc/fr/weechat_plugin_api.fr.txt +++ b/doc/fr/weechat_plugin_api.fr.txt @@ -9300,12 +9300,13 @@ Liste des modificateurs utilisés par WeeChat et les extensions : | irc_color_decode | "1" pour garder les couleurs, "0" pour les supprimer | Toute chaîne | - Chaîne avec des codes couleur WeeChat, ou sans couleur + Chaîne avec les couleurs IRC converties en couleurs WeeChat (ou avec les + couleurs IRC supprimées) | irc_color_encode | "1" pour garder les couleurs, "0" pour les supprimer | Toute chaîne | - Chaîne avec des codes couleur IRC, ou sans couleur + Chaîne avec les couleurs IRC (ou avec les couleurs IRC supprimées) | irc_command_auth + _(WeeChat ≥ 0.4.1)_ | @@ -9343,6 +9344,13 @@ Liste des modificateurs utilisés par WeeChat et les extensions : automatique pour tenir dans les 512 octets) | Nouveau contenu du message +| color_decode_ansi + + _(WeeChat ≥ 0.4.4)_ | + "1" pour garder les couleurs, "0" pour les supprimer | + Toute chaîne | + Chaîne avec les couleurs ANSI converties en couleurs WeeChat (ou avec les + couleurs ANSI supprimées) + | bar_condition_yyy ^(2)^ | Chaîne avec un pointeur vers la fenêtre ("0x123..") | Chaîne vide | diff --git a/doc/it/weechat_plugin_api.it.txt b/doc/it/weechat_plugin_api.it.txt index eaccf8cc0..c9cd4f236 100644 --- a/doc/it/weechat_plugin_api.it.txt +++ b/doc/it/weechat_plugin_api.it.txt @@ -9356,15 +9356,17 @@ List of modifiers used by WeeChat and plugins: Qualsiasi stringa | Stringa codificata da UTF-8 al set caratteri trovato per il plugin/buffer +// TRANSLATION MISSING | irc_color_decode | "1" per mantenere i colori, "0" per rimuovere i colori | Qualsiasi stringa | - Stringa con i codici colori di Weechat, o senza colore + String with IRC colors converted to WeeChat colors (or IRC colors removed) +// TRANSLATION MISSING | irc_color_encode | "1" per mantenere i colori, "0" per rimuovere i colori | Qualsiasi stringa | - Stringa con i codici colori IRC, o senza colore + String with IRC colors (or IRC colors removed) // TRANSLATION MISSING | irc_command_auth + @@ -9402,6 +9404,13 @@ List of modifiers used by WeeChat and plugins: Contenuto del messaggio che sta per essere inviato al server IRC (dopo la divisione automatica da adattare in 512 byte) | Nuovo contenuto del messaggio +// TRANSLATION MISSING +| color_decode_ansi + + _(WeeChat ≥ 0.4.4)_ | + "1" per mantenere i colori, "0" per rimuovere i colori | + Qualsiasi stringa | + String with ANSI colors converted to WeeChat colors (or ANSI colors removed) + | bar_condition_yyy ^(2)^ | Stringa con puntatore alla finestra ("0x123..") | Stringa vuota | diff --git a/doc/ja/weechat_plugin_api.ja.txt b/doc/ja/weechat_plugin_api.ja.txt index 136950763..796303068 100644 --- a/doc/ja/weechat_plugin_api.ja.txt +++ b/doc/ja/weechat_plugin_api.ja.txt @@ -9148,15 +9148,17 @@ WeeChat とプラグインが使う修飾子のリスト: 任意の文字列 | UTF-8 からプラグインおよびバッファの文字セットにエンコードされた文字列 +// TRANSLATION MISSING | irc_color_decode | 色を保持する場合は "1"、削除する場合は "0" | 任意の文字列 | - WeeChat 色コードを含む文字列および含まない文字列 + String with IRC colors converted to WeeChat colors (or IRC colors removed) +// TRANSLATION MISSING | irc_color_encode | 色を保持する場合は "1"、削除する場合は "0" | 任意の文字列 | - IRC 色コードを含む文字列および含まない文字列 + String with IRC colors (or IRC colors removed) | irc_command_auth + _(WeeChat バージョン 0.4.1 以上で利用可)_ | @@ -9192,6 +9194,13 @@ WeeChat とプラグインが使う修飾子のリスト: IRC サーバに送信するメッセージの内容 (512 バイトを超えないように自動分割した後) | メッセージの新しい内容 +// TRANSLATION MISSING +| color_decode_ansi + + _(WeeChat バージョン 0.4.4 以上で利用可)_ | + 色を保持する場合は "1"、削除する場合は "0" | + 任意の文字列 | + String with ANSI colors converted to WeeChat colors (or ANSI colors removed) + | bar_condition_yyy ^(2)^ | ウィンドウへのポインタの文字列 ("0x123..") | 空文字列 | diff --git a/src/gui/curses/gui-curses-color.c b/src/gui/curses/gui-curses-color.c index 41ce2b54a..60291421b 100644 --- a/src/gui/curses/gui-curses-color.c +++ b/src/gui/curses/gui-curses-color.c @@ -1539,20 +1539,3 @@ gui_color_dump () } } } - -/* - * Ends GUI colors. - */ - -void -gui_color_end () -{ - int i; - - for (i = 0; i < GUI_COLOR_NUM_COLORS; i++) - { - gui_color_free (gui_color[i]); - } - gui_color_palette_free_structs (); - gui_color_free_vars (); -} diff --git a/src/gui/curses/gui-curses.h b/src/gui/curses/gui-curses.h index 35c4b9b20..7553e842f 100644 --- a/src/gui/curses/gui-curses.h +++ b/src/gui/curses/gui-curses.h @@ -86,7 +86,6 @@ extern int gui_color_get_pair (int fg, int bg); extern int gui_color_weechat_get_pair (int weechat_color); extern void gui_color_pre_init (); extern void gui_color_init (); -extern void gui_color_end (); /* chat functions */ extern void gui_chat_calculate_line_diff (struct t_gui_window *window, diff --git a/src/gui/gui-color.c b/src/gui/gui-color.c index 59bf114c1..e62f6bc24 100644 --- a/src/gui/gui-color.c +++ b/src/gui/gui-color.c @@ -100,6 +100,11 @@ int gui_color_term256[256] = 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee, /* 252-255 */ }; +/* ANSI colors */ +regex_t *gui_color_regex_ansi = NULL; +char *gui_color_ansi[8] = +{ "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" }; + /* * Searches for a color with configuration option name. @@ -704,6 +709,216 @@ gui_color_decode (const char *string, const char *replacement) return (char *)out; } +/* + * Converts ANSI color codes to WeeChat colors (or removes them). + * + * This callback is called by gui_color_decode_ansi, it must not be called + * directly. + */ + +char * +gui_color_decode_ansi_cb (void *data, const char *text) +{ + unsigned long keep_colors; + char *text2, **items, *output, str_color[128]; + int i, length, num_items, value; + + keep_colors = (unsigned long)data; + + /* if we don't keep colors of if text is empty, just return empty string */ + if (!keep_colors || !text || !text[0]) + return strdup (""); + + /* only sequences ending with 'm' are used, the others are discarded */ + length = strlen (text); + if (text[length - 1] != 'm') + return strdup (""); + + /* sequence "\33[m" resets color */ + if (length < 4) + return strdup (gui_color_get_custom ("reset")); + + text2 = NULL; + items = NULL; + output = NULL; + + /* extract text between "\33[" and "m" */ + text2 = string_strndup (text + 2, length - 3); + if (!text2) + goto end; + + items = string_split (text2, ";", 0, 0, &num_items); + if (!items) + goto end; + + output = malloc ((32 * num_items) + 1); + if (!output) + goto end; + output[0] = '\0'; + + for (i = 0; i < num_items; i++) + { + value = atoi (items[i]); + switch (value) + { + case 0: /* reset */ + strcat (output, gui_color_get_custom ("reset")); + break; + case 1: /* bold */ + strcat (output, gui_color_get_custom ("bold")); + break; + case 2: /* remove bold */ + case 21: + case 22: + strcat (output, gui_color_get_custom ("-bold")); + break; + case 3: /* italic */ + strcat (output, gui_color_get_custom ("italic")); + break; + case 4: /* underline */ + strcat (output, gui_color_get_custom ("underline")); + break; + case 23: /* remove italic */ + strcat (output, gui_color_get_custom ("-italic")); + break; + case 24: /* remove underline */ + strcat (output, gui_color_get_custom ("-underline")); + break; + case 30: /* text color */ + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + strcat (output, + gui_color_get_custom (gui_color_ansi[value - 30])); + break; + case 38: /* text color */ + if (i + 1 < num_items) + { + switch (atoi (items[i + 1])) + { + case 2: /* RGB color */ + if (i + 4 < num_items) + { + snprintf (str_color, sizeof (str_color), + "|%d", + gui_color_convert_rgb_to_term ( + (atoi (items[i + 2]) << 16) | + (atoi (items[i + 3]) << 8) | + atoi (items[i + 4]), + 256)); + strcat (output, gui_color_get_custom (str_color)); + i += 4; + } + break; + case 5: /* terminal color (0-255) */ + if (i + 2 < num_items) + { + snprintf (str_color, sizeof (str_color), + "|%d", atoi (items[i + 2])); + strcat (output, gui_color_get_custom (str_color)); + i += 2; + } + break; + } + } + break; + case 39: /* default text color */ + strcat (output, gui_color_get_custom ("default")); + break; + case 40: /* background color */ + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + snprintf (str_color, sizeof (str_color), + "|,%s", + gui_color_ansi[value - 40]); + strcat (output, gui_color_get_custom (str_color)); + break; + case 48: /* background color */ + if (i + 1 < num_items) + { + switch (atoi (items[i + 1])) + { + case 2: /* RGB color */ + if (i + 4 < num_items) + { + snprintf (str_color, sizeof (str_color), + "|,%d", + gui_color_convert_rgb_to_term ( + (atoi (items[i + 2]) << 16) | + (atoi (items[i + 3]) << 8) | + atoi (items[i + 4]), + 256)); + strcat (output, gui_color_get_custom (str_color)); + i += 4; + } + break; + case 5: /* terminal color (0-255) */ + if (i + 2 < num_items) + { + snprintf (str_color, sizeof (str_color), + "|,%d", atoi (items[i + 2])); + strcat (output, gui_color_get_custom (str_color)); + i += 2; + } + break; + } + } + break; + case 49: /* default background color */ + strcat (output, gui_color_get_custom (",default")); + break; + } + } + +end: + if (items) + string_free_split (items); + if (text2) + free (text2); + + return (output) ? output : strdup (""); +} + +/* + * Converts ANSI color codes to WeeChat colors (or removes them). + * + * Note: result must be freed after use. + */ + +char * +gui_color_decode_ansi (const char *string, int keep_colors) +{ + /* allocate/compile regex if needed (first call) */ + if (!gui_color_regex_ansi) + { + gui_color_regex_ansi = malloc (sizeof (*gui_color_regex_ansi)); + if (!gui_color_regex_ansi) + return NULL; + if (string_regcomp (gui_color_regex_ansi, + GUI_COLOR_REGEX_ANSI_DECODE, + REG_EXTENDED) != 0) + { + free (gui_color_regex_ansi); + gui_color_regex_ansi = NULL; + return NULL; + } + } + + return string_replace_regex (string, gui_color_regex_ansi, + "$0", '$', + &gui_color_decode_ansi_cb, + (void *)((unsigned long)keep_colors)); +} + /* * Emphasizes a string or regular expression in a string (which can contain * colors). @@ -1027,3 +1242,27 @@ gui_color_palette_free_structs () if (gui_color_list_with_alias) weelist_free (gui_color_list_with_alias); } + +/* + * Ends GUI colors. + */ + +void +gui_color_end () +{ + int i; + + for (i = 0; i < GUI_COLOR_NUM_COLORS; i++) + { + gui_color_free (gui_color[i]); + } + gui_color_palette_free_structs (); + gui_color_free_vars (); + + if (gui_color_regex_ansi) + { + regfree (gui_color_regex_ansi); + free (gui_color_regex_ansi); + gui_color_regex_ansi = NULL; + } +} diff --git a/src/gui/gui-color.h b/src/gui/gui-color.h index a40527ca9..b19a500f7 100644 --- a/src/gui/gui-color.h +++ b/src/gui/gui-color.h @@ -138,6 +138,12 @@ enum t_gui_color_enum #define GUI_COLOR_EXTENDED_MASK 0x00FFFFF #define GUI_COLOR_EXTENDED_MAX 99999 +#define GUI_COLOR_REGEX_ANSI_DECODE \ + "\33(" \ + "([()].)|" \ + "([<>])|" \ + "(\\[[0-9;?]*[A-Za-z]))" + /* color structure */ struct t_gui_color @@ -169,9 +175,10 @@ extern const char *gui_color_search_config (const char *color_name); extern int gui_color_attr_get_flag (char c); extern void gui_color_attr_build_string (int color, char *str_attr); extern const char *gui_color_get_custom (const char *color_name); -extern char *gui_color_decode (const char *string, const char *replacement); extern int gui_color_convert_term_to_rgb (int color); extern int gui_color_convert_rgb_to_term (int rgb, int limit); +extern char *gui_color_decode (const char *string, const char *replacement); +extern char *gui_color_decode_ansi (const char *string, int keep_colors); extern char *gui_color_emphasize (const char *string, const char *search, int case_sensitive, regex_t *regex); extern void gui_color_free (struct t_gui_color *color); @@ -180,7 +187,7 @@ extern int gui_color_palette_get_alias (const char *alias); extern struct t_gui_color_palette *gui_color_palette_get (int number); extern void gui_color_palette_add (int number, const char *value); extern void gui_color_palette_remove (int number); -extern void gui_color_palette_free_structs (); +extern void gui_color_end (); /* color functions (GUI dependent) */ @@ -191,6 +198,7 @@ extern int gui_color_assign_by_diff (int *color, const char *color_name, extern int gui_color_get_weechat_colors_number (); extern int gui_color_get_term_colors (); extern const char *gui_color_get_name (int num_color); +extern void gui_color_free_vars (); extern void gui_color_init_weechat (); extern void gui_color_display_terminal_colors (); extern void gui_color_info_term_colors (char *buffer, int size); diff --git a/src/plugins/plugin-api.c b/src/plugins/plugin-api.c index 8a1c4dfb7..5dd4a983a 100644 --- a/src/plugins/plugin-api.c +++ b/src/plugins/plugin-api.c @@ -277,6 +277,25 @@ plugin_api_command (struct t_weechat_plugin *plugin, free (command2); } +/* + * Modifier to decode ANSI colors. + */ + +char * +plugin_api_modifier_color_decode_ansi (void *data, + const char *modifier, + const char *modifier_data, + const char *string) +{ + /* make C compiler happy */ + (void) data; + (void) modifier; + + return gui_color_decode_ansi (string, + (modifier_data && (strcmp (modifier_data, "1") == 0)) ? + 1: 0); +} + /* * Gets info about WeeChat. */ @@ -288,10 +307,11 @@ plugin_api_info_get_internal (void *data, const char *info_name, time_t inactivity; static char value[32], version_number[32] = { '\0' }; static char weechat_dir_absolute_path[PATH_MAX] = { '\0' }; + int rgb, limit; + char *pos, *color; /* make C compiler happy */ (void) data; - (void) arguments; if (!info_name) return NULL; @@ -397,6 +417,43 @@ plugin_api_info_get_internal (void *data, const char *info_name, snprintf (value, sizeof (value), "%d", gui_window_get_height ()); return value; } + else if (string_strcasecmp (info_name, "color_ansi_regex") == 0) + { + return GUI_COLOR_REGEX_ANSI_DECODE; + } + else if (string_strcasecmp (info_name, "color_term2rgb") == 0) + { + if (arguments && arguments[0]) + { + snprintf (value, sizeof (value), + "%d", + gui_color_convert_term_to_rgb (atoi (arguments))); + return value; + } + } + else if (string_strcasecmp (info_name, "color_rgb2term") == 0) + { + if (arguments && arguments[0]) + { + limit = 256; + pos = strchr (arguments, ','); + if (pos) + { + color = string_strndup (arguments, pos - arguments); + if (!color) + return NULL; + rgb = atoi (color); + limit = atoi (pos + 1); + free (color); + } + else + rgb = atoi (arguments); + snprintf (value, sizeof (value), + "%d", + gui_color_convert_rgb_to_term (rgb, limit)); + return value; + } + } /* info not found */ return NULL; @@ -1097,6 +1154,10 @@ plugin_api_infolist_free (struct t_infolist *infolist) void plugin_api_init () { + /* WeeChat core modifiers */ + hook_modifier (NULL, "color_decode_ansi", + &plugin_api_modifier_color_decode_ansi, NULL); + /* WeeChat core info hooks */ hook_info (NULL, "version", N_("WeeChat version"), NULL, &plugin_api_info_get_internal, NULL); @@ -1141,6 +1202,12 @@ plugin_api_init () &plugin_api_info_get_internal, NULL); hook_info (NULL, "term_height", N_("height of terminal"), NULL, &plugin_api_info_get_internal, NULL); + hook_info (NULL, "color_ansi_regex", N_("regular expression to match ANSI escape codes"), NULL, + &plugin_api_info_get_internal, NULL); + hook_info (NULL, "color_term2rgb", N_("terminal color (0-255) converted to RGB color"), NULL, + &plugin_api_info_get_internal, NULL); + hook_info (NULL, "color_rgb2term", N_("RGB color converted to terminal color (0-255)"), NULL, + &plugin_api_info_get_internal, NULL); /* WeeChat core infolist hooks */ hook_infolist (NULL, "bar", N_("list of bars"),