hjkl_buffer/lib.rs
1//! # hjkl-buffer
2//!
3//! Rope-backed text buffer with vim-shaped semantics: charwise/linewise/
4//! blockwise selection, motions matching vim edge cases (no `h` wrap, `$`
5//! clamp, sticky col on `j`/`k`), folds, viewport, and search.
6//!
7//! Extracted from `sqeel-buffer` with full git history.
8//!
9//! ## Features
10//!
11//! - `ratatui` (off by default): enables the `render` module with a direct
12//! cell-write `ratatui::widgets::Widget` impl for [`Buffer`] via
13//! [`BufferView`].
14//!
15//! ## Pre-1.0 stability
16//!
17//! Pre-1.0: signatures may shift between patch versions. The invariants
18//! documented on each type and function are the load-bearing semantics — they
19//! will not silently change without a CHANGELOG entry and a deliberate version
20//! bump.
21//!
22//! ## Why so many invariants?
23//!
24//! Most of them follow from one rule: **the engine layer treats
25//! [`Buffer`] as the source of truth for text content**. Any divergence
26//! between cached state (engine-side selections, undo stacks, search matches)
27//! and the buffer's `lines()` is a bug. The invariants documented on each type
28//! are the contract that lets the engine cache aggressively without risking
29//! that divergence.
30//!
31//! Open issues: <https://github.com/kryptic-sh/hjkl/issues>.
32//!
33//! ## Testing your `Buffer` use
34//!
35//! Property tests are encouraged for any non-trivial caller. The crate ships
36//! its own test suite; reuse [`Buffer::from_str`] to construct fixtures from
37//! inline strings.
38//!
39//! Things worth proving:
40//!
41//! - After any sequence of valid edits + their inverses, the buffer returns to
42//! its original `lines()`.
43//! - For any valid [`Position`] and motion call, the resulting cursor is itself
44//! valid.
45//! - [`Buffer::dirty_gen`] strictly increases across mutations and stays
46//! constant across read-only queries.
47
48#![deny(unsafe_op_in_unsafe_fn)]
49
50mod buffer;
51mod edit;
52mod folds;
53mod motion;
54mod position;
55#[cfg(feature = "ratatui")]
56mod render;
57mod selection;
58mod span;
59mod viewport;
60pub mod wrap;
61
62pub use buffer::Buffer;
63pub use edit::{Edit, MotionKind};
64pub use folds::Fold;
65pub use motion::is_keyword_char;
66pub use position::Position;
67#[cfg(feature = "ratatui")]
68pub use render::{BufferView, Gutter, Sign, StyleResolver};
69pub use selection::{RowSpan, Selection};
70pub use span::Span;
71pub use viewport::Viewport;
72pub use wrap::Wrap;