make heavy operation async

This commit is contained in:
yggverse 2025-03-14 00:00:31 +02:00
parent 4002c94a4a
commit c3f63dfbdc
3 changed files with 73 additions and 45 deletions

View file

@ -155,32 +155,51 @@ impl Suggestion {
pub fn update(&self, limit: Option<usize>) {
use gtk::prelude::EditableExt;
use itertools::Itertools;
self.popover.popdown();
if self.request.text_length() > 0 {
self.list_store.remove_all();
let query = self.request.text();
let items = self.profile.history.contains_request(&query, limit);
if !items.is_empty() {
for item in items
.into_iter()
.sorted_by(|a, b| Ord::cmp(&b.opened.count, &a.opened.count))
{
let subtitle = highlight(&item.request, &query);
let title = match item.title {
Some(title) => highlight(&title, &query),
None => subtitle.clone(),
};
self.list_store.append(&Item::build(
title,
subtitle,
self.profile.bookmark.is_match_request(&item.request),
item.request,
));
let popover = self.popover.clone();
let list_store = self.list_store.clone();
let history = self.profile.history.memory.clone(); // @TODO
let bookmark = self.profile.bookmark.memory.clone(); // @TODO
gtk::glib::spawn_future_local(async move {
let list_items = gtk::gio::spawn_blocking(move || {
let result = history
.read()
.unwrap()
.contains_request(&query, limit)
.into_iter()
.sorted_by(|a, b| Ord::cmp(&b.opened.count, &a.opened.count));
let mut list_items = Vec::with_capacity(result.len());
for item in result {
let subtitle = highlight(&item.request, &query);
let title = match item.title {
Some(title) => highlight(&title, &query),
None => subtitle.clone(),
};
list_items.push((
title,
subtitle,
bookmark.read().unwrap().is_match_request(&item.request),
item.request,
))
}
list_items
})
.await
.unwrap();
if !list_items.is_empty() {
for (title, subtitle, has_bookmark, request) in list_items {
list_store.append(&Item::build(title, subtitle, has_bookmark, request));
} // @TODO take a while
popover.popup()
}
self.popover.popup();
return;
}
});
}
self.hide();
}
pub fn hide(&self) {

View file

@ -8,12 +8,15 @@ use gtk::glib::DateTime;
use item::Item;
use memory::Memory;
use sqlite::{Connection, Transaction};
use std::{cell::RefCell, rc::Rc, sync::RwLock};
use std::{
rc::Rc,
sync::{Arc, RwLock},
};
pub struct Bookmark {
database: Database, // permanent storage
memory: RefCell<Memory>, // fast search index
}
database: Database, // permanent storage
pub memory: Arc<RwLock<Memory>>, // fast search index
} // @TODO close memory member, Arc entire profile instead
impl Bookmark {
// Constructors
@ -22,11 +25,11 @@ impl Bookmark {
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
// Init children components
let database = Database::new(connection, profile_id);
let memory = RefCell::new(Memory::new());
let memory = Arc::new(RwLock::new(Memory::new()));
// Build initial index
{
let mut memory = memory.borrow_mut();
let mut memory = memory.write().unwrap();
for item in database.records(None, None)? {
memory.add(item);
}
@ -41,7 +44,7 @@ impl Bookmark {
/// Toggle bookmark in `database` and `memory` index
/// * return `true` on bookmark create, `false` on delete
pub fn toggle(&self, request: &str, title: Option<&str>) -> Result<bool> {
let mut memory = self.memory.borrow_mut();
let mut memory = self.memory.write().unwrap();
Ok(match memory.delete_by_request(request) {
Some(item) => {
self.database.delete(item.id)?;
@ -62,17 +65,20 @@ impl Bookmark {
/// Check `request` exists in the memory index
pub fn is_match_request(&self, request: &str) -> bool {
self.memory.borrow_mut().is_match_request(request)
self.memory.write().unwrap().is_match_request(request)
}
/// Find Items match `request`
pub fn contains_request(&self, request: &str, limit: Option<usize>) -> Vec<Item> {
self.memory.borrow_mut().contains_request(request, limit)
self.memory
.write()
.unwrap()
.contains_request(request, limit)
}
/// Get recent Items vector from `memory`, sorted by `ID` DESC
pub fn recent(&self, limit: Option<usize>) -> Vec<Item> {
self.memory.borrow().recent(limit)
self.memory.read().unwrap().recent(limit)
}
}

View file

@ -8,12 +8,15 @@ use gtk::glib::GString;
use item::{Event, Item};
use memory::Memory;
use sqlite::{Connection, Transaction};
use std::{cell::RefCell, rc::Rc, sync::RwLock};
use std::{
rc::Rc,
sync::{Arc, RwLock},
};
pub struct History {
database: Database, // permanent storage
memory: RefCell<Memory>, // fast search index
}
database: Database, // permanent storage
pub memory: Arc<RwLock<Memory>>, // fast search index
} // @TODO close memory member, Arc entire profile instead
impl History {
// Constructors
@ -22,10 +25,10 @@ impl History {
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
// Init children components
let database = Database::build(connection, profile_id);
let memory = RefCell::new(Memory::new());
let memory = Arc::new(RwLock::new(Memory::new()));
for item in database.records(None, None)? {
memory.borrow_mut().add(item)
memory.write().unwrap().add(item)
}
// Return new `Self`
@ -35,7 +38,7 @@ impl History {
// Actions
pub fn save(&self) -> Result<()> {
for item in self.memory.borrow().items() {
for item in self.memory.read().unwrap().items() {
if !item.is_saved {
match item.id {
Some(_) => {
@ -54,7 +57,7 @@ impl History {
/// Create new history record
pub fn open(&self, request: GString, title: Option<GString>) {
let mut memory = self.memory.borrow_mut();
let mut memory = self.memory.write().unwrap();
if !memory.open(&request) {
memory.add(Item {
id: None,
@ -69,25 +72,25 @@ impl History {
/// Close existing history record
pub fn close(&self, request: &str) {
self.memory.borrow_mut().close(request)
self.memory.write().unwrap().close(request)
}
// Getters
/// Get recently `opened` Items vector from the memory index, sorted by ASC
pub fn recently_opened(&self, limit: Option<usize>) -> Vec<Item> {
self.memory.borrow().recently_opened(limit)
self.memory.read().unwrap().recently_opened(limit)
}
/// Get recently `closed` Items vector from the memory index, sorted by ASC
pub fn recently_closed(&self, limit: Option<usize>) -> Vec<Item> {
self.memory.borrow().recently_closed(limit)
self.memory.read().unwrap().recently_closed(limit)
}
/// Get unordered Items vector contains `request`
/// Get unordered Items vector that contains given `request`
pub fn contains_request(&self, request: &str, limit: Option<usize>) -> Vec<Item> {
self.memory.borrow().contains_request(request, limit)
}
self.memory.read().unwrap().contains_request(request, limit)
} // @TODO close memory member
}
// Tools