Allow using the ask kitten to pick a choice
This commit is contained in:
parent
5737904cec
commit
437efe5473
@ -13,7 +13,8 @@ from kitty.constants import cache_dir
|
|||||||
from kitty.typing import BossType
|
from kitty.typing import BossType
|
||||||
|
|
||||||
from ..tui.handler import result_handler
|
from ..tui.handler import result_handler
|
||||||
from ..tui.operations import alternate_screen, set_cursor_visible, styled
|
from ..tui.operations import alternate_screen, styled
|
||||||
|
from ..tui.utils import get_key_press
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import readline
|
import readline
|
||||||
@ -70,7 +71,7 @@ class HistoryCompleter:
|
|||||||
def option_text() -> str:
|
def option_text() -> str:
|
||||||
return '''\
|
return '''\
|
||||||
--type -t
|
--type -t
|
||||||
choices=line,yesno
|
choices=line,yesno,choices
|
||||||
default=line
|
default=line
|
||||||
Type of input. Defaults to asking for a line of text.
|
Type of input. Defaults to asking for a line of text.
|
||||||
|
|
||||||
@ -83,6 +84,16 @@ message is shown.
|
|||||||
--name -n
|
--name -n
|
||||||
The name for this question. Used to store history of previous answers which can
|
The name for this question. Used to store history of previous answers which can
|
||||||
be used for completions and via the browse history readline bindings.
|
be used for completions and via the browse history readline bindings.
|
||||||
|
|
||||||
|
|
||||||
|
--choice -c
|
||||||
|
type=list
|
||||||
|
dest=choices
|
||||||
|
A choice for the choices type. Every choice has the syntax: letter:text Where
|
||||||
|
letter is the accelerator key and text is the corresponding text. There can be
|
||||||
|
an optional color specification after the letter to indicate what color it should
|
||||||
|
be.
|
||||||
|
For example: y:Yes and n;red:No
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@ -97,23 +108,34 @@ class Response(TypedDict):
|
|||||||
response: Optional[str]
|
response: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
def choice(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||||
import tty
|
|
||||||
with alternate_screen():
|
with alternate_screen():
|
||||||
if cli_opts.message:
|
if cli_opts.message:
|
||||||
print(styled(cli_opts.message, bold=True))
|
print(styled(cli_opts.message, bold=True))
|
||||||
print()
|
print()
|
||||||
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o', set_cursor_visible(False))
|
allowed = ''
|
||||||
sys.stdout.flush()
|
for choice in cli_opts.choices:
|
||||||
tty.setraw(sys.stdin.fileno())
|
color = 'green'
|
||||||
try:
|
letter, text = choice.split(':', maxsplit=1)
|
||||||
response = sys.stdin.buffer.read(1)
|
if ';' in letter:
|
||||||
yes = response in (b'y', b'Y', b'\r', b'\n', b' ')
|
letter, color = letter.split(';', maxsplit=1)
|
||||||
return {'items': items, 'response': 'y' if yes else 'n'}
|
letter = letter.lower()
|
||||||
finally:
|
idx = text.lower().index(letter)
|
||||||
sys.stdout.write(set_cursor_visible(True))
|
allowed += letter
|
||||||
tty.setcbreak(sys.stdin.fileno())
|
print(text[:idx], styled(text[idx], fg=color), text[idx:], sep='', end=' ')
|
||||||
sys.stdout.flush()
|
print()
|
||||||
|
response = get_key_press(allowed, '')
|
||||||
|
return {'items': items, 'response': response}
|
||||||
|
|
||||||
|
|
||||||
|
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||||
|
with alternate_screen():
|
||||||
|
if cli_opts.message:
|
||||||
|
print(styled(cli_opts.message, bold=True))
|
||||||
|
print()
|
||||||
|
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o')
|
||||||
|
response = get_key_press('yn', 'n')
|
||||||
|
return {'items': items, 'response': response}
|
||||||
|
|
||||||
|
|
||||||
def main(args: List[str]) -> Response:
|
def main(args: List[str]) -> Response:
|
||||||
@ -132,6 +154,8 @@ def main(args: List[str]) -> Response:
|
|||||||
|
|
||||||
if cli_opts.type == 'yesno':
|
if cli_opts.type == 'yesno':
|
||||||
return yesno(cli_opts, items)
|
return yesno(cli_opts, items)
|
||||||
|
if cli_opts.type == 'choices':
|
||||||
|
return choice(cli_opts, items)
|
||||||
|
|
||||||
import readline as rl
|
import readline as rl
|
||||||
readline = rl
|
readline = rl
|
||||||
|
|||||||
@ -11,43 +11,27 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
from contextlib import suppress
|
|
||||||
from typing import Any, List, Optional
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
from kitty.cli import parse_args
|
from kitty.cli import parse_args
|
||||||
from kitty.cli_stub import RemoteFileCLIOptions
|
from kitty.cli_stub import RemoteFileCLIOptions
|
||||||
from kitty.constants import cache_dir
|
from kitty.constants import cache_dir
|
||||||
from kitty.typing import BossType
|
from kitty.typing import BossType
|
||||||
from kitty.utils import command_for_open, get_editor, open_cmd, SSHConnectionData
|
from kitty.utils import (
|
||||||
|
SSHConnectionData, command_for_open, get_editor, open_cmd
|
||||||
|
)
|
||||||
|
|
||||||
from ..tui.handler import result_handler
|
from ..tui.handler import result_handler
|
||||||
from ..tui.operations import (
|
from ..tui.operations import (
|
||||||
faint, raw_mode, reset_terminal, set_cursor_visible, styled
|
faint, raw_mode, reset_terminal, styled
|
||||||
)
|
)
|
||||||
|
from ..tui.utils import get_key_press
|
||||||
|
|
||||||
|
|
||||||
def key(x: str) -> str:
|
def key(x: str) -> str:
|
||||||
return styled(x, bold=True, fg='green')
|
return styled(x, bold=True, fg='green')
|
||||||
|
|
||||||
|
|
||||||
def get_key_press(allowed: str, default: str) -> str:
|
|
||||||
response = default
|
|
||||||
with raw_mode():
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
q = sys.stdin.buffer.read(1)
|
|
||||||
if q:
|
|
||||||
if q in b'\x1b\x03':
|
|
||||||
break
|
|
||||||
with suppress(Exception):
|
|
||||||
response = q.decode('utf-8').lower()
|
|
||||||
if response in allowed:
|
|
||||||
break
|
|
||||||
except (KeyboardInterrupt, EOFError):
|
|
||||||
pass
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def option_text() -> str:
|
def option_text() -> str:
|
||||||
return '''\
|
return '''\
|
||||||
--mode -m
|
--mode -m
|
||||||
@ -194,7 +178,6 @@ def main(args: List[str]) -> Result:
|
|||||||
input('Press enter to quit...')
|
input('Press enter to quit...')
|
||||||
raise SystemExit(e.code)
|
raise SystemExit(e.code)
|
||||||
|
|
||||||
print(set_cursor_visible(False), end='', flush=True)
|
|
||||||
try:
|
try:
|
||||||
action = ask_action(cli_opts)
|
action = ask_action(cli_opts)
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
29
kittens/tui/utils.py
Normal file
29
kittens/tui/utils.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from contextlib import suppress
|
||||||
|
|
||||||
|
from .operations import raw_mode, set_cursor_visible
|
||||||
|
|
||||||
|
|
||||||
|
def get_key_press(allowed: str, default: str) -> str:
|
||||||
|
response = default
|
||||||
|
with raw_mode():
|
||||||
|
print(set_cursor_visible(False), end='', flush=True)
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
q = sys.stdin.buffer.read(1)
|
||||||
|
if q:
|
||||||
|
if q in b'\x1b\x03':
|
||||||
|
break
|
||||||
|
with suppress(Exception):
|
||||||
|
response = q.decode('utf-8').lower()
|
||||||
|
if response in allowed:
|
||||||
|
break
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
print(set_cursor_visible(True), end='', flush=True)
|
||||||
|
return response
|
||||||
Loading…
x
Reference in New Issue
Block a user