use std::sync::mpsc::Receiver;
use strop_core::worker::{FailureKind, Load, Outcome, Ticket};
use strop_picker::PickerMsg;
use super::super::events::AppEvent;
use super::super::trace;
use super::super::Editor;
use super::{PickerEvent, PickerKey, PreviewEntry, PreviewResult};
pub(crate) fn forward_picker_stream(
rx: Receiver<PickerMsg>,
ticket: Ticket<PickerKey>,
tx: super::super::events::EventSender,
) -> std::io::Result<()> {
std::thread::Builder::new()
.name("picker-bridge".into())
.spawn(move || loop {
match rx.recv() {
Ok(msg) => {
let terminal = matches!(msg, PickerMsg::Finished(_));
if tx
.send(AppEvent::Picker(PickerEvent {
ticket: ticket.clone(),
msg,
}))
.is_err()
{
return; }
if terminal {
return;
}
}
Err(_) => {
let outcome =
Outcome::failed(FailureKind::Disconnected, "picker worker channel closed");
let _ = tx.send(AppEvent::Picker(PickerEvent {
ticket: ticket.clone(),
msg: PickerMsg::Finished(outcome),
}));
return;
}
}
})
.map(|_| ())
}
impl Editor {
pub(crate) fn handle_picker_event(&mut self, event: PickerEvent) {
trace::services::picker(&event);
let Some(glue) = self.picker.as_mut() else {
return;
};
if glue.active.as_ref() != Some(&event.ticket) {
trace::services::rejected("picker", "picker request superseded or completed");
return;
}
let appended = matches!(&event.msg, PickerMsg::Items(_));
match event.msg {
PickerMsg::Items(items) => glue.picker.append(items.into_items()),
PickerMsg::Warning(message) => glue.picker.error = Some(message),
PickerMsg::Finished(outcome) => {
glue.active = None;
glue.rx = None;
glue.picker.streaming = false;
glue.worker = None;
if let Outcome::Failed { failure, .. } = outcome {
glue.picker.error = Some(failure.message);
glue.accept_when_ranked = false;
}
}
}
if appended {
self.request_picker_ranking();
}
self.finish_pending_picker_accept();
}
pub(crate) fn handle_preview(&mut self, result: PreviewResult) {
let path = result.ticket.key.path.clone();
if !self
.preview_loads
.get(&path)
.is_some_and(|load| load.owns(&result.ticket))
{
trace::services::rejected("preview", "preview request superseded");
return;
}
self.worker_handles.remove(&result.ticket.request);
self.preview_loads.remove(&path);
if !self
.picker
.as_ref()
.is_some_and(|glue| glue.id == result.ticket.key.picker)
{
trace::services::rejected("preview", "picker closed");
return;
}
strop_trace::record_with(strop_trace::EventKind::JobFinished, || {
let outcome = match &result.outcome {
Outcome::Success(text) => {
serde_json::json!({"result":"success","bytes":text.rope.len_bytes()})
}
Outcome::Failed { failure, .. } => serde_json::json!({
"result":"failed","kind":format!("{:?}",failure.kind),
"message":failure.message}),
Outcome::Cancelled(reason) => serde_json::json!({
"result":"cancelled","reason":format!("{reason:?}")}),
};
serde_json::json!({
"service":"preview","request":result.ticket.request.get(),
"path":path.to_string_lossy(),"outcome":outcome,
})
});
let key = result.ticket.key;
match result.outcome {
Outcome::Success(prepared) => {
self.previews.insert(
path.clone(),
PreviewEntry {
rope: prepared.rope,
},
);
self.preview_loads.insert(path, Load::Ready(key));
}
Outcome::Failed { failure, .. } => {
self.message = format!("preview: {}", failure.message);
self.preview_loads
.insert(path, Load::Failed { key, failure });
}
Outcome::Cancelled(reason) => {
self.preview_loads
.insert(path, Load::Cancelled { key, reason });
}
}
}
}