summaryrefslogtreecommitdiff
path: root/src/tabs.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/tabs.py')
-rw-r--r--src/tabs.py99
1 files changed, 84 insertions, 15 deletions
diff --git a/src/tabs.py b/src/tabs.py
index 7bc51f6c..4e1c5141 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -8,9 +8,9 @@
"""
a Tab object is a way to organize various Windows (see windows.py)
around the screen at once.
-A tab is then composed of multiple Buffer.
+A tab is then composed of multiple Buffers.
Each Tab object has different refresh() and resize() methods, defining how its
-Windows are displayed, resized, etc
+Windows are displayed, resized, etc.
"""
MIN_WIDTH = 42
@@ -216,11 +216,12 @@ class Tab(object):
# one possibily. The next tab will complete the argument.
# Otherwise we would need to add a useless space before being
# able to complete the arguments.
- hit_copy = the_input.hit_list[:]
- for w in hit_copy[:]:
- while hit_copy.count(w) > 1:
- hit_copy.remove(w)
- if len(hit_copy) in (1, 0):
+ hit_copy = set(the_input.hit_list)
+ while not hit_copy:
+ the_input.key_backspace()
+ the_input.auto_completion(words, '', quotify=False)
+ hit_copy = set(the_input.hit_list)
+ if len(hit_copy) == 1:
the_input.do_command(' ')
return True
return False
@@ -393,6 +394,7 @@ class ChatTab(Tab):
# since the last input
self.remote_supports_attention = False
self.key_func['M-v'] = self.move_separator
+ self.key_func['M-h'] = self.scroll_separator
self.key_func['M-/'] = self.last_words_completion
self.key_func['^M'] = self.on_enter
self.commands['say'] = (self.command_say,
@@ -534,7 +536,7 @@ class ChatTab(Tab):
def move_separator(self):
self.text_win.remove_line_separator()
- self.text_win.add_line_separator()
+ self.text_win.add_line_separator(self._text_buffer)
self.text_win.refresh()
self.input.refresh()
@@ -565,6 +567,11 @@ class ChatTab(Tab):
def on_half_scroll_down(self):
self.text_win.scroll_down((self.text_win.height-1) // 2)
+ def scroll_separator(self):
+ self.text_win.scroll_to_separator()
+ self.refresh()
+ self.core.doupdate()
+
class MucTab(ChatTab):
"""
@@ -599,6 +606,8 @@ class MucTab(ChatTab):
self.key_func['^I'] = self.completion
self.key_func['M-u'] = self.scroll_user_list_down
self.key_func['M-y'] = self.scroll_user_list_up
+ self.key_func['M-n'] = self.go_to_next_hl
+ self.key_func['M-p'] = self.go_to_prev_hl
# commands
self.commands['ignore'] = (self.command_ignore, _("Usage: /ignore <nickname> \nIgnore: Ignore a specified nickname."), self.completion_ignore)
self.commands['unignore'] = (self.command_unignore, _("Usage: /unignore <nickname>\nUnignore: Remove the specified nickname from the ignore list."), self.completion_unignore)
@@ -629,6 +638,22 @@ class MucTab(ChatTab):
def general_jid(self):
return self.get_name()
+ def go_to_next_hl(self):
+ """
+ Go to the next HL in the room, or the last
+ """
+ self.text_win.next_highlight()
+ self.refresh()
+ self.core.doupdate()
+
+ def go_to_prev_hl(self):
+ """
+ Go to the previous HL in the room, or the first
+ """
+ self.text_win.previous_highlight()
+ self.refresh()
+ self.core.doupdate()
+
def completion_version(self, the_input):
"""Completion for /version"""
compare_users = lambda x: x.last_talked
@@ -808,6 +833,7 @@ class MucTab(ChatTab):
/part [msg]
"""
arg = arg.strip()
+ msg = None
if self.joined:
self.disconnect()
muc.leave_groupchat(self.core.xmpp, self.name, self.own_nick, arg)
@@ -853,7 +879,8 @@ class MucTab(ChatTab):
/topic [new topic]
"""
if not arg.strip():
- self._text_buffer.add_message(_("The subject of the room is: %s") % self.topic)
+ self._text_buffer.add_message(_("\x19%s}The subject of the room is: %s") %
+ (get_theme().COLOR_INFORMATION_TEXT[0], self.topic))
self.text_win.refresh()
self.input.refresh()
return
@@ -1131,13 +1158,13 @@ class MucTab(ChatTab):
else:
self.state = 'disconnected'
self.text_win.remove_line_separator()
- self.text_win.add_line_separator()
+ self.text_win.add_line_separator(self._text_buffer)
if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text():
self.send_chat_state('inactive')
def on_gain_focus(self):
self.state = 'current'
- if self.text_win.built_lines and self.text_win.built_lines[-1] is None:
+ if self.text_win.built_lines and self.text_win.built_lines[-1] is None and config.getl('show_useless_separator', 'false') != 'true':
self.text_win.remove_line_separator()
curses.curs_set(1)
if self.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text():
@@ -1172,6 +1199,7 @@ class MucTab(ChatTab):
self.core.events.trigger('muc_join', presence, self)
if from_nick == self.own_nick:
self.joined = True
+ roster.blacklist.add(JID(from_room).server)
if self.get_name() in self.core.initial_joins:
self.core.initial_joins.remove(self.get_name())
self._state = 'normal'
@@ -1181,8 +1209,12 @@ class MucTab(ChatTab):
self.send_chat_state('active')
new_user.color = get_theme().COLOR_OWN_NICK
self.add_message(_("\x19%(info_col)s}Your nickname is \x193}%(nick)s") % {'nick': from_nick, 'info_col': get_theme().COLOR_INFORMATION_TEXT[0]})
+ if '201' in status_codes:
+ self.add_message('\x19%(info_col)s}Info: The room has been created' % {'info_col': get_theme().COLOR_INFORMATION_TEXT[0]})
if '170' in status_codes:
self.add_message('\x191}Warning: \x19%(info_col)s}this room is publicly logged' % {'info_col': get_theme().COLOR_INFORMATION_TEXT[0]})
+ if '100' in status_codes:
+ self.add_message('\x191}Warning: \x19%(info_col)s}This room is not anonymous.' % {'info_col': get_theme().COLOR_INFORMATION_TEXT[0]})
if self.core.current_tab() is not self:
self.refresh_tab_win()
self.core.current_tab().input.refresh()
@@ -1192,6 +1224,8 @@ class MucTab(ChatTab):
change_nick = '303' in status_codes
kick = '307' in status_codes and typ == 'unavailable'
ban = '301' in status_codes and typ == 'unavailable'
+ shutdown = '332' in status_codes and typ == 'unavailable'
+ non_member = '322' in status_codes and typ == 'unavailable'
user = self.get_user_by_name(from_nick)
# New user
if not user:
@@ -1210,6 +1244,12 @@ class MucTab(ChatTab):
self.core.events.trigger('muc_kick', presence, self)
self.core.on_user_left_private_conversation(from_room, from_nick, status)
self.on_user_kicked(presence, user, from_nick)
+ elif shutdown:
+ self.core.events.trigger('muc_shutdown', presence, self)
+ self.on_muc_shutdown()
+ elif non_member:
+ self.core.events.trigger('muc_shutdown', presence, self)
+ self.on_non_member_kick()
# user quit
elif typ == 'unavailable':
self.on_user_leave_groupchat(user, jid, status, from_nick, from_room)
@@ -1223,6 +1263,16 @@ class MucTab(ChatTab):
self.input.refresh()
self.core.doupdate()
+ 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': get_theme().COLOR_INFORMATION_TEXT[0]})
+ 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': get_theme().COLOR_INFORMATION_TEXT[0]})
+ self.disconnect()
+
def on_user_join(self, from_nick, affiliation, show, status, role, jid):
"""
When a new user joins the groupchat
@@ -1478,7 +1528,7 @@ class MucTab(ChatTab):
if highlight:
nick_color = highlight
time = time or datetime.now()
- self._text_buffer.add_message(txt, time, nickname, nick_color, history, user)
+ self._text_buffer.add_message(txt, time, nickname, nick_color, history, user, highlight=highlight)
return highlight
class PrivateTab(ChatTab):
@@ -1518,7 +1568,26 @@ class PrivateTab(ChatTab):
self.parent_muc.privates.remove(self)
def completion(self):
- self.complete_commands(self.input)
+ """
+ Called when Tab is pressed, complete the nickname in the input
+ """
+ if self.complete_commands(self.input):
+ return
+
+ # If we are not completing a command or a command's argument, complete a nick
+ compare_users = lambda x: x.last_talked
+ word_list = [user.nick for user in sorted(self.parent_muc.users, key=compare_users, reverse=True)\
+ if user.nick != self.own_nick]
+ after = config.get('after_completion', ',')+" "
+ input_pos = self.input.pos + self.input.line_pos
+ if ' ' not in self.input.get_text()[:input_pos] or (self.input.last_completion and\
+ self.input.get_text()[:input_pos] == self.input.last_completion + after):
+ add_after = after
+ else:
+ add_after = ''
+ self.input.auto_completion(word_list, add_after, quotify=False)
+ empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//'))
+ self.send_composing_chat_state(empty_after)
def command_say(self, line, attention=False):
if not self.on:
@@ -1644,7 +1713,7 @@ class PrivateTab(ChatTab):
def on_lose_focus(self):
self.state = 'normal'
self.text_win.remove_line_separator()
- self.text_win.add_line_separator()
+ self.text_win.add_line_separator(self._text_buffer)
tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab)
if tab and tab.joined and config.get_by_tabname(
'send_chat_states', 'true', self.general_jid, True) == 'true'\
@@ -2562,7 +2631,7 @@ class ConversationTab(ChatTab):
resource = None
self.state = 'normal'
self.text_win.remove_line_separator()
- self.text_win.add_line_separator()
+ self.text_win.add_line_separator(self._text_buffer)
if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and (not self.input.get_text() or not self.input.get_text().startswith('//')):
if resource:
self.send_chat_state('inactive')