Skip to main content

App

Struct App 

Source
pub struct App {
    pub editor_actor: EditorActorHandle,
    pub render_state: Arc<ArcSwap<RenderState>>,
    pub syntax_static_overlay_quads_cell: Arc<ArcSwap<StaticOverlayQuads>>,
    pub modeline_hits: RefCell<ModelineHitMap>,
    pub pane_hits: RefCell<PaneHitMap>,
    pub pane_render_registry: PaneRenderRegistry,
    pub theme: Theme,
    /* private fields */
}

Fields§

§editor_actor: EditorActorHandle

Composition root for the renderer-agnostic editor state.

Slice 3c.final.E.swap: the field is cfg-gated. In production builds (cfg(not(test))) the renderer holds an [EditorActorHandle] — Editor lives on its own thread and the renderer reaches it only through the handle’s blocking RPCs (mutate_blocking, with_editor, mutate_blocking_with, apply_blocking). In test builds (cfg(test)) the field keeps the original direct-ownership shape so the existing test fixtures (which mutate state without going through the dispatch path) keep compiling. This is the architectural realisation of paramount goal #4: the &mut Editor type cannot escape the actor thread in production, enforced by the type system.

§render_state: Arc<ArcSwap<RenderState>>

Phase 5.8.AF.5 / Slice 3c.atomic.A: renderer-owned clone of the editor’s Arc<ArcSwap<RenderState>>. Lets the renderer read state without going through self.editor, which is the structural seam the eventual actor migration pivots on. Today this Arc is a direct clone of editor.render_state at construction; after 3c moves Editor to its own thread, the same Arc is published from the actor thread and read here – identical contract, different writer.

§syntax_static_overlay_quads_cell: Arc<ArcSwap<StaticOverlayQuads>>

Perf plan B.2 slice B.2.a: renderer-owned clone of the editor’s syntax_static_overlay_quads_cell. The cell is the overlay worker’s output channel — written by lattice_host::overlay_worker::recompute, read by the per-frame overlay paint path. Caching the Arc on App matches the render_state pattern (slice 3c.atomic.A): pre-swap this is a direct clone at construction; post-swap the same Arc comes from the actor handle.

display-line B4.2: the dead syntax_visible_spans_cell / syntax_visible_rows_cell clones were deleted with the overlay worker’s span/row cache; this is the only worker output cell the App keeps a clone of now.

§modeline_hits: RefCell<ModelineHitMap>

ML.4: where each clickable modeline element was painted, rebuilt every frame and read when a mouse click arrives.

RefCell because the paint path takes &App and this is the one thing it produces rather than consumes. It is renderer-local by nature — a record of where THIS terminal put THIS frame’s pixels — so it lives on the TUI’s App rather than in RenderState, which is the renderer-neutral publication the GPUI peer reads too. GPUI needs no equivalent: its elements are real divs and the window system does the hit test.

§pane_hits: RefCell<PaneHitMap>

MO.2: this frame’s pane bodies, for editor-body mouse hit-testing. Same lifecycle as modeline_hits beside it — recorded during paint, cleared at the top of each frame — so a pane that stops painting stops taking clicks.

§pane_render_registry: PaneRenderRegistry

Handle to the per-document actor (DESIGN.md §5.2.1, §5.7). The actor owns the writable Document (from lattice-core); mutations route through it; reads load a versioned snapshot. Denormalized from documents[active_document_id].handle for hot-path access. Per-thread cached reader for [Self::document]’s published snapshot cell (DESIGN.md §5.6.8). The renderer’s per-frame snapshot_cache.load() returns the current Arc<DocumentSnapshot> in ~300ps in steady state (no edit since last frame); ~16ns when the actor has just published. Rebuilt whenever [Self::document] is reassigned – arc_swap::Cache caches against a specific cell, so it must follow the active document’s handle. Stable id for the active document buffer. Mirrors the active pane’s buffer_id whenever that pane holds a Document leaf. Position-history entries (§5.1.1) and per-pane state record this id; switching the active document via :bnext / :e FILE rotates Self::document / Self::syntax etc. to the new active. Pane tree (DESIGN.md §5.9). Moved to editor.pane_tree (Phase 5.B C4). In-flight partial-chord stack from the trie (slice 8.i.4). When the trie returns LookupResult::Partial, dispatch_normal / dispatch_insert emit Action::AbsorbPartialChord(c) and App::apply appends c here. The next keystroke runs through the trie with this stack as prefix and resolves the full multi-key chord. Cleared on every non-AbsorbPartialChord action. Operator-prefix pushes (8 prefixes: d, c, y, >, <, gU, gu, g~) come from AppEffect::AbsorbOperatorPrefix(_) via apply_app_effect, which also latches pending_count into op_count atomically with the prefix push. Grammar registry shared with the document actor by Arc. The actor calls lattice_grammar::execute with this registry from inside its own task. The App also reads it directly for the parser, completion pipeline, and introspection – all read-only operations. In-process event bus (DESIGN.md §5.10). The App publishes editor lifecycle events (DocumentChanged, SelectionsChanged, ModalModeChanged, BeforeSave, DocumentSaved, BeforeQuit, OptionChanged) after observing the corresponding state transitions. The App itself subscribes to OptionChanged for the cascade hook (see [Self::option_change_rx]); other subscribers (plugins, autocmds) wire up the same way. Receiver end of the App’s own subscription to EventKind::OptionChanged (DESIGN.md §5.10 + §5.12). The typed-options registry publishes through event_bus on every successful set; this channel queues those events for Self::drain_option_changes to consume on the App’s main thread. Decouples cascade timing from the publish path (publishes can come from any thread – plugin tasks, future LSP-driven config writes, the customize buffer) without risking re-entrancy on the registry mutex or the renderer.

Option only because the field needs to be take-able so the drain method can borrow &mut self for cascade work while iterating the receiver. Always Some between calls. Shared language registry for tree-sitter highlighting. One Arc<LangRegistry> services the document buffer’s Syntax AND every HelpBuffer constructed by :describe-* / :apropos / :keymap. Help bodies render with markdown highlighting (headings, fenced-block injections to the language tag) sourced from this same registry. App-side typed action IDs (CommandKind::Action registrations from crate::actions::populate). Each field is a CommandId resolving to an ActionSpec whose apply returns Effect::AppAction(AppEffect::Foo). Per- mode keymap modules consume this alongside builtins to build typed CommandInvocations for chord bindings (slice 8.i; see docs/dev/notes/8i-approach.md). Layered keymap registry (DESIGN.md §5.2.3, audit slice 8.c). Populated at construction time; the input dispatcher reads from it on every keystroke. Wait-free reads via the internal ArcSwap; concurrent registration writes (mode push/pop, plugin registration, :bind) never stall the input path. Slices 8.d / 8.e / 8.f wire Replace, Visual, and Insert through this; Normal follows in 8.g. LayerId of the active completion-popup minor-mode layer when the popup is open; None otherwise. Pushed / popped by Self::sync_keymap_overlays in lockstep with self.editor.insert_completion. Slice 8.f. LayerId of the active-snippet minor-mode layer when a snippet is in flight; None otherwise. Same lockstep pattern as [Self::completion_popup_layer]. Per-document tree-sitter state. None when the document’s language is Plain (no grammar bundled).

Audit slice 3: this is now an async handle. Reparses run on a worker task (tokio::task::spawn_blocking) so the UI thread never parses; reads against the latest snapshot are wait-free via ArcSwap. The Syntax struct itself stays accessible for one-shot users (help-buffer markdown highlighting). Slice B.3: cache key validating the contents of visible_highlights. When refresh_highlights finds the freshly-computed key matches this stored key, the existing visible_highlights is still valid and the highlight_lines call is skipped entirely (~178µs at 24-line viewport on rust per BENCHMARKS.md → noise-floor on cache hit).

Invariant: Some ⟹ visible_highlights was computed against this key’s snapshot+state. None after construction, after the syntax handle is replaced, and after a state- change render where the key check passes the recompute branch (the new key is stored).

Steady-state hit rate: ~100% (cursor blinking, no edit). Drops cleanly to 0% during edits/scroll/fold-toggle. Unified position-history ring (§5.1.1). Every entry is tagged by source, so different keybindings can iterate filtered views of the same data:

  • Ctrl-O / Ctrl-I (Tab) walk AutoJump and PluginPush.
  • g; / g, walk NamedMark.

