This commit is contained in:
Robin Appelman 2024-07-24 23:22:04 +02:00
commit 6e0c662fb4
13 changed files with 263 additions and 45 deletions

41
src/ui/footer.rs Normal file
View file

@ -0,0 +1,41 @@
use crate::app::App;
use crate::ui::state::UiPage;
use ratatui::layout::Constraint;
use ratatui::prelude::Style;
use ratatui::style::palette::tailwind;
use ratatui::widgets::{Row, Table};
pub fn footer(app: &App, page: UiPage) -> Table {
let footer_style = Style::default()
.bg(tailwind::BLACK)
.fg(tailwind::GREEN.c600);
let widths = [
Constraint::Percentage(100),
Constraint::Min(25),
Constraint::Min(20),
];
Table::new(
[Row::new([
help(page).to_string(),
format!(
"{} unmatched items",
app.unmatched
.iter()
.map(|unmatched| unmatched.count())
.sum::<usize>()
),
format!("{} parse errors", app.error_count),
])],
widths,
)
.style(footer_style)
}
fn help(page: UiPage) -> &'static str {
match page {
UiPage::MatchList => "«Q» Exit - «Enter» Select",
UiPage::Match => "«Q» Exit - «Esc» Back",
}
}

View file

@ -1,23 +1,15 @@
use crate::app::{App, LogMatch};
use crate::ui::style::{TABLE_HEADER_STYLE, TABLE_SELECTED_STYLE};
use ratatui::prelude::*;
use ratatui::style::palette::tailwind;
use ratatui::widgets::{Cell, HighlightSpacing, Row, Table};
use std::fmt::Write;
pub fn match_list(app: &App) -> Table {
let header_style = Style::default()
.bg(tailwind::BLACK)
.fg(tailwind::GREEN.c600);
let selected_style = Style::default()
.add_modifier(Modifier::REVERSED)
.bg(tailwind::BLACK)
.fg(tailwind::GREEN.c600);
let header = ["Statement", "File", "Line", "Count"]
.into_iter()
.map(Cell::from)
.collect::<Row>()
.style(header_style)
.style(TABLE_HEADER_STYLE)
.height(1);
let widths = [
@ -31,7 +23,7 @@ pub fn match_list(app: &App) -> Table {
widths,
)
.header(header)
.highlight_style(selected_style)
.highlight_style(TABLE_SELECTED_STYLE)
.highlight_spacing(HighlightSpacing::Always);
table
}
@ -46,5 +38,5 @@ fn log_row<'a>(result: &LogMatch, app: &'a App) -> Row<'a> {
writeln!(&mut paths, "{}", statement.path()).unwrap();
writeln!(&mut lines, "{}", statement.line).unwrap();
}
Row::new([message, paths, lines, result.count.to_string()]).height(result.result.len() as u16)
Row::new([message, paths, lines, result.count().to_string()]).height(result.result.len() as u16)
}

View file

@ -1,6 +1,8 @@
use crate::app::App;
use crate::error::UiError;
use crate::ui::footer::footer;
use crate::ui::match_list::match_list;
use crate::ui::single_match::single_match;
use crate::ui::state::{UiEvent, UiState};
use ratatui::crossterm::event::{Event, KeyCode, KeyModifiers};
use ratatui::crossterm::terminal::{
@ -12,8 +14,11 @@ use ratatui::Terminal;
use std::io;
use std::io::stdout;
mod footer;
mod match_list;
mod single_match;
mod state;
pub mod style;
pub fn run_ui(app: App) -> Result<(), UiError> {
enable_raw_mode()?;
@ -46,6 +51,7 @@ fn handle_events() -> io::Result<Option<UiEvent>> {
KeyCode::Esc => Some(UiEvent::Back),
KeyCode::Down => Some(UiEvent::Down),
KeyCode::Up => Some(UiEvent::Up),
KeyCode::Enter => Some(UiEvent::Select),
_ => None,
});
}
@ -55,10 +61,25 @@ fn handle_events() -> io::Result<Option<UiEvent>> {
}
fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
let page = state.page();
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Percentage(100), Constraint::Length(1)])
.split(frame.size());
match state {
UiState::Quit => {}
UiState::MatchList { table_state } => {
frame.render_stateful_widget(match_list(app), frame.size(), table_state);
frame.render_stateful_widget(match_list(app), layout[0], table_state);
frame.render_widget(footer(app, page), layout[1]);
}
UiState::Match {
selected: index,
table_state,
} => {
let log_match = &app.matches[*index];
frame.render_stateful_widget(single_match(app, log_match), layout[0], table_state);
frame.render_widget(footer(app, page), layout[1]);
}
}
}

