Add threaded job infrastructure to tui

This commit is contained in:
Kovid Goyal 2018-04-20 21:12:10 +05:30
parent ea9b431386
commit 92bb6e293a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 48 additions and 20 deletions

View File

@ -7,7 +7,6 @@ import sys
import traceback
from functools import partial
from gettext import gettext as _
from threading import Thread
from kitty.cli import parse_args
from kitty.key_encoding import ESCAPE
@ -28,14 +27,7 @@ class DiffHandler(Handler):
self.report_traceback_on_exit = None
def create_collection(self):
try:
self.collection = create_collection(self.left, self.right)
except Exception:
self.report_traceback_on_exit = traceback.format_exc()
self.quit_loop(1)
else:
self.state = READY
self.wakeup()
self.start_job('diff', create_collection, self.left, self.right)
def init_terminal_state(self):
self.write(set_line_wrapping(False))
@ -45,9 +37,7 @@ class DiffHandler(Handler):
Handler.initialize(self, *args)
self.init_terminal_state()
self.draw_screen()
t = Thread(target=self.create_collection, name='CreatingCollection')
t.daemon = True
t.start()
self.create_collection()
def draw_screen(self):
if self.state is INITIALIZING:
@ -65,8 +55,14 @@ class DiffHandler(Handler):
self.quit_loop(0)
return
def on_wakeup(self):
self.draw_screen()
def on_job_done(self, job_id, job_result):
if 'tb' in job_result:
self.report_traceback_on_exit = traceback.format_exc()
self.quit_loop(1)
if job_id == 'diff':
self.collection = job_result['result']
self.state = READY
self.write(clear_screen())
def on_interrupt(self):
self.quit_loop(1)

View File

@ -5,9 +5,10 @@
class Handler:
def initialize(self, screen_size, quit_loop, wakeup):
def initialize(self, screen_size, quit_loop, wakeup, start_job):
self.screen_size, self.quit_loop = screen_size, quit_loop
self.wakeup = wakeup
self.start_job = start_job
def on_resize(self, screen_size):
self.screen_size = screen_size
@ -33,6 +34,9 @@ class Handler:
def on_wakeup(self):
pass
def on_job_done(self, job_id, job_result):
pass
def write(self, data):
if isinstance(data, str):
data = data.encode('utf-8')

View File

@ -15,6 +15,7 @@ import tty
from collections import namedtuple
from contextlib import closing, contextmanager
from functools import partial
from queue import Empty, Queue
from kitty.fast_data_types import parse_input_from_terminal, safe_pipe
from kitty.icat import screen_size
@ -24,7 +25,7 @@ from kitty.key_encoding import (
)
from .handler import Handler
from .operations import init_state, reset_state, clear_screen
from .operations import clear_screen, init_state, reset_state
def log(*a, **kw):
@ -120,8 +121,8 @@ class UnhandledException(Handler):
def __init__(self, tb):
self.tb = tb
def initialize(self, screen_size, quit_loop, wakeup):
Handler.initialize(self, screen_size, quit_loop, wakeup)
def initialize(self, *args):
Handler.initialize(self, *args)
self.write(clear_screen())
self.write(self.tb.replace('\n', '\r\n'))
self.write('\r\n')
@ -167,6 +168,24 @@ class Loop:
self.sanitize_bracketed_paste = bool(sanitize_bracketed_paste)
if self.sanitize_bracketed_paste:
self.sanitize_ibp_pat = re.compile(sanitize_bracketed_paste)
self.jobs_queue = Queue()
def start_job(self, job_id, func, *args, **kw):
from threading import Thread
t = Thread(target=partial(self._run_job, job_id, func), args=args, kwargs=kw, name='LoopJob')
t.daemon = True
t.start()
def _run_job(self, job_id, func, *args, **kw):
try:
result = func(*args, **kw)
except Exception as err:
import traceback
entry = {'id': job_id, 'exception': err, 'tb': traceback.format_exc()}
else:
entry = {'id': job_id, 'result': result}
self.jobs_queue.put(entry)
self._wakeup_write(b'j')
def _read_ready(self, handler):
if not self.read_allowed:
@ -283,6 +302,15 @@ class Loop:
handler.on_term()
if b'i' in data:
handler.on_interrupt()
if b'j' in data:
while True:
try:
entry = self.jobs_queue.get_nowait()
except Empty:
break
else:
job_id = entry.pop('id')
handler.on_job_done(job_id, entry)
if b'1' in data:
handler.on_wakeup()
@ -331,7 +359,7 @@ class Loop:
handler._term_manager = term_manager
keep_going = True
try:
handler.initialize(screen_size(), self.quit, self.wakeup)
handler.initialize(screen_size(), self.quit, self.wakeup, self.start_job)
except Exception:
import traceback
tb = traceback.format_exc()
@ -363,7 +391,7 @@ class Loop:
handler = UnhandledException(tb)
handler.write_buf = []
handler._term_manager = term_manager
handler.initialize(screen_size(), self.quit, self.wakeup)
handler.initialize(screen_size(), self.quit, self.wakeup, self.start_job)
while True:
has_data_to_write = bool(handler.write_buf)
if not has_data_to_write and not self.read_allowed: