Skip to content

Commit cf81ab7

Browse files
committed
reload histories if persistent_undo is dynamically enabled
1 parent 8a60b79 commit cf81ab7

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

helix-core/src/history.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl Default for History {
9696

9797
impl Revision {
9898
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
99+
// `timestamp` is ignored since `Instant`s can't be serialized.
99100
write_usize(writer, self.parent)?;
100101
self.transaction.serialize(writer)?;
101102
self.inversion.serialize(writer)?;
@@ -117,8 +118,7 @@ impl Revision {
117118
}
118119
}
119120

120-
// Temporarily 3 for review.
121-
const HEADER_TAG: &str = "Helix Undofile 4\n";
121+
const HEADER_TAG: &str = "Helix Undofile 1\n";
122122

123123
fn get_hash<R: Read>(reader: &mut R) -> std::io::Result<[u8; 20]> {
124124
const BUF_SIZE: usize = 8192;
@@ -144,6 +144,7 @@ impl History {
144144
revision: usize,
145145
last_saved_revision: usize,
146146
) -> std::io::Result<()> {
147+
// Header
147148
let mtime = std::fs::metadata(path)?
148149
.modified()?
149150
.duration_since(std::time::UNIX_EPOCH)
@@ -164,9 +165,14 @@ impl History {
164165
Ok(())
165166
}
166167

168+
/// Returns the deserialized [`History`] and the last_saved_revision.
167169
pub fn deserialize<R: Read>(reader: &mut R, path: &Path) -> std::io::Result<(usize, Self)> {
168170
let (current, last_saved_revision) = Self::read_header(reader, path)?;
171+
172+
// Since `timestamp` can't be serialized, a new timestamp is created.
169173
let timestamp = Instant::now();
174+
175+
// Read the revisions and construct the tree.
170176
let len = read_usize(reader)?;
171177
let mut revisions: Vec<Revision> = Vec::with_capacity(len);
172178
for _ in 0..len {
@@ -184,6 +190,16 @@ impl History {
184190
Ok((last_saved_revision, history))
185191
}
186192

193+
/// If two histories originate from: `A -> B (B is head)` but have deviated since then such that
194+
/// the first history is: `A -> B -> C -> D (D is head)` and the second one is:
195+
/// `A -> B -> E -> F (F is head)`.
196+
/// Then they are merged into
197+
/// ```
198+
/// A -> B -> C -> D
199+
/// \
200+
/// \ -> E -> F
201+
/// ```
202+
/// and retain their revision heads.
187203
pub fn merge(&mut self, mut other: History, offset: usize) -> std::io::Result<()> {
188204
let revisions = self.revisions.split_off(offset);
189205
let len = other.revisions.len();
@@ -823,6 +839,7 @@ mod test {
823839

824840
quickcheck!(
825841
fn serde_history(original: String, changes_a: Vec<String>, changes_b: Vec<String>) -> bool {
842+
// Constructs a set of transactions and applies them to the history.
826843
fn create_changes(history: &mut History, doc: &mut Rope, changes: Vec<String>) {
827844
for c in changes.into_iter().map(Rope::from) {
828845
let transaction = crate::diff::compare_ropes(doc, &c);
@@ -843,6 +860,8 @@ mod test {
843860
let file = tempfile::NamedTempFile::new().unwrap();
844861
history.serialize(&mut cursor, file.path(), 0, 0).unwrap();
845862
cursor.set_position(0);
863+
864+
// Check if the original and deserialized history match.
846865
let (_, res) = History::deserialize(&mut cursor, file.path()).unwrap();
847866
assert_eq!(history, res);
848867

@@ -854,6 +873,8 @@ mod test {
854873
.serialize(&mut cursor, file.path(), 0, last_saved_revision)
855874
.unwrap();
856875
cursor.set_position(0);
876+
877+
// Check if they are the same after appending new changes.
857878
let (_, res) = History::deserialize(&mut cursor, file.path()).unwrap();
858879
history == res
859880
}

helix-term/src/application.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,21 @@ impl Application {
385385
// the Application can apply it.
386386
ConfigEvent::Update(editor_config) => {
387387
let mut app_config = (*self.config.load().clone()).clone();
388+
if self.config.load().editor.persistent_undo == false
389+
&& editor_config.persistent_undo == true
390+
{
391+
for doc in self.editor.documents_mut() {
392+
// HAXX: Do this so all revisions in this doc are treated as new.
393+
doc.set_last_saved_revision(0);
394+
if let Err(e) = doc.load_history() {
395+
log::error!(
396+
"failed to reload history for {}: {e}",
397+
doc.path().unwrap().to_string_lossy()
398+
);
399+
return;
400+
}
401+
}
402+
}
388403
app_config.editor = *editor_config;
389404
self.config.store(Arc::new(app_config));
390405
}
@@ -439,6 +454,17 @@ impl Application {
439454
let mut refresh_config = || -> Result<(), Error> {
440455
let default_config = Config::load_default()
441456
.map_err(|err| anyhow::anyhow!("Failed to load config: {}", err))?;
457+
458+
// Merge histories of existing docs if persistent undo was enabled.
459+
if self.config.load().editor.persistent_undo == false
460+
&& default_config.editor.persistent_undo == true
461+
{
462+
for doc in self.editor.documents_mut() {
463+
// HAXX: Do this so all revisions in this doc are treated as new.
464+
doc.set_last_saved_revision(0);
465+
doc.load_history()?;
466+
}
467+
}
442468
self.refresh_language_config()?;
443469
self.refresh_theme(&default_config)?;
444470
// Store new config

helix-view/src/document.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,10 +1387,8 @@ impl Display for FormatterError {
13871387

13881388
#[cfg(test)]
13891389
mod test {
1390-
use arc_swap::{access::Map, ArcSwap};
1391-
use quickcheck::Gen;
1392-
13931390
use super::*;
1391+
use arc_swap::ArcSwap;
13941392

13951393
#[test]
13961394
fn changeset_to_changes_ignore_line_endings() {
@@ -1561,6 +1559,7 @@ mod test {
15611559
#[tokio::test(flavor = "multi_thread")]
15621560
async fn reload_history() {
15631561
let test_fn: fn(Vec<String>) -> bool = |changes| -> bool {
1562+
// Divide the vec into 3 sets of changes.
15641563
let len = changes.len() / 3;
15651564
let mut original = Rope::new();
15661565
let mut iter = changes.into_iter();
@@ -1623,7 +1622,6 @@ mod test {
16231622
for c in changes_b {
16241623
doc_1.apply(&c, view_id);
16251624
}
1626-
16271625
for c in changes_c {
16281626
doc_2.apply(&c, view_id);
16291627
}
@@ -1632,6 +1630,7 @@ mod test {
16321630
doc_1.load_history().unwrap();
16331631
doc_3.load_history().unwrap();
16341632

1633+
// doc_3 had no diverging edits, so they should be the same.
16351634
assert_eq!(doc_2.history.get_mut(), doc_3.history.get_mut());
16361635

16371636
helix_lsp::block_on(doc_1.save::<PathBuf>(None, true).unwrap()).unwrap();

0 commit comments

Comments
 (0)