diff --git a/Cargo.lock b/Cargo.lock index 93b401d..ff9dfbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,27 +140,25 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-macro" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -168,30 +166,27 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.16" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ - "autocfg", "futures-core", "futures-macro", "futures-task", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -496,18 +491,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "1.0.28" diff --git a/src/ui/no_yaml_found.rs b/src/ui/no_yaml_found.rs index 7a300d3..3f3da8a 100644 --- a/src/ui/no_yaml_found.rs +++ b/src/ui/no_yaml_found.rs @@ -73,6 +73,8 @@ impl Ui { events: mpsc::Receiver, sender: mpsc::Sender, ) -> Result<(), Error> { + use std::sync::atomic::Ordering; + let fetching_tags = Arc::new(std::sync::atomic::AtomicBool::new(false)); loop { match events.recv() { Ok(DeferredEvent::Quit) => break, @@ -92,23 +94,50 @@ impl Ui { ui.details = ui.tags.create_detail_widget(); } Ok(DeferredEvent::TagNext) => { - let (fetched_new_tags, mut tags) = { + let mut tags_copy = { let mut ui = ui.lock().unwrap(); - if ui.tags.at_end_of_list() { - ui.info.set_text("Fetching more tags..."); - sender.send(UiEvent::RefreshOnNewData)?; - (true, ui.tags.clone()) - } else { - (false, ui.tags.clone()) + match ui.tags.next() { + None => { + // return early, also releases lock + ui.details = ui.tags.create_detail_widget(); + sender.send(UiEvent::RefreshOnNewData)?; + continue; + } + Some(_) if !fetching_tags.load(Ordering::Relaxed) => { + fetching_tags.store(true, Ordering::Relaxed); + ui.info.set_text("Fetching more tags..."); + sender.send(UiEvent::RefreshOnNewData)?; + ui.tags.clone() + } + Some(_) => { + // do nothing, as we are already fetching for new tags + continue; + } } }; - tags.next().await; - let mut ui = ui.lock().unwrap(); - ui.tags = tags; - ui.details = ui.tags.create_detail_widget(); - if fetched_new_tags { - ui.info.set_text("Fetching tags done"); - } + + // fetching new tags + let sender_copy = sender.clone(); + let ui_copy = ui.clone(); + let fetching_tags_copy = fetching_tags.clone(); + std::thread::spawn(move || { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + tags_copy.load_next_page().await; + let mut ui = ui_copy.lock().unwrap(); + //set position to the position of old TagList + //it may have changed since tag fetching has been invoked + tags_copy.set_cursor(ui.tags.get_cursor().clone()); + ui.tags = tags_copy; + ui.details = ui.tags.create_detail_widget(); + ui.info.set_text("Fetching tags done"); + sender_copy.send(UiEvent::RefreshOnNewData).unwrap(); + fetching_tags_copy.store(false, Ordering::Relaxed); + }) + }); } Err(e) => { let mut ui = ui.lock().unwrap(); diff --git a/src/ui/yaml_found.rs b/src/ui/yaml_found.rs index 219bb97..dd14398 100644 --- a/src/ui/yaml_found.rs +++ b/src/ui/yaml_found.rs @@ -78,6 +78,8 @@ impl Ui { events: mpsc::Receiver, sender: mpsc::Sender, ) -> Result<(), Error> { + use std::sync::atomic::Ordering; + let fetching_tags = Arc::new(std::sync::atomic::AtomicBool::new(false)); loop { match events.recv() { Ok(DeferredEvent::Quit) => break, @@ -97,21 +99,50 @@ impl Ui { ui.details = ui.tags.create_detail_widget(); } Ok(DeferredEvent::TagNext) => { - let (fetched_new_tags, mut tags) = { + let mut tags_copy = { let mut ui = ui.lock().unwrap(); - if ui.tags.at_end_of_list() { - ui.info.set_text("Fetching more tags..."); - sender.send(UiEvent::RefreshOnNewData)?; + match ui.tags.next() { + None => { + // return early, also releases lock + ui.details = ui.tags.create_detail_widget(); + sender.send(UiEvent::RefreshOnNewData)?; + continue; + } + Some(_) if !fetching_tags.load(Ordering::Relaxed) => { + fetching_tags.store(true, Ordering::Relaxed); + ui.info.set_text("Fetching more tags..."); + sender.send(UiEvent::RefreshOnNewData)?; + ui.tags.clone() + } + Some(_) => { + // do nothing, as we are already fetching for new tags + continue; + } } - (ui.tags.at_end_of_list(), ui.tags.clone()) }; - tags.next().await; - let mut ui = ui.lock().unwrap(); - ui.tags = tags; - ui.details = ui.tags.create_detail_widget(); - if fetched_new_tags { - ui.info.set_text("Fetching tags done"); - } + + // fetching new tags + let sender_copy = sender.clone(); + let ui_copy = ui.clone(); + let fetching_tags_copy = fetching_tags.clone(); + std::thread::spawn(move || { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + tags_copy.load_next_page().await; + let mut ui = ui_copy.lock().unwrap(); + //set position to the position of old TagList + //it may have changed since tag fetching has been invoked + tags_copy.set_cursor(ui.tags.get_cursor().clone()); + ui.tags = tags_copy; + ui.details = ui.tags.create_detail_widget(); + ui.info.set_text("Fetching tags done"); + sender_copy.send(UiEvent::RefreshOnNewData).unwrap(); + fetching_tags_copy.store(false, Ordering::Relaxed); + }) + }); } Err(e) => { let mut ui = ui.lock().unwrap(); diff --git a/src/widget/async_tag_list.rs b/src/widget/async_tag_list.rs index fe901f7..4b5c07b 100644 --- a/src/widget/async_tag_list.rs +++ b/src/widget/async_tag_list.rs @@ -86,11 +86,12 @@ impl TagList { } } - pub fn at_end_of_list(&self) -> bool { - if let Some(i) = self.state.selected() { - return i == self.lines.len() - 2; - } - false + pub fn set_cursor(&mut self, state: ListState) { + self.state = state; + } + + pub fn get_cursor(&self) -> &ListState { + &self.state } pub fn render(&mut self, colored: bool) -> (List, &mut ListState) { @@ -177,16 +178,19 @@ impl TagList { } /// select next tag - pub async fn next(&mut self) { + /// returns Some when more tags need to be fetched otherwise None + pub fn next(&mut self) -> Option<()> { if let Some(Line::Status(_)) = self.lines.get(0) { - return; + return None; } match self.state.selected() { None if !self.lines.is_empty() => self.state.select(Some(0)), None => (), - Some(i) if i == self.lines.len() - 2 => self.load_next_page().await, + Some(i) if i == self.lines.len() - 2 => return Some(()), + // Some(i) if i == self.lines.len() - 2 => return self.load_next_page().await, Some(i) => self.state.select(Some(i + 1)), } + None } /// select previous tag