Remove unused files

This commit is contained in:
Joscha 2022-08-02 01:42:10 +02:00
parent 9ac646174c
commit baa49107f1
4 changed files with 0 additions and 520 deletions

View file

@ -1,97 +0,0 @@
use std::sync::Arc;
use parking_lot::FairMutex;
use toss::terminal::Terminal;
use crate::store::{Msg, MsgStore};
use crate::ui::util;
use super::{Cursor, InnerTreeViewState};
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
pub async fn reply_normal(
&self,
terminal: &mut Terminal,
crossterm_lock: &Arc<FairMutex<()>>,
) -> Option<(Option<M::Id>, String)> {
match &self.cursor {
Cursor::Bottom => {
if let Some(content) = util::prompt(terminal, crossterm_lock) {
return Some((None, content));
}
}
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let tree = self.store.tree(path.first()).await;
let parent_id = if tree.next_sibling(msg).is_some() {
// A reply to a message that has further siblings should be a
// direct reply. An indirect reply might end up a lot further
// down in the current conversation.
msg.clone()
} else if let Some(parent) = tree.parent(msg) {
// A reply to a message without younger siblings should be
// an indirect reply so as not to create unnecessarily deep
// threads. In the case that our message has children, this
// might get a bit confusing. I'm not sure yet how well this
// "smart" reply actually works in practice.
parent
} else {
// When replying to a top-level message, it makes sense to avoid
// creating unnecessary new threads.
msg.clone()
};
if let Some(content) = util::prompt(terminal, crossterm_lock) {
return Some((Some(parent_id), content));
}
}
_ => {}
}
None
}
/// Does approximately the opposite of [`Self::reply_normal`].
pub async fn reply_alternate(
&self,
terminal: &mut Terminal,
crossterm_lock: &Arc<FairMutex<()>>,
) -> Option<(Option<M::Id>, String)> {
match &self.cursor {
Cursor::Bottom => {
if let Some(content) = util::prompt(terminal, crossterm_lock) {
return Some((None, content));
}
}
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let tree = self.store.tree(path.first()).await;
let parent_id = if tree.next_sibling(msg).is_none() {
// The opposite of replying normally
msg.clone()
} else if let Some(parent) = tree.parent(msg) {
// The opposite of replying normally
parent
} else {
// The same as replying normally, still to avoid creating
// unnecessary new threads
msg.clone()
};
if let Some(content) = util::prompt(terminal, crossterm_lock) {
return Some((Some(parent_id), content));
}
}
_ => {}
}
None
}
pub fn create_new_thread(
terminal: &mut Terminal,
crossterm_lock: &Arc<FairMutex<()>>,
) -> Option<(Option<M::Id>, String)> {
util::prompt(terminal, crossterm_lock).map(|content| (None, content))
}
}

View file

