diff --git a/Cargo.lock b/Cargo.lock index d2f906698..7f5eaa4cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1346,6 +1355,7 @@ name = "helix-loader" version = "24.7.0" dependencies = [ "anyhow", + "bincode", "cc", "dunce", "etcetera", diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index f74829f30..a589eae1b 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -24,6 +24,7 @@ etcetera = "0.8" tree-sitter.workspace = true once_cell = "1.19" log = "0.4" +bincode = "1.3.3" # TODO: these two should be on !wasm32 only diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 7707c76bc..12abd93b9 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -20,6 +20,8 @@ static COMMAND_HISTFILE: once_cell::sync::OnceCell = once_cell::sync::O static SEARCH_HISTFILE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); +static FILE_HISTFILE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); + pub fn initialize_config_file(specified_file: Option) { let config_file = specified_file.unwrap_or_else(default_config_file); ensure_parent_dir(&config_file); @@ -44,6 +46,12 @@ pub fn initialize_search_histfile(specified_file: Option) { SEARCH_HISTFILE.set(search_histfile).ok(); } +pub fn initialize_file_histfile(specified_file: Option) { + let file_histfile = specified_file.unwrap_or_else(default_file_histfile); + ensure_parent_dir(&file_histfile); + FILE_HISTFILE.set(file_histfile).ok(); +} + /// A list of runtime directories from highest to lowest priority /// /// The priority is: @@ -179,6 +187,10 @@ pub fn search_histfile() -> PathBuf { .unwrap() } +pub fn file_histfile() -> PathBuf { + FILE_HISTFILE.get().map(|path| path.to_path_buf()).unwrap() +} + pub fn workspace_config_file() -> PathBuf { find_workspace().0.join(".helix").join("config.toml") } @@ -199,6 +211,10 @@ pub fn default_search_histfile() -> PathBuf { state_dir().join("search_history") } +pub fn default_file_histfile() -> PathBuf { + state_dir().join("file_history") +} + /// Merge two TOML documents, merging values from `right` onto `left` /// /// When an array exists in both `left` and `right`, `right`'s array is diff --git a/helix-loader/src/session.rs b/helix-loader/src/session.rs index 63eb7ac8e..33b3814b9 100644 --- a/helix-loader/src/session.rs +++ b/helix-loader/src/session.rs @@ -1,10 +1,51 @@ -use crate::{command_histfile, search_histfile}; +use crate::{command_histfile, file_histfile, search_histfile}; +use bincode::serialize_into; +use serde::{Deserialize, Serialize}; use std::{ fs::{File, OpenOptions}, io::{self, BufRead, BufReader, Write}, path::PathBuf, }; +// TODO: should this contain a ViewPosition? +// it would require exposing that type in a new crate, re-exporting in helix-view, +// since this crate is a dependency of helix-view +#[derive(Debug, Serialize, Deserialize)] +pub struct FileHistoryEntry { + path: PathBuf, + anchor: usize, + vertical_offset: usize, + horizontal_offset: usize, +} + +impl FileHistoryEntry { + pub fn new( + path: PathBuf, + anchor: usize, + vertical_offset: usize, + horizontal_offset: usize, + ) -> Self { + Self { + path, + anchor, + vertical_offset, + horizontal_offset, + } + } +} + +pub fn push_file_history(entry: FileHistoryEntry) { + let file = OpenOptions::new() + .append(true) + .create(true) + .open(file_histfile()) + // TODO: do something about this unwrap + .unwrap(); + + // TODO: do something about this unwrap + serialize_into(file, &entry).unwrap(); +} + pub fn push_history(register: char, line: &str) { let filepath = match register { ':' => command_histfile(), diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index c6f11b8d0..02df55c7a 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -82,6 +82,7 @@ FLAGS: helix_loader::initialize_log_file(args.log_file.clone()); helix_loader::initialize_command_histfile(None); helix_loader::initialize_search_histfile(None); + helix_loader::initialize_file_histfile(None); // Help has a higher priority and should be handled separately. if args.display_help { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1708b3b4e..3c8e8edaa 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -13,6 +13,7 @@ use crate::{ Document, DocumentId, View, ViewId, }; use dap::StackFrame; +use helix_loader::session::{push_file_history, FileHistoryEntry}; use helix_vcs::DiffProviderRegistry; use futures_util::stream::select_all::SelectAll; @@ -1725,6 +1726,18 @@ impl Editor { } pub fn close(&mut self, id: ViewId) { + let view = self.tree.get(id); + // TODO: do something about this unwrap + let doc = self.document(view.doc).unwrap(); + if let Some(path) = doc.path() { + push_file_history(FileHistoryEntry::new( + path.to_owned(), + view.offset.anchor, + view.offset.vertical_offset, + view.offset.horizontal_offset, + )); + }; + // Remove selections for the closed view on all documents. for doc in self.documents_mut() { doc.remove_view(id);