Coding style.
- Since there is only one display, appearance_changed_event can be a module level global in fill3. - Remove all the appearance_changed_event plumbing.
This commit is contained in:
parent
71b9da128b
commit
4150a9a250
5 changed files with 55 additions and 76 deletions
|
|
@ -340,7 +340,7 @@ class Summary:
|
||||||
if y >= len(self._entries):
|
if y >= len(self._entries):
|
||||||
self._cursor_position = (x, len(self._entries) - 1)
|
self._cursor_position = (x, len(self._entries) - 1)
|
||||||
|
|
||||||
async def sync_with_filesystem(self, appearance_changed_event, log=None):
|
async def sync_with_filesystem(self, log=None):
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
cache = {}
|
cache = {}
|
||||||
log.log_message("Started loading summary…")
|
log.log_message("Started loading summary…")
|
||||||
|
|
@ -350,7 +350,7 @@ class Summary:
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
self.add_entry(entry)
|
self.add_entry(entry)
|
||||||
if index % 1000 == 0:
|
if index % 1000 == 0:
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
cache[entry.path] = entry.change_time
|
cache[entry.path] = entry.change_time
|
||||||
duration = time.time() - start_time
|
duration = time.time() - start_time
|
||||||
log.log_message(f"Finished loading summary. {round(duration, 2)} secs")
|
log.log_message(f"Finished loading summary. {round(duration, 2)} secs")
|
||||||
|
|
@ -371,7 +371,7 @@ class Summary:
|
||||||
entry.change_time = change_time
|
entry.change_time = change_time
|
||||||
else:
|
else:
|
||||||
self.on_file_added(path)
|
self.on_file_added(path)
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
for path in cache.keys() - all_paths:
|
for path in cache.keys() - all_paths:
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
self.on_file_deleted(path)
|
self.on_file_deleted(path)
|
||||||
|
|
@ -565,16 +565,10 @@ class Log:
|
||||||
_GREY_BOLD_STYLE = termstr.CharStyle(termstr.Color.grey_100, is_bold=True)
|
_GREY_BOLD_STYLE = termstr.CharStyle(termstr.Color.grey_100, is_bold=True)
|
||||||
_GREEN_STYLE = termstr.CharStyle(termstr.Color.lime)
|
_GREEN_STYLE = termstr.CharStyle(termstr.Color.lime)
|
||||||
|
|
||||||
def __init__(self, appearance_changed_event):
|
def __init__(self):
|
||||||
self._appearance_changed_event = appearance_changed_event
|
|
||||||
self.lines = []
|
self.lines = []
|
||||||
self._appearance = None
|
self._appearance = None
|
||||||
|
|
||||||
def __getstate__(self):
|
|
||||||
state = self.__dict__.copy()
|
|
||||||
state["_appearance_changed_event"] = None
|
|
||||||
return state
|
|
||||||
|
|
||||||
def log_message(self, message, timestamp=None, char_style=None):
|
def log_message(self, message, timestamp=None, char_style=None):
|
||||||
if isinstance(message, list):
|
if isinstance(message, list):
|
||||||
message = [part[1] if isinstance(part, tuple) else part for part in message]
|
message = [part[1] if isinstance(part, tuple) else part for part in message]
|
||||||
|
|
@ -588,7 +582,7 @@ class Log:
|
||||||
return
|
return
|
||||||
self.lines.append(line)
|
self.lines.append(line)
|
||||||
self._appearance = None
|
self._appearance = None
|
||||||
self._appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def log_command(self, message, timestamp=None):
|
def log_command(self, message, timestamp=None):
|
||||||
self.log_message(message, char_style=Log._GREEN_STYLE)
|
self.log_message(message, char_style=Log._GREEN_STYLE)
|
||||||
|
|
@ -631,20 +625,20 @@ class Help:
|
||||||
def _exit_help(self):
|
def _exit_help(self):
|
||||||
self.screen._is_help_visible = False
|
self.screen._is_help_visible = False
|
||||||
|
|
||||||
def on_mouse_input(self, term_code, appearance_changed_event):
|
def on_mouse_input(self, term_code):
|
||||||
event = terminal.decode_mouse_input(term_code)
|
event = terminal.decode_mouse_input(term_code)
|
||||||
if event[1] == terminal.WHEEL_UP_MOUSE:
|
if event[1] == terminal.WHEEL_UP_MOUSE:
|
||||||
self.view.portal.scroll_up()
|
self.view.portal.scroll_up()
|
||||||
appearance_changed_event.set()
|
fiil3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
elif event[1] == terminal.WHEEL_DOWN_MOUSE:
|
elif event[1] == terminal.WHEEL_DOWN_MOUSE:
|
||||||
self.view.portal.scroll_down()
|
self.view.portal.scroll_down()
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def on_keyboard_input(self, term_code, appearance_changed_event):
|
def on_keyboard_input(self, term_code):
|
||||||
action = self.key_map.get(term_code) or self.key_map.get(term_code.lower())
|
action = self.key_map.get(term_code) or self.key_map.get(term_code.lower())
|
||||||
if action is not None:
|
if action is not None:
|
||||||
action()
|
action()
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def appearance(self, dimensions):
|
def appearance(self, dimensions):
|
||||||
return self.widget.appearance(dimensions)
|
return self.widget.appearance(dimensions)
|
||||||
|
|
@ -663,10 +657,9 @@ class Listing:
|
||||||
|
|
||||||
class Screen:
|
class Screen:
|
||||||
|
|
||||||
def __init__(self, summary, log, appearance_changed_event, main_loop):
|
def __init__(self, summary, log, main_loop):
|
||||||
self._summary = summary
|
self._summary = summary
|
||||||
self._log = log
|
self._log = log
|
||||||
self._appearance_changed_event = appearance_changed_event
|
|
||||||
self._main_loop = main_loop
|
self._main_loop = main_loop
|
||||||
self._is_summary_focused = True
|
self._is_summary_focused = True
|
||||||
self.workers = None
|
self.workers = None
|
||||||
|
|
@ -679,7 +672,6 @@ class Screen:
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
state = self.__dict__.copy()
|
state = self.__dict__.copy()
|
||||||
state["_appearance_changed_event"] = None
|
|
||||||
state["_main_loop"] = None
|
state["_main_loop"] = None
|
||||||
state["workers"] = None
|
state["workers"] = None
|
||||||
return state
|
return state
|
||||||
|
|
@ -690,8 +682,7 @@ class Screen:
|
||||||
worker_ = worker.Worker(is_being_tested, compression)
|
worker_ = worker.Worker(is_being_tested, compression)
|
||||||
workers.append(worker_)
|
workers.append(worker_)
|
||||||
future = worker_.job_runner(self, self._summary, self._log,
|
future = worker_.job_runner(self, self._summary, self._log,
|
||||||
self._summary._jobs_added_event,
|
self._summary._jobs_added_event)
|
||||||
self._appearance_changed_event)
|
|
||||||
worker_.future = future
|
worker_.future = future
|
||||||
self.workers = workers
|
self.workers = workers
|
||||||
|
|
||||||
|
|
@ -886,7 +877,7 @@ class Screen:
|
||||||
|
|
||||||
def on_mouse_input(self, term_code):
|
def on_mouse_input(self, term_code):
|
||||||
if self._is_help_visible:
|
if self._is_help_visible:
|
||||||
self._help_widget.on_mouse_input(term_code, self._appearance_changed_event)
|
self._help_widget.on_mouse_input(term_code)
|
||||||
return
|
return
|
||||||
event = terminal.decode_mouse_input(term_code)
|
event = terminal.decode_mouse_input(term_code)
|
||||||
if event[0] not in [terminal.PRESS_MOUSE, terminal.DRAG_MOUSE]:
|
if event[0] not in [terminal.PRESS_MOUSE, terminal.DRAG_MOUSE]:
|
||||||
|
|
@ -912,16 +903,16 @@ class Screen:
|
||||||
self._select_entry_at_position(
|
self._select_entry_at_position(
|
||||||
x, y, view_width, view_height)
|
x, y, view_width, view_height)
|
||||||
self._last_mouse_position = x, y
|
self._last_mouse_position = x, y
|
||||||
self._appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def on_keyboard_input(self, term_code):
|
def on_keyboard_input(self, term_code):
|
||||||
if self._is_help_visible:
|
if self._is_help_visible:
|
||||||
self._help_widget.on_keyboard_input(term_code, self._appearance_changed_event)
|
self._help_widget.on_keyboard_input(term_code)
|
||||||
return
|
return
|
||||||
action = Screen._KEY_MAP.get(term_code) or Screen._KEY_MAP.get(term_code.lower())
|
action = Screen._KEY_MAP.get(term_code) or Screen._KEY_MAP.get(term_code.lower())
|
||||||
if action is not None:
|
if action is not None:
|
||||||
action(self)
|
action(self)
|
||||||
self._appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def _fix_listing(self):
|
def _fix_listing(self):
|
||||||
widget = self._summary.get_selection()
|
widget = self._summary.get_selection()
|
||||||
|
|
@ -999,29 +990,27 @@ def setup_inotify(root_path, loop, on_filesystem_event, exclude_filter):
|
||||||
return pyinotify.AsyncioNotifier(watch_manager, loop, callback=lambda notifier: None)
|
return pyinotify.AsyncioNotifier(watch_manager, loop, callback=lambda notifier: None)
|
||||||
|
|
||||||
|
|
||||||
def load_state(pickle_path, jobs_added_event, appearance_changed_event, root_path, loop):
|
def load_state(pickle_path, jobs_added_event, root_path, loop):
|
||||||
is_first_run = True
|
is_first_run = True
|
||||||
try:
|
try:
|
||||||
with gzip.open(pickle_path, "rb") as file_:
|
with gzip.open(pickle_path, "rb") as file_:
|
||||||
screen = pickle.load(file_)
|
screen = pickle.load(file_)
|
||||||
except (FileNotFoundError, AttributeError):
|
except (FileNotFoundError, AttributeError):
|
||||||
summary = Summary(root_path, jobs_added_event)
|
summary = Summary(root_path, jobs_added_event)
|
||||||
log = Log(appearance_changed_event)
|
log = Log()
|
||||||
screen = Screen(summary, log, appearance_changed_event, loop)
|
screen = Screen(summary, log, loop)
|
||||||
else:
|
else:
|
||||||
is_first_run = False
|
is_first_run = False
|
||||||
screen._appearance_changed_event = appearance_changed_event
|
|
||||||
screen._main_loop = loop
|
screen._main_loop = loop
|
||||||
summary = screen._summary
|
summary = screen._summary
|
||||||
summary._jobs_added_event = jobs_added_event
|
summary._jobs_added_event = jobs_added_event
|
||||||
summary._root_path = root_path
|
summary._root_path = root_path
|
||||||
summary.clear_running()
|
summary.clear_running()
|
||||||
log = screen._log
|
log = screen._log
|
||||||
log._appearance_changed_event = appearance_changed_event
|
|
||||||
return summary, screen, log, is_first_run
|
return summary, screen, log, is_first_run
|
||||||
|
|
||||||
|
|
||||||
def on_filesystem_event(event, summary, root_path, appearance_changed_event):
|
def on_filesystem_event(event, summary, root_path):
|
||||||
path = list(fix_paths(root_path, [event.pathname]))[0]
|
path = list(fix_paths(root_path, [event.pathname]))[0]
|
||||||
if is_path_excluded(path[2:]):
|
if is_path_excluded(path[2:]):
|
||||||
return
|
return
|
||||||
|
|
@ -1038,7 +1027,7 @@ def on_filesystem_event(event, summary, root_path, appearance_changed_event):
|
||||||
except Exception:
|
except Exception:
|
||||||
tools.log_error()
|
tools.log_error()
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
|
|
||||||
def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
|
def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
|
||||||
|
|
@ -1052,15 +1041,13 @@ def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
|
||||||
os.environ["PYGMENT_STYLE"] = theme
|
os.environ["PYGMENT_STYLE"] = theme
|
||||||
pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle")
|
pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle")
|
||||||
jobs_added_event = asyncio.Event()
|
jobs_added_event = asyncio.Event()
|
||||||
appearance_changed_event = asyncio.Event()
|
summary, screen, log, is_first_run = load_state(pickle_path, jobs_added_event, root_path, loop)
|
||||||
summary, screen, log, is_first_run = load_state(pickle_path, jobs_added_event,
|
|
||||||
appearance_changed_event, root_path, loop)
|
|
||||||
screen.editor_command = editor_command
|
screen.editor_command = editor_command
|
||||||
log.log_message("Program started.")
|
log.log_message("Program started.")
|
||||||
jobs_added_event.set()
|
jobs_added_event.set()
|
||||||
|
|
||||||
def callback(event):
|
def callback(event):
|
||||||
on_filesystem_event(event, summary, root_path, appearance_changed_event)
|
on_filesystem_event(event, summary, root_path)
|
||||||
notifier = setup_inotify(root_path, loop, callback, is_path_excluded)
|
notifier = setup_inotify(root_path, loop, callback, is_path_excluded)
|
||||||
try:
|
try:
|
||||||
log.log_message(f"Starting workers ({worker_count}) …")
|
log.log_message(f"Starting workers ({worker_count}) …")
|
||||||
|
|
@ -1071,11 +1058,11 @@ def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
screen.stop_workers()
|
screen.stop_workers()
|
||||||
loop.stop()
|
loop.stop()
|
||||||
loop.create_task(summary.sync_with_filesystem(appearance_changed_event, log))
|
loop.create_task(summary.sync_with_filesystem(log))
|
||||||
for worker_ in screen.workers:
|
for worker_ in screen.workers:
|
||||||
loop.create_task(worker_.future)
|
loop.create_task(worker_.future)
|
||||||
if sys.stdout.isatty():
|
if sys.stdout.isatty():
|
||||||
with fill3.context(loop, appearance_changed_event, screen, exit_loop=exit_loop):
|
with fill3.context(loop, screen, exit_loop=exit_loop):
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
log.log_message("Program stopped.")
|
log.log_message("Program stopped.")
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -559,18 +559,18 @@ class Result:
|
||||||
def is_completed(self):
|
def is_completed(self):
|
||||||
return self.status in Result.COMPLETED_STATUSES
|
return self.status in Result.COMPLETED_STATUSES
|
||||||
|
|
||||||
async def run(self, log, appearance_changed_event, runner):
|
async def run(self, log, runner):
|
||||||
tool_name = tool_name_colored(self.tool, self.path)
|
tool_name = tool_name_colored(self.tool, self.path)
|
||||||
path = path_colored(self.path)
|
path = path_colored(self.path)
|
||||||
log.log_message(["Running ", tool_name, " on ", path, "…"])
|
log.log_message(["Running ", tool_name, " on ", path, "…"])
|
||||||
self.set_status(Status.running)
|
self.set_status(Status.running)
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
new_status = await runner.run_tool(self.path, self.tool)
|
new_status = await runner.run_tool(self.path, self.tool)
|
||||||
Result.result.fget.evict(self)
|
Result.result.fget.evict(self)
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
self.set_status(new_status)
|
self.set_status(new_status)
|
||||||
appearance_changed_event.set()
|
fill3.APPEARANCE_CHANGED_EVENT.set()
|
||||||
log.log_message(["Finished running ", tool_name, " on ", path, ". ",
|
log.log_message(["Finished running ", tool_name, " on ", path, ". ",
|
||||||
STATUS_TO_TERMSTR[new_status], f" {round(end_time - start_time, 2)} secs"])
|
STATUS_TO_TERMSTR[new_status], f" {round(end_time - start_time, 2)} secs"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class Worker:
|
||||||
break
|
break
|
||||||
return tools.Status(int(data))
|
return tools.Status(int(data))
|
||||||
|
|
||||||
async def job_runner(self, screen, summary, log, jobs_added_event, appearance_changed_event):
|
async def job_runner(self, screen, summary, log, jobs_added_event):
|
||||||
await self.create_process()
|
await self.create_process()
|
||||||
while True:
|
while True:
|
||||||
await jobs_added_event.wait()
|
await jobs_added_event.wait()
|
||||||
|
|
@ -55,7 +55,7 @@ class Worker:
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
self.result = None
|
self.result = None
|
||||||
break
|
break
|
||||||
await self.result.run(log, appearance_changed_event, self)
|
await self.result.run(log, self)
|
||||||
self.result.compression = self.compression
|
self.result.compression = self.compression
|
||||||
Worker.unsaved_jobs_total += 1
|
Worker.unsaved_jobs_total += 1
|
||||||
if Worker.unsaved_jobs_total == 5000 and summary.is_loaded:
|
if Worker.unsaved_jobs_total == 5000 and summary.is_loaded:
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,9 @@ class ScreenWidgetTestCase(unittest.TestCase):
|
||||||
foo_path = os.path.join(project_dir, "foo.py")
|
foo_path = os.path.join(project_dir, "foo.py")
|
||||||
_touch(foo_path)
|
_touch(foo_path)
|
||||||
jobs_added_event = asyncio.Event()
|
jobs_added_event = asyncio.Event()
|
||||||
appearance_changed_event = asyncio.Event()
|
|
||||||
summary = __main__.Summary(project_dir, jobs_added_event)
|
summary = __main__.Summary(project_dir, jobs_added_event)
|
||||||
log = __main__.Log(appearance_changed_event)
|
log = __main__.Log()
|
||||||
self.main_widget = __main__.Screen(
|
self.main_widget = __main__.Screen(summary, log, _MockMainLoop())
|
||||||
summary, log, appearance_changed_event, _MockMainLoop())
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.temp_dir)
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
@ -123,20 +121,17 @@ class SummarySyncWithFilesystemTestCase(unittest.TestCase):
|
||||||
self.bar_path = os.path.join(self.temp_dir, "bar.md")
|
self.bar_path = os.path.join(self.temp_dir, "bar.md")
|
||||||
self.zoo_path = os.path.join(self.temp_dir, "zoo.html")
|
self.zoo_path = os.path.join(self.temp_dir, "zoo.html")
|
||||||
self.jobs_added_event = asyncio.Event()
|
self.jobs_added_event = asyncio.Event()
|
||||||
self.appearance_changed_event = asyncio.Event()
|
|
||||||
self.summary = __main__.Summary(self.temp_dir, self.jobs_added_event)
|
self.summary = __main__.Summary(self.temp_dir, self.jobs_added_event)
|
||||||
self.loop = asyncio.new_event_loop()
|
self.loop = asyncio.new_event_loop()
|
||||||
|
|
||||||
def callback(event):
|
def callback(event):
|
||||||
__main__.on_filesystem_event(event, self.summary, self.temp_dir,
|
__main__.on_filesystem_event(event, self.summary, self.temp_dir)
|
||||||
self.appearance_changed_event)
|
|
||||||
__main__.setup_inotify(self.temp_dir, self.loop, callback,
|
__main__.setup_inotify(self.temp_dir, self.loop, callback,
|
||||||
__main__.is_path_excluded)
|
__main__.is_path_excluded)
|
||||||
_touch(self.foo_path)
|
_touch(self.foo_path)
|
||||||
_touch(self.bar_path)
|
_touch(self.bar_path)
|
||||||
self.log = __main__.Log(self.appearance_changed_event)
|
self.log = __main__.Log()
|
||||||
self.loop.run_until_complete(self.summary.sync_with_filesystem(
|
self.loop.run_until_complete(self.summary.sync_with_filesystem(self.log))
|
||||||
self.appearance_changed_event, self.log))
|
|
||||||
self.jobs_added_event.clear()
|
self.jobs_added_event.clear()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
|
@ -188,9 +183,8 @@ class SummarySyncWithFilesystemTestCase(unittest.TestCase):
|
||||||
baz_path = os.path.join(self.temp_dir, "baz")
|
baz_path = os.path.join(self.temp_dir, "baz")
|
||||||
os.symlink(self.foo_path, baz_path)
|
os.symlink(self.foo_path, baz_path)
|
||||||
os.link(self.foo_path, self.zoo_path)
|
os.link(self.foo_path, self.zoo_path)
|
||||||
log = __main__.Log(self.appearance_changed_event)
|
log = __main__.Log()
|
||||||
self.loop.run_until_complete(self.summary.sync_with_filesystem(
|
self.loop.run_until_complete(self.summary.sync_with_filesystem(log))
|
||||||
self.appearance_changed_event, log))
|
|
||||||
self._assert_paths(["./bar.md", "./baz", "./foo", "./zoo.html"])
|
self._assert_paths(["./bar.md", "./baz", "./foo", "./zoo.html"])
|
||||||
self.assertTrue(id(self.summary._entries[1]) != # baz
|
self.assertTrue(id(self.summary._entries[1]) != # baz
|
||||||
id(self.summary._entries[2])) # foo
|
id(self.summary._entries[2])) # foo
|
||||||
|
|
|
||||||
|
|
@ -406,30 +406,31 @@ class Fixed:
|
||||||
##########################
|
##########################
|
||||||
|
|
||||||
|
|
||||||
_last_appearance = []
|
APPEARANCE_CHANGED_EVENT = asyncio.Event()
|
||||||
|
_LAST_APPEARANCE = []
|
||||||
|
|
||||||
|
|
||||||
def draw_screen(widget):
|
def draw_screen(widget):
|
||||||
global _last_appearance
|
global _LAST_APPEARANCE
|
||||||
appearance = widget.appearance(os.get_terminal_size())
|
appearance = widget.appearance(os.get_terminal_size())
|
||||||
print(terminal.move(0, 0), *appearance, sep="", end="", flush=True)
|
print(terminal.move(0, 0), *appearance, sep="", end="", flush=True)
|
||||||
_last_appearance = appearance
|
_LAST_APPEARANCE = appearance
|
||||||
|
|
||||||
|
|
||||||
def patch_screen(widget):
|
def patch_screen(widget):
|
||||||
global _last_appearance
|
global _LAST_APPEARANCE
|
||||||
appearance = widget.appearance(os.get_terminal_size())
|
appearance = widget.appearance(os.get_terminal_size())
|
||||||
zip_func = (itertools.zip_longest if len(appearance) > len(_last_appearance) else zip)
|
zip_func = (itertools.zip_longest if len(appearance) > len(_LAST_APPEARANCE) else zip)
|
||||||
changed_lines = (str(terminal.move(0, row_index)) + line for row_index, (line, old_line)
|
changed_lines = (str(terminal.move(0, row_index)) + line for row_index, (line, old_line)
|
||||||
in enumerate(zip_func(appearance, _last_appearance)) if line != old_line)
|
in enumerate(zip_func(appearance, _LAST_APPEARANCE)) if line != old_line)
|
||||||
print(*changed_lines, sep="", end="", flush=True)
|
print(*changed_lines, sep="", end="", flush=True)
|
||||||
_last_appearance = appearance
|
_LAST_APPEARANCE = appearance
|
||||||
|
|
||||||
|
|
||||||
async def update_screen(screen_widget, appearance_changed_event):
|
async def update_screen(screen_widget):
|
||||||
while True:
|
while True:
|
||||||
await appearance_changed_event.wait()
|
await APPEARANCE_CHANGED_EVENT.wait()
|
||||||
appearance_changed_event.clear()
|
APPEARANCE_CHANGED_EVENT.clear()
|
||||||
patch_screen(screen_widget)
|
patch_screen(screen_widget)
|
||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
|
|
@ -453,8 +454,8 @@ def signal_handler(loop, signal_, func):
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def context(loop, appearance_changed_event, screen_widget, exit_loop=None):
|
def context(loop, screen_widget, exit_loop=None):
|
||||||
appearance_changed_event.set()
|
APPEARANCE_CHANGED_EVENT.set()
|
||||||
if exit_loop is None:
|
if exit_loop is None:
|
||||||
exit_loop = loop.stop
|
exit_loop = loop.stop
|
||||||
with (signal_handler(loop, signal.SIGWINCH, lambda: draw_screen(screen_widget)),
|
with (signal_handler(loop, signal.SIGWINCH, lambda: draw_screen(screen_widget)),
|
||||||
|
|
@ -462,7 +463,7 @@ def context(loop, appearance_changed_event, screen_widget, exit_loop=None):
|
||||||
signal_handler(loop, signal.SIGTERM, exit_loop), terminal.alternate_buffer(),
|
signal_handler(loop, signal.SIGTERM, exit_loop), terminal.alternate_buffer(),
|
||||||
terminal.interactive(), terminal.mouse_tracking()):
|
terminal.interactive(), terminal.mouse_tracking()):
|
||||||
update_task = loop.create_task(
|
update_task = loop.create_task(
|
||||||
update_screen(screen_widget, appearance_changed_event))
|
update_screen(screen_widget))
|
||||||
try:
|
try:
|
||||||
loop.add_reader(sys.stdin, on_terminal_input, screen_widget)
|
loop.add_reader(sys.stdin, on_terminal_input, screen_widget)
|
||||||
try:
|
try:
|
||||||
|
|
@ -478,8 +479,7 @@ def context(loop, appearance_changed_event, screen_widget, exit_loop=None):
|
||||||
|
|
||||||
class _Screen:
|
class _Screen:
|
||||||
|
|
||||||
def __init__(self, appearance_changed_event):
|
def __init__(self):
|
||||||
self._appearance_changed_event = appearance_changed_event
|
|
||||||
self.content = Filler(Text("Hello World"))
|
self.content = Filler(Text("Hello World"))
|
||||||
|
|
||||||
def appearance(self, dimensions):
|
def appearance(self, dimensions):
|
||||||
|
|
@ -490,19 +490,17 @@ class _Screen:
|
||||||
asyncio.get_event_loop().stop()
|
asyncio.get_event_loop().stop()
|
||||||
else:
|
else:
|
||||||
self.content = Filler(Text(repr(term_code)))
|
self.content = Filler(Text(repr(term_code)))
|
||||||
self._appearance_changed_event.set()
|
APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
def on_mouse_input(self, term_code):
|
def on_mouse_input(self, term_code):
|
||||||
mouse_code = terminal.decode_mouse_input(term_code)
|
mouse_code = terminal.decode_mouse_input(term_code)
|
||||||
self.content = Filler(Text(repr(term_code) + " " + repr(mouse_code)))
|
self.content = Filler(Text(repr(term_code) + " " + repr(mouse_code)))
|
||||||
self._appearance_changed_event.set()
|
APPEARANCE_CHANGED_EVENT.set()
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
appearance_changed_event = asyncio.Event()
|
with context(loop, _Screen()):
|
||||||
screen = _Screen(appearance_changed_event)
|
|
||||||
with context(loop, appearance_changed_event, screen):
|
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue