diff --git a/plugins/day_change.py b/plugins/day_change.py
index 051b447b..5d3ab37c 100644
--- a/plugins/day_change.py
+++ b/plugins/day_change.py
@@ -4,11 +4,12 @@ date has changed.
"""
-from gettext import gettext as _
-from poezio.plugin import BasePlugin
import datetime
-from poezio import tabs
-from poezio import timed_events
+from gettext import gettext as _
+
+from poezio import timed_events, tabs
+from poezio.plugin import BasePlugin
+from poezio.ui.types import InfoMessage
class Plugin(BasePlugin):
@@ -30,7 +31,7 @@ class Plugin(BasePlugin):
for tab in self.core.tabs:
if isinstance(tab, tabs.ChatTab):
- tab.add_message(msg)
+ tab.add_message(InfoMessage(msg))
self.core.refresh_window()
self.schedule_event()
diff --git a/plugins/embed.py b/plugins/embed.py
index 0c4a4a2a..aee7d44b 100644
--- a/plugins/embed.py
+++ b/plugins/embed.py
@@ -16,6 +16,7 @@ Usage
from poezio import tabs
from poezio.plugin import BasePlugin
from poezio.theming import get_theme
+from poezio.ui.types import Message
class Plugin(BasePlugin):
@@ -37,11 +38,13 @@ class Plugin(BasePlugin):
if not isinstance(tab, tabs.MucTab):
message['type'] = 'chat'
tab.add_message(
- message['body'],
- nickname=tab.core.own_nick,
- nick_color=get_theme().COLOR_OWN_NICK,
- identifier=message['id'],
- jid=tab.core.xmpp.boundjid,
+ Message(
+ message['body'],
+ nickname=tab.core.own_nick,
+ nick_color=get_theme().COLOR_OWN_NICK,
+ identifier=message['id'],
+ jid=tab.core.xmpp.boundjid,
+ ),
typ=1,
)
message.send()
diff --git a/plugins/lastlog.py b/plugins/lastlog.py
index 104399b4..49efa522 100644
--- a/plugins/lastlog.py
+++ b/plugins/lastlog.py
@@ -17,7 +17,8 @@ from datetime import datetime
from poezio.plugin import BasePlugin
from poezio import tabs
-from poezio.text_buffer import Message, TextBuffer
+from poezio.text_buffer import TextBuffer
+from poezio.ui.types import InfoMessage
def add_line(
@@ -26,18 +27,7 @@ def add_line(
datetime: Optional[datetime] = None,
) -> None:
"""Adds a textual entry in the TextBuffer"""
- text_buffer.add_message(
- text,
- datetime, # Time
- None, # Nickname
- None, # Nick Color
- False, # History
- None, # User
- False, # Highlight
- None, # Identifier
- None, # str_time
- None, # Jid
- )
+ text_buffer.add_message(InfoMessage(text, time=datetime))
class Plugin(BasePlugin):
diff --git a/plugins/otr.py b/plugins/otr.py
index 2ddc332b..81e1621f 100644
--- a/plugins/otr.py
+++ b/plugins/otr.py
@@ -205,6 +205,7 @@ from poezio.tabs import StaticConversationTab, PrivateTab
from poezio.theming import get_theme, dump_tuple
from poezio.decorators import command_args_parser
from poezio.core.structs import Completion
+from poezio.ui.types import InfoMessage, Message
POLICY_FLAGS = {
'ALLOW_V1': False,
@@ -385,25 +386,30 @@ class PoezioContext(Context):
log.debug('OTR conversation with %s refreshed', self.peer)
if self.getCurrentTrust():
msg = OTR_REFRESH_TRUSTED % format_dict
- tab.add_message(msg, typ=self.log)
+ tab.add_message(InfoMessage(msg), typ=self.log)
else:
msg = OTR_REFRESH_UNTRUSTED % format_dict
- tab.add_message(msg, typ=self.log)
+ tab.add_message(InfoMessage(msg), typ=self.log)
hl(tab)
elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT:
log.debug('OTR conversation with %s finished', self.peer)
if tab:
- tab.add_message(OTR_END % format_dict, typ=self.log)
+ tab.add_message(InfoMessage(OTR_END % format_dict), typ=self.log)
hl(tab)
elif newstate == STATE_ENCRYPTED and tab:
if self.getCurrentTrust():
- tab.add_message(OTR_START_TRUSTED % format_dict, typ=self.log)
+ tab.add_message(InfoMessage(OTR_START_TRUSTED % format_dict), typ=self.log)
else:
format_dict['our_fpr'] = self.user.getPrivkey()
format_dict['remote_fpr'] = self.getCurrentKey()
- tab.add_message(OTR_TUTORIAL % format_dict, typ=0)
tab.add_message(
- OTR_START_UNTRUSTED % format_dict, typ=self.log)
+ InfoMessage(OTR_TUTORIAL % format_dict),
+ typ=0
+ )
+ tab.add_message(
+ InfoMessage(OTR_START_UNTRUSTED % format_dict),
+ typ=self.log,
+ )
hl(tab)
log.debug('Set encryption state of %s to %s', self.peer,
@@ -639,7 +645,7 @@ class Plugin(BasePlugin):
# Received an OTR error
proto_error = err.args[0].error # pylint: disable=no-member
format_dict['err'] = proto_error.decode('utf-8', errors='replace')
- tab.add_message(OTR_ERROR % format_dict, typ=0)
+ tab.add_message(InfoMessage(OTR_ERROR % format_dict), typ=0)
del msg['body']
del msg['html']
hl(tab)
@@ -649,7 +655,7 @@ class Plugin(BasePlugin):
# Encrypted message received, but unreadable as we do not have
# an OTR session in place.
text = MESSAGE_UNREADABLE % format_dict
- tab.add_message(text, jid=msg['from'], typ=0)
+ tab.add_message(InfoMessage(text), typ=0)
hl(tab)
del msg['body']
del msg['html']
@@ -658,7 +664,7 @@ class Plugin(BasePlugin):
except crypt.InvalidParameterError:
# Malformed OTR payload and stuff
text = MESSAGE_INVALID % format_dict
- tab.add_message(text, jid=msg['from'], typ=0)
+ tab.add_message(InfoMessage(text), typ=0)
hl(tab)
del msg['body']
del msg['html']
@@ -669,7 +675,7 @@ class Plugin(BasePlugin):
import traceback
exc = traceback.format_exc()
format_dict['exc'] = exc
- tab.add_message(POTR_ERROR % format_dict, typ=0)
+ tab.add_message(InfoMessage(POTR_ERROR % format_dict), typ=0)
log.error('Unspecified error in the OTR plugin', exc_info=True)
return
# No error, proceed with the message
@@ -688,10 +694,10 @@ class Plugin(BasePlugin):
abort = get_tlv(tlvs, potr.proto.SMPABORTTLV)
if abort:
ctx.reset_smp()
- tab.add_message(SMP_ABORTED_PEER % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_ABORTED_PEER % format_dict), typ=0)
elif ctx.in_smp and not ctx.smpIsValid():
ctx.reset_smp()
- tab.add_message(SMP_ABORTED % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_ABORTED % format_dict), typ=0)
elif smp1 or smp1q:
# Received an SMP request (with a question or not)
if smp1q:
@@ -709,22 +715,22 @@ class Plugin(BasePlugin):
# we did not initiate it
ctx.smp_own = False
format_dict['q'] = question
- tab.add_message(SMP_REQUESTED % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_REQUESTED % format_dict), typ=0)
elif smp2:
# SMP reply received
if not ctx.in_smp:
ctx.reset_smp()
else:
- tab.add_message(SMP_PROGRESS % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_PROGRESS % format_dict), typ=0)
elif smp3 or smp4:
# Type 4 (SMP message 3) or 5 (SMP message 4) TLVs received
# in both cases it is the final message of the SMP exchange
if ctx.smpIsSuccess():
- tab.add_message(SMP_SUCCESS % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_SUCCESS % format_dict), typ=0)
if not ctx.getCurrentTrust():
- tab.add_message(SMP_RECIPROCATE % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_RECIPROCATE % format_dict), typ=0)
else:
- tab.add_message(SMP_FAIL % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_FAIL % format_dict), typ=0)
ctx.reset_smp()
hl(tab)
self.core.refresh_window()
@@ -780,12 +786,15 @@ class Plugin(BasePlugin):
if decode_newlines:
body = body.replace('
', '\n').replace('
', '\n')
tab.add_message(
- body,
- nickname=tab.nick,
- jid=msg['from'],
- forced_user=user,
+ Message(
+ body,
+ nickname=tab.nick,
+ jid=msg['from'],
+ user=user,
+ nick_color=nick_color
+ ),
typ=ctx.log,
- nick_color=nick_color)
+ )
hl(tab)
self.core.refresh_window()
del msg['body']
@@ -826,19 +835,22 @@ class Plugin(BasePlugin):
tab.send_chat_state('inactive', always_send=True)
tab.add_message(
- msg['body'],
- nickname=self.core.own_nick or tab.own_nick,
- nick_color=get_theme().COLOR_OWN_NICK,
- identifier=msg['id'],
- jid=self.core.xmpp.boundjid,
- typ=ctx.log)
+ Message(
+ msg['body'],
+ nickname=self.core.own_nick or tab.own_nick,
+ nick_color=get_theme().COLOR_OWN_NICK,
+ identifier=msg['id'],
+ jid=self.core.xmpp.boundjid,
+ ),
+ typ=ctx.log
+ )
# remove everything from the message so that it doesn’t get sent
del msg['body']
del msg['replace']
del msg['html']
elif is_relevant(tab) and ctx and ctx.getPolicy('REQUIRE_ENCRYPTION'):
warning_msg = MESSAGE_NOT_SENT % format_dict
- tab.add_message(warning_msg, typ=0)
+ tab.add_message(InfoMessage(warning_msg), typ=0)
del msg['body']
del msg['replace']
del msg['html']
@@ -856,7 +868,7 @@ class Plugin(BasePlugin):
('\n - /message %s' % jid) for jid in res)
format_dict['help'] = help_msg
warning_msg = INCOMPATIBLE_TAB % format_dict
- tab.add_message(warning_msg, typ=0)
+ tab.add_message(InfoMessage(warning_msg), typ=0)
del msg['body']
del msg['replace']
del msg['html']
@@ -900,22 +912,22 @@ class Plugin(BasePlugin):
self.otr_start(tab, name, format_dict)
elif action == 'ourfpr':
format_dict['fpr'] = self.account.getPrivkey()
- tab.add_message(OTR_OWN_FPR % format_dict, typ=0)
+ tab.add_message(InfoMessage(OTR_OWN_FPR % format_dict), typ=0)
elif action == 'fpr':
if name in self.contexts:
ctx = self.contexts[name]
if ctx.getCurrentKey() is not None:
format_dict['fpr'] = ctx.getCurrentKey()
- tab.add_message(OTR_REMOTE_FPR % format_dict, typ=0)
+ tab.add_message(InfoMessage(OTR_REMOTE_FPR % format_dict), typ=0)
else:
- tab.add_message(OTR_NO_FPR % format_dict, typ=0)
+ tab.add_message(InfoMessage(OTR_NO_FPR % format_dict), typ=0)
elif action == 'drop':
# drop the privkey (and obviously, end the current conversations before that)
for context in self.contexts.values():
if context.state not in (STATE_FINISHED, STATE_PLAINTEXT):
context.disconnect()
self.account.drop_privkey()
- tab.add_message(KEY_DROPPED % format_dict, typ=0)
+ tab.add_message(InfoMessage(KEY_DROPPED % format_dict), typ=0)
elif action == 'trust':
ctx = self.get_context(name)
key = ctx.getCurrentKey()
@@ -927,7 +939,7 @@ class Plugin(BasePlugin):
format_dict['key'] = key
ctx.setTrust(fpr, 'verified')
self.account.saveTrusts()
- tab.add_message(TRUST_ADDED % format_dict, typ=0)
+ tab.add_message(InfoMessage(TRUST_ADDED % format_dict), typ=0)
elif action == 'untrust':
ctx = self.get_context(name)
key = ctx.getCurrentKey()
@@ -939,7 +951,7 @@ class Plugin(BasePlugin):
format_dict['key'] = key
ctx.setTrust(fpr, '')
self.account.saveTrusts()
- tab.add_message(TRUST_REMOVED % format_dict, typ=0)
+ tab.add_message(InfoMessage(TRUST_REMOVED % format_dict), typ=0)
self.core.refresh_window()
def otr_start(self, tab, name, format_dict):
@@ -954,7 +966,7 @@ class Plugin(BasePlugin):
if otr.state != STATE_ENCRYPTED:
format_dict['secs'] = secs
text = OTR_NOT_ENABLED % format_dict
- tab.add_message(text, typ=0)
+ tab.add_message(InfoMessage(text), typ=0)
self.core.refresh_window()
if secs > 0:
@@ -962,7 +974,7 @@ class Plugin(BasePlugin):
self.api.add_timed_event(event)
body = self.get_context(name).sendMessage(0, b'?OTRv?').decode()
self.core.xmpp.send_message(mto=name, mtype='chat', mbody=body)
- tab.add_message(OTR_REQUEST % format_dict, typ=0)
+ tab.add_message(InfoMessage(OTR_REQUEST % format_dict), typ=0)
@staticmethod
def completion_otr(the_input):
@@ -1012,13 +1024,13 @@ class Plugin(BasePlugin):
ctx.smpInit(secret, question)
else:
ctx.smpInit(secret)
- tab.add_message(SMP_INITIATED % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_INITIATED % format_dict), typ=0)
elif action == 'answer':
ctx.smpGotSecret(secret)
elif action == 'abort':
if ctx.in_smp:
ctx.smpAbort()
- tab.add_message(SMP_ABORTED % format_dict, typ=0)
+ tab.add_message(InfoMessage(SMP_ABORTED % format_dict), typ=0)
self.core.refresh_window()
@staticmethod
diff --git a/poezio/core/core.py b/poezio/core/core.py
index 2b8252b1..8f25d551 100644
--- a/poezio/core/core.py
+++ b/poezio/core/core.py
@@ -53,8 +53,15 @@ from poezio.core.completions import CompletionCore
from poezio.core.tabs import Tabs
from poezio.core.commands import CommandCore
from poezio.core.handlers import HandlerCore
-from poezio.core.structs import POSSIBLE_SHOW, DEPRECATED_ERRORS, \
- ERROR_AND_STATUS_CODES, Command, Status
+from poezio.core.structs import (
+ Command,
+ Status,
+ DEPRECATED_ERRORS,
+ ERROR_AND_STATUS_CODES,
+ POSSIBLE_SHOW,
+)
+
+from poezio.ui.types import Message, InfoMessage
log = logging.getLogger(__name__)
@@ -1317,7 +1324,7 @@ class Core:
"""
tab = self.tabs.by_name_and_class(jid, tabs.ConversationTab)
if tab is not None:
- tab.add_message(msg, typ=2)
+ tab.add_message(InfoMessage(msg), typ=2)
if self.tabs.current_tab is tab:
self.refresh_window()
@@ -1349,9 +1356,11 @@ class Core:
colors = get_theme().INFO_COLORS
color = colors.get(typ.lower(), colors.get('default', None))
nb_lines = self.information_buffer.add_message(
- txt=msg,
- nickname=typ,
- nick_color=color
+ Message(
+ txt=msg,
+ nickname=typ,
+ nick_color=color
+ )
)
popup_on = config.get('information_buffer_popup_on').split()
if isinstance(self.tabs.current_tab, tabs.RosterInfoTab):
@@ -1582,17 +1591,6 @@ class Core:
self.tab_win.resize(1, tabs.Tab.width, tabs.Tab.height - 2, 0)
self.left_tab_win = None
- def add_message_to_text_buffer(self, buff, txt, nickname=None):
- """
- Add the message to the room if possible, else, add it to the Info window
- (in the Info tab of the info window in the RosterTab)
- """
- if not buff:
- self.information('Trying to add a message in no room: %s' % txt,
- 'Error')
- return
- buff.add_message(txt, nickname=nickname)
-
def full_screen_redraw(self):
"""
Completely erase and redraw the screen
@@ -2064,15 +2062,18 @@ class Core:
return
error_message = self.get_error_message(error)
tab.add_message(
- error_message,
- highlight=True,
- nickname='Error',
- nick_color=get_theme().COLOR_ERROR_MSG,
- typ=2)
+ Message(
+ error_message,
+ highlight=True,
+ nickname='Error',
+ nick_color=get_theme().COLOR_ERROR_MSG,
+ ),
+ typ=2,
+ )
code = error['error']['code']
if code == '401':
msg = 'To provide a password in order to join the room, type "/join / password" (replace "password" by the real password)'
- tab.add_message(msg, typ=2)
+ tab.add_message(InfoMessage(msg), typ=2)
if code == '409':
if config.get('alternative_nickname') != '':
if not tab.joined:
@@ -2081,8 +2082,12 @@ class Core:
else:
if not tab.joined:
tab.add_message(
- 'You can join the room with an other nick, by typing "/join /other_nick"',
- typ=2)
+ InfoMessage(
+ 'You can join the room with another nick, '
+ 'by typing "/join /other_nick"'
+ ),
+ typ=2,
+ )
self.refresh_window()
diff --git a/poezio/core/handlers.py b/poezio/core/handlers.py
index 2232f723..cf04d582 100644
--- a/poezio/core/handlers.py
+++ b/poezio/core/handlers.py
@@ -39,6 +39,7 @@ from poezio.logger import logger
from poezio.roster import roster
from poezio.text_buffer import CorrectionError, AckError
from poezio.theming import dump_tuple, get_theme
+from poezio.ui.types import XMLLog, Message as PMessage, BaseMessage, InfoMessage
from poezio.core.commands import dumb_callback
@@ -326,7 +327,7 @@ class HandlerCore:
error = '\x19%s}%s\x19o' % (dump_tuple(get_theme().COLOR_CHAR_NACK),
error_msg)
if not tab.nack_message('\n' + error, message['id'], message['to']):
- tab.add_message(error, typ=0)
+ tab.add_message(InfoMessage(error), typ=0)
self.core.refresh_window()
def on_normal_message(self, message):
@@ -421,14 +422,17 @@ class HandlerCore:
if not try_modify():
conversation.add_message(
- body,
- date,
- nickname=remote_nick,
- nick_color=color,
- history=delayed,
- identifier=message['id'],
- jid=jid,
- typ=1)
+ PMessage(
+ txt=body,
+ time=date,
+ nickname=remote_nick,
+ nick_color=color,
+ history=delayed,
+ identifier=message['id'],
+ jid=jid,
+ ),
+ typ=1,
+ )
if not own and 'private' in config.get('beep_on').split():
if not config.get_by_tabname('disable_beep', conv_jid.bare):
@@ -769,12 +773,15 @@ class HandlerCore:
except CorrectionError:
log.debug('Unable to correct a message', exc_info=True)
if not replaced and tab.add_message(
- body,
- date,
- nick_from,
- history=delayed,
- identifier=message['id'],
- jid=message['from'],
+ PMessage(
+ txt=body,
+ time=date,
+ nickname=nick_from,
+ history=delayed,
+ identifier=message['id'],
+ jid=message['from'],
+ user=user,
+ ),
typ=1):
self.core.events.trigger('highlight', message, tab)
@@ -862,14 +869,16 @@ class HandlerCore:
log.debug('Unable to correct a message', exc_info=True)
if not replaced:
tab.add_message(
- body,
- time=None,
- nickname=sender_nick,
- nick_color=get_theme().COLOR_OWN_NICK if sent else None,
- forced_user=user,
- identifier=message['id'],
- jid=message['from'],
- typ=1)
+ PMessage(
+ txt=body,
+ nickname=sender_nick,
+ nick_color=get_theme().COLOR_OWN_NICK if sent else None,
+ user=user,
+ identifier=message['id'],
+ jid=message['from'],
+ ),
+ typ=1,
+ )
if sent:
tab.set_last_sent_message(message, correct=replaced)
else:
@@ -1361,36 +1370,52 @@ class HandlerCore:
if show_unavailable or hide_unavailable or non_priv or logging_off\
or non_anon or semi_anon or full_anon:
tab.add_message(
- '\x19%(info_col)s}Info: A configuration change not privacy-related occurred.' % info_col,
+ InfoMessage(
+ 'Info: A configuration change not privacy-related occurred.'
+ ),
typ=2)
modif = True
if show_unavailable:
tab.add_message(
- '\x19%(info_col)s}Info: The unavailable members are now shown.' % info_col,
+ InfoMessage(
+ 'Info: The unavailable members are now shown.'
+ ),
typ=2)
elif hide_unavailable:
tab.add_message(
- '\x19%(info_col)s}Info: The unavailable members are now hidden.' % info_col,
+ InfoMessage(
+ 'Info: The unavailable members are now hidden.',
+ ),
typ=2)
if non_anon:
tab.add_message(
- '\x191}Warning:\x19%(info_col)s} The room is now not anonymous. (public JID)' % info_col,
+ InfoMessage(
+ '\x191}Warning:\x19%(info_col)s} The room is now not anonymous. (public JID)' % info_col
+ ),
typ=2)
elif semi_anon:
tab.add_message(
- '\x19%(info_col)s}Info: The room is now semi-anonymous. (moderators-only JID)' % info_col,
+ InfoMessage(
+ 'Info: The room is now semi-anonymous. (moderators-only JID)',
+ ),
typ=2)
elif full_anon:
tab.add_message(
- '\x19%(info_col)s}Info: The room is now fully anonymous.' % info_col,
+ InfoMessage(
+ 'Info: The room is now fully anonymous.',
+ ),
typ=2)
if logging_on:
tab.add_message(
- '\x191}Warning: \x19%(info_col)s}This room is publicly logged' % info_col,
+ InfoMessage(
+ '\x191}Warning: \x19%(info_col)s}This room is publicly logged' % info_col
+ ),
typ=2)
elif logging_off:
tab.add_message(
- '\x19%(info_col)s}Info: This room is not logged anymore.' % info_col,
+ InfoMessage(
+ 'Info: This room is not logged anymore.',
+ ),
typ=2)
if modif:
self.core.refresh_window()
@@ -1434,15 +1459,17 @@ class HandlerCore:
if nick_from:
tab.add_message(
- "%(user)s set the subject to: \x19%(text_col)s}%(subject)s"
- % fmt,
- str_time=time,
+ InfoMessage(
+ "%(user)s set the subject to: \x19%(text_col)s}%(subject)s" % fmt,
+ time=time,
+ ),
typ=2)
else:
tab.add_message(
- "\x19%(info_col)s}The subject is: \x19%(text_col)s}%(subject)s"
- % fmt,
- str_time=time,
+ InfoMessage(
+ "The subject is: \x19%(text_col)s}%(subject)s" % fmt,
+ time=time,
+ ),
typ=2)
tab.topic = subject
tab.topic_from = nick_from
@@ -1506,18 +1533,15 @@ class HandlerCore:
xhtml_text, force=True).rstrip('\x19o').strip()
else:
poezio_colored = str(stanza)
- char = get_theme().CHAR_XML_OUT
- self.core.add_message_to_text_buffer(
- self.core.xml_buffer,
- poezio_colored,
- nickname=char)
+ self.core.xml_buffer.add_message(
+ XMLLog(txt=poezio_colored, incoming=False),
+ )
try:
if self.core.xml_tab.match_stanza(
ElementBase(ET.fromstring(stanza))):
- self.core.add_message_to_text_buffer(
- self.core.xml_tab.filtered_buffer,
- poezio_colored,
- nickname=char)
+ self.core.xml_tab.filtered_buffer.add_message(
+ XMLLog(txt=poezio_colored, incoming=False),
+ )
except:
# Most of the time what gets logged is whitespace pings. Skip.
# And also skip tab updates.
@@ -1540,17 +1564,14 @@ class HandlerCore:
xhtml_text, force=True).rstrip('\x19o').strip()
else:
poezio_colored = str(stanza)
- char = get_theme().CHAR_XML_IN
- self.core.add_message_to_text_buffer(
- self.core.xml_buffer,
- poezio_colored,
- nickname=char)
+ self.core.xml_buffer.add_message(
+ XMLLog(txt=poezio_colored, incoming=True),
+ )
try:
if self.core.xml_tab.match_stanza(stanza):
- self.core.add_message_to_text_buffer(
- self.core.xml_tab.filtered_buffer,
- poezio_colored,
- nickname=char)
+ self.core.xml_tab.filtered_buffer.add_message(
+ XMLLog(txt=poezio_colored, incoming=True),
+ )
except:
log.debug('', exc_info=True)
if isinstance(self.core.tabs.current_tab, tabs.XMLTab):
diff --git a/poezio/mam.py b/poezio/mam.py
index 6e13c074..50dad4a3 100644
--- a/poezio/mam.py
+++ b/poezio/mam.py
@@ -18,6 +18,7 @@ from poezio import tabs
from poezio import xhtml, colors
from poezio.config import config
from poezio.text_buffer import TextBuffer
+from poezio.ui.types import Message
class DiscoInfoException(Exception): pass
@@ -63,16 +64,15 @@ def add_line(
nick = nick.split('/')[0]
color = get_theme().COLOR_OWN_NICK
text_buffer.add_message(
- txt=text,
- time=time,
- nickname=nick,
- nick_color=color,
- history=True,
- user=None,
- highlight=False,
- top=top,
- identifier=None,
- jid=None,
+ Message(
+ txt=text,
+ time=time,
+ nickname=nick,
+ nick_color=color,
+ history=True,
+ user=None,
+ top=top,
+ )
)
diff --git a/poezio/tabs/basetabs.py b/poezio/tabs/basetabs.py
index eadc9a3f..fbb0c4cf 100644
--- a/poezio/tabs/basetabs.py
+++ b/poezio/tabs/basetabs.py
@@ -47,6 +47,7 @@ from poezio.text_buffer import TextBuffer
from poezio.theming import get_theme, dump_tuple
from poezio.ui.funcs import truncate_nick
from poezio.ui.consts import LONG_FORMAT_LENGTH
+from poezio.ui.types import BaseMessage, InfoMessage
from slixmpp import JID, InvalidJID, Message
@@ -572,40 +573,19 @@ class ChatTab(Tab):
def general_jid(self) -> JID:
raise NotImplementedError
- def log_message(self,
- txt: str,
- nickname: str,
- time: Optional[datetime] = None,
- typ=1):
+ def log_message(self, message: BaseMessage, typ=1):
"""
Log the messages in the archives.
"""
name = self.jid.bare
- if not logger.log_message(name, nickname, txt, date=time, typ=typ):
+ if not isinstance(message, Message):
+ return
+ if not logger.log_message(name, message.nickname, message.txt, date=message.time, typ=typ):
self.core.information('Unable to write in the log file', 'Error')
- def add_message(self,
- txt,
- time=None,
- nickname=None,
- forced_user=None,
- nick_color=None,
- identifier=None,
- jid=None,
- history=None,
- typ=1,
- highlight=False):
- self.log_message(txt, nickname, time=time, typ=typ)
- self._text_buffer.add_message(
- txt,
- time=time,
- nickname=nickname,
- highlight=highlight,
- nick_color=nick_color,
- history=history,
- user=forced_user,
- identifier=identifier,
- jid=jid)
+ def add_message(self, message: BaseMessage, typ=1):
+ self.log_message(message, typ=typ)
+ self._text_buffer.add_message(message)
def modify_message(self,
txt,
@@ -614,10 +594,10 @@ class ChatTab(Tab):
user=None,
jid=None,
nickname=None):
- self.log_message(txt, nickname, typ=1)
message = self._text_buffer.modify_message(
- txt, old_id, new_id, time=time, user=user, jid=jid)
+ txt, old_id, new_id, user=user, jid=jid)
if message:
+ self.log_message(message, typ=1)
self.text_win.modify_message(message.identifier, message)
self.core.refresh_window()
return True
@@ -1010,7 +990,10 @@ class OneToOneTab(ChatTab):
msg += 'status: %s, ' % status.message
if status.show in SHOW_NAME:
msg += 'show: %s, ' % SHOW_NAME[status.show]
- self.add_message(msg[:-2], typ=2)
+ self.add_message(
+ InfoMessage(txt=msg[:-2]),
+ typ=2,
+ )
def ack_message(self, msg_id: str, msg_jid: JID):
"""
@@ -1042,11 +1025,14 @@ class OneToOneTab(ChatTab):
message.send()
body = xhtml.xhtml_to_poezio_colors(xhtml_data, force=True)
self._text_buffer.add_message(
- body,
- nickname=self.core.own_nick,
- nick_color=get_theme().COLOR_OWN_NICK,
- identifier=message['id'],
- jid=self.core.xmpp.boundjid)
+ Message(
+ body,
+ nickname=self.core.own_nick,
+ nick_color=get_theme().COLOR_OWN_NICK,
+ identifier=message['id'],
+ jid=self.core.xmpp.boundjid,
+ )
+ )
self.refresh()
def check_features(self):
diff --git a/poezio/tabs/conversationtab.py b/poezio/tabs/conversationtab.py
index 410c5eda..70005f0f 100644
--- a/poezio/tabs/conversationtab.py
+++ b/poezio/tabs/conversationtab.py
@@ -28,6 +28,7 @@ from poezio.roster import roster
from poezio.text_buffer import CorrectionError
from poezio.theming import get_theme, dump_tuple
from poezio.decorators import command_args_parser
+from poezio.ui.types import InfoMessage
log = logging.getLogger(__name__)
@@ -179,7 +180,7 @@ class ConversationTab(OneToOneTab):
(' and their last status was %s' % status)
if status else '',
)
- self.add_message(msg)
+ self.add_message(InfoMessage(msg), typ=0)
self.core.refresh_window()
self.core.xmpp.plugin['xep_0012'].get_last_activity(
@@ -200,17 +201,21 @@ class ConversationTab(OneToOneTab):
if resource:
status = (
'Status: %s' % resource.status) if resource.status else ''
- self._text_buffer.add_message(
- "\x19%(info_col)s}Show: %(show)s, %(status)s\x19o" % {
- 'show': resource.presence or 'available',
- 'status': status,
- 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
- })
+ self.add_message(
+ InfoMessage(
+ "Show: %(show)s, %(status)s" % {
+ 'show': resource.presence or 'available',
+ 'status': status,
+ }
+ ),
+ typ=0,
+ )
return True
else:
- self._text_buffer.add_message(
- "\x19%(info_col)s}No information available\x19o" %
- {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)})
+ self.add_message(
+ InfoMessage("No information available"),
+ typ=0,
+ )
return True
@command_args_parser.quoted(0, 1)
diff --git a/poezio/tabs/muctab.py b/poezio/tabs/muctab.py
index 73359610..ff8f6c07 100644
--- a/poezio/tabs/muctab.py
+++ b/poezio/tabs/muctab.py
@@ -40,6 +40,7 @@ from poezio.roster import roster
from poezio.theming import get_theme, dump_tuple
from poezio.user import User
from poezio.core.structs import Completion, Status
+from poezio.ui.types import BaseMessage, Message, InfoMessage, StatusMessage
log = logging.getLogger(__name__)
@@ -197,8 +198,7 @@ class MucTab(ChatTab):
'color_spec': spec_col,
'nick': self.own_nick,
}
-
- self.add_message(msg, typ=2)
+ self.add_message(InfoMessage(msg), typ=2)
self.disconnect()
muc.leave_groupchat(self.core.xmpp, self.jid.bare, self.own_nick,
message)
@@ -301,7 +301,7 @@ class MucTab(ChatTab):
'role': user.role or 'None',
'status': '\n%s' % user.status if user.status else ''
}
- self.add_message(info, typ=0)
+ self.add_message(InfoMessage(info), typ=0)
return True
def change_topic(self, topic: str):
@@ -327,9 +327,13 @@ class MucTab(ChatTab):
else:
user_string = ''
- self._text_buffer.add_message(
- "\x19%s}The subject of the room is: \x19%s}%s %s" %
- (info_text, norm_text, self.topic, user_string))
+ self.add_message(
+ InfoMessage(
+ "The subject of the room is: \x19%s}%s %s" %
+ (norm_text, self.topic, user_string),
+ ),
+ typ=0,
+ )
@refresh_wrapper.always
def recolor(self, random_colors=False):
@@ -558,28 +562,32 @@ class MucTab(ChatTab):
'nick_col': color,
'info_col': info_col,
}
- self.add_message(enable_message, typ=2)
+ self.add_message(InfoMessage(enable_message), typ=2)
self.core.enable_private_tabs(self.jid.bare, enable_message)
if '201' in status_codes:
self.add_message(
- '\x19%(info_col)s}Info: The room '
- 'has been created' % {'info_col': info_col},
- typ=0)
+ InfoMessage('Info: The room has been created'),
+ typ=0
+ )
if '170' in status_codes:
self.add_message(
- '\x19%(warn_col)s}Warning:\x19%(info_col)s}'
- ' This room is publicly logged' % {
- 'info_col': info_col,
- 'warn_col': warn_col
- },
+ InfoMessage(
+ '\x19%(warn_col)s}Warning:\x19%(info_col)s}'
+ ' This room is publicly logged' % {
+ 'info_col': info_col,
+ 'warn_col': warn_col
+ },
+ ),
typ=0)
if '100' in status_codes:
self.add_message(
- '\x19%(warn_col)s}Warning:\x19%(info_col)s}'
- ' This room is not anonymous.' % {
- 'info_col': info_col,
- 'warn_col': warn_col
- },
+ InfoMessage(
+ '\x19%(warn_col)s}Warning:\x19%(info_col)s}'
+ ' This room is not anonymous.' % {
+ 'info_col': info_col,
+ 'warn_col': warn_col
+ },
+ ),
typ=0)
def handle_presence_joined(self, presence, status_codes):
@@ -635,18 +643,20 @@ class MucTab(ChatTab):
def on_non_member_kicked(self):
"""We have been kicked because the MUC is members-only"""
self.add_message(
- '\x19%(info_col)s}You have been kicked because you '
- 'are not a member and the room is now members-only.' %
- {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
+ InfoMessage(
+ 'You have been kicked because you '
+ 'are not a member and the room is now members-only.'
+ ),
typ=2)
self.disconnect()
def on_muc_shutdown(self):
"""We have been kicked because the MUC service is shutting down"""
self.add_message(
- '\x19%(info_col)s}You have been kicked because the'
- ' MUC service is shutting down.' %
- {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
+ InfoMessage(
+ 'You have been kicked because the'
+ ' MUC service is shutting down.'
+ ),
typ=2)
self.disconnect()
@@ -693,7 +703,7 @@ class MucTab(ChatTab):
'jid_color': dump_tuple(theme.COLOR_MUC_JID),
'color_spec': spec_col,
}
- self.add_message(msg, typ=2)
+ self.add_message(InfoMessage(msg), typ=2)
self.core.on_user_rejoined_private_conversation(self.jid.bare, from_nick)
def on_user_nick_change(self, presence, user, from_nick, from_room):
@@ -723,14 +733,16 @@ class MucTab(ChatTab):
old_color = color = 3
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
self.add_message(
- '\x19%(old_color)s}%(old)s\x19%(info_col)s} is'
- ' now known as \x19%(color)s}%(new)s' % {
- 'old': from_nick,
- 'new': new_nick,
- 'color': color,
- 'old_color': old_color,
- 'info_col': info_col
- },
+ InfoMessage(
+ '\x19%(old_color)s}%(old)s\x19%(info_col)s} is'
+ ' now known as \x19%(color)s}%(new)s' % {
+ 'old': from_nick,
+ 'new': new_nick,
+ 'color': color,
+ 'old_color': old_color,
+ 'info_col': info_col
+ },
+ ),
typ=2)
# rename the private tabs if needed
self.core.rename_private_tabs(self.jid.bare, from_nick, user)
@@ -814,7 +826,7 @@ class MucTab(ChatTab):
'reason': reason.text,
'info_col': info_col
}
- self.add_message(kick_msg, typ=2)
+ self.add_message(InfoMessage(kick_msg), typ=2)
def on_user_kicked(self, presence, user, from_nick):
"""
@@ -892,7 +904,7 @@ class MucTab(ChatTab):
'reason': reason.text,
'info_col': info_col
}
- self.add_message(kick_msg, typ=2)
+ self.add_message(InfoMessage(kick_msg), typ=2)
def on_user_leave_groupchat(self,
user: User,
@@ -957,7 +969,7 @@ class MucTab(ChatTab):
}
if status:
leave_msg += ' (\x19o%s\x19%s})' % (status, info_col)
- self.add_message(leave_msg, typ=2)
+ self.add_message(InfoMessage(leave_msg), typ=2)
self.core.on_user_left_private_conversation(from_room, user, status)
def on_user_change_status(self, user, from_nick, from_room, affiliation,
@@ -1016,7 +1028,7 @@ class MucTab(ChatTab):
or show != user.show or status != user.status)) or (
affiliation != user.affiliation or role != user.role):
# display the message in the room
- self._text_buffer.add_message(msg)
+ self.add_message(InfoMessage(msg))
self.core.on_user_changed_status_in_private(
'%s/%s' % (from_room, from_nick), Status(show, status))
self.users.remove(user)
@@ -1118,7 +1130,6 @@ class MucTab(ChatTab):
nickname=None,
user=None,
jid=None):
- self.log_message(txt, nickname, time=time, typ=1)
highlight = self.do_highlight(txt, time, nickname, corrected=True)
message = self._text_buffer.modify_message(
txt,
@@ -1129,6 +1140,7 @@ class MucTab(ChatTab):
user=user,
jid=jid)
if message:
+ self.log_message(message, typ=1)
self.text_win.modify_message(message.identifier, message)
return highlight
return False
@@ -1192,9 +1204,11 @@ class MucTab(ChatTab):
def on_self_ping_failed(self, iq):
if not self.lagged:
self.lagged = True
- info_text = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
self._text_buffer.add_message(
- "\x19%s}MUC service not responding." % info_text)
+ InfoMessage(
+ "MUC service not responding."
+ ),
+ )
self._state = 'disconnected'
self.core.refresh_window()
self.enable_self_ping_event()
@@ -1202,9 +1216,9 @@ class MucTab(ChatTab):
def reset_lag(self):
if self.lagged:
self.lagged = False
- info_text = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
- self._text_buffer.add_message(
- "\x19%s}MUC service is responding again." % info_text)
+ self.add_message(
+ InfoMessage("MUC service is responding again.")
+ )
if self != self.core.tabs.current_tab:
self._state = 'joined'
else:
@@ -1551,7 +1565,7 @@ class MucTab(ChatTab):
buff.append('\n')
message = ' '.join(buff)
- self._text_buffer.add_message(message)
+ self.add_message(InfoMessage(message), typ=0)
self.text_win.refresh()
self.input.refresh()
diff --git a/poezio/tabs/privatetab.py b/poezio/tabs/privatetab.py
index 7206240f..b43294a1 100644
--- a/poezio/tabs/privatetab.py
+++ b/poezio/tabs/privatetab.py
@@ -27,6 +27,7 @@ from poezio.decorators import refresh_wrapper
from poezio.logger import logger
from poezio.theming import get_theme, dump_tuple
from poezio.decorators import command_args_parser
+from poezio.ui.types import BaseMessage, Message, InfoMessage
log = logging.getLogger(__name__)
@@ -106,12 +107,14 @@ class PrivateTab(OneToOneTab):
def remove_information_element(plugin_name):
del PrivateTab.additional_information[plugin_name]
- def log_message(self, txt, nickname, time=None, typ=1):
+ def log_message(self, msg: BaseMessage, typ=1):
"""
Log the messages in the archives.
"""
+ if not isinstance(msg, Message):
+ return
if not logger.log_message(
- self.jid.full, nickname, txt, date=time, typ=typ):
+ self.jid.full, msg.nickname, msg.txt, date=msg.time, typ=typ):
self.core.information('Unable to write in the log file', 'Error')
def on_close(self):
@@ -163,8 +166,6 @@ class PrivateTab(OneToOneTab):
self.core.events.trigger('private_say', msg, self)
if not msg['body']:
return
- user = self.parent_muc.get_user_by_name(self.own_nick)
- replaced = False
if correct or msg['replace']['id']:
msg['replace']['id'] = self.last_sent_message['id']
else:
@@ -311,13 +312,15 @@ class PrivateTab(OneToOneTab):
display a message.
"""
self.add_message(
- '\x19%(nick_col)s}%(old)s\x19%(info_col)s} is now '
- 'known as \x19%(nick_col)s}%(new)s' % {
- 'old': old_nick,
- 'new': user.nick,
- 'nick_col': dump_tuple(user.color),
- 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
- },
+ InfoMessage(
+ '\x19%(nick_col)s}%(old)s\x19%(info_col)s} is now '
+ 'known as \x19%(nick_col)s}%(new)s' % {
+ 'old': old_nick,
+ 'new': user.nick,
+ 'nick_col': dump_tuple(user.color),
+ 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
+ },
+ ),
typ=2)
new_jid = self.jid.bare + '/' + user.nick
self.name = new_jid
@@ -338,27 +341,31 @@ class PrivateTab(OneToOneTab):
if not status_message:
self.add_message(
- '\x19%(quit_col)s}%(spec)s \x19%(nick_col)s}'
- '%(nick)s\x19%(info_col)s} has left the room' % {
- 'nick': user.nick,
- 'spec': theme.CHAR_QUIT,
- 'nick_col': color,
- 'quit_col': dump_tuple(theme.COLOR_QUIT_CHAR),
- 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
- },
+ InfoMessage(
+ '\x19%(quit_col)s}%(spec)s \x19%(nick_col)s}'
+ '%(nick)s\x19%(info_col)s} has left the room' % {
+ 'nick': user.nick,
+ 'spec': theme.CHAR_QUIT,
+ 'nick_col': color,
+ 'quit_col': dump_tuple(theme.COLOR_QUIT_CHAR),
+ 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
+ },
+ ),
typ=2)
else:
self.add_message(
- '\x19%(quit_col)s}%(spec)s \x19%(nick_col)s}'
- '%(nick)s\x19%(info_col)s} has left the room'
- ' (%(status)s)' % {
- 'status': status_message,
- 'nick': user.nick,
- 'spec': theme.CHAR_QUIT,
- 'nick_col': color,
- 'quit_col': dump_tuple(theme.COLOR_QUIT_CHAR),
- 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
- },
+ InfoMessage(
+ '\x19%(quit_col)s}%(spec)s \x19%(nick_col)s}'
+ '%(nick)s\x19%(info_col)s} has left the room'
+ ' (%(status)s)' % {
+ 'status': status_message,
+ 'nick': user.nick,
+ 'spec': theme.CHAR_QUIT,
+ 'nick_col': color,
+ 'quit_col': dump_tuple(theme.COLOR_QUIT_CHAR),
+ 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
+ },
+ ),
typ=2)
return self.core.tabs.current_tab is self
@@ -378,26 +385,28 @@ class PrivateTab(OneToOneTab):
if user:
color = dump_tuple(user.color)
self.add_message(
- '\x19%(join_col)s}%(spec)s \x19%(color)s}%(nick)s\x19'
- '%(info_col)s} joined the room' % {
- 'nick': nick,
- 'color': color,
- 'spec': theme.CHAR_JOIN,
- 'join_col': dump_tuple(theme.COLOR_JOIN_CHAR),
- 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
- },
+ InfoMessage(
+ '\x19%(join_col)s}%(spec)s \x19%(color)s}%(nick)s\x19'
+ '%(info_col)s} joined the room' % {
+ 'nick': nick,
+ 'color': color,
+ 'spec': theme.CHAR_JOIN,
+ 'join_col': dump_tuple(theme.COLOR_JOIN_CHAR),
+ 'info_col': dump_tuple(theme.COLOR_INFORMATION_TEXT)
+ },
+ ),
typ=2)
return self.core.tabs.current_tab is self
def activate(self, reason=None):
self.on = True
if reason:
- self.add_message(txt=reason, typ=2)
+ self.add_message(InfoMessage(reason), typ=2)
def deactivate(self, reason=None):
self.on = False
if reason:
- self.add_message(txt=reason, typ=2)
+ self.add_message(InfoMessage(reason), typ=2)
def matching_names(self):
return [(3, self.jid.resource), (4, self.name)]
@@ -407,9 +416,12 @@ class PrivateTab(OneToOneTab):
error = '\x19%s}%s\x19o' % (dump_tuple(theme.COLOR_CHAR_NACK),
error_message)
self.add_message(
- error,
- highlight=True,
- nickname='Error',
- nick_color=theme.COLOR_ERROR_MSG,
- typ=2)
+ Message(
+ error,
+ highlight=True,
+ nickname='Error',
+ nick_color=theme.COLOR_ERROR_MSG,
+ ),
+ typ=2,
+ )
self.core.refresh_window()
diff --git a/poezio/tabs/rostertab.py b/poezio/tabs/rostertab.py
index 6f43cca1..50b8c0d5 100644
--- a/poezio/tabs/rostertab.py
+++ b/poezio/tabs/rostertab.py
@@ -27,6 +27,7 @@ from poezio.theming import get_theme, dump_tuple
from poezio.decorators import command_args_parser
from poezio.core.structs import Command, Completion
from poezio.tabs import Tab
+from poezio.ui.types import InfoMessage
log = logging.getLogger(__name__)
@@ -402,11 +403,11 @@ class RosterInfoTab(Tab):
if not tab:
log.debug('Received message from nonexistent tab: %s',
message['from'])
- message = '\x19%(info_col)s}Cannot send message to %(jid)s: contact blocked' % {
+ message = 'Cannot send message to %(jid)s: contact blocked' % {
'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
'jid': message['from'],
}
- tab.add_message(message)
+ tab.add_message(InfoMessage(message), typ=0)
@command_args_parser.ignored
def command_list_blocks(self):
diff --git a/poezio/tabs/xmltab.py b/poezio/tabs/xmltab.py
index c73eddd0..85828602 100644
--- a/poezio/tabs/xmltab.py
+++ b/poezio/tabs/xmltab.py
@@ -65,7 +65,7 @@ class XMLTab(Tab):
self.filtered_buffer = text_buffer.TextBuffer()
self.info_header = windows.XMLInfoWin()
- self.text_win = windows.XMLTextWin()
+ self.text_win = windows.TextWin()
self.core_buffer.add_window(self.text_win)
self.default_help_message = windows.HelpText("/ to enter a command")
diff --git a/poezio/text_buffer.py b/poezio/text_buffer.py
index c03f84f5..3c8d78ba 100644
--- a/poezio/text_buffer.py
+++ b/poezio/text_buffer.py
@@ -14,7 +14,7 @@ log = logging.getLogger(__name__)
from typing import Dict, Union, Optional, List, Tuple
from datetime import datetime
from poezio.config import config
-from poezio.ui.types import Message
+from poezio.ui.types import Message, BaseMessage
@@ -38,7 +38,7 @@ class TextBuffer:
messages_nb_limit = config.get('max_messages_in_memory')
self._messages_nb_limit = messages_nb_limit # type: int
# Message objects
- self.messages = [] # type: List[Message]
+ self.messages = [] # type: List[BaseMessage]
# COMPAT: Correction id -> Original message id.
self.correction_ids = {} # type: Dict[str, str]
# we keep track of one or more windows
@@ -53,33 +53,10 @@ class TextBuffer:
def last_message(self) -> Optional[Message]:
return self.messages[-1] if self.messages else None
- def add_message(self,
- txt: str,
- time: Optional[datetime] = None,
- nickname: Optional[str] = None,
- nick_color: Optional[Tuple] = None,
- history: bool = False,
- user: Optional[str] = None,
- highlight: bool = False,
- top: Optional[bool] = False,
- identifier: Optional[str] = None,
- jid: Optional[str] = None,
- ack: int = 0) -> int:
+ def add_message(self, msg: BaseMessage):
"""
Create a message and add it to the text buffer
"""
- msg = Message(
- txt,
- time=time,
- nickname=nickname,
- nick_color=nick_color,
- history=history,
- user=user,
- identifier=identifier,
- top=top,
- highlight=highlight,
- jid=jid,
- ack=ack)
self.messages.append(msg)
while len(self.messages) > self._messages_nb_limit:
@@ -92,13 +69,11 @@ class TextBuffer:
# build the lines from the new message
nb = window.build_new_message(
msg,
- history=history,
- highlight=highlight,
timestamp=show_timestamps,
- top=top,
nick_size=nick_size)
if ret_val == 0:
ret_val = nb
+ top = isinstance(msg, Message) and msg.top
if window.pos != 0 and top is False:
window.scroll_up(nb)
@@ -156,7 +131,7 @@ class TextBuffer:
highlight: bool = False,
time: Optional[datetime] = None,
user: Optional[str] = None,
- jid: Optional[str] = None):
+ jid: Optional[str] = None) -> Message:
"""
Correct a message in a text buffer.
diff --git a/poezio/ui/render.py b/poezio/ui/render.py
index b695e8f3..3f94ecd8 100644
--- a/poezio/ui/render.py
+++ b/poezio/ui/render.py
@@ -3,10 +3,14 @@ import curses
from datetime import datetime
from functools import singledispatch
-from typing import List, Optional, Tuple
+from typing import List, Tuple
from math import ceil, log10
from poezio import poopt
+from poezio.theming import (
+ get_theme,
+)
+from poezio.windows import Win
from poezio.ui.consts import (
FORMAT_CHAR,
LONG_FORMAT,
@@ -16,12 +20,10 @@ from poezio.ui.funcs import (
truncate_nick,
parse_attrs,
)
-from poezio.theming import (
- get_theme,
-)
from poezio.ui.types import (
BaseMessage,
Message,
+ StatusMessage,
XMLLog,
)
@@ -86,6 +88,17 @@ def build_message(msg: Message, width: int, timestamp: bool, nick_size: int = 10
return []
offset = msg.compute_offset(timestamp, nick_size)
lines = poopt.cut_text(txt, width - offset - 1)
+ generated_lines = generate_lines(lines, msg, default_color='')
+ if msg.top:
+ generated_lines.reverse()
+ return generated_lines
+
+
+@build_lines.register(StatusMessage)
+def build_status(msg: StatusMessage, width: int, timestamp: bool, nick_size: int = 10) -> List[Line]:
+ msg.rebuild()
+ offset = msg.compute_offset(timestamp, nick_size)
+ lines = poopt.cut_text(msg.txt, width - offset - 1)
return generate_lines(lines, msg, default_color='')
@@ -97,7 +110,7 @@ def build_xmllog(msg: XMLLog, width: int, timestamp: bool, nick_size: int = 10)
@singledispatch
-def write_pre(msg: BaseMessage, win, with_timestamps: bool, nick_size: int) -> int:
+def write_pre(msg: BaseMessage, win: Win, with_timestamps: bool, nick_size: int) -> int:
"""Write the part before text (only the timestamp)"""
if with_timestamps:
return PreMessageHelpers.write_time(win, False, msg.time)
@@ -105,7 +118,7 @@ def write_pre(msg: BaseMessage, win, with_timestamps: bool, nick_size: int) -> i
@write_pre.register(Message)
-def write_pre_message(msg: Message, win, with_timestamps: bool, nick_size: int) -> int:
+def write_pre_message(msg: Message, win: Win, with_timestamps: bool, nick_size: int) -> int:
"""Write the part before the body:
- timestamp (short or long)
- ack/nack
@@ -149,7 +162,7 @@ def write_pre_message(msg: Message, win, with_timestamps: bool, nick_size: int)
@write_pre.register(XMLLog)
-def write_pre_xmllog(msg: XMLLog, win, with_timestamps: bool, nick_size: int) -> int:
+def write_pre_xmllog(msg: XMLLog, win: Win, with_timestamps: bool, nick_size: int) -> int:
"""Write the part before the stanza (timestamp + IN/OUT)"""
offset = 0
if with_timestamps:
@@ -170,7 +183,7 @@ def write_pre_xmllog(msg: XMLLog, win, with_timestamps: bool, nick_size: int) ->
class PreMessageHelpers:
@staticmethod
- def write_revisions(buffer, msg: Message) -> int:
+ def write_revisions(buffer: Win, msg: Message) -> int:
if msg.revisions:
color = get_theme().COLOR_REVISIONS_MESSAGE
with buffer.colored_text(color=color):
@@ -179,7 +192,7 @@ class PreMessageHelpers:
return 0
@staticmethod
- def write_ack(buffer) -> int:
+ def write_ack(buffer: Win) -> int:
theme = get_theme()
color = theme.COLOR_CHAR_ACK
with buffer.colored_text(color=color):
@@ -188,7 +201,7 @@ class PreMessageHelpers:
return poopt.wcswidth(theme.CHAR_ACK_RECEIVED) + 1
@staticmethod
- def write_nack(buffer) -> int:
+ def write_nack(buffer: Win) -> int:
theme = get_theme()
color = theme.COLOR_CHAR_NACK
with buffer.colored_text(color=color):
@@ -197,7 +210,7 @@ class PreMessageHelpers:
return poopt.wcswidth(theme.CHAR_NACK) + 1
@staticmethod
- def write_nickname(buffer, nickname: str, color, highlight=False) -> None:
+ def write_nickname(buffer: Win, nickname: str, color, highlight=False) -> None:
"""
Write the nickname, using the user's color
and return the number of written characters
@@ -215,7 +228,7 @@ class PreMessageHelpers:
buffer.addstr(nickname)
@staticmethod
- def write_time(buffer, history: bool, time: datetime) -> int:
+ def write_time(buffer: Win, history: bool, time: datetime) -> int:
"""
Write the date on the yth line of the window
"""
diff --git a/poezio/ui/types.py b/poezio/ui/types.py
index 6c744ac3..9ecdc185 100644
--- a/poezio/ui/types.py
+++ b/poezio/ui/types.py
@@ -27,6 +27,12 @@ class BaseMessage:
return SHORT_FORMAT_LENGTH + 1
+class InfoMessage(BaseMessage):
+ def __init__(self, txt: str, identifier: str = '', time: Optional[datetime] = None):
+ txt = ('\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)) + txt
+ super().__init__(txt=txt, identifier=identifier, time=time)
+
+
class XMLLog(BaseMessage):
"""XML Log message"""
__slots__ = ('txt', 'time', 'identifier', 'incoming')
@@ -59,6 +65,25 @@ class XMLLog(BaseMessage):
return offset
+class StatusMessage(BaseMessage):
+ __slots__ = ('txt', 'time', 'identifier', 'format_string', 'format_args')
+
+ def __init__(self, format_string: str, format_args: dict):
+ BaseMessage.__init__(
+ self,
+ txt='',
+ )
+ self.format_string = format_string
+ self.format_args = format_args
+ self.rebuild()
+
+ def rebuild(self):
+ real_args = {}
+ for key, func in self.format_args.items():
+ real_args[key] = func()
+ self.txt = self.format_string.format(**real_args)
+
+
class Message(BaseMessage):
__slots__ = ('txt', 'nick_color', 'time', 'nickname', 'user', 'history',
'identifier', 'top', 'highlight', 'me', 'old_message', 'revisions',
diff --git a/poezio/user.py b/poezio/user.py
index 146a70da..bead0a93 100644
--- a/poezio/user.py
+++ b/poezio/user.py
@@ -97,7 +97,8 @@ class User:
"""
time: datetime object
"""
- self.last_talked = time
+ if time > self.last_talked:
+ self.last_talked = time
def has_talked_since(self, t: int) -> bool:
"""
diff --git a/test/test_ui/test_render.py b/test/test_ui/test_render.py
index d13751d1..57bd05c9 100644
--- a/test/test_ui/test_render.py
+++ b/test/test_ui/test_render.py
@@ -4,7 +4,7 @@ from datetime import datetime
from poezio.theming import get_theme
from poezio.ui.render import build_lines, Line, write_pre
from poezio.ui.consts import SHORT_FORMAT
-from poezio.ui.types import BaseMessage, Message, XMLLog
+from poezio.ui.types import BaseMessage, Message, StatusMessage, XMLLog
def test_simple_build_basemsg():
msg = BaseMessage(txt='coucou')
@@ -28,6 +28,17 @@ def test_simple_render_separator():
line = build_lines(None, 100, True, 10)[0]
assert line is None
+
+def test_simple_render_status():
+ class Obj:
+ name = 'toto'
+ msg = StatusMessage("Coucou {name}", {'name': lambda: Obj.name})
+ assert msg.txt == "Coucou toto"
+ Obj.name = 'titi'
+ build_lines(msg, 100, True, 10)[0]
+ assert msg.txt == "Coucou titi"
+
+
class FakeBuffer:
def __init__(self):
self.text = ''