diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-03-12 16:13:33 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-03-12 16:13:33 +0100 |
commit | 34828885b99a808a09bb05820faa3f10a5025a47 (patch) | |
tree | 814ba088e41392ecd97923a0a2c70f875113d0a1 /src/plugins | |
parent | b7a68af26f2d377ef28c7ff521da1e62ccd97ebd (diff) |
Matrix: add support for sending (code)blocks and greentext in replies
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/Matrix.cpp | 129 |
1 files changed, 85 insertions, 44 deletions
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index c725fc8..1a70a54 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -2577,6 +2577,84 @@ namespace QuickMedia { return "m.file"; } + static size_t find_backquote_index_with_escape(const std::string &str, size_t start_index = 0) { + bool escape = false; + for(size_t i = start_index; i < str.size(); ++i) { + char c = str[i]; + if(c == '\\') { + escape = !escape; + } else if(c == '`' && !escape) { + return i; + } else { + escape = false; + } + } + return std::string::npos; + } + + static void formatted_body_add_line(std::string &formatted_body, const std::string &line_str) { + size_t index = 0; + while(true) { + size_t backquote_start_index = find_backquote_index_with_escape(line_str, index); + if(backquote_start_index != std::string::npos) { + size_t backquote_end_index = find_backquote_index_with_escape(line_str, backquote_start_index + 1); + if(backquote_end_index != std::string::npos) { + formatted_body += line_str.substr(0, backquote_start_index); + formatted_body += "<code>"; + formatted_body += line_str.substr(backquote_start_index + 1, backquote_end_index - (backquote_start_index + 1)); + formatted_body += "</code>"; + index = backquote_end_index + 1; + continue; + } + } + + formatted_body += line_str.substr(index); + break; + } + } + + static std::string body_to_formatted_body(const std::string &body) { + std::string formatted_body; + bool is_inside_code_block = false; + bool is_first_line = true; + string_split(body, '\n', [&formatted_body, &is_inside_code_block, &is_first_line](const char *str, size_t size){ + if(!is_first_line) + formatted_body += "<br/>"; + + std::string line_str(str, size); + html_escape_sequences(line_str); + if(size >= 3 && strncmp(str, "```", 3) == 0) { + if(is_inside_code_block) { + formatted_body += "</code></pre>"; + is_inside_code_block = false; + } else { + if(size > 3) { + formatted_body += "<pre><code class=\"language-" + strip(line_str.substr(3)) + "\">"; + } else { + formatted_body += "<pre><code>"; + } + is_inside_code_block = true; + } + is_first_line = true; + } else { + if(!is_inside_code_block && size > 0 && str[0] == '>') { + formatted_body += "<font color=\"#789922\">"; + formatted_body_add_line(formatted_body, line_str); + formatted_body += "</font>"; + } else { + if(is_inside_code_block) + formatted_body += line_str; + else + formatted_body_add_line(formatted_body, line_str); + } + is_first_line = false; + } + + return true; + }); + return formatted_body; + } + PluginResult Matrix::post_message(RoomData *room, const std::string &body, std::string &event_id_response, const std::optional<UploadInfo> &file_info, const std::optional<UploadInfo> &thumbnail_info, const std::string &msgtype) { std::string transaction_id = create_transaction_id(); if(transaction_id.empty()) @@ -2585,26 +2663,8 @@ namespace QuickMedia { my_events_transaction_ids.insert(transaction_id); std::string formatted_body; - bool contains_formatted_text = false; - if(!file_info) { - int line = 0; - string_split(body, '\n', [&formatted_body, &contains_formatted_text, &line](const char *str, size_t size){ - if(line > 0) - formatted_body += "<br/>"; - std::string line_str(str, size); - html_escape_sequences(line_str); - if(size > 0 && str[0] == '>') { - formatted_body += "<font color=\"#789922\">"; - formatted_body += line_str; - formatted_body += "</font>"; - contains_formatted_text = true; - } else { - formatted_body += line_str; - } - ++line; - return true; - }); - } + if(!file_info) + formatted_body = body_to_formatted_body(body); rapidjson::Document request_data(rapidjson::kObjectType); if(msgtype.empty()) @@ -2612,7 +2672,7 @@ namespace QuickMedia { else request_data.AddMember("msgtype", rapidjson::StringRef(msgtype.c_str()), request_data.GetAllocator()); request_data.AddMember("body", rapidjson::StringRef(body.c_str()), request_data.GetAllocator()); - if(contains_formatted_text) { + if(!formatted_body.empty()) { request_data.AddMember("format", "org.matrix.custom.html", request_data.GetAllocator()); request_data.AddMember("formatted_body", rapidjson::StringRef(formatted_body.c_str()), request_data.GetAllocator()); } @@ -2752,9 +2812,8 @@ namespace QuickMedia { } static std::string create_formatted_body_for_message_reply(RoomData *room, const Message *message, const std::string &body) { - std::string formatted_body = body; + std::string formatted_body = body_to_formatted_body(body); std::string related_to_body = get_reply_message(message); - html_escape_sequences(formatted_body); html_escape_sequences(related_to_body); // TODO: Add keybind to navigate to the reply message, which would also depend on this formatting. // Note: user id and event id is not url escaped here on purpose, because that messes up riot.im replies for certain user ids... @@ -2834,30 +2893,12 @@ namespace QuickMedia { return PluginResult::ERR; my_events_transaction_ids.insert(transaction_id); - std::string formatted_body; - bool contains_formatted_text = false; - int line = 0; - string_split(body, '\n', [&formatted_body, &contains_formatted_text, &line](const char *str, size_t size){ - if(line > 0) - formatted_body += "<br/>"; - if(size > 0 && str[0] == '>') { - std::string line(str, size); - html_escape_sequences(line); - formatted_body += "<font color=\"#789922\">"; - formatted_body += line; - formatted_body += "</font>"; - contains_formatted_text = true; - } else { - formatted_body.append(str, size); - } - ++line; - return true; - }); + std::string formatted_body = body_to_formatted_body(body); rapidjson::Document new_content_json(rapidjson::kObjectType); new_content_json.AddMember("msgtype", "m.text", new_content_json.GetAllocator()); new_content_json.AddMember("body", rapidjson::StringRef(body.c_str()), new_content_json.GetAllocator()); - if(contains_formatted_text) { + if(!formatted_body.empty()) { new_content_json.AddMember("format", "org.matrix.custom.html", new_content_json.GetAllocator()); new_content_json.AddMember("formatted_body", rapidjson::StringRef(formatted_body.c_str()), new_content_json.GetAllocator()); } @@ -2872,7 +2913,7 @@ namespace QuickMedia { rapidjson::Document request_data(rapidjson::kObjectType); request_data.AddMember("msgtype", "m.text", request_data.GetAllocator()); // TODO: Allow other types of edits request_data.AddMember("body", rapidjson::StringRef(body_edit_str.c_str()), request_data.GetAllocator()); - if(contains_formatted_text) { + if(!formatted_body.empty()) { formatted_body_edit_str = " * " + formatted_body; request_data.AddMember("format", "org.matrix.custom.html", request_data.GetAllocator()); request_data.AddMember("formatted_body", rapidjson::StringRef(formatted_body_edit_str.c_str()), request_data.GetAllocator()); |