Make buffers return their items lazily from the end instead of materializing them
This commit is contained in:
@ -24,7 +24,7 @@ use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
use super::Buffer;
|
||||
use super::{Buffer, BufferItem};
|
||||
|
||||
/// Maximum number of log lines to be stored in memory
|
||||
const MAX_MEM_LOG_LINES: usize = 100;
|
||||
@ -61,19 +61,21 @@ impl Buffer for LogBuffer {
|
||||
self.lines.push_back(line);
|
||||
}
|
||||
|
||||
fn content(&self) -> Vec<Text> {
|
||||
fn content<'a>(&'a self) -> Box<dyn Iterator<Item = BufferItem<'a>> + 'a> {
|
||||
use ansi_to_tui::IntoText;
|
||||
let (slice1, slice2) = self.lines.as_slices();
|
||||
slice1
|
||||
.into_iter()
|
||||
.chain(slice2.into_iter())
|
||||
.cloned()
|
||||
.map(|line| {
|
||||
line.into_text().unwrap_or_else(|e| {
|
||||
tracing::error!("Could not convert line from ANSI codes to ratatui: {}", e);
|
||||
Text::raw(line)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
Box::new(
|
||||
slice1
|
||||
.into_iter()
|
||||
.chain(slice2.into_iter())
|
||||
.rev()
|
||||
.cloned()
|
||||
.map(|line| BufferItem {
|
||||
text: line.into_text().unwrap_or_else(|e| {
|
||||
tracing::error!("Could not convert line from ANSI codes to ratatui: {}", e);
|
||||
Text::raw(line)
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,17 @@ use futures::stream::FuturesUnordered;
|
||||
use futures::StreamExt;
|
||||
use matrix_sdk::async_trait;
|
||||
use nonempty::NonEmpty;
|
||||
use ratatui::text::Text;
|
||||
|
||||
mod log;
|
||||
pub use log::LogBuffer;
|
||||
mod room;
|
||||
pub use room::RoomBuffer;
|
||||
|
||||
pub struct BufferItem<'a> {
|
||||
pub text: Text<'a>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Buffer: Send + Sync {
|
||||
/// A short human-readable name for the room, eg. to show in compact buflist
|
||||
@ -34,7 +39,7 @@ pub trait Buffer: Send + Sync {
|
||||
}
|
||||
/// Returns if there are any updates to apply.
|
||||
async fn poll_updates(&mut self);
|
||||
fn content(&self) -> Vec<ratatui::text::Text>; // TODO: make this lazy, only the last few are used
|
||||
fn content<'a>(&'a self) -> Box<dyn Iterator<Item = BufferItem<'a>> + 'a>;
|
||||
/// Called when the user is being showned the oldest items this buffer returned.
|
||||
///
|
||||
/// This should return immediately, not waiting for anything to be loaded.
|
||||
|
@ -32,7 +32,7 @@ use matrix_sdk_ui::timeline::{
|
||||
use ratatui::text::Text;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::Buffer;
|
||||
use super::{Buffer, BufferItem};
|
||||
|
||||
pub struct SingleClientRoomBuffer {
|
||||
room_id: OwnedRoomId,
|
||||
@ -304,16 +304,20 @@ impl Buffer for RoomBuffer {
|
||||
.await;
|
||||
}
|
||||
|
||||
fn content(&self) -> Vec<Text> {
|
||||
fn content<'a>(&'a self) -> Box<dyn Iterator<Item = BufferItem<'a>> + 'a> {
|
||||
// TODO: merge buffers, etc.
|
||||
self
|
||||
.buffers
|
||||
.first()
|
||||
.unwrap_or_else(|| panic!("No sub-buffer for {}", self.room_id))
|
||||
.items
|
||||
.iter()
|
||||
.map(|line| Text::raw(line))
|
||||
.collect()
|
||||
Box::new(
|
||||
self
|
||||
.buffers
|
||||
.first()
|
||||
.unwrap_or_else(|| panic!("No sub-buffer for {}", self.room_id))
|
||||
.items
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|line| BufferItem {
|
||||
text: Text::raw(line),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn request_back_pagination(&self, num: u16) {
|
||||
|
@ -64,8 +64,6 @@ impl Component for Backlog {
|
||||
|
||||
let active_buffer = buffers.active_buffer();
|
||||
let mut items = active_buffer.content();
|
||||
items.reverse();
|
||||
let mut items = items.into_iter();
|
||||
let mut scroll = self.scroll;
|
||||
|
||||
// Skip widgets at the bottom (if scrolled up), and render the first visible one
|
||||
@ -73,7 +71,7 @@ impl Component for Backlog {
|
||||
let Some(item) = items.next() else {
|
||||
break;
|
||||
};
|
||||
let widget = BottomAlignedParagraph::new(item);
|
||||
let widget = BottomAlignedParagraph::new(item.text);
|
||||
let expected_height = widget.height(text_area.width);
|
||||
|
||||
if scroll.saturating_sub(expected_height) > text_area.height.into() {
|
||||
@ -95,7 +93,7 @@ impl Component for Backlog {
|
||||
|
||||
// Render other widgets
|
||||
for item in items {
|
||||
let widget = BottomAlignedParagraph::new(item);
|
||||
let widget = BottomAlignedParagraph::new(item.text);
|
||||
let height = widget.render_overlap(text_area, frame.buffer_mut());
|
||||
assert!(area.height >= height, "{:?} {}", area, height);
|
||||
text_area.height = text_area.height.saturating_sub(height); // Remove lines at the bottom used by this paragraph
|
||||
|
Reference in New Issue
Block a user