Merge branch 'master' into plugins
Conflicts: src/core.py
This commit is contained in:
commit
8911f85a42
4 changed files with 50 additions and 50 deletions
16
src/core.py
16
src/core.py
|
@ -51,6 +51,7 @@ from text_buffer import TextBuffer
|
||||||
from keyboard import read_char
|
from keyboard import read_char
|
||||||
from theming import get_theme
|
from theming import get_theme
|
||||||
from fifo import Fifo
|
from fifo import Fifo
|
||||||
|
from windows import g_lock
|
||||||
|
|
||||||
# http://xmpp.org/extensions/xep-0045.html#errorstatus
|
# http://xmpp.org/extensions/xep-0045.html#errorstatus
|
||||||
ERROR_AND_STATUS_CODES = {
|
ERROR_AND_STATUS_CODES = {
|
||||||
|
@ -73,8 +74,6 @@ possible_show = {'available':None,
|
||||||
'xa':'xa'
|
'xa':'xa'
|
||||||
}
|
}
|
||||||
|
|
||||||
resize_lock = threading.Lock()
|
|
||||||
|
|
||||||
Status = collections.namedtuple('Status', 'show message')
|
Status = collections.namedtuple('Status', 'show message')
|
||||||
|
|
||||||
class Core(object):
|
class Core(object):
|
||||||
|
@ -208,18 +207,21 @@ class Core(object):
|
||||||
'Just press Ctrl-n.' \
|
'Just press Ctrl-n.' \
|
||||||
))
|
))
|
||||||
self.refresh_window()
|
self.refresh_window()
|
||||||
|
|
||||||
def resize_global_information_win(self):
|
def resize_global_information_win(self):
|
||||||
"""
|
"""
|
||||||
Resize the global_information_win only once at each resize.
|
Resize the global_information_win only once at each resize.
|
||||||
"""
|
"""
|
||||||
self.information_win.resize(self.information_win_size, tabs.Tab.width,
|
with g_lock:
|
||||||
tabs.Tab.height - 2 - self.information_win_size, 0)
|
self.information_win.resize(self.information_win_size, tabs.Tab.width,
|
||||||
|
tabs.Tab.height - 2 - self.information_win_size, 0)
|
||||||
|
|
||||||
def resize_global_info_bar(self):
|
def resize_global_info_bar(self):
|
||||||
"""
|
"""
|
||||||
Resize the GlobalInfoBar only once at each resize
|
Resize the GlobalInfoBar only once at each resize
|
||||||
"""
|
"""
|
||||||
self.tab_win.resize(1, tabs.Tab.width, tabs.Tab.height - 2, 0)
|
with g_lock:
|
||||||
|
self.tab_win.resize(1, tabs.Tab.width, tabs.Tab.height - 2, 0)
|
||||||
|
|
||||||
def on_exception(self, typ, value, trace):
|
def on_exception(self, typ, value, trace):
|
||||||
"""
|
"""
|
||||||
|
@ -559,7 +561,7 @@ class Core(object):
|
||||||
if not body:
|
if not body:
|
||||||
return
|
return
|
||||||
tab.add_message(body, time=None, nickname=nick_from,
|
tab.add_message(body, time=None, nickname=nick_from,
|
||||||
forced_user=self.get_tab_by_name(room_from, tabs.MucTab).get_user_by_name(nick_from))
|
forced_user=self.get_tab_by_name(room_from, tabs.MucTab).get_user_by_name(nick_from))
|
||||||
conversation = self.get_tab_by_name(jid.full, tabs.PrivateTab)
|
conversation = self.get_tab_by_name(jid.full, tabs.PrivateTab)
|
||||||
if conversation and conversation.remote_wants_chatstates is None:
|
if conversation and conversation.remote_wants_chatstates is None:
|
||||||
if message['chat_state']:
|
if message['chat_state']:
|
||||||
|
@ -706,7 +708,7 @@ class Core(object):
|
||||||
tabs.Tab.resize(self.stdscr)
|
tabs.Tab.resize(self.stdscr)
|
||||||
self.resize_global_information_win()
|
self.resize_global_information_win()
|
||||||
self.resize_global_info_bar()
|
self.resize_global_info_bar()
|
||||||
with resize_lock:
|
with g_lock:
|
||||||
for tab in self.tabs:
|
for tab in self.tabs:
|
||||||
if config.get('lazy_resize', 'true') == 'true':
|
if config.get('lazy_resize', 'true') == 'true':
|
||||||
tab.need_resize = True
|
tab.need_resize = True
|
||||||
|
|
22
src/tabs.py
22
src/tabs.py
|
@ -305,7 +305,7 @@ class ChatTab(Tab):
|
||||||
# build the list of the recent words
|
# build the list of the recent words
|
||||||
char_we_dont_want = string.punctuation+' '
|
char_we_dont_want = string.punctuation+' '
|
||||||
words = list()
|
words = list()
|
||||||
for msg in self.messages[:-40:-1]:
|
for msg in self._text_buffer.messages[:-40:-1]:
|
||||||
if not msg:
|
if not msg:
|
||||||
continue
|
continue
|
||||||
txt = xhtml.clean_text(msg.txt)
|
txt = xhtml.clean_text(msg.txt)
|
||||||
|
@ -497,7 +497,7 @@ class MucTab(ChatTab):
|
||||||
"""
|
"""
|
||||||
/clear
|
/clear
|
||||||
"""
|
"""
|
||||||
self.messages = []
|
self._text_buffer.messages = []
|
||||||
self.text_win.rebuild_everything(self._text_buffer)
|
self.text_win.rebuild_everything(self._text_buffer)
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.core.doupdate()
|
self.core.doupdate()
|
||||||
|
@ -1218,7 +1218,7 @@ class PrivateTab(ChatTab):
|
||||||
msg['chat_state'] = needed
|
msg['chat_state'] = needed
|
||||||
self.core.events.trigger('private_say', msg)
|
self.core.events.trigger('private_say', msg)
|
||||||
msg.send()
|
msg.send()
|
||||||
self.core.add_message_to_text_buffer(self._text_buffer, line, None, self.core.own_nick or self.own_nick)
|
self.core.add_message_to_text_buffer(self._text_buffer, xhtml.convert_simple_to_full_colors(line), None, self.core.own_nick or self.own_nick)
|
||||||
self.cancel_paused_delay()
|
self.cancel_paused_delay()
|
||||||
self.text_win.refresh()
|
self.text_win.refresh()
|
||||||
self.input.refresh()
|
self.input.refresh()
|
||||||
|
@ -1580,7 +1580,6 @@ class RosterInfoTab(Tab):
|
||||||
self.command_add(jid.lstrip('\n'))
|
self.command_add(jid.lstrip('\n'))
|
||||||
self.core.information('Contacts imported from %s' % filepath, 'Info')
|
self.core.information('Contacts imported from %s' % filepath, 'Info')
|
||||||
|
|
||||||
|
|
||||||
def command_export(self, arg):
|
def command_export(self, arg):
|
||||||
"""
|
"""
|
||||||
Export the contacts
|
Export the contacts
|
||||||
|
@ -1864,6 +1863,7 @@ class ConversationTab(ChatTab):
|
||||||
self.commands['unquery'] = (self.command_unquery, _("Usage: /unquery\nUnquery: close the tab"), None)
|
self.commands['unquery'] = (self.command_unquery, _("Usage: /unquery\nUnquery: close the tab"), None)
|
||||||
self.commands['close'] = (self.command_unquery, _("Usage: /close\Close: close the tab"), None)
|
self.commands['close'] = (self.command_unquery, _("Usage: /close\Close: close the tab"), None)
|
||||||
self.commands['version'] = (self.command_version, _('Usage: /version\nVersion: get the software version of the current interlocutor (usually its XMPP client and Operating System)'), None)
|
self.commands['version'] = (self.command_version, _('Usage: /version\nVersion: get the software version of the current interlocutor (usually its XMPP client and Operating System)'), None)
|
||||||
|
self.commands['info'] = (self.command_info, _('Usage: /info\nInfo: get the status of the contact.'), None)
|
||||||
self.resize()
|
self.resize()
|
||||||
|
|
||||||
def completion(self):
|
def completion(self):
|
||||||
|
@ -1882,12 +1882,24 @@ class ConversationTab(ChatTab):
|
||||||
msg['chat_state'] = needed
|
msg['chat_state'] = needed
|
||||||
self.core.events.trigger('conversation_say', msg)
|
self.core.events.trigger('conversation_say', msg)
|
||||||
msg.send()
|
msg.send()
|
||||||
self.core.add_message_to_text_buffer(self._text_buffer, line, None, self.core.own_nick)
|
self.core.add_message_to_text_buffer(self._text_buffer, xhtml.convert_simple_to_full_colors(line), None, self.core.own_nick)
|
||||||
logger.log_message(JID(self.get_name()).bare, self.core.own_nick, line)
|
logger.log_message(JID(self.get_name()).bare, self.core.own_nick, line)
|
||||||
self.cancel_paused_delay()
|
self.cancel_paused_delay()
|
||||||
self.text_win.refresh()
|
self.text_win.refresh()
|
||||||
self.input.refresh()
|
self.input.refresh()
|
||||||
|
|
||||||
|
def command_info(self, arg):
|
||||||
|
contact = roster.get_contact_by_jid(self.get_name())
|
||||||
|
jid = JID(self.get_name())
|
||||||
|
if jid.resource:
|
||||||
|
resource = contact.get_resource_by_fulljid(jid.full)
|
||||||
|
else:
|
||||||
|
resource = contact.get_highest_priority_resource()
|
||||||
|
if resource:
|
||||||
|
self._text_buffer.add_message("\x195}Status: %s\x193}" %resource.get_status(), None, None, None, None, None)
|
||||||
|
self.refresh()
|
||||||
|
self.core.doupdate()
|
||||||
|
|
||||||
def command_unquery(self, arg):
|
def command_unquery(self, arg):
|
||||||
self.core.close_tab()
|
self.core.close_tab()
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import curses
|
||||||
import string
|
import string
|
||||||
from config import config
|
from config import config
|
||||||
|
|
||||||
from threading import Lock
|
from threading import RLock
|
||||||
|
|
||||||
from contact import Contact, Resource
|
from contact import Contact, Resource
|
||||||
from roster import RosterGroup, roster
|
from roster import RosterGroup, roster
|
||||||
|
@ -46,7 +46,7 @@ allowed_color_digits = ('0', '1', '2', '3', '4', '5', '6', '7')
|
||||||
# first is a bool telling if this is the first line of the message.
|
# first is a bool telling if this is the first line of the message.
|
||||||
Line = collections.namedtuple('Line', 'msg start_pos end_pos')
|
Line = collections.namedtuple('Line', 'msg start_pos end_pos')
|
||||||
|
|
||||||
g_lock = Lock()
|
g_lock = RLock()
|
||||||
|
|
||||||
LINES_NB_LIMIT = 4096
|
LINES_NB_LIMIT = 4096
|
||||||
|
|
||||||
|
@ -79,7 +79,8 @@ class Win(object):
|
||||||
"""
|
"""
|
||||||
Override if something has to be done on resize
|
Override if something has to be done on resize
|
||||||
"""
|
"""
|
||||||
self._resize(height, width, y, x)
|
with g_lock:
|
||||||
|
self._resize(height, width, y, x)
|
||||||
|
|
||||||
def _refresh(self):
|
def _refresh(self):
|
||||||
self._win.noutrefresh()
|
self._win.noutrefresh()
|
||||||
|
@ -255,10 +256,11 @@ class UserList(Win):
|
||||||
self._refresh()
|
self._refresh()
|
||||||
|
|
||||||
def resize(self, height, width, y, x):
|
def resize(self, height, width, y, x):
|
||||||
self._resize(height, width, y, x)
|
with g_lock:
|
||||||
self._win.attron(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
|
self._resize(height, width, y, x)
|
||||||
self._win.vline(0, 0, curses.ACS_VLINE, self.height)
|
self._win.attron(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
|
||||||
self._win.attroff(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
|
self._win.vline(0, 0, curses.ACS_VLINE, self.height)
|
||||||
|
self._win.attroff(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
|
||||||
|
|
||||||
class Topic(Win):
|
class Topic(Win):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -674,9 +676,10 @@ class TextWin(Win):
|
||||||
self.addstr(' ')
|
self.addstr(' ')
|
||||||
|
|
||||||
def resize(self, height, width, y, x, room=None):
|
def resize(self, height, width, y, x, room=None):
|
||||||
self._resize(height, width, y, x)
|
with g_lock:
|
||||||
if room:
|
self._resize(height, width, y, x)
|
||||||
self.rebuild_everything(room)
|
if room:
|
||||||
|
self.rebuild_everything(room)
|
||||||
|
|
||||||
def rebuild_everything(self, room):
|
def rebuild_everything(self, room):
|
||||||
self.built_lines = []
|
self.built_lines = []
|
||||||
|
|
39
src/xhtml.py
39
src/xhtml.py
|
@ -178,6 +178,8 @@ whitespace_re = re.compile(r'\s+')
|
||||||
|
|
||||||
xhtml_attr_re = re.compile(r'\x19\d{0,3}\}|\x19[buaio]')
|
xhtml_attr_re = re.compile(r'\x19\d{0,3}\}|\x19[buaio]')
|
||||||
|
|
||||||
|
xhtml_simple_attr_re = re.compile(r'\x19\d')
|
||||||
|
|
||||||
def get_body_from_message_stanza(message):
|
def get_body_from_message_stanza(message):
|
||||||
"""
|
"""
|
||||||
Returns a string with xhtml markups converted to
|
Returns a string with xhtml markups converted to
|
||||||
|
@ -342,6 +344,15 @@ def clean_text_simple(string):
|
||||||
pos = string.find('\x19')
|
pos = string.find('\x19')
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
def convert_simple_to_full_colors(text):
|
||||||
|
"""
|
||||||
|
takes a \x19n formatted string and returns
|
||||||
|
a \x19n} formatted one.
|
||||||
|
"""
|
||||||
|
def add_curly_bracket(match):
|
||||||
|
return match.group(0) + '}'
|
||||||
|
return re.sub(xhtml_simple_attr_re, add_curly_bracket, text)
|
||||||
|
|
||||||
number_to_color_names = {
|
number_to_color_names = {
|
||||||
1: 'red',
|
1: 'red',
|
||||||
2: 'green',
|
2: 'green',
|
||||||
|
@ -394,31 +405,3 @@ def poezio_colors_to_html(string):
|
||||||
res += '</%s>' % (elem,)
|
res += '</%s>' % (elem,)
|
||||||
res += "</p></body>"
|
res += "</p></body>"
|
||||||
return res.replace('\n', '<br />')
|
return res.replace('\n', '<br />')
|
||||||
|
|
||||||
def poezio_colors_to_xhtml(string):
|
|
||||||
"""
|
|
||||||
Generate a valid xhtml string from
|
|
||||||
the poezio colors in the given string
|
|
||||||
"""
|
|
||||||
res = "<body xmlns='http://www.w3.org/1999/xhtml'>"
|
|
||||||
next_attr_char = string.find('\x19')
|
|
||||||
open_elements = []
|
|
||||||
while next_attr_char != -1:
|
|
||||||
attr_char = string[next_attr_char+1].lower()
|
|
||||||
if next_attr_char != 0:
|
|
||||||
res += string[:next_attr_char]
|
|
||||||
string = string[next_attr_char+2:]
|
|
||||||
if attr_char == 'o':
|
|
||||||
# close all opened elements
|
|
||||||
for elem in open_elements:
|
|
||||||
res += '</%s>'
|
|
||||||
open_elements = []
|
|
||||||
elif attr_char == 'b':
|
|
||||||
if 'strong' not in open_elements:
|
|
||||||
res += '<strong>'
|
|
||||||
open_elements.append('strong')
|
|
||||||
elif attr_char in digits:
|
|
||||||
self._win.attron(common.curses_color_pair(int(attr_char)))
|
|
||||||
next_attr_char = string.find('\x19')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue