Skip to content

Commit

Permalink
refactor(tui): use built-in list and remove mouse events
Browse files Browse the repository at this point in the history
  • Loading branch information
orhun committed Dec 1, 2024
1 parent 8fdf418 commit f1af005
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 131 deletions.
53 changes: 3 additions & 50 deletions git-cliff-tui/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ use ratatui::crossterm::event::{
KeyEvent,
KeyEventKind,
KeyModifiers,
MouseButton,
MouseEvent,
MouseEventKind,
};
use ratatui::layout::Position;
use std::sync::mpsc;
use std::thread;
use std::time::{
Expand Down Expand Up @@ -132,19 +129,10 @@ pub fn handle_key_events(
}
}
KeyCode::Char('k') | KeyCode::Char('K') | KeyCode::Up => {
state.selected_index = if state.selected_index == 0 {
state.configs.len() - 1
} else {
state.selected_index - 1
}
state.list_state.select_previous();
}
KeyCode::Char('j') | KeyCode::Char('J') | KeyCode::Down => {
state.selected_index = if state.selected_index >= state.configs.len() - 1
{
0
} else {
state.selected_index + 1
}
state.list_state.select_next();
}
KeyCode::Char('h') | KeyCode::Char('H') | KeyCode::Left => {
state.markdown.scroll_index =
Expand All @@ -159,10 +147,7 @@ pub fn handle_key_events(
sender.send(Event::Generate)?;
}
}
KeyCode::Enter => {
state.markdown.config_index = state.selected_index;
sender.send(Event::Generate)?
}
KeyCode::Enter => sender.send(Event::Generate)?,
KeyCode::Char('a') | KeyCode::Char('A') => {
state.autoload = !state.autoload;
}
Expand All @@ -177,35 +162,3 @@ pub fn handle_key_events(
}
Ok(())
}

