lingora-tui 0.4.9

Lingora is a free and open-source localization management program that analyses fluent translation files highlighting discrepancies between reference and target languages. This application provides a terminal user interface; run as `lingora-tui`.
Documentation
use crossterm::event::{Event, KeyCode, KeyEvent};
use fluent4rs::ast::Entry;
use rat_event::{HandleEvent, Outcome, Regular};
use rat_focus::{FocusBuilder, FocusFlag, HasFocus};
use ratatui::{prelude::*, widgets::*};

use crate::theme::LingoraTheme;

#[derive(Debug, Default)]
pub struct EntriesState {
    focus_flag: FocusFlag,
    list_state: ListState,
    area: Rect,
}

impl EntriesState {
    fn handle_key_event(&mut self, event: &KeyEvent) -> Outcome {
        match &event.code {
            KeyCode::Up => {
                self.list_state.select_previous();
                Outcome::Unchanged
            }
            KeyCode::Down => {
                self.list_state.select_next();
                Outcome::Unchanged
            }
            _ => Outcome::Continue,
        }
    }
}

impl HasFocus for EntriesState {
    fn build(&self, builder: &mut FocusBuilder) {
        builder.leaf_widget(self);
    }

    fn focus(&self) -> FocusFlag {
        self.focus_flag.clone()
    }

    fn area(&self) -> Rect {
        self.area
    }
}

impl HandleEvent<Event, Regular, Outcome> for EntriesState {
    fn handle(&mut self, event: &Event, _qualifier: Regular) -> Outcome {
        if self.focus_flag.is_focused() {
            match event {
                Event::Key(event) => self.handle_key_event(event),
                _ => Outcome::Continue,
            }
        } else {
            Outcome::Continue
        }
    }
}

pub struct Entries<'a> {
    theme: &'a LingoraTheme,
    entries: Vec<Entry>,
}

impl<'a> Entries<'a> {
    pub fn new(theme: &'a LingoraTheme, entries: impl Iterator<Item = &'a Entry>) -> Self {
        let entries = Vec::from_iter(entries.cloned());
        Self { theme, entries }
    }
}

impl StatefulWidget for &Entries<'_> {
    type State = EntriesState;

    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
    where
        Self: Sized,
    {
        state.area = area;

        let list = List::new(self.entries.iter().map(|e| Text::from(e.to_string())))
            .block(self.theme.focus_block(&state.focus_flag))
            .highlight_style(self.theme.selection())
            .highlight_symbol("ยป ")
            .highlight_spacing(HighlightSpacing::Always);

        StatefulWidget::render(list, area, buf, &mut state.list_state);
    }
}