Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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);
                });
            });
        });
    }
}