aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-03-12 16:13:33 +0100
committerdec05eba <dec05eba@protonmail.com>2021-03-12 16:13:33 +0100
commit34828885b99a808a09bb05820faa3f10a5025a47 (patch)
tree814ba088e41392ecd97923a0a2c70f875113d0a1
parentb7a68af26f2d377ef28c7ff521da1e62ccd97ebd (diff)
Matrix: add support for sending (code)blocks and greentext in replies
-rw-r--r--TODO3
-rw-r--r--src/plugins/Matrix.cpp129
2 files changed, 86 insertions, 46 deletions
diff --git a/TODO b/TODO
index 480f827..a9aac9d 100644
--- a/TODO
+++ b/TODO
@@ -6,7 +6,7 @@ Optimize shadow rendering for items (Right now they fill too much space that is
When continuing to read manga from a different page from the first and there is no cache for the chapter, then start downloading from the current page instead of page 1.
Show progress of manga in the history tab (current chapter out of total chapters).
Animate page navigation.
-Add greentext support for quotes.
+Add greentext support for 4chan quotes.
Add support for special formatting for posts by admins on imageboards.
For image boards, track (You)'s and show notification when somebody replies to your post.
Go to next chapter when reaching the end of the chapter in image endless mode.
@@ -49,7 +49,6 @@ Add room topic beside room name in matrix (in messages tab).
Add /me to matrix, emoji, reactions...
Set the icon of the window to be the icon of the plugin. Nice for KDE, GNOME, etc with titlebars.
Set a minimum wrap size for text. We dont want one line of text to fully fill the window vertically when the window size width is small. Its better to cut off the text and add eclipses.
-Support matrix html (for replies and text styling, such as greentext).
If --no-audio is used then music should be played with a lightweight music player instead. MPV is heavy even for music (60mb RAM). Maybe use sfml audio functions?
Optimize startup time.
Update 4chan thread in real time, just like 4chan-x.
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());