Repository: helix-editor/helix
File: helix-term/src/handlers/diagnostics.rs (Rust)

Code before:

#[derive(Debug)]
pub(super) struct PullDiagnosticsHandler {
    no_inter_file_dependency_timeout: Option<tokio::time::Instant>,
}

impl PullDiagnosticsHandler {
    pub fn new() -> PullDiagnosticsHandler {
        PullDiagnosticsHandler {
            no_inter_file_dependency_timeout: None,
        }
    }
}

const TIMEOUT: Duration = Duration::from_millis(500);
const TIMEOUT_NO_INTER_FILE_DEPENDENCY: Duration = Duration::from_millis(125);

impl helix_event::AsyncHook for PullDiagnosticsHandler {
    type Event = PullDiagnosticsEvent;

    fn handle_event(
        &mut self,
        event: Self::Event,
        timeout: Option<tokio::time::Instant>,
    ) -> Option<tokio::time::Instant> {
        if timeout.is_none() {
            dispatch_pull_diagnostic_for_document(event.document_id, false);
            self.no_inter_file_dependency_timeout = Some(Instant::now());
        }

        if self
            .no_inter_file_dependency_timeout
            .is_some_and(|nifd_timeout| {
                nifd_timeout.duration_since(Instant::now()) > TIMEOUT_NO_INTER_FILE_DEPENDENCY
            })
        {
            dispatch_pull_diagnostic_for_document(event.document_id, true);
            self.no_inter_file_dependency_timeout = Some(Instant::now());
        };

        Some(Instant::now() + TIMEOUT)
    }

    fn finish_debounce(&mut self) {
        dispatch_pull_diagnostic_for_open_documents();
    }
}

fn dispatch_pull_diagnostic_for_document(
    document_id: DocumentId,
    exclude_language_servers_without_inter_file_dependency: bool,

Review comment (suggestion):
the logic here does not make sense to me. The no_inter_file_dependency timeout does not really work. What I would expect is the following:

* have a debuounce of 125ms until we refresh diagnostics for the current document
* if there are lsps with inter-file dependencies then refresh all open documents registered with one of the inter-file LSPs active for the current document.

This would be structured as the following:

* change event triggers a short debounce (125ms) and at the end requests diagnostic locally
* when the local debounces finishes and the set of active language servers with inter-file dependencies is not-empy, we send another event (containing the set of active lsp with inter-file dependencies and the active document) to a second handler with a larger debounce (500ms?) that will request diagnostics for all documents for those lsps (and exclude the document that orginated the request)

Code after:
            send_blocking(
                &tx_all_documents,
                PullAllDocumentsDiagnosticsEvent {
                    language_servers: inter_file_dependencies_language_servers,
                },
            );
        }
        Ok(())
    });

    register_hook!(move |event: &mut DocumentDidOpen<'_>| {
        request_document_diagnostics(event.editor, event.doc);

        Ok(())
    });

    register_hook!(move |event: &mut LanguageServerInitialized<'_>| {
        let doc_ids: Vec<_> = event.editor.documents.keys().copied().collect();

        for doc_id in doc_ids {
            request_document_diagnostics(event.editor, doc_id);
        }

        Ok(())
    });
}

#[derive(Debug, Default)]
pub(super) struct PullDiagnosticsHandler {
    document_ids: HashSet<DocumentId>,
}

impl helix_event::AsyncHook for PullDiagnosticsHandler {
    type Event = PullDiagnosticsEvent;

    fn handle_event(
        &mut self,
        event: Self::Event,
        _timeout: Option<tokio::time::Instant>,
    ) -> Option<tokio::time::Instant> {
        self.document_ids.insert(event.document_id);
        Some(Instant::now() + Duration::from_millis(250))
    }

    fn finish_debounce(&mut self) {
        let document_ids = mem::take(&mut self.document_ids);
        job::dispatch_blocking(move |editor, _| {
            for document_id in document_ids {
                request_document_diagnostics(editor, document_id);
            }
        })