From 006e25aab8c64a38150df4a97a68755dd21df521 Mon Sep 17 00:00:00 2001
From: fiaxh <git@mx.ax.lt>
Date: Tue, 23 Oct 2018 22:33:19 +0200
Subject: Display bold/italic/monospace message formating, improve
 message-to-markup parsing

fixes #433
fixes #442
---
 .../content_item_widget_factory.vala               |  7 +-
 main/src/ui/util/helper.vala                       | 86 ++++++++++++++--------
 2 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/main/src/ui/conversation_summary/content_item_widget_factory.vala b/main/src/ui/conversation_summary/content_item_widget_factory.vala
index 9e1edcb0..26b66664 100644
--- a/main/src/ui/conversation_summary/content_item_widget_factory.vala
+++ b/main/src/ui/conversation_summary/content_item_widget_factory.vala
@@ -60,10 +60,11 @@ public class MessageItemWidgetGenerator : WidgetGenerator, Object {
         if (message_item.message.body.has_prefix("/me")) {
             markup_text = markup_text.substring(3);
         }
-        markup_text = Markup.escape_text(markup_text);
 
         if (conversation.type_ == Conversation.Type.GROUPCHAT) {
-            markup_text = Util.make_word_bold_markup(markup_text, conversation.nickname);
+            markup_text = Util.parse_add_markup(markup_text, conversation.nickname, true, true);
+        } else {
+            markup_text = Util.parse_add_markup(markup_text, null, true, true);
         }
 
         if (message_item.message.body.has_prefix("/me")) {
@@ -73,8 +74,6 @@ public class MessageItemWidgetGenerator : WidgetGenerator, Object {
             label.style_updated.connect(() => update_me_style(stream_interactor, message.real_jid ?? message.from, display_name, conversation.account, label, markup_text));
         }
 
-        markup_text = Util.make_link_markup(markup_text);
-
         label.label = markup_text;
         return label;
     }
diff --git a/main/src/ui/util/helper.vala b/main/src/ui/util/helper.vala
index 06715ad6..9472c965 100644
--- a/main/src/ui/util/helper.vala
+++ b/main/src/ui/util/helper.vala
@@ -138,39 +138,63 @@ public static bool is_24h_format() {
     return settings_format == "24h" || p_format == " ";
 }
 
-public static string make_word_bold_markup(string s, string word) {
-    string ret = s;
-    int elongated_by = 0;
-    Regex highlight_regex = new Regex("\\b" + Regex.escape_string(word.down()) + "\\b");
-    MatchInfo match_info;
-    string markup_text_bak = s.down();
-    highlight_regex.match(markup_text_bak, 0, out match_info);
-    for (; match_info.matches(); match_info.next()) {
-        int start, end;
-        match_info.fetch_pos(0, out start, out end);
-        ret = ret[0:start+elongated_by] + "<b>" + ret[start+elongated_by:end+elongated_by] + "</b>" + ret[end+elongated_by:ret.length];
-        elongated_by += 7;
+public static string parse_add_markup(string s_, string? highlight_word, bool parse_links, bool parse_text_markup, bool already_escaped_ = false) {
+    string s = s_;
+    bool already_escaped = already_escaped_;
+
+    if (parse_links) {
+        Regex url_regex = new Regex("""(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""");
+        MatchInfo match_info;
+        url_regex.match(s.down(), 0, out match_info);
+        if (match_info.matches())  {
+            int start, end;
+            match_info.fetch_pos(0, out start, out end);
+            string link = s[start:end];
+            return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
+                "<a href=\"" + Markup.escape_text(link) + "\">" + parse_add_markup(link, highlight_word, false, false, already_escaped) + "</a>" +
+                parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+        }
+    }
+
+    if (!already_escaped) {
+        s = Markup.escape_text(s);
+        already_escaped = true;
+    }
+
+    if (highlight_word != null) {
+        Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b");
+        MatchInfo match_info;
+        highlight_regex.match(s.down(), 0, out match_info);
+        if (match_info.matches()) {
+            int start, end;
+            match_info.fetch_pos(0, out start, out end);
+            return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
+                "<b>" + s[start:end] + "</b>" +
+                parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+        }
     }
-    markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string
-    return ret;
-}
-
-public static string make_link_markup(string s) {
-    string ret = s;
-    Regex url_regex = new Regex("""(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""");
-    int elongated_by = 0;
-    MatchInfo match_info;
-    string markup_text_bak = ret.down();
-    url_regex.match(markup_text_bak, 0, out match_info);
-    for (; match_info.matches(); match_info.next()) {
-        int start, end;
-        match_info.fetch_pos(0, out start, out end);
-        string link = ret[start+elongated_by:end+elongated_by];
-        ret = ret[0:start+elongated_by] + "<a href=\"" + link + "\">" + link + "</a>" + ret[end+elongated_by:ret.length];
-        elongated_by += 15 + link.length;
+
+    if (parse_text_markup) {
+        string[] markup_string = new string[]{"`", "_", "*"};
+        string[] convenience_tag = new string[]{"tt", "i", "b"};
+
+        for (int i = 0; i < markup_string.length; i++) {
+            Regex regex = new Regex(Regex.escape_string(markup_string[i]) + ".+" + Regex.escape_string(markup_string[i]));
+            MatchInfo match_info;
+            regex.match(s.down(), 0, out match_info);
+            if (match_info.matches()) {
+                int start, end;
+                match_info.fetch_pos(0, out start, out end);
+                start += markup_string[i].length;
+                end -= markup_string[i].length;
+                return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
+                    @"<$(convenience_tag[i])>" + s[start:end] + @"</$(convenience_tag[i])>" +
+                    parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+            }
+        }
     }
-    markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string
-    return ret;
+
+    return s;
 }
 
 }
-- 
cgit v1.2.3-70-g09d2