pub struct FrameView<'a> {Show 15 fields
pub app: &'a App,
pub folds: Arc<[Fold]>,
pub show_line_numbers: bool,
pub relative_line_numbers: bool,
pub foldenable: bool,
pub fold_index: FoldIndex,
pub inlay_hints: Arc<[InlayHintRow]>,
pub lsp_mode_enabled: bool,
pub lsp_diagnostics_enabled: bool,
pub lsp_semantic_tokens_enabled: bool,
pub lsp_document_highlight_enabled: bool,
pub lsp_progress_enabled: bool,
pub wrap_lines: bool,
pub sign_column: bool,
pub content_left_pad: u32,
}Expand description
Per-render-chain snapshot of App state the renderer reads.
Audit slice 7 / M2. The renderer is one of multiple peer renderer implementations (TUI today, GPUI as part of 1.0, future WebRenderer). The architecture is renderer-agnostic: no render path may depend on single-threaded discipline as its safety mechanism, because GPUI runs on a separate thread from the App’s input loop.
FrameView is taken once at entry to each render chain
(compose_visible_lines, draw_inactive_document) and
threaded into the chain’s helpers. Internal reads then go
through immutable Arc-shared / by-value snapshots; an async
mutator that writes the underlying App fields can no longer
produce a torn mid-render view, regardless of which thread
the renderer runs on.
Fields:
app: &App– stable App fields (cursor, modal, command_line, picker, …) that don’t mutate during a render pass even under multi-thread rendering. Read directly through this borrowed reference.folds: Arc<[Fold]>– frozen snapshot. Replaces directapp.editor.folds.iter()reads.show_line_numbers: bool– cached typed-options value. The typed-options ArcSwap read is wait-free per call, but caching once per chain keeps gutter computation deterministic if the option flips mid-chain under multi-thread input.
app.editor.lsp_diagnostics is left as a borrowed
&DiagnosticsLayer because that layer is already wait-free
behind its own ArcSwap (audit slice 2); the existing
line_severity / diagnostics_on_line API is structurally
safe to call from any thread.
Fields§
§app: &'a App§folds: Arc<[Fold]>§show_line_numbers: bool§relative_line_numbers: boolM.4: resolved per-pane in for_buffer; tracks the active
buffer’s setting in from_app. Reading this through the
view lets per-pane render paths route consistently.
foldenable: boolSlice 3c.extension.fold-rs: cache foldenable at view
construction. Prior to this, view.line_inside_closed_fold
and friends called self.app.foldenable() per line, each
triggering an actor mailbox round-trip (~µs–tens-of-µs).
One pre-cached bool per frame replaces 120+ RPCs in the
compose loop.
fold_index: FoldIndexPerf plan C: O(log folds) lookup index built once per frame
from folds + foldenable. The compose loop’s per-line
line_inside_closed_fold check used to walk every fold per
row (iter().any(...) — O(rows × folds)); via this index it
becomes a partition-point binary search with a constant-time
fast path for the common non-overlapping case.
inlay_hints: Arc<[InlayHintRow]>Fold-bleed follow-up (2026-06-30): this pane’s OWN byte-baked
inlay-hint rows, resolved via RenderState::inlay_hints_for_buffer
(active → baked syntax.inlay_hints; inactive → published
cells.panes entry). One source for both focus states so the
compose loop splices hints through a single path — no
active-vs-inactive divergence to drift.
lsp_mode_enabled: boolSlice 3c.extension.fold-rs: per-frame LSP-mode gates,
cached once at FrameView::from_app so the compose loop’s
per-line decoration checks don’t pay actor-RPC cost. Each
is one read_editor at frame entry; a 120-row paint that
previously triggered 120× per-line RPC for
app.lsp_semantic_tokens_mode_enabled_for(...) now reads
view.lsp_semantic_tokens_enabled directly.
lsp_diagnostics_enabled: bool§lsp_semantic_tokens_enabled: bool§lsp_document_highlight_enabled: bool§lsp_progress_enabled: boolSlice A.2b.2: inlay-hint mode gate moved to publish-time
(Editor::build_active_inlay_hints returns an empty list
when the mode is off). The compose loop no longer reads
this field; rs.syntax.inlay_hints is already gated, so
is_empty() on the published list is the cheap fast-path
check.
wrap_lines: boolWhether soft-wrap is enabled for this pane’s buffer. Global
option today (option_cache.wrap_lines); the seam for
per-buffer options: when buffer-local options land,
for_buffer resolves from that buffer’s local value with
the global default as fallback (emacs buffer-local pattern).
Compose paths read view.wrap_lines instead of touching
app.ad().option_cache directly so the resolver is always
in one place.
sign_column: boolPU.1b-1a (signcolumn): whether to reserve this pane’s gutter
sign columns (diagnostics severity + diff sign). Resolved
per-buffer like every other view option — from_app reads the
active buffer’s option_cache.sign_column; for_buffer reads
app.sign_column_for(buffer_id). The compose path reserves the
two sign cells iff this is true, so a buffer with
signcolumn=no (help-mode, synthetic buffers) renders
gutterless without the renderer knowing it’s help.
content_left_pad: u32DB.4: extra leading gutter cells to horizontally centre the buffer’s
content (dashboard). Added to the computed gutter width for both
document lines and virtual rows, so content + cursor shift right. 0
for every non-centred buffer.
Implementations§
Source§impl<'a> FrameView<'a>
impl<'a> FrameView<'a>
Sourcepub fn from_app(app: &'a App) -> Self
pub fn from_app(app: &'a App) -> Self
Snapshot the App’s per-render-chain state once.
Arc::from(Vec<T>) is one alloc + a memcpy of the
slice metadata; the underlying span / fold data already
lives in heap-allocated vecs, so the snapshot cost is
O(folds.len() + viewport_height) – negligible at
terminal sizes. GPUI-era multi-thread rendering can call
this from the render thread without taking any App
lock; the App’s main loop owns the underlying vecs and
the snapshot is consistent at the moment from_app runs.
Sourcepub fn for_buffer(app: &'a App, buffer_id: BufferId) -> Self
pub fn for_buffer(app: &'a App, buffer_id: BufferId) -> Self
M.4: per-pane FrameView – resolves options for buffer_id
instead of capturing the active buffer’s settings. Used by
inactive-pane render paths so each pane’s mode stack drives
its own gutter independently.
DR.2: inactive panes now source decorations from their own
per-pane DisplayMatrix; pane_highlights is retired.
Sourcepub fn fold_start_at_any(&self, line: u32) -> Option<&Fold>
pub fn fold_start_at_any(&self, line: u32) -> Option<&Fold>
Mirror of App::fold_start_at_any but reads from the
frozen view.folds snapshot instead of app.editor.folds.
Used by the gutter glyph provider so the renderer’s view
of folds can’t go out of sync with the snapshot it took
at chain entry.
Sourcepub fn fold_start_at(&self, line: u32) -> Option<&Fold>
pub fn fold_start_at(&self, line: u32) -> Option<&Fold>
Mirror of App::fold_start_at – only matches CLOSED
folds at line. Reads from the frozen view.folds
snapshot.
Sourcepub fn line_inside_closed_fold(&self, line: u32) -> bool
pub fn line_inside_closed_fold(&self, line: u32) -> bool
Mirror of App::line_inside_closed_fold reading from
the snapshot.
Perf plan C: routes through the per-frame
lattice_host::folds::FoldIndex so the per-line cost in
compose loops drops from O(folds) to O(log folds) amortized
constant. The foldenable short-circuit is baked into the
index at construction time — no extra branch here.
Auto Trait Implementations§
impl<'a> !RefUnwindSafe for FrameView<'a>
impl<'a> !Send for FrameView<'a>
impl<'a> !Sync for FrameView<'a>
impl<'a> !UnwindSafe for FrameView<'a>
impl<'a> Freeze for FrameView<'a>
impl<'a> Unpin for FrameView<'a>
impl<'a> UnsafeUnpin for FrameView<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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