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
3 changed files with 48 additions and 20 deletions

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ import tty
from collections import namedtuple from collections import namedtuple
from contextlib import closing, contextmanager from contextlib import closing, contextmanager
from functools import partial from functools import partial
from queue import Empty, Queue
from kitty.fast_data_types import parse_input_from_terminal, safe_pipe from kitty.fast_data_types import parse_input_from_terminal, safe_pipe
from kitty.icat import screen_size from kitty.icat import screen_size
@@ -24,7 +25,7 @@ from kitty.key_encoding import (
) )
from .handler import Handler 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): def log(*a, **kw):
@@ -120,8 +121,8 @@ class UnhandledException(Handler):
def __init__(self, tb): def __init__(self, tb):
self.tb = tb self.tb = tb
def initialize(self, screen_size, quit_loop, wakeup): def initialize(self, *args):
Handler.initialize(self, screen_size, quit_loop, wakeup) Handler.initialize(self, *args)
self.write(clear_screen()) self.write(clear_screen())
self.write(self.tb.replace('\n', '\r\n')) self.write(self.tb.replace('\n', '\r\n'))
self.write('\r\n') self.write('\r\n')
@@ -167,6 +168,24 @@ class Loop:
self.sanitize_bracketed_paste = bool(sanitize_bracketed_paste) self.sanitize_bracketed_paste = bool(sanitize_bracketed_paste)
if self.sanitize_bracketed_paste: if self.sanitize_bracketed_paste:
self.sanitize_ibp_pat = re.compile(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): def _read_ready(self, handler):
if not self.read_allowed: if not self.read_allowed:
@@ -283,6 +302,15 @@ class Loop:
handler.on_term() handler.on_term()
if b'i' in data: if b'i' in data:
handler.on_interrupt() 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: if b'1' in data:
handler.on_wakeup() handler.on_wakeup()
@@ -331,7 +359,7 @@ class Loop:
handler._term_manager = term_manager handler._term_manager = term_manager
keep_going = True keep_going = True
try: try:
handler.initialize(screen_size(), self.quit, self.wakeup) handler.initialize(screen_size(), self.quit, self.wakeup, self.start_job)
except Exception: except Exception:
import traceback import traceback
tb = traceback.format_exc() tb = traceback.format_exc()
@@ -363,7 +391,7 @@ class Loop:
handler = UnhandledException(tb) handler = UnhandledException(tb)
handler.write_buf = [] handler.write_buf = []
handler._term_manager = term_manager 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: while True:
has_data_to_write = bool(handler.write_buf) has_data_to_write = bool(handler.write_buf)
if not has_data_to_write and not self.read_allowed: if not has_data_to_write and not self.read_allowed: