Work on themes kitten UI

This commit is contained in:
Kovid Goyal 2021-08-03 17:32:15 +05:30
parent 37c563802c
commit a402d848d2
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 123 additions and 3 deletions

View File

@ -42,7 +42,7 @@ def fetch_themes(
if m.etag: if m.etag:
rq.add_header('If-None-Match', m.etag) rq.add_header('If-None-Match', m.etag)
try: try:
res = urlopen(rq) res = urlopen(rq, timeout=30)
except HTTPError as e: except HTTPError as e:
if m.etag and e.code == http.HTTPStatus.NOT_MODIFIED: if m.etag and e.code == http.HTTPStatus.NOT_MODIFIED:
return dest_path return dest_path
@ -60,7 +60,7 @@ def zip_file_loader(path_to_zip: str, theme_file_name: str, file_name: str) -> C
name = os.path.join(os.path.dirname(theme_file_name), file_name) name = os.path.join(os.path.dirname(theme_file_name), file_name)
def zip_loader() -> str: def zip_loader() -> str:
with zipfile.ZipFile(path_to_zip, 'r') as zf, zf.open(name, 'rb') as f: with zipfile.ZipFile(path_to_zip, 'r') as zf, zf.open(name) as f:
return f.read().decode('utf-8') return f.read().decode('utf-8')
return zip_loader return zip_loader
@ -176,7 +176,7 @@ class Themes:
for name in zf.namelist(): for name in zf.namelist():
if os.path.basename(name) == 'themes.json': if os.path.basename(name) == 'themes.json':
theme_file_name = name theme_file_name = name
with zf.open(theme_file_name, 'rb') as f: with zf.open(theme_file_name) as f:
items = json.loads(f.read()) items = json.loads(f.read())
break break
else: else:

View File

@ -1,3 +1,123 @@
#!/usr/bin/env python #!/usr/bin/env python
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import os
import sys
import traceback
from enum import Enum, auto
from typing import List, Optional, Union
from kitty.typing import KeyEventType
from kitty.utils import ScreenSize
from ..tui.handler import Handler
from ..tui.loop import Loop
from ..tui.operations import styled
from .collection import Themes, load_themes
def format_traceback(msg: str) -> str:
return traceback.format_exc() + '\n\n' + styled(msg, fg='red')
class State(Enum):
fetching = auto()
browsing = auto()
class ThemesHandler(Handler):
def __init__(self) -> None:
self.state = State.fetching
self.report_traceback_on_exit: Optional[str] = None
def enforce_cursor_state(self) -> None:
self.cmd.set_cursor_visible(self.state == State.fetching)
def init_terminal_state(self) -> None:
self.cmd.set_line_wrapping(False)
self.cmd.set_window_title('Choose a theme for kitty')
self.cmd.set_cursor_shape('bar')
def initialize(self) -> None:
self.init_terminal_state()
self.draw_screen()
self.fetch_themes()
def finalize(self) -> None:
self.cmd.set_default_colors()
self.cmd.set_cursor_visible(True)
# Theme fetching {{{
def fetch_themes(self) -> None:
def fetching_done(themes_or_exception: Union[Themes, str]) -> None:
if isinstance(themes_or_exception, str):
self.report_traceback_on_exit = themes_or_exception
self.quit_loop(1)
return
else:
self.themes: Themes = themes_or_exception
self.state = State.browsing
self.draw_screen()
def fetch() -> None:
import time
time.sleep(15)
try:
themes: Union[Themes, str] = load_themes()
except Exception:
themes = format_traceback('Failed to download themes')
self.asyncio_loop.call_soon_threadsafe(fetching_done, themes)
self.asyncio_loop.run_in_executor(None, fetch)
self.draw_screen()
def draw_fetching_screen(self) -> None:
self.print('Downloading themes from repository, please wait...')
def on_fetching_key_event(self, key_event: KeyEventType, in_bracketed_paste: bool = False) -> None:
if key_event.matches('esc'):
self.quit_loop(0)
# }}}
def on_key_event(self, key_event: KeyEventType, in_bracketed_paste: bool = False) -> None:
if self.state is State.fetching:
self.on_fetching_key_event(key_event, in_bracketed_paste)
def draw_screen(self) -> None:
self.cmd.clear_screen()
self.enforce_cursor_state()
if self.state is State.fetching:
self.draw_fetching_screen()
def on_resize(self, screen_size: ScreenSize) -> None:
self.screen_size = screen_size
def on_interrupt(self) -> None:
self.quit_loop(1)
def on_eot(self) -> None:
self.quit_loop(1)
def main(args: List[str]) -> None:
loop = Loop()
handler = ThemesHandler()
loop.loop(handler)
if loop.return_code != 0:
if handler.report_traceback_on_exit:
print(handler.report_traceback_on_exit, file=sys.stderr)
input('Press Enter to quit.')
if handler.state is State.fetching:
# asycio uses non-daemonic threads in its ThreadPoolExecutor
# so we will hang here till the download completes without
# os._exit
os._exit(loop.return_code)
raise SystemExit(loop.return_code)
if __name__ == '__main__':
main(sys.argv)