Compare commits

..

18 Commits

Author SHA1 Message Date
Benedikt Peetz 7adea99703
Refactor(treewide): Remove the useless `tui_app` directory 2023-07-26 21:19:50 +02:00
Benedikt Peetz 15c705154e
Fix(handlers::main): Don't close the cli after an entered command 2023-07-26 21:17:37 +02:00
Benedikt Peetz 80a8c9ccf5
Fix(handlers::command): Only send success on real success
The `room_message_send()` function told the user about a successful sent
room message, even if that was not the case.
2023-07-26 21:15:53 +02:00
Benedikt Peetz 363a0f8fc4
Fix(handlers::command): Add the missing displayOutput handler
This handler is called by the lua executor, to show the final output of
a lua execution.
2023-07-26 21:14:36 +02:00
Benedikt Peetz fdb6ab1c29
Fix(app::command_interface): Add a `greet_multiple()` func to test tables
This is, like the `greet` function only here to debug the lua api. It
outputs a table.
2023-07-26 21:12:17 +02:00
Benedikt Peetz 57b01f0dbb
Fix(app::command_interface): Add a (workaround) print function
The default print function prints to stdout, which obviously
doesn't work with a tui application. This wrapper however is a
rather poor workaround, as it only works with strings (lua `print`
calls `tostring` to turn non string values in something printable).
2023-07-26 21:08:56 +02:00
Benedikt Peetz 49c9e90ba6
Feat(treewide): Add a way for Commands to return more than just strings 2023-07-26 21:04:04 +02:00
Benedikt Peetz a4c09c7b42
Fix(app::command_interface): Use new language_macro api 2023-07-26 17:19:57 +02:00
Benedikt Peetz ddd64f9ad3
Build(flake): Switch back to stable 2023-07-26 17:12:33 +02:00
Benedikt Peetz ae7f99632a
Build(flake+Cargo): Update lockfiles 2023-07-26 17:11:52 +02:00
Benedikt Peetz dc5d08f1a3
Refactor(language_macros): Complete rewrite
This **should** have everything the other implementation had, but the
api is implemented in a way, which is more in line with the expectation
raised at the lua functions (being that they are only wrappers over the
command api, and nothing more).

Aside of that, this version is actually documented!
2023-07-26 16:59:05 +02:00
Benedikt Peetz 296ebdb0cd
Fix(handlers::main): Close ci after a command input 2023-07-24 23:54:45 +02:00
Benedikt Peetz fe3849a7b7
Feat(ui): Add status panel, which shows command statuses and errors 2023-07-24 23:53:21 +02:00
Benedikt Peetz d46a0c3a24
Fix(lua_command::handle): Move lua_command handler to separate thread
This makes it possible to have lua code execute commands and receive
their output value, without risking a deadlock.
2023-07-24 23:45:44 +02:00
Benedikt Peetz b67dbf8e31
Refactor(treewide): Remove the repl, reuse of e. handling is hard
The event handling is deeply ingrained in the ui code, the commands are
focused around the ui code, in short splitting of the event handling and
command system from the ui is intentionally hard and in my opinion not
really worth it right now.
2023-07-24 23:38:16 +02:00
Benedikt Peetz d88cf810a4
Fix(app::command_interface): Provide pre-generated file, to check syntax 2023-07-23 16:39:03 +02:00
Benedikt Peetz e792334d21
Feat(treewide): Add a feature based layout and repl subcommand
Compiling the whole tui stack, just to debug the lua command line seems
counterproductive to me. This allows to just compile the needed parts
for a basic lua repl.

As of yet the repl is just a mock-up, as the event handling can, as of
right now, not easily be separated from the tui.

To activate specific features add specify the on the cargo command line
like this:
```
cargo run --features "cli tui"
```
or add them to the `default` feature set in the `Cargo.toml`.
2023-07-23 16:39:01 +02:00
antifallobst 21b42bbb9e
Fix(event_handlers): removed outdated reference to the ci_output module 2023-07-22 18:01:47 +02:00
8 changed files with 53 additions and 126 deletions

