diff --git a/src/buffers/log.rs b/src/buffers/log.rs index 18cb4f4..729955c 100644 --- a/src/buffers/log.rs +++ b/src/buffers/log.rs @@ -89,7 +89,7 @@ impl Buffer for LogBuffer { .iter() .rev() .map(|(line_id, line, prerender)| BufferItem { - content: BufferItemContent::Text(line.clone().into_text().unwrap_or_else(|e| { + content: BufferItemContent::SimpleText(line.clone().into_text().unwrap_or_else(|e| { tracing::error!("Could not convert line from ANSI codes to ratatui: {}", e); Text::raw(line) })), diff --git a/src/buffers/mod.rs b/src/buffers/mod.rs index 1812394..a94c756 100644 --- a/src/buffers/mod.rs +++ b/src/buffers/mod.rs @@ -22,6 +22,7 @@ use futures::StreamExt; use matrix_sdk::async_trait; use nonempty::NonEmpty; use ratatui::text::Text; +use smallvec::SmallVec; use sorted_vec::SortedVec; use crate::widgets::Prerender; @@ -92,7 +93,9 @@ impl PartialOrd for BufferSortKey { #[derive(Debug, Clone)] pub enum BufferItemContent<'buf> { - Text(Text<'buf>), + SimpleText(Text<'buf>), + /// Pairs of `(padding, content)` + Text(Vec<(String, Text<'buf>)>), Divider(Text<'buf>), Empty, } diff --git a/src/buffers/room.rs b/src/buffers/room.rs index 605b9a8..3d25162 100644 --- a/src/buffers/room.rs +++ b/src/buffers/room.rs @@ -58,11 +58,17 @@ use crate::widgets::Prerender; /// Like [`BufferItemContent`] but owned. #[derive(Debug, Clone)] pub enum OwnedBufferItemContent { - Text { + SimpleText { event_id: Option, is_message: bool, text: Text<'static>, }, + Text { + event_id: Option, + is_message: bool, + /// `(padding, content)` pairs + text: Vec<(String, Text<'static>)>, + }, Divider(String), Empty, } @@ -71,19 +77,32 @@ impl DynamicUsage for OwnedBufferItemContent { fn dynamic_usage(&self) -> usize { std::mem::size_of::() + match self { - OwnedBufferItemContent::Text { text, .. } => { + OwnedBufferItemContent::SimpleText { text, .. } => { text.width() * text.height() * 4 // FIXME: rough approx }, + OwnedBufferItemContent::Text { text, .. } => { + text + .iter() + .map(|item| item.1.width() * item.1.height() * 4) + .sum() // FIXME: rough approx + }, OwnedBufferItemContent::Divider(s) => s.dynamic_usage(), OwnedBufferItemContent::Empty => 0, } } fn dynamic_usage_bounds(&self) -> (usize, Option) { let (min, max) = match self { - OwnedBufferItemContent::Text { text, .. } => { + OwnedBufferItemContent::SimpleText { text, .. } => { let area = text.width() * text.height(); (area, Some(area * 12)) // FIXME: rough approx }, + OwnedBufferItemContent::Text { text, .. } => { + let area = text + .iter() + .map(|item| item.1.width() * item.1.height()) + .sum(); + (area, Some(area * 12)) // FIXME: rough approx + }, OwnedBufferItemContent::Divider(s) => s.dynamic_usage_bounds(), OwnedBufferItemContent::Empty => (0, Some(0)), }; @@ -175,22 +194,22 @@ impl SingleClientRoomBuffer { // Like `format!()` but returns OwnedBufferItemContent::Text, with is_message=false macro_rules! text { - ($($tokens:tt)*) => { + ($prefix: expr, $($tokens:tt)*) => { OwnedBufferItemContent::Text { event_id: event.event_id().map(ToOwned::to_owned), is_message: false, - text: format_html(&self.config, &format!($($tokens)*)) + text: format_html(&self.config, $prefix, &format!($($tokens)*)) } } } // Like `format!()` but returns OwnedBufferItemContent::Text, with is_message=true macro_rules! msg { - ($($tokens:tt)*) => { + ($prefix: expr, $($tokens:tt)*) => { OwnedBufferItemContent::Text { event_id: event.event_id().map(ToOwned::to_owned), is_message: true, - text: format_html(&self.config, &format!($($tokens)*)) + text: format_html(&self.config, $prefix, &format!($($tokens)*)) } } } @@ -217,73 +236,95 @@ impl SingleClientRoomBuffer { "FormattedBody::sanitize_html set type to {:?} instead of Html", formatted.format ); - msg!(" <{}> {}", sender, formatted.body) + msg!(" ", "<{}> {}", sender, formatted.body) }, MessageType::Text(TextMessageEventContent { body, .. }) => { - msg!(" <{}> {}", sender, escape_html(body)) + msg!(" ", "<{}> {}", sender, escape_html(body)) }, _ => // Fallback to text body { msg!( - " <{}> {}", + " ", + "<{}> {}", sender, escape_html(&message.body().replace('\n', "\n ")) ) }, }, - RedactedMessage => msg!("xx <{}> [redacted]", sender), + RedactedMessage => msg!("xx ", "<{}> [redacted]", sender), Sticker(sticker) => msg!( - "st <{}> {}", + "st ", + "<{}> {}", sender, escape_html(&sticker.content().body) ), - UnableToDecrypt(_) => text!("xx <{}> [unable to decrypt]", sender), + UnableToDecrypt(_) => text!("xx ", "<{}> [unable to decrypt]", sender), MembershipChange(change) => { use matrix_sdk_ui::timeline::MembershipChange::*; if change.user_id() == event.sender() { let Some(change_kind) = change.change() else { - return text!("--- {} made incomprehensible changes to themselves", sender); + return text!( + "--- ", + "{} made incomprehensible changes to themselves", + sender + ); }; match change_kind { - None => text!("--- {} made no discernable changes to themselves", sender), - Error => text!( - "xxx {} made a change to themselves that made matrix-sdk-ui error", + None => text!( + "--- ", + "{} made no discernable changes to themselves", sender ), - Joined => text!("--> {} joined", sender), - Left => text!("<-- {} left", sender), - Banned => text!("-x- {} banned themselves", sender), - Unbanned => text!("-x- {} unbanned themselves", sender), - Kicked => text!("<!- {} kicked themselves", sender), - Invited => text!("-o- {} invited themselves", sender), - KickedAndBanned => text!("<!x {} kicked and banned themselves", sender), - InvitationAccepted => text!("-o> {} accepted an invite", sender), - InvitationRejected => text!("-ox {} rejected an invite", sender), - InvitationRevoked => text!("--x {} revoked an invite", sender), - Knocked => text!("-?> {} knocked", sender), - KnockAccepted => text!("-?o {} accepted a knock", sender), - KnockRetracted => text!("-?x {} retracted a knock", sender), - KnockDenied => text!("-?x {} denied a knock", sender), + Error => text!( + "xxx ", + "{} made a change to themselves that made matrix-sdk-ui error", + sender + ), + Joined => text!("--> ", "{} joined", sender), + Left => text!("<-- ", "{} left", sender), + Banned => text!("-x- ", "{} banned themselves", sender), + Unbanned => text!("-x- ", "{} unbanned themselves", sender), + Kicked => text!("<!- ", "{} kicked themselves", sender), + Invited => text!("-o- ", "{} invited themselves", sender), + KickedAndBanned => text!("<!x ", "{} kicked and banned themselves", sender), + InvitationAccepted => text!("-o> ", "{} accepted an invite", sender), + InvitationRejected => text!("-ox ", "{} rejected an invite", sender), + InvitationRevoked => text!("--x ", "{} revoked an invite", sender), + Knocked => text!("-?> ", "{} knocked", sender), + KnockAccepted => text!("-?o ", "{} accepted a knock", sender), + KnockRetracted => text!("-?x ", "{} retracted a knock", sender), + KnockDenied => text!("-?x ", "{} denied a knock", sender), NotImplemented => text!( - "xxx {} made a change matrix-sdk-ui does not support yet", + "xxx ", + "{} made a change matrix-sdk-ui does not support yet", sender ), } } else if change.user_id() == "" { let Some(change_kind) = change.change() else { - return text!("--- {} made incomprehensible changes", sender); + return text!("--- ", "{} made incomprehensible changes", sender); }; match change_kind { - None => text!("--- {} made no discernable changes", sender), - Error => text!("xxx {} made a change that made matrix-sdk-ui error", sender), + None => text!("--- ", "{} made no discernable changes", sender), + Error => text!( + "xxx ", + "{} made a change that made matrix-sdk-ui error", + sender + ), Joined | Left | Banned | Unbanned | Kicked | Invited | KickedAndBanned | InvitationAccepted | InvitationRejected | InvitationRevoked | Knocked | KnockAccepted | KnockRetracted | KnockDenied => { - text!("--> {} made a non-sensical change: {:?}", sender, change) + text!( + "--> ", + "{} made a non-sensical change: {:?}", + sender, + change + ) }, NotImplemented => text!( - "xxx {} made a change matrix-sdk-ui does not support yet", + "xxx ", + "{} made a change matrix-sdk-ui does not support yet", sender ), } @@ -297,35 +338,48 @@ impl SingleClientRoomBuffer { ); let target = markup_colored_by_mxid(&target, &target); let Some(change_kind) = change.change() else { - return text!("--- {} made incomprehensible changes to {}", sender, target); + return text!( + "--- ", + "{} made incomprehensible changes to {}", + sender, + target + ); }; match change_kind { - None => text!("--- {} made no discernable changes to {}", sender, target), + None => text!( + "--- ", + "{} made no discernable changes to {}", + sender, + target + ), Error => text!( - "xxx {} made a change to {} that made matrix-sdk-ui error", + "xxx ", + "{} made a change to {} that made matrix-sdk-ui error", sender, target ), Joined | Left => text!( - "--> {} made a non-sensical change to {}: {:?}", + "--> ", + "{} made a non-sensical change to {}: {:?}", sender, target, change ), - Banned => text!("-x- {} banned {}", sender, target), - Unbanned => text!("-x- {} unbanned {}", sender, target), - Kicked => text!("<!- {} kicked {}", sender, target), - Invited => text!("-o- {} invited {}", sender, target), - KickedAndBanned => text!("<!x {} kicked and banned {}", sender, target), - InvitationAccepted => text!("-o> {} accepted an invite to {}", sender, target), - InvitationRejected => text!("-ox {} rejected an invite to {}", sender, target), - InvitationRevoked => text!("--x {} revoked an invite to {}", sender, target), - Knocked => text!("-?> {} made {} knock", sender, target), - KnockAccepted => text!("-?o {} accepted {}'s knock", sender, target), - KnockRetracted => text!("-?x {} retracted {}'s knock", sender, target), - KnockDenied => text!("-?x {} denied {}'s knock", sender, target), + Banned => text!("-x- ", "{} banned {}", sender, target), + Unbanned => text!("-x- ", "{} unbanned {}", sender, target), + Kicked => text!("<!- ", "{} kicked {}", sender, target), + Invited => text!("-o- ", "{} invited {}", sender, target), + KickedAndBanned => text!("<!x ", "{} kicked and banned {}", sender, target), + InvitationAccepted => text!("-o> ", "{} accepted an invite to {}", sender, target), + InvitationRejected => text!("-ox ", "{} rejected an invite to {}", sender, target), + InvitationRevoked => text!("--x ", "{} revoked an invite to {}", sender, target), + Knocked => text!("-?> ", "{} made {} knock", sender, target), + KnockAccepted => text!("-?o ", "{} accepted {}'s knock", sender, target), + KnockRetracted => text!("-?x ", "{} retracted {}'s knock", sender, target), + KnockDenied => text!("-?x ", "{} denied {}'s knock", sender, target), NotImplemented => text!( - "xxx {} made a change to {} that matrix-sdk-ui does not support yet", + "xxx ", + "{} made a change to {} that matrix-sdk-ui does not support yet", sender, target ), @@ -333,13 +387,14 @@ impl SingleClientRoomBuffer { } }, - ProfileChange(_) => text!("--- {} updated their profile", sender), + ProfileChange(_) => text!("--- ", "{} updated their profile", sender), OtherState(state) => { if state.state_key() == "" { - text!("--- {} changed the room: {:?}", sender, state.content()) + text!("--- ", "{} changed the room: {:?}", sender, state.content()) } else { text!( - "--- {} changed {}: {:?}", + "--- ", + "{} changed {}: {:?}", sender, escape_html(state.state_key()), state.content() // TODO: escape html @@ -347,7 +402,8 @@ impl SingleClientRoomBuffer { } }, FailedToParseMessageLike { event_type, error } => text!( - "xxx {} sent a {} message that made matrix-sdk-ui error: {:?}", + "xxx ", + "{} sent a {} message that made matrix-sdk-ui error: {:?}", sender, escape_html(&event_type.to_string()), error // TODO: escape html @@ -358,14 +414,15 @@ impl SingleClientRoomBuffer { error, } => { text!( - "xxx {} made a {} change to {} that made matrix-sdk-ui error: {:?}", + "xxx ", + "{} made a {} change to {} that made matrix-sdk-ui error: {:?}", sender, escape_html(&event_type.to_string()), escape_html(state_key), error // TODO: escape html ) }, - Poll(_) => text!("-?- {} acted on a poll", sender), + Poll(_) => text!("-?- ", "{} acted on a poll", sender), } }, TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker) => { @@ -492,7 +549,7 @@ impl RoomBuffer { .map(|item| { ( None, - OwnedBufferItemContent::Text { + OwnedBufferItemContent::SimpleText { event_id: None, is_message: false, text: Text::raw(format!("Initial item: {:#?}", item)), @@ -638,6 +695,9 @@ impl Buffer for RoomBuffer { .rev() .map(|(line_id, line, prerender)| BufferItem { content: match line { + OwnedBufferItemContent::SimpleText { text, .. } => { + BufferItemContent::SimpleText(text.clone()) + }, OwnedBufferItemContent::Text { text, .. } => BufferItemContent::Text(text.clone()), OwnedBufferItemContent::Divider(text) => BufferItemContent::Divider(Text::raw(text)), OwnedBufferItemContent::Empty => BufferItemContent::Empty, diff --git a/src/components/backlog.rs b/src/components/backlog.rs index 2e89d0e..b5314bd 100644 --- a/src/components/backlog.rs +++ b/src/components/backlog.rs @@ -26,7 +26,8 @@ use crate::components::Action; use crate::config::{Config, ScrollAmount}; use crate::widgets::prerender::{PrerenderInner, PrerenderValue}; use crate::widgets::{ - BacklogItemWidget, BottomAlignedParagraph, Divider, EmptyWidget, OverlappableWidget, + BacklogItemWidget, BottomAlignedContainer, BottomAlignedParagraph, Divider, EmptyWidget, + OverlappableWidget, }; use super::Component; @@ -128,7 +129,17 @@ impl Backlog { fn build_widget<'a>(&self, content: BufferItemContent<'a>, scroll: u64) -> BacklogItemWidget<'a> { match content { - BufferItemContent::Text(text) => BottomAlignedParagraph::new(text).scroll(scroll).into(), + BufferItemContent::SimpleText(text) => { + BottomAlignedParagraph::new(text).scroll(scroll).into() + }, + BufferItemContent::Text(text) => BottomAlignedContainer::new( + text + .into_iter() + .map(|(padding, text)| (padding, BottomAlignedParagraph::new(text))) + .collect(), + ) + .scroll(scroll) + .into(), BufferItemContent::Divider(text) => { if scroll == 0 { Divider::new(Paragraph::new(text).alignment(Alignment::Center)).into() diff --git a/src/html/mod.rs b/src/html/mod.rs index f57e935..27e0abf 100644 --- a/src/html/mod.rs +++ b/src/html/mod.rs @@ -95,23 +95,25 @@ fn format_tree( config: &Config, tree: Rc, state: &mut FormatState, - text: &mut Text<'static>, + text: &mut Vec<(String, Text<'static>)>, mut previous_sibling_is_block: bool, ) -> bool { - use markup5ever_rcdom::NodeData::*; let mut state = match &tree.data { - Document | Doctype { .. } | Comment { .. } | ProcessingInstruction { .. } => state.to_owned(), - Text { contents } => { + NodeData::Document + | NodeData::Doctype { .. } + | NodeData::Comment { .. } + | NodeData::ProcessingInstruction { .. } => state.to_owned(), + NodeData::Text { contents } => { let s: String = contents.clone().into_inner().into(); let s = s.replace('\n', ""); // Lines are insignificant in HTML if previous_sibling_is_block && !s.is_empty() { - text.lines.push(Line { - spans: vec![Span::styled(state.padding.to_owned(), state.style)], - alignment: None, - }); + text.push((state.padding.clone(), Text::raw(""))); previous_sibling_is_block = false; } text + .last_mut() + .unwrap() + .1 .lines .last_mut() .unwrap() @@ -119,7 +121,7 @@ fn format_tree( .push(Span::styled(s, state.style)); state.to_owned() }, - Element { + NodeData::Element { name: QualName { ns: ns!(html), local: name, @@ -173,7 +175,7 @@ fn format_tree( state }, local_name!("br") => { - text.lines.push(Line::raw(state.padding.to_owned())); + text.push((state.padding.clone(), Text::raw(""))); state.to_owned() }, local_name!("p") => { @@ -202,7 +204,7 @@ fn format_tree( .borrow() .iter() .map(|child| match &child.data { - Element { + NodeData::Element { name: QualName { ns: ns!(html), @@ -228,11 +230,8 @@ fn format_tree( ListState::None => state.to_owned(), ListState::Unordered => { let mut line = Line::default(); - line - .spans - .push(Span::styled(state.padding.to_owned(), state.style)); line.spans.push(Span::styled("* ", state.style)); - text.lines.push(line); + text.push((state.padding.to_owned(), line.into())); FormatState { padding: state.padding.to_owned() + " ", ..state.to_owned() @@ -243,9 +242,6 @@ fn format_tree( digits, } => { let mut line = Line::default(); - line - .spans - .push(Span::styled(state.padding.to_owned(), state.style)); *counter += 1; line .spans @@ -256,7 +252,7 @@ fn format_tree( state.style, )); } - text.lines.push(line); + text.push((state.padding.to_owned(), line.into())); FormatState { padding: state.padding.to_owned() + " " + &" ".repeat(digits.into()), ..state.to_owned() @@ -278,7 +274,7 @@ fn format_tree( }, _ => state.to_owned(), }, - Element { .. } => state.to_owned(), // Element not in the HTML namespace + NodeData::Element { .. } => state.to_owned(), // Element not in the HTML namespace }; for subtree in tree.children.borrow().iter() { @@ -292,9 +288,12 @@ fn format_tree( } match &tree.data { - Document | Doctype { .. } | Comment { .. } | ProcessingInstruction { .. } => {}, - Text { .. } => {}, - Element { + NodeData::Document + | NodeData::Doctype { .. } + | NodeData::Comment { .. } + | NodeData::ProcessingInstruction { .. } => {}, + NodeData::Text { .. } => {}, + NodeData::Element { name: QualName { ns: ns!(html), local: name, @@ -308,13 +307,16 @@ fn format_tree( }, _ => {}, }, - Element { .. } => {}, + NodeData::Element { .. } => {}, } previous_sibling_is_block } -pub fn format_html(config: &Config, s: &str) -> Text<'static> { +/// Returns a list of pairs `(padding, text)`. +/// +/// When rendering, the padding should be added left of every line of the text. +pub fn format_html(config: &Config, prefix: &'static str, s: &str) -> Vec<(String, Text<'static>)> { let tree = parse_fragment( RcDom::default(), Default::default(), @@ -323,11 +325,12 @@ pub fn format_html(config: &Config, s: &str) -> Text<'static> { ) .one(s) .document; + let prefix = Text::raw(prefix); let mut state = FormatState { - padding: " ".to_owned(), + padding: " ".repeat(prefix.width() + 1), // TODO: make +1 configurable ..Default::default() }; - let mut text = Text::raw(""); + let mut text = vec![("".to_owned(), prefix)]; format_tree(config, tree, &mut state, &mut text, false); text } diff --git a/src/widgets/bottom_aligned_container.rs b/src/widgets/bottom_aligned_container.rs new file mode 100644 index 0000000..cf9a440 --- /dev/null +++ b/src/widgets/bottom_aligned_container.rs @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2023 Valentin Lorentz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use ratatui::prelude::*; +use ratatui::widgets::{Paragraph, Widget}; + +use super::{BottomAlignedParagraph, OverlappableWidget}; + +/// Container of multiple [`BottomAlignedParagraph`] +#[derive(Debug)] +pub struct BottomAlignedContainer<'a> { + /// Pairs of `(padding, content)` + paragraphs: Vec<(String, BottomAlignedParagraph<'a>)>, + /// Number of lines at the bottom that should not be rendered + scroll: u64, +} + +impl<'a> BottomAlignedContainer<'a> { + pub fn new(paragraphs: Vec<(String, BottomAlignedParagraph<'a>)>) -> BottomAlignedContainer<'a> { + BottomAlignedContainer { + paragraphs, + scroll: 0, + } + } + + /// How many lines should be skipped at the bottom + /// + /// This is like [`Paragraph::scroll`](ratatui::widgets::Paragraph::scroll), but it's only vertical. + pub fn scroll(mut self, offset: u64) -> BottomAlignedContainer<'a> { + self.scroll = offset; + self + } + + fn padding_width(padding: &Text<'_>, max_width: u16) -> u16 { + usize::min( + (max_width - 10).into(), // TODO: make the minimum content width (10) configurable + padding.width(), + ) as u16 + } +} + +impl<'a> OverlappableWidget for BottomAlignedContainer<'a> { + fn height(&self, width: u16) -> u64 { + self + .paragraphs + .iter() + .map(|(padding, paragraph)| { + paragraph.height(width - Self::padding_width(&Line::raw(padding).into(), width)) + }) + .sum() + } + + fn render_overlap(self, mut area: Rect, buf: &mut Buffer) -> (u16, u16) { + if area.height == 0 { + // Don't even bother + return (0, 0); + } + let mut scroll = self.scroll; + + let mut actual_width = 0u16; + let mut actual_height = 0usize; + + for (padding, paragraph) in self.paragraphs.into_iter().rev() { + let padding: Text<'_> = Line::raw(&padding).into(); + let padding_width = Self::padding_width(&padding, area.width); + assert_eq!( + padding.height(), + 1, + "Unexpected padding height: {} (padding={:?})", + padding.height(), + padding + ); + + // FIXME: paragraph.height() is expensive because it needs to run line-wrapping, + // and paragraph.render_overlap then needs to run it again twice. + let paragraph_height = paragraph.height(area.width - padding_width); + if paragraph_height <= scroll { + // Paragraph is under the viewport, don't render it + scroll -= paragraph_height; + } else { + let paragraph = paragraph.scroll(scroll); + let (actual_paragraph_width, actual_paragraph_height) = paragraph.render_overlap( + Rect { + x: area.x + padding_width, + width: area.width - padding_width, + ..area + }, + buf, + ); + scroll = 0; + + // Write the padding on each line the paragraph was rendered on + for y in (u16::max( + area.top(), + area.bottom().saturating_sub(actual_paragraph_height), + ))..area.bottom() + { + Paragraph::new(padding.clone()).render( + Rect { + x: area.x, + y, + height: 1, + width: padding_width, + }, + buf, + ); + } + + area.height = area.height.saturating_sub(actual_paragraph_height); + actual_height = actual_height.saturating_add(actual_paragraph_height.into()); + actual_width = u16::max(actual_width, padding_width + actual_paragraph_width); + if area.height == 0 { + break; + } + } + } + + (actual_width, actual_height as u16) + } +} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 762b0c7..4372236 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -18,6 +18,8 @@ use enum_dispatch::enum_dispatch; use ratatui::prelude::*; use ratatui::widgets::Widget; +mod bottom_aligned_container; +pub use bottom_aligned_container::BottomAlignedContainer; mod bottom_aligned_paragraph; pub use bottom_aligned_paragraph::BottomAlignedParagraph; @@ -47,6 +49,7 @@ pub trait OverlappableWidget { #[enum_dispatch(OverlappableWidget)] pub enum BacklogItemWidget<'a> { Paragraph(BottomAlignedParagraph<'a>), + Container(BottomAlignedContainer<'a>), Divider(Divider<'a>), Empty(EmptyWidget), } diff --git a/tests/components/backlog.rs b/tests/components/backlog.rs index d8e4e52..f2859a8 100644 --- a/tests/components/backlog.rs +++ b/tests/components/backlog.rs @@ -64,7 +64,7 @@ fn test_single_item() { let mut bl = Backlog::new(config()); let prerender = Prerender::new(); let item = BufferItem { - content: BufferItemContent::Text(Text::raw("hello")), + content: BufferItemContent::SimpleText(Text::raw("hello")), prerender: &prerender, unique_id: None, }; @@ -91,7 +91,7 @@ fn test_single_item_cached() { let mut bl = Backlog::new(config()); let prerender = Prerender::new(); let item = BufferItem { - content: BufferItemContent::Text(Text::raw("hello")), + content: BufferItemContent::SimpleText(Text::raw("hello")), prerender: &prerender, unique_id: None, }; @@ -116,7 +116,7 @@ fn test_single_item_cached() { assert_eq!(prerender.key(), Some(10)); let item = BufferItem { - content: BufferItemContent::Text(Text::raw("hello")), + content: BufferItemContent::SimpleText(Text::raw("hello")), prerender: &prerender, unique_id: None, }; @@ -134,12 +134,12 @@ fn test_only_necessary_width() { let prerender1 = Prerender::new(); let prerender2 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi\nworld")), + content: BufferItemContent::SimpleText(Text::raw("hi\nworld")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw(":)")), + content: BufferItemContent::SimpleText(Text::raw(":)")), prerender: &prerender2, unique_id: None, }; @@ -165,12 +165,12 @@ fn test_only_necessary_width() { assert_eq!(prerender1.key(), Some(10)); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi\nworld")), + content: BufferItemContent::SimpleText(Text::raw("hi\nworld")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw(":)")), + content: BufferItemContent::SimpleText(Text::raw(":)")), prerender: &prerender2, unique_id: None, }; @@ -195,7 +195,7 @@ fn test_single_item_tight() { let mut bl = Backlog::new(config()); let prerender = Prerender::new(); let item = BufferItem { - content: BufferItemContent::Text(Text::raw("hello")), + content: BufferItemContent::SimpleText(Text::raw("hello")), prerender: &prerender, unique_id: None, }; @@ -221,13 +221,13 @@ fn test_two_items() { let mut bl = Backlog::new(config()); let prerender1 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: None, }; let prerender2 = Prerender::new(); let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: None, }; @@ -255,12 +255,12 @@ fn test_two_items_scroll() { let prerender2 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: Some(123), }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: Some(456), }; @@ -283,12 +283,12 @@ fn test_two_items_scroll() { bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: Some(123), }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: Some(456), }; @@ -311,12 +311,12 @@ fn test_two_items_scroll() { bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: Some(123), }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: Some(456), }; @@ -342,13 +342,13 @@ fn test_two_items_multiline() { let mut bl = Backlog::new(config()); let prerender1 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: None, }; let prerender2 = Prerender::new(); let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world\n!")), + content: BufferItemContent::SimpleText(Text::raw("world\n!")), prerender: &prerender2, unique_id: None, }; @@ -374,13 +374,13 @@ fn test_two_items_tight() { let mut bl = Backlog::new(config()); let prerender1 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: None, }; let prerender2 = Prerender::new(); let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: None, }; @@ -405,7 +405,7 @@ fn test_cache_moved() { let mut bl = Backlog::new(config()); let prerender1 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: None, }; @@ -428,13 +428,13 @@ fn test_cache_moved() { // New item added at bottom let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi")), + content: BufferItemContent::SimpleText(Text::raw("hi")), prerender: &prerender1, unique_id: None, }; let prerender2 = Prerender::new(); let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("world")), + content: BufferItemContent::SimpleText(Text::raw("world")), prerender: &prerender2, unique_id: None, }; @@ -462,17 +462,17 @@ fn test_overflow_and_scroll() { let prerender3 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("line1 x")), + content: BufferItemContent::SimpleText(Text::raw("line1 x")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")), + content: BufferItemContent::SimpleText(Text::raw("line2 y\nline3 y\nline4 y")), prerender: &prerender2, unique_id: None, }; let item3 = BufferItem { - content: BufferItemContent::Text(Text::raw("line5 z")), + content: BufferItemContent::SimpleText(Text::raw("line5 z")), prerender: &prerender3, unique_id: None, }; @@ -498,17 +498,17 @@ fn test_overflow_and_scroll() { bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("line1 x")), + content: BufferItemContent::SimpleText(Text::raw("line1 x")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")), + content: BufferItemContent::SimpleText(Text::raw("line2 y\nline3 y\nline4 y")), prerender: &prerender2, unique_id: None, }; let item3 = BufferItem { - content: BufferItemContent::Text(Text::raw("line5 z")), + content: BufferItemContent::SimpleText(Text::raw("line5 z")), prerender: &prerender3, unique_id: None, }; @@ -534,17 +534,17 @@ fn test_overflow_and_scroll() { bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("line1 x")), + content: BufferItemContent::SimpleText(Text::raw("line1 x")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")), + content: BufferItemContent::SimpleText(Text::raw("line2 y\nline3 y\nline4 y")), prerender: &prerender2, unique_id: None, }; let item3 = BufferItem { - content: BufferItemContent::Text(Text::raw("line5 z")), + content: BufferItemContent::SimpleText(Text::raw("line5 z")), prerender: &prerender3, unique_id: None, }; @@ -569,17 +569,17 @@ fn test_overflow_and_scroll() { bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("line1 x")), + content: BufferItemContent::SimpleText(Text::raw("line1 x")), prerender: &prerender1, unique_id: None, }; let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")), + content: BufferItemContent::SimpleText(Text::raw("line2 y\nline3 y\nline4 y")), prerender: &prerender2, unique_id: None, }; let item3 = BufferItem { - content: BufferItemContent::Text(Text::raw("line5 z")), + content: BufferItemContent::SimpleText(Text::raw("line5 z")), prerender: &prerender3, unique_id: None, }; @@ -608,7 +608,7 @@ fn test_scrolledup_new_line() { let mut bl = Backlog::new(config()); let prerender1 = Prerender::new(); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi\nworld")), + content: BufferItemContent::SimpleText(Text::raw("hi\nworld")), prerender: &prerender1, unique_id: Some(123), }; @@ -632,7 +632,7 @@ fn test_scrolledup_new_line() { // Scroll up one line bl.scroll_up(1); let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi\nworld")), + content: BufferItemContent::SimpleText(Text::raw("hi\nworld")), prerender: &prerender1, unique_id: Some(123), }; @@ -653,13 +653,13 @@ fn test_scrolledup_new_line() { // New item added at bottom, displayed paragraph should not move up let item1 = BufferItem { - content: BufferItemContent::Text(Text::raw("hi\nworld")), + content: BufferItemContent::SimpleText(Text::raw("hi\nworld")), prerender: &prerender1, unique_id: Some(123), }; let prerender2 = Prerender::new(); let item2 = BufferItem { - content: BufferItemContent::Text(Text::raw("!")), + content: BufferItemContent::SimpleText(Text::raw("!")), prerender: &prerender2, unique_id: Some(456), };