Full Async Events
There are a number of ways to make our application work more in an async
manner. The easiest way
to do this is to add more Event
variants to our existing EventHandler
. Specifically, we would
like to only render in the main run loop when we receive a Event::Render
variant:
Another thing I personally like to do is combine the EventHandler
struct and the Terminal
functionality. To do this, we are going to rename our EventHandler
struct to a Tui
struct. We
are also going to include a few more Event
variants for making our application more capable.
Below is the relevant snippet of an updated Tui
struct. You can click on the “Show hidden lines”
button at the top right of the code block or check out
this section of the book for the full version this
struct.
The key things to note are that we create a tick_interval
, render_interval
and reader
stream
that can be polled using tokio::select!
. This means that even while waiting for a key press, we
will still send a Event::Tick
and Event::Render
at regular intervals.
We made a number of changes to the Tui
struct.
- We added a
Deref
andDerefMut
so we can calltui.draw(|f| ...)
to have it calltui.terminal.draw(|f| ...)
. - We moved the
startup()
andshutdown()
functionality into theTui
struct. - We also added a
CancellationToken
so that we can start and stop the tokio task more easily. - We added
Event
variants forResize
,Focus
, andPaste
. - We added methods to set the
tick_rate
,frame_rate
, and whether we want to enablemouse
orpaste
events.
Here’s the code for the fully async application:
The above code ensures that we render at a consistent frame rate. As an exercise, play around with this frame rate and tick rate to see how the CPU utilization changes as you change those numbers.
Even though our application renders in an “async” manner, we also want to perform “actions” in an asynchronous manner. We will improve this in the next section to make our application truly async capable.