diff --git a/main.py b/main.py
index dd61919..4b68777 100644
--- a/main.py
+++ b/main.py
@@ -28,7 +28,7 @@ from builtins import str
# pylint: disable=unused-import
from typing import (List, Set, Dict, Tuple, Text, Optional, AnyStr, Deque, Any)
-from matrix import colors
+from matrix.colors import Formatted
from matrix.utf import utf8_decode
from matrix.http import HttpResponse
from matrix.api import MatrixMessage, MessageType, matrix_login
@@ -407,13 +407,7 @@ def room_input_cb(server_name, buffer, input_data):
if room.encrypted:
return W.WEECHAT_RC_OK
- formatted_data = colors.parse_input_line(input_data)
-
- extra_data = {
- "author": server.user,
- "message": colors.formatted_to_weechat(W, formatted_data),
- "room_id": room_id
- }
+ formatted_data = Formatted.from_input_line(input_data)
message = MatrixMessage(server, OPTIONS, MessageType.SEND, room_id=room_id,
formatted_message=formatted_data)
diff --git a/matrix/api.py b/matrix/api.py
index 9f45949..f160eef 100644
--- a/matrix/api.py
+++ b/matrix/api.py
@@ -29,7 +29,6 @@ except ImportError:
from matrix.globals import OPTIONS
from matrix.http import RequestType, HttpRequest
-from matrix.colors import formatted_to_plain, formatted_to_html, is_formatted
MATRIX_API_PATH = "/_matrix/client/r0" # type: str
@@ -259,11 +258,10 @@ class MatrixMessage:
assert self.room_id
assert self.formatted_message
- data = {"content": formatted_to_plain(self.formatted_message)}
+ data = {"content": self.formatted_message.to_plain()}
- if is_formatted(self.formatted_message):
- data["formatted_content"] = formatted_to_html(
- self.formatted_message)
+ if self.formatted_message.is_formatted:
+ data["formatted_content"] = self.formatted_message.to_html()
self.request = server.client.room_send_message(
self.room_id,
diff --git a/matrix/colors.py b/matrix/colors.py
index 056467b..25c7e44 100644
--- a/matrix/colors.py
+++ b/matrix/colors.py
@@ -21,6 +21,7 @@ from __future__ import unicode_literals
# pylint: disable=redefined-builtin
from builtins import str
from collections import namedtuple
+from matrix.globals import W
import webcolors
@@ -36,6 +37,238 @@ FormattedString = namedtuple(
)
+class Formatted():
+ def __init__(self, substrings):
+ # type: List[FormattedString] -> None
+ self.substrings = substrings
+
+
+ def is_formatted(self):
+ # type: (Formatted) -> bool
+ for string in self.substrings:
+ if string.attributes != DEFAULT_ATRIBUTES:
+ return True
+ return False
+
+ # TODO reverse video
+ @classmethod
+ def from_input_line(cls, line):
+ # type: (str) -> Formatted
+ """Parses the weechat input line and produces formatted strings that
+ can be later converted to HTML or to a string for weechat's print
+ functions
+ """
+ text = "" # type: str
+ substrings = [] # type: List[FormattedString]
+ attributes = DEFAULT_ATRIBUTES.copy()
+
+ i = 0
+ while i < len(line):
+ # Bold
+ if line[i] == "\x02":
+ if text:
+ substrings.append(FormattedString(text, attributes.copy()))
+ text = ""
+ attributes["bold"] = not attributes["bold"]
+ i = i + 1
+
+ # Color
+ elif line[i] == "\x03":
+ if text:
+ substrings.append(FormattedString(text, attributes.copy()))
+ text = ""
+ i = i + 1
+
+ # check if it's a valid color, add it to the attributes
+ if line[i].isdigit():
+ color_string = line[i]
+ i = i + 1
+
+ if line[i].isdigit():
+ if color_string == "0":
+ color_string = line[i]
+ else:
+ color_string = color_string + line[i]
+ i = i + 1
+
+ attributes["fgcolor"] = color_line_to_weechat(color_string)
+ else:
+ attributes["fgcolor"] = None
+
+ # check if we have a background color
+ if line[i] == "," and line[i + 1].isdigit():
+ color_string = line[i + 1]
+ i = i + 2
+
+ if line[i].isdigit():
+ if color_string == "0":
+ color_string = line[i]
+ else:
+ color_string = color_string + line[i]
+ i = i + 1
+
+ attributes["bgcolor"] = color_line_to_weechat(color_string)
+ else:
+ attributes["bgcolor"] = None
+ # Reset
+ elif line[i] == "\x0F":
+ if text:
+ substrings.append(FormattedString(text, attributes.copy()))
+ text = ""
+ # Reset all the attributes
+ attributes = DEFAULT_ATRIBUTES.copy()
+ i = i + 1
+ # Italic
+ elif line[i] == "\x1D":
+ if text:
+ substrings.append(FormattedString(text, attributes.copy()))
+ text = ""
+ attributes["italic"] = not attributes["italic"]
+ i = i + 1
+
+ # Underline
+ elif line[i] == "\x1F":
+ if text:
+ substrings.append(FormattedString(text, attributes.copy()))
+ text = ""
+ attributes["underline"] = not attributes["underline"]
+ i = i + 1
+
+ # Normal text
+ else:
+ text = text + line[i]
+ i = i + 1
+
+ substrings.append(FormattedString(text, attributes))
+ return cls(substrings)
+
+ @classmethod
+ def from_html(cls, html):
+ # type: (str) -> Formatted
+ parser = MatrixHtmlParser()
+ parser.feed(html)
+ return cls(parser.get_substrings())
+
+ def to_html(self):
+ # TODO BG COLOR
+ def add_attribute(string, name, value):
+ if name == "bold" and value:
+ return "{bold_on}{text}{bold_off}".format(
+ bold_on="",
+ text=string,
+ bold_off="")
+ elif name == "italic" and value:
+ return "{italic_on}{text}{italic_off}".format(
+ italic_on="",
+ text=string,
+ italic_off="")
+ elif name == "underline" and value:
+ return "{underline_on}{text}{underline_off}".format(
+ underline_on="",
+ text=string,
+ underline_off="")
+ elif name == "strikethrough" and value:
+ return "{strike_on}{text}{strike_off}".format(
+ strike_on="",
+ text=string,
+ strike_off="")
+ elif name == "quote" and value:
+ return "{quote_on}{text}{quote_off}".format(
+ quote_on="
", + text=string, + quote_off="") + elif name == "fgcolor" and value: + return "{color_on}{text}{color_off}".format( + color_on="".format( + color=color_weechat_to_html(value) + ), + text=string, + color_off="") + + return string + + def format_string(formatted_string): + text = formatted_string.text + attributes = formatted_string.attributes + + for key, value in attributes.items(): + text = add_attribute(text, key, value) + return text + + html_string = map(format_string, self.substrings) + return "".join(html_string) + + # TODO do we want at least some formatting using unicode + # (strikethrough, quotes)? + def to_plain(self): + # type: (List[FormattedString]) -> str + def strip_atribute(string, _, __): + return string + + def format_string(formatted_string): + text = formatted_string.text + attributes = formatted_string.attributes + + for key, value in attributes.items(): + text = strip_atribute(text, key, value) + return text + + plain_string = map(format_string, self.substrings) + return "".join(plain_string) + + def to_weechat(self): + # TODO BG COLOR + def add_attribute(string, name, value): + if name == "bold" and value: + return "{bold_on}{text}{bold_off}".format( + bold_on=W.color("bold"), + text=string, + bold_off=W.color("-bold")) + + elif name == "italic" and value: + return "{italic_on}{text}{italic_off}".format( + italic_on=W.color("italic"), + text=string, + italic_off=W.color("-italic")) + + elif name == "underline" and value: + return "{underline_on}{text}{underline_off}".format( + underline_on=W.color("underline"), + text=string, + underline_off=W.color("-underline")) + + elif name == "strikethrough" and value: + return string_strikethrough(string) + + elif name == "quote" and value: + return "“{text}”".format(text=string) + + elif name == "fgcolor" and value: + return "{color_on}{text}{color_off}".format( + color_on=W.color(value), + text=string, + color_off=W.color("resetcolor")) + + elif name == "bgcolor" and value: + return "{color_on}{text}{color_off}".format( + color_on=W.color("," + value), + text=string, + color_off=W.color("resetcolor")) + + return string + + def format_string(formatted_string): + text = formatted_string.text + attributes = formatted_string.attributes + + for key, value in attributes.items(): + text = add_attribute(text, key, value) + return text + + weechat_strings = map(format_string, self.substrings) + return "".join(weechat_strings) + + # TODO this should be a typed dict. DEFAULT_ATRIBUTES = { "bold": False, @@ -631,236 +864,6 @@ def color_weechat_to_html(color): return hex_color -# TODO reverse video -def parse_input_line(line): - # type: (str) -> List[FormattedString] - """Parses the weechat input line and produces formatted strings that can be - later converted to HTML or to a string for weechat's print functions - """ - text = "" # type: str - substrings = [] # type: List[FormattedString] - attributes = DEFAULT_ATRIBUTES.copy() - - i = 0 - while i < len(line): - # Bold - if line[i] == "\x02": - if text: - substrings.append(FormattedString(text, attributes.copy())) - text = "" - attributes["bold"] = not attributes["bold"] - i = i + 1 - - # Color - elif line[i] == "\x03": - if text: - substrings.append(FormattedString(text, attributes.copy())) - text = "" - i = i + 1 - - # check if it's a valid color, add it to the attributes - if line[i].isdigit(): - color_string = line[i] - i = i + 1 - - if line[i].isdigit(): - if color_string == "0": - color_string = line[i] - else: - color_string = color_string + line[i] - i = i + 1 - - attributes["fgcolor"] = color_line_to_weechat(color_string) - else: - attributes["fgcolor"] = None - - # check if we have a background color - if line[i] == "," and line[i+1].isdigit(): - color_string = line[i+1] - i = i + 2 - - if line[i].isdigit(): - if color_string == "0": - color_string = line[i] - else: - color_string = color_string + line[i] - i = i + 1 - - attributes["bgcolor"] = color_line_to_weechat(color_string) - else: - attributes["bgcolor"] = None - # Reset - elif line[i] == "\x0F": - if text: - substrings.append(FormattedString(text, attributes.copy())) - text = "" - # Reset all the attributes - attributes = DEFAULT_ATRIBUTES.copy() - i = i + 1 - # Italic - elif line[i] == "\x1D": - if text: - substrings.append(FormattedString(text, attributes.copy())) - text = "" - attributes["italic"] = not attributes["italic"] - i = i + 1 - - # Underline - elif line[i] == "\x1F": - if text: - substrings.append(FormattedString(text, attributes.copy())) - text = "" - attributes["underline"] = not attributes["underline"] - i = i + 1 - - # Normal text - else: - text = text + line[i] - i = i + 1 - - substrings.append(FormattedString(text, attributes)) - return substrings - - -def is_formatted(strings): - # type: (List[FormattedString]) -> bool - for string in strings: - if string.attributes != DEFAULT_ATRIBUTES: - return True - return False - - -def formatted_to_html(strings): - # type: (List[FormattedString]) -> str - # TODO BG COLOR - def add_attribute(string, name, value): - if name == "bold" and value: - return "{bold_on}{text}{bold_off}".format( - bold_on="", - text=string, - bold_off="") - elif name == "italic" and value: - return "{italic_on}{text}{italic_off}".format( - italic_on="", - text=string, - italic_off="") - elif name == "underline" and value: - return "{underline_on}{text}{underline_off}".format( - underline_on="", - text=string, - underline_off="") - elif name == "strikethrough" and value: - return "{strike_on}{text}{strike_off}".format( - strike_on="
", - text=string, - quote_off="") - elif name == "fgcolor" and value: - return "{color_on}{text}{color_off}".format( - color_on="".format( - color=color_weechat_to_html(value) - ), - text=string, - color_off="") - - return string - - def format_string(formatted_string): - text = formatted_string.text - attributes = formatted_string.attributes - - for key, value in attributes.items(): - text = add_attribute(text, key, value) - return text - - html_string = map(format_string, strings) - return "".join(html_string) - - -# TODO do we want at least some formatting using unicode -# (strikethrough, quotes)? -def formatted_to_plain(strings): - # type: (List[FormattedString]) -> str - def strip_atribute(string, _, __): - return string - - def format_string(formatted_string): - text = formatted_string.text - attributes = formatted_string.attributes - - for key, value in attributes.items(): - text = strip_atribute(text, key, value) - return text - - plain_string = map(format_string, strings) - return "".join(plain_string) - - -def html_to_formatted(html): - # type: (str) -> FormattedString - parser = MatrixHtmlParser() - parser.feed(html) - return parser.get_substrings() - - def string_strikethrough(string): # type (str) -> str return "".join(["{}\u0336".format(c) for c in string]) - - -def formatted_to_weechat(W, strings): - # type: (weechat, List[FormattedString]) -> str - # TODO BG COLOR - def add_attribute(string, name, value): - if name == "bold" and value: - return "{bold_on}{text}{bold_off}".format( - bold_on=W.color("bold"), - text=string, - bold_off=W.color("-bold")) - - elif name == "italic" and value: - return "{italic_on}{text}{italic_off}".format( - italic_on=W.color("italic"), - text=string, - italic_off=W.color("-italic")) - - elif name == "underline" and value: - return "{underline_on}{text}{underline_off}".format( - underline_on=W.color("underline"), - text=string, - underline_off=W.color("-underline")) - - elif name == "strikethrough" and value: - return string_strikethrough(string) - - elif name == "quote" and value: - return "“{text}”".format(text=string) - - elif name == "fgcolor" and value: - return "{color_on}{text}{color_off}".format( - color_on=W.color(value), - text=string, - color_off=W.color("resetcolor")) - - elif name == "bgcolor" and value: - return "{color_on}{text}{color_off}".format( - color_on=W.color("," + value), - text=string, - color_off=W.color("resetcolor")) - - return string - - def format_string(formatted_string): - text = formatted_string.text - attributes = formatted_string.attributes - - for key, value in attributes.items(): - text = add_attribute(text, key, value) - return text - - weechat_strings = map(format_string, strings) - return "".join(weechat_strings) diff --git a/matrix/messages.py b/matrix/messages.py index a0654bc..076925d 100644 --- a/matrix/messages.py +++ b/matrix/messages.py @@ -24,7 +24,7 @@ import datetime from operator import itemgetter -import matrix.colors as colors +from matrix.colors import Formatted from matrix.globals import W, OPTIONS @@ -190,9 +190,9 @@ def matrix_handle_room_text_message(server, room_id, event, old=False): if 'format' in event['content'] and 'formatted_body' in event['content']: if event['content']['format'] == "org.matrix.custom.html": - formatted_data = colors.html_to_formatted( + formatted_data = Formatted.from_html( event['content']['formatted_body']) - msg = colors.formatted_to_weechat(W, formatted_data) + msg = formatted_data.to_weechat() if event['sender'] in room.users: user = room.users[event['sender']] @@ -708,10 +708,7 @@ def matrix_handle_message( elif message_type is MessageType.SEND: room_id = message.room_id author = server.user - weechat_message = colors.formatted_to_weechat( - W, - message.formatted_message - ) + weechat_message = message.formatted_message.to_weechat() date = int(time.time()) # TODO the event_id can be missing if sending has failed for