killing buffers

This commit is contained in:
filipriec
2025-05-25 22:02:18 +02:00
parent 6e1997fd9d
commit d8f9372bbd
3 changed files with 42 additions and 28 deletions

View File

@@ -4,6 +4,7 @@
enter_command_mode = [":", "ctrl+;"]
next_buffer = ["ctrl+l"]
previous_buffer = ["ctrl+h"]
close_buffer = ["ctrl+k"]
[keybindings.general]
move_up = ["k", "Up"]

View File

@@ -161,6 +161,7 @@ impl EventHandler {
return Ok(EventOutcome::Ok(message));
}
if !matches!(current_mode, AppMode::Edit | AppMode::Command) {
if let Some(action) = config.get_action_for_key_in_mode(
&config.keybindings.global, key_code, modifiers
@@ -176,6 +177,10 @@ impl EventHandler {
return Ok(EventOutcome::Ok("Switched to previous buffer".to_string()));
}
}
"close_buffer" => {
let message = buffer_state.close_buffer_with_intro_fallback();
return Ok(EventOutcome::Ok(message));
}
_ => {}
}
}

View File

@@ -1,6 +1,5 @@
// src/state/app/buffer.rs
/// Represents the distinct views or "buffers" the user can navigate.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AppView {
Intro,
@@ -14,7 +13,6 @@ pub enum AppView {
}
impl AppView {
/// Returns the display name for the view.
pub fn display_name(&self) -> &str {
match self {
AppView::Intro => "Intro",
@@ -29,7 +27,6 @@ impl AppView {
}
}
/// Holds the state related to buffer management (navigation history).
#[derive(Debug, Clone)]
pub struct BufferState {
pub history: Vec<AppView>,
@@ -39,23 +36,17 @@ pub struct BufferState {
impl Default for BufferState {
fn default() -> Self {
Self {
history: vec![AppView::Intro], // Start with Intro view
history: vec![AppView::Intro],
active_index: 0,
}
}
}
impl BufferState {
/// Updates the buffer history and active index.
/// If the view already exists, it sets it as active.
/// Otherwise, it adds the new view and makes it active.
pub fn update_history(&mut self, view: AppView) {
let existing_pos = self.history.iter().position(|v| v == &view);
match existing_pos {
Some(pos) => {
self.active_index = pos;
}
Some(pos) => self.active_index = pos,
None => {
self.history.push(view.clone());
self.active_index = self.history.len() - 1;
@@ -63,34 +54,51 @@ impl BufferState {
}
}
/// Gets the currently active view.
pub fn get_active_view(&self) -> Option<&AppView> {
self.history.get(self.active_index)
}
/// Removes the currently active buffer from the history, unless it's the Intro buffer.
/// Sets the new active buffer to the one preceding the closed one.
/// # Returns
/// * `true` if a non-Intro buffer was closed.
/// * `false` if the active buffer was Intro or only Intro remained.
pub fn close_active_buffer(&mut self) -> bool {
let current_index = self.active_index;
if self.history.is_empty() {
self.history.push(AppView::Intro);
self.active_index = 0;
return false;
}
// Rule 1: Cannot close Intro buffer.
let current_index = self.active_index;
if matches!(self.history.get(current_index), Some(AppView::Intro)) {
return false;
}
// Rule 2: Cannot close if only Intro would remain (or already remains).
// This check implicitly covers the case where len <= 1.
if self.history.len() <= 1 {
return false;
}
self.history.remove(current_index);
self.active_index = current_index.saturating_sub(1).min(self.history.len() - 1);
if self.history.is_empty() {
self.history.push(AppView::Intro);
self.active_index = 0;
} else if self.active_index >= self.history.len() {
self.active_index = self.history.len() - 1;
}
true
}
}
pub fn close_buffer_with_intro_fallback(&mut self) -> String {
let current_view_cloned = self.get_active_view().cloned();
if let Some(AppView::Intro) = current_view_cloned {
return "Cannot close intro buffer".to_string();
}
let closed_name = current_view_cloned
.as_ref()
.map(|v| v.display_name().to_string())
.unwrap_or_else(|| "Unknown".to_string());
if self.close_active_buffer() {
if self.history.len() == 1 && matches!(self.history.get(0), Some(AppView::Intro)) {
format!("Closed '{}' - returned to intro", closed_name)
} else {
format!("Closed '{}'", closed_name)
}
} else {
format!("Cannot close buffer: {}", closed_name)
}
}
}