This commit is contained in:
Ahmed Ibrahim
2025-12-01 13:23:30 -08:00
parent 981e2f742d
commit 0809a45e1c
5 changed files with 64 additions and 39 deletions

View File

@@ -288,8 +288,8 @@ mod tests {
}
#[cfg(target_os = "macos")]
#[test]
fn list_child_pids_includes_spawned_child() {
#[tokio::test]
async fn list_child_pids_includes_spawned_child() {
let mut child = Command::new("/bin/sleep")
.arg("5")
.stdin(Stdio::null())
@@ -305,7 +305,7 @@ mod tests {
found = true;
break;
}
std::thread::sleep(Duration::from_millis(10));
tokio::time::sleep(Duration::from_millis(10)).await;
}
let _ = child.kill();

View File

@@ -17,7 +17,6 @@
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Result;
use std::io::Write;
use std::path::PathBuf;
use serde::Deserialize;

View File

@@ -447,6 +447,16 @@ fn bind_server(port: u16) -> io::Result<Server> {
const MAX_ATTEMPTS: u32 = 10;
const RETRY_DELAY: Duration = Duration::from_millis(200);
fn retry_sleep(delay: Duration) {
if tokio::runtime::Handle::try_current().is_ok() {
let _ = tokio::task::block_in_place(|| {
std::thread::sleep(delay);
});
} else {
std::thread::sleep(delay);
}
}
loop {
match Server::http(&bind_address) {
Ok(server) => return Ok(server),
@@ -467,7 +477,7 @@ fn bind_server(port: u16) -> io::Result<Server> {
}
}
thread::sleep(RETRY_DELAY);
retry_sleep(RETRY_DELAY);
if attempts >= MAX_ATTEMPTS {
return Err(io::Error::new(

View File

@@ -50,10 +50,10 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;
use tokio::select;
use tokio::sync::mpsc::unbounded_channel;
use tokio::time::sleep;
#[cfg(not(debug_assertions))]
use crate::history_cell::UpdateAvailableHistoryCell;
@@ -502,9 +502,9 @@ impl App {
{
let tx = self.app_event_tx.clone();
let running = self.commit_anim_running.clone();
thread::spawn(move || {
tokio::spawn(async move {
while running.load(Ordering::Relaxed) {
thread::sleep(Duration::from_millis(50));
sleep(Duration::from_millis(50)).await;
tx.send(AppEvent::CommitTick);
}
});

View File

@@ -25,8 +25,9 @@ use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;
use tokio::task::spawn_blocking;
use tokio::time::sleep;
use crate::app_event::AppEvent;
use crate::app_event_sender::AppEventSender;
@@ -117,16 +118,16 @@ impl FileSearchManager {
let state = self.state.clone();
let search_dir = self.search_dir.clone();
let tx_clone = self.app_tx.clone();
thread::spawn(move || {
tokio::spawn(async move {
// Always do a minimum debounce, but then poll until the
// `active_search` is cleared.
thread::sleep(FILE_SEARCH_DEBOUNCE);
sleep(FILE_SEARCH_DEBOUNCE).await;
loop {
#[expect(clippy::unwrap_used)]
if state.lock().unwrap().active_search.is_none() {
break;
}
thread::sleep(ACTIVE_SEARCH_COMPLETE_POLL_INTERVAL);
sleep(ACTIVE_SEARCH_COMPLETE_POLL_INTERVAL).await;
}
// The debounce timer has expired, so start a search using the
@@ -162,36 +163,51 @@ impl FileSearchManager {
cancellation_token: Arc<AtomicBool>,
search_state: Arc<Mutex<SearchState>>,
) {
let compute_indices = true;
std::thread::spawn(move || {
let matches = file_search::run(
&query,
MAX_FILE_SEARCH_RESULTS,
&search_dir,
Vec::new(),
NUM_FILE_SEARCH_THREADS,
cancellation_token.clone(),
compute_indices,
true,
)
.map(|res| res.matches)
.unwrap_or_default();
tokio::spawn({
let query_for_result = query.clone();
let cancellation_token_for_result = cancellation_token.clone();
let query_for_search = query.clone();
let cancellation_token_for_search = cancellation_token.clone();
let search_state = Arc::clone(&search_state);
let search_dir = search_dir.clone();
async move {
let compute_indices = true;
let matches = spawn_blocking(move || {
file_search::run(
&query_for_search,
MAX_FILE_SEARCH_RESULTS,
&search_dir,
Vec::new(),
NUM_FILE_SEARCH_THREADS,
cancellation_token_for_search,
compute_indices,
true,
)
.map(|res| res.matches)
.unwrap_or_default()
})
.await
.unwrap_or_default();
let is_cancelled = cancellation_token.load(Ordering::Relaxed);
if !is_cancelled {
tx.send(AppEvent::FileSearchResult { query, matches });
}
let is_cancelled = cancellation_token_for_result.load(Ordering::Relaxed);
if !is_cancelled {
tx.send(AppEvent::FileSearchResult {
query: query_for_result,
matches,
});
}
// Reset the active search state. Do a pointer comparison to verify
// that we are clearing the ActiveSearch that corresponds to the
// cancellation token we were given.
{
#[expect(clippy::unwrap_used)]
let mut st = search_state.lock().unwrap();
if let Some(active_search) = &st.active_search
&& Arc::ptr_eq(&active_search.cancellation_token, &cancellation_token)
// Reset the active search state. Do a pointer comparison to verify
// that we are clearing the ActiveSearch that corresponds to the
// cancellation token we were given.
{
st.active_search = None;
#[expect(clippy::unwrap_used)]
let mut st = search_state.lock().unwrap();
if let Some(active_search) = &st.active_search
&& Arc::ptr_eq(&active_search.cancellation_token, &cancellation_token)
{
st.active_search = None;
}
}
}
});