Skip to main content

ChatBuffer

Struct ChatBuffer 

Source
pub struct ChatBuffer { /* private fields */ }
Expand description

A scrollable list of laid-out messages.

Implementations§

Source§

impl ChatBuffer

Source

pub fn new(params: LayoutParams) -> ChatBuffer

Source

pub fn len(&self) -> usize

Source

pub fn is_empty(&self) -> bool

Source

pub fn anchor(&self) -> ScrollAnchor

Source

pub fn set_anchor(&mut self, a: ScrollAnchor)

Source

pub fn params(&self) -> &LayoutParams

Source

pub fn generation(&self) -> LayoutGeneration

Source

pub fn max_rows(&self) -> usize

The scrollback cap on live rows; 0 is no limit.

Source

pub fn set_max_rows(&mut self, n: usize, measure: &dyn TextMeasure)

Scrollback cap on live rows. Matches rotulus_view_set_max_lines.

Source

pub fn message(&self, id: MessageId) -> Option<&Message>

Source

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

Source

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

Source

pub fn row_of(&self, id: MessageId) -> Option<usize>

Row position of id, or None if it has been trimmed/cleared.

Source

pub fn reindex(&mut self)

Rebuild the id → position map if stale.

Source

pub fn append(&mut self, msg: Message, measure: &dyn TextMeasure) -> MessageId

Append a message; returns its mark.

Source

pub fn insert_before( &mut self, anchor: Option<MessageId>, msg: Message, measure: &dyn TextMeasure, ) -> MessageId

Insert immediately before anchor, or at the front if anchor is None or stale. Returns the new mark.

This is the chat-history Load-Older path. Nothing here needs to compensate the scroll position: the anchor names a row, that row did not move, so the viewport does not move. xtext had to bump pagetop_line / pagetop_subline / last_pixel_pos / old_value by the inserted row’s subline count to approximate the same effect (xtext.c:5720).

Source

pub fn remove(&mut self, id: MessageId, measure: &dyn TextMeasure) -> bool

Remove the row id names. false if the mark was already stale, which is not an error — it is how a caller learns the row was trimmed.

Source

pub fn replace( &mut self, id: MessageId, msg: Message, measure: &dyn TextMeasure, ) -> bool

Replace a message in place, e.g. to attach a decoded image size.

Source

pub fn set_image_size( &mut self, id: MessageId, token: u32, size: Option<ImageSize>, measure: &dyn TextMeasure, ) -> bool

Attach a decoded size to an image block, growing the row.

The single operation the old design was worst at: xtext had to recompute the entry’s subline list, diff the count, and patch the buffer’s num_lines plus the scroll anchors. Here it is a height change, and the anchor absorbs it. Attach (or with None, clear) the decoded size of an image block.

None is the decode-failed path: the row must shrink back to its placeholder height, or the alt text ends up floating inside a tall empty box the size of an image that never arrived.

Source

pub fn find_image(&self, token: u32) -> Option<MessageId>

Find the row carrying an image block with token.

Source

pub fn clear(&mut self)

Source

pub fn set_group_gap_secs(&mut self, secs: i64, measure: &dyn TextMeasure)

Grouping controls. 0 disables it; rows already in the buffer are re-evaluated, since the flag describes neighbours rather than the message itself.

Source

pub fn group_gap_secs(&self) -> i64

Source

pub fn set_width(&mut self, width: u32)

Change the content width. Invalidates layout without recomputing it — the whole point of the lazy cache.

Source

pub fn set_font_generation(&mut self, font: u32)

Source

pub fn set_zoom_permille(&mut self, zoom: u32)

Zoom, in per-mille (1000 = 100%).

Source

pub fn set_word_wrap(&mut self, on: bool)

Source

pub fn set_avatar_size(&mut self, px: u32)

Edge length of the avatar slot in the gutter; 0 turns avatars off. Invalidates every layout, since it changes the gutter width and the height of every group head.

Source

pub fn set_indent(&mut self, on: bool)

Two-column mode.

Source

pub fn set_stamp_width(&mut self, px: u32)

Width to reserve for the timestamp column; 0 turns it off.

Source

pub fn stamp_width(&self) -> u32

Source

pub fn set_max_indent(&mut self, px: u32)

Cap on the gutter width.

Source

pub fn ensure_layout(&mut self, row: usize, measure: &dyn TextMeasure) -> u32

Ensure row row has a current layout, computing it if not. Returns its height.

Source

pub fn ensure_visible( &mut self, y: u64, viewport_height: u32, measure: &dyn TextMeasure, ) -> Vec<usize>

Lay out every row intersecting [y, y + height) and return their positions.

Every returned row is guaranteed to have a current layout. That guarantee needs defending, because laying a row out can invalidate the rows already done: meeting a wider nick widens the shared gutter, which makes every other row’s cached layout stale. Without the retry below, the rows laid out earlier in the pass come back with layout_at(row) == None, the view skips them, and the first paint of a fresh buffer is visibly shredded — while the next message, by which time the gutter has settled, looks fine.

The gutter only ever grows and is capped by max_indent, so this converges fast; the bound is belt-and-braces.

Source

pub fn source_text(&self, row: usize, source: LineSource) -> Option<&str>

Text of one of a message’s sources, for hit-testing and copying.

The link under a caret, as (href, visible text).

Returned by value rather than by reference because the caller is the widget, which needs to hold it across a popup. The byte range of the link under caret, in its source’s text.

Split from link_at because the hover underline needs the extent and not the target — and deriving the extent a second way is how the underline and the click end up disagreeing about where a link stops.

Source

pub fn gutter_range(&self, id: MessageId) -> Option<Range<usize>>

