Compare commits
22 Commits
7adea99703
...
84c13fd6f8
Author | SHA1 | Date |
---|---|---|
Benedikt Peetz | 84c13fd6f8 | |
Benedikt Peetz | 855d487693 | |
Benedikt Peetz | 258f784098 | |
Benedikt Peetz | a80245c523 | |
Benedikt Peetz | f7b161fb55 | |
Benedikt Peetz | 909fc01a48 | |
Benedikt Peetz | c0a1fc0a02 | |
Benedikt Peetz | 1a35bb152c | |
Benedikt Peetz | 7489f06a7c | |
Benedikt Peetz | 3ca01912b9 | |
Benedikt Peetz | fbcf572f47 | |
Benedikt Peetz | 27ad48c5e9 | |
Benedikt Peetz | a3b49b17f4 | |
Benedikt Peetz | 0288bdb0ad | |
Benedikt Peetz | 1fe04ca5c6 | |
Benedikt Peetz | c7a4d5a8ab | |
Benedikt Peetz | 189ae509f8 | |
Benedikt Peetz | ebb16a20de | |
antifallobst | 993ef6af89 | |
antifallobst | d447eb2312 | |
antifallobst | 4856ecc582 | |
antifallobst | dcf87f257d |
|
@ -40,6 +40,11 @@ struct Commands {
|
||||||
/// Go to the previous plane
|
/// Go to the previous plane
|
||||||
cycle_planes_rev: fn(),
|
cycle_planes_rev: fn(),
|
||||||
|
|
||||||
|
/// Sets the current app mode to Normal / navigation mode
|
||||||
|
set_mode_normal: fn(),
|
||||||
|
/// Sets the current app mode to Insert / editing mode
|
||||||
|
set_mode_insert: fn(),
|
||||||
|
|
||||||
/// Send a message to the current room
|
/// Send a message to the current room
|
||||||
/// The sent message is interpreted literally.
|
/// The sent message is interpreted literally.
|
||||||
room_message_send: fn(String),
|
room_message_send: fn(String),
|
||||||
|
|
|
@ -4,14 +4,14 @@ use anyhow::{Error, Result};
|
||||||
use cli_log::{trace, warn};
|
use cli_log::{trace, warn};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
use crate::app::{
|
use crate::{app::{
|
||||||
command_interface::{
|
command_interface::{
|
||||||
lua_command_manager::{CommandTransferValue, Table},
|
lua_command_manager::{CommandTransferValue, Table},
|
||||||
Command,
|
Command,
|
||||||
},
|
},
|
||||||
events::event_types::EventStatus,
|
events::event_types::EventStatus,
|
||||||
App,
|
App, status::State,
|
||||||
};
|
}, ui::central::InputPosition};
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
app: &mut App<'_>,
|
app: &mut App<'_>,
|
||||||
|
@ -97,6 +97,18 @@ pub async fn handle(
|
||||||
EventStatus::Ok
|
EventStatus::Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Command::SetModeNormal => {
|
||||||
|
app.status.set_state(State::Normal);
|
||||||
|
send_status_output!("Set input mode to Normal");
|
||||||
|
EventStatus::Ok
|
||||||
|
}
|
||||||
|
Command::SetModeInsert => {
|
||||||
|
app.status.set_state(State::Insert);
|
||||||
|
app.ui.set_input_position(InputPosition::MessageCompose);
|
||||||
|
send_status_output!("Set input mode to Insert");
|
||||||
|
EventStatus::Ok
|
||||||
|
}
|
||||||
|
|
||||||
Command::RoomMessageSend(msg) => {
|
Command::RoomMessageSend(msg) => {
|
||||||
if let Some(room) = app.status.room_mut() {
|
if let Some(room) = app.status.room_mut() {
|
||||||
room.send(msg.clone()).await?;
|
room.send(msg.clone()).await?;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
ui::central,
|
ui::central,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle_normal(
|
||||||
app: &mut App<'_>,
|
app: &mut App<'_>,
|
||||||
input_event: &CrosstermEvent,
|
input_event: &CrosstermEvent,
|
||||||
) -> Result<EventStatus> {
|
) -> Result<EventStatus> {
|
||||||
|
@ -38,37 +38,22 @@ pub async fn handle(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
CrosstermEvent::Key(KeyEvent {
|
CrosstermEvent::Key(KeyEvent {
|
||||||
code: KeyCode::Char('c'),
|
code: KeyCode::Char(':'),
|
||||||
modifiers: KeyModifiers::CONTROL,
|
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
app.tx
|
app.tx
|
||||||
.send(Event::CommandEvent(Command::CommandLineShow, None))
|
.send(Event::CommandEvent(Command::CommandLineShow, None))
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
input => match app.ui.input_position() {
|
|
||||||
central::InputPosition::MessageCompose => {
|
|
||||||
match input {
|
|
||||||
CrosstermEvent::Key(KeyEvent {
|
CrosstermEvent::Key(KeyEvent {
|
||||||
code: KeyCode::Enter,
|
code: KeyCode::Char('i'),
|
||||||
modifiers: KeyModifiers::ALT,
|
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
app.tx
|
app.tx
|
||||||
.send(Event::CommandEvent(
|
.send(Event::CommandEvent(Command::SetModeInsert, None))
|
||||||
Command::RoomMessageSend(app.ui.message_compose.lines().join("\n")),
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
.await?;
|
.await?;
|
||||||
app.ui.message_compose_clear();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
app.ui
|
|
||||||
.message_compose
|
|
||||||
.input(tui_textarea::Input::from(input.to_owned()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
input => match app.ui.input_position() {
|
||||||
central::InputPosition::Rooms => {
|
central::InputPosition::Rooms => {
|
||||||
match input {
|
match input {
|
||||||
CrosstermEvent::Key(KeyEvent {
|
CrosstermEvent::Key(KeyEvent {
|
||||||
|
@ -189,3 +174,35 @@ pub async fn handle(
|
||||||
};
|
};
|
||||||
Ok(EventStatus::Ok)
|
Ok(EventStatus::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_insert(app: &mut App<'_>, event: &CrosstermEvent) -> Result<EventStatus> {
|
||||||
|
match event {
|
||||||
|
CrosstermEvent::Key(KeyEvent {
|
||||||
|
code: KeyCode::Esc, ..
|
||||||
|
}) => {
|
||||||
|
app.tx
|
||||||
|
.send(Event::CommandEvent(Command::SetModeNormal, None))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
CrosstermEvent::Key(KeyEvent {
|
||||||
|
code: KeyCode::Enter,
|
||||||
|
modifiers: KeyModifiers::ALT,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
app.tx
|
||||||
|
.send(Event::CommandEvent(
|
||||||
|
Command::RoomMessageSend(app.ui.message_compose.lines().join("\n")),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
app.ui.message_compose_clear();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
app.ui
|
||||||
|
.message_compose
|
||||||
|
.input(tui_textarea::Input::from(event.to_owned()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(EventStatus::Ok)
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,11 @@ use cli_log::trace;
|
||||||
use crossterm::event::Event as CrosstermEvent;
|
use crossterm::event::Event as CrosstermEvent;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
use crate::app::{command_interface::{Command, lua_command_manager::CommandTransferValue}, status::State, App};
|
use crate::app::{
|
||||||
|
command_interface::{lua_command_manager::CommandTransferValue, Command},
|
||||||
|
status::State,
|
||||||
|
App,
|
||||||
|
};
|
||||||
|
|
||||||
use self::handlers::{command, lua_command, main, matrix, setup};
|
use self::handlers::{command, lua_command, main, matrix, setup};
|
||||||
|
|
||||||
|
@ -35,15 +39,15 @@ impl Event {
|
||||||
.with_context(|| format!("Failed to handle lua code: `{}`", lua_code)),
|
.with_context(|| format!("Failed to handle lua code: `{}`", lua_code)),
|
||||||
|
|
||||||
Event::InputEvent(event) => match app.status.state() {
|
Event::InputEvent(event) => match app.status.state() {
|
||||||
State::None => unreachable!(
|
State::Normal => main::handle_normal(app, &event).await.with_context(|| {
|
||||||
"This state should not be available, when we are in the input handling"
|
format!("Failed to handle input (normal) event: `{:#?}`", event)
|
||||||
),
|
}),
|
||||||
State::Main => main::handle(app, &event)
|
State::Insert => main::handle_insert(app, &event).await.with_context(|| {
|
||||||
.await
|
format!("Failed to handle input (insert) event: `{:#?}`", event)
|
||||||
.with_context(|| format!("Failed to handle input event: `{:#?}`", event)),
|
}),
|
||||||
State::Setup => setup::handle(app, &event)
|
State::Setup => setup::handle(app, &event).await.with_context(|| {
|
||||||
.await
|
format!("Failed to handle input (setup) event: `{:#?}`", event)
|
||||||
.with_context(|| format!("Failed to handle input event: `{:#?}`", event)),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,9 @@ impl App<'_> {
|
||||||
self.init_account().await?;
|
self.init_account().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.status.set_state(State::Normal);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
self.status.set_state(State::Main);
|
|
||||||
self.ui.update(&self.status).await?;
|
self.ui.update(&self.status).await?;
|
||||||
|
|
||||||
let event = self.rx.recv().await.context("Failed to get next event")?;
|
let event = self.rx.recv().await.context("Failed to get next event")?;
|
||||||
|
@ -94,8 +95,9 @@ impl App<'_> {
|
||||||
async fn setup(&mut self) -> Result<()> {
|
async fn setup(&mut self) -> Result<()> {
|
||||||
self.ui.setup_ui = Some(setup::UI::new());
|
self.ui.setup_ui = Some(setup::UI::new());
|
||||||
|
|
||||||
loop {
|
|
||||||
self.status.set_state(State::Setup);
|
self.status.set_state(State::Setup);
|
||||||
|
|
||||||
|
loop {
|
||||||
self.ui.update_setup().await?;
|
self.ui.update_setup().await?;
|
||||||
|
|
||||||
let event = self.rx.recv().await.context("Failed to get next event")?;
|
let event = self.rx.recv().await.context("Failed to get next event")?;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use cli_log::warn;
|
use cli_log::warn;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
@ -11,8 +13,9 @@ use matrix_sdk::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum State {
|
pub enum State {
|
||||||
None,
|
Normal,
|
||||||
Main,
|
Insert,
|
||||||
|
/// Temporary workaround until command based login is working
|
||||||
Setup,
|
Setup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +52,16 @@ pub struct Status {
|
||||||
status_messages: Vec<StatusMessage>,
|
status_messages: Vec<StatusMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for State {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Normal => write!(f, "Normal"),
|
||||||
|
Self::Insert => write!(f, "Insert"),
|
||||||
|
Self::Setup => write!(f, "Setup (!! workaround !!)"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Room {
|
impl Room {
|
||||||
pub fn new(matrix_room: matrix_sdk::room::Joined) -> Self {
|
pub fn new(matrix_room: matrix_sdk::room::Joined) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -138,7 +151,7 @@ impl Status {
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
state: State::None,
|
state: State::Normal,
|
||||||
account_name: "".to_owned(),
|
account_name: "".to_owned(),
|
||||||
account_user_id: "".to_owned(),
|
account_user_id: "".to_owned(),
|
||||||
client,
|
client,
|
||||||
|
|
|
@ -226,6 +226,10 @@ impl UI<'_> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_input_position(&mut self, position: InputPosition) {
|
||||||
|
self.input_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn input_position(&self) -> &InputPosition {
|
pub fn input_position(&self) -> &InputPosition {
|
||||||
&self.input_position
|
&self.input_position
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use tui::layout::{Constraint, Direction, Layout};
|
use tui::{layout::{Constraint, Direction, Layout}, widgets::{Paragraph, Block, Borders}, style::{Style, Color}};
|
||||||
|
|
||||||
use crate::app::status::Status;
|
use crate::app::status::Status;
|
||||||
|
|
||||||
|
@ -13,13 +13,21 @@ pub mod widgets;
|
||||||
|
|
||||||
impl UI<'_> {
|
impl UI<'_> {
|
||||||
pub async fn update(&mut self, status: &Status) -> Result<()> {
|
pub async fn update(&mut self, status: &Status) -> Result<()> {
|
||||||
let chunks = match self.cli {
|
let chunks = Layout::default()
|
||||||
Some(_) => Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Min(10), Constraint::Length(3)].as_ref())
|
.constraints([Constraint::Min(10), Constraint::Length(3)].as_ref())
|
||||||
.split(self.terminal.size()?),
|
.split(self.terminal.size()?);
|
||||||
None => vec![self.terminal.size()?],
|
|
||||||
};
|
let bottom_chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints(
|
||||||
|
[
|
||||||
|
Constraint::Length((status.state().to_string().len() + 2) as u16),
|
||||||
|
Constraint::Min(16),
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
.split(chunks[1]);
|
||||||
|
|
||||||
let main_chunks = Layout::default()
|
let main_chunks = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
|
@ -59,6 +67,13 @@ impl UI<'_> {
|
||||||
.colors(&mut self.cli, &mut self.message_compose);
|
.colors(&mut self.cli, &mut self.message_compose);
|
||||||
|
|
||||||
// initiate the widgets
|
// initiate the widgets
|
||||||
|
let mode_indicator = Paragraph::new(status.state().to_string())
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.borders(Borders::ALL)
|
||||||
|
.style(Style::default().fg(Color::DarkGray)),
|
||||||
|
)
|
||||||
|
.style(Style::default().fg(Color::LightYellow));
|
||||||
let status_panel = status::init(status, &colors);
|
let status_panel = status::init(status, &colors);
|
||||||
let rooms_panel = rooms::init(status, &colors);
|
let rooms_panel = rooms::init(status, &colors);
|
||||||
let (messages_panel, mut messages_state) = messages::init(status.room(), &colors)
|
let (messages_panel, mut messages_state) = messages::init(status.room(), &colors)
|
||||||
|
@ -72,8 +87,9 @@ impl UI<'_> {
|
||||||
frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state);
|
frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state);
|
||||||
frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state);
|
frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state);
|
||||||
frame.render_widget(self.message_compose.widget(), middle_chunks[1]);
|
frame.render_widget(self.message_compose.widget(), middle_chunks[1]);
|
||||||
|
frame.render_widget(mode_indicator, bottom_chunks[0]);
|
||||||
match &self.cli {
|
match &self.cli {
|
||||||
Some(cli) => frame.render_widget(cli.widget(), chunks[1]),
|
Some(cli) => frame.render_widget(cli.widget(), bottom_chunks[1]),
|
||||||
None => (),
|
None => (),
|
||||||
};
|
};
|
||||||
frame.render_widget(room_info_panel, right_chunks[0]);
|
frame.render_widget(room_info_panel, right_chunks[0]);
|
||||||
|
|
Reference in New Issue