From e88793bff6bc7a9b094482b5a55ec9b12858b57d Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Sun, 3 May 2020 19:04:15 +0300 Subject: [PATCH] added gg, 4j, 3k keybinding support --- tg/controllers/__init__.py | 17 ++++++++---- tg/models/__init__.py | 56 ++++++++++++++++++++------------------ tg/utils.py | 7 +++++ tg/views/__init__.py | 38 +++++++++++++++++--------- 4 files changed, 72 insertions(+), 46 deletions(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index 34298cb..d99bb8f 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -35,7 +35,7 @@ class Controller: while True: - key = self.view.get_key(self.view.chats.h, self.view.chats.w) + repeat_factor, key = self.view.get_key(self.view.chats.h, self.view.chats.w) log.info('Pressed key: %s', key) if key == 'q': return 'QUIT' @@ -52,10 +52,10 @@ class Controller: if self.model.jump_prev_msg(): self.refresh_msgs() elif key in ('j', '^B'): - if self.model.next_msg(): + if self.model.next_msg(repeat_factor): self.refresh_msgs() elif key in ('k', '^C'): - if self.model.prev_msg(): + if self.model.prev_msg(repeat_factor): self.refresh_msgs() elif key == 'G': if self.model.jump_bottom(): @@ -99,7 +99,7 @@ class Controller: self.refresh_chats() while True: - key = self.view.get_key(self.view.chats.h, self.view.chats.w) + repeat_factor, key = self.view.get_key(self.view.chats.h, self.view.chats.w) log.info('Pressed key: %s', key) if key == 'q': return @@ -112,12 +112,17 @@ class Controller: self.refresh_chats() elif key in ('j', '^B'): - is_changed = self.model.next_chat() + is_changed = self.model.next_chat(repeat_factor) if is_changed: self.refresh_chats() elif key in ('k', '^C'): - is_changed = self.model.prev_chat() + is_changed = self.model.prev_chat(repeat_factor) + if is_changed: + self.refresh_chats() + + elif key == 'gg': + is_changed = self.model.first_chat() if is_changed: self.refresh_chats() diff --git a/tg/models/__init__.py b/tg/models/__init__.py index 5578586..58e61d7 100644 --- a/tg/models/__init__.py +++ b/tg/models/__init__.py @@ -33,25 +33,32 @@ class Model: chat_id = self.chats.chat_ids[self.current_chat] return self.msgs.jump_bottom(chat_id) - def next_chat(self): - if self.current_chat < len(self.chats.chats): - self.current_chat += 1 + def next_chat(self, step=1): + new_idx = self.current_chat + step + if new_idx < len(self.chats.chats): + self.current_chat = new_idx return True return False - def prev_chat(self): - if self.current_chat > 0: - self.current_chat -= 1 + def prev_chat(self, step=1): + if self.current_chat == 0: + return False + self.current_chat = max(0, self.current_chat - step) + return True + + def first_chat(self): + if self.current_chat != 0: + self.current_chat = 0 return True return False - def next_msg(self): + def next_msg(self, step=1): chat_id = self.chats.chat_ids[self.current_chat] - return self.msgs.next_msg(chat_id) + return self.msgs.next_msg(chat_id, step) - def prev_msg(self): + def prev_msg(self, step=1): chat_id = self.chats.chat_ids[self.current_chat] - return self.msgs.prev_msg(chat_id) + return self.msgs.prev_msg(chat_id, step) def jump_next_msg(self): chat_id = self.chats.chat_ids[self.current_chat] @@ -156,11 +163,12 @@ class MsgModel: self.msgs = defaultdict(list) # Dict[int, list] self.current_msgs = defaultdict(int) - def next_msg(self, chat_id): - if self.current_msgs[chat_id] > 0: - self.current_msgs[chat_id] -= 1 - return True - return False + def next_msg(self, chat_id, step=1): + current_msgs = self.current_msgs[chat_id] + if current_msgs == 0: + return False + self.current_msgs[chat_id] = max(0, current_msgs - step) + return True def jump_bottom(self, chat_id): if self.current_msgs[chat_id] == 0: @@ -169,21 +177,15 @@ class MsgModel: return True def jump_next_msg(self, chat_id): - if self.current_msgs[chat_id] - 10 > 0: - self.current_msgs[chat_id] -= 10 - else: - self.current_msgs[chat_id] = 0 - return True + return self.next_msg(chat_id, step=10) def jump_prev_msg(self, chat_id): - if self.current_msgs[chat_id] + 10 < len(self.msgs[chat_id]): - self.current_msgs[chat_id] += 10 - return True - return False + return self.prev_msg(chat_id, step=10) - def prev_msg(self, chat_id): - if self.current_msgs[chat_id] < len(self.msgs[chat_id]): - self.current_msgs[chat_id] += 1 + def prev_msg(self, chat_id, step=1): + new_idx = self.current_msgs[chat_id] + step + if new_idx < len(self.msgs[chat_id]): + self.current_msgs[chat_id] = new_idx return True return False diff --git a/tg/utils.py b/tg/utils.py index c95310a..ad196bb 100644 --- a/tg/utils.py +++ b/tg/utils.py @@ -4,6 +4,13 @@ import os log = logging.getLogger(__name__) +def num(value, default=None): + try: + return int(value) + except ValueError: + return default + + def notify(msg, subtitle='New message', title='Telegram'): msg = '-message {!r}'.format(msg) subtitle = '-subtitle {!r}'.format(subtitle) diff --git a/tg/views/__init__.py b/tg/views/__init__.py index e026e98..295bf5a 100644 --- a/tg/views/__init__.py +++ b/tg/views/__init__.py @@ -4,8 +4,13 @@ import math import re from datetime import datetime +from utils import num + log = logging.getLogger(__name__) +MAX_KEYBINDING_LENGTH = 5 +MULTICHAR_KEYBINDINGS = ("gg",) + class View: @@ -49,21 +54,28 @@ class View: self.msgs.draw(current, msgs) def get_key(self, y, x): - # return self.stdscr.getkey() + keys = repeat_factor = '' - ch = self.stdscr.getch(y, x) - log.info('raw ch without unctrl: %s', ch) - try: - return curses.unctrl(ch).decode() - except UnicodeDecodeError: - log.warning('cant uncrtl: %s', ch) - return 'UNKNOWN' + for _ in range(MAX_KEYBINDING_LENGTH): + ch = self.stdscr.getch(y, x) + log.info('raw ch without unctrl: %s', ch) + try: + key = curses.unctrl(ch).decode() + except UnicodeDecodeError: + log.warning('cant uncrtl: %s', ch) + break + if key.isdigit(): + repeat_factor += key + continue + keys += key + # if match found or there are not any shortcut matches at all + if all( + p == keys or not p.startswith(keys) + for p in MULTICHAR_KEYBINDINGS + ): + break - def get_key_input(self, y, x): - ch = self.msgs.win.getch(y, x) - log.info('raw ch without unctrl in msgs: %s', ch) - return ch - # return curses.unctrl(ch).decode() + return num(repeat_factor, default=1), keys or 'UNKNOWN' def get_input(self): return self.status.get_input()