Add '> ' prefix before each line of a blockquote, even after line-wrapping
This commit is contained in:
@ -89,7 +89,7 @@ impl Buffer for LogBuffer {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.map(|(line_id, line, prerender)| BufferItem {
|
.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);
|
tracing::error!("Could not convert line from ANSI codes to ratatui: {}", e);
|
||||||
Text::raw(line)
|
Text::raw(line)
|
||||||
})),
|
})),
|
||||||
|
@ -22,6 +22,7 @@ use futures::StreamExt;
|
|||||||
use matrix_sdk::async_trait;
|
use matrix_sdk::async_trait;
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
use ratatui::text::Text;
|
use ratatui::text::Text;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use sorted_vec::SortedVec;
|
use sorted_vec::SortedVec;
|
||||||
|
|
||||||
use crate::widgets::Prerender;
|
use crate::widgets::Prerender;
|
||||||
@ -92,7 +93,9 @@ impl PartialOrd for BufferSortKey {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum BufferItemContent<'buf> {
|
pub enum BufferItemContent<'buf> {
|
||||||
Text(Text<'buf>),
|
SimpleText(Text<'buf>),
|
||||||
|
/// Pairs of `(padding, content)`
|
||||||
|
Text(Vec<(String, Text<'buf>)>),
|
||||||
Divider(Text<'buf>),
|
Divider(Text<'buf>),
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,17 @@ use crate::widgets::Prerender;
|
|||||||
/// Like [`BufferItemContent`] but owned.
|
/// Like [`BufferItemContent`] but owned.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum OwnedBufferItemContent {
|
pub enum OwnedBufferItemContent {
|
||||||
Text {
|
SimpleText {
|
||||||
event_id: Option<OwnedEventId>,
|
event_id: Option<OwnedEventId>,
|
||||||
is_message: bool,
|
is_message: bool,
|
||||||
text: Text<'static>,
|
text: Text<'static>,
|
||||||
},
|
},
|
||||||
|
Text {
|
||||||
|
event_id: Option<OwnedEventId>,
|
||||||
|
is_message: bool,
|
||||||
|
/// `(padding, content)` pairs
|
||||||
|
text: Vec<(String, Text<'static>)>,
|
||||||
|
},
|
||||||
Divider(String),
|
Divider(String),
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
@ -71,19 +77,32 @@ impl DynamicUsage for OwnedBufferItemContent {
|
|||||||
fn dynamic_usage(&self) -> usize {
|
fn dynamic_usage(&self) -> usize {
|
||||||
std::mem::size_of::<Self>()
|
std::mem::size_of::<Self>()
|
||||||
+ match self {
|
+ match self {
|
||||||
OwnedBufferItemContent::Text { text, .. } => {
|
OwnedBufferItemContent::SimpleText { text, .. } => {
|
||||||
text.width() * text.height() * 4 // FIXME: rough approx
|
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::Divider(s) => s.dynamic_usage(),
|
||||||
OwnedBufferItemContent::Empty => 0,
|
OwnedBufferItemContent::Empty => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
|
fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
|
||||||
let (min, max) = match self {
|
let (min, max) = match self {
|
||||||
OwnedBufferItemContent::Text { text, .. } => {
|
OwnedBufferItemContent::SimpleText { text, .. } => {
|
||||||
let area = text.width() * text.height();
|
let area = text.width() * text.height();
|
||||||
(area, Some(area * 12)) // FIXME: rough approx
|
(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::Divider(s) => s.dynamic_usage_bounds(),
|
||||||
OwnedBufferItemContent::Empty => (0, Some(0)),
|
OwnedBufferItemContent::Empty => (0, Some(0)),
|
||||||
};
|
};
|
||||||
@ -175,22 +194,22 @@ impl SingleClientRoomBuffer {
|
|||||||
|
|
||||||
// Like `format!()` but returns OwnedBufferItemContent::Text, with is_message=false
|
// Like `format!()` but returns OwnedBufferItemContent::Text, with is_message=false
|
||||||
macro_rules! text {
|
macro_rules! text {
|
||||||
($($tokens:tt)*) => {
|
($prefix: expr, $($tokens:tt)*) => {
|
||||||
OwnedBufferItemContent::Text {
|
OwnedBufferItemContent::Text {
|
||||||
event_id: event.event_id().map(ToOwned::to_owned),
|
event_id: event.event_id().map(ToOwned::to_owned),
|
||||||
is_message: false,
|
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
|
// Like `format!()` but returns OwnedBufferItemContent::Text, with is_message=true
|
||||||
macro_rules! msg {
|
macro_rules! msg {
|
||||||
($($tokens:tt)*) => {
|
($prefix: expr, $($tokens:tt)*) => {
|
||||||
OwnedBufferItemContent::Text {
|
OwnedBufferItemContent::Text {
|
||||||
event_id: event.event_id().map(ToOwned::to_owned),
|
event_id: event.event_id().map(ToOwned::to_owned),
|
||||||
is_message: true,
|
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",
|
"FormattedBody::sanitize_html set type to {:?} instead of Html",
|
||||||
formatted.format
|
formatted.format
|
||||||
);
|
);
|
||||||
msg!(" <{}> {}", sender, formatted.body)
|
msg!(" ", "<{}> {}", sender, formatted.body)
|
||||||
},
|
},
|
||||||
MessageType::Text(TextMessageEventContent { body, .. }) => {
|
MessageType::Text(TextMessageEventContent { body, .. }) => {
|
||||||
msg!(" <{}> {}", sender, escape_html(body))
|
msg!(" ", "<{}> {}", sender, escape_html(body))
|
||||||
},
|
},
|
||||||
_ =>
|
_ =>
|
||||||
// Fallback to text body
|
// Fallback to text body
|
||||||
{
|
{
|
||||||
msg!(
|
msg!(
|
||||||
|
" ",
|
||||||
"<{}> {}",
|
"<{}> {}",
|
||||||
sender,
|
sender,
|
||||||
escape_html(&message.body().replace('\n', "\n "))
|
escape_html(&message.body().replace('\n', "\n "))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RedactedMessage => msg!("xx <{}> [redacted]", sender),
|
RedactedMessage => msg!("xx ", "<{}> [redacted]", sender),
|
||||||
Sticker(sticker) => msg!(
|
Sticker(sticker) => msg!(
|
||||||
"st <{}> {}",
|
"st ",
|
||||||
|
"<{}> {}",
|
||||||
sender,
|
sender,
|
||||||
escape_html(&sticker.content().body)
|
escape_html(&sticker.content().body)
|
||||||
),
|
),
|
||||||
UnableToDecrypt(_) => text!("xx <{}> [unable to decrypt]", sender),
|
UnableToDecrypt(_) => text!("xx ", "<{}> [unable to decrypt]", sender),
|
||||||
MembershipChange(change) => {
|
MembershipChange(change) => {
|
||||||
use matrix_sdk_ui::timeline::MembershipChange::*;
|
use matrix_sdk_ui::timeline::MembershipChange::*;
|
||||||
if change.user_id() == event.sender() {
|
if change.user_id() == event.sender() {
|
||||||
let Some(change_kind) = change.change() else {
|
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 {
|
match change_kind {
|
||||||
None => text!("--- {} made no discernable changes to themselves", sender),
|
None => text!(
|
||||||
Error => text!(
|
"--- ",
|
||||||
"xxx {} made a change to themselves that made matrix-sdk-ui error",
|
"{} made no discernable changes to themselves",
|
||||||
sender
|
sender
|
||||||
),
|
),
|
||||||
Joined => text!("--> {} joined", sender),
|
Error => text!(
|
||||||
Left => text!("<-- {} left", sender),
|
"xxx ",
|
||||||
Banned => text!("-x- {} banned themselves", sender),
|
"{} made a change to themselves that made matrix-sdk-ui error",
|
||||||
Unbanned => text!("-x- {} unbanned themselves", sender),
|
sender
|
||||||
Kicked => text!("<!- {} kicked themselves", sender),
|
),
|
||||||
Invited => text!("-o- {} invited themselves", sender),
|
Joined => text!("--> ", "{} joined", sender),
|
||||||
KickedAndBanned => text!("<!x {} kicked and banned themselves", sender),
|
Left => text!("<-- ", "{} left", sender),
|
||||||
InvitationAccepted => text!("-o> {} accepted an invite", sender),
|
Banned => text!("-x- ", "{} banned themselves", sender),
|
||||||
InvitationRejected => text!("-ox {} rejected an invite", sender),
|
Unbanned => text!("-x- ", "{} unbanned themselves", sender),
|
||||||
InvitationRevoked => text!("--x {} revoked an invite", sender),
|
Kicked => text!("<!- ", "{} kicked themselves", sender),
|
||||||
Knocked => text!("-?> {} knocked", sender),
|
Invited => text!("-o- ", "{} invited themselves", sender),
|
||||||
KnockAccepted => text!("-?o {} accepted a knock", sender),
|
KickedAndBanned => text!("<!x ", "{} kicked and banned themselves", sender),
|
||||||
KnockRetracted => text!("-?x {} retracted a knock", sender),
|
InvitationAccepted => text!("-o> ", "{} accepted an invite", sender),
|
||||||
KnockDenied => text!("-?x {} denied a knock", 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!(
|
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
|
sender
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else if change.user_id() == "" {
|
} else if change.user_id() == "" {
|
||||||
let Some(change_kind) = change.change() else {
|
let Some(change_kind) = change.change() else {
|
||||||
return text!("--- {} made incomprehensible changes", sender);
|
return text!("--- ", "{} made incomprehensible changes", sender);
|
||||||
};
|
};
|
||||||
match change_kind {
|
match change_kind {
|
||||||
None => text!("--- {} made no discernable changes", sender),
|
None => text!("--- ", "{} made no discernable changes", sender),
|
||||||
Error => text!("xxx {} made a change that made matrix-sdk-ui error", sender),
|
Error => text!(
|
||||||
|
"xxx ",
|
||||||
|
"{} made a change that made matrix-sdk-ui error",
|
||||||
|
sender
|
||||||
|
),
|
||||||
Joined | Left | Banned | Unbanned | Kicked | Invited | KickedAndBanned
|
Joined | Left | Banned | Unbanned | Kicked | Invited | KickedAndBanned
|
||||||
| InvitationAccepted | InvitationRejected | InvitationRevoked | Knocked
|
| InvitationAccepted | InvitationRejected | InvitationRevoked | Knocked
|
||||||
| KnockAccepted | KnockRetracted | KnockDenied => {
|
| KnockAccepted | KnockRetracted | KnockDenied => {
|
||||||
text!("--> {} made a non-sensical change: {:?}", sender, change)
|
text!(
|
||||||
|
"--> ",
|
||||||
|
"{} made a non-sensical change: {:?}",
|
||||||
|
sender,
|
||||||
|
change
|
||||||
|
)
|
||||||
},
|
},
|
||||||
NotImplemented => text!(
|
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
|
sender
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -297,35 +338,48 @@ impl SingleClientRoomBuffer {
|
|||||||
);
|
);
|
||||||
let target = markup_colored_by_mxid(&target, &target);
|
let target = markup_colored_by_mxid(&target, &target);
|
||||||
let Some(change_kind) = change.change() else {
|
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 {
|
match change_kind {
|
||||||
None => text!("--- {} made no discernable changes to {}", sender, target),
|
None => text!(
|
||||||
|
"--- ",
|
||||||
|
"{} made no discernable changes to {}",
|
||||||
|
sender,
|
||||||
|
target
|
||||||
|
),
|
||||||
Error => text!(
|
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,
|
sender,
|
||||||
target
|
target
|
||||||
),
|
),
|
||||||
Joined | Left => text!(
|
Joined | Left => text!(
|
||||||
"--> {} made a non-sensical change to {}: {:?}",
|
"--> ",
|
||||||
|
"{} made a non-sensical change to {}: {:?}",
|
||||||
sender,
|
sender,
|
||||||
target,
|
target,
|
||||||
change
|
change
|
||||||
),
|
),
|
||||||
Banned => text!("-x- {} banned {}", sender, target),
|
Banned => text!("-x- ", "{} banned {}", sender, target),
|
||||||
Unbanned => text!("-x- {} unbanned {}", sender, target),
|
Unbanned => text!("-x- ", "{} unbanned {}", sender, target),
|
||||||
Kicked => text!("<!- {} kicked {}", sender, target),
|
Kicked => text!("<!- ", "{} kicked {}", sender, target),
|
||||||
Invited => text!("-o- {} invited {}", sender, target),
|
Invited => text!("-o- ", "{} invited {}", sender, target),
|
||||||
KickedAndBanned => text!("<!x {} kicked and banned {}", sender, target),
|
KickedAndBanned => text!("<!x ", "{} kicked and banned {}", sender, target),
|
||||||
InvitationAccepted => text!("-o> {} accepted an invite to {}", sender, target),
|
InvitationAccepted => text!("-o> ", "{} accepted an invite to {}", sender, target),
|
||||||
InvitationRejected => text!("-ox {} rejected an invite to {}", sender, target),
|
InvitationRejected => text!("-ox ", "{} rejected an invite to {}", sender, target),
|
||||||
InvitationRevoked => text!("--x {} revoked an invite to {}", sender, target),
|
InvitationRevoked => text!("--x ", "{} revoked an invite to {}", sender, target),
|
||||||
Knocked => text!("-?> {} made {} knock", sender, target),
|
Knocked => text!("-?> ", "{} made {} knock", sender, target),
|
||||||
KnockAccepted => text!("-?o {} accepted {}'s knock", sender, target),
|
KnockAccepted => text!("-?o ", "{} accepted {}'s knock", sender, target),
|
||||||
KnockRetracted => text!("-?x {} retracted {}'s knock", sender, target),
|
KnockRetracted => text!("-?x ", "{} retracted {}'s knock", sender, target),
|
||||||
KnockDenied => text!("-?x {} denied {}'s knock", sender, target),
|
KnockDenied => text!("-?x ", "{} denied {}'s knock", sender, target),
|
||||||
NotImplemented => text!(
|
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,
|
sender,
|
||||||
target
|
target
|
||||||
),
|
),
|
||||||
@ -333,13 +387,14 @@ impl SingleClientRoomBuffer {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ProfileChange(_) => text!("--- {} updated their profile", sender),
|
ProfileChange(_) => text!("--- ", "{} updated their profile", sender),
|
||||||
OtherState(state) => {
|
OtherState(state) => {
|
||||||
if state.state_key() == "" {
|
if state.state_key() == "" {
|
||||||
text!("--- {} changed the room: {:?}", sender, state.content())
|
text!("--- ", "{} changed the room: {:?}", sender, state.content())
|
||||||
} else {
|
} else {
|
||||||
text!(
|
text!(
|
||||||
"--- {} changed {}: {:?}",
|
"--- ",
|
||||||
|
"{} changed {}: {:?}",
|
||||||
sender,
|
sender,
|
||||||
escape_html(state.state_key()),
|
escape_html(state.state_key()),
|
||||||
state.content() // TODO: escape html
|
state.content() // TODO: escape html
|
||||||
@ -347,7 +402,8 @@ impl SingleClientRoomBuffer {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
FailedToParseMessageLike { event_type, error } => text!(
|
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,
|
sender,
|
||||||
escape_html(&event_type.to_string()),
|
escape_html(&event_type.to_string()),
|
||||||
error // TODO: escape html
|
error // TODO: escape html
|
||||||
@ -358,14 +414,15 @@ impl SingleClientRoomBuffer {
|
|||||||
error,
|
error,
|
||||||
} => {
|
} => {
|
||||||
text!(
|
text!(
|
||||||
"xxx {} made a {} change to {} that made matrix-sdk-ui error: {:?}",
|
"xxx ",
|
||||||
|
"{} made a {} change to {} that made matrix-sdk-ui error: {:?}",
|
||||||
sender,
|
sender,
|
||||||
escape_html(&event_type.to_string()),
|
escape_html(&event_type.to_string()),
|
||||||
escape_html(state_key),
|
escape_html(state_key),
|
||||||
error // TODO: escape html
|
error // TODO: escape html
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Poll(_) => text!("-?- {} acted on a poll", sender),
|
Poll(_) => text!("-?- ", "{} acted on a poll", sender),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker) => {
|
TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker) => {
|
||||||
@ -492,7 +549,7 @@ impl RoomBuffer {
|
|||||||
.map(|item| {
|
.map(|item| {
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
OwnedBufferItemContent::Text {
|
OwnedBufferItemContent::SimpleText {
|
||||||
event_id: None,
|
event_id: None,
|
||||||
is_message: false,
|
is_message: false,
|
||||||
text: Text::raw(format!("Initial item: {:#?}", item)),
|
text: Text::raw(format!("Initial item: {:#?}", item)),
|
||||||
@ -638,6 +695,9 @@ impl Buffer for RoomBuffer {
|
|||||||
.rev()
|
.rev()
|
||||||
.map(|(line_id, line, prerender)| BufferItem {
|
.map(|(line_id, line, prerender)| BufferItem {
|
||||||
content: match line {
|
content: match line {
|
||||||
|
OwnedBufferItemContent::SimpleText { text, .. } => {
|
||||||
|
BufferItemContent::SimpleText(text.clone())
|
||||||
|
},
|
||||||
OwnedBufferItemContent::Text { text, .. } => BufferItemContent::Text(text.clone()),
|
OwnedBufferItemContent::Text { text, .. } => BufferItemContent::Text(text.clone()),
|
||||||
OwnedBufferItemContent::Divider(text) => BufferItemContent::Divider(Text::raw(text)),
|
OwnedBufferItemContent::Divider(text) => BufferItemContent::Divider(Text::raw(text)),
|
||||||
OwnedBufferItemContent::Empty => BufferItemContent::Empty,
|
OwnedBufferItemContent::Empty => BufferItemContent::Empty,
|
||||||
|
@ -26,7 +26,8 @@ use crate::components::Action;
|
|||||||
use crate::config::{Config, ScrollAmount};
|
use crate::config::{Config, ScrollAmount};
|
||||||
use crate::widgets::prerender::{PrerenderInner, PrerenderValue};
|
use crate::widgets::prerender::{PrerenderInner, PrerenderValue};
|
||||||
use crate::widgets::{
|
use crate::widgets::{
|
||||||
BacklogItemWidget, BottomAlignedParagraph, Divider, EmptyWidget, OverlappableWidget,
|
BacklogItemWidget, BottomAlignedContainer, BottomAlignedParagraph, Divider, EmptyWidget,
|
||||||
|
OverlappableWidget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Component;
|
use super::Component;
|
||||||
@ -128,7 +129,17 @@ impl Backlog {
|
|||||||
|
|
||||||
fn build_widget<'a>(&self, content: BufferItemContent<'a>, scroll: u64) -> BacklogItemWidget<'a> {
|
fn build_widget<'a>(&self, content: BufferItemContent<'a>, scroll: u64) -> BacklogItemWidget<'a> {
|
||||||
match content {
|
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) => {
|
BufferItemContent::Divider(text) => {
|
||||||
if scroll == 0 {
|
if scroll == 0 {
|
||||||
Divider::new(Paragraph::new(text).alignment(Alignment::Center)).into()
|
Divider::new(Paragraph::new(text).alignment(Alignment::Center)).into()
|
||||||
|
@ -95,23 +95,25 @@ fn format_tree(
|
|||||||
config: &Config,
|
config: &Config,
|
||||||
tree: Rc<Node>,
|
tree: Rc<Node>,
|
||||||
state: &mut FormatState,
|
state: &mut FormatState,
|
||||||
text: &mut Text<'static>,
|
text: &mut Vec<(String, Text<'static>)>,
|
||||||
mut previous_sibling_is_block: bool,
|
mut previous_sibling_is_block: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
use markup5ever_rcdom::NodeData::*;
|
|
||||||
let mut state = match &tree.data {
|
let mut state = match &tree.data {
|
||||||
Document | Doctype { .. } | Comment { .. } | ProcessingInstruction { .. } => state.to_owned(),
|
NodeData::Document
|
||||||
Text { contents } => {
|
| NodeData::Doctype { .. }
|
||||||
|
| NodeData::Comment { .. }
|
||||||
|
| NodeData::ProcessingInstruction { .. } => state.to_owned(),
|
||||||
|
NodeData::Text { contents } => {
|
||||||
let s: String = contents.clone().into_inner().into();
|
let s: String = contents.clone().into_inner().into();
|
||||||
let s = s.replace('\n', ""); // Lines are insignificant in HTML
|
let s = s.replace('\n', ""); // Lines are insignificant in HTML
|
||||||
if previous_sibling_is_block && !s.is_empty() {
|
if previous_sibling_is_block && !s.is_empty() {
|
||||||
text.lines.push(Line {
|
text.push((state.padding.clone(), Text::raw("")));
|
||||||
spans: vec![Span::styled(state.padding.to_owned(), state.style)],
|
|
||||||
alignment: None,
|
|
||||||
});
|
|
||||||
previous_sibling_is_block = false;
|
previous_sibling_is_block = false;
|
||||||
}
|
}
|
||||||
text
|
text
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
.lines
|
.lines
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -119,7 +121,7 @@ fn format_tree(
|
|||||||
.push(Span::styled(s, state.style));
|
.push(Span::styled(s, state.style));
|
||||||
state.to_owned()
|
state.to_owned()
|
||||||
},
|
},
|
||||||
Element {
|
NodeData::Element {
|
||||||
name: QualName {
|
name: QualName {
|
||||||
ns: ns!(html),
|
ns: ns!(html),
|
||||||
local: name,
|
local: name,
|
||||||
@ -173,7 +175,7 @@ fn format_tree(
|
|||||||
state
|
state
|
||||||
},
|
},
|
||||||
local_name!("br") => {
|
local_name!("br") => {
|
||||||
text.lines.push(Line::raw(state.padding.to_owned()));
|
text.push((state.padding.clone(), Text::raw("")));
|
||||||
state.to_owned()
|
state.to_owned()
|
||||||
},
|
},
|
||||||
local_name!("p") => {
|
local_name!("p") => {
|
||||||
@ -202,7 +204,7 @@ fn format_tree(
|
|||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|child| match &child.data {
|
.map(|child| match &child.data {
|
||||||
Element {
|
NodeData::Element {
|
||||||
name:
|
name:
|
||||||
QualName {
|
QualName {
|
||||||
ns: ns!(html),
|
ns: ns!(html),
|
||||||
@ -228,11 +230,8 @@ fn format_tree(
|
|||||||
ListState::None => state.to_owned(),
|
ListState::None => state.to_owned(),
|
||||||
ListState::Unordered => {
|
ListState::Unordered => {
|
||||||
let mut line = Line::default();
|
let mut line = Line::default();
|
||||||
line
|
|
||||||
.spans
|
|
||||||
.push(Span::styled(state.padding.to_owned(), state.style));
|
|
||||||
line.spans.push(Span::styled("* ", state.style));
|
line.spans.push(Span::styled("* ", state.style));
|
||||||
text.lines.push(line);
|
text.push((state.padding.to_owned(), line.into()));
|
||||||
FormatState {
|
FormatState {
|
||||||
padding: state.padding.to_owned() + " ",
|
padding: state.padding.to_owned() + " ",
|
||||||
..state.to_owned()
|
..state.to_owned()
|
||||||
@ -243,9 +242,6 @@ fn format_tree(
|
|||||||
digits,
|
digits,
|
||||||
} => {
|
} => {
|
||||||
let mut line = Line::default();
|
let mut line = Line::default();
|
||||||
line
|
|
||||||
.spans
|
|
||||||
.push(Span::styled(state.padding.to_owned(), state.style));
|
|
||||||
*counter += 1;
|
*counter += 1;
|
||||||
line
|
line
|
||||||
.spans
|
.spans
|
||||||
@ -256,7 +252,7 @@ fn format_tree(
|
|||||||
state.style,
|
state.style,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
text.lines.push(line);
|
text.push((state.padding.to_owned(), line.into()));
|
||||||
FormatState {
|
FormatState {
|
||||||
padding: state.padding.to_owned() + " " + &" ".repeat(digits.into()),
|
padding: state.padding.to_owned() + " " + &" ".repeat(digits.into()),
|
||||||
..state.to_owned()
|
..state.to_owned()
|
||||||
@ -278,7 +274,7 @@ fn format_tree(
|
|||||||
},
|
},
|
||||||
_ => state.to_owned(),
|
_ => 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() {
|
for subtree in tree.children.borrow().iter() {
|
||||||
@ -292,9 +288,12 @@ fn format_tree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
match &tree.data {
|
match &tree.data {
|
||||||
Document | Doctype { .. } | Comment { .. } | ProcessingInstruction { .. } => {},
|
NodeData::Document
|
||||||
Text { .. } => {},
|
| NodeData::Doctype { .. }
|
||||||
Element {
|
| NodeData::Comment { .. }
|
||||||
|
| NodeData::ProcessingInstruction { .. } => {},
|
||||||
|
NodeData::Text { .. } => {},
|
||||||
|
NodeData::Element {
|
||||||
name: QualName {
|
name: QualName {
|
||||||
ns: ns!(html),
|
ns: ns!(html),
|
||||||
local: name,
|
local: name,
|
||||||
@ -308,13 +307,16 @@ fn format_tree(
|
|||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
Element { .. } => {},
|
NodeData::Element { .. } => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_sibling_is_block
|
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(
|
let tree = parse_fragment(
|
||||||
RcDom::default(),
|
RcDom::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
@ -323,11 +325,12 @@ pub fn format_html(config: &Config, s: &str) -> Text<'static> {
|
|||||||
)
|
)
|
||||||
.one(s)
|
.one(s)
|
||||||
.document;
|
.document;
|
||||||
|
let prefix = Text::raw(prefix);
|
||||||
let mut state = FormatState {
|
let mut state = FormatState {
|
||||||
padding: " ".to_owned(),
|
padding: " ".repeat(prefix.width() + 1), // TODO: make +1 configurable
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut text = Text::raw("");
|
let mut text = vec![("".to_owned(), prefix)];
|
||||||
format_tree(config, tree, &mut state, &mut text, false);
|
format_tree(config, tree, &mut state, &mut text, false);
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
133
src/widgets/bottom_aligned_container.rs
Normal file
133
src/widgets/bottom_aligned_container.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ use enum_dispatch::enum_dispatch;
|
|||||||
use ratatui::prelude::*;
|
use ratatui::prelude::*;
|
||||||
use ratatui::widgets::Widget;
|
use ratatui::widgets::Widget;
|
||||||
|
|
||||||
|
mod bottom_aligned_container;
|
||||||
|
pub use bottom_aligned_container::BottomAlignedContainer;
|
||||||
mod bottom_aligned_paragraph;
|
mod bottom_aligned_paragraph;
|
||||||
pub use bottom_aligned_paragraph::BottomAlignedParagraph;
|
pub use bottom_aligned_paragraph::BottomAlignedParagraph;
|
||||||
|
|
||||||
@ -47,6 +49,7 @@ pub trait OverlappableWidget {
|
|||||||
#[enum_dispatch(OverlappableWidget)]
|
#[enum_dispatch(OverlappableWidget)]
|
||||||
pub enum BacklogItemWidget<'a> {
|
pub enum BacklogItemWidget<'a> {
|
||||||
Paragraph(BottomAlignedParagraph<'a>),
|
Paragraph(BottomAlignedParagraph<'a>),
|
||||||
|
Container(BottomAlignedContainer<'a>),
|
||||||
Divider(Divider<'a>),
|
Divider(Divider<'a>),
|
||||||
Empty(EmptyWidget),
|
Empty(EmptyWidget),
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ fn test_single_item() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender = Prerender::new();
|
let prerender = Prerender::new();
|
||||||
let item = BufferItem {
|
let item = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hello")),
|
content: BufferItemContent::SimpleText(Text::raw("hello")),
|
||||||
prerender: &prerender,
|
prerender: &prerender,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -91,7 +91,7 @@ fn test_single_item_cached() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender = Prerender::new();
|
let prerender = Prerender::new();
|
||||||
let item = BufferItem {
|
let item = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hello")),
|
content: BufferItemContent::SimpleText(Text::raw("hello")),
|
||||||
prerender: &prerender,
|
prerender: &prerender,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -116,7 +116,7 @@ fn test_single_item_cached() {
|
|||||||
assert_eq!(prerender.key(), Some(10));
|
assert_eq!(prerender.key(), Some(10));
|
||||||
|
|
||||||
let item = BufferItem {
|
let item = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hello")),
|
content: BufferItemContent::SimpleText(Text::raw("hello")),
|
||||||
prerender: &prerender,
|
prerender: &prerender,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -134,12 +134,12 @@ fn test_only_necessary_width() {
|
|||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
content: BufferItemContent::SimpleText(Text::raw("hi\nworld")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw(":)")),
|
content: BufferItemContent::SimpleText(Text::raw(":)")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -165,12 +165,12 @@ fn test_only_necessary_width() {
|
|||||||
assert_eq!(prerender1.key(), Some(10));
|
assert_eq!(prerender1.key(), Some(10));
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
content: BufferItemContent::SimpleText(Text::raw("hi\nworld")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw(":)")),
|
content: BufferItemContent::SimpleText(Text::raw(":)")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -195,7 +195,7 @@ fn test_single_item_tight() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender = Prerender::new();
|
let prerender = Prerender::new();
|
||||||
let item = BufferItem {
|
let item = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hello")),
|
content: BufferItemContent::SimpleText(Text::raw("hello")),
|
||||||
prerender: &prerender,
|
prerender: &prerender,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -221,13 +221,13 @@ fn test_two_items() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -255,12 +255,12 @@ fn test_two_items_scroll() {
|
|||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: Some(456),
|
unique_id: Some(456),
|
||||||
};
|
};
|
||||||
@ -283,12 +283,12 @@ fn test_two_items_scroll() {
|
|||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: Some(456),
|
unique_id: Some(456),
|
||||||
};
|
};
|
||||||
@ -311,12 +311,12 @@ fn test_two_items_scroll() {
|
|||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: Some(456),
|
unique_id: Some(456),
|
||||||
};
|
};
|
||||||
@ -342,13 +342,13 @@ fn test_two_items_multiline() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world\n!")),
|
content: BufferItemContent::SimpleText(Text::raw("world\n!")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -374,13 +374,13 @@ fn test_two_items_tight() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -405,7 +405,7 @@ fn test_cache_moved() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -428,13 +428,13 @@ fn test_cache_moved() {
|
|||||||
|
|
||||||
// New item added at bottom
|
// New item added at bottom
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi")),
|
content: BufferItemContent::SimpleText(Text::raw("hi")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("world")),
|
content: BufferItemContent::SimpleText(Text::raw("world")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -462,17 +462,17 @@ fn test_overflow_and_scroll() {
|
|||||||
let prerender3 = Prerender::new();
|
let prerender3 = Prerender::new();
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line1 x")),
|
content: BufferItemContent::SimpleText(Text::raw("line1 x")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
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,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item3 = BufferItem {
|
let item3 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line5 z")),
|
content: BufferItemContent::SimpleText(Text::raw("line5 z")),
|
||||||
prerender: &prerender3,
|
prerender: &prerender3,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -498,17 +498,17 @@ fn test_overflow_and_scroll() {
|
|||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line1 x")),
|
content: BufferItemContent::SimpleText(Text::raw("line1 x")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
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,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item3 = BufferItem {
|
let item3 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line5 z")),
|
content: BufferItemContent::SimpleText(Text::raw("line5 z")),
|
||||||
prerender: &prerender3,
|
prerender: &prerender3,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -534,17 +534,17 @@ fn test_overflow_and_scroll() {
|
|||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line1 x")),
|
content: BufferItemContent::SimpleText(Text::raw("line1 x")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
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,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item3 = BufferItem {
|
let item3 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line5 z")),
|
content: BufferItemContent::SimpleText(Text::raw("line5 z")),
|
||||||
prerender: &prerender3,
|
prerender: &prerender3,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -569,17 +569,17 @@ fn test_overflow_and_scroll() {
|
|||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
|
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line1 x")),
|
content: BufferItemContent::SimpleText(Text::raw("line1 x")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item2 = BufferItem {
|
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,
|
prerender: &prerender2,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
let item3 = BufferItem {
|
let item3 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("line5 z")),
|
content: BufferItemContent::SimpleText(Text::raw("line5 z")),
|
||||||
prerender: &prerender3,
|
prerender: &prerender3,
|
||||||
unique_id: None,
|
unique_id: None,
|
||||||
};
|
};
|
||||||
@ -608,7 +608,7 @@ fn test_scrolledup_new_line() {
|
|||||||
let mut bl = Backlog::new(config());
|
let mut bl = Backlog::new(config());
|
||||||
let prerender1 = Prerender::new();
|
let prerender1 = Prerender::new();
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
content: BufferItemContent::SimpleText(Text::raw("hi\nworld")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
@ -632,7 +632,7 @@ fn test_scrolledup_new_line() {
|
|||||||
// Scroll up one line
|
// Scroll up one line
|
||||||
bl.scroll_up(1);
|
bl.scroll_up(1);
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
content: BufferItemContent::SimpleText(Text::raw("hi\nworld")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
@ -653,13 +653,13 @@ fn test_scrolledup_new_line() {
|
|||||||
|
|
||||||
// New item added at bottom, displayed paragraph should not move up
|
// New item added at bottom, displayed paragraph should not move up
|
||||||
let item1 = BufferItem {
|
let item1 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
content: BufferItemContent::SimpleText(Text::raw("hi\nworld")),
|
||||||
prerender: &prerender1,
|
prerender: &prerender1,
|
||||||
unique_id: Some(123),
|
unique_id: Some(123),
|
||||||
};
|
};
|
||||||
let prerender2 = Prerender::new();
|
let prerender2 = Prerender::new();
|
||||||
let item2 = BufferItem {
|
let item2 = BufferItem {
|
||||||
content: BufferItemContent::Text(Text::raw("!")),
|
content: BufferItemContent::SimpleText(Text::raw("!")),
|
||||||
prerender: &prerender2,
|
prerender: &prerender2,
|
||||||
unique_id: Some(456),
|
unique_id: Some(456),
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user