Update toss

This commit is contained in:
Joscha 2023-02-17 20:07:08 +01:00
parent b515ace906
commit 059ff94aef
41 changed files with 165 additions and 179 deletions

3
Cargo.lock generated
View file

@ -1313,8 +1313,9 @@ dependencies = [
[[package]] [[package]]
name = "toss" name = "toss"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/Garmelon/toss.git?rev=0d59116012a51516a821991e2969b1cf4779770f#0d59116012a51516a821991e2969b1cf4779770f" source = "git+https://github.com/Garmelon/toss.git?rev=59710c816269c434b97ece3ab1701d3fef2269cb#59710c816269c434b97ece3ab1701d3fef2269cb"
dependencies = [ dependencies = [
"async-trait",
"crossterm", "crossterm",
"unicode-linebreak", "unicode-linebreak",
"unicode-segmentation", "unicode-segmentation",

View file

@ -43,7 +43,7 @@ features = ["bot"]
[dependencies.toss] [dependencies.toss]
git = "https://github.com/Garmelon/toss.git" git = "https://github.com/Garmelon/toss.git"
rev = "0d59116012a51516a821991e2969b1cf4779770f" rev = "59710c816269c434b97ece3ab1701d3fef2269cb"
# [patch."https://github.com/Garmelon/toss.git"] # [patch."https://github.com/Garmelon/toss.git"]
# toss = { path = "../toss/" } # toss = { path = "../toss/" }

View file

@ -1,9 +1,9 @@
use std::mem; use std::mem;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use euphoxide::api::{MessageId, Snowflake, Time}; use euphoxide::api::{MessageId, Snowflake, Time};
use time::OffsetDateTime; use time::OffsetDateTime;
use toss::styled::Styled; use toss::{Style, Styled};
use crate::store::Msg; use crate::store::Msg;
use crate::ui::ChatMsg; use crate::ui::ChatMsg;
@ -35,7 +35,7 @@ enum Span {
struct Highlighter<'a> { struct Highlighter<'a> {
content: &'a str, content: &'a str,
base_style: ContentStyle, base_style: Style,
exact: bool, exact: bool,
span: Span, span: Span,
@ -177,7 +177,7 @@ impl<'a> Highlighter<'a> {
self.room_or_mention_possible = !char.is_alphanumeric(); self.room_or_mention_possible = !char.is_alphanumeric();
} }
fn highlight(content: &'a str, base_style: ContentStyle, exact: bool) -> Styled { fn highlight(content: &'a str, base_style: Style, exact: bool) -> Styled {
let mut this = Self { let mut this = Self {
content: if exact { content } else { content.trim() }, content: if exact { content } else { content.trim() },
base_style, base_style,
@ -198,7 +198,7 @@ impl<'a> Highlighter<'a> {
} }
} }
fn highlight_content(content: &str, base_style: ContentStyle, exact: bool) -> Styled { fn highlight_content(content: &str, base_style: Style, exact: bool) -> Styled {
Highlighter::highlight(content, base_style, exact) Highlighter::highlight(content, base_style, exact)
} }
@ -216,13 +216,13 @@ fn as_me(content: &str) -> Option<&str> {
content.strip_prefix("/me") content.strip_prefix("/me")
} }
fn style_me() -> ContentStyle { fn style_me() -> Style {
ContentStyle::default().grey().italic() Style::new().grey().italic()
} }
fn styled_nick(nick: &str) -> Styled { fn styled_nick(nick: &str) -> Styled {
Styled::new_plain("[") Styled::new_plain("[")
.and_then(util::style_nick(nick, ContentStyle::default())) .and_then(util::style_nick(nick, Style::new()))
.then_plain("]") .then_plain("]")
} }
@ -232,7 +232,7 @@ fn styled_nick_me(nick: &str) -> Styled {
} }
fn styled_content(content: &str) -> Styled { fn styled_content(content: &str) -> Styled {
highlight_content(content.trim(), ContentStyle::default(), false) highlight_content(content.trim(), Style::new(), false)
} }
fn styled_content_me(content: &str) -> Styled { fn styled_content_me(content: &str) -> Styled {
@ -244,7 +244,7 @@ fn styled_editor_content(content: &str) -> Styled {
let style = if as_me(content).is_some() { let style = if as_me(content).is_some() {
style_me() style_me()
} else { } else {
ContentStyle::default() Style::new()
}; };
highlight_content(content, style, true) highlight_content(content, style, true)
} }

View file

@ -1,7 +1,7 @@
use crossterm::style::{Color, ContentStyle, Stylize}; use crossterm::style::{Color, Stylize};
use euphoxide::Emoji; use euphoxide::Emoji;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use toss::styled::Styled; use toss::{Style, Styled};
pub static EMOJI: Lazy<Emoji> = Lazy::new(Emoji::load); pub static EMOJI: Lazy<Emoji> = Lazy::new(Emoji::load);
@ -42,15 +42,15 @@ pub fn nick_color(nick: &str) -> (u8, u8, u8) {
hsl_to_rgb(hue, 1.0, 0.72) hsl_to_rgb(hue, 1.0, 0.72)
} }
pub fn nick_style(nick: &str, base: ContentStyle) -> ContentStyle { pub fn nick_style(nick: &str, base: Style) -> Style {
let (r, g, b) = nick_color(nick); let (r, g, b) = nick_color(nick);
base.bold().with(Color::Rgb { r, g, b }) base.bold().with(Color::Rgb { r, g, b })
} }
pub fn style_nick(nick: &str, base: ContentStyle) -> Styled { pub fn style_nick(nick: &str, base: Style) -> Styled {
Styled::new(EMOJI.replace(nick), nick_style(nick, base)) Styled::new(EMOJI.replace(nick), nick_style(nick, base))
} }
pub fn style_nick_exact(nick: &str, base: ContentStyle) -> Styled { pub fn style_nick_exact(nick: &str, base: Style) -> Styled {
Styled::new(nick, nick_style(nick, base)) Styled::new(nick, nick_style(nick, base))
} }

View file

@ -3,12 +3,12 @@ use std::sync::Arc;
use std::vec; use std::vec;
use async_trait::async_trait; use async_trait::async_trait;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use log::{Level, LevelFilter, Log}; use log::{Level, LevelFilter, Log};
use parking_lot::Mutex; use parking_lot::Mutex;
use time::OffsetDateTime; use time::OffsetDateTime;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use toss::styled::Styled; use toss::{Style, Styled};
use crate::store::{Msg, MsgStore, Path, Tree}; use crate::store::{Msg, MsgStore, Path, Tree};
use crate::ui::ChatMsg; use crate::ui::ChatMsg;
@ -48,11 +48,11 @@ impl ChatMsg for LogMsg {
fn styled(&self) -> (Styled, Styled) { fn styled(&self) -> (Styled, Styled) {
let nick_style = match self.level { let nick_style = match self.level {
Level::Error => ContentStyle::default().bold().red(), Level::Error => Style::new().bold().red(),
Level::Warn => ContentStyle::default().bold().yellow(), Level::Warn => Style::new().bold().yellow(),
Level::Info => ContentStyle::default().bold().green(), Level::Info => Style::new().bold().green(),
Level::Debug => ContentStyle::default().bold().blue(), Level::Debug => Style::new().bold().blue(),
Level::Trace => ContentStyle::default().bold().magenta(), Level::Trace => Style::new().bold().magenta(),
}; };
let nick = Styled::new(format!("{}", self.level), nick_style); let nick = Styled::new(format!("{}", self.level), nick_style);
let content = Styled::new_plain(&self.content); let content = Styled::new_plain(&self.content);

View file

@ -31,7 +31,7 @@ use cookie::CookieJar;
use directories::{BaseDirs, ProjectDirs}; use directories::{BaseDirs, ProjectDirs};
use log::info; use log::info;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use toss::terminal::Terminal; use toss::Terminal;
use crate::config::Config; use crate::config::Config;
use crate::logger::Logger; use crate::logger::Logger;

View file

@ -14,7 +14,7 @@ use parking_lot::FairMutex;
use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::error::TryRecvError;
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::task; use tokio::task;
use toss::terminal::Terminal; use toss::Terminal;
use crate::config::Config; use crate::config::Config;
use crate::logger::{LogMsg, Logger}; use crate::logger::{LogMsg, Logger};
@ -144,14 +144,7 @@ impl Ui {
terminal.present()?; terminal.present()?;
loop { loop {
// 1. Measure grapheme widths if required // 1. Handle events (in batches)
if terminal.measuring_required() {
let _guard = crossterm_lock.lock();
terminal.measure_widths()?;
ok_or_return!(self.event_tx.send(UiEvent::GraphemeWidthsChanged), Ok(()));
}
// 2. Handle events (in batches)
let mut event = match event_rx.recv().await { let mut event = match event_rx.recv().await {
Some(event) => event, Some(event) => event,
None => return Ok(()), None => return Ok(()),
@ -174,12 +167,18 @@ impl Ui {
}; };
} }
// 3. Render and present final state
if redraw { if redraw {
// 2. Draw and present resulting state
terminal.autoresize()?; terminal.autoresize()?;
terminal.frame().reset();
self.widget().await.render(terminal.frame()).await; self.widget().await.render(terminal.frame()).await;
terminal.present()?; terminal.present()?;
// 3. Measure grapheme widths
if terminal.measuring_required() {
let _guard = crossterm_lock.lock();
terminal.measure_widths()?;
ok_or_return!(self.event_tx.send(UiEvent::GraphemeWidthsChanged), Ok(()));
}
} }
} }
} }

View file

@ -11,9 +11,7 @@ use std::{fmt, io};
use async_trait::async_trait; use async_trait::async_trait;
use parking_lot::FairMutex; use parking_lot::FairMutex;
use time::OffsetDateTime; use time::OffsetDateTime;
use toss::frame::{Frame, Size}; use toss::{Frame, Size, Styled, Terminal};
use toss::styled::Styled;
use toss::terminal::Terminal;
use crate::store::{Msg, MsgStore}; use crate::store::{Msg, MsgStore};

View file

@ -1,7 +1,7 @@
use std::collections::{vec_deque, VecDeque}; use std::collections::{vec_deque, VecDeque};
use std::ops::Range; use std::ops::Range;
use toss::frame::Frame; use toss::Frame;
use crate::macros::some_or_return; use crate::macros::some_or_return;
use crate::ui::widgets::BoxedWidget; use crate::ui::widgets::BoxedWidget;

View file

@ -12,8 +12,7 @@ use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use parking_lot::FairMutex; use parking_lot::FairMutex;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size, Terminal};
use toss::terminal::Terminal;
use crate::macros::logging_unwrap; use crate::macros::logging_unwrap;
use crate::store::{Msg, MsgStore}; use crate::store::{Msg, MsgStore};

View file

@ -1,4 +1,4 @@
use toss::frame::Frame; use toss::Frame;
use crate::store::{Msg, MsgStore, Path, Tree}; use crate::store::{Msg, MsgStore, Path, Tree};
use crate::ui::chat::blocks::Block; use crate::ui::chat::blocks::Block;

View file

@ -2,9 +2,8 @@ mod indent;
mod seen; mod seen;
mod time; mod time;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use toss::styled::Styled; use toss::{Style, Styled, WidthDb};
use toss::widthdb::WidthDb;
use super::super::ChatMsg; use super::super::ChatMsg;
use crate::store::Msg; use crate::store::Msg;
@ -19,36 +18,36 @@ use self::indent::Indent;
pub const PLACEHOLDER: &str = "[...]"; pub const PLACEHOLDER: &str = "[...]";
pub fn style_placeholder() -> ContentStyle { pub fn style_placeholder() -> Style {
ContentStyle::default().dark_grey() Style::new().dark_grey()
} }
fn style_time(highlighted: bool) -> ContentStyle { fn style_time(highlighted: bool) -> Style {
if highlighted { if highlighted {
ContentStyle::default().black().on_white() Style::new().black().on_white()
} else { } else {
ContentStyle::default().grey() Style::new().grey()
} }
} }
fn style_indent(highlighted: bool) -> ContentStyle { fn style_indent(highlighted: bool) -> Style {
if highlighted { if highlighted {
ContentStyle::default().black().on_white() Style::new().black().on_white()
} else { } else {
ContentStyle::default().dark_grey() Style::new().dark_grey()
} }
} }
fn style_info() -> ContentStyle { fn style_info() -> Style {
ContentStyle::default().italic().dark_grey() Style::new().italic().dark_grey()
} }
fn style_editor_highlight() -> ContentStyle { fn style_editor_highlight() -> Style {
ContentStyle::default().black().on_cyan() Style::new().black().on_cyan()
} }
fn style_pseudo_highlight() -> ContentStyle { fn style_pseudo_highlight() -> Style {
ContentStyle::default().black().on_yellow() Style::new().black().on_yellow()
} }
pub fn msg<M: Msg + ChatMsg>( pub fn msg<M: Msg + ChatMsg>(
@ -74,7 +73,9 @@ pub fn msg<M: Msg + ChatMsg>(
), ),
Segment::new(Indent::new(indent, style_indent(highlighted))), Segment::new(Indent::new(indent, style_indent(highlighted))),
Segment::new(Layer::new(vec![ Segment::new(Layer::new(vec![
Indent::new(1, style_indent(false)).into(), Padding::new(Indent::new(1, style_indent(false)))
.top(1)
.into(),
Padding::new(Text::new(nick)).right(1).into(), Padding::new(Text::new(nick)).right(1).into(),
])), ])),
// TODO Minimum content width // TODO Minimum content width
@ -129,7 +130,9 @@ pub fn editor<M: ChatMsg>(
), ),
Segment::new(Indent::new(indent, style_editor_highlight())), Segment::new(Indent::new(indent, style_editor_highlight())),
Segment::new(Layer::new(vec![ Segment::new(Layer::new(vec![
Indent::new(1, style_indent(false)).into(), Padding::new(Indent::new(1, style_indent(false)))
.top(1)
.into(),
Padding::new(Text::new(nick)).right(1).into(), Padding::new(Text::new(nick)).right(1).into(),
])), ])),
Segment::new(editor).priority(1).expanding(true), Segment::new(editor).priority(1).expanding(true),
@ -151,7 +154,9 @@ pub fn pseudo<M: ChatMsg>(indent: usize, nick: &str, editor: &EditorState) -> Bo
), ),
Segment::new(Indent::new(indent, style_pseudo_highlight())), Segment::new(Indent::new(indent, style_pseudo_highlight())),
Segment::new(Layer::new(vec![ Segment::new(Layer::new(vec![
Indent::new(1, style_indent(false)).into(), Padding::new(Indent::new(1, style_indent(false)))
.top(1)
.into(),
Padding::new(Text::new(nick)).right(1).into(), Padding::new(Text::new(nick)).right(1).into(),
])), ])),
Segment::new(Text::new(content).wrap(true)).priority(1), Segment::new(Text::new(content).wrap(true)).priority(1),