View File

@ -40,11 +40,6 @@ 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),

View File

@ -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, status::State, App,
}, ui::central::InputPosition}; };
pub async fn handle( pub async fn handle(
app: &mut App<'_>, app: &mut App<'_>,
@ -97,18 +97,6 @@ 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?;

View File

@ -10,7 +10,7 @@ use crate::{
ui::central, ui::central,
}; };
pub async fn handle_normal( pub async fn handle(
app: &mut App<'_>, app: &mut App<'_>,
input_event: &CrosstermEvent, input_event: &CrosstermEvent,
) -> Result<EventStatus> { ) -> Result<EventStatus> {
@ -38,22 +38,37 @@ pub async fn handle_normal(
.await?; .await?;
} }
CrosstermEvent::Key(KeyEvent { CrosstermEvent::Key(KeyEvent {
code: KeyCode::Char(':'), code: KeyCode::Char('c'),
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::Char('i'), code: KeyCode::Enter,
modifiers: KeyModifiers::ALT,
.. ..
}) => { }) => {
app.tx app.tx
.send(Event::CommandEvent(Command::SetModeInsert, None)) .send(Event::CommandEvent(
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 {
@ -174,35 +189,3 @@ pub async fn handle_normal(
}; };
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)
}

View File

@ -5,11 +5,7 @@ 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::{ use crate::app::{command_interface::{Command, lua_command_manager::CommandTransferValue}, status::State, 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};
@ -39,15 +35,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::Normal => main::handle_normal(app, &event).await.with_context(|| { State::None => unreachable!(
format!("Failed to handle input (normal) event: `{:#?}`", event) "This state should not be available, when we are in the input handling"
}), ),
State::Insert => main::handle_insert(app, &event).await.with_context(|| { State::Main => main::handle(app, &event)
format!("Failed to handle input (insert) event: `{:#?}`", event) .await
}), .with_context(|| format!("Failed to handle input event: `{:#?}`", event)),
State::Setup => setup::handle(app, &event).await.with_context(|| { State::Setup => setup::handle(app, &event)
format!("Failed to handle input (setup) event: `{:#?}`", event) .await
}), .with_context(|| format!("Failed to handle input event: `{:#?}`", event)),
}, },
} }
} }

View File

@ -75,9 +75,8 @@ 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")?;
@ -95,9 +94,8 @@ 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());
self.status.set_state(State::Setup);
loop { loop {
self.status.set_state(State::Setup);
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")?;

View File

@ -1,5 +1,3 @@
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;
@ -13,9 +11,8 @@ use matrix_sdk::{
}; };
pub enum State { pub enum State {
Normal, None,
Insert, Main,
/// Temporary workaround until command based login is working
Setup, Setup,
} }
@ -52,16 +49,6 @@ 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 {
@ -151,7 +138,7 @@ impl Status {
}; };
Self { Self {
state: State::Normal, state: State::None,
account_name: "".to_owned(), account_name: "".to_owned(),
account_user_id: "".to_owned(), account_user_id: "".to_owned(),
client, client,

View File

@ -226,10 +226,6 @@ 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
} }

View File

@ -1,7 +1,7 @@
use std::cmp; use std::cmp;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use tui::{layout::{Constraint, Direction, Layout}, widgets::{Paragraph, Block, Borders}, style::{Style, Color}}; use tui::layout::{Constraint, Direction, Layout};
use crate::app::status::Status; use crate::app::status::Status;
@ -13,21 +13,13 @@ 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 = Layout::default() let chunks = match self.cli {
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)
@ -67,13 +59,6 @@ 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)
@ -87,9 +72,8 @@ 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(), bottom_chunks[1]), Some(cli) => frame.render_widget(cli.widget(), chunks[1]),
None => (), None => (),
}; };
frame.render_widget(room_info_panel, right_chunks[0]); frame.render_widget(room_info_panel, right_chunks[0]);