Byte extent of a row’s gutter text, for the nick hover underline.

Source

pub fn speaker_of(&self, id: MessageId) -> Option<&Speaker>

The speaker of a row, if it has one.

Source

pub fn word_at(&self, caret: &Caret) -> Option<String>

The whitespace-delimited word around a caret.

Tokenised like xtext’s is_del macro: space, newline, <, > and NUL. The angle brackets are what let <nick> split into a bare nick when it is double-clicked.

Source

pub fn word_bounds(&self, caret: &Caret) -> Option<(usize, usize)>

Byte bounds of the word around a caret, in its own source.

Shared by word_at (which the word-click emission needs as a string) and double-click word-select, so the two can never disagree about where a word begins.

Source

pub fn select_word(&self, caret: &Caret) -> Option<Selection>

Double-click: select the word under the caret.

Source

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

Triple-click: select the whole row, gutter included.

The gutter is part of what the user sees on that line, so it is part of what a “select this line” gesture should give them — consistent with a whole-row selection dragged from above.

Source

pub fn search(&self, needle: &str, case_sensitive: bool) -> Vec<Match>

Every occurrence of needle, in reading order.

Reading order means row by row, and within a row by source_rank — the same order selected_rows walks and the same order the eye does, so stepping through matches never jumps backwards on screen.

Searches the model, not the layout, so matches in rows that have never been laid out are found too. That matters: the whole point of search is to reach the part of the scrollback you haven’t scrolled to.

Source

pub fn avatar_at(&mut self, x: i32, y: u64) -> Option<(MessageId, u64)>

The speaker whose avatar covers content point (x, y), if any.

The avatar is painted from LayoutCache::avatar, not from a line box, so the ordinary caret hit-test cannot see it — clicking an icon found nothing at all. Asking the layout directly keeps the clickable area and the painted area the same rectangle by construction.

Source

pub fn select_all(&self) -> Option<Selection>

A selection covering the whole buffer, or None when empty.

The model owns what “everything” means, because the view kept getting it wrong: it hard-coded Block(0) at both ends, which skipped the first row’s gutter and — once markdown started splitting a body into several blocks — stopped at the end of the first block of the last row, dropping any code block or quote after it.

Source

pub fn matches_in( all: &[Match], id: MessageId, source: LineSource, ) -> Vec<Match>

Matches falling inside one row’s one source, for the renderer.

The renderer asks per source per row while drawing, so this is a filter over the result set rather than a fresh search.

Source

pub fn reveal( &mut self, id: MessageId, viewport_height: u32, measure: &dyn TextMeasure, )

Scroll so id is on screen, centred if it isn’t already visible.

Leaves an already-visible row where it is. Yanking the viewport on every step would make walking a cluster of matches in one screenful feel like the view was fighting you.

Source

pub fn indent_width(&self) -> u32

The settled gutter width. 0 when not in indent mode.

Source

pub fn indent_pinned(&self) -> bool

Whether the gutter has been pinned by a separator drag.

Source

pub fn set_indent_width(&mut self, px: u32) -> bool

Pin the gutter to px, as a separator drag does.

Deliberately not clamped to max_indent: that cap governs how far the gutter may grow on its own, and a user dragging the separator is saying something the cap has no business overruling. The caller clamps to the viewport instead. Returns whether anything moved.

Source

pub fn unpin_indent(&mut self)

Release the pin and let the gutter auto-size again.

Source

pub fn hit_test( &mut self, x: i32, y: u64, measure: &dyn TextMeasure, ) -> Option<Caret>

Map a content-space pixel to a document position.

x / y are in content coordinates (the view subtracts its own padding first). y is absolute within the buffer, not viewport-relative.

Returns None only for an empty buffer; a point past the end clamps to the last row, because a drag that runs off the bottom should select to the end rather than stop tracking.

Source

pub fn row_selection(&self, row: usize, sel: &Selection) -> RowSelection

How much of row a selection covers.

Source

pub fn sources_of(&self, row: usize) -> Vec<LineSource>

The row’s sources in visual order: gutter first, then blocks.

Source

pub fn covered_range( &self, row: usize, source: LineSource, sel: &RowSelection, ) -> Option<Range<usize>>

The byte range of source covered by a row selection, if any.

The one place that resolves a possibly-cross-source Partial against a single text, so the view and selected_text cannot disagree about what is highlighted versus what gets copied.

Source

pub fn selected_rows(&self, sel: &Selection) -> Vec<(usize, String)>

The selected text of each covered row, as (row, text).

Exposed per row because a row’s own text may contain hard newlines — the wrap engine supports them — so a caller cannot recover row boundaries by splitting the joined string. The autocopy-timestamp path needs exactly that: it prefixes each row with that row’s stamp, and iterating lines() over the joined output drifts onto the wrong rows the moment any selected message spans more than one line.

Source

pub fn selected_text(&self, sel: &Selection) -> String

The selected text, rows joined by newlines.

Source

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

Source

pub fn total_height(&mut self) -> u64

Source

pub fn index_mut(&mut self) -> &mut HeightIndex

Source

pub fn scroll_offset(&mut self, viewport_height: u32) -> u64

The scroll adjustment value the current anchor implies.

Source

pub fn scroll_to(&mut self, y: u64, viewport_height: u32, follow_slop: u32)

Re-anchor from a pixel position — a scrollbar drag.

Source

pub fn scroll_to_bottom(&mut self)

Pin to the bottom and resume following.

Source

pub fn is_following(&self) -> bool

Trait Implementations§

Source§

impl Debug for ChatBuffer

Source§

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

Formats the value using the given formatter. 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.