View file

@ -1,6 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use crossterm::style::ContentStyle; use toss::{Frame, Pos, Size, Style};
use toss::frame::{Frame, Pos, Size};
use crate::ui::widgets::Widget; use crate::ui::widgets::Widget;
@ -9,11 +8,11 @@ pub const INDENT_WIDTH: usize = 2;
pub struct Indent { pub struct Indent {
level: usize, level: usize,
style: ContentStyle, style: Style,
} }
impl Indent { impl Indent {
pub fn new(level: usize, style: ContentStyle) -> Self { pub fn new(level: usize, style: Style) -> Self {
Self { level, style } Self { level, style }
} }
} }

View file

@ -1,4 +1,5 @@
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use toss::Style;
use crate::ui::widgets::background::Background; use crate::ui::widgets::background::Background;
use crate::ui::widgets::empty::Empty; use crate::ui::widgets::empty::Empty;
@ -8,8 +9,8 @@ use crate::ui::widgets::BoxedWidget;
const UNSEEN: &str = "*"; const UNSEEN: &str = "*";
const WIDTH: u16 = 1; const WIDTH: u16 = 1;
fn seen_style() -> ContentStyle { fn seen_style() -> Style {
ContentStyle::default().black().on_green() Style::new().black().on_green()
} }
pub fn widget(seen: bool) -> BoxedWidget { pub fn widget(seen: bool) -> BoxedWidget {

View file

@ -1,7 +1,7 @@
use crossterm::style::ContentStyle;
use time::format_description::FormatItem; use time::format_description::FormatItem;
use time::macros::format_description; use time::macros::format_description;
use time::OffsetDateTime; use time::OffsetDateTime;
use toss::Style;
use crate::ui::widgets::background::Background; use crate::ui::widgets::background::Background;
use crate::ui::widgets::empty::Empty; use crate::ui::widgets::empty::Empty;
@ -11,7 +11,7 @@ use crate::ui::widgets::BoxedWidget;
const TIME_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day] [hour]:[minute]"); const TIME_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day] [hour]:[minute]");
const TIME_WIDTH: u16 = 16; const TIME_WIDTH: u16 = 16;
pub fn widget(time: Option<OffsetDateTime>, style: ContentStyle) -> BoxedWidget { pub fn widget(time: Option<OffsetDateTime>, style: Style) -> BoxedWidget {
if let Some(time) = time { if let Some(time) = time {
let text = time.format(TIME_FORMAT).expect("could not format time"); let text = time.format(TIME_FORMAT).expect("could not format time");
Background::new(Text::new((text, style))) Background::new(Text::new((text, style)))

View file

@ -1,7 +1,7 @@
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use euphoxide::api::PersonalAccountView; use euphoxide::api::PersonalAccountView;
use euphoxide::conn; use euphoxide::conn;
use toss::terminal::Terminal; use toss::{Style, Terminal};
use crate::euph::{self, Room}; use crate::euph::{self, Room};
use crate::ui::input::{key, InputEvent, KeyBindingsList}; use crate::ui::input::{key, InputEvent, KeyBindingsList};
@ -36,7 +36,7 @@ impl LoggedOut {
} }
fn widget(&self) -> BoxedWidget { fn widget(&self) -> BoxedWidget {
let bold = ContentStyle::default().bold(); let bold = Style::new().bold();
VJoin::new(vec![ VJoin::new(vec![
Segment::new(Text::new(("Not logged in", bold.yellow()))), Segment::new(Text::new(("Not logged in", bold.yellow()))),
Segment::new(Empty::new().height(1)), Segment::new(Empty::new().height(1)),
@ -64,7 +64,7 @@ pub struct LoggedIn(PersonalAccountView);
impl LoggedIn { impl LoggedIn {
fn widget(&self) -> BoxedWidget { fn widget(&self) -> BoxedWidget {
let bold = ContentStyle::default().bold(); let bold = Style::new().bold();
VJoin::new(vec![ VJoin::new(vec![
Segment::new(Text::new(("Logged in", bold.green()))), Segment::new(Text::new(("Logged in", bold.green()))),
Segment::new(Empty::new().height(1)), Segment::new(Empty::new().height(1)),

View file

@ -1,4 +1,4 @@
use toss::terminal::Terminal; use toss::Terminal;
use crate::euph::Room; use crate::euph::Room;
use crate::ui::input::{key, InputEvent, KeyBindingsList}; use crate::ui::input::{key, InputEvent, KeyBindingsList};

View file

@ -1,7 +1,7 @@
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use euphoxide::api::{Message, NickEvent, SessionView}; use euphoxide::api::{Message, NickEvent, SessionView};
use euphoxide::conn::SessionInfo; use euphoxide::conn::SessionInfo;
use toss::styled::Styled; use toss::{Style, Styled};
use crate::ui::input::{key, InputEvent, KeyBindingsList}; use crate::ui::input::{key, InputEvent, KeyBindingsList};
use crate::ui::widgets::popup::Popup; use crate::ui::widgets::popup::Popup;
@ -11,31 +11,33 @@ use crate::ui::widgets::BoxedWidget;
macro_rules! line { macro_rules! line {
( $text:ident, $name:expr, $val:expr ) => { ( $text:ident, $name:expr, $val:expr ) => {
$text = $text $text = $text
.then($name, ContentStyle::default().cyan()) .then($name, Style::new().cyan())
.then_plain(format!(" {}\n", $val)); .then_plain(format!(" {}\n", $val));
}; };
( $text:ident, $name:expr, $val:expr, debug ) => { ( $text:ident, $name:expr, $val:expr, debug ) => {
$text = $text $text = $text
.then($name, ContentStyle::default().cyan()) .then($name, Style::new().cyan())
.then_plain(format!(" {:?}\n", $val)); .then_plain(format!(" {:?}\n", $val));
}; };
( $text:ident, $name:expr, $val:expr, optional ) => { ( $text:ident, $name:expr, $val:expr, optional ) => {
if let Some(val) = $val { if let Some(val) = $val {
$text = $text $text = $text
.then($name, ContentStyle::default().cyan()) .then($name, Style::new().cyan())
.then_plain(format!(" {val}\n")); .then_plain(format!(" {val}\n"));
} else { } else {
$text = $text $text = $text
.then($name, ContentStyle::default().cyan()) .then($name, Style::new().cyan())
.then_plain(" ") .then_plain(" ")
.then("none", ContentStyle::default().italic().grey()) .then("none", Style::new().italic().grey())
.then_plain("\n"); .then_plain("\n");
} }
}; };
( $text:ident, $name:expr, $val:expr, yes or no ) => { ( $text:ident, $name:expr, $val:expr, yes or no ) => {
$text = $text $text = $text.then($name, Style::new().cyan()).then_plain(if $val {
.then($name, ContentStyle::default().cyan()) " yes\n"
.then_plain(if $val { " yes\n" } else { " no\n" }); } else {
" no\n"
});
}; };
} }
@ -87,7 +89,7 @@ fn message_lines(mut text: Styled, msg: &Message) -> Styled {
} }
pub fn session_widget(session: &SessionInfo) -> BoxedWidget { pub fn session_widget(session: &SessionInfo) -> BoxedWidget {
let heading_style = ContentStyle::default().bold(); let heading_style = Style::new().bold();
let text = match session { let text = match session {
SessionInfo::Full(session) => { SessionInfo::Full(session) => {
@ -104,7 +106,7 @@ pub fn session_widget(session: &SessionInfo) -> BoxedWidget {
} }
pub fn message_widget(msg: &Message) -> BoxedWidget { pub fn message_widget(msg: &Message) -> BoxedWidget {
let heading_style = ContentStyle::default().bold(); let heading_style = Style::new().bold();
let mut text = Styled::new("Message", heading_style).then_plain("\n"); let mut text = Styled::new("Message", heading_style).then_plain("\n");

View file

@ -1,8 +1,8 @@
use std::io; use std::io;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use linkify::{LinkFinder, LinkKind}; use linkify::{LinkFinder, LinkKind};
use toss::styled::Styled; use toss::{Style, Styled};
use crate::ui::input::{key, InputEvent, KeyBindingsList}; use crate::ui::input::{key, InputEvent, KeyBindingsList};
use crate::ui::widgets::list::ListState; use crate::ui::widgets::list::ListState;
@ -40,22 +40,16 @@ impl LinksState {
} }
pub fn widget(&self) -> BoxedWidget { pub fn widget(&self) -> BoxedWidget {
let style_selected = ContentStyle::default().black().on_white(); let style_selected = Style::new().black().on_white();
let mut list = self.list.widget().focus(true); let mut list = self.list.widget().focus(true);
if self.links.is_empty() { if self.links.is_empty() {
list.add_unsel(Text::new(( list.add_unsel(Text::new(("No links found", Style::new().grey().italic())))
"No links found",
ContentStyle::default().grey().italic(),
)))
} }
for (id, link) in self.links.iter().enumerate() { for (id, link) in self.links.iter().enumerate() {
let (line_normal, line_selected) = if let Some(number_key) = NUMBER_KEYS.get(id) { let (line_normal, line_selected) = if let Some(number_key) = NUMBER_KEYS.get(id) {
( (
Styled::new( Styled::new(format!("[{number_key}]"), Style::new().dark_grey().bold())
format!("[{number_key}]"),
ContentStyle::default().dark_grey().bold(),
)
.then_plain(" ") .then_plain(" ")
.then_plain(link), .then_plain(link),
Styled::new(format!("[{number_key}]"), style_selected.bold()) Styled::new(format!("[{number_key}]"), style_selected.bold())

View file

@ -1,6 +1,5 @@
use crossterm::style::ContentStyle;
use euphoxide::conn::Joined; use euphoxide::conn::Joined;
use toss::terminal::Terminal; use toss::{Style, Terminal};
use crate::euph::{self, Room}; use crate::euph::{self, Room};
use crate::ui::input::{key, InputEvent, KeyBindingsList}; use crate::ui::input::{key, InputEvent, KeyBindingsList};
@ -17,7 +16,7 @@ pub fn new(joined: Joined) -> EditorState {
pub fn widget(editor: &EditorState) -> BoxedWidget { pub fn widget(editor: &EditorState) -> BoxedWidget {
let editor = editor let editor = editor
.widget() .widget()
.highlight(|s| euph::style_nick_exact(s, ContentStyle::default())); .highlight(|s| euph::style_nick_exact(s, Style::new()));
Popup::new(Padding::new(editor).left(1)) Popup::new(Padding::new(editor).left(1))
.title("Choose nick") .title("Choose nick")
.inner_padding(false) .inner_padding(false)

View file

@ -1,10 +1,10 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::iter; use std::iter;
use crossterm::style::{Color, ContentStyle, Stylize}; use crossterm::style::{Color, Stylize};
use euphoxide::api::{NickEvent, SessionId, SessionType, SessionView, UserId}; use euphoxide::api::{NickEvent, SessionId, SessionType, SessionView, UserId};
use euphoxide::conn::{Joined, SessionInfo}; use euphoxide::conn::{Joined, SessionInfo};
use toss::styled::Styled; use toss::{Style, Styled};
use crate::euph; use crate::euph;
use crate::ui::widgets::background::Background; use crate::ui::widgets::background::Background;
@ -98,7 +98,7 @@ fn render_section(
return; return;
} }
let heading_style = ContentStyle::new().bold(); let heading_style = Style::new().bold();
if !list.is_empty() { if !list.is_empty() {
list.add_unsel(Empty::new()); list.add_unsel(Empty::new());
@ -117,16 +117,16 @@ fn render_section(
fn render_row(list: &mut List<SessionId>, session: &HalfSession, own_session: &SessionView) { fn render_row(list: &mut List<SessionId>, session: &HalfSession, own_session: &SessionView) {
let (name, style, style_inv, perms_style_inv) = if session.name.is_empty() { let (name, style, style_inv, perms_style_inv) = if session.name.is_empty() {
let name = "lurk"; let name = "lurk";
let style = ContentStyle::default().grey(); let style = Style::new().grey();
let style_inv = ContentStyle::default().black().on_grey(); let style_inv = Style::new().black().on_grey();
(Cow::Borrowed(name), style, style_inv, style_inv) (Cow::Borrowed(name), style, style_inv, style_inv)
} else { } else {
let name = &session.name as &str; let name = &session.name as &str;
let (r, g, b) = euph::nick_color(name); let (r, g, b) = euph::nick_color(name);
let color = Color::Rgb { r, g, b }; let color = Color::Rgb { r, g, b };
let style = ContentStyle::default().bold().with(color); let style = Style::new().bold().with(color);
let style_inv = ContentStyle::default().bold().black().on(color); let style_inv = Style::new().bold().black().on(color);
let perms_style_inv = ContentStyle::default().black().on(color); let perms_style_inv = Style::new().black().on(color);
(euph::EMOJI.replace(name), style, style_inv, perms_style_inv) (euph::EMOJI.replace(name), style, style_inv, perms_style_inv)
}; };

View file

@ -1,5 +1,5 @@
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use toss::styled::Styled; use toss::{Style, Styled};
use crate::ui::widgets::float::Float; use crate::ui::widgets::float::Float;
use crate::ui::widgets::popup::Popup; use crate::ui::widgets::popup::Popup;
@ -12,10 +12,10 @@ pub enum RoomPopup {
impl RoomPopup { impl RoomPopup {
fn server_error_widget(description: &str, reason: &str) -> BoxedWidget { fn server_error_widget(description: &str, reason: &str) -> BoxedWidget {
let border_style = ContentStyle::default().red().bold(); let border_style = Style::new().red().bold();
let text = Styled::new_plain(description) let text = Styled::new_plain(description)
.then_plain("\n\n") .then_plain("\n\n")
.then("Reason:", ContentStyle::default().bold()) .then("Reason:", Style::new().bold())
.then_plain(" ") .then_plain(" ")
.then_plain(reason); .then_plain(reason);
Popup::new(Text::new(text)) Popup::new(Text::new(text))

View file

@ -1,15 +1,14 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::Arc; use std::sync::Arc;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use euphoxide::api::{Data, Message, MessageId, PacketType, SessionId}; use euphoxide::api::{Data, Message, MessageId, PacketType, SessionId};
use euphoxide::bot::instance::{Event, ServerConfig}; use euphoxide::bot::instance::{Event, ServerConfig};
use euphoxide::conn::{self, Joined, Joining, SessionInfo}; use euphoxide::conn::{self, Joined, Joining, SessionInfo};
use parking_lot::FairMutex; use parking_lot::FairMutex;
use tokio::sync::oneshot::error::TryRecvError; use tokio::sync::oneshot::error::TryRecvError;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use toss::styled::Styled; use toss::{Style, Styled, Terminal};
use toss::terminal::Terminal;
use crate::config; use crate::config;
use crate::euph; use crate::euph;
@ -277,7 +276,7 @@ impl EuphRoom {
} }
async fn status_widget(&self, state: Option<&euph::State>) -> BoxedWidget { async fn status_widget(&self, state: Option<&euph::State>) -> BoxedWidget {
let room_style = ContentStyle::default().bold().blue(); let room_style = Style::new().bold().blue();
let mut info = Styled::new(format!("&{}", self.name()), room_style); let mut info = Styled::new(format!("&{}", self.name()), room_style);
info = match state { info = match state {
@ -296,7 +295,7 @@ impl EuphRoom {
info.then_plain(", present without nick") info.then_plain(", present without nick")
} else { } else {
info.then_plain(", present as ") info.then_plain(", present as ")
.and_then(euph::style_nick(nick, ContentStyle::default())) .and_then(euph::style_nick(nick, Style::new()))
} }
} }
}; };
@ -305,7 +304,7 @@ impl EuphRoom {
if unseen > 0 { if unseen > 0 {
info = info info = info
.then_plain(" (") .then_plain(" (")
.then(format!("{unseen}"), ContentStyle::default().bold().green()) .then(format!("{unseen}"), Style::new().bold().green())
.then_plain(")"); .then_plain(")");
} }

View file

@ -1,8 +1,8 @@
use std::convert::Infallible; use std::convert::Infallible;
use crossterm::event::{Event, KeyCode, KeyModifiers}; use crossterm::event::{Event, KeyCode, KeyModifiers};
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use toss::styled::Styled; use toss::{Style, Styled};
use super::widgets::background::Background; use super::widgets::background::Background;
use super::widgets::border::Border; use super::widgets::border::Border;
@ -94,8 +94,8 @@ impl KeyBindingsList {
Self(state.widget()) Self(state.widget())
} }
fn binding_style() -> ContentStyle { fn binding_style() -> Style {
ContentStyle::default().cyan() Style::new().cyan()
} }
pub fn widget(self) -> BoxedWidget { pub fn widget(self) -> BoxedWidget {
@ -124,8 +124,7 @@ impl KeyBindingsList {
} }
pub fn heading(&mut self, name: &str) { pub fn heading(&mut self, name: &str) {
self.0 self.0.add_unsel(Text::new((name, Style::new().bold())));
.add_unsel(Text::new((name, ContentStyle::default().bold())));
} }
pub fn binding(&mut self, binding: &str, description: &str) { pub fn binding(&mut self, binding: &str, description: &str) {

View file

@ -2,14 +2,13 @@ use std::collections::{HashMap, HashSet};
use std::iter; use std::iter;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use euphoxide::api::SessionType; use euphoxide::api::SessionType;
use euphoxide::bot::instance::{Event, ServerConfig}; use euphoxide::bot::instance::{Event, ServerConfig};
use euphoxide::conn::{self, Joined}; use euphoxide::conn::{self, Joined};
use parking_lot::FairMutex; use parking_lot::FairMutex;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use toss::styled::Styled; use toss::{Style, Styled, Terminal};
use toss::terminal::Terminal;
use crate::config::{Config, RoomsSortOrder}; use crate::config::{Config, RoomsSortOrder};
use crate::euph; use crate::euph;
@ -199,7 +198,7 @@ impl Rooms {
} }
fn new_room_widget(editor: &EditorState) -> BoxedWidget { fn new_room_widget(editor: &EditorState) -> BoxedWidget {
let room_style = ContentStyle::default().bold().blue(); let room_style = Style::new().bold().blue();
let editor = editor.widget().highlight(|s| Styled::new(s, room_style)); let editor = editor.widget().highlight(|s| Styled::new(s, room_style));
Popup::new(HJoin::new(vec![ Popup::new(HJoin::new(vec![
Segment::new(Text::new(("&", room_style))), Segment::new(Text::new(("&", room_style))),
@ -210,8 +209,8 @@ impl Rooms {
} }
fn delete_room_widget(name: &str, editor: &EditorState) -> BoxedWidget { fn delete_room_widget(name: &str, editor: &EditorState) -> BoxedWidget {
let warn_style = ContentStyle::default().bold().red(); let warn_style = Style::new().bold().red();
let room_style = ContentStyle::default().bold().blue(); let room_style = Style::new().bold().blue();
let editor = editor.widget().highlight(|s| Styled::new(s, room_style)); let editor = editor.widget().highlight(|s| Styled::new(s, room_style));
let text = Styled::new_plain("Are you sure you want to delete ") let text = Styled::new_plain("Are you sure you want to delete ")
.then("&", room_style) .then("&", room_style)
@ -219,7 +218,7 @@ impl Rooms {
.then_plain("?\n\n") .then_plain("?\n\n")
.then_plain("This will delete the entire room history from your vault. ") .then_plain("This will delete the entire room history from your vault. ")
.then_plain("To shrink your vault afterwards, run ") .then_plain("To shrink your vault afterwards, run ")
.then("cove gc", ContentStyle::default().italic().grey()) .then("cove gc", Style::new().italic().grey())
.then_plain(".\n\n") .then_plain(".\n\n")
.then_plain("To confirm the deletion, ") .then_plain("To confirm the deletion, ")
.then_plain("enter the full name of the room and press enter:"); .then_plain("enter the full name of the room and press enter:");
@ -304,7 +303,7 @@ impl Rooms {
} }
fn format_room_info(state: Option<&euph::State>, unseen: usize) -> Styled { fn format_room_info(state: Option<&euph::State>, unseen: usize) -> Styled {
let unseen_style = ContentStyle::default().bold().green(); let unseen_style = Style::new().bold().green();
let state = Self::format_room_state(state); let state = Self::format_room_state(state);
let unseen = Self::format_unseen_msgs(unseen); let unseen = Self::format_unseen_msgs(unseen);
@ -336,7 +335,7 @@ impl Rooms {
if self.euph_rooms.is_empty() { if self.euph_rooms.is_empty() {
list.add_unsel(Text::new(( list.add_unsel(Text::new((
"Press F1 for key bindings", "Press F1 for key bindings",
ContentStyle::default().grey().italic(), Style::new().grey().italic(),
))) )))
} }
@ -348,8 +347,8 @@ impl Rooms {
} }
self.sort_rooms(&mut rooms); self.sort_rooms(&mut rooms);
for (name, state, unseen) in rooms { for (name, state, unseen) in rooms {
let room_style = ContentStyle::default().bold().blue(); let room_style = Style::new().bold().blue();
let room_sel_style = ContentStyle::default().bold().black().on_white(); let room_sel_style = Style::new().bold().black().on_white();
let mut normal = Styled::new(format!("&{name}"), room_style); let mut normal = Styled::new(format!("&{name}"), room_style);
let mut selected = Styled::new(format!("&{name}"), room_sel_style); let mut selected = Styled::new(format!("&{name}"), room_sel_style);
@ -363,7 +362,7 @@ impl Rooms {
} }
async fn rooms_widget(&self) -> BoxedWidget { async fn rooms_widget(&self) -> BoxedWidget {
let heading_style = ContentStyle::default().bold(); let heading_style = Style::new().bold();
let amount = self.euph_rooms.len(); let amount = self.euph_rooms.len();
let heading = let heading =
Text::new(Styled::new("Rooms", heading_style).then_plain(format!(" ({amount})"))); Text::new(Styled::new("Rooms", heading_style).then_plain(format!(" ({amount})")));

View file

@ -2,7 +2,7 @@ use std::io;
use std::sync::Arc; use std::sync::Arc;
use parking_lot::FairMutex; use parking_lot::FairMutex;
use toss::terminal::Terminal; use toss::Terminal;
use super::input::{key, InputEvent, KeyBindingsList}; use super::input::{key, InputEvent, KeyBindingsList};
use super::widgets::editor::EditorState; use super::widgets::editor::EditorState;

View file

@ -19,7 +19,7 @@ pub mod rules;
pub mod text; pub mod text;
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Size}; use toss::{Frame, Size};
// TODO Add Error type and return Result-s (at least in Widget::render) // TODO Add Error type and return Result-s (at least in Widget::render)

View file

@ -1,23 +1,22 @@
use async_trait::async_trait; use async_trait::async_trait;
use crossterm::style::ContentStyle; use toss::{Frame, Pos, Size, Style};
use toss::frame::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};
pub struct Background { pub struct Background {
inner: BoxedWidget, inner: BoxedWidget,
style: ContentStyle, style: Style,
} }
impl Background { impl Background {
pub fn new<W: Into<BoxedWidget>>(inner: W) -> Self { pub fn new<W: Into<BoxedWidget>>(inner: W) -> Self {
Self { Self {
inner: inner.into(), inner: inner.into(),
style: ContentStyle::default(), style: Style::new().opaque(),
} }
} }
pub fn style(mut self, style: ContentStyle) -> Self { pub fn style(mut self, style: Style) -> Self {
self.style = style; self.style = style;
self self
} }

View file

@ -1,23 +1,22 @@
use async_trait::async_trait; use async_trait::async_trait;
use crossterm::style::ContentStyle; use toss::{Frame, Pos, Size, Style};
use toss::frame::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};
pub struct Border { pub struct Border {
inner: BoxedWidget, inner: BoxedWidget,
style: ContentStyle, style: Style,
} }
impl Border { impl Border {
pub fn new<W: Into<BoxedWidget>>(inner: W) -> Self { pub fn new<W: Into<BoxedWidget>>(inner: W) -> Self {
Self { Self {
inner: inner.into(), inner: inner.into(),
style: ContentStyle::default(), style: Style::new(),
} }
} }
pub fn style(mut self, style: ContentStyle) -> Self { pub fn style(mut self, style: Style) -> Self {
self.style = style; self.style = style;
self self
} }

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -2,12 +2,9 @@ use std::sync::Arc;
use std::{io, iter}; use std::{io, iter};
use async_trait::async_trait; use async_trait::async_trait;
use crossterm::style::{ContentStyle, Stylize}; use crossterm::style::Stylize;
use parking_lot::{FairMutex, Mutex}; use parking_lot::{FairMutex, Mutex};
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size, Style, Styled, Terminal, WidthDb};
use toss::styled::Styled;
use toss::terminal::Terminal;
use toss::widthdb::WidthDb;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use crate::ui::util; use crate::ui::util;
@ -461,7 +458,7 @@ impl Editor {
} }
pub fn hidden(self) -> Self { pub fn hidden(self) -> Self {
self.hidden_with_placeholder(("<hidden>", ContentStyle::default().grey().italic())) self.hidden_with_placeholder(("<hidden>", Style::new().grey().italic()))
} }
pub fn hidden_with_placeholder<S: Into<Styled>>(mut self, placeholder: S) -> Self { pub fn hidden_with_placeholder<S: Into<Styled>>(mut self, placeholder: S) -> Self {

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Size}; use toss::{Frame, Size};
use super::Widget; use super::Widget;

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Size}; use toss::{Frame, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use parking_lot::Mutex; use parking_lot::Mutex;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -1,5 +1,4 @@
use crossterm::style::ContentStyle; use toss::{Style, Styled};
use toss::styled::Styled;
use super::background::Background; use super::background::Background;
use super::border::Border; use super::border::Border;
@ -13,8 +12,8 @@ pub struct Popup {
inner: BoxedWidget, inner: BoxedWidget,
inner_padding: bool, inner_padding: bool,
title: Option<Styled>, title: Option<Styled>,
border_style: ContentStyle, border_style: Style,
bg_style: ContentStyle, bg_style: Style,
} }
impl Popup { impl Popup {
@ -23,8 +22,8 @@ impl Popup {
inner: inner.into(), inner: inner.into(),
inner_padding: true, inner_padding: true,
title: None, title: None,
border_style: ContentStyle::default(), border_style: Style::new(),
bg_style: ContentStyle::default(), bg_style: Style::new().opaque(),
} }
} }
@ -38,12 +37,12 @@ impl Popup {
self self
} }
pub fn border(mut self, style: ContentStyle) -> Self { pub fn border(mut self, style: Style) -> Self {
self.border_style = style; self.border_style = style;
self self
} }
pub fn background(mut self, style: ContentStyle) -> Self { pub fn background(mut self, style: Style) -> Self {
self.bg_style = style; self.bg_style = style;
self self
} }

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Size}; use toss::{Frame, Size};
use super::{BoxedWidget, Widget}; use super::{BoxedWidget, Widget};

View file

@ -1,5 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size};
use super::Widget; use super::Widget;

View file

@ -1,7 +1,5 @@
use async_trait::async_trait; use async_trait::async_trait;
use toss::frame::{Frame, Pos, Size}; use toss::{Frame, Pos, Size, Styled, WidthDb};
use toss::styled::Styled;
use toss::widthdb::WidthDb;
use super::Widget; use super::Widget;