/// Handles the mouse events and updates the state.
pub(crate) fn handle_mouse_events(
mouse_event: MouseEvent,
sender: mpsc::Sender<Event>,
state: &mut State,
) -> Result<()> {
match mouse_event.kind {
MouseEventKind::Moved => {
let position = Position::new(mouse_event.column, mouse_event.row);
state.configs.iter_mut().for_each(|config| {
config.is_hovered = config.area.contains(position);
})
}
MouseEventKind::Down(MouseButton::Left) => {
if let Some(i) = state.configs.iter().position(|p| p.is_hovered) {
state.selected_index = i;
sender.send(Event::Generate)?;
}
}
MouseEventKind::ScrollUp => {
state.markdown.scroll_index =
state.markdown.scroll_index.saturating_sub(1);
}
MouseEventKind::ScrollDown => {
state.markdown.scroll_index =
state.markdown.scroll_index.saturating_add(1);
}
_ => {}
}
Ok(())
}
13 changes: 6 additions & 7 deletions git-cliff-tui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,7 @@ fn main() -> Result<()> {
events.sender.clone(),
&mut state,
)?,
Event::Mouse(mouse_event) => event::handle_mouse_events(
mouse_event,
events.sender.clone(),
&mut state,
)?,
Event::Mouse(_) => {}
Event::Resize(_, _) => {}
Event::Generate | Event::AutoGenerate => {
if event == Event::AutoGenerate && !state.autoload {
Expand All @@ -114,8 +110,11 @@ fn main() -> Result<()> {
let sender = events.sender.clone();
let args = state.args.clone();
state.is_generating = true;
state.args.config =
PathBuf::from(state.configs[state.selected_index].file.clone());
state.args.config = PathBuf::from(
state.configs[state.list_state.selected().unwrap_or_default()]
.file
.clone(),
);
thread::spawn(move || {
let mut output = Vec::new();
sender
Expand Down
21 changes: 10 additions & 11 deletions git-cliff-tui/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use git_cliff::args::Args;
use git_cliff::core::embed::BuiltinConfig;
use md_tui::nodes::root::ComponentRoot;
use ratatui::layout::Rect;
use ratatui::widgets::ListState;
use std::error;
use throbber_widgets_tui::ThrobberState;

Expand All @@ -13,11 +14,7 @@ pub type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
#[derive(Debug, Default)]
pub struct Config {
/// Name/path of the configuration.
pub file: String,
/// Widget area.
pub area: Rect,
/// Is the widget hovered?
pub is_hovered: bool,
pub file: String,
}

/// Markdown content.
Expand All @@ -42,8 +39,8 @@ pub struct State {
pub is_running: bool,
/// Configuration files.
pub configs: Vec<Config>,
/// Index of the selected configuration.
pub selected_index: usize,
/// The state of the list.
pub list_state: ListState,
/// Changelog contents.
pub changelog: String,
/// Error message.
Expand All @@ -67,9 +64,7 @@ impl State {
pub fn new(args: Args) -> Result<Self> {
let configs = BuiltinConfig::iter()
.map(|file| Config {
file: file.to_string(),
area: Rect::default(),
is_hovered: false,
file: file.to_string(),
})
.collect();
Ok(Self {
Expand All @@ -78,7 +73,11 @@ impl State {
is_toggled: true,
is_generating: false,
configs,
selected_index: 0,
list_state: {
let mut list_state = ListState::default();
list_state.select_first();
list_state
},
changelog: String::new(),
error: None,
markdown: Markdown::default(),
Expand Down
103 changes: 40 additions & 63 deletions git-cliff-tui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use ratatui::{
widgets::{
Block,
BorderType,
List,
ListItem,
Paragraph,
Scrollbar,
ScrollbarOrientation,
Expand Down Expand Up @@ -73,7 +75,7 @@ pub fn render(state: &mut State, frame: &mut Frame) {
}
}

fn render_key_bindings(frame: &mut Frame, rect: Rect) {
fn render_key_bindings(frame: &mut Frame, area: Rect) {
frame.render_widget(
Paragraph::new(
Line::default()
Expand All @@ -93,69 +95,44 @@ fn render_key_bindings(frame: &mut Frame, rect: Rect) {
)
.alignment(Alignment::Center),
),
rect,
area,
);
}

fn render_list(state: &mut State, frame: &mut Frame, rect: Rect) {
frame.render_widget(
Block::bordered()
.title_top("|Config|".yellow())
.title_alignment(Alignment::Center)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Rgb(100, 100, 100))),
rect,
);
fn render_list(state: &mut State, frame: &mut Frame, area: Rect) {
if !state.configs.is_empty() {
let rect =
Layout::vertical([Constraint::Min(1), Constraint::Percentage(100)])
.split(rect)[1];
let borders_line = 2;
let item_count = (rect.height - borders_line) as usize;
let start_offset = (state.selected_index + 1).saturating_sub(item_count);
let rects =
Layout::vertical([Constraint::Length(1)].repeat(item_count)).split(rect);
for (i, config) in state
let items = state
.configs
.iter_mut()
.skip(start_offset)
.take(item_count)
.enumerate()
{
let mut style = Style::new();
if config.is_hovered {
style = style.yellow()
} else if state.selected_index == i + start_offset {
style = style.yellow();
}
let item = Layout::horizontal([
Constraint::Min(1),
Constraint::Percentage(100),
])
.split(rects[i]);
config.area = rects[i];
frame.render_widget(
Paragraph::new(Line::from(config.file.clone()).style(style)),
item[1],
);
}
if state.configs.len() > rect.height as usize - 2 {
frame.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓")),
rect.inner(Margin {
vertical: 1,
horizontal: 0,
}),
&mut ScrollbarState::new(item_count).position(state.selected_index),
);
}
.iter()
.map(|c| ListItem::new(c.file.to_string()))
.collect::<Vec<ListItem>>();
let list = List::new(items)
.block(
Block::bordered()
.title_top("|Config|".yellow())
.title_alignment(Alignment::Center)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Rgb(100, 100, 100))),
)
.style(Style::new().white())
.highlight_style(Style::new().reversed());
frame.render_stateful_widget(list, area, &mut state.list_state);
frame.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓")),
area.inner(Margin {
vertical: 1,
horizontal: 0,
}),
&mut ScrollbarState::new(state.configs.len())
.position(state.list_state.selected().unwrap_or_default()),
);
}
}

fn render_changelog(state: &mut State, frame: &mut Frame, rect: Rect) {
state.markdown.area = rect.inner(Margin {
fn render_changelog(state: &mut State, frame: &mut Frame, area: Rect) {
state.markdown.area = area.inner(Margin {
horizontal: 1,
vertical: 1,
});
Expand Down Expand Up @@ -222,7 +199,7 @@ fn render_changelog(state: &mut State, frame: &mut Frame, rect: Rect) {
Line::from(format!("|{}|", env!("CARGO_PKG_VERSION")))
.right_aligned(),
),
rect,
area,
);
if let Some(component) = &mut state.markdown.component {
let mut height = 2;
Expand All @@ -241,7 +218,7 @@ fn render_changelog(state: &mut State, frame: &mut Frame, rect: Rect) {
Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓")),
rect.inner(Margin {
area.inner(Margin {
vertical: 1,
horizontal: 0,
}),
Expand All @@ -252,8 +229,8 @@ fn render_changelog(state: &mut State, frame: &mut Frame, rect: Rect) {

if state.is_generating {
let throbber_area = Rect::new(
rect.left().saturating_add(2),
rect.bottom().saturating_sub(1),
area.left().saturating_add(2),
area.bottom().saturating_sub(1),
1,
1,
);
Expand All @@ -273,20 +250,20 @@ fn render_changelog(state: &mut State, frame: &mut Frame, rect: Rect) {
}
}

fn render_error(state: &mut State, frame: &mut Frame, rect: Rect) {
fn render_error(state: &mut State, frame: &mut Frame, area: Rect) {
if let Some(error) = &state.error {
frame.render_widget(
Block::bordered()
.title_top("|Error|".red().into_centered_line())
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Rgb(100, 100, 100))),
rect,
area,
);
frame.render_widget(
Paragraph::new(Line::from(error.clone()))
.alignment(Alignment::Center)
.wrap(Wrap { trim: false }),
rect.inner(Margin {
area.inner(Margin {
horizontal: 1,
vertical: 1,
}),
Expand Down

0 comments on commit f1af005

Please sign in to comment.