diff --git a/examples/demo.rs b/examples/demo.rs index ad1f808a..867d58b1 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -16,7 +16,7 @@ use { #[cfg(not(any(feature = "sqlite", feature = "sqlite-dynlib")))] use reedline::FileBackedHistory; -use reedline::{CursorConfig, MenuBuilder}; +use reedline::{CursorConfig, HistoryItemId, MenuBuilder}; fn main() -> reedline::Result<()> { println!("Ctrl-D to quit"); @@ -175,6 +175,18 @@ fn main() -> reedline::Result<()> { line_editor.print_history_session()?; continue; } + // Delete history entry of a certain id + if buffer.trim().starts_with("history remove-item") { + let parts: Vec<&str> = buffer.split_whitespace().collect(); + if parts.len() == 3 { + if let Ok(id) = parts[2].parse::() { + line_editor.history_mut().delete(HistoryItemId::new(id))?; + continue; + } + } + println!("Invalid command. Use: history remove-item "); + continue; + } // Get this history session identifier if buffer.trim() == "history sessionid" { line_editor.print_history_session_id()?; diff --git a/src/engine.rs b/src/engine.rs index e7bcceb7..dd2a12fb 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -536,8 +536,9 @@ impl Reedline { .search(SearchQuery::everything(SearchDirection::Forward, None)) .expect("todo: error handling"); - for (i, entry) in history.iter().enumerate() { - self.print_line(&format!("{}\t{}", i, entry.command_line))?; + for entry in history.iter() { + let Some(id) = entry.id else { continue }; + self.print_line(&format!("{}\t{}", id, entry.command_line))?; } Ok(()) } diff --git a/src/history/file_backed.rs b/src/history/file_backed.rs index ffff840b..239e4371 100644 --- a/src/history/file_backed.rs +++ b/src/history/file_backed.rs @@ -31,6 +31,7 @@ pub struct FileBackedHistory { file: Option, len_on_disk: usize, // Keep track what was previously written to disk session: Option, + overwrite: bool, // Will overwrite file on next sync, not just new entries } impl Default for FileBackedHistory { @@ -205,23 +206,30 @@ impl History for FileBackedHistory { Ok(()) } - fn delete(&mut self, _h: super::HistoryItemId) -> Result<()> { - Err(ReedlineError( - ReedlineErrorVariants::HistoryFeatureUnsupported { - history: "FileBackedHistory", - feature: "removing entries", - }, - )) + fn delete(&mut self, h: super::HistoryItemId) -> Result<()> { + let id = h.0 as usize; + let num_entries = self.entries.len(); + // Check if the id is valid + if id >= num_entries { + return Err(ReedlineError(ReedlineErrorVariants::OtherHistoryError( + "Given id is out of range.", + ))); + } + + // Remove the item with the specified id + self.entries.remove(id); + self.overwrite = true; + + Ok(()) } - /// Writes unwritten history contents to disk. + /// Syncs current state with disk. /// + /// Normally, that means reading entries from the file and appending new entries to it. /// If file would exceed `capacity` truncates the oldest entries. + /// If necessary, the whole file is overwritten. fn sync(&mut self) -> std::io::Result<()> { if let Some(fname) = &self.file { - // The unwritten entries - let own_entries = self.entries.range(self.len_on_disk..); - if let Some(base_dir) = fname.parent() { std::fs::create_dir_all(base_dir)?; } @@ -231,14 +239,39 @@ impl History for FileBackedHistory { .create(true) .write(true) .read(true) + .truncate(self.overwrite) .open(fname)?, ); let mut writer_guard = f_lock.write()?; + + if self.overwrite { + self.overwrite = false; + let mut writer = BufWriter::new(writer_guard.deref_mut()); + for line in &self.entries { + writer.write_all(encode_entry(line).as_bytes())?; + writer.write_all("\n".as_bytes())?; + } + writer.flush()?; + return Ok(()); + } + + // The unwritten entries + let own_entries = self.entries.range(self.len_on_disk..); + let (mut foreign_entries, truncate) = { let reader = BufReader::new(writer_guard.deref()); let mut from_file = reader .lines() .map(|o| o.map(|i| decode_entry(&i))) + .filter(|e| { + if let Ok(entry) = e { + if entry.starts_with(' ') { + self.overwrite = true; + return false; + } + } + true + }) .collect::>>()?; if from_file.len() + own_entries.len() > self.capacity { ( @@ -306,6 +339,7 @@ impl FileBackedHistory { file: None, len_on_disk: 0, session: None, + overwrite: false, }) }