use crate::{
config::Config,
editor::{Click, EditorMode, MiniBufferState},
input::Event,
key::Input,
term::CurShape,
};
use std::{
fmt,
sync::{Arc, RwLock, mpsc::Sender},
};
mod layout;
mod tui;
pub use layout::{Border, Layout, SCRATCH_ID};
pub use tui::{GenericTui, Tui};
pub trait UserInterface {
fn init(&mut self, tx: Sender<Event>) -> (usize, usize);
fn shutdown(&mut self);
fn state_change(&mut self, change: StateChange);
fn refresh(
&mut self,
mode_name: &str,
layout: &mut Layout,
n_running: usize,
pending_keys: &[Input],
held_click: Option<&Click>,
mb: Option<MiniBufferState<'_>>,
);
fn set_cursor_shape(&mut self, cur_shape: CurShape);
}
#[derive(Debug, Clone)]
pub enum StateChange {
ConfigUpdated,
StatusMessage { msg: String },
}
#[allow(clippy::large_enum_variant)]
pub(crate) enum Ui {
Headless,
Tui(Tui),
Boxed(Box<dyn UserInterface>),
}
impl fmt::Debug for Ui {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Headless => f.debug_struct("Ui::Headless").finish(),
Self::Tui(_) => f.debug_struct("Ui::Tui").finish(),
Self::Boxed(_) => f.debug_struct("Ui::Boxed").finish(),
}
}
}
impl Ui {
pub(crate) fn new(mode: EditorMode, config: Arc<RwLock<Config>>) -> Self {
match mode {
EditorMode::Headless => Self::Headless,
EditorMode::Terminal => Self::Tui(Tui::new(config)),
EditorMode::Boxed(ui) => Self::Boxed(ui),
}
}
}
impl UserInterface for Ui {
fn init(&mut self, tx: Sender<Event>) -> (usize, usize) {
match self {
Self::Headless => (60, 80),
Self::Tui(tui) => tui.init(tx),
Self::Boxed(ui) => ui.init(tx),
}
}
fn shutdown(&mut self) {
match self {
Self::Headless => (),
Self::Tui(tui) => tui.shutdown(),
Self::Boxed(ui) => ui.shutdown(),
}
}
fn state_change(&mut self, change: StateChange) {
match self {
Self::Headless => (),
Self::Tui(tui) => tui.state_change(change),
Self::Boxed(ui) => ui.state_change(change),
}
}
fn refresh(
&mut self,
mode_name: &str,
layout: &mut Layout,
n_running: usize,
pending_keys: &[Input],
held_click: Option<&Click>,
mb: Option<MiniBufferState<'_>>,
) {
match self {
Self::Headless => (),
Self::Tui(tui) => {
tui.refresh(mode_name, layout, n_running, pending_keys, held_click, mb)
}
Self::Boxed(ui) => {
ui.refresh(mode_name, layout, n_running, pending_keys, held_click, mb)
}
}
}
fn set_cursor_shape(&mut self, cur_shape: CurShape) {
match self {
Self::Headless => (),
Self::Tui(tui) => tui.set_cursor_shape(cur_shape),
Self::Boxed(ui) => ui.set_cursor_shape(cur_shape),
}
}
}