@ -1,267 +0,0 @@
//! Intermediate representation of chat history as blocks of things.
use std::collections::{vec_deque, VecDeque};
use std::iter;
use time::OffsetDateTime;
use toss::styled::Styled;
use crate::macros::some_or_return;
#[derive(Debug, Clone, Copy)]
pub enum MarkerBlock<I> {
After(I), // TODO Is this marker necessary?
Bottom,
}
#[derive(Debug, Clone)]
pub enum MsgContent {
Msg { nick: Styled, lines: Vec<Styled> },
Placeholder,
}
#[derive(Debug, Clone)]
pub struct MsgBlock<I> {
pub id: I,
pub content: MsgContent,
}
impl<I> MsgBlock<I> {
pub fn height(&self) -> i32 {
match &self.content {
MsgContent::Msg { lines, .. } => lines.len() as i32,
MsgContent::Placeholder => 1,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ComposeBlock {
// TODO Editor widget
}
#[derive(Debug, Clone)]
pub enum BlockBody<I> {
Marker(MarkerBlock<I>),
Msg(MsgBlock<I>),
Compose(ComposeBlock),
}
#[derive(Debug, Clone)]
pub struct Block<I> {
pub line: i32,
pub time: Option<OffsetDateTime>,
pub indent: usize,
pub body: BlockBody<I>,
}
impl<I> Block<I> {
pub fn bottom(line: i32) -> Self {
Self {
line,
time: None,
indent: 0,
body: BlockBody::Marker(MarkerBlock::Bottom),
}
}
pub fn after(indent: usize, id: I) -> Self {
Self {
line: 0,
time: None,
indent,
body: BlockBody::Marker(MarkerBlock::After(id)),
}
}
pub fn msg(
time: OffsetDateTime,
indent: usize,
id: I,
nick: Styled,
lines: Vec<Styled>,
) -> Self {
Self {
line: 0,
time: Some(time),
indent,
body: BlockBody::Msg(MsgBlock {
id,
content: MsgContent::Msg { nick, lines },
}),
}
}
pub fn placeholder(time: Option<OffsetDateTime>, indent: usize, id: I) -> Self {
Self {
line: 0,
time,
indent,
body: BlockBody::Msg(MsgBlock {
id,
content: MsgContent::Placeholder,
}),
}
}
pub fn height(&self) -> i32 {
match &self.body {
BlockBody::Marker(m) => 0,
BlockBody::Msg(m) => m.height(),
BlockBody::Compose(e) => todo!(),
}
}
}
/// Pre-layouted messages as a sequence of blocks.
///
/// These blocks are straightforward to render, but also provide a level of
/// abstraction between the layouting and actual displaying of messages.
///
/// The following equation describes the relationship between the
/// [`Blocks::top_line`] and [`Blocks::bottom_line`] fields:
///
/// `bottom_line - top_line = sum of all heights - 1`
///
/// This ensures that `top_line` is always the first line and `bottom_line` is
/// always the last line in a nonempty [`Blocks`]. In an empty layout, the
/// equation simplifies to
///
/// `bottom_line = top_line - 1`
#[derive(Debug, Clone)]
pub struct Blocks<I> {
pub blocks: VecDeque<Block<I>>,
/// The top line of the first block. Useful for prepending blocks,
/// especially to empty [`Blocks`]s.
pub top_line: i32,
/// The bottom line of the last block. Useful for appending blocks,
/// especially to empty [`Blocks`]s.
pub bottom_line: i32,
/// The root of the first and last tree, if any. Useful for figuring out
/// which blocks to prepend or append.
pub roots: Option<(I, I)>,
}
impl<I> Blocks<I> {
pub fn new() -> Self {
Self {
blocks: VecDeque::new(),
top_line: 1,
bottom_line: 0,
roots: None,
}
}
pub fn new_bottom(line: i32) -> Self {
Self {
blocks: iter::once(Block::bottom(line)).collect(),
top_line: line,
bottom_line: line - 1,
roots: None,
}
}
pub fn find<F>(&self, f: F) -> Option<&Block<I>>
where
F: Fn(&Block<I>) -> bool,
{
self.blocks.iter().find(|b| f(b))
}
pub fn iter(&self) -> vec_deque::Iter<Block<I>> {
self.blocks.iter()
}
pub fn update<F>(&mut self, f: F)
where
F: Fn(&mut Block<I>),
{
for block in &mut self.blocks {
f(block);
}
}
fn find_index_and_line<F>(&self, f: F) -> Option<(usize, i32)>
where
F: Fn(&Block<I>) -> Option<i32>,
{
self.blocks
.iter()
.enumerate()
.find_map(|(i, b)| f(b).map(|l| (i, l)))
}
/// Update the offsets such that the line of the first block with a `Some`
/// return value becomes that value.
pub fn recalculate_offsets<F>(&mut self, f: F)
where
F: Fn(&Block<I>) -> Option<i32>,
{
let (idx, line) = some_or_return!(self.find_index_and_line(f));
// Propagate lines from index to both ends
self.blocks[idx].line = line;
for i in (0..idx).rev() {
self.blocks[i].line = self.blocks[i + 1].line - self.blocks[i].height();
}
for i in (idx + 1)..self.blocks.len() {
self.blocks[i].line = self.blocks[i - 1].line + self.blocks[i - 1].height();
}
self.top_line = self.blocks.front().expect("blocks nonempty").line;
let bottom = self.blocks.back().expect("blocks nonempty");
self.bottom_line = bottom.line + bottom.height() - 1;
}
pub fn push_front(&mut self, mut block: Block<I>) {
self.top_line -= block.height();
block.line = self.top_line;
self.blocks.push_front(block);
}
pub fn push_back(&mut self, mut block: Block<I>) {
block.line = self.bottom_line + 1;
self.bottom_line += block.height();
self.blocks.push_back(block);
}
pub fn offset(&mut self, delta: i32) {
self.top_line += delta;
self.bottom_line += delta;
for block in &mut self.blocks {
block.line += delta;
}
}
}
impl<I: Ord> Blocks<I> {
pub fn prepend(&mut self, mut layout: Self) {
while let Some(block) = layout.blocks.pop_back() {
self.push_front(block);
}
if let Some((l_root_top, l_root_bot)) = layout.roots {
if let Some((root_top, _)) = &mut self.roots {
assert!(l_root_bot < *root_top);
*root_top = l_root_top;
} else {
self.roots = Some((l_root_top, l_root_bot));
}
}
}
pub fn append(&mut self, mut layout: Self) {
while let Some(block) = layout.blocks.pop_front() {
self.push_back(block);
}
if let Some((l_root_top, l_root_bot)) = layout.roots {
if let Some((_, root_bot)) = &mut self.roots {
assert!(l_root_top > *root_bot);
*root_bot = l_root_bot;
} else {
self.roots = Some((l_root_top, l_root_bot));
}
}
}
}

View file

@ -1,109 +0,0 @@
//! Rendering blocks to a [`Frame`].
use time::OffsetDateTime;
use toss::frame::{Frame, Pos};
use toss::styled::Styled;
use crate::store::{Msg, MsgStore};
use super::blocks::{Block, BlockBody, MsgBlock, MsgContent};
use super::{util, InnerTreeViewState};
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
fn render_time(frame: &mut Frame, line: i32, time: Option<OffsetDateTime>, is_cursor: bool) {
let pos = Pos::new(0, line);
let style = if is_cursor {
util::style_time_inverted()
} else {
util::style_time()
};
if let Some(time) = time {
let time = time
.format(util::TIME_FORMAT)
.expect("time can be formatted");
frame.write(pos, (&time, style));
} else {
frame.write(pos, (util::TIME_EMPTY, style));
}
}
fn render_indent(frame: &mut Frame, line: i32, indent: usize, is_cursor: bool) {
let pos = Pos::new(util::after_indent(0), line);
let style = if is_cursor {
util::style_indent_inverted()
} else {
util::style_indent()
};
let mut styled = Styled::default();
for _ in 0..indent {
styled = styled.then((util::INDENT, style));
}
frame.write(pos, styled);
}
fn render_nick(frame: &mut Frame, line: i32, indent: usize, nick: Styled) {
let nick_pos = Pos::new(util::after_indent(indent), line);
let styled = Styled::new("[").and_then(nick).then("]");
frame.write(nick_pos, styled);
}
fn draw_msg_block(
frame: &mut Frame,
line: i32,
time: Option<OffsetDateTime>,
indent: usize,
msg: &MsgBlock<M::Id>,
is_cursor: bool,
) {
match &msg.content {
MsgContent::Msg { nick, lines } => {
let height: i32 = frame.size().height.into();
let after_nick = util::after_nick(frame, indent, nick);
for (i, text) in lines.iter().enumerate() {
let line = line + i as i32;
if line < 0 || line >= height {
continue;
}
if i == 0 {
Self::render_indent(frame, line, indent, is_cursor);
Self::render_time(frame, line, time, is_cursor);
Self::render_nick(frame, line, indent, nick.clone());
} else {
Self::render_indent(frame, line, indent + 1, false);
Self::render_indent(frame, line, indent, is_cursor);
Self::render_time(frame, line, None, is_cursor);
}
frame.write(Pos::new(after_nick, line), text.clone());
}
}
MsgContent::Placeholder => {
Self::render_time(frame, line, time, is_cursor);
Self::render_indent(frame, line, indent, is_cursor);
let pos = Pos::new(util::after_indent(indent), line);
frame.write(pos, (util::PLACEHOLDER, util::style_placeholder()));
}
}
}
fn draw_block(frame: &mut Frame, block: &Block<M::Id>, is_cursor: bool) {
match &block.body {
BlockBody::Marker(_) => {}
BlockBody::Msg(msg) => {
Self::draw_msg_block(frame, block.line, block.time, block.indent, msg, is_cursor)
}
BlockBody::Compose(_) => {}
}
}
pub fn draw_blocks(&self, frame: &mut Frame) {
for block in self.last_blocks.iter() {
Self::draw_block(frame, block, self.cursor.matches_block(block));
}
}
}

View file

@ -1,47 +0,0 @@
//! Constants and helper functions.
use crossterm::style::{ContentStyle, Stylize};
use time::format_description::FormatItem;
use time::macros::format_description;
use toss::frame::Frame;
use toss::styled::Styled;
pub const TIME_FORMAT: &[FormatItem<'_>] =
format_description!("[year]-[month]-[day] [hour]:[minute] ");
pub const TIME_EMPTY: &str = " ";
pub const TIME_WIDTH: usize = TIME_EMPTY.len();
pub fn style_time() -> ContentStyle {
ContentStyle::default().grey()
}
pub fn style_time_inverted() -> ContentStyle {
ContentStyle::default().black().on_white()
}
pub const INDENT: &str = "";
pub const INDENT_WIDTH: usize = 2;
pub fn style_indent() -> ContentStyle {
ContentStyle::default().dark_grey()
}
pub fn style_indent_inverted() -> ContentStyle {
ContentStyle::default().black().on_white()
}
pub const PLACEHOLDER: &str = "[...]";
pub fn style_placeholder() -> ContentStyle {
ContentStyle::default().dark_grey()
}
pub const MIN_CONTENT_WIDTH: usize = "[+, 1234 more]".len();
pub fn after_indent(indent: usize) -> i32 {
(TIME_WIDTH + indent * INDENT_WIDTH) as i32
}
pub fn after_nick(frame: &mut Frame, indent: usize, nick: &Styled) -> i32 {
after_indent(indent) + 1 + frame.width_styled(nick) as i32 + 2
}