pass AppAction back to app
This commit is contained in:
+12
-19
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user