Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / hilight-text.c
index 197957f6cf8b3f89acebc22aa8442c8555a5c79a..f501db9311250ced88aca6ecfe205ef561eb9467 100644 (file)
@@ -13,9 +13,9 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "module.h"
 #include "formats.h"
 
 static NICKMATCH_REC *nickmatch;
-static HILIGHT_REC *next_nick_hilight, *next_line_hilight;
-static int next_hilight_start, next_hilight_end;
 static int never_hilight_level, default_hilight_level;
 GSList *hilights;
 
-static void reset_cache(void)
+static void reset_level_cache(void)
 {
        GSList *tmp;
 
@@ -53,7 +51,11 @@ static void reset_cache(void)
                if (never_hilight_level & rec->level)
                         never_hilight_level &= ~rec->level;
        }
+}
 
+static void reset_cache(void)
+{
+       reset_level_cache();
        nickmatch_rebuild(nickmatch);
 }
 
@@ -114,12 +116,38 @@ static void hilights_destroy_all(void)
        hilights = NULL;
 }
 
-static void hilight_remove(HILIGHT_REC *rec)
+static void hilight_init_rec(HILIGHT_REC *rec)
+{
+#ifdef HAVE_REGEX_H
+       if (rec->regexp_compiled) regfree(&rec->preg);
+       rec->regexp_compiled = !rec->regexp ? FALSE :
+               regcomp(&rec->preg, rec->text, REG_EXTENDED|REG_ICASE) == 0;
+#endif
+}
+
+void hilight_create(HILIGHT_REC *rec)
+{
+       if (g_slist_find(hilights, rec) != NULL) {
+               hilight_remove_config(rec);
+               hilights = g_slist_remove(hilights, rec);
+       }
+
+       hilights = g_slist_append(hilights, rec);
+       hilight_add_config(rec);
+
+       hilight_init_rec(rec);
+
+       signal_emit("hilight created", 1, rec);
+}
+
+void hilight_remove(HILIGHT_REC *rec)
 {
        g_return_if_fail(rec != NULL);
 
        hilight_remove_config(rec);
        hilights = g_slist_remove(hilights, rec);
+
+       signal_emit("hilight destroyed", 1, rec);
        hilight_destroy(rec);
 }
 
@@ -255,7 +283,7 @@ static char *hilight_get_act_color(HILIGHT_REC *rec)
                        settings_get_str("hilight_act_color"));
 }
 
-static char *hilight_get_color(HILIGHT_REC *rec)
+char *hilight_get_color(HILIGHT_REC *rec)
 {
        const char *color;
 
@@ -264,120 +292,108 @@ static char *hilight_get_color(HILIGHT_REC *rec)
        color = rec->color != NULL ? rec->color :
                settings_get_str("hilight_color");
 
-       return format_string_expand(color);
+       return format_string_expand(color, NULL);
 }
 
-static void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec)
+void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec)
 {
        dest->level |= MSGLEVEL_HILIGHT;
 
        if (rec->priority > 0)
                dest->hilight_priority = rec->priority;
 
-        dest->hilight_color = hilight_get_act_color(rec);
+       g_free_and_null(dest->hilight_color);
+       if (rec->act_color != NULL && strcmp(rec->act_color, "%n") == 0)
+               dest->level |= MSGLEVEL_NO_ACT;
+        else
+               dest->hilight_color = hilight_get_act_color(rec);
 }
 
