vorto 0.15.0

A Vim-flavored modal terminal editor with batteries included: tree-sitter, LSP, fuzzy pickers, vim-surround, multi-cursor, and optional Copilot.
//! 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>>,
    },
    /// A chunk of output read from the in-app agent's PTY (see
    /// [`crate::agent::AgentSession`]). The main loop appends it to the
    /// session's retained buffer and redraws. Chunks are sent as the
    /// reader thread receives them; coalescing is left to the OS pipe
    /// buffering.
    AgentOutput(Vec<u8>),
    /// The agent process exited / its PTY closed (reader thread saw
    /// EOF). The main loop closes the agent pane and drops the process.
    AgentExited,
}