Daniel Brötzmann pushed to branch master at gajim / gajim
Commits:
b403484a by wurstsalat at 2022-06-23T22:11:29+02:00
refactor: Move GroupChatNickCompletion into ChatActionProcessor
- - - - -
4 changed files:
- gajim/gtk/chat_action_processor.py
- gajim/gtk/controls/groupchat.py
- gajim/gtk/groupchat_nick_completion.py
- gajim/gtk/message_input.py
Changes:
=====================================
gajim/gtk/chat_action_processor.py
=====================================
@@ -24,9 +24,13 @@
from gi.repository import Gtk
from gajim.common import app
+from gajim.common import types
from gajim.common.const import Direction
+from gajim.common.modules.contacts import GroupchatContact
from .emoji_data_gtk import get_emoji_data
+from .groupchat_nick_completion import GroupChatNickCompletion
+
if TYPE_CHECKING:
from .message_input import MessageInputTextView
@@ -34,7 +38,11 @@
class ChatActionProcessor(Gtk.Popover):
- def __init__(self, message_input: MessageInputTextView) -> None:
+ def __init__(self,
+ account: str,
+ contact: types.ChatContactT,
+ message_input: MessageInputTextView
+ ) -> None:
Gtk.Popover.__init__(self)
self._menu = Gio.Menu()
self.bind_model(self._menu)
@@ -51,6 +59,12 @@ def __init__(self, message_input: MessageInputTextView) -> None:
self._buf = message_input.get_buffer()
self._buf.connect('changed', self._on_changed)
+ self._nick_completion: Optional[GroupChatNickCompletion] = None
+ if contact.is_groupchat:
+ assert isinstance(contact, GroupchatContact)
+ self._nick_completion = GroupChatNickCompletion(
+ account, contact, message_input)
+
self._start_mark: Optional[Gtk.TextMark] = None
self._current_iter: Optional[Gtk.TextIter] = None
@@ -60,9 +74,14 @@ def _on_destroy(self, _popover: Gtk.Popover) -> None:
app.check_finalize(self)
def _on_key_press(self,
- _textview: Gtk.TextView,
+ textview: MessageInputTextView,
event: Gdk.EventKey
) -> bool:
+ if self._nick_completion is not None:
+ res = self._nick_completion.process_key_press(textview, event)
+ if res:
+ return True
+
if not self._active:
return False
@@ -305,3 +324,7 @@ def _move_selection(self, direction: Direction) -> None:
def _item_has_focus(item: Gtk.ModelButton) -> bool:
flags = item.get_state_flags()
return 'GTK_STATE_FLAG_FOCUSED' in str(flags)
+
+ def process_outgoing_message(self, contact: str, highlight: bool) -> None:
+ if self._nick_completion is not None:
+ self._nick_completion.record_message(contact, highlight)
=====================================
gajim/gtk/controls/groupchat.py
=====================================
@@ -72,7 +72,6 @@
from gajim.gui.groupchat_inviter import GroupChatInviter
from gajim.gui.groupchat_roster import GroupchatRoster
from gajim.gui.groupchat_state import GroupchatState
-from gajim.gui.groupchat_nick_completion import GroupChatNickCompletion
from gajim.gui.util import open_window
from ..menus import get_encryption_menu
@@ -152,9 +151,6 @@ def __init__(self, account: str, jid: JID) -> None:
# if True, the room has mentioned us
self.attention_flag: bool = False
- self._nick_completion = GroupChatNickCompletion(
- self.account, self.contact, self.msg_textview)
-
# Send file
self.xml.sendfile_button.set_action_name(
f'win.send-file-{self.control_id}')
@@ -657,7 +653,7 @@ def add_message(self,
highlight = helpers.message_needs_highlight(
text, self.contact.nickname, self._client.get_own_jid().bare)
- self._nick_completion.record_message(contact, highlight)
+ self.msg_textview.process_outgoing_message(contact, highlight)
BaseControl.add_message(self,
text,
=====================================
gajim/gtk/groupchat_nick_completion.py
=====================================
@@ -44,8 +44,6 @@ def __init__(self,
self._contact.connect(
'user-nickname-changed', self._on_user_nickname_changed)
- message_input.connect('key-press-event', self._on_key_press)
-
self._sender_list: list[str] = []
self._attention_list: list[str] = []
self._nick_hits: list[str] = []
@@ -140,10 +138,10 @@ def _nick_matching(nick: str) -> bool:
return matches + other_nicks
- def _on_key_press(self,
- textview: MessageInputTextView,
- event: Gdk.EventKey
- ) -> bool:
+ def process_key_press(self,
+ textview: MessageInputTextView,
+ event: Gdk.EventKey
+ ) -> bool:
if event.keyval not in (Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Tab):
self._last_key_tab = False
return False
@@ -156,7 +154,6 @@ def _on_key_press(self,
text_split = text.split()
- # nick completion
# check if tab is pressed with empty message
if text_split: # if there are any words
begin = text_split[-1] # last word we typed
@@ -194,22 +191,21 @@ def _on_key_press(self,
return False
if self._nick_hits:
+ shell_like_completion = app.settings.get('shell_like_completion')
+
if len(text_split) < 2 or with_refer_to_nick_char:
# This is the 1st word of the line or no word or we are
- # cycling at the beginning, possibly with a space in
- # one nick
+ # cycling at the beginning, possibly with a space in one nick
add = gc_refer_to_nick_char + ' '
else:
add = ' '
start_iter = end_iter.copy()
if (self._last_key_tab and
with_refer_to_nick_char or (text and text[-1] == ' ')):
- # have to accommodate for the added space from last
- # completion
+ # have to accommodate for the added space from last completion
# gc_refer_to_nick_char may be more than one char!
start_iter.backward_chars(len(begin) + len(add))
- elif (self._last_key_tab and
- not app.settings.get('shell_like_completion')):
+ elif self._last_key_tab and not shell_like_completion:
# have to accommodate for the added space from last
# completion
start_iter.backward_chars(
@@ -225,11 +221,10 @@ def _on_key_press(self,
# get a shell-like completion
# if there's more than one nick for this completion, complete
# only the part that all these nicks have in common
- if (app.settings.get('shell_like_completion') and
- len(self._nick_hits) > 1):
+ if shell_like_completion and len(self._nick_hits) > 1:
end = False
completion = ''
- add = "" # if nick is not complete, don't add anything
+ add = '' # if nick is not complete, don't add anything
while not end and len(completion) < len(self._nick_hits[0]):
completion = self._nick_hits[0][:len(completion) + 1]
for nick in self._nick_hits:
=====================================
gajim/gtk/message_input.py
=====================================
@@ -73,7 +73,8 @@ def __init__(self, account: str, contact: ChatContactT) -> None:
self._undo_list: list[str] = []
self.undo_pressed: bool = False
- self._chat_action_processor = ChatActionProcessor(self)
+ self._chat_action_processor = ChatActionProcessor(
+ account, contact, self)
self.get_buffer().create_tag('strong', weight=Pango.Weight.BOLD)
self.get_buffer().create_tag('emphasis', style=Pango.Style.ITALIC)
@@ -313,3 +314,10 @@ def undo(self, *args: Any) -> None:
if self._undo_list:
buf.set_text(self._undo_list.pop())
self.undo_pressed = True
+
+ def process_outgoing_message(self,
+ contact_name: str,
+ highlight: bool
+ ) -> None:
+ self._chat_action_processor.process_outgoing_message(
+ contact_name, highlight)
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/b403484a10236a77d8cc2cdf60b0bfcb…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/b403484a10236a77d8cc2cdf60b0bfcb…
You're receiving this email because of your account on dev.gajim.org.
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
0ae36837 by lovetox at 2022-06-22T22:46:22+02:00
fix: StatusIcon: Logic error on activate
- - - - -
1 changed file:
- gajim/gtk/status_icon.py
Changes:
=====================================
gajim/gtk/status_icon.py
=====================================
@@ -193,7 +193,7 @@ def _on_toggle_window(self, _widget: Gtk.MenuItem) -> None:
def _on_activate(self, *args: Any) -> None:
if app.window.is_minimized():
app.window.unminimize()
- if app.window.is_withdrawn():
+ elif app.window.is_withdrawn():
app.window.show()
else:
app.window.hide()
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/0ae36837eb957626fa497c8409059dc4…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/0ae36837eb957626fa497c8409059dc4…
You're receiving this email because of your account on dev.gajim.org.
Daniel Brötzmann pushed to branch master at gajim / gajim
Commits:
6cd4bf4a by wurstsalat at 2022-06-22T20:08:41+02:00
refactor: Separate nickname generator to GroupChatNickCompletion
- - - - -
5 changed files:
- gajim/gtk/controls/base.py
- gajim/gtk/controls/groupchat.py
- + gajim/gtk/groupchat_nick_completion.py
- gajim/gtk/util.py
- pyrightconfig.json
Changes:
=====================================
gajim/gtk/controls/base.py
=====================================
@@ -266,9 +266,6 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None:
# TODO:
self.user_nick: Optional[str] = None
- self.command_hits: list[str] = []
- self.last_key_tabs: bool = False
-
self.sendmessage: bool = True
self._client.get_module('Chatstate').set_active(self.contact)
@@ -846,10 +843,6 @@ def _on_message_textview_key_press_event(self,
self.space_pressed = False
# Ctrl [+ Shift] + Tab are not forwarded to notebook. We handle it here
- if self.is_groupchat:
- if event.keyval not in (Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Tab):
- self.last_key_tabs = False
-
if event.get_state() & Gdk.ModifierType.SHIFT_MASK:
if (event.get_state() & Gdk.ModifierType.CONTROL_MASK and
event.keyval == Gdk.KEY_ISO_Left_Tab):
=====================================
gajim/gtk/controls/groupchat.py
=====================================
@@ -72,8 +72,7 @@
from gajim.gui.groupchat_inviter import GroupChatInviter
from gajim.gui.groupchat_roster import GroupchatRoster
from gajim.gui.groupchat_state import GroupchatState
-from gajim.gui.message_input import MessageInputTextView
-from gajim.gui.util import NickCompletionGenerator
+from gajim.gui.groupchat_nick_completion import GroupChatNickCompletion
from gajim.gui.util import open_window
from ..menus import get_encryption_menu
@@ -153,11 +152,8 @@ def __init__(self, account: str, jid: JID) -> None:
# if True, the room has mentioned us
self.attention_flag: bool = False
- # sorted list of nicks who mentioned us (last at the end)
- self.attention_list: list[str] = []
- self.nick_hits: list[str] = []
- self.__nick_completion: Optional[NickCompletionGenerator] = None
- self.last_key_tabs: bool = False
+ self._nick_completion = GroupChatNickCompletion(
+ self.account, self.contact, self.msg_textview)
# Send file
self.xml.sendfile_button.set_action_name(
@@ -260,13 +256,6 @@ def _on_client_state_changed(self,
) -> None:
pass
- @property
- def _nick_completion(self) -> NickCompletionGenerator:
- if self.__nick_completion is None:
- self.__nick_completion = NickCompletionGenerator(
- self.contact.nickname)
- return self.__nick_completion
-
@property
def disco_info(self):
return app.storage.cache.get_last_disco_info(self.contact.jid)
@@ -797,7 +786,7 @@ def _on_user_joined(self,
_contact: GroupchatContact,
_signal_name: str,
user_contact: GroupchatParticipant,
- properties: MessageProperties
+ properties: PresenceProperties
) -> None:
nick = user_contact.name
if not properties.is_muc_self_presence:
@@ -852,12 +841,10 @@ def _on_user_nickname_changed(self,
nick = user_contact.name
new_nick = properties.muc_user.nick
if properties.is_muc_self_presence:
- self._nick_completion.change_nick(new_nick)
message = _('You are now known as %s') % new_nick
else:
message = _('{nick} is now known '
'as {new_nick}').format(nick=nick, new_nick=new_nick)
- self._nick_completion.contact_renamed(nick, new_nick)
self.add_info_message(message)
@@ -1224,128 +1211,6 @@ def _on_drag_data_received(self,
# File drag and drop (handled in chat_control_base)
self.drag_data_file_transfer(selection)
- def _jid_not_blocked(self, bare_jid: str) -> bool:
- fjid = self.room_jid + '/' + bare_jid
- return not helpers.jid_is_blocked(self.account, fjid)
-
- def _on_message_textview_key_press_event(self,
- textview: MessageInputTextView,
- event: Gdk.EventKey
- ) -> bool:
- # pylint: disable=too-many-nested-blocks
- res = BaseControl._on_message_textview_key_press_event(
- self, textview, event)
- if res:
- return True
-
- if event.keyval == Gdk.KEY_Tab: # TAB
- message_buffer = textview.get_buffer()
- start_iter, end_iter = message_buffer.get_bounds()
- cursor_position = message_buffer.get_insert()
- end_iter = message_buffer.get_iter_at_mark(cursor_position)
- text = message_buffer.get_text(start_iter, end_iter, False)
-
- splitted_text = text.split()
-
- # nick completion
- # check if tab is pressed with empty message
- if splitted_text: # if there are any words
- begin = splitted_text[-1] # last word we typed
- else:
- begin = ''
-
- gc_refer_to_nick_char = app.settings.get('gc_refer_to_nick_char')
- with_refer_to_nick_char = False
- after_nick_len = 1 # the space that is printed after we type [Tab]
-
- # first part of this if : works fine even if refer_to_nick_char
- if (gc_refer_to_nick_char and
- text.endswith(gc_refer_to_nick_char + ' ')):
- with_refer_to_nick_char = True
- after_nick_len = len(gc_refer_to_nick_char + ' ')
- if self.nick_hits and self.last_key_tabs and \
- text[:-after_nick_len].endswith(self.nick_hits[0]):
- # we should cycle
- # Previous nick in list may had a space inside, so we check text
- # and not splitted_text and store it into 'begin' var
- self.nick_hits.append(self.nick_hits[0])
- begin = self.nick_hits.pop(0)
- else:
- list_nick = self.contact.get_user_nicknames()
- list_nick = list(filter(self._jid_not_blocked, list_nick))
-
- log.debug("Nicks to be considered for autosuggestions: %s",
- list_nick)
- self.nick_hits = self._nick_completion.generate_suggestions(
- nicks=list_nick, beginning=begin)
- log.debug("Nicks filtered for autosuggestions: %s",
- self.nick_hits)
-
- if self.nick_hits:
- if len(splitted_text) < 2 or with_refer_to_nick_char:
- # This is the 1st word of the line or no word or we are
- # cycling at the beginning, possibly with a space in
- # one nick
- add = gc_refer_to_nick_char + ' '
- else:
- add = ' '
- start_iter = end_iter.copy()
- if (self.last_key_tabs and
- with_refer_to_nick_char or (text and text[-1] == ' ')):
- # have to accommodate for the added space from last
- # completion
- # gc_refer_to_nick_char may be more than one char!
- start_iter.backward_chars(len(begin) + len(add))
- elif (self.last_key_tabs and
- not app.settings.get('shell_like_completion')):
- # have to accommodate for the added space from last
- # completion
- start_iter.backward_chars(
- len(begin) + len(gc_refer_to_nick_char))
- else:
- start_iter.backward_chars(len(begin))
-
- self._client.get_module('Chatstate').block_chatstates(
- self.contact, True)
-
- message_buffer.delete(start_iter, end_iter)
- # get a shell-like completion
- # if there's more than one nick for this completion, complete
- # only the part that all these nicks have in common
- if (app.settings.get('shell_like_completion') and
- len(self.nick_hits) > 1):
- end = False
- completion = ''
- add = "" # if nick is not complete, don't add anything
- while not end and len(completion) < len(self.nick_hits[0]):
- completion = self.nick_hits[0][:len(completion) + 1]
- for nick in self.nick_hits:
- if completion.lower() not in nick.lower():
- end = True
- completion = completion[:-1]
- break
- # if the current nick matches a COMPLETE existing nick,
- # and if the user tab TWICE, complete that nick (with the
- # "add")
- if self.last_key_tabs:
- for nick in self.nick_hits:
- if nick == completion:
- # The user seems to want this nick, so
- # complete it as if it were the only nick
- # available
- add = gc_refer_to_nick_char + ' '
- else:
- completion = self.nick_hits[0]
- message_buffer.insert_at_cursor(completion + add)
-
- self._client.get_module('Chatstate').block_chatstates(
- self.contact, False)
-
- self.last_key_tabs = True
- return True
- self.last_key_tabs = False
- return False
-
def delegate_action(self, action: str) -> int:
res = super().delegate_action(action)
if res == Gdk.EVENT_STOP:
=====================================
gajim/gtk/groupchat_nick_completion.py
=====================================
@@ -0,0 +1,264 @@
+# This file is part of Gajim.
+#
+# Gajim is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; version 3 only.
+#
+# Gajim is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import logging
+
+from nbxmpp.structs import PresenceProperties
+
+from gi.repository import Gdk
+
+from gajim.common import app
+from gajim.common import types
+from gajim.common.helpers import jid_is_blocked
+
+if TYPE_CHECKING:
+ from .message_input import MessageInputTextView
+
+log = logging.getLogger('gajim.gui.groupchat_nick_completion')
+
+
+class GroupChatNickCompletion:
+ def __init__(self,
+ account: str,
+ contact: types.GroupchatContactT,
+ message_input: MessageInputTextView
+ ) -> None:
+ self._account = account
+ self._client = app.get_client(account)
+
+ self._contact = contact
+ self._contact.connect(
+ 'user-nickname-changed', self._on_user_nickname_changed)
+
+ self._message_input = message_input
+ self._message_input.connect('key-press-event', self._on_key_press)
+
+ self._sender_list: list[str] = []
+ self._attention_list: list[str] = []
+ self._nick_hits: list[str] = []
+ self._last_key_tab = False
+
+ def _on_user_nickname_changed(self,
+ _contact: types.GroupchatContact,
+ _signal_name: str,
+ user_contact: types.GroupchatParticipant,
+ properties: PresenceProperties
+ ) -> None:
+ if properties.is_muc_self_presence:
+ return
+
+ old_name = user_contact.name
+ assert properties.muc_user
+ new_name = properties.muc_user.nick
+ assert new_name is not None
+ log.debug('Contact %s renamed to %s', old_name, new_name)
+ for lst in (self._attention_list, self._sender_list):
+ for idx, contact in enumerate(lst):
+ if contact == old_name:
+ lst[idx] = new_name
+
+ def record_message(self, contact_name: str, highlight: bool) -> None:
+ if contact_name == self._contact.nickname:
+ return
+
+ log.debug('Recorded a message from %s, highlight; %s',
+ contact_name,
+ highlight)
+
+ if highlight:
+ try:
+ self._attention_list.remove(contact_name)
+ except ValueError:
+ pass
+ if len(self._attention_list) > 6:
+ self._attention_list.pop(0) # remove older
+ self._attention_list.append(contact_name)
+
+ # TODO implement it in a more efficient way
+ # Currently it's O(n*m + n*s), where n is the number of participants and
+ # m is the number of messages processed, s - the number of times the
+ # suggestions are requested
+ #
+ # A better way to do it would be to keep a dict: contact -> timestamp
+ # with expected O(1) insert, and sort it by timestamps in O(n log n)
+ # for each suggestion (currently generating the suggestions is O(n))
+ # this would give the expected complexity of O(m + s * n log n)
+ try:
+ self._sender_list.remove(contact_name)
+ except ValueError:
+ pass
+ self._sender_list.append(contact_name)
+
+ def _generate_suggestions(self,
+ nicks: list[str],
+ beginning: str
+ ) -> list[str]:
+ """
+ Generate the order of suggested MUC autocompletions
+
+ `nicks` is the list of contacts currently participating in a MUC
+ `beginning` is the text already typed by the user
+ """
+ def _nick_matching(nick: str) -> bool:
+ return (nick != self._contact.nickname and
+ nick.lower().startswith(beginning.lower()))
+
+ if beginning == '':
+ # empty message, so just suggest recent mentions
+ potential_matches = self._attention_list
+ else:
+ # nick partially typed, try completing it
+ potential_matches = self._sender_list
+
+ potential_matches_set = set(potential_matches)
+ log.debug('Priority matches: %s', potential_matches_set)
+
+ matches = [n for n in potential_matches if _nick_matching(n)]
+ # the most recent nick is the last one on the list
+ matches.reverse()
+
+ # handle people who have not posted/mentioned us
+ other_nicks = [
+ n for n in nicks
+ if _nick_matching(n) and n not in potential_matches_set
+ ]
+ other_nicks.sort(key=str.lower)
+ log.debug('Other matches: %s', other_nicks)
+
+ return matches + other_nicks
+
+ def _on_key_press(self,
+ textview: MessageInputTextView,
+ event: Gdk.EventKey
+ ) -> bool:
+ if event.keyval not in (Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Tab):
+ self._last_key_tab = False
+ return False
+
+ message_buffer = textview.get_buffer()
+ start_iter, end_iter = message_buffer.get_bounds()
+ cursor_position = message_buffer.get_insert()
+ end_iter = message_buffer.get_iter_at_mark(cursor_position)
+ text = message_buffer.get_text(start_iter, end_iter, False)
+
+ text_split = text.split()
+
+ # nick completion
+ # check if tab is pressed with empty message
+ if text_split: # if there are any words
+ begin = text_split[-1] # last word we typed
+ else:
+ begin = ''
+
+ gc_refer_to_nick_char = app.settings.get('gc_refer_to_nick_char')
+ with_refer_to_nick_char = False
+ after_nick_len = 1 # the space that is printed after we type [Tab]
+
+ # first part of this if : works fine even if refer_to_nick_char
+ if (gc_refer_to_nick_char and
+ text.endswith(gc_refer_to_nick_char + ' ')):
+ with_refer_to_nick_char = True
+ after_nick_len = len(gc_refer_to_nick_char + ' ')
+ if (self._nick_hits and self._last_key_tab and
+ text[:-after_nick_len].endswith(self._nick_hits[0])):
+ # we should cycle
+ # Previous nick in list may had a space inside, so we check text
+ # and not text_split and store it into 'begin' var
+ self._nick_hits.append(self._nick_hits[0])
+ begin = self._nick_hits.pop(0)
+ else:
+ list_nick = self._contact.get_user_nicknames()
+ list_nick = list(filter(self._jid_not_blocked, list_nick))
+
+ log.debug('Nicks to be considered for autosuggestions: %s',
+ list_nick)
+ self._nick_hits = self._generate_suggestions(
+ nicks=list_nick, beginning=begin)
+ log.debug('Nicks filtered for autosuggestions: %s',
+ self._nick_hits)
+ if not self._nick_hits:
+ self._last_key_tab = True
+ return False
+
+ if self._nick_hits:
+ if len(text_split) < 2 or with_refer_to_nick_char:
+ # This is the 1st word of the line or no word or we are
+ # cycling at the beginning, possibly with a space in
+ # one nick
+ add = gc_refer_to_nick_char + ' '
+ else:
+ add = ' '
+ start_iter = end_iter.copy()
+ if (self._last_key_tab and
+ with_refer_to_nick_char or (text and text[-1] == ' ')):
+ # have to accommodate for the added space from last
+ # completion
+ # gc_refer_to_nick_char may be more than one char!
+ start_iter.backward_chars(len(begin) + len(add))
+ elif (self._last_key_tab and
+ not app.settings.get('shell_like_completion')):
+ # have to accommodate for the added space from last
+ # completion
+ start_iter.backward_chars(
+ len(begin) + len(gc_refer_to_nick_char))
+ else:
+ start_iter.backward_chars(len(begin))
+
+ self._client.get_module('Chatstate').block_chatstates(
+ self._contact, True)
+
+ message_buffer.delete(start_iter, end_iter)
+ # get a shell-like completion
+ # if there's more than one nick for this completion, complete
+ # only the part that all these nicks have in common
+ if (app.settings.get('shell_like_completion') and
+ len(self._nick_hits) > 1):
+ end = False
+ completion = ''
+ add = "" # if nick is not complete, don't add anything
+ while not end and len(completion) < len(self._nick_hits[0]):
+ completion = self._nick_hits[0][:len(completion) + 1]
+ for nick in self._nick_hits:
+ if completion.lower() not in nick.lower():
+ end = True
+ completion = completion[:-1]
+ break
+ # if the current nick matches a COMPLETE existing nick,
+ # and if the user tab TWICE, complete that nick (with the
+ # "add")
+ if self._last_key_tab:
+ for nick in self._nick_hits:
+ if nick == completion:
+ # The user seems to want this nick, so
+ # complete it as if it were the only nick
+ # available
+ add = gc_refer_to_nick_char + ' '
+ else:
+ completion = self._nick_hits[0]
+ message_buffer.insert_at_cursor(completion + add)
+
+ self._client.get_module('Chatstate').block_chatstates(
+ self._contact, False)
+
+ self._last_key_tab = True
+ return True
+
+ def _jid_not_blocked(self, resource: str) -> bool:
+ resource_contact = self._contact.get_resource(resource)
+ return not jid_is_blocked(
+ self._account, str(resource_contact.jid))
=====================================
gajim/gtk/util.py
=====================================
@@ -65,89 +65,6 @@
MenuItemListT = list[tuple[str, str, MenuValueT]]
-class NickCompletionGenerator:
- def __init__(self, self_nick: str) -> None:
- self.nick = self_nick
- self.sender_list: list[str] = []
- self.attention_list: list[str] = []
-
- def change_nick(self, new_nick: str) -> None:
- self.nick = new_nick
-
- def record_message(self, contact: str, highlight: bool) -> None:
- if contact == self.nick:
- return
-
- log.debug('Recorded a message from %s, highlight; %s', contact,
- highlight)
- if highlight:
- try:
- self.attention_list.remove(contact)
- except ValueError:
- pass
- if len(self.attention_list) > 6:
- self.attention_list.pop(0) # remove older
- self.attention_list.append(contact)
-
- # TODO implement it in a more efficient way
- # Currently it's O(n*m + n*s), where n is the number of participants and
- # m is the number of messages processed, s - the number of times the
- # suggestions are requested
- #
- # A better way to do it would be to keep a dict: contact -> timestamp
- # with expected O(1) insert, and sort it by timestamps in O(n log n)
- # for each suggestion (currently generating the suggestions is O(n))
- # this would give the expected complexity of O(m + s * n log n)
- try:
- self.sender_list.remove(contact)
- except ValueError:
- pass
- self.sender_list.append(contact)
-
- def contact_renamed(self, contact_old: str, contact_new: str) -> None:
- log.debug('Contact %s renamed to %s', contact_old, contact_new)
- for lst in (self.attention_list, self.sender_list):
- for idx, contact in enumerate(lst):
- if contact == contact_old:
- lst[idx] = contact_new
-
- def generate_suggestions(self, nicks: list[str],
- beginning: str) -> list[str]:
- """
- Generate the order of suggested MUC autocompletions
-
- `nicks` is the list of contacts currently participating in a MUC
- `beginning` is the text already typed by the user
- """
- def nick_matching(nick: str) -> bool:
- return nick != self.nick \
- and nick.lower().startswith(beginning.lower())
-
- if beginning == '':
- # empty message, so just suggest recent mentions
- potential_matches = self.attention_list
- else:
- # nick partially typed, try completing it
- potential_matches = self.sender_list
-
- potential_matches_set = set(potential_matches)
- log.debug('Priority matches: %s', potential_matches_set)
-
- matches = [n for n in potential_matches if nick_matching(n)]
- # the most recent nick is the last one on the list
- matches.reverse()
-
- # handle people who have not posted/mentioned us
- other_nicks = [
- n for n in nicks
- if nick_matching(n) and n not in potential_matches_set
- ]
- other_nicks.sort(key=str.lower)
- log.debug('Other matches: %s', other_nicks)
-
- return matches + other_nicks
-
-
def set_urgency_hint(window: Gtk.Window, setting: bool) -> None:
if app.settings.get('use_urgency_hint'):
window.set_urgency_hint(setting)
=====================================
pyrightconfig.json
=====================================
@@ -79,6 +79,7 @@
"gajim/gtk/groupchat_invitation.py",
"gajim/gtk/groupchat_inviter.py",
"gajim/gtk/groupchat_nick.py",
+ "gajim/gtk/groupchat_nick_completion.py",
"gajim/gtk/groupchat_outcasts.py",
"gajim/gtk/groupchat_settings.py",
"gajim/gtk/groupchat_state.py",
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/6cd4bf4ac6deb4ddac9c6f463967027d…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/6cd4bf4ac6deb4ddac9c6f463967027d…
You're receiving this email because of your account on dev.gajim.org.
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
53ebe405 by lovetox at 2022-06-22T18:39:59+02:00
ci: Windows: Update python version to 3.10
- - - - -
1 changed file:
- win/_base.sh
Changes:
=====================================
win/_base.sh
=====================================
@@ -12,7 +12,7 @@ cd "${DIR}"
# CONFIG START
MAJOR_PY_VERSION="3"
-MINOR_PY_VERSION="9"
+MINOR_PY_VERSION="10"
PYTHON_VERSION="${MAJOR_PY_VERSION}.${MINOR_PY_VERSION}"
BUILD_VERSION="0"
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/53ebe405880d6d75d4568d1896236ec6…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/53ebe405880d6d75d4568d1896236ec6…
You're receiving this email because of your account on dev.gajim.org.