pass AppAction back to app

This commit is contained in:
alice pellerin
2026-03-19 03:38:19 -05:00
parent 0f11fb9273
commit 4f61f2fb93
5 changed files with 63 additions and 58 deletions
+12 -19
View File
@@ -1,11 +1,10 @@
use std::{cmp::min, fs::File, io::Write, mem::{replace, swap}}; use std::{cmp::min, fs::File, io::Write, mem::{replace, swap}};
use ratatui::{style::Stylize, text::Span};
use crate::{BYTES_PER_LINE, app::WindowSize, buffer::{Buffer, Mode, PartialAction}, edit_action::EditAction}; use crate::{BYTES_PER_LINE, app::WindowSize, buffer::{Buffer, Mode, PartialAction}, edit_action::EditAction};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Action { pub enum Action {
CloseIfSaved, QuitIfSaved,
Close, Quit,
NormalMode, NormalMode,
SelectMode, SelectMode,
@@ -60,11 +59,17 @@ pub enum Action {
Save, Save,
} }
// actions that act on the app as a whole, not just one buffer
pub enum AppAction {
QuitIfSaved,
Quit,
}
impl Buffer { impl Buffer {
pub fn execute(&mut self, action: Action, window_size: WindowSize) { pub fn execute(&mut self, action: Action, window_size: WindowSize) -> Option<AppAction> {
match action { match action {
Action::CloseIfSaved => self.close_if_saved(), Action::QuitIfSaved => return Some(AppAction::QuitIfSaved),
Action::Close => self.close(), Action::Quit => return Some(AppAction::Quit),
Action::NormalMode => self.normal_mode(), Action::NormalMode => self.normal_mode(),
Action::SelectMode => self.select_mode(), Action::SelectMode => self.select_mode(),
@@ -118,20 +123,8 @@ impl Buffer {
Action::Save => self.save(), Action::Save => self.save(),
} }
}
fn close_if_saved(&mut self) { None
if self.all_changes_saved() {
self.close();
} else {
self.alert_message = Span::from(
"there are unsaved changes, use Q to override"
).red();
}
}
const fn close(&mut self) {
self.should_close = true;
} }
const fn normal_mode(&mut self) { const fn normal_mode(&mut self) {
+27 -15
View File
@@ -1,6 +1,7 @@
use std::{cmp::min, env, process::exit}; use std::{env, process::exit};
use crossterm::{event::{self, Event, KeyEvent}, terminal::window_size}; use crossterm::{event::{self, Event, KeyEvent}, terminal::window_size};
use crate::{BYTES_PER_LINE, buffer::Buffer, config::Config}; use ratatui::{style::Stylize, text::Span};
use crate::{BYTES_PER_LINE, action::AppAction, buffer::Buffer, config::Config};
mod widget; mod widget;
@@ -70,24 +71,35 @@ impl App {
} }
fn handle_key(&mut self, key_event: KeyEvent) { fn handle_key(&mut self, key_event: KeyEvent) {
self.buffers[self.current_buffer_index] let maybe_app_action = self.buffers[self.current_buffer_index].handle_key(
.handle_key(key_event, &self.config, self.window_size); key_event,
&self.config,
self.window_size
);
if self.current_buffer().should_close { if let Some(app_action) = maybe_app_action {
self.buffers.remove(self.current_buffer_index); match app_action {
AppAction::QuitIfSaved => self.quit_if_saved(),
if self.buffers.is_empty() { AppAction::Quit => self.quit(),
self.should_quit = true;
} else {
self.current_buffer_index = min(
self.current_buffer_index,
self.buffers.len() - 1
);
} }
} }
} }
fn current_buffer(&self) -> &Buffer { fn quit_if_saved(&mut self) {
if self.buffers.iter().all(Buffer::all_changes_saved) {
self.quit();
} else {
self.buffers[self.current_buffer_index].alert_message = Span::from(
"there are unsaved changes, use Q to override"
).red();
}
}
const fn quit(&mut self) {
self.should_quit = true;
}
pub fn current_buffer(&self) -> &Buffer {
&self.buffers[self.current_buffer_index] &self.buffers[self.current_buffer_index]
} }
} }
+12 -12
View File
@@ -20,18 +20,18 @@ impl App {
self.buffers self.buffers
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, buffer)| self.tab_for(buffer, index == self.current_buffer_index)) .map(|(index, buffer)| tab_for(buffer, index == self.current_buffer_index))
.collect() .collect()
} }
}
fn tab_for(&self, buffer: &Buffer, is_active: bool) -> Span<'static> {
let background = if is_active { fn tab_for(buffer: &Buffer, is_active: bool) -> Span<'static> {
Color::select_grey() let background = if is_active {
} else { Color::select_grey()
Color::ui_grey() } else {
}; Color::ui_grey()
};
Span::from(format!(" {} ", buffer.file_name))
.bg(background) Span::from(format!(" {} ", buffer.file_name))
} .bg(background)
} }
+7 -7
View File
@@ -1,7 +1,7 @@
use std::{fs::File, io::Read, path::PathBuf}; use std::{fs::File, io::Read, path::PathBuf};
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use ratatui::{style::Color, text::Span}; use ratatui::{style::Color, text::Span};
use crate::{app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction}; use crate::{action::AppAction, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
mod widget; mod widget;
@@ -25,8 +25,6 @@ pub struct Buffer {
pub time_traveling: Option<usize>, pub time_traveling: Option<usize>,
// the index *after* the last saved edit action // the index *after* the last saved edit action
pub last_saved_at: Option<usize>, pub last_saved_at: Option<usize>,
pub should_close: bool,
} }
#[derive(Clone, Copy, Hash, PartialEq, Eq)] #[derive(Clone, Copy, Hash, PartialEq, Eq)]
@@ -92,8 +90,6 @@ impl Buffer {
edit_history: Vec::new(), edit_history: Vec::new(),
time_traveling: None, time_traveling: None,
last_saved_at: Some(0), last_saved_at: Some(0),
should_close: false,
} }
} }
@@ -102,9 +98,11 @@ impl Buffer {
event: KeyEvent, event: KeyEvent,
config: &Config, config: &Config,
window_size: WindowSize window_size: WindowSize
) { ) -> Option<AppAction> {
self.alert_message = "".into(); self.alert_message = "".into();
let mut app_action = None;
if self.partial_action == Some(PartialAction::Replace) { if self.partial_action == Some(PartialAction::Replace) {
if let Some(hex_character) = event.code.as_char() && if let Some(hex_character) = event.code.as_char() &&
let Some(nybble) = nybble_from_hex(hex_character) let Some(nybble) = nybble_from_hex(hex_character)
@@ -132,13 +130,15 @@ impl Buffer {
let Some(keybinds) = mode_config.0.get(&self.partial_action) && let Some(keybinds) = mode_config.0.get(&self.partial_action) &&
let Some(action) = keybinds.0.get(&event.into()) let Some(action) = keybinds.0.get(&event.into())
{ {
self.execute(*action, window_size); app_action = self.execute(*action, window_size);
} }
if should_reset_partial { if should_reset_partial {
self.partial_action = None; self.partial_action = None;
} }
} }
app_action
} }
pub const fn has_unsaved_changes(&self) -> bool { pub const fn has_unsaved_changes(&self) -> bool {
+4 -4
View File
@@ -99,8 +99,8 @@ impl Default for Config {
[ [
(Mode::Normal, [ (Mode::Normal, [
(None, [ (None, [
("q".try_into().unwrap(), Action::CloseIfSaved), ("q".try_into().unwrap(), Action::QuitIfSaved),
("Q".try_into().unwrap(), Action::Close), ("Q".try_into().unwrap(), Action::Quit),
("v".try_into().unwrap(), Action::SelectMode), ("v".try_into().unwrap(), Action::SelectMode),
@@ -151,8 +151,8 @@ impl Default for Config {
].into()), ].into()),
(Mode::Select, [ (Mode::Select, [
(None, [ (None, [
("q".try_into().unwrap(), Action::CloseIfSaved), ("q".try_into().unwrap(), Action::QuitIfSaved),
("Q".try_into().unwrap(), Action::Close), ("Q".try_into().unwrap(), Action::Quit),
("v".try_into().unwrap(), Action::NormalMode), ("v".try_into().unwrap(), Action::NormalMode),