pub struct Buffer { /* private fields */ }Expand description
Per-window view onto a Content.
Buffer is the type the rest of hjkl-buffer — and all consumers —
use directly. It owns exactly the state that is local to one editor
window:
cursor— the charwise caret for this window.
All document-level state (text rows, dirty generation, folds) lives on
the inner Content and is accessed via Arc<Mutex<Content>>.
Two Buffer instances that share the same Arc share text + folds
but carry independent cursors — the Helix Document+View model.
§Send + Sync
Arc<Mutex<Content>> is Send + Sync, so Buffer remains Send.
The engine trait surface requires Buffer: Send; this constraint
drove the choice of Mutex over RefCell. The mutex is never
contended in normal operation (single-threaded app loop), so the
lock cost is negligible (~5 ns uncontested).
§0.8.0 migration notes
The existing constructors (Buffer::new, Buffer::from_str,
Buffer::replace_all, etc.) keep the same external signatures.
Callers that do not need multi-window sharing see no behaviour change.
Use Buffer::new_view to create a second window onto the same
Content.
§Viewport
The lines invariant — at least one entry, never empty — is
preserved by every mutation. The viewport itself (top_row, top_col,
width, height, wrap, text_width) lives on the engine Host adapter;
methods that need it take a &Viewport / &mut Viewport parameter
so the rope-walking math stays here while runtime state lives there.
Implementations§
Source§impl Buffer
impl Buffer
Sourcepub fn from_str(text: &str) -> Self
pub fn from_str(text: &str) -> Self
Build a buffer from a flat string. Splits on \n; a trailing
\n produces a trailing empty line (matches every text
editor’s behaviour and keeps from_text(buf.as_string()) an
identity round-trip in the common case).
Sourcepub fn new_view(content: Arc<Mutex<Content>>) -> Self
pub fn new_view(content: Arc<Mutex<Content>>) -> Self
Create a second per-window view onto existing Content.
The new Buffer shares text + folds with every other view on the
same Arc. Its cursor starts at (0, 0) independently. This is
the primary entry point for split-window features.
let a = Buffer::from_str("hello\nworld");
let content = a.content_arc();
let mut b = Buffer::new_view(Arc::clone(&content));
// Cursors are independent.
let mut a = Buffer::new_view(Arc::clone(&content));
a.set_cursor(Position::new(1, 0));
assert_eq!(b.cursor(), Position::new(0, 0));Sourcepub fn content_arc(&self) -> Arc<Mutex<Content>>
pub fn content_arc(&self) -> Arc<Mutex<Content>>
Return a clone of the Arc<Mutex<Content>> so callers can
create additional views with Buffer::new_view.
Sourcepub fn lines(&self) -> Vec<String>
pub fn lines(&self) -> Vec<String>
Returns a snapshot of every line as an owned Vec<String>.
Owned rather than &[String] because a Buffer is a per-window
view onto a shared Content; another view could mutate the rope
between when this returns and when the caller reads the slice,
invalidating any borrowed reference.
Sourcepub fn line(&self, row: usize) -> Option<String>
pub fn line(&self, row: usize) -> Option<String>
Returns a clone of the line at row, or None if out of bounds.
Owned rather than Option<&str> for the same reason as Buffer::lines:
another view sharing the same Content could reallocate the backing Vec
between the lock release and the caller’s use of the reference.
pub fn cursor(&self) -> Position
pub fn dirty_gen(&self) -> u64
Sourcepub fn set_cursor(&mut self, pos: Position)
pub fn set_cursor(&mut self, pos: Position)
Set cursor without scrolling. Clamps to valid positions.
The optional sticky column for j/k motions is not reset
by this call — it survives set_cursor intentionally.
Sourcepub fn ensure_cursor_visible(&mut self, viewport: &mut Viewport)
pub fn ensure_cursor_visible(&mut self, viewport: &mut Viewport)
Bring the cursor into the visible Viewport, scrolling by the
minimum amount needed.
Sourcepub fn cursor_screen_row(&self, viewport: &Viewport) -> Option<usize>
pub fn cursor_screen_row(&self, viewport: &Viewport) -> Option<usize>
Cursor’s screen row offset (0-based) from viewport.top_row.
Sourcepub fn screen_rows_between(
&self,
viewport: &Viewport,
start: usize,
end: usize,
) -> usize
pub fn screen_rows_between( &self, viewport: &Viewport, start: usize, end: usize, ) -> usize
Number of screen rows the doc range start..=end occupies.
Sourcepub fn max_top_for_height(&self, viewport: &Viewport, height: usize) -> usize
pub fn max_top_for_height(&self, viewport: &Viewport, height: usize) -> usize
Earliest top_row such that screen_rows_between(top, last)
is at least height.
Sourcepub fn clamp_position(&self, pos: Position) -> Position
pub fn clamp_position(&self, pos: Position) -> Position
Clamp pos to the buffer’s content.
Sourcepub fn replace_all(&mut self, text: &str)
pub fn replace_all(&mut self, text: &str)
Replace the buffer’s full text in place. Cursor is clamped to the new content.
Source§impl Buffer
impl Buffer
Sourcepub fn apply_edit(&mut self, edit: Edit) -> Edit
pub fn apply_edit(&mut self, edit: Edit) -> Edit
Apply edit and return the inverse. Pushing the inverse back
through apply_edit restores the previous state, making it the
single hook for undo-stack integration.
apply_edit is the only way to mutate buffer text.
§Post-conditions
After any Edit variant:
Buffer::dirty_genis incremented exactly once.- The cursor is repositioned to a sensible place for the edit kind
(insert lands past the inserted content; delete lands at the
start). Callers that need to override the new cursor must call
Buffer::set_cursorimmediately after. - All
Positionvalues the caller held from before the edit may be invalid. Re-derive from row / col deltas; do not cache.
Source§impl Buffer
impl Buffer
Sourcepub fn folds(&self) -> Vec<Fold>
pub fn folds(&self) -> Vec<Fold>
Returns a snapshot of all folds as an owned Vec<Fold>.
Owned rather than &[Fold] because a Buffer is a per-window
view onto a shared Content; another view could mutate the folds vec
between when this returns and when the caller reads the slice.
Sourcepub fn add_fold(&mut self, start_row: usize, end_row: usize, closed: bool)
pub fn add_fold(&mut self, start_row: usize, end_row: usize, closed: bool)
Register a new fold. If an existing fold has the same
start_row, it’s replaced; otherwise the new one is inserted
in start-row order. Empty / inverted ranges are rejected.
Sourcepub fn remove_fold_at(&mut self, row: usize) -> bool
pub fn remove_fold_at(&mut self, row: usize) -> bool
Drop the fold whose range covers row. Returns true when a
fold was actually removed.
Sourcepub fn open_fold_at(&mut self, row: usize) -> bool
pub fn open_fold_at(&mut self, row: usize) -> bool
Open the fold at row (no-op if already open or no fold).
Sourcepub fn close_fold_at(&mut self, row: usize) -> bool
pub fn close_fold_at(&mut self, row: usize) -> bool
Close the fold at row (no-op if already closed or no fold).
Sourcepub fn toggle_fold_at(&mut self, row: usize) -> bool
pub fn toggle_fold_at(&mut self, row: usize) -> bool
Flip the closed/open state of the fold containing row.
Sourcepub fn open_all_folds(&mut self)
pub fn open_all_folds(&mut self)
zR — open every fold.
Sourcepub fn clear_all_folds(&mut self)
pub fn clear_all_folds(&mut self)
zE — eliminate every fold.
Sourcepub fn close_all_folds(&mut self)
pub fn close_all_folds(&mut self)
zM — close every fold.
Sourcepub fn fold_at_row(&self, row: usize) -> Option<Fold>
pub fn fold_at_row(&self, row: usize) -> Option<Fold>
First fold whose range contains row. Useful for the host’s
za/zo/zc handlers.
True iff row is hidden by a closed fold (any fold).
Sourcepub fn next_visible_row(&self, row: usize) -> Option<usize>
pub fn next_visible_row(&self, row: usize) -> Option<usize>
First visible row strictly after row, skipping any rows hidden
by closed folds. Returns None past the end of the buffer.
Sourcepub fn prev_visible_row(&self, row: usize) -> Option<usize>
pub fn prev_visible_row(&self, row: usize) -> Option<usize>
First visible row strictly before row, skipping hidden rows.
Sourcepub fn invalidate_folds_in_range(&mut self, start_row: usize, end_row: usize)
pub fn invalidate_folds_in_range(&mut self, start_row: usize, end_row: usize)
Drop every fold that touches [start_row, end_row].
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Buffer
impl RefUnwindSafe for Buffer
impl Send for Buffer
impl Sync for Buffer
impl Unpin for Buffer
impl UnsafeUnpin for Buffer
impl UnwindSafe for Buffer
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
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