Make new ChatMsg trait for Chat message rendering
This commit is contained in:
parent
5c9c6e9d98
commit
4ac0b5f074
13 changed files with 122 additions and 69 deletions
|
|
@ -1,8 +1,10 @@
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod conn;
|
mod conn;
|
||||||
|
mod message;
|
||||||
mod room;
|
mod room;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use conn::{Joined, Joining, Status};
|
pub use conn::{Joined, Joining, Status};
|
||||||
|
pub use message::Message;
|
||||||
pub use room::Room;
|
pub use room::Room;
|
||||||
pub use util::{hue, nick_color, nick_style};
|
pub use util::{hue, nick_color, nick_style};
|
||||||
|
|
|
||||||
62
src/euph/message.rs
Normal file
62
src/euph/message.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use crossterm::style::{ContentStyle, Stylize};
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
use toss::styled::Styled;
|
||||||
|
|
||||||
|
use crate::store::Msg;
|
||||||
|
use crate::ui::ChatMsg;
|
||||||
|
|
||||||
|
use super::api::{Snowflake, Time};
|
||||||
|
use super::util;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Message {
|
||||||
|
pub id: Snowflake,
|
||||||
|
pub parent: Option<Snowflake>,
|
||||||
|
pub time: Time,
|
||||||
|
pub nick: String,
|
||||||
|
pub content: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn styled_nick(nick: &str) -> Styled {
|
||||||
|
Styled::new_plain("[")
|
||||||
|
.then(nick, util::nick_style(nick))
|
||||||
|
.then_plain("]")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn styled_content(content: &str) -> Styled {
|
||||||
|
Styled::new_plain(content.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Msg for Message {
|
||||||
|
type Id = Snowflake;
|
||||||
|
|
||||||
|
fn id(&self) -> Self::Id {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<Self::Id> {
|
||||||
|
self.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_possible_id() -> Self::Id {
|
||||||
|
Snowflake::MAX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChatMsg for Message {
|
||||||
|
fn time(&self) -> OffsetDateTime {
|
||||||
|
self.time.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn styled(&self) -> (Styled, Styled) {
|
||||||
|
Self::pseudo(&self.nick, &self.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit(nick: &str, content: &str) -> (Styled, Styled) {
|
||||||
|
(styled_nick(nick), styled_content(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pseudo(nick: &str, content: &str) -> (Styled, Styled) {
|
||||||
|
(styled_nick(nick), styled_content(content))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,10 @@ use time::format_description::FormatItem;
|
||||||
use time::macros::format_description;
|
use time::macros::format_description;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
use crate::euph;
|
||||||
use crate::euph::api::Snowflake;
|
use crate::euph::api::Snowflake;
|
||||||
use crate::store::{MsgStore, Tree};
|
use crate::store::{MsgStore, Tree};
|
||||||
use crate::vault::{EuphMsg, Vault};
|
use crate::vault::Vault;
|
||||||
|
|
||||||
const TIME_FORMAT: &[FormatItem<'_>] =
|
const TIME_FORMAT: &[FormatItem<'_>] =
|
||||||
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
|
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
|
||||||
|
|
@ -43,7 +44,7 @@ pub async fn export(vault: &Vault, room: String, file: &Path) -> anyhow::Result<
|
||||||
|
|
||||||
fn write_tree(
|
fn write_tree(
|
||||||
file: &mut BufWriter<File>,
|
file: &mut BufWriter<File>,
|
||||||
tree: &Tree<EuphMsg>,
|
tree: &Tree<euph::Message>,
|
||||||
id: Snowflake,
|
id: Snowflake,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
|
@ -64,7 +65,11 @@ fn write_tree(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_msg(file: &mut BufWriter<File>, indent_string: &str, msg: &EuphMsg) -> anyhow::Result<()> {
|
fn write_msg(
|
||||||
|
file: &mut BufWriter<File>,
|
||||||
|
indent_string: &str,
|
||||||
|
msg: &euph::Message,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let nick = &msg.nick;
|
let nick = &msg.nick;
|
||||||
let nick_empty = " ".repeat(nick.width());
|
let nick_empty = " ".repeat(nick.width());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use tokio::sync::mpsc;
|
||||||
use toss::styled::Styled;
|
use toss::styled::Styled;
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore, Path, Tree};
|
use crate::store::{Msg, MsgStore, Path, Tree};
|
||||||
|
use crate::ui::ChatMsg;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LogMsg {
|
pub struct LogMsg {
|
||||||
|
|
@ -30,28 +31,35 @@ impl Msg for LogMsg {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn last_possible_id() -> Self::Id {
|
||||||
|
Self::Id::MAX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChatMsg for LogMsg {
|
||||||
fn time(&self) -> OffsetDateTime {
|
fn time(&self) -> OffsetDateTime {
|
||||||
self.time
|
self.time
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nick(&self) -> Styled {
|
fn styled(&self) -> (Styled, Styled) {
|
||||||
let style = match self.level {
|
let nick_style = match self.level {
|
||||||
Level::Error => ContentStyle::default().bold().red(),
|
Level::Error => ContentStyle::default().bold().red(),
|
||||||
Level::Warn => ContentStyle::default().bold().yellow(),
|
Level::Warn => ContentStyle::default().bold().yellow(),
|
||||||
Level::Info => ContentStyle::default().bold().green(),
|
Level::Info => ContentStyle::default().bold().green(),
|
||||||
Level::Debug => ContentStyle::default().bold().blue(),
|
Level::Debug => ContentStyle::default().bold().blue(),
|
||||||
Level::Trace => ContentStyle::default().bold().magenta(),
|
Level::Trace => ContentStyle::default().bold().magenta(),
|
||||||
};
|
};
|
||||||
let text = format!("{}", self.level);
|
let nick = Styled::new(format!("{}", self.level), nick_style);
|
||||||
Styled::new(text, style)
|
let content = Styled::new_plain(&self.content);
|
||||||
|
(nick, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(&self) -> Styled {
|
fn edit(nick: &str, content: &str) -> (Styled, Styled) {
|
||||||
Styled::new_plain(&self.content)
|
panic!("log is not editable")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_possible_id() -> Self::Id {
|
fn pseudo(nick: &str, content: &str) -> (Styled, Styled) {
|
||||||
Self::Id::MAX
|
panic!("log is not editable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,12 @@ use std::hash::Hash;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use time::OffsetDateTime;
|
|
||||||
use toss::styled::Styled;
|
|
||||||
|
|
||||||
pub trait Msg {
|
pub trait Msg {
|
||||||
type Id: Clone + Debug + Hash + Eq + Ord;
|
type Id: Clone + Debug + Hash + Eq + Ord;
|
||||||
fn id(&self) -> Self::Id;
|
fn id(&self) -> Self::Id;
|
||||||
fn parent(&self) -> Option<Self::Id>;
|
fn parent(&self) -> Option<Self::Id>;
|
||||||
|
|
||||||
fn time(&self) -> OffsetDateTime;
|
|
||||||
fn nick(&self) -> Styled;
|
|
||||||
fn content(&self) -> Styled;
|
|
||||||
|
|
||||||
fn last_possible_id() -> Self::Id;
|
fn last_possible_id() -> Self::Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use toss::terminal::Terminal;
|
||||||
use crate::logger::{LogMsg, Logger};
|
use crate::logger::{LogMsg, Logger};
|
||||||
use crate::vault::Vault;
|
use crate::vault::Vault;
|
||||||
|
|
||||||
|
pub use self::chat::ChatMsg;
|
||||||
use self::chat::ChatState;
|
use self::chat::ChatState;
|
||||||
use self::rooms::Rooms;
|
use self::rooms::Rooms;
|
||||||
use self::widgets::BoxedWidget;
|
use self::widgets::BoxedWidget;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ use std::sync::Arc;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
|
use time::OffsetDateTime;
|
||||||
use toss::frame::{Frame, Size};
|
use toss::frame::{Frame, Size};
|
||||||
|
use toss::styled::Styled;
|
||||||
use toss::terminal::Terminal;
|
use toss::terminal::Terminal;
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
|
|
@ -15,6 +17,17 @@ use self::tree::{TreeView, TreeViewState};
|
||||||
|
|
||||||
use super::widgets::Widget;
|
use super::widgets::Widget;
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Trait //
|
||||||
|
///////////
|
||||||
|
|
||||||
|
pub trait ChatMsg {
|
||||||
|
fn time(&self) -> OffsetDateTime;
|
||||||
|
fn styled(&self) -> (Styled, Styled);
|
||||||
|
fn edit(nick: &str, content: &str) -> (Styled, Styled);
|
||||||
|
fn pseudo(nick: &str, content: &str) -> (Styled, Styled);
|
||||||
|
}
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// State //
|
// State //
|
||||||
///////////
|
///////////
|
||||||
|
|
@ -87,7 +100,7 @@ pub enum Chat<M: Msg, S: MsgStore<M>> {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<M, S> Widget for Chat<M, S>
|
impl<M, S> Widget for Chat<M, S>
|
||||||
where
|
where
|
||||||
M: Msg,
|
M: Msg + ChatMsg,
|
||||||
M::Id: Send + Sync,
|
M::Id: Send + Sync,
|
||||||
S: MsgStore<M> + Send + Sync,
|
S: MsgStore<M> + Send + Sync,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ use crate::ui::widgets::Widget;
|
||||||
|
|
||||||
use self::cursor::Cursor;
|
use self::cursor::Cursor;
|
||||||
|
|
||||||
|
use super::ChatMsg;
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// State //
|
// State //
|
||||||
///////////
|
///////////
|
||||||
|
|
@ -115,7 +117,7 @@ pub struct TreeView<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<M, S> Widget for TreeView<M, S>
|
impl<M, S> Widget for TreeView<M, S>
|
||||||
where
|
where
|
||||||
M: Msg,
|
M: Msg + ChatMsg,
|
||||||
M::Id: Send + Sync,
|
M::Id: Send + Sync,
|
||||||
S: MsgStore<M> + Send + Sync,
|
S: MsgStore<M> + Send + Sync,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ use crate::store::{Msg, MsgStore, Path, Tree};
|
||||||
use crate::ui::chat::blocks::Block;
|
use crate::ui::chat::blocks::Block;
|
||||||
use crate::ui::widgets::empty::Empty;
|
use crate::ui::widgets::empty::Empty;
|
||||||
use crate::ui::widgets::text::Text;
|
use crate::ui::widgets::text::Text;
|
||||||
|
use crate::ui::ChatMsg;
|
||||||
|
|
||||||
use super::tree_blocks::{BlockId, Root, TreeBlocks};
|
use super::tree_blocks::{BlockId, Root, TreeBlocks};
|
||||||
use super::{widgets, Cursor, InnerTreeViewState};
|
use super::{widgets, Cursor, InnerTreeViewState};
|
||||||
|
|
||||||
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Path<M::Id> {
|
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Path<M::Id> {
|
||||||
match cursor {
|
match cursor {
|
||||||
Cursor::Msg(id) => self.store.path(id).await,
|
Cursor::Msg(id) => self.store.path(id).await,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ mod time;
|
||||||
|
|
||||||
use crossterm::style::{ContentStyle, Stylize};
|
use crossterm::style::{ContentStyle, Stylize};
|
||||||
|
|
||||||
|
use super::super::ChatMsg;
|
||||||
use crate::store::Msg;
|
use crate::store::Msg;
|
||||||
use crate::ui::widgets::join::{HJoin, Segment};
|
use crate::ui::widgets::join::{HJoin, Segment};
|
||||||
use crate::ui::widgets::padding::Padding;
|
use crate::ui::widgets::padding::Padding;
|
||||||
|
|
@ -19,7 +20,8 @@ pub fn style_placeholder() -> ContentStyle {
|
||||||
ContentStyle::default().dark_grey()
|
ContentStyle::default().dark_grey()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn msg<M: Msg>(highlighted: bool, indent: usize, msg: &M) -> BoxedWidget {
|
pub fn msg<M: Msg + ChatMsg>(highlighted: bool, indent: usize, msg: &M) -> BoxedWidget {
|
||||||
|
let (nick, content) = msg.styled();
|
||||||
HJoin::new(vec![
|
HJoin::new(vec![
|
||||||
Segment::new(
|
Segment::new(
|
||||||
Padding::new(time::widget(Some(msg.time()), highlighted))
|
Padding::new(time::widget(Some(msg.time()), highlighted))
|
||||||
|
|
@ -27,10 +29,10 @@ pub fn msg<M: Msg>(highlighted: bool, indent: usize, msg: &M) -> BoxedWidget {
|
||||||
.right(1),
|
.right(1),
|
||||||
),
|
),
|
||||||
Segment::new(Indent::new(indent, highlighted)),
|
Segment::new(Indent::new(indent, highlighted)),
|
||||||
Segment::new(Padding::new(Text::new(msg.nick())).right(1)),
|
Segment::new(Padding::new(Text::new(nick)).right(1)),
|
||||||
// TODO Minimum content width
|
// TODO Minimum content width
|
||||||
// TODO Minimizing and maximizing messages
|
// TODO Minimizing and maximizing messages
|
||||||
Segment::new(Text::new(msg.content()).wrap(true)).priority(1),
|
Segment::new(Text::new(content).wrap(true)).priority(1),
|
||||||
])
|
])
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use toss::terminal::Terminal;
|
||||||
|
|
||||||
use crate::euph::api::{SessionType, SessionView};
|
use crate::euph::api::{SessionType, SessionView};
|
||||||
use crate::euph::{self, Joined, Status};
|
use crate::euph::{self, Joined, Status};
|
||||||
use crate::vault::{EuphMsg, EuphVault};
|
use crate::vault::EuphVault;
|
||||||
|
|
||||||
use super::chat::ChatState;
|
use super::chat::ChatState;
|
||||||
use super::widgets::background::Background;
|
use super::widgets::background::Background;
|
||||||
|
|
@ -37,7 +37,7 @@ pub struct EuphRoom {
|
||||||
state: State,
|
state: State,
|
||||||
|
|
||||||
room: Option<euph::Room>,
|
room: Option<euph::Room>,
|
||||||
chat: ChatState<EuphMsg, EuphVault>,
|
chat: ChatState<euph::Message, EuphVault>,
|
||||||
nick_list: ListState<String>,
|
nick_list: ListState<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use rusqlite::Connection;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
|
||||||
use self::euph::EuphRequest;
|
use self::euph::EuphRequest;
|
||||||
pub use self::euph::{EuphMsg, EuphVault};
|
pub use self::euph::EuphVault;
|
||||||
|
|
||||||
enum Request {
|
enum Request {
|
||||||
Close(oneshot::Sender<()>),
|
Close(oneshot::Sender<()>),
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ use rusqlite::types::{FromSql, FromSqlError, ToSqlOutput, Value, ValueRef};
|
||||||
use rusqlite::{named_params, params, Connection, OptionalExtension, ToSql, Transaction};
|
use rusqlite::{named_params, params, Connection, OptionalExtension, ToSql, Transaction};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use toss::styled::Styled;
|
|
||||||
|
|
||||||
use crate::euph;
|
use crate::euph;
|
||||||
use crate::euph::api::{Message, Snowflake, Time};
|
use crate::euph::api::{Message, Snowflake, Time};
|
||||||
use crate::store::{Msg, MsgStore, Path, Tree};
|
use crate::store::{Msg, MsgStore, Path, Tree};
|
||||||
|
use crate::ui::ChatMsg;
|
||||||
|
|
||||||
use super::{Request, Vault};
|
use super::{Request, Vault};
|
||||||
|
|
||||||
|
|
@ -43,43 +43,6 @@ impl FromSql for Time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EuphMsg {
|
|
||||||
pub id: Snowflake,
|
|
||||||
pub parent: Option<Snowflake>,
|
|
||||||
pub time: Time,
|
|
||||||
pub nick: String,
|
|
||||||
pub content: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Msg for EuphMsg {
|
|
||||||
type Id = Snowflake;
|
|
||||||
|
|
||||||
fn id(&self) -> Self::Id {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent(&self) -> Option<Self::Id> {
|
|
||||||
self.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
fn time(&self) -> OffsetDateTime {
|
|
||||||
self.time.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nick(&self) -> Styled {
|
|
||||||
(&self.nick, euph::nick_style(&self.nick)).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content(&self) -> Styled {
|
|
||||||
self.content.trim().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn last_possible_id() -> Self::Id {
|
|
||||||
Snowflake::MAX
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EuphRequest> for Request {
|
impl From<EuphRequest> for Request {
|
||||||
fn from(r: EuphRequest) -> Self {
|
fn from(r: EuphRequest) -> Self {
|
||||||
Self::Euph(r)
|
Self::Euph(r)
|
||||||
|
|
@ -168,7 +131,7 @@ impl EuphVault {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl MsgStore<EuphMsg> for EuphVault {
|
impl MsgStore<euph::Message> for EuphVault {
|
||||||
async fn path(&self, id: &Snowflake) -> Path<Snowflake> {
|
async fn path(&self, id: &Snowflake) -> Path<Snowflake> {
|
||||||
// TODO vault::Error
|
// TODO vault::Error
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
@ -181,7 +144,7 @@ impl MsgStore<EuphMsg> for EuphVault {
|
||||||
rx.await.unwrap()
|
rx.await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tree(&self, tree_id: &Snowflake) -> Tree<EuphMsg> {
|
async fn tree(&self, tree_id: &Snowflake) -> Tree<euph::Message> {
|
||||||
// TODO vault::Error
|
// TODO vault::Error
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let request = EuphRequest::GetTree {
|
let request = EuphRequest::GetTree {
|
||||||
|
|
@ -290,7 +253,7 @@ pub(super) enum EuphRequest {
|
||||||
GetTree {
|
GetTree {
|
||||||
room: String,
|
room: String,
|
||||||
root: Snowflake,
|
root: Snowflake,
|
||||||
result: oneshot::Sender<Tree<EuphMsg>>,
|
result: oneshot::Sender<Tree<euph::Message>>,
|
||||||
},
|
},
|
||||||
GetPrevTreeId {
|
GetPrevTreeId {
|
||||||
room: String,
|
room: String,
|
||||||
|
|
@ -681,7 +644,7 @@ impl EuphRequest {
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
room: String,
|
room: String,
|
||||||
root: Snowflake,
|
root: Snowflake,
|
||||||
result: oneshot::Sender<Tree<EuphMsg>>,
|
result: oneshot::Sender<Tree<euph::Message>>,
|
||||||
) -> rusqlite::Result<()> {
|
) -> rusqlite::Result<()> {
|
||||||
let msgs = conn
|
let msgs = conn
|
||||||
.prepare(
|
.prepare(
|
||||||
|
|
@ -703,7 +666,7 @@ impl EuphRequest {
|
||||||
",
|
",
|
||||||
)?
|
)?
|
||||||
.query_map(params![room, root], |row| {
|
.query_map(params![room, root], |row| {
|
||||||
Ok(EuphMsg {
|
Ok(euph::Message {
|
||||||
id: row.get(0)?,
|
id: row.get(0)?,
|
||||||
parent: row.get(1)?,
|
parent: row.get(1)?,
|
||||||
time: row.get(2)?,
|
time: row.get(2)?,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue