From: Christian Heller Date: Tue, 9 Dec 2025 17:31:39 +0000 (+0100) Subject: Add most basic nickname autocompletion. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/static/%7B%7Bprefix%7D%7D/conditions?a=commitdiff_plain;ds=inline;p=ircplom Add most basic nickname autocompletion. --- diff --git a/src/ircplom/client_tui.py b/src/ircplom/client_tui.py index 323e29d..18c9be6 100644 --- a/src/ircplom/client_tui.py +++ b/src/ircplom/client_tui.py @@ -431,13 +431,24 @@ class _ClientWindowsManager: else _QueryWindow), get_nick_data=lambda: (self.db.users['me'].nick if 'me' in self.db.users.keys() - else '?')) + else '?'), + get_completables=lambda: self._get_chat_usernames(title)) else: - win = self._tui_new_window(path_logs=self._path_logs, win_cls=( - _ServerWindow if scope == _LogScope.SERVER else _DebugWindow)) + win = self._tui_new_window( + path_logs=self._path_logs, + win_cls=(_ServerWindow if scope == _LogScope.SERVER + else _DebugWindow)) self.windows += [win] return win + def _get_chat_usernames(self, title: str) -> tuple[str, ...]: + if not self.db.is_chan_name(title): + return (title,) + if title not in self.db.channels.keys(): # ChannelWindow may call for + return tuple() # channel we're atm not in + return tuple(sorted([self.db.users[user_id].nick + for user_id in self.db.channels[title].user_ids])) + def windows_for(self, scope: _LogScope, id_='') -> list[_ClientWindow]: 'Return client windows of scope, and additional potential identifier.' ret = [] diff --git a/src/ircplom/tui_base.py b/src/ircplom/tui_base.py index a44d4f7..07d51c3 100644 --- a/src/ircplom/tui_base.py +++ b/src/ircplom/tui_base.py @@ -52,6 +52,7 @@ _KEYBINDINGS = { 'esc:91:49:59:51:68': ('window', 'left'), 'esc:91:49:59:51:67': ('window', 'right'), 'KEY_F1': ('window.paste',), + 'KEY_TAB': ('window.prompt.autocomplete',), } CMD_SHORTCUTS: dict[str, str] = {} @@ -506,7 +507,11 @@ class PromptWidget(_ScrollableWidget): _input_buffer_unsafe: str _cursor_x: int - def __init__(self, **kwargs) -> None: + def __init__(self, + get_completables: Callable[[], tuple[str, ...]] = tuple, + **kwargs + ) -> None: + self._get_completables = get_completables super().__init__(**kwargs) self._reset_buffer('') @@ -599,6 +604,21 @@ class PromptWidget(_ScrollableWidget): self._archive_prompt() # empties .input_buffer, thus use to_return return to_return + def cmd__autocomplete(self) -> None: + 'Insert completion of current (space-separated) word if available.' + start_x = self._cursor_x + while start_x > 0 and self.input_buffer[start_x - 1] != ' ': + start_x -= 1 + word_start = self.input_buffer[start_x:self._cursor_x] + options = tuple(word for word in self._get_completables() + if word.startswith(word_start)) + if len(options) == 1: + to_insert = options[0][len(word_start):] + if self.input_buffer[self._cursor_x: + self._cursor_x + 1] not in ('', ' '): + to_insert += ' ' + self.insert(to_insert) + class _StatusLine(_WidgetAtom): @@ -645,6 +665,7 @@ class Window(_Widget): write: Callable[[int, str | StylingString], None], len_to_term: Callable[[str], int], maxlen_log: int, + get_completables: Callable[[], tuple[str, ...]] = tuple, **kwargs ) -> None: super().__init__(**kwargs) @@ -653,7 +674,9 @@ class Window(_Widget): self.history = _HistoryWidget(maxlen_log=maxlen_log, len_to_term=len_to_term, write=self._write) - self.prompt = self.__annotations__['prompt'](write=self._write) + self.prompt = self.__annotations__['prompt']( + write=self._write, + get_completables=get_completables) def ensure_date(self, today: str) -> None: 'Log date of today if it has not been logged yet.' diff --git a/src/tests/lib/enter_misc b/src/tests/lib/enter_misc index 0960960..37c751e 100644 --- a/src/tests/lib/enter_misc +++ b/src/tests/lib/enter_misc @@ -9,6 +9,7 @@ log 0 # /quit log 0 # /window TOWARDS log 0 # /window.history.scroll DIRECTION log 0 # /window.paste +log 0 # /window.prompt.autocomplete log 0 # /window.prompt.backspace log 0 # /window.prompt.move_cursor DIRECTION log 0 # /window.prompt.scroll DIRECTION diff --git a/src/tests/test.test b/src/tests/test.test index b747218..235dd5d 100644 --- a/src/tests/test.test +++ b/src/tests/test.test @@ -8,6 +8,8 @@ insert ./lib/disconnect # for: disconnect0, disconnect1 insert ./lib/disconnect-to-stop-auto-reconnect insert ./lib/enter-list-start +insert ./lib/enter_misc +# for: enter-help-win0 insert ./lib/isupport-clear insert ./lib/join-empty # for: join-channel-0-cmd-to-list-residents, join-channel-1-end-of-names @@ -192,29 +194,24 @@ log 0 # 1) foo.bar.baz:debug log 0 # 2) foo.bar.baz:server log 0 # 3) foo.bar.baz/SaslServ > /window 1 -> /help -log 1 # commands available in this window: -log 1 # /connect HOST_PORT [NICKNAME_PW] [REALNAME_USERNAME] +insert enter-help-win0 range=:3 [% log%0%=log%1%] log 1 # /disconnect [QUIT_MSG] -log 1 # /help +insert enter-help-win0 range=3:4 [% log%0%=log%1%] log 1 # /join CHANNEL -log 1 # /list +insert enter-help-win0 range=4:5 [% log%0%=log%1%] log 1 # /nick NEW_NICK log 1 # /privmsg TARGET MSG -log 1 # /prompt_enter -log 1 # /quit +insert enter-help-win0 range=5:7 [% log%0%=log%1%] log 1 # /raw VERB [PARAMS_STR] log 1 # /reconnect -log 1 # /window TOWARDS +insert enter-help-win0 range=7:8 [% log%0%=log%1%] log 1 # /window.disconnect [QUIT_MSG] -log 1 # /window.history.scroll DIRECTION +insert enter-help-win0 range=8:9 [% log%0%=log%1%] log 1 # /window.join CHANNEL log 1 # /window.nick NEW_NICK -log 1 # /window.paste +insert enter-help-win0 range=9:10 [% log%0%=log%1%] log 1 # /window.privmsg TARGET MSG -log 1 # /window.prompt.backspace -log 1 # /window.prompt.move_cursor DIRECTION -log 1 # /window.prompt.scroll DIRECTION +insert enter-help-win0 range=10: [% log%0%=log%1%] log 1 # /window.raw VERB [PARAMS_STR] log 1 # /window.reconnect diff --git a/src/tests/tui_draw.test b/src/tests/tui_draw.test index 6947ed6..727d753 100644 --- a/src/tests/tui_draw.test +++ b/src/tests/tui_draw.test @@ -102,17 +102,17 @@ insert line-tui-log bump=8 [% ?=%%/quit§§] insert line-tui-log bump=9 [% ?=%%/window%TOWARDS§§] insert line-tui-log bump=10 [% ?=%%/window.history.scroll%DIRECTION§§] insert line-tui-log bump=11 [% ?=%%/window.paste] -insert line-tui-log bump=12 [% ?=%%/window.prompt.backspace§§] -insert line-tui-log bump=13 [% ?=%%/window.prompt.move_cursor%DIRECTION§§] -insert line-tui-log bump=14 [% ?=%%/window.prompt.scroll%DIRECTION§§] -insert line-invalid-prompt-command-unknown bump=15 [(CMD)=0] -insert line-invalid-prompt-command-unknown bump=16 [(CMD)=1] -insert line-invalid-prompt-command-unknown bump=17 [(CMD)=2] -insert line-invalid-prompt-command-unknown bump=18 [(CMD)=3] -insert line-invalid-prompt-command-unknown bump=19 [(CMD)=4] -insert line-invalid-prompt-command-unknown bump=20 [(CMD)=5] -insert line-invalid-prompt-command-unknown bump=21 [(CMD)=6] -insert line-invalid-prompt-command-unknown bump=22 [(CMD)=7] +insert line-tui-log bump=12 [% ?=%%/window.prompt.autocomplete§§] +insert line-tui-log bump=13 [% ?=%%/window.prompt.backspace§§] +insert line-tui-log bump=14 [% ?=%%/window.prompt.move_cursor%DIRECTION§§] +insert line-tui-log bump=15 [% ?=%%/window.prompt.scroll%DIRECTION§§] +insert line-invalid-prompt-command-unknown bump=16 [(CMD)=0] +insert line-invalid-prompt-command-unknown bump=17 [(CMD)=1] +insert line-invalid-prompt-command-unknown bump=18 [(CMD)=2] +insert line-invalid-prompt-command-unknown bump=19 [(CMD)=3] +insert line-invalid-prompt-command-unknown bump=20 [(CMD)=4] +insert line-invalid-prompt-command-unknown bump=21 [(CMD)=5] +insert line-invalid-prompt-command-unknown bump=22 [(CMD)=6] insert line-invalid-prompt-command-unknown bump=23 [(CMD)=foo_0123456789_0123456789_0123456789] insert line-invalid-prompt-command bump=24 [(MSG)=/foo_0123456789_0123456789_0123456789_§§] insert line-bright-red-bold bump=25 [% ?=%%%unknown] @@ -237,32 +237,32 @@ insert lines-status-prompt-start [(FOCUS_X)=77 (FOCUS_STR)=0 X123456789X12345678 insert enter-help-win0 insert lines-empty range=:20 insert history_0 range=:1 bump=20 -insert line-scrolldown bump=21 [% XXXXXX=[14]%v] -insert lines-status-prompt-start [(FOCUS_X)=72 (FOCUS_STR)=(0:12) X123456789X123456789X=============(§§§§§§§§] +insert line-scrolldown bump=21 [% XXXXXX=[15]%v] +insert lines-status-prompt-start [(FOCUS_X)=72 (FOCUS_STR)=(0:13) X123456789X123456789X=============(§§§§§§§§] # check scroll-down on newer history longer than half a screen width does not fully land at bottom > /window.history.scroll down insert lines-empty range=:9 insert history_0 range=:12 bump=9 -insert line-scrolldown bump=21 [% XXXXXX=[3]%vv] -insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:3) X123456789X123456789X==============(§§§§§§§] +insert line-scrolldown bump=21 [% XXXXXX=[4]%vv] +insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:4) X123456789X123456789X==============(§§§§§§§] # check previous scroll-down not hitting bottom be fully reversible > /window.history.scroll up insert lines-empty range=:20 insert history_0 range=:1 bump=20 -insert line-scrolldown bump=21 [% XXXXXX=[14]%v] -insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:3) X123456789X123456789X==============(§§§§§§§] +insert line-scrolldown bump=21 [% XXXXXX=[15]%v] +insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:4) X123456789X123456789X==============(§§§§§§§] > /window.history.scroll down insert lines-empty range=:9 insert history_0 range=:12 bump=9 -insert line-scrolldown bump=21 [% XXXXXX=[3]%vv] -insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:3) X123456789X123456789X==============(§§§§§§§] +insert line-scrolldown bump=21 [% XXXXXX=[4]%vv] +insert lines-status-prompt-start [(FOCUS_X)=73 (FOCUS_STR)=(0:4) X123456789X123456789X==============(§§§§§§§] # scroll to bottom, check history still growing up even beyond upper fold > /window.history.scroll down -insert lines-empty range=:7 -insert history_0 range=:15 bump=7 +insert lines-empty range=:6 +insert history_0 range=:16 bump=6 insert lines-status-prompt-start [(FOCUS_X)=77 (FOCUS_STR)=0 X123456789X123456789X==================(§§§] insert enter-unknown [?=0] insert enter-unknown [?=1] @@ -271,7 +271,6 @@ insert enter-unknown [?=3] insert enter-unknown [?=4] insert enter-unknown [?=5] insert enter-unknown [?=6] -insert enter-unknown [?=7] insert history_0 range=1:23 bump=0 insert lines-status-prompt-start [(FOCUS_X)=77 (FOCUS_STR)=0 X123456789X123456789X==================(§§§]