aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-11-08 20:01:27 +0100
committerdec05eba <dec05eba@protonmail.com>2022-11-08 20:01:27 +0100
commitf91ff5856e2276825d450610d1b040fcf8bda6cd (patch)
treed9f5bb5428fe87e9c59d08ba12b854d926f846b9 /src/plugins
parent840b87c42bb55ae6f47acc7576b3b40af4c6a68c (diff)
Add syntax highlighting (currently only for matrix codeblocks)
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Matrix.cpp49
1 files changed, 43 insertions, 6 deletions
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index a9284f5..d1a060d 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -2289,10 +2289,21 @@ namespace QuickMedia {
bool inside_font_tag = false;
bool font_tag_has_custom_color = false;
bool inside_code_tag = false;
+ std::string_view code_tag_language;
bool allow_formatted_text = false;
+ bool inside_source_highlight = false;
+ bool supports_syntax_highlight = false;
mgl::Color font_color = mgl::Color(255, 255, 255, 255);
};
+ static int accumulate_string(char *data, int size, void *userdata) {
+ std::string *str = (std::string*)userdata;
+ if(str->size() + size > 1024 * 1024 * 100) // 100mb sane limit, TODO: make configurable
+ return 1;
+ str->append(data, size);
+ return 0;
+ }
+
// TODO: Full proper parsing with tag depth
static int formattext_text_parser_callback(HtmlParser *html_parser, HtmlParseType parse_type, void *userdata) {
FormattedTextParseUserdata &parse_userdata = *(FormattedTextParseUserdata*)userdata;
@@ -2304,8 +2315,10 @@ namespace QuickMedia {
parse_userdata.inside_font_tag = true;
else if(html_parser->tag_name.size == 8 && memcmp(html_parser->tag_name.data, "mx-reply", 8) == 0)
++parse_userdata.mx_reply_depth;
- else if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "code", 4) == 0)
+ else if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "code", 4) == 0) {
parse_userdata.inside_code_tag = true;
+ parse_userdata.code_tag_language = std::string_view();
+ }
break;
}
case HTML_PARSE_TAG_END: {
@@ -2325,6 +2338,9 @@ namespace QuickMedia {
if(parse_userdata.inside_font_tag && html_parser->attribute_key.size == 5 && memcmp(html_parser->attribute_key.data, "color", 5) == 0) {
if(parse_hex_set_color(html_parser->attribute_value.data, html_parser->attribute_value.size, parse_userdata.font_color))
parse_userdata.font_tag_has_custom_color = true;
+ } else if(parse_userdata.inside_code_tag && html_parser->attribute_key.size == 5 && memcmp(html_parser->attribute_key.data, "class", 5) == 0) {
+ if(html_parser->attribute_value.size > 9 && memcmp(html_parser->attribute_value.data, "language-", 9) == 0)
+ parse_userdata.code_tag_language = std::string_view(html_parser->attribute_value.data + 9, html_parser->attribute_value.size - 9);
}
break;
}
@@ -2335,12 +2351,32 @@ namespace QuickMedia {
html_unescape_sequences(text_to_add);
uint8_t formatted_text_flags = FORMATTED_TEXT_FLAG_NONE;
- if(parse_userdata.font_tag_has_custom_color)
- formatted_text_flags |= FORMATTED_TEXT_FLAG_COLOR;
- if(parse_userdata.inside_code_tag)
- formatted_text_flags |= FORMATTED_TEXT_FLAG_MONOSPACE;
+ if(parse_userdata.allow_formatted_text) {
+ if(parse_userdata.font_tag_has_custom_color)
+ formatted_text_flags |= FORMATTED_TEXT_FLAG_COLOR;
+
+ if(parse_userdata.inside_source_highlight || !parse_userdata.supports_syntax_highlight || (parse_userdata.inside_code_tag && parse_userdata.code_tag_language.size() == 0)) {
+ formatted_text_flags |= FORMATTED_TEXT_FLAG_MONOSPACE;
+ } else if(parse_userdata.inside_code_tag) {
+ formatted_text_flags |= FORMATTED_TEXT_FLAG_MONOSPACE;
+ // TODO: guess language from code if no language is set.
+ // TODO: Allow the user to choose style in config file.
+
+ const std::string code_language(parse_userdata.code_tag_language);
+ const char *args[] = { "source-highlight", "-f", "html", "-s", code_language.c_str(), "--style-file=esc256.style", "-o", "STDOUT", nullptr };
+ std::string output;
+ if(exec_program_write_stdin(args, text_to_add.c_str(), text_to_add.size(), accumulate_string, &output) == 0) {
+ FormattedTextParseUserdata code_parse_userdata;
+ code_parse_userdata.allow_formatted_text = true;
+ code_parse_userdata.inside_source_highlight = true;
+ html_parser_parse(output.c_str(), output.size(), formattext_text_parser_callback, &code_parse_userdata);
+ text_to_add = std::move(code_parse_userdata.result);
+ formatted_text_flags = FORMATTED_TEXT_FLAG_NONE;
+ }
+ }
+ }
- if(formatted_text_flags != FORMATTED_TEXT_FLAG_NONE && parse_userdata.allow_formatted_text)
+ if(formatted_text_flags != FORMATTED_TEXT_FLAG_NONE)
parse_userdata.result += Text::formatted_text(text_to_add, parse_userdata.font_color, formatted_text_flags);
else
parse_userdata.result += std::move(text_to_add);
@@ -2354,6 +2390,7 @@ namespace QuickMedia {
std::string formatted_text_to_qm_text(const char *str, size_t size, bool allow_formatted_text) {
FormattedTextParseUserdata parse_userdata;
parse_userdata.allow_formatted_text = allow_formatted_text;
+ parse_userdata.supports_syntax_highlight = is_program_executable_by_name("source-highlight");
html_parser_parse(str, size, formattext_text_parser_callback, &parse_userdata);
return std::move(parse_userdata.result);
}