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
//! Unified event type for the main loop.
//!
//! Terminal input and LSP reader threads both feed into a single
//! `mpsc::Sender<AppEvent>` so the main loop can block on one channel
//! and drain bursts of either kind.
use std::path::PathBuf;
use crossterm::event::Event;
use crate::copilot::{CopilotClient, CopilotEvent};
use crate::finder::PreviewEntry;
use crate::lsp::{LspClient, LspEvent};
use crate::syntax::Engine;
pub enum AppEvent {
Term(Event),
Lsp(LspEvent),
/// Reader-thread event from the Copilot LSP client. The main loop
/// hands these to [`crate::app::App::handle_copilot_event`].
Copilot(CopilotEvent),
/// Worker-thread completion for [`crate::app::App::spawn_copilot_if_needed`].
/// `Ok(Some(client))` → adopt the client; `Ok(None)` → binary not
/// on PATH (silent); `Err` → handshake failed (logged, no UI).
/// Run off the main thread so startup doesn't block on Copilot's
/// initialize round-trip (Node start-up + GitHub Copilot init can
/// be 500ms–2s).
CopilotReady {
result: anyhow::Result<Option<CopilotClient>>,
},
/// A worker thread spawned by `open_path` finished building a
/// tree-sitter highlighter (grammar dlopen + query compile + initial
/// parse). `gen` is the generation the worker was spawned for — the
/// main loop drops the event when `app.open_gen != gen` so a stale
/// result from a previous file doesn't clobber the current buffer.
EngineReady {
generation: u64,
result: anyhow::Result<Engine>,
},
/// A worker thread finished spawning an LSP client and running its
/// `initialize` handshake. The main loop adopts the client and
/// fires `didOpen` with a fresh snapshot of the current buffer.
/// `client_key` is the per-server identifier (`"<lang>::<server>"`)
/// the coordinator stores the client under; one of these events is
/// emitted per `[[languages.<lang>.lsp]]` entry configured for the
/// opened file.
LspReady {
generation: u64,
client_key: String,
lang: String,
path: PathBuf,
result: anyhow::Result<LspClient>,
},
/// The fuzzy-finder preview worker finished building a highlighted
/// snapshot for a file. The main loop drops it into the preview LRU.
/// Stale results are kept anyway — the LRU is keyed by path, so a
/// late-arriving response just becomes a cheap cache entry for next
/// time the user navigates back to that file.
PreviewReady(PreviewEntry),
/// A worker thread finished installing a tree-sitter grammar
/// (fetch + in-process compile + query vendoring). Fired by
/// [`crate::app::App::spawn_grammar_install`]. On `Ok` the main loop
/// updates the `:grammar` modal (if open) and re-highlights every
/// open buffer whose language uses the freshly-installed grammar;
/// on `Err` it surfaces a toast and reverts the modal row to
/// "missing". Not generation-gated — a grammar install is a global
/// side effect, not tied to whichever file is active.
GrammarInstalled {
name: String,
result: anyhow::Result<()>,
},
/// A worker thread finished reading the HEAD blob for an opened
/// file (two `git` subprocesses). Computed off-thread so the
/// initial buffer paint isn't blocked on git — the gutter diff
/// fills in a frame later. `base` is `None` when the file isn't in
/// a git repo. Reconciled against `open_gen` like the other
/// open-time workers so a stale result from a previous file is
/// dropped.
VcsBaseReady {
generation: u64,
path: PathBuf,
base: Option<Vec<String>>,
},
}