-static void sig_print_text_stripped(TEXT_DEST_REC *dest, const char *str)
+static void hilight_print(int index, HILIGHT_REC *rec);
+
+static void sig_print_text(TEXT_DEST_REC *dest, const char *text,
+                          const char *stripped)
 {
-        HILIGHT_REC *hilight;
-
-       g_return_if_fail(str != NULL);
-
-       if (next_nick_hilight != NULL) {
-               if (!next_nick_hilight->nick) {
-                        /* non-nick hilight wanted */
-                       hilight = next_nick_hilight;
-                       next_nick_hilight = NULL;
-                       if (!hilight_match_text(hilight, str,
-                                               &next_hilight_start,
-                                               &next_hilight_end)) {
-                                next_hilight_start = 0;
-                                next_hilight_end = strlen(str);
-                       }
-               } else {
-                       /* nick is highlighted, just set priority */
-                       hilight_update_text_dest(dest, next_nick_hilight);
-                       next_nick_hilight = NULL;
-                       return;
-               }
-       } else {
-               if (dest->level & (MSGLEVEL_NOHILIGHT|MSGLEVEL_HILIGHT))
-                       return;
+       HILIGHT_REC *hilight;
+       char *color, *newstr;
+       int old_level, hilight_start, hilight_end, hilight_len;
+       int nick_match;
 
-               hilight = hilight_match(dest->server, dest->target,
-                                       NULL, NULL, dest->level, str,
-                                       &next_hilight_start,
-                                       &next_hilight_end);
-       }
+       if (dest->level & MSGLEVEL_NOHILIGHT)
+               return;
 
-       if (hilight != NULL) {
+        hilight_start = hilight_end = 0;
+       hilight = hilight_match(dest->server, dest->target,
+                               NULL, NULL, dest->level, stripped,
+                               &hilight_start,
+                               &hilight_end);
+       if (hilight == NULL)
+               return;
+
+       nick_match = hilight->nick && (dest->level & (MSGLEVEL_PUBLIC|MSGLEVEL_ACTIONS)) == MSGLEVEL_PUBLIC;
+
+       old_level = dest->level;
+       if (!nick_match || (dest->level & MSGLEVEL_HILIGHT)) {
                /* update the level / hilight info */
                hilight_update_text_dest(dest, hilight);
-
-               next_line_hilight = hilight;
        }
-}
 
-static void sig_print_text(TEXT_DEST_REC *dest, const char *str)
-{
-       char *color, *newstr;
-        int next_hilight_len;
+       if (nick_match)
+               return; /* fe-messages.c should have taken care of this */
 
-       if (next_line_hilight == NULL)
-                return;
+       if (old_level & MSGLEVEL_HILIGHT) {
+               /* nick is highlighted, just set priority */
+               return;
+       }
 
-       color = hilight_get_color(next_line_hilight);
-       next_hilight_len = next_hilight_end-next_hilight_start;
+       color = hilight_get_color(hilight);
+       hilight_len = hilight_end-hilight_start;
 
-       if (!next_line_hilight->word) {
+       if (!hilight->word) {
                /* hilight whole line */
-               char *tmp = strip_codes(str);
+               char *tmp = strip_codes(text);
                newstr = g_strconcat(color, tmp, NULL);
                 g_free(tmp);
        } else {
                /* hilight part of the line */
                 GString *tmp;
-                char *middle, *lastcolor;
+                char *middle;
                int pos, color_pos, color_len;
 
                 tmp = g_string_new(NULL);
 
                 /* start of the line */
-               pos = strip_real_length(str, next_hilight_start, NULL, NULL);
-               g_string_append(tmp, str);
+               pos = strip_real_length(text, hilight_start, NULL, NULL);
+               g_string_append(tmp, text);
                 g_string_truncate(tmp, pos);
 
                /* color */
                 g_string_append(tmp, color);
 
                /* middle of the line, stripped */
-               middle = strip_codes(str+pos);
+               middle = strip_codes(text+pos);
                 pos = tmp->len;
                g_string_append(tmp, middle);
-                g_string_truncate(tmp, pos+next_hilight_len);
+                g_string_truncate(tmp, pos+hilight_len);
                 g_free(middle);
 
                /* end of the line */
-               pos = strip_real_length(str, next_hilight_end,
+               pos = strip_real_length(text, hilight_end,
                                        &color_pos, &color_len);
                if (color_pos > 0)
-                       lastcolor = g_strndup(str+color_pos, color_len);
+                       g_string_append_len(tmp, text+color_pos, color_len);
                 else {
                         /* no colors in line, change back to default */
-                       lastcolor = g_malloc0(3);
-                       lastcolor[0] = 4;
-                        lastcolor[1] = FORMAT_STYLE_DEFAULTS;
+                       g_string_append_c(tmp, 4);
+                       g_string_append_c(tmp, FORMAT_STYLE_DEFAULTS);
                }
-               g_string_append(tmp, lastcolor);
-               g_string_append(tmp, str+pos);
-               g_free(lastcolor);
+               g_string_append(tmp, text+pos);
 
                 newstr = tmp->str;
                 g_string_free(tmp, FALSE);
        }
 
-       next_line_hilight = NULL;
-       signal_emit("print text", 2, dest, newstr);
+       signal_emit("print text", 3, dest, newstr, stripped);
 
        g_free(color);
        g_free(newstr);
@@ -385,20 +401,15 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *str)
        signal_stop();
 }
 
-char *hilight_match_nick(SERVER_REC *server, const char *channel,
+HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel,
                         const char *nick, const char *address,
                         int level, const char *msg)
 {
         HILIGHT_REC *rec;
-       char *color;
 
        rec = hilight_match(server, channel, nick, address,
                            level, msg, NULL, NULL);
-       color = rec == NULL || !rec->nick ? NULL :
-               hilight_get_color(rec);
-
-        next_nick_hilight = rec;
-       return color;
+       return (rec == NULL || !rec->nick) ? NULL : rec;
 }
 
 static void read_hilight_config(void)
@@ -416,7 +427,8 @@ static void read_hilight_config(void)
                return;
        }
 
-       for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
+       tmp = config_node_first(node->value);
+       for (; tmp != NULL; tmp = config_node_next(tmp)) {
                node = tmp->data;
 
                if (node->type != NODE_TYPE_BLOCK)
@@ -448,11 +460,7 @@ static void read_hilight_config(void)
                rec->fullword = config_node_get_bool(node, "fullword", FALSE);
                rec->regexp = config_node_get_bool(node, "regexp", FALSE);
 
-#ifdef HAVE_REGEX_H
-               rec->regexp_compiled = !rec->regexp ? FALSE :
-                       regcomp(&rec->preg, rec->text,
-                               REG_EXTENDED|REG_ICASE) == 0;
-#endif
+               hilight_init_rec(rec);
 
                node = config_node_section(node, "channels", -1);
                if (node != NULL) rec->channels = config_node_get_list(node);
@@ -464,20 +472,45 @@ static void read_hilight_config(void)
 static void hilight_print(int index, HILIGHT_REC *rec)
 {
        char *chans, *levelstr;
+       GString *options;
+
+       options = g_string_new(NULL);
+       if (!rec->nick || !rec->word) {
+               if (rec->nick) g_string_append(options, "-nick ");
+               if (rec->word) g_string_append(options, "-word ");
+       }
+
+       if (rec->nickmask) g_string_append(options, "-mask ");
+       if (rec->fullword) g_string_append(options, "-full ");
+       if (rec->regexp) {
+               g_string_append(options, "-regexp ");
+#ifdef HAVE_REGEX_H
+               if (!rec->regexp_compiled)
+                       g_string_append(options, "[INVALID!] ");
+#endif
+       }
+
+       if (rec->priority != 0)
+               g_string_append_printf(options, "-priority %d ", rec->priority);
+       if (rec->color != NULL)
+               g_string_append_printf(options, "-color %s ", rec->color);
+       if (rec->act_color != NULL)
+               g_string_append_printf(options, "-actcolor %s ", rec->act_color);
 
        chans = rec->channels == NULL ? NULL :
                g_strjoinv(",", rec->channels);
        levelstr = rec->level == 0 ? NULL :
                bits2level(rec->level);
+       if (levelstr != NULL)
+               levelstr = g_strconcat(levelstr, " ", NULL);
        printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
                    TXT_HILIGHT_LINE, index, rec->text,
                    chans != NULL ? chans : "",
                    levelstr != NULL ? levelstr : "",
-                   rec->nickmask ? " -mask" : "",
-                   rec->fullword ? " -full" : "",
-                   rec->regexp ? " -regexp" : "");
+                   options->str);
        g_free_not_null(chans);
        g_free_not_null(levelstr);
+       g_string_free(options, TRUE);
 }
 
 static void cmd_hilight_show(void)