35
src/ui/single_match.rs Normal file
View file

@ -0,0 +1,35 @@
use crate::app::{App, LogMatch};
use crate::logline::LogLine;
use crate::ui::style::{TABLE_HEADER_STYLE, TABLE_SELECTED_STYLE};
use ratatui::layout::Constraint;
use ratatui::widgets::{Cell, HighlightSpacing, Row, Table};
pub fn single_match<'a>(app: &'a App, matches: &'a LogMatch) -> Table<'a> {
let lines = matches.lines.iter().map(|i| &app.lines[*i]);
let header = ["Level", "App", "Message"]
.into_iter()
.map(Cell::from)
.collect::<Row>()
.style(TABLE_HEADER_STYLE)
.height(1);
let widths = [
Constraint::Min(10),
Constraint::Min(20),
Constraint::Percentage(100),
];
let table = Table::new(lines.map(|line| log_row(line)), widths)
.header(header)
.highlight_style(TABLE_SELECTED_STYLE)
.highlight_spacing(HighlightSpacing::Always);
table
}
fn log_row(line: &LogLine) -> Row {
Row::new([
line.level.as_str(),
line.app.as_str(),
line.message.as_str(),
])
}

View file

@ -4,7 +4,13 @@ use table_state::TableStateExt;
#[derive(Clone, Debug)]
pub enum UiState {
MatchList { table_state: TableState },
MatchList {
table_state: TableState,
},
Match {
selected: usize,
table_state: TableState,
},
Quit,
}
@ -17,6 +23,13 @@ impl Default for UiState {
}
impl UiState {
pub fn page(&self) -> UiPage {
match self {
UiState::Quit | UiState::MatchList { .. } => UiPage::MatchList,
UiState::Match { .. } => UiPage::Match,
}
}
pub fn process(self, event: UiEvent, app: &App) -> UiState {
match (self, event) {
(UiState::Quit, _) => UiState::Quit,
@ -30,6 +43,52 @@ impl UiState {
table_state.up(app.matches.len());
UiState::MatchList { table_state }
}
(UiState::MatchList { table_state }, UiEvent::Select) => {
let selected = table_state.selected().unwrap_or(0);
let mut table_state = TableState::default();
table_state.select(Some(0));
UiState::Match {
selected,
table_state,
}
}
(
UiState::Match {
selected: index, ..
},
UiEvent::Back,
) => {
let mut table_state = TableState::default();
table_state.select(Some(index));
UiState::MatchList { table_state }
}
(
UiState::Match {
mut table_state,
selected,
},
UiEvent::Down,
) => {
table_state.down(app.matches[selected].count());
UiState::Match {
table_state,
selected,
}
}
(
UiState::Match {
mut table_state,
selected,
},
UiEvent::Up,
) => {
table_state.up(app.matches[selected].count());
UiState::Match {
table_state,
selected,
}
}
(state @ UiState::Match { .. }, _) => state,
}
}
}
@ -39,6 +98,12 @@ pub enum UiEvent {
Back,
Up,
Down,
Select,
}
pub enum UiPage {
MatchList,
Match,
}
mod table_state {

5
src/ui/style.rs Normal file
View file

@ -0,0 +1,5 @@
use ratatui::prelude::Style;
use ratatui::style::palette::tailwind;
pub const TABLE_HEADER_STYLE: Style = Style::new().bg(tailwind::BLACK).fg(tailwind::GREEN.c600);
pub const TABLE_SELECTED_STYLE: Style = Style::new().fg(tailwind::BLACK).bg(tailwind::GREEN.c600);