pub mod fswatch;
pub mod git;
pub mod highlight;
pub mod image_decode;
pub use git::GitCache;
use std::path::PathBuf;
use tokio::sync::mpsc;
use crate::app::state::{AppState, GitDirState, GitFileStatus};
use crate::preview::provider::PreviewContent;
pub fn channel() -> (mpsc::Sender<WorkerMsg>, mpsc::Receiver<WorkerMsg>) {
mpsc::channel(64)
}
#[derive(Debug)]
pub enum WorkerMsg {
Git {
path: PathBuf,
state: Option<GitDirState>,
file_statuses: Vec<(String, GitFileStatus)>,
},
FsChanged {
path: PathBuf,
},
#[allow(dead_code)]
Preview {
generation: u64,
path: PathBuf,
content: PreviewContent,
truncated: bool,
is_text: Option<bool>,
},
#[allow(dead_code)]
ImageMeta {
generation: u64,
path: PathBuf,
content: PreviewContent,
},
TerminalOutput {
id: u64,
},
TerminalExited {
id: u64,
code: Option<u32>,
},
TransferProgress {
id: u64,
done: usize,
total: usize,
},
TransferDone {
report: crate::actions::transfer::TransferReport,
},
}
pub fn merge(msg: WorkerMsg, state: &mut AppState) {
match msg {
WorkerMsg::Git {
path,
state: git_state,
file_statuses,
} => {
if path != state.cwd {
tracing::debug!(
?path,
cwd = ?state.cwd,
"dropping stale Git result for different directory"
);
return;
}
state.git = git_state;
for entry in state.entries.iter_mut() {
let status = file_statuses
.iter()
.find(|(name, _)| *name == entry.file_name)
.map(|(_, s)| s.clone());
entry.git_status = status;
}
state.dirty = true;
tracing::debug!(?path, "merged Git worker result");
}
WorkerMsg::FsChanged { path } => {
tracing::debug!(?path, "FsChanged received in merge (handled by event loop)");
}
WorkerMsg::Preview {
generation,
path,
content,
truncated,
is_text,
} => {
if let Some(is_text) = is_text {
state.classify_entry(&path, is_text);
}
if generation != state.preview.generation {
tracing::debug!(
generation,
current = state.preview.generation,
"dropping stale Preview result (generation mismatch)"
);
return;
}
if path != state.preview.for_path {
tracing::debug!(
?path,
current_path = ?state.preview.for_path,
"dropping stale Preview result (path mismatch)"
);
return;
}
state.preview.content = content;
state.preview.truncated = truncated;
state.dirty = true;
tracing::debug!(?path, generation, truncated, "merged Preview worker result");
}
WorkerMsg::ImageMeta {
generation,
path,
content,
} => {
if generation != state.preview.generation {
tracing::debug!(
generation,
current = state.preview.generation,
"dropping stale ImageMeta result (generation mismatch)"
);
return;
}
if path != state.preview.for_path {
tracing::debug!(
?path,
current_path = ?state.preview.for_path,
"dropping stale ImageMeta result (path mismatch)"
);
return;
}
state.preview.content = content;
state.preview.truncated = false;
state.dirty = true;
tracing::debug!(?path, generation, "merged ImageMeta worker result");
}
WorkerMsg::TerminalOutput { id } => {
tracing::trace!(id, "terminal output");
state.terminal.note_output();
}
WorkerMsg::TerminalExited { id, code } => {
tracing::debug!(id, ?code, "terminal shell exited");
if state.terminal.on_exit(id) {
state.dirty = true;
}
}
WorkerMsg::TransferProgress { id, done, total } => {
if state.transfers.progress(id, done, total) {
state.dirty = true;
}
}
WorkerMsg::TransferDone { report } => {
crate::actions::transfer::finish(state, report);
}
}
}