Skip to main content

Buffer

Struct Buffer 

Source
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

Source

pub fn new() -> Self

Construct an empty buffer with one empty row + cursor at (0, 0).

Source

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).

Source

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));
Source

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.

Source

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.

Source

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.

Source

pub fn cursor(&self) -> Position

Source

pub fn dirty_gen(&self) -> u64

Source

pub fn row_count(&self) -> usize

Number of rows in the buffer. Always >= 1.

Source

pub fn as_string(&self) -> String

Concatenate the rows into a single String joined by \n.

Source

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.

Source

pub fn ensure_cursor_visible(&mut self, viewport: &mut Viewport)

Bring the cursor into the visible Viewport, scrolling by the minimum amount needed.

Source

pub fn cursor_screen_row(&self, viewport: &Viewport) -> Option<usize>

Cursor’s screen row offset (0-based) from viewport.top_row.

Source

pub fn screen_rows_between( &self, viewport: &Viewport, start: usize, end: usize, ) -> usize

Number of screen rows the doc range start..=end occupies.

Source

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.

Source

pub fn clamp_position(&self, pos: Position) -> Position

Clamp pos to the buffer’s content.

Source

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

Source

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_gen is 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_cursor immediately after.
  • All Position values the caller held from before the edit may be invalid. Re-derive from row / col deltas; do not cache.
Source§

impl Buffer

Source

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.

Source

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.

Source

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.

Source

pub fn open_fold_at(&mut self, row: usize) -> bool

Open the fold at row (no-op if already open or no fold).

Source

pub fn close_fold_at(&mut self, row: usize) -> bool

Close the fold at row (no-op if already closed or no fold).

Source

pub fn toggle_fold_at(&mut self, row: usize) -> bool

Flip the closed/open state of the fold containing row.

Source

pub fn open_all_folds(&mut self)

zR — open every fold.

Source

pub fn clear_all_folds(&mut self)

zE — eliminate every fold.

Source

pub fn close_all_folds(&mut self)

zM — close every fold.

Source

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.

Source

pub fn is_row_hidden(&self, row: usize) -> bool

True iff row is hidden by a closed fold (any fold).

Source

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.

Source

pub fn prev_visible_row(&self, row: usize) -> Option<usize>

First visible row strictly before row, skipping hidden rows.

Source

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§

Source§

impl Default for Buffer

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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
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.