INPUT_PROMPT = '> '
KEYBINDINGS = {
- 'KEY_BACKSPACE': ('prompt_backspace',),
+ 'KEY_BACKSPACE': ('window.prompt.backspace',),
'KEY_ENTER': ('prompt_enter',),
- 'KEY_UP': ('prompt_scroll', 'up'),
- 'KEY_DOWN': ('prompt_scroll', 'down'),
- 'KEY_PGUP': ('log_scroll', 'up'),
- 'KEY_PGDOWN': ('log_scroll', 'down'),
+ 'KEY_UP': ('window.prompt.scroll', 'up'),
+ 'KEY_DOWN': ('window.prompt.scroll', 'down'),
+ 'KEY_PGUP': ('window.log.scroll', 'up'),
+ 'KEY_PGDOWN': ('window.log.scroll', 'down'),
'[91, 49, 59, 51, 68]': ('window', 'left'),
'[91, 49, 59, 51, 67]': ('window', 'right'),
}
def _scroll(self, up=True) -> None:
pass
- def scroll(self, up=True) -> None:
+ def cmd__scroll(self, direction: str) -> None:
'Scroll through stored content/history.'
- self._scroll(up)
+ self._scroll(up=direction == 'up')
self.draw()
self._input_buffer = self._history[self._history_idx][:]
self.draw()
- def backspace(self) -> None:
+ def cmd__backspace(self) -> None:
'Truncate current content by one character, if possible.'
self._input_buffer = self._input_buffer[:-1]
self._history_idx = 0
self._term.flush()
super().__init__(*args, **kwargs)
+ def _cmd_name_to_cmd(self, cmd_name: str) -> Optional[Callable]:
+ cmd_parent = self
+ while True:
+ cmd_name_toks = cmd_name.split('.', maxsplit=1)
+ if len(cmd_name_toks) == 1:
+ break
+ if not hasattr(cmd_parent, cmd_name_toks[0]):
+ return None
+ cmd_parent = getattr(cmd_parent, cmd_name_toks[0])
+ cmd_name = cmd_name_toks[1]
+ cmd_name = f'cmd__{cmd_name}'
+ if not hasattr(cmd_parent, cmd_name):
+ return None
+ return getattr(cmd_parent, cmd_name)
+
def process_main(self, event: Event) -> bool:
if not super().process_main(event):
return False
self._windows[1].log.append(f'<- {event.payload.raw}')
elif event.type_ == 'SEND':
self._windows[1].log.append(f'-> {event.payload.raw}')
- self._window.log.draw()
+ self.window.log.draw()
elif event.type_ == 'KEYBINDING':
- getattr(self, f'_cmd__{event.payload[0]}')(*event.payload[1:])
+ cmd = self._cmd_name_to_cmd(event.payload[0])
+ assert cmd is not None
+ cmd(*event.payload[1:])
elif event.type_ == 'INPUT_CHAR':
- self._window.prompt.append(event.payload)
+ self.window.prompt.append(event.payload)
elif event.type_ == 'SIGWINCH':
self._calc_and_draw_all()
# elif event.type_ == 'DEBUG':
# from traceback import format_exception
# for line in '\n'.join(format_exception(event.payload)
# ).split('\n'):
- # self._window.log.append(f'DEBUG {line}')
- # self._window.log.draw()
+ # self.window.log.append(f'DEBUG {line}')
+ # self.window.log.draw()
else:
return True
self._term.flush()
return True
@property
- def _window(self) -> Window:
+ def window(self) -> Window:
+ 'Currently selected Window.'
return self._windows[self._window_idx]
def _calc_and_draw_all(self) -> None:
self._term.write_yx(YX(y_prompt, 0), INPUT_PROMPT)
for window in self._windows:
window.set_geometry((y_separator, y_prompt))
- self._window.draw()
+ self.window.draw()
- def _cmd__prompt_backspace(self) -> None:
- self._window.prompt.backspace()
+ def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
+ 'Send QUIT command to server.'
+ self.broadcast('SEND', IrcMessage('QUIT', [quit_msg]))
- def _cmd__prompt_enter(self) -> None:
- to_parse = self._window.prompt.enter()
+ def cmd__prompt_enter(self) -> None:
+ 'Get prompt content from .window.prompt.enter, parse to & run command.'
+ to_parse = self.window.prompt.enter()
if not to_parse:
return
alert: Optional[str] = None
if to_parse[0:1] == '/':
toks = to_parse[1:].split(maxsplit=1)
- method_name = f'_cmd__{toks[0]}'
alert = f'{toks[0]} unknown'
- if hasattr(self, method_name)\
- and method_name != stack()[0].function:
- method = getattr(self, method_name)
- params = signature(method).parameters
+ cmd_name = toks[0]
+ cmd = self._cmd_name_to_cmd(cmd_name)
+ if cmd and cmd.__name__ != stack()[0].function:
+ params = signature(cmd).parameters
n_args_max = len(params)
n_args_min = len([p for p in params.values()
if p.default == inspect_empty])
alert = f'{toks[0]} needs {n_args_min} - {n_args_max} args'
if len(toks) == 1 and not n_args_min:
- alert = method()
+ alert = cmd()
elif len(toks) > 1 and params\
and n_args_min <= len(toks[1].split()):
args = []
toks = toks[1].split(maxsplit=1)
args += [toks[0]]
n_args_max -= 1
- alert = method(*args)
+ alert = cmd(*args)
else:
alert = 'not prefixed by /'
if alert:
self.broadcast('ALERT', f'invalid prompt command: {alert}')
- def _cmd__prompt_scroll(self, direction: str) -> None:
- self._window.prompt.scroll(up=direction == 'up')
-
- def _cmd__log_scroll(self, direction: str) -> None:
- self._window.log.scroll(up=direction == 'up')
-
- def _cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
- self.broadcast('SEND', IrcMessage('QUIT', [quit_msg]))
-
- def _cmd__quit(self) -> None:
+ def cmd__quit(self) -> None:
+ 'Send QUIT to all threads.'
self.broadcast('QUIT')
- def _cmd__window(self, towards: str) -> Optional[str]:
+ def cmd__window(self, towards: str) -> Optional[str]:
+ 'Switch window selection.'
n_windows = len(self._windows)
if n_windows < 2:
return 'no alternate window to move into'
if not 0 <= window_idx < n_windows:
return f'unavailable window idx: {window_idx}'
self._window_idx = window_idx
- self._window.draw()
+ self.window.draw()
return None