Pushed before “big jumps” (gg, G, search submit, n / N, *, #, %, mark jumps) with AutoJump, plus on every mX with NamedMark(X). The cursor sits at one past the last navigated Manual folds. v1 supports non-nested folds defined by line range. closed=true means the fold’s interior is skipped during render. Shared typed-options registry (DESIGN.md §5.12). Every option’s current value lives in here behind an ArcSwap<T>; :set parses against it; the customize buffer view (post-1.0) reads + writes through the same surface. Renderer-agnostic options self-register via the linkme-aggregated OPTION_DECLS slice; this renderer’s own options register via the linkme slice in crate::tui_options. Hot-path read cache for the option values. Populated at Self::new time; refreshed inside the Event::OptionChanged cascade so writes through any path (cmdline, plugins, the future customize buffer) propagate. Accessor methods on App (foldmethod() / tabstop() / show_line_numbers() / …) read the cached primitive directly (~1ns field access) instead of going through the registry’s mutex + ArcSwap + downcast (~33ns). The renderer hits these accessors per visible line, so the difference is measurable on the 60-line / 120-line frame benchmarks. Single source of truth stays in [Self::config]; this struct is a derived projection. Mode registry (M.1). Owns the catalogue of registered modes; activation / deactivation routes through here. One process-shared registry; all Documents share the same mode definitions. Phase 3: typed service map subsystems hand off to modes so the mode’s Mode::on_activate can pull subsystem handles via ctx.service::<T>(). Populated at boot (LSP supervisor handle, buffer-uri resolver). Read-only after init.

M-async.1: Arc<ServiceRegistry> (not bare ServiceRegistry) because ModeContext owns its handles by Arc clone – the dispatcher does services.clone() per activation to build the owned ctx. M-async.1/2: per-(buffer, mode) Guard storage. Modes return an owned Mode::Guard from on_activate; the dispatcher stashes it here keyed by (BufferId, ModeId). On deactivation the dispatcher drops the Guard, firing its Drop impl for synchronous cleanup (unsubscribe, restore prior option, drop supervisor handle).

M-async.2: wrapped in [GuardStoreHandle] (Arc<Mutex<>>) because the spawned lifecycle task locks + inserts on on_activate resolve from a tokio worker thread; the App thread locks + removes on deactivate. Mode-keyed pane render dispatch (M.4 follow-up). Populated at boot; lookup walks active minors then the major to find the per-buffer renderer + status formatter, with the document path as the fallback when no provider matches. Replaces the helper-side match buffer.kind in draw_pane_content and pane_status_label.

§theme: Theme

Per-buffer active modes (major + minors). M.1 wired the field on Document for the document buffer, but Document lives behind the actor’s snapshot-cache, so for M.2.1 the App layer maintains a parallel per-buffer map keyed by buffers::BufferId – this is the version recompute_options_for_buffer reads to pull mode contributions. Document.modes and this map converge in M.4 when ActiveModes joins DocumentSnapshot. Per-buffer mode-owned local state (M.3.2.a). Modes populate locals via the BufferLocal typed-map during on_activate; the App routes &mut BufferLocals into the registry’s activation methods. M.3.2.b/c migrates existing per-variant data (SyntaxHandle, Vec<Fold>, etc.) into locals owned by their respective modes; until then this map exists to thread through the new activation API and to back :describe-buffer’s inspection (no entries until M.3.2.b). Per-buffer mode-resolved options cache (M.2.1, see mode-architecture.md §6.3 / §9.4 — note: the doc shows this on Document, but lattice-core cannot depend on lattice-config without a dep cycle, so the cache lives at the App layer keyed by buffers::BufferId (the App’s per-buffer key, not the lower-level lattice_protocol::BufferId). Refreshed eagerly on mode toggle and option write per §6.3.1. Reads via type-keyed access against the cached snapshot are O(1). Buffer-local explicit overrides (:setlocal foo=bar) per buffer. Inputs to resolution; the resolver chains these with mode contributions before writing [Self::resolved_options]. Empty for buffers the user has never run :setlocal against. Free-form help topic registry (DESIGN.md §5.11). :help reads from this; built-ins are sourced from docs/user/*.md at build time. Plugins / future LSP integrations register additional topics through the same registry. UI styling knobs (DESIGN.md §5.6). Carries per-pane status line colors, the inactive-pane dim overlay, separator characters, etc. Customizable via :set ui.* options.

Phase 5.3: the canonical state is [Self::host_theme] (renderer-neutral). This field is the cached ratatui-typed adapter that the TUI renderer reads on the hot path; it’s rebuilt from host_theme on every successful sync_theme_from_config. The duplication is transitional; when GPUI lands and the TUI cache moves off App, App.theme collapses into host_theme (renamed) and each renderer maintains its own cached view.

Implementations§

Source§

impl App

Source

pub fn new(document: Document) -> Self

Source

pub fn sync_keymap_overlays(&mut self)

Re-stack the Insert-mode minor-mode overlays (completion popup + active snippet) so the layered keymap registry mirrors the App’s overlay state. Called from the apply loop after every Action; cheap when nothing changed (single mutex acquisition + early return).

Push order is enforced here so popup always sits at the top of the stack when both overlays are active: the method pops everything, then pushes snippet (if active), then popup (if active). Popup’s LayerId is therefore always higher than snippet’s, and popup wins on overlapping chords (preserving the legacy “popup precedes snippet” gating in input::translate).

Slice 8.f.

Source

pub fn sync_theme_from_config(&mut self)

Re-derive App.theme’s renderer-specific Style values from the current ui.* option values in the config. Called at App-init time (after registration) and on every :set ui.* so the cached theme stays in lockstep with the canonical primitives in config.

Source

pub fn rebuild_tui_theme(&mut self)

Rebuild the cached TUI-typed crate::theme::Theme from the renderer-neutral [lattice_host::ui::theme::Theme] plus the resolved theme table (T.4). Cheap (every field is Copy); the rebuild fires only on option cascade or on a host-emitted lattice_host::dispatch::RendererSignal::ThemeChanged, never per frame — so a :colorscheme / palette swap (which bumps ResolvedTheme::version() and emits ThemeChanged) recolors the cache without any per-frame style adaptation. A future GPUI renderer implements an equivalent rebuild_gpui_theme on its own App.

Source

pub fn load_persistent_config(&mut self, workspace_root: Option<&Path>)

Load ~/.editor.config/lattice/lattice.toml (user) and <workspace_root>/.lattice/config.toml (project) in precedence order, applying scalar overrides to self.editor.config and bucketing structural sub-tables (per- language overrides, plugin sections) into self.editor.pending_config_structural_sections for their owners to drain.

Called once by the runtime startup before the main loop (so the first frame already reflects user overrides). NOT called from App::new – tests stay isolated from the user’s real ~/.editor.config/lattice/. Test fixtures that want to exercise the load path can call this directly with a synthesized workspace root.

Loader diagnostics (parse errors, unknown keys, validation rejects) collapse into a single echo at the most-severe level: Error if any file failed to parse / read, Warn if any key was rejected, otherwise silent. Per-file path:body detail rides the message body so the user can see which file complained.

Source

pub fn load_snippets_at_startup(&mut self)

Load built-in + user snippet packs into the registry at startup (built-ins 2026-06-13). Delegates to [lattice_host::dispatch::Editor::load_snippets_at_startup]. Called by the runtime right after load_persistent_config so a fresh editor has its snippet set ready; quiet (logs, no echo). Kept out of App::new so test Apps start with an empty registry.

Source

pub fn open_tutor(&mut self, lesson: u32)

T.5: open the tutor at lesson lesson. Called from lattice-cli when --tutor [N] is passed; fires after load_persistent_config so user config lands first.

Source§

impl App

Source

pub fn chord_capture_active(&self) -> bool

True when the cmdline cursor is on an ArgKind::Chord arg slot. Drives the input layer’s chord-capture overlay (translate_command_chord_capture). v1: :describe-key’s chord arg is the only Chord-kinded arg in the registry; when :map / :nnoremap land they reuse this gate.

Source§

impl App

Source

pub fn do_reload_snippets(&mut self)

:reload-snippets – 5.8.AF.3: body migrated to [lattice_host::dispatch::Editor::do_reload_snippets].

Source§

impl App

Source

pub fn do_completion_next(&mut self)

Source

pub fn do_completion_prev(&mut self)

Source

pub fn do_completion_trigger(&mut self)

Manual trigger / refresh. Opens the popup if it’s closed; refreshes raw + rendered candidates if it’s already open. Sources contributing today: buffer-words. LSP / snippets / path / tree-sitter follow in 4.2.g.2+.

Source

pub fn completion_ghost_text_suffix(&self) -> Option<String>

Suffix of the top-ranked completion candidate that would extend the user’s current query, or None when the renderer should paint nothing (Phase 4.2.g.7 ghost-text polish). Returned suffix is the part of the candidate text BEYOND the case-insensitive prefix-match against state.query. Phase 5.8.AD.4: migrated.

Returns None when:

  • completion.ghost_text option is off (default).
  • The popup is closed.
  • The top-ranked candidate doesn’t case-insensitively prefix-match the query.
  • The popup is in path-completion mode (filenames are already shown in full inside the string literal – ghost would double up).
  • The query is empty (an empty popup just lists everything; ghosting the first arbitrary candidate would surprise the user).
Source

pub fn do_completion_accept(&mut self)

Accept the focused candidate. Three routing paths:

  1. Snippet candidate (sync source gen:snippet or LSP item with insertTextFormat == Snippet): expand the body via lattice-snippet, splice the rendered text, start an ActiveSnippet.
  2. LSP candidate: apply the LSP-shaped insert (textEdit range when present) plus any additionalTextEdits as one undo unit.
  3. Sync-source candidate: simple replace-[anchor, cursor] splice.
Source

pub fn do_completion_toggle_docs(&mut self)

<C-d> inside the completion-popup minor mode. Toggles the side documentation popup. When opening, pre-fills body from the focused candidate’s cached metadata when available; fires completionItem/resolve when the documentation is missing AND the originating server advertises the resolve provider.

Source

pub fn do_completion_cancel(&mut self)

Source

pub fn do_completion_filter_to_source(&mut self, id: String)

CSM.K2: restrict the open completion popup to a single source. id is the SourceId as a raw string (e.g. "gen:buffer-words", "gen:lsp-completion"). When the referenced source has no candidates in the current state.raw, refilter yields an empty rendered list – the popup stays open so the user can switch chords or clear the filter without losing the trigger context.

Source

pub fn do_completion_filter_clear(&mut self)

CSM.K2: clear the active source filter. Phase 5.8.AD.4.

Source§

impl App

Source

pub fn dispatch_blocking( &self, invocation: CommandInvocation, ) -> Result<Effect, RuntimeError>

Block_on a grammar dispatch through the actor (DESIGN.md §5.2.1). Replaces direct lattice_grammar::execute(&self.editor.registry, &mut self.editor.document, ...) calls; the actor holds the only &mut Document and runs execute inside its task.

v1 passes a CancellationToken::never() – the input loop (lattice_ui_tui::runtime::run) is single-threaded crossterm poll, so no concurrent code path can flip the token while block_on parks the thread. The plumbing is in place for a future runtime that reads input on a separate task and flips the dispatch token on Esc; see dispatch_with_cancel on RopeDocumentHandle. 5.5.G.23: body migrated to [lattice_host::dispatch::Editor::dispatch_blocking]. Retained as a 1-line delegate while App-side helpers (run_oil_invocation / run_read_only_motion / run_document_invocation) are still hosted here.

Source

pub fn apply(&mut self, action: Action) -> bool

Returns true when the resolved binding was a grammar action that declined (Effect::Declined) — it did nothing, and the caller holding the originating KeyChord (the TUI live loop) should re-resolve the chord at the next keymap layer (AP.0.2 fall-through). The host dispatch_chord path (GPUI / tests) does this itself; the TUI’s translate→apply path lost the chord by the time the decline is known, so apply surfaces the flag and runtime.rs performs the re-resolve.

Source

pub fn drain_async_pending(&mut self)

Drain pending async results (hover, signature-help, etc.) without a full keystroke apply. Called from the TUI main loop on Wake::Repaint batches that contained no input events — the X1b gap: idle LSP responses arrive, fire paint_request, the loop wakes and redraws, but the pending channels are only drained at the apply tail so the first repaint doesn’t show the popup until the next keystroke.

Source

pub fn handle_renderer_signal(&mut self, signal: RendererSignal)

Renderer-side side-effect dispatcher. Receives every RendererSignal the host emits during a dispatch and runs the TUI-specific follow-up: ThemeChanged rebuilds the TUI Style cache from editor.host_theme; Quit is a no-op (already set on editor.should_quit, which runtime::main_loop reads each tick). A future GPUI renderer implements its own equivalent on lattice-ui-gpui::App.

Source§

impl App

Source

pub fn resolve_display(&self, category: BufferDisplayCategory) -> BufferDisplay

Resolve a BufferDisplayCategory to a concrete BufferDisplay. Reads the per-category typed option (:set <category>.display = ...) and falls back to default_display when the option resolves to BufferDisplayPreference::Default (the implicit value when the user hasn’t set it explicitly).

Reads route through the config registry’s typed-keyed get_typed::<D>() – O(1) hash lookup + an Arc::clone.

Source§

impl App

Source

pub fn recompute_folds(&mut self)

Refresh [Self::folds] from the active [FoldMethod]. manual – no-op (preserves user zf folds). The other providers (indent / markdown / syntax) replace folds with the recomputed set, preserving the closed/open state of any existing fold whose identity matches a recomputed one (so zc survives a reparse).

Syntax runs the language’s tree-sitter folds.scm query against the live parse tree and emits one fold per @fold capture spanning more than one line. When the buffer’s language doesn’t ship a folds.scm (or the parse tree hasn’t been built yet), the syntax provider cascades to the markdown / indent providers based on the file extension – so :set foldmethod=syntax is useful even on a plain-text buffer. 5.5.D: full fold recompute moved to lattice_host::editor::Editor::recompute_folds alongside recompute_syntax_folds / recompute_lsp_folds. Renderer call sites keep this thin wrapper until 5.5.G collapses App’s match entirely.

Source

pub fn line_inside_closed_fold(&self, line: u32) -> bool

5.8.U: body migrated to [lattice_host::dispatch::Editor::line_inside_closed_fold] so the GPUI peer can reach the same check.

Source

pub fn fold_start_at(&self, line: u32) -> Option<Fold>

5.5.G.23: body migrated to [lattice_host::dispatch::Editor::fold_start_at]. Retained as a delegate because the renderer’s per-frame gutter pass (search.rs, motions.rs, render.rs) and the host-side run_document_invocation both still call it before the helper deletion sweep.

Source

pub fn fold_start_at_any(&self, line: u32) -> Option<Fold>

5.5.G.23: body migrated to [lattice_host::dispatch::Editor::fold_start_at_any]. Retained as a 1-line delegate; renderer call sites retire on the same sweep as fold_start_at.

Source

pub fn auto_open_folds_at_cursor(&mut self)

5.5.G.4: body migrated to [lattice_host::dispatch::Editor::auto_open_folds_at_cursor]. Retained as a delegate because 7 ui-tui call sites (search.rs, motions.rs, dispatch.rs) still invoke it; the delegate retires when those call sites migrate.

Source§

impl App

Source

pub fn activate_document(&mut self, id: BufferId)

Switch the active document to id. Snapshots the current active state into its entry, then loads from the destination’s entry. No-op if id is already active or not registered.

5.5.F.4.2: the body relocated to [lattice_host::dispatch::Editor::activate_document]; the returned bool indicates whether the full-activation path was taken (caller runs activate_buffer_state on true). activate_buffer_state itself stays on App until F.5 lands mode lifecycle host-side.

Source

pub fn activate_buffer(&mut self, id: BufferId)

Switch the active pane to whatever buffer id references, regardless of kind. Document buffers route through activate_document; tree buffers update the active pane + load the tree’s stash; help buffers go through activate_help_in_pane.

5.5.F.4.2: the dispatch body relocated to [lattice_host::dispatch::Editor::activate_buffer]. The returned bool indicates whether the dispatch went through the full activate_document path; on true the App-side wrapper runs activate_buffer_state (mode/syntax/option re-init still on App until F.5).

Source

pub fn activate_file_tree(&mut self, id: BufferId)

5.5.F.4.2: see [lattice_host::dispatch::Editor::activate_file_tree]. No activate_buffer_state tail — tree buffers don’t have document/syntax/options state to re-resolve.

Source

pub fn activate_oil(&mut self, id: BufferId)

5.5.F.4.2: see [lattice_host::dispatch::Editor::activate_oil].

Source

pub fn pane_status_label(&self, pane: &PaneState) -> String

Pane buffer-label string — the path/dirty segment (or a pane provider’s custom label). Kept for its existing callers/tests (synthetic-name fallback, log/messages labels); the modeline renderer (draw_pane_status_line) lays out zones from the registered elements instead.

ML.3 retired the appended mode-items (LSP / diff badges) — those are registered modeline elements now, not part of this label.

Source§

impl App

Source

pub fn lsp_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.5.0: is lsp-mode active for buffer_id? Every LSP entry point (hover, completion, diagnostics-render, document-sync, …) gates on this in subsequent slices; returns true when the minor is in active_modes[buffer_id]’s minor list, false otherwise (no buffer registered, or mode not active on it).

In M.5.0 nothing reads this – the surface is here so M.5.2 (auto-activation hook), M.5.3 (lifecycle), and M.5.4+ (gates) have a single accessor to consume. 5.5.F.5.1: see [lattice_host::dispatch::Editor::lsp_mode_enabled_for].

Slice 3c.extension.fold-rs: route through the published ModesRenderState (B.11) instead of read_editor. Per-frame hot path — every paint queries this for the diagnostics / semantic-token / document-highlight / inlay-hint / progress gates, so each saved actor RPC drops ~100µs off the frame budget.

Source

pub fn completion_mode_active_for(&self, buffer_id: BufferId) -> bool

CSM.K1: is completion-mode (the persistent gate) active on buffer_id? Auto-activates on writable buffer kinds; the popup-trigger entry points check this before opening the popup so read-only buffers (Help, FileTree, Oil) silently no-op on <C-Space>.

Source

pub fn completion_popup_mode_active_for(&self, buffer_id: BufferId) -> bool

CSM.K1: is completion-popup-mode (the transient popup-live marker) active on buffer_id? Architectural answer to “is the insert-completion popup live on this buffer.” Tests + production code asking the popup-state question should read this rather than poking App.insert_completion.is_some() directly – the field is the popup’s content; the mode is the gate.

Source

pub fn completion_popup_active(&self) -> bool

Shorthand: is the insert-completion popup live on the active document buffer? The popup is anchored to the doc the user is typing in; v1 has a single self.document_buffer_id().

Source

pub fn lsp_completion_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.6.0: is lsp-completion-mode active on buffer_id? Read by do_lsp_completion_request / do_async_insert_completion_requests and the LSP completion source filter once M.6.2 / M.6.3 wire the gates.

Source

pub fn lsp_diagnostics_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.6.0: is lsp-diagnostics-mode active on buffer_id? Read by the publish-diagnostics paint pipeline and :diag-next / :diag-prev once M.6.3 wires the gate.

Source

pub fn lsp_hover_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.6.0: is lsp-hover-mode active on buffer_id? Read by do_lsp_hover_request once M.6.2 wires the gate.

Source

pub fn lsp_signature_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.6.0: is lsp-signature-mode active on buffer_id?

Source

pub fn lsp_format_mode_enabled_for(&self, buffer_id: BufferId) -> bool

M.6.0: is lsp-format-mode active on buffer_id? Gates :lsp-format / :lsp-format-range and onTypeFormatting.

Source

pub fn lsp_rename_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn lsp_symbols_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn lsp_code_action_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn lsp_nav_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn lsp_progress_mode_enabled_for(&self, buffer_id: BufferId) -> bool

4.4.c: is lsp-progress-mode active on buffer_id? Gates the modeline $/progress segment and progress accumulation for buffers attached to a server. With the mode off, incoming progress events still flow on the bus (plugins can subscribe) but the modeline stays quiet for that buffer.

Source

pub fn lsp_document_highlight_mode_enabled_for( &self, buffer_id: BufferId, ) -> bool

4.4.e: is lsp-document-highlight-mode active on buffer_id? Gates the cursor-driven textDocument/documentHighlight request issuance and the soft-highlight decoration overlay.

Source

pub fn lsp_selection_range_mode_enabled_for(&self, buffer_id: BufferId) -> bool

4.4.e: is lsp-selection-range-mode active on buffer_id? Gates textDocument/selectionRange issuance for the smart-expansion operator.

Source

pub fn lsp_folding_mode_enabled_for(&self, buffer_id: BufferId) -> bool

4.4.f: is lsp-folding-mode active on buffer_id? Gates textDocument/foldingRange issuance. Independent of the foldmethod option: when the mode is off the cache stays empty and :set foldmethod=lsp cascades to Syntax.

Source

pub fn lsp_inlay_hint_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn lsp_semantic_tokens_mode_enabled_for(&self, buffer_id: BufferId) -> bool

Source

pub fn drain_pending_hover(&mut self)

Drain the channel populated by do_lsp_hover_request and act on every pending HoverOutcome: open the popup for Body, echo a clear message for NoBody / NoServers so the user always knows their K press was processed. Called once per main_loop iteration before draw; cheap when the channel is empty (the common case).

Source

pub fn drain_pending_completion_resolve(&mut self)

Drain queued completionItem/resolve responses – decode the matching candidate’s payload, apply the resolved fields, re-encode in place, then refresh the docs-popup body when the resolved item is the popup’s currently-focused one. CSM.8b.5: state.raw is the source of truth; no parallel sidecar to keep in sync.

Source

pub fn drain_pending_insert_completion_lsp(&mut self)

Per-frame drain hook – merge any LSP completion response into the active popup’s raw set, refilter, and update the lsp_incomplete flag.

Source

pub fn drain_lsp_log_events(&mut self)

Drain queued lattice_lsp::LspLogPushed events for the App-side concerns the modes don’t own. After B’.6 the three log majors (LspLogMode, LspServerLogMode, LspTraceLogMode) own every buffer append; this drain only surfaces window/showMessage-sourced records to the minibuffer (vim’s :echom-style transient surface) so users see server-emitted notifications without opening the LSP log buffer. Multiple showMessages in one tick collapse to the last (matches successive :echo calls).

Called once per main-loop tick.

Source

pub fn drain_lsp_detach_events(&mut self)

4.4.c: drain queued LspProgressUpdate events and fold them into self.editor.lsp_progress. Begin inserts, Report updates (preserving title from the prior Begin when the report doesn’t restate it), End removes. Called once per main-loop tick.

Cheap when no events arrived: a single try_recv that returns Empty and exits. Drain queued lattice_lsp::LspBufferDetached events (published by LspMode::on_deactivate via Phase 2’s ctx.events()). For each event, call Self::lsp_close_buffer to fire the wire-level textDocument/didClose and clear the buffer’s URI mapping. Called once per main-loop tick.

Cheap when no events arrived (single try_recv → Empty). Cheap when the buffer has no URI mapping (the close path short-circuits on buffer_uris.remove returning None).

Source

pub fn fan_out_did_change_configuration(&mut self, server_id: &str)

4.4.k: fan out workspace/didChangeConfiguration to every running actor with the given server_id. Called from the typed-option cascade (the private apply_option_cascade) whenever a key under lsp.<server_id>.* changes. The notification’s settings payload is the full lsp.<server_id> JSON subtree from the merged TOML tree – matches the shape returned by workspace/configuration so servers that pull and servers that read-inline see consistent data.

Empty subtree (server doesn’t exist in TOML) still fires the notification with settings: null; per spec servers MAY interpret that as “reset to defaults”. Notify-only – no response, errors log and skip.

Cross-workspace fan-out: if two actors share server_id across different workspace roots, both receive the notification (config is global, not workspace-scoped). Thin wrapper around lattice_host::editor::Editor::fan_out_did_change_configuration (Phase 5.7.B.7 migration). Kept on impl App so the TUI peer’s handle_renderer_signal match arm doesn’t churn while the body lives host-side – the GPUI peer reaches the same logic through editor.fan_out_did_change_configuration.

Source

pub fn drain_inbound_show_message_requests(&mut self)

4.4.b: drain server-initiated Drain server-initiated window/showMessageRequest inbound requests (4.4.b). Each request comes with a prompt, an optional action list, and a oneshot for the reply. The actionless case (just an info / warn / error notification) auto-replies null and surfaces the prompt on the minibuffer + LSP log. The actionful case registers the request in lsp_pending_show_message_requests and either opens an action picker (if no picker is currently up) or queues the id behind the active one.

Picker accept (the AcceptShowMessageAction routing arm) and picker dismiss (the LspShowMessageRequest source arm) both pull the slot out, ferry back the response, then drain the queue so the next pending SMR opens on the same tick.

Source

pub fn drain_inbound_apply_edits(&mut self)

Drain server-initiated workspace/applyEdit requests (Phase 4.3). Each request lands as a lattice_lsp::InboundApplyEdit carrying a typed WorkspaceEdit + a oneshot for the response. We flatten the edit into per-file Vec<TextEdit> batches (same flatten_workspace_edit path the :rename drain uses), apply each, and reply via the oneshot.

Apply semantics mirror apply_rename_workspace_edit: edits to the active buffer land directly via apply_lsp_text_edits; cross-file edits open the target via do_edit and apply there. Failures on individual files echo a warning but don’t roll back successfully- applied files.

Source

pub fn buffer_uri(&self, id: BufferId) -> Option<Uri>

Look up the current URI of a buffer. None for buffers that have no on-disk path yet (new unsaved scratch buffers).

Source

pub fn lsp_flush(&self, buffer_id: BufferId)

Flush queued didChange events for a buffer immediately. Used by will-save hooks (4.3) so the server’s view is caught up before pre-save requests fire. Fire-and-forget against the supervisor mailbox.

Source

pub fn lsp_close_buffer(&mut self, buffer_id: BufferId)

5.5.F.4.4: see [lattice_host::dispatch::Editor::lsp_close_buffer]. App-side wrapper kept as a thin delegate because drain_lsp_detach_events (App tick path) still calls it; tests in this module call it directly. Deletes when the tick-event drain moves host-side.

Source

pub fn drain_pending_rename(&mut self)

Drain queued :rename responses; apply the WorkspaceEdit. v1: per-file edits land as one undo unit in each affected buffer.

Source

pub fn drain_pending_code_actions(&mut self)

Drain queued code-action responses. 5.8.AA.r: full apply chain (Items/Resolved/NoProvider + workspace-edit + executeCommand) hoisted to host; this wrapper exists for any remaining direct callers and the test-suite. The host drain is folded into run_tick_pending so the TUI runtime no longer needs an explicit call.

Source

pub fn drain_pending_completion(&mut self)

Drain queued LSP completion responses and open a picker. NoServers echoes; empty list echoes.

Source

pub fn drain_pending_format(&mut self)

Drain the format response channel and apply the returned edits as one undo unit. Echoes when the server returned no edits (“already formatted”) or no provider was available.

Source

pub fn drain_pending_symbols(&mut self)

Drain queued document-symbol / workspace-symbol responses and open the picker.

Source

pub fn drain_pending_moniker(&mut self)

4.5.g: drain queued moniker responses + echo. Called per main-loop tick like the other LSP drains; cheap when the channel is empty.

Source

pub fn drain_pending_signature_help(&mut self)

Drain queued signature-help responses. A non-empty body renders into the popup; empty echoes “no signature info”; NoServers echoes the standard “no LSP server” message.

Source

pub fn drain_pending_definitions(&mut self)

Drain queued nav (definition / declaration / typeDef / impl) results and act on them: 0 -> echo, 1 -> jump, N>1 -> echo count + open picker. Pushes the pre-jump cursor onto the position history so <C-o> walks back. The verb in echoes (definitions vs implementations etc.) reads from pending_nav_kind.

Source

pub fn drain_pending_references(&mut self)

Drain queued references results. The merged list is rendered as a *lsp:references* help buffer and opened in-pane via the LSP-locations picker; existing follow- link machinery (<CR> on a Source link) handles jumps. NoServers echoes “no LSP server attached”; an empty Found(_, []) echoes “no references for X”.

Source

pub fn do_list_diagnostics(&mut self)

5.5.F.7: see [lattice_host::dispatch::Editor::do_list_diagnostics]. App-side wrapper retained because three tests (app.rs::tests, lsp.rs::tests) call it directly outside the Effect-arm dispatch path.

Source

pub fn do_next_diagnostic(&mut self)

]d / :diag-next / :cnext – move the cursor to the next diagnostic in the active buffer. Wraps to top.

Source

pub fn do_prev_diagnostic(&mut self)

[d / :diag-prev / :cprev – move the cursor to the previous diagnostic in the active buffer. Wraps to bottom.

Source

pub fn do_open_lsp_log(&mut self, server_id: Option<&str>)

:lsp-log [server] – activate the subsystem-wide *lsp* buffer (no arg) or a specific server’s *lsp:<server>* buffer (with arg).

Behaviour:

  • No arg: switch to *lsp*. Captures everything the LSP subsystem logs (lifecycle, attach driver, supervisor, plus every per-server record prefixed with the server id). Always works, even when no servers are running – *lsp* is created at boot.
  • With arg: switch to *lsp:<server>* after resolving the name through the alias table. Errors if no running instance matches.

Use :lsp-server-log for the picker over running instances.

Source

pub fn do_open_lsp_trace_log(&mut self, server_id: Option<&str>)

:lsp-trace-log [server]. Phase 5.8.AD.2: migrated.

Source

pub fn do_toggle_lsp_trace(&mut self, name: &str)

:lsp-trace <name>. Phase 5.8.AD.2: migrated.

Source

pub fn do_lsp_diagnostics_to_error_list(&mut self)

EP.4: :lsp-diagnostics-to-error-list – pull the currently published diagnostics into the error list. Body lives on Editor (host-resident, like the live feed); this is the thin renderer-side delegation.

Source

pub fn do_lsp_status(&mut self)

:lsp-status – render every running server in a help-style buffer.

Source

pub fn do_lsp_server_log_listing(&mut self)

:lsp-server-log – vertico picker over every running (workspace, server_id) LSP actor. <CR> opens the per-server log (*lsp:<server>*) for the chosen row.

Source

pub fn do_lsp_restart(&mut self, server_id: &str)

:lsp-restart <server> – supervisor restart hook. Currently emits an info message; full restart-with- backoff lands in 4.4.

Source

pub fn maybe_request_folding_range(&mut self)

:lsp-progress-cancel [server] – send window/workDoneProgress/cancel for every cancellable 4.4.f: per-tick foldingRange pump. Only fires when:

  • :set foldmethod=lsp is active for the buffer, AND
  • lsp-folding-mode is enabled, AND
  • the buffer’s document version differs from the cached version (or there’s no cache), AND
  • no in-flight request is already chasing this version.

Single-flight: each new request cancels its predecessor. The drain seats the response into lsp_folds_cache and triggers recompute_folds so the fold list refreshes without the user having to do anything.

Source

pub fn maybe_request_semantic_tokens(&mut self)

4.4.h: per-tick semanticTokens/full pump. Fires when lsp-semantic-tokens-mode is on AND the buffer’s document version differs from the cache (or there’s no cache). Single-flight; the decoder runs server-side on the spawned task and the drain seats decoded tokens into the cache.

Source

pub fn maybe_request_pull_diagnostics(&mut self)

4.4.j: per-tick textDocument/diagnostic (pull-based) pump. Fires when:

  • lsp-diagnostics-mode is enabled (umbrella + diagnostics sub-mode), AND
  • the active server advertises pull diagnostics, AND
  • the buffer’s document version differs from the cached one (or there’s no cache entry).

Threads the cached result_id back via previous_result_id so the server can answer Unchanged cheaply when nothing moved. Single-flight: each new request cancels its predecessor. Failures surface as PullDiagnosticsOutcome::Empty and the drain seats a cache entry at the current version so the pump doesn’t re-fire on the next tick without an actual edit.

Source

pub fn drain_diagnostic_refresh(&mut self)

4.4.j: drain workspace/diagnostic/refresh events. Each event names a server; evict the per-buffer result_id cache for every attached buffer so the next pump tick re-pulls without a previous_result_id and the server emits a forced Full report.

Source

pub fn maybe_request_inlay_hint(&mut self)

4.4.g: per-tick inlayHint pump. Fires when:

  • lsp-inlay-hint-mode is enabled, AND
  • the buffer’s document version differs from the cache (or there’s no cache).

Single-flight: each new request cancels its predecessor. Whole-buffer range for simplicity – the LSP request signature requires a range, but production servers happily handle the entire buffer span. Viewport-only fetching is a follow-up optimization.

Source

pub fn drain_inlay_hint_refresh(&mut self)

4.4.g: drain workspace/inlayHint/refresh events. Each event names a server; clear cached inlay hints for any buffer attached to that server so the next render tick’s pump re-issues inlayHint.

Source

pub fn drain_semantic_tokens_refresh(&mut self)

4.4.i: drain workspace/semanticTokens/refresh events. Same shape as the inlay-hint refresh drain: each event names a server; drop the semantic-tokens cache for every attached buffer so the next render tick’s pump re-issues semanticTokens/full against a fresh baseline (dropping the now-stale result_id rules out a delta request that the server would reject).

4.5.c: per-tick documentLink pump. Fires on document-version change (cheap when versions match; the cache lookup short-circuits). Whole-buffer request since link ranges are typically sparse and not bound to a viewport. Single-flight per buffer; each new request cancels its predecessor.

4.5.c: follow the LSP documentLink at the cursor (the gx keystroke). Walks the cache, picks the first link whose range covers the cursor, follows its target. When the link has no target AND the server advertises documentLinkProvider.resolveProvider, fires documentLink/resolve to fill in the target before following. Echoes (no link at cursor) when the cache is empty or the cursor sits outside every cached range.

Source

pub fn maybe_request_code_lens(&mut self)

4.5.d: per-tick codeLens pump. Fires on document- version change OR cache miss (workspace/codeLens/refresh evicts the entry). Single-flight per buffer.

Source

pub fn maybe_request_document_color(&mut self)

4.5.e: per-tick documentColor pump. Same shape as the documentLink pump: fires on doc-version change, single-flight per buffer.

Source

pub fn drain_code_lens_refresh(&mut self)

4.5.d: drain workspace/codeLens/refresh events. Each event names a server; evict every cached code-lens entry that came from that server. The next pump tick re-issues textDocument/codeLens.

Source

pub fn maybe_request_document_highlight(&mut self)

4.4.e: per-tick documentHighlight pump. Compares the current cursor against the cache anchor; when they differ AND the sub-mode is on AND the buffer has an attached server advertising the capability, fires a fresh request (cancelling any in-flight).

Phase 5.8.AF.5 / Slice 3b.0: the spawned LSP request task now writes results directly into editor.lsp_document_highlights (Arc<ArcSwapOption<...>>) when the response arrives – no channel, no UI-thread drain. Self-cancelling: the cursor moves faster than the network round-trip during a /word search, so the CancellationToken invalidates every in-flight request the moment the next one fires.

Source

pub fn do_lsp_expand_region(&mut self)

4.4.e: :lsp-expand-region – structural smart- expansion. If a cached chain still applies (cursor sits inside its innermost range AND same buffer), step the index outward and apply the new selection. Otherwise fire textDocument/selectionRange and let the drain seat the chain + apply step 0 on completion.

Source

pub fn do_lsp_shrink_region(&mut self)

4.4.e: :lsp-shrink-region. Phase 5.8.AD.2: migrated.

Source

pub fn drain_pending_selection_range(&mut self)

4.4.e: drain the in-flight selectionRange response. Seats the chain into App::lsp_selection_chain and applies the step the original invocation requested.

Source

pub fn do_lsp_progress_cancel(&mut self, server_id: Option<&str>)

active progress entry (4.4.c). With server_id == Some, cancel only entries on that server; with None, cancel across every server attached to the current buffer.

The entry stays in the accumulator until the server sends the end progress notification — cancel is best-effort per spec, and the server may decline.

Source

pub fn do_set_lsp_log_level(&mut self, server_id: Option<&str>, level: &str)

:lsp-log-level [server] <level> – set the subsystem default min level (when no server) or a per-server override.

Source

pub fn do_lsp_log_clear(&mut self, server_id: Option<&str>)

:lsp-log-clear [server]. Phase 5.8.AD.2: migrated.

Source§

impl App

Source

pub fn do_open_messages(&mut self)

:messages – activate the *messages* Document buffer. 5.8.AF.3: body migrated to lattice_host::editor::Editor::do_open_messages. Wrapper fans renderer signals through handle_renderer_signal.

Source

pub fn do_open_ai_log(&mut self, provider: Option<&str>)

:ai-log [provider] – open the per-session AI log buffer (AI-1b, T12b). Thin peer forwarder: the count logic (0 → info hint, 1 → open, >1 → picker) + the buffer open live host-side in lattice_host::editor::Editor::do_open_ai_log; the GPUI peer reaches the same method. Mirrors do_open_lsp_log.

Source

pub fn open_synthetic_buffer(&mut self, name: &str, mode_id: &str)

Effect::OpenSyntheticBuffer – open a named synthetic buffer under a major mode. Thin peer forwarder to lattice_host::editor::Editor::open_synthetic_buffer; the GPUI peer reaches the same method.

Source

pub fn open_synthetic_buffer_seeded( &mut self, name: &str, mode_id: &str, content: Option<&str>, cursor: Option<Position>, activate_minor: Option<&str>, )

OC.7a: the seeded peer forwarder. Same thin shape as its neighbour — the body lives on Editor so both renderers reach one implementation.

Source

pub fn drain_message_events(&mut self)

Drain queued lattice_runtime::MessagePushed events; append each formatted record to the *messages* buffer. Called from the runtime’s per-frame tick. Coalescing matters during bursts (LSP $/progress floods, batch echo): all records in a tick land in one apply_edit_batch so the actor sees one edit per drain regardless of event rate.

Source§

impl App

Source

pub fn activate_major_for_buffer_kind( &mut self, buffer_id: BufferId, kind: BufferKind, )

5.5.F.5.3: see [lattice_host::dispatch::Editor::activate_major_for_buffer_kind]. Wrapper fans host-returned RendererSignals through Self::handle_renderer_signal.

Source

pub fn activate_mode_by_id(&mut self, buffer_id: BufferId, mode_id: ModeId)

M.5.1: programmatic activation of mode_id on buffer_id. Used by hooks (auto-activation on MajorEntered etc.) and by the auto-generated :<mode-name> toggle command. The registry decides Major-vs-Minor and runs the appropriate activation; for majors the previous major is deactivated first.

On failure, surfaces an EchoLevel::Warn and returns without mutating state. Callers that need to know the outcome can read self.editor.active_modes[buffer_id] after. 5.5.F.5.2: see [lattice_host::dispatch::Editor::activate_mode_by_id]. Wrapper fans host-returned RendererSignals through Self::handle_renderer_signal.

Source

pub fn deactivate_mode_by_id(&mut self, buffer_id: BufferId, mode_id: ModeId)

M.5.1: programmatic deactivation of mode_id on buffer_id. Symmetric to Self::activate_mode_by_id. Major deactivation leaves the buffer with no active major until the next activation; user-facing flows usually flow through the toggle command which performs swap rather than a bare deactivate. 5.5.F.5.2: see [lattice_host::dispatch::Editor::deactivate_mode_by_id]. Wrapper fans host-returned RendererSignals through Self::handle_renderer_signal.

Source

pub fn toggle_mode_by_name(&mut self, name: &str)

M.5.1: toggle a mode by name on the active pane’s buffer. This is the apply-fn target for the auto-generated :<mode-name> ex-commands (mode-architecture §9.6.1). Toggle semantics:

  • Minor: deactivate if active; activate if inactive.
  • Major: activate if not currently the major; if it’s already the active major, the registry treats this as a reload (deactivate then re-activate, per §9.6).

Activating a major that differs from the current major performs a swap – the registry deactivates the previous major before activating the new one. Active minors stay untouched across the swap (their state lives in type-keyed BufferLocals owned per-mode; no kill-all-local-variables semantics). 5.5.F.5.2: see [lattice_host::dispatch::Editor::toggle_mode_by_name]. Wrapper fans host-returned RendererSignals through Self::handle_renderer_signal.

Source

pub fn drain_mode_lifecycle_events(&mut self)

5.5.F.5.3: see [lattice_host::dispatch::Editor::drain_mode_lifecycle_events]. Wrapper fans host-returned RendererSignals through Self::handle_renderer_signal.

Source

pub fn modal_label(&self) -> &'static str

Source§

impl App

Source

pub fn set_viewport_height(&mut self, height: u32)

Source

pub fn active_pane_content_height(&self, buffer_height: u32) -> u32

Compute the active pane’s content height inside a buffer area of buffer_height rows. Mirrors the renderer’s per-pane layout: the pane tree splits the area evenly; with more than one pane, the bottom row of each pane is reserved for the status line. Returns at least 1 so callers can multiply / use without checking for zero.

Used by the runtime to feed set_viewport_height the active pane’s content height – not the full buffer area – so motions, scroll, fold-aware ensure_cursor_visible all agree with what’s actually drawn. Without this, a horizontal split clips the lower half of the upper pane: the App thinks it has the whole screen, the renderer only paints half.

Help-popup overlay (State B). When the focus has moved into a hover/help popup that paints as a centred overlay (active_buffer == Help, but the active pane still shows a Document underneath), the popup – not the pane – is the surface receiving motion. Returning the popup’s inner height here keeps ensure_cursor_visible and the renderer in sync: without it, j past the last visible popup row silently advanced cursor.line (the pane viewport is much taller than the popup, so the App thought the cursor was fine) and the renderer pinned the cursor visually to the last drawn row – so subsequent k had to “unwind” the phantom overshoot before any visible motion. Help-as-buffer (in-pane help, where pane.buffer == Help) doesn’t take this branch – the pane content height is the right answer.

Source

pub fn help_popup_inner_height(&self, buffer_height: u32) -> Option<u32>

Inner height of the hover/help popup overlay when one is active in State B (focused popup, doc still showing in the pane below). None when no overlay is active or help fills the pane (in which case the regular pane-content-height path applies).

Sizing matches render::position_help_popup exactly so the motion engine and the renderer agree on the popup viewport. Border rows (top + bottom) are subtracted; the result is the row count Paragraph actually paints into.

Source

pub fn active_buffer_id(&self) -> BufferId

Id of whichever buffer is currently active. The active pane’s buffer_id is the source of truth – documents and trees both live in Self::buffers under one id space. Help still lives outside the registry as a transient overlay; while help is active we return its id, otherwise the active pane’s id.

Source

pub fn active_cursor(&self) -> Position

Source

pub fn active_text(&self) -> Buffer

Source§

impl App

Source

pub fn show_line_numbers(&self) -> bool

:set number. Default true. Reads the active buffer’s resolved value via the hot-path cache.

Source

pub fn show_line_numbers_for(&self, buffer: BufferId) -> bool

:set number for an arbitrary buffer (per-pane resolution). Used by inactive-pane render paths so each pane’s mode stack can drive its own gutter independently of the active buffer’s settings.

Source

pub fn relative_line_numbers(&self) -> bool

:set relativenumber. Default false. When true the gutter shows distance from the cursor; the cursor’s line shows its absolute number. Implies number (vim’s behaviour) – the private apply_option_cascade cascade hook mirrors that cascade.

Source

pub fn relative_line_numbers_for(&self, buffer: BufferId) -> bool

:set relativenumber for an arbitrary buffer (per-pane resolution). Same shape as Self::show_line_numbers_for.

Source

pub fn wrap_lines(&self) -> bool

:set wrap. Default false. (v1 renderer always horizontal-scrolls; this flag is read by future B.3 polish.)

Source

pub fn wrap_lines_for(&self, buffer: BufferId) -> bool

:set wrap for an arbitrary buffer (per-pane resolution). Same shape as Self::show_line_numbers_for; used by the inactive-pane FrameView::for_buffer so each pane wraps per its own mode stack (e.g. help-mode’s Wrap = true) rather than inheriting the active buffer’s setting.

Source

pub fn sign_column_for(&self, buffer: BufferId) -> bool

:set signcolumn for an arbitrary buffer (per-pane resolution). Returns whether the gutter sign columns (diagnostics severity + diff sign) are reserved. Default true (always reserve, no layout shift); help / synthetic buffers resolve false via their mode’s signcolumn=no override. The renderer reads this — never the buffer kind.

Source

pub fn ignorecase(&self) -> bool

:set ignorecase. Default false.

Source

pub fn tabstop(&self) -> u32

:set tabstop=N. Default 8. Stored as i64 in config (the typed system’s integer type) and cast back to u32 at cache-rebuild time – the validate closure on the option caps the range to 1..=32 so the cast can never lose bits.

Source

pub fn scrolloff(&self) -> u32

:set scrolloff=N. Default 0. Same i64→u32 shape as Self::tabstop; range 0..=64.

Source

pub fn foldmethod(&self) -> FoldMethod

:set foldmethod=.... Default FoldMethod::Manual.

Source

pub fn foldenable(&self) -> bool

5.5.G.23: body migrated to [lattice_host::dispatch::Editor::foldenable]. Retained as a 1-line delegate while the renderer’s gutter + motions still reach the App surface.

Source

pub fn completion_auto_insert_single(&self) -> bool

5.5.G.23.cmdline: body migrated to [lattice_host::dispatch::Editor::completion_auto_insert_single]. Retained as a 1-line delegate; deletion follows when the remaining App callers (cmdline + completion arms) retire.

Source

pub fn recompute_options_for_buffer(&mut self, buffer: BufferId)

Delegate to lattice_host::editor::Editor::recompute_options_for_buffer. Phase 5.5.E.6 moved the body host-side; layer ordering and the resolver walk are documented on the host method.

Source

pub fn recompute_active_completion_sources_for(&mut self, buffer: BufferId)

CSM.3 (insert-completion.md §12.4): recompute the ActiveCompletionSources buffer-local for buffer by walking active_modes[buffer] and calling mode.completion_sources() on each. Aggregator reads the cached result on the popup-open / refilter path; this runs at mode-transition rate, not keystroke rate, so the allocation cost is amortised away from the hot path.

Empty in practice today – no mode contributes a source yet. CSM.4 (buffer-words-mode) is the first slice that lights up the cache; CSM.5 – CSM.8 add the rest. Until then, populate_insert_completion_sync reads the cache, finds it empty, and falls through to the v1 hardcoded calls – proving the read path works without changing behaviour. 5.5.F.5.1: see [lattice_host::dispatch::Editor::recompute_active_completion_sources_for].

Source

pub fn resolved_option<D>(&self, buffer: BufferId) -> Arc<D::Value> ⓘ
where D: OptionDecl + 'static, D::Value: Clone + Send + Sync + 'static,

Delegate to lattice_host::editor::Editor::resolved_option. Phase 5.5.E.6 moved the body host-side; this wrapper keeps the existing hot-path call sites (app.show_line_numbers_for etc.) compiling against &App without a per-site rewrite.

Source

pub fn drain_option_changes(&mut self)

Delegate to lattice_host::editor::Editor::drain_option_changes. Phase 5.5.E.6 moved the cascade body host-side; the host returns the [RendererSignal] list its cascade enqueued and the renderer fans them out through Self::handle_renderer_signal. Why a channel and not a callback: typed-option writes can originate from anywhere – the cmdline, plugin tasks (Phase 7), the customize buffer view (post-1.0), or future LSP-driven config writes. Routing every cascade through this channel keeps the per-option cascade off the publish thread.

Source

pub fn apply_per_language_toml_overrides(&mut self)

Drain every completion.per-language.<lang> structural section the loader bucketed and merge each into self.editor.per_language_completion. Per-key TOML wins over the spec defaults seeded at App::new; unset keys leave the default in place.

Called by the runtime startup right after load_persistent_config finishes. Idempotent (the bucket empties as we drain). Per-key parse warnings collapse into a single echo at Warn level the same way the loader’s other diagnostics do.

Source§

impl App

Source

pub fn popup_help(&self) -> Option<HelpBuffer>

M.4 (b): resolve the popup’s HelpBuffer through the unified registry. The field stores only the BufferId; the actual buffer lives in app.editor.buffers with BufferFlags { listed: false, hidden: true }. Returns a cloned snapshot (the rope is cheap-to-clone); None when no popup is open or the registry entry has been torn down.

Source§

impl App

Source

pub fn ad(&self) -> Arc<ActiveDocumentRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.2: wait-free snapshot of the active-buffer hot-path render state. Returns an Arc clone of RenderState.active_document. Used by renderer code that today reads app.editor.cursor / .scroll / .modal / etc. – those reads migrate to app.ad().cursor (etc.) during 3c.2 / 3c.3. After 3c.5 severs the Arc<Editor> reference, the method body flips to read from a renderer-owned render_state field; call sites stay unchanged.

Source

pub fn pin_render_state(&self)

Pin the current ActiveDocumentRenderState snapshot so every ad() call until unpin_render_state returns the same Arc. Call at the start of each frame render (before terminal.draw() in the TUI, before the GPUI render).

Source

pub fn unpin_render_state(&self)

Release the per-frame pin so the next ad() call loads a fresh snapshot from the actor. Call after each frame render completes.

Source

pub fn panes(&self) -> Arc<PanesRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.final.B (group 1): wait-free snapshot of the pane-tree sub-state. Renderer code reads app.panes().tree.X() instead of app.editor.pane_tree.X(). Body matches ad() — one Arc clone off the same Arc<ArcSwap<RenderState>> cell.

Source

pub fn buffers(&self) -> Arc<BuffersRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.final.B (group 1): wait-free snapshot of the buffer-registry sub-state. Renderer code reads app.buffers().registry.X() and app.buffers().uris.get(&id) instead of reaching through app.editor.buffers.X() / app.editor.buffer_uris.get(...).

Source

pub fn picker_state(&self) -> Arc<PickerRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.final.B (group 3): wait-free snapshot of the picker sub-state. Renderer code reads app.picker_state().state.as_deref() instead of app.editor.picker.as_ref(). Named to avoid colliding with the legacy app.editor.picker field name.

Source

pub fn completion(&self) -> Arc<CompletionRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.final.B (group 3): wait-free snapshot of the completion sub-state. Carries both the in-buffer ghost popup (insert) and the cmdline completion popup (state).

Source

pub fn popup(&self) -> Arc<PopupRenderState> ⓘ

Phase 5.8.AF.5 / Slice 3c.final.B (group 3): wait-free snapshot of the popup sub-state. Renderer code reads app.popup().is_open() / .placement / .buffer_id instead of app.editor.popup_buffer.is_some() etc.

Source

pub fn band(&self) -> Arc<PopupRenderState> ⓘ

WK.12: the minibuffer band’s published sub-state. Separate from Self::popup because both can be open at once — that independence is the point of the band.

Source

pub fn messages(&self) -> Arc<MessagesRenderState> ⓘ

Slice 3c.final.B.7: published echo-area state. Replaces read_editor(|e| e.last_message.clone()) in render.rs.

Source

pub fn modeline(&self) -> Arc<ModelineRenderState> ⓘ

Slice 3c.final.B.7: published modeline + cmdline + search state. Replaces the per-frame read_editor calls for command_line, auto_submit_after_chord, search_line.

Source

pub fn options(&self) -> Arc<OptionsRenderState> ⓘ

Slice 3c.final.B.10: published typed-options registry. Replaces read_editor(|e| e.config.get_typed::<X>()) — caller does app.options().config.get_typed::<X>().

Source

pub fn modes(&self) -> Arc<ModesRenderState> ⓘ

Slice 3c.final.B.11: published active-modes map. app.modes().map.get(&buf) replaces read_editor(|e| e.active_modes.get(&buf).cloned()).

Source

pub fn buffer_locals(&self) -> Arc<BufferLocalsRenderState> ⓘ

Slice 3c.final.B.9: published buffer-locals map. app.buffer_locals().map.get(&buf).and_then(|l| l.get::<T>()) replaces the equivalent read_editor chain.

Source

pub fn mutate_editor<F>(&mut self, f: F)
where F: FnOnce(&mut Editor) + Send + 'static,

Phase 5.8.AF.5 / Slice 3c.final.E.2: routing helper for editor mutations. Pre-swap: runs f against the in-process Editor and publishes RenderState. Post-swap (when Editor moves to the actor thread): the body delegates to self.editor_actor.mutate_blocking(Box::new(f)). The Send + 'static bounds are forward-compatible — every caller already passes a closure that satisfies them today, so the swap is a one-line change in this method’s body. Used to migrate self.editor.X(args) method call sites across the renderer App.

Source

pub fn set_pane_viewport(&mut self, idx: usize, rows: u32, cols: u32)

2026-05-27: per-pane geometry hand-off. Mirrors the GPUI peer’s set_pane_viewport. The host writes onto PaneState[idx]; for terminal-kind panes the SetPaneViewport handler also resizes alacritty + PTY so the shell wraps its output to the new column count. Without this, TUI terminal panes never reflowed on split / resize and content overflowed past the visible area.

Source

pub fn set_popup_viewport(&mut self, rows: u32, cols: u32)

PU.1b-3: floating-popup geometry hand-off. The renderer is the single authority on the popup’s inner rect (it computes it from the buffer area + popup_outer_size + placement), so it pushes the resolved inner (rows, cols) to the host each frame — exactly mirroring Self::set_pane_viewport for real panes. build_cells_panes reads popup_viewport_{height,width} to size the synthetic popup-pane DisplayMatrix. Diff-then-send in the runtime loop keeps steady-state cost at zero.

Source

pub fn set_band_viewport(&mut self, rows: u32, cols: u32)

WK.12: the band’s inner-geometry hand-off, the peer of Self::set_popup_viewport for PaneId::MINIBUFFER_BAND. Without it build_cells_panes never sizes the band’s matrix and the band paints nothing.

Source

pub fn set_completion_docs_viewport(&mut self, rows: u32, cols: u32)

PU.5c: completion-docs side-popup inner-geometry hand-off — the peer of Self::set_popup_viewport for the second synthetic popup (PaneId::COMPLETION_DOCS). build_cells_panes reads Editor::completion_docs_viewport_{height,width} to size the docs DisplayMatrix. Diff-then-send in the runtime loop keeps churn down.

Source

pub fn mutate_editor_with<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut Editor) -> R + Send + 'static, R: Send + 'static,

Variant of Self::mutate_editor for closures that return a value (typically Vec<RendererSignal> from host helpers). Same routing contract.

Source

pub fn read_editor<F, R>(&self, f: F) -> R
where F: FnOnce(&Editor) -> R + Send + 'static, R: Send + 'static,

Slice 3c.final.E.swap: read-side helper for &self methods that need to query editor state without mutating. In production it routes through the actor handle’s with_editor blocking RPC; in tests it calls the closure directly against the in-process Editor.

Source

pub fn set_message(&mut self, level: EchoLevel, text: impl Into<String>)

Thin renderer-side wrapper around lattice_host::editor::Editor::set_message.

5.5.D moved the implementation into the host so renderer and non-renderer call sites share one code path. Existing app.set_message(...) call sites in tests / boot keep working without churn; the body just routes through mutate_editor. The host-side impl preserves the legacy two-step contract: write to the echo-area slot + push to the bounded *messages* ring + emit a typed lattice_runtime::MessagePushed event so per-App isolation (one bus + ring per App) survives the move.

Source§

impl App

Source

pub fn pane_render_provider( &self, buffer_id: BufferId, ) -> Option<&PaneRenderProvider>

Resolve the PaneRenderProvider for buffer_id. Walks active minors in reverse activation order (most-recently activated wins – the same priority the option resolver uses) before falling back to the major. Returns None when nothing is registered, in which case the renderer uses its default document path.

Phase 5.6: the walk lives host-side in lattice_host::pane_render::resolve_pane_render_mode; this method is a thin renderer-side adapter that hands the host the active editor + registry and looks up the matched provider from the resulting ModeId. The two-step shape (resolve id, then registry.get) keeps the trait minimal: the host never sees the renderer-typed PaneRenderProvider.

Trait Implementations§

Source§

impl Debug for App

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for App

§

impl !RefUnwindSafe for App

§

impl !Sync for App

§

impl !UnwindSafe for App

§

impl Send for App

§

impl Unpin for App

§

impl UnsafeUnpin for App

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> IntoMaybeUndefined<T> for T

§

fn into_maybe_undefined(self) -> MaybeUndefined<T>

Converts this value into a three-state builder argument.
§

impl<T> IntoOption<T> for T

§

fn into_option(self) -> Option<T>

Converts this value into an optional builder argument.
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> Pointee for T

§

type Pointer = u32

§

fn debug( pointer: <T as Pointee>::Pointer, f: &mut Formatter<'_>, ) -> Result<(), Error>

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more