@@ -526,7 +559,7 @@ static void cmd_hilight(const char *data)
        if (*text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
 
        channels = (chanarg == NULL || *chanarg == '\0') ? NULL :
-               g_strsplit(replace_chars(chanarg, ',', ' '), " ", -1);
+               g_strsplit(chanarg, ",", -1);
 
        rec = hilight_find(text, channels);
        if (rec == NULL) {
@@ -540,13 +573,10 @@ static void cmd_hilight(const char *data)
                rec->channels = channels;
        } else {
                g_strfreev(channels);
-
-                hilight_remove_config(rec);
-               hilights = g_slist_remove(hilights, rec);
        }
 
        rec->level = (levelarg == NULL || *levelarg == '\0') ? 0 :
-               level2bits(replace_chars(levelarg, ',', ' '));
+               level2bits(replace_chars(levelarg, ',', ' '), NULL);
        rec->priority = priorityarg == NULL ? 0 : atoi(priorityarg);
 
        if (g_hash_table_lookup(optlist, "line") != NULL) {
@@ -567,27 +597,17 @@ static void cmd_hilight(const char *data)
        rec->regexp = g_hash_table_lookup(optlist, "regexp") != NULL;
 
        if (colorarg != NULL) {
+               g_free_and_null(rec->color);
                if (*colorarg != '\0')
                        rec->color = g_strdup(colorarg);
-               else
-                       g_free_and_null(rec->color);
        }
        if (actcolorarg != NULL) {
+               g_free_and_null(rec->act_color);
                if (*actcolorarg != '\0')
                        rec->act_color = g_strdup(actcolorarg);
-               else
-                       g_free_and_null(rec->act_color);
        }
 
-#ifdef HAVE_REGEX_H
-       if (rec->regexp_compiled)
-               regfree(&rec->preg);
-       rec->regexp_compiled = !rec->regexp ? FALSE :
-               regcomp(&rec->preg, rec->text, REG_EXTENDED|REG_ICASE) == 0;
-#endif
-
-       hilights = g_slist_append(hilights, rec);
-       hilight_add_config(rec);
+       hilight_create(rec);
 
        hilight_print(g_slist_index(hilights, rec)+1, rec);
         cmd_params_free(free_arg);
@@ -655,24 +675,21 @@ static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel,
 
 static void read_settings(void)
 {
-       default_hilight_level = level2bits(settings_get_str("hilight_level"));
+       default_hilight_level = settings_get_level("hilight_level");
+       reset_level_cache();
 }
 
 void hilight_text_init(void)
 {
        settings_add_str("lookandfeel", "hilight_color", "%Y");
        settings_add_str("lookandfeel", "hilight_act_color", "%M");
-       settings_add_str("lookandfeel", "hilight_level", "PUBLIC DCCMSGS");
-
-       next_nick_hilight = NULL;
-       next_line_hilight = NULL;
+       settings_add_level("lookandfeel", "hilight_level", "PUBLIC DCCMSGS");
 
         read_settings();
 
        nickmatch = nickmatch_init(hilight_nick_cache);
        read_hilight_config();
 
-       signal_add_first("print text stripped", (SIGNAL_FUNC) sig_print_text_stripped);
        signal_add_first("print text", (SIGNAL_FUNC) sig_print_text);
         signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config);
         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
@@ -687,7 +704,6 @@ void hilight_text_deinit(void)
        hilights_destroy_all();
         nickmatch_deinit(nickmatch);
 
-       signal_remove("print text stripped", (SIGNAL_FUNC) sig_print_text_stripped);
        signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
         signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config);
         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);