mirror of https://github.com/helix-editor/helix
Use an AsyncHook for picker preview highlighting
The picker previously used the IdleTimeout event as a trigger for syntax-highlighting the currently selected document in the preview pane. This is a bit ad-hoc now that the event system has landed and we can refactor towards an AsyncHook (like those used for LSP completion and signature-help). This should resolve some odd scenarios where the preview did not highlight because of a race between the idle timeout and items appearing in the picker.pull/9647/head
parent
1bad3b0dd4
commit
dae3841a75
@ -0,0 +1,117 @@
|
|||||||
|
use std::{path::Path, sync::Arc, time::Duration};
|
||||||
|
|
||||||
|
use helix_event::AsyncHook;
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
job,
|
||||||
|
ui::{menu::Item, overlay::Overlay},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{CachedPreview, DynamicPicker, Picker};
|
||||||
|
|
||||||
|
pub(super) struct PreviewHighlightHandler<T: Item> {
|
||||||
|
trigger: Option<Arc<Path>>,
|
||||||
|
phantom_data: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Item> Default for PreviewHighlightHandler<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
trigger: None,
|
||||||
|
phantom_data: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Item> AsyncHook for PreviewHighlightHandler<T> {
|
||||||
|
type Event = Arc<Path>;
|
||||||
|
|
||||||
|
fn handle_event(
|
||||||
|
&mut self,
|
||||||
|
path: Self::Event,
|
||||||
|
timeout: Option<tokio::time::Instant>,
|
||||||
|
) -> Option<tokio::time::Instant> {
|
||||||
|
if self
|
||||||
|
.trigger
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|trigger| trigger == &path)
|
||||||
|
{
|
||||||
|
// If the path hasn't changed, don't reset the debounce
|
||||||
|
timeout
|
||||||
|
} else {
|
||||||
|
self.trigger = Some(path);
|
||||||
|
Some(Instant::now() + Duration::from_millis(150))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_debounce(&mut self) {
|
||||||
|
let Some(path) = self.trigger.take() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
job::dispatch_blocking(move |editor, compositor| {
|
||||||
|
let picker = match compositor.find::<Overlay<Picker<T>>>() {
|
||||||
|
Some(Overlay { content, .. }) => content,
|
||||||
|
None => match compositor.find::<Overlay<DynamicPicker<T>>>() {
|
||||||
|
Some(Overlay { content, .. }) => &mut content.file_picker,
|
||||||
|
None => return,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(CachedPreview::Document(ref mut doc)) = picker.preview_cache.get_mut(&path)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if doc.language_config().is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(language_config) = doc.detect_language_config(&editor.syn_loader.load())
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
doc.language = Some(language_config.clone());
|
||||||
|
let text = doc.text().clone();
|
||||||
|
let loader = editor.syn_loader.clone();
|
||||||
|
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let Some(syntax) = language_config
|
||||||
|
.highlight_config(&loader.load().scopes())
|
||||||
|
.and_then(|highlight_config| {
|
||||||
|
helix_core::Syntax::new(text.slice(..), highlight_config, loader)
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
log::info!("highlighting picker item failed");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
job::dispatch_blocking(move |editor, compositor| {
|
||||||
|
let picker = match compositor.find::<Overlay<Picker<T>>>() {
|
||||||
|
Some(Overlay { content, .. }) => Some(content),
|
||||||
|
None => compositor
|
||||||
|
.find::<Overlay<DynamicPicker<T>>>()
|
||||||
|
.map(|overlay| &mut overlay.content.file_picker),
|
||||||
|
};
|
||||||
|
let Some(picker) = picker else {
|
||||||
|
log::info!("picker closed before syntax highlighting finished");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(CachedPreview::Document(ref mut doc)) =
|
||||||
|
picker.preview_cache.get_mut(&path)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let diagnostics = helix_view::Editor::doc_diagnostics(
|
||||||
|
&editor.language_servers,
|
||||||
|
&editor.diagnostics,
|
||||||
|
doc,
|
||||||
|
);
|
||||||
|
doc.replace_diagnostics(diagnostics, &[], None);
|
||||||
|
doc.syntax = Some(syntax);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue