diff --git a/src/buffer/buffers.rs b/src/buffer/buffers.rs index 16f6bb6..c74bab9 100644 --- a/src/buffer/buffers.rs +++ b/src/buffer/buffers.rs @@ -5,8 +5,10 @@ use crate::{ use std::{ collections::VecDeque, io::{self, ErrorKind}, + mem, path::Path, }; +use tracing::debug; const MAX_JUMPS: usize = 100; @@ -54,21 +56,68 @@ impl Buffers { return Ok(None); } + let id = self.next_id; + self.next_id += 1; + let mut b = Buffer::new_from_canonical_file_path(id, path)?; + // Remove an empty scratch buffer if the user has now opened a file if self.is_empty_scratch() { - self.inner.remove(0); + mem::swap(&mut self.inner[0], &mut b); } else { self.record_jump_position(); + self.push_buffer(b); } - let id = self.next_id; - self.next_id += 1; - let b = Buffer::new_from_canonical_file_path(id, path)?; - self.inner.insert(0, b); - Ok(Some(id)) } + pub fn next(&mut self) { + if !self.remove_head_buffer_if_virtual() { + self.inner.rotate_right(1); + } + } + + pub fn previous(&mut self) { + self.remove_head_buffer_if_virtual(); + self.inner.rotate_left(1) + } + + pub fn close_buffer(&mut self, id: BufferId) { + self.inner.retain(|b| b.id != id); + self.jump_list.clear_for_buffer(id); + + if self.inner.is_empty() { + self.inner.push_back(Buffer::new_unnamed(self.next_id, "")); + self.next_id += 1; + } + } + + /// The bool returned here denotes wether we removed the head buffer or not + fn remove_head_buffer_if_virtual(&mut self) -> bool { + let is_virtual = matches!(self.inner[0].kind, BufferKind::Virtual(_)); + if is_virtual { + debug!("removing virtual buffer"); + let prev = self + .inner + .remove(0) + .expect("always have at least one buffer"); + self.jump_list.clear_for_buffer(prev.id); + } + + is_virtual + } + + fn push_buffer(&mut self, buf: Buffer) { + self.remove_head_buffer_if_virtual(); + self.inner.push_front(buf); + } + + pub(crate) fn open_virtual(&mut self, name: String, content: String) { + let buf = Buffer::new_virtual(self.next_id, name, content); + self.push_buffer(buf); + self.next_id += 1; + } + /// Used to seed the buffer selection mini-buffer pub(crate) fn as_buf_list(&self) -> Vec { let focused = self.inner[0].id; @@ -124,6 +173,7 @@ impl Buffers { } fn jump(&mut self, bufid: BufferId, cur: Cur, screen_rows: usize, screen_cols: usize) { + self.remove_head_buffer_if_virtual(); if let Some(idx) = self.inner.iter().position(|b| b.id == bufid) { self.inner.swap(0, idx); self.inner[0].dot = cur.into(); @@ -153,24 +203,6 @@ impl Buffers { pub fn is_empty_scratch(&self) -> bool { self.inner.len() == 1 && self.inner[0].is_unnamed() && !self.inner[0].dirty } - - pub fn next(&mut self) { - self.inner.rotate_right(1) - } - - pub fn previous(&mut self) { - self.inner.rotate_left(1) - } - - pub fn close_buffer(&mut self, id: BufferId) { - self.inner.retain(|b| b.id != id); - self.jump_list.clear_for_buffer(id); - - if self.inner.is_empty() { - self.inner.push_back(Buffer::new_unnamed(self.next_id, "")); - self.next_id += 1; - } - } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index a777c8c..7d0ce5e 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -237,7 +237,10 @@ impl Buffer { } } - /// Create a new virtual buffer with the given name and content + /// Create a new virtual buffer with the given name and content. + /// + /// The buffer will not be included in the virtual filesystem and it will be removed when it + /// loses focus. pub fn new_virtual(id: usize, name: String, mut content: String) -> Self { if content.ends_with('\n') { content.pop(); @@ -359,7 +362,7 @@ impl Buffer { } pub(crate) fn debug_edit_log(&self) -> Vec { - self.edit_log.debug_edits(self).into_iter().collect() + self.edit_log.debug_edits(self) } /// Clamp the current viewport to include the [Dot]. diff --git a/src/editor/actions.rs b/src/editor/actions.rs index 26ade86..ab69ea0 100644 --- a/src/editor/actions.rs +++ b/src/editor/actions.rs @@ -388,15 +388,7 @@ impl Editor { } pub(super) fn view_logs(&mut self) { - MiniBuffer::select_from( - "+Log ", - self.log_buffer - .content() - .lines() - .map(|s| s.to_string()) - .collect(), - self, - ); + self.open_virtual("+logs", self.log_buffer.content()) } pub(super) fn debug_edit_log(&mut self) { diff --git a/src/editor/commands.rs b/src/editor/commands.rs index c2775b3..47a19ca 100644 --- a/src/editor/commands.rs +++ b/src/editor/commands.rs @@ -91,6 +91,8 @@ impl Editor { input: args.to_string(), })), + "vl" | "view-logs" => Some(Single(ViewLogs)), + "w" | "write" => { if args.is_empty() { Some(Single(SaveBuffer { force: false })) diff --git a/src/editor/mod.rs b/src/editor/mod.rs index d5ceef8..6b8fea7 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -201,6 +201,11 @@ impl Editor { } } + /// Open a new virtual buffer which will be removed from state when it loses focus. + pub(crate) fn open_virtual(&mut self, name: impl Into, content: impl Into) { + self.buffers.open_virtual(name.into(), content.into()); + } + fn send_buffer_resp( &self, id: usize,