@@ -656,7 +656,8 @@ async def run_async(
656
656
handle_sigint = False
657
657
658
658
async def _run_async (f : "asyncio.Future[_AppResult]" ) -> _AppResult :
659
- self .context = contextvars .copy_context ()
659
+ context = contextvars .copy_context ()
660
+ self .context = context
660
661
661
662
# Counter for cancelling 'flush' timeouts. Every time when a key is
662
663
# pressed, we start a 'flush' timer for flushing our escape key. But
@@ -700,6 +701,16 @@ def read_from_input() -> None:
700
701
flush_task .cancel ()
701
702
flush_task = self .create_background_task (auto_flush_input ())
702
703
704
+ def read_from_input_in_context () -> None :
705
+ # Ensure that key bindings callbacks are always executed in the
706
+ # current context. This is important when key bindings are
707
+ # accessing contextvars. (These callbacks are currently being
708
+ # called from a different context. Underneath,
709
+ # `loop.add_reader` is used to register the stdin FD.)
710
+ # (We copy the context to avoid a `RuntimeError` in case the
711
+ # context is already active.)
712
+ context .copy ().run (read_from_input )
713
+
703
714
async def auto_flush_input () -> None :
704
715
# Flush input after timeout.
705
716
# (Used for flushing the enter key.)
@@ -719,7 +730,7 @@ def flush_input() -> None:
719
730
720
731
# Enter raw mode, attach input and attach WINCH event handler.
721
732
with self .input .raw_mode (), self .input .attach (
722
- read_from_input
733
+ read_from_input_in_context
723
734
), attach_winch_signal_handler (self ._on_resize ):
724
735
# Draw UI.
725
736
self ._request_absolute_cursor_position ()
0 commit comments