From 42f34f749bf2082186133aa28d6709178faa35e5 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Fri, 23 Mar 2018 09:51:58 +0100 Subject: [PATCH] Handle combination of strikethrough and other attributes. Strikethrough has to be done first, before handling any other attribute, because otherwise it doesn't render correctly. The following changes were made: 1. When striking due to redaction, we simply strip all the other attributes and then do the strikethrough, because this is the only practical option. 2. When rendering rich text received from the server, we ensure we handle strikethrough first, before any other attribute. --- matrix/colors.py | 8 ++++++++ matrix/rooms.py | 5 ++++- tests/color_test.py | 19 +++++++++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/matrix/colors.py b/matrix/colors.py index 231531e..6a79b3c 100644 --- a/matrix/colors.py +++ b/matrix/colors.py @@ -288,6 +288,14 @@ class Formatted(): text = formatted_string.text attributes = formatted_string.attributes + # We need to handle strikethrough first, since doing + # a strikethrough followed by other attributes succeeds in the + # terminal, but doing it the other way around results in garbage. + if 'strikethrough' in attributes: + text = add_attribute(text, 'strikethrough', + attributes['strikethrough']) + attributes.pop('strikethrough') + for key, value in attributes.items(): text = add_attribute(text, key, value) return text diff --git a/matrix/rooms.py b/matrix/rooms.py index 11bfefb..8bec82b 100644 --- a/matrix/rooms.py +++ b/matrix/rooms.py @@ -33,6 +33,8 @@ from matrix.utils import ( get_prefix_for_level, sanitize_power_level, string_strikethrough, line_pointer_and_tags_from_event, sender_to_prefix_and_color) +from weechat import string_remove_color + PowerLevel = namedtuple('PowerLevel', ['user', 'level']) @@ -815,7 +817,8 @@ class RoomRedactionEvent(RoomEvent): new_message = "" if OPTIONS.redaction_type == RedactType.STRIKETHROUGH: - new_message = string_strikethrough(message) + plaintext_msg = string_remove_color(message, '') + new_message = string_strikethrough(plaintext_msg) elif OPTIONS.redaction_type == RedactType.NOTICE: new_message = message elif OPTIONS.redaction_type == RedactType.DELETE: diff --git a/tests/color_test.py b/tests/color_test.py index 749f855..6b290ff 100644 --- a/tests/color_test.py +++ b/tests/color_test.py @@ -1,11 +1,14 @@ +# -*- coding: utf-8 -*- + from __future__ import unicode_literals import webcolors +from collections import OrderedDict from hypothesis import given from hypothesis.strategies import sampled_from -from matrix.colors import (Formatted, color_html_to_weechat, - color_weechat_to_html) +from matrix.colors import (Formatted, FormattedString, + color_html_to_weechat, color_weechat_to_html) html_prism = ("Test") @@ -27,3 +30,15 @@ def test_color_conversion(color_name): hex_color = color_weechat_to_html(color_html_to_weechat(color_name)) new_color_name = webcolors.hex_to_name(hex_color, spec='html4') assert new_color_name == color_name + + +def test_handle_strikethrough_first(): + valid_result = '\x1b[038;5;1mf̶o̶o̶\x1b[039m' + + d1 = OrderedDict([('fgcolor', 'red'), ('strikethrough', True)]) + d2 = OrderedDict([('strikethrough', True), ('fgcolor', 'red'), ]) + f1 = Formatted([FormattedString('foo', d1)]) + f2 = Formatted([FormattedString('foo', d2)]) + + assert f1.to_weechat() == valid_result + assert f2.to_weechat() == valid_result