refactor(app): buffering actions and events handling to improve overall UI responsiveness (#328)

This commit is contained in:
Alexandre Pasmantier 2025-01-31 23:58:13 +01:00 committed by GitHub
parent be80496549
commit 5214dd17d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 180 additions and 144 deletions

169
Cargo.lock generated
View File

@ -4,19 +4,13 @@ version = 4
[[package]]
name = "addr2line"
version = "0.21.0"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler2"
version = "2.0.0"
@ -117,17 +111,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.71"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide 0.7.4",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
]
[[package]]
@ -216,9 +210,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.16.0"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "bytemuck"
@ -287,9 +281,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.10"
version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf"
dependencies = [
"shlex",
]
@ -329,9 +323,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.26"
version = "4.5.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
dependencies = [
"clap_builder",
"clap_derive",
@ -339,9 +333,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.26"
version = "4.5.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
dependencies = [
"anstream",
"anstyle",
@ -556,9 +550,9 @@ dependencies = [
[[package]]
name = "crunchy"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "cursor-icon"
@ -716,7 +710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide 0.8.3",
"miniz_oxide",
]
[[package]]
@ -820,14 +814,26 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets 0.52.6",
]
[[package]]
name = "gimli"
version = "0.28.1"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "globset"
@ -953,13 +959,13 @@ dependencies = [
[[package]]
name = "is-terminal"
version = "0.4.13"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1110,15 +1116,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
]
[[package]]
name = "miniz_oxide"
version = "0.8.3"
@ -1136,7 +1133,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
@ -1236,9 +1233,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.2"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
@ -1438,9 +1435,9 @@ dependencies = [
[[package]]
name = "quick-xml"
version = "0.36.2"
version = "0.37.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003"
dependencies = [
"memchr",
]
@ -1511,7 +1508,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"getrandom 0.2.15",
"libredox",
"thiserror",
]
@ -1583,9 +1580,9 @@ checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "rustix"
version = "0.38.43"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.8.0",
"errno",
@ -1602,9 +1599,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "ryu"
version = "1.0.18"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "same-file"
@ -1655,9 +1652,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.137"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
dependencies = [
"itoa",
"memchr",
@ -1920,13 +1917,13 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.15.0"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
dependencies = [
"cfg-if",
"fastrand",
"getrandom",
"getrandom 0.3.1",
"once_cell",
"rustix",
"windows-sys 0.59.0",
@ -2055,9 +2052,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.22"
version = "0.22.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee"
dependencies = [
"indexmap",
"serde",
@ -2129,9 +2126,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.14"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "unicode-segmentation"
@ -2176,11 +2173,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.12.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
dependencies = [
"getrandom",
"getrandom 0.2.15",
]
[[package]]
@ -2205,6 +2202,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
@ -2265,9 +2271,9 @@ dependencies = [
[[package]]
name = "wayland-backend"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6"
checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf"
dependencies = [
"cc",
"downcast-rs",
@ -2279,9 +2285,9 @@ dependencies = [
[[package]]
name = "wayland-client"
version = "0.31.7"
version = "0.31.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280"
checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f"
dependencies = [
"bitflags 2.8.0",
"rustix",
@ -2302,9 +2308,9 @@ dependencies = [
[[package]]
name = "wayland-cursor"
version = "0.31.7"
version = "0.31.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c"
checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d"
dependencies = [
"rustix",
"wayland-client",
@ -2313,9 +2319,9 @@ dependencies = [
[[package]]
name = "wayland-protocols"
version = "0.32.5"
version = "0.32.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e"
checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc"
dependencies = [
"bitflags 2.8.0",
"wayland-backend",
@ -2325,9 +2331,9 @@ dependencies = [
[[package]]
name = "wayland-protocols-wlr"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022"
checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2"
dependencies = [
"bitflags 2.8.0",
"wayland-backend",
@ -2338,20 +2344,20 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.31.5"
version = "0.31.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
dependencies = [
"proc-macro2",
"quick-xml 0.36.2",
"quick-xml 0.37.2",
"quote",
]
[[package]]
name = "wayland-sys"
version = "0.31.5"
version = "0.31.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09"
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615"
dependencies = [
"dlib",
"log",
@ -2550,13 +2556,22 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.24"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.8.0",
]
[[package]]
name = "x11-clipboard"
version = "0.9.3"

View File

@ -1,7 +1,9 @@
use serde::{Deserialize, Serialize};
/// The different actions that can be performed by the application.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord,
)]
pub enum Action {
// input actions
/// Add a character to the input buffer.

View File

@ -78,6 +78,9 @@ impl From<ActionOutcome> for AppOutput {
}
}
const EVENT_BUF_SIZE: usize = 4;
const ACTION_BUF_SIZE: usize = 16;
impl App {
pub fn new(
channel: TelevisionChannel,
@ -151,14 +154,23 @@ impl App {
// event handling loop
debug!("Starting event handling loop");
let action_tx = self.action_tx.clone();
let mut event_buf = Vec::with_capacity(EVENT_BUF_SIZE);
let mut action_buf = Vec::with_capacity(ACTION_BUF_SIZE);
loop {
// handle event and convert to action
if let Some(event) = self.event_rx.recv().await {
let action = self.convert_event_to_action(event);
action_tx.send(action)?;
if self
.event_rx
.recv_many(&mut event_buf, EVENT_BUF_SIZE)
.await
> 0
{
for event in event_buf.drain(..) {
let action = self.convert_event_to_action(event);
action_tx.send(action)?;
}
}
let action_outcome = self.handle_actions()?;
let action_outcome = self.handle_action(&mut action_buf).await?;
if self.should_quit {
// send a termination signal to the event loop
@ -229,69 +241,76 @@ impl App {
///
/// # Errors
/// If an error occurs during the execution of the application.
fn handle_actions(&mut self) -> Result<ActionOutcome> {
while let Ok(action) = self.action_rx.try_recv() {
if action != Action::Tick {
trace!("{action:?}");
}
match action {
Action::Quit => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
async fn handle_action(
&mut self,
buf: &mut Vec<Action>,
) -> Result<ActionOutcome> {
if self.action_rx.recv_many(buf, ACTION_BUF_SIZE).await > 0 {
buf.sort_unstable();
buf.dedup();
for action in buf.drain(..) {
if action != Action::Tick {
trace!("{action:?}");
}
Action::Suspend => {
self.should_suspend = true;
self.render_tx.send(RenderingTask::Suspend)?;
}
Action::Resume => {
self.should_suspend = false;
self.render_tx.send(RenderingTask::Resume)?;
}
Action::SelectAndExit => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
if let Some(entries) = self
.television
.get_selected_entries(Some(Mode::Channel))
{
return Ok(ActionOutcome::Entries(entries));
match action {
Action::Quit => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
}
Action::Suspend => {
self.should_suspend = true;
self.render_tx.send(RenderingTask::Suspend)?;
}
Action::Resume => {
self.should_suspend = false;
self.render_tx.send(RenderingTask::Resume)?;
}
Action::SelectAndExit => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
if let Some(entries) = self
.television
.get_selected_entries(Some(Mode::Channel))
{
return Ok(ActionOutcome::Entries(entries));
}
return Ok(ActionOutcome::Input(
self.television.current_pattern.clone(),
));
}
Action::SelectPassthrough(passthrough) => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
if let Some(entries) = self
.television
.get_selected_entries(Some(Mode::Channel))
{
return Ok(ActionOutcome::Passthrough(
entries,
passthrough,
return Ok(ActionOutcome::Input(
self.television.current_pattern.clone(),
));
}
return Ok(ActionOutcome::None);
Action::SelectPassthrough(passthrough) => {
self.should_quit = true;
self.render_tx.send(RenderingTask::Quit)?;
if let Some(entries) = self
.television
.get_selected_entries(Some(Mode::Channel))
{
return Ok(ActionOutcome::Passthrough(
entries,
passthrough,
));
}
return Ok(ActionOutcome::None);
}
Action::ClearScreen => {
self.render_tx.send(RenderingTask::ClearScreen)?;
}
Action::Resize(w, h) => {
self.render_tx.send(RenderingTask::Resize(w, h))?;
}
Action::Render => {
self.render_tx.send(RenderingTask::Render(
self.television.dump_context(),
))?;
}
_ => {}
}
Action::ClearScreen => {
self.render_tx.send(RenderingTask::ClearScreen)?;
}
Action::Resize(w, h) => {
self.render_tx.send(RenderingTask::Resize(w, h))?;
}
Action::Render => {
self.render_tx.send(RenderingTask::Render(
self.television.dump_context(),
))?;
}
_ => {}
// forward action to the television handler
if let Some(action) = self.television.update(&action)? {
self.action_tx.send(action)?;
};
}
// forward action to the television handler
if let Some(action) = self.television.update(&action)? {
self.action_tx.send(action)?;
};
}
Ok(ActionOutcome::None)
}

View File

@ -569,17 +569,17 @@ impl Television {
self.action_tx.send(Action::Render)?;
}
let selected_entry = self
.get_selected_entry(Some(Mode::Channel))
.unwrap_or(ENTRY_PLACEHOLDER);
self.update_preview_state(&selected_entry)?;
self.handle_action(action)?;
self.update_results_picker_state();
self.update_rc_picker_state();
self.handle_action(action)?;
let selected_entry = self
.get_selected_entry(Some(Mode::Channel))
.unwrap_or(ENTRY_PLACEHOLDER);
self.update_preview_state(&selected_entry)?;
self.ticks += 1;