1use crate::{
3 config::Config,
4 editor::{Click, EditorMode, MiniBufferState},
5 input::Event,
6 key::Input,
7 term::CurShape,
8};
9use std::{
10 fmt,
11 sync::{Arc, RwLock, mpsc::Sender},
12};
13
14mod layout;
15mod tui;
16
17pub use layout::{Border, Layout, SCRATCH_ID};
18pub use tui::{GenericTui, Tui};
19
20pub trait UserInterface {
22 fn init(&mut self, tx: Sender<Event>) -> (usize, usize);
26
27 fn shutdown(&mut self);
29
30 fn state_change(&mut self, change: StateChange);
32
33 fn refresh(
35 &mut self,
36 mode_name: &str,
37 layout: &mut Layout,
38 n_running: usize,
39 pending_keys: &[Input],
40 held_click: Option<&Click>,
41 mb: Option<MiniBufferState<'_>>,
42 );
43
44 fn set_cursor_shape(&mut self, cur_shape: CurShape);
46}
47
48#[derive(Debug, Clone)]
54pub enum StateChange {
55 ConfigUpdated,
70 StatusMessage { msg: String },
74}
75
76#[allow(clippy::large_enum_variant)]
77pub(crate) enum Ui {
78 Headless,
79 Tui(Tui),
80 Boxed(Box<dyn UserInterface>),
81}
82
83impl fmt::Debug for Ui {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 Self::Headless => f.debug_struct("Ui::Headless").finish(),
87 Self::Tui(_) => f.debug_struct("Ui::Tui").finish(),
88 Self::Boxed(_) => f.debug_struct("Ui::Boxed").finish(),
89 }
90 }
91}
92
93impl Ui {
94 pub(crate) fn new(mode: EditorMode, config: Arc<RwLock<Config>>) -> Self {
95 match mode {
96 EditorMode::Headless => Self::Headless,
97 EditorMode::Terminal => Self::Tui(Tui::new(config)),
98 EditorMode::Boxed(ui) => Self::Boxed(ui),
99 }
100 }
101}
102
103impl UserInterface for Ui {
104 fn init(&mut self, tx: Sender<Event>) -> (usize, usize) {
105 match self {
106 Self::Headless => (60, 80),
107 Self::Tui(tui) => tui.init(tx),
108 Self::Boxed(ui) => ui.init(tx),
109 }
110 }
111
112 fn shutdown(&mut self) {
113 match self {
114 Self::Headless => (),
115 Self::Tui(tui) => tui.shutdown(),
116 Self::Boxed(ui) => ui.shutdown(),
117 }
118 }
119
120 fn state_change(&mut self, change: StateChange) {
121 match self {
122 Self::Headless => (),
123 Self::Tui(tui) => tui.state_change(change),
124 Self::Boxed(ui) => ui.state_change(change),
125 }
126 }
127
128 fn refresh(
129 &mut self,
130 mode_name: &str,
131 layout: &mut Layout,
132 n_running: usize,
133 pending_keys: &[Input],
134 held_click: Option<&Click>,
135 mb: Option<MiniBufferState<'_>>,
136 ) {
137 match self {
138 Self::Headless => (),
139 Self::Tui(tui) => {
140 tui.refresh(mode_name, layout, n_running, pending_keys, held_click, mb)
141 }
142 Self::Boxed(ui) => {
143 ui.refresh(mode_name, layout, n_running, pending_keys, held_click, mb)
144 }
145 }
146 }
147
148 fn set_cursor_shape(&mut self, cur_shape: CurShape) {
149 match self {
150 Self::Headless => (),
151 Self::Tui(tui) => tui.set_cursor_shape(cur_shape),
152 Self::Boxed(ui) => ui.set_cursor_shape(cur_shape),
153 }
154 }
155}