aboutsummaryrefslogtreecommitdiff
path: root/helix-vcs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-vcs')
-rw-r--r--helix-vcs/src/diff.rs58
-rw-r--r--helix-vcs/src/diff/line_cache.rs8
-rw-r--r--helix-vcs/src/diff/worker.rs15
-rw-r--r--helix-vcs/src/diff/worker/test.rs6
4 files changed, 62 insertions, 25 deletions
diff --git a/helix-vcs/src/diff.rs b/helix-vcs/src/diff.rs
index 9c6a362f..ca33dda4 100644
--- a/helix-vcs/src/diff.rs
+++ b/helix-vcs/src/diff.rs
@@ -28,11 +28,18 @@ struct Event {
render_lock: Option<RenderLock>,
}
+#[derive(Clone, Debug, Default)]
+struct DiffInner {
+ diff_base: Rope,
+ doc: Rope,
+ hunks: Vec<Hunk>,
+}
+
#[derive(Clone, Debug)]
pub struct DiffHandle {
channel: UnboundedSender<Event>,
render_lock: Arc<RwLock<()>>,
- hunks: Arc<Mutex<Vec<Hunk>>>,
+ diff: Arc<Mutex<DiffInner>>,
inverted: bool,
}
@@ -47,10 +54,10 @@ impl DiffHandle {
redraw_handle: RedrawHandle,
) -> (DiffHandle, JoinHandle<()>) {
let (sender, receiver) = unbounded_channel();
- let hunks: Arc<Mutex<Vec<Hunk>>> = Arc::default();
+ let diff: Arc<Mutex<DiffInner>> = Arc::default();
let worker = DiffWorker {
channel: receiver,
- hunks: hunks.clone(),
+ diff: diff.clone(),
new_hunks: Vec::default(),
redraw_notify: redraw_handle.0,
diff_finished_notify: Arc::default(),
@@ -58,7 +65,7 @@ impl DiffHandle {
let handle = tokio::spawn(worker.run(diff_base, doc));
let differ = DiffHandle {
channel: sender,
- hunks,
+ diff,
inverted: false,
render_lock: redraw_handle.1,
};
@@ -69,9 +76,9 @@ impl DiffHandle {
self.inverted = !self.inverted;
}
- pub fn hunks(&self) -> FileHunks {
- FileHunks {
- hunks: self.hunks.lock(),
+ pub fn load(&self) -> Diff {
+ Diff {
+ diff: self.diff.lock(),
inverted: self.inverted,
}
}
@@ -168,12 +175,28 @@ impl Hunk {
/// A list of changes in a file sorted in ascending
/// non-overlapping order
#[derive(Debug)]
-pub struct FileHunks<'a> {
- hunks: MutexGuard<'a, Vec<Hunk>>,
+pub struct Diff<'a> {
+ diff: MutexGuard<'a, DiffInner>,
inverted: bool,
}
-impl FileHunks<'_> {
+impl Diff<'_> {
+ pub fn diff_base(&self) -> &Rope {
+ if self.inverted {
+ &self.diff.doc
+ } else {
+ &self.diff.diff_base
+ }
+ }
+
+ pub fn doc(&self) -> &Rope {
+ if self.inverted {
+ &self.diff.diff_base
+ } else {
+ &self.diff.doc
+ }
+ }
+
pub fn is_inverted(&self) -> bool {
self.inverted
}
@@ -181,7 +204,7 @@ impl FileHunks<'_> {
/// Returns the `Hunk` for the `n`th change in this file.
/// if there is no `n`th change `Hunk::NONE` is returned instead.
pub fn nth_hunk(&self, n: u32) -> Hunk {
- match self.hunks.get(n as usize) {
+ match self.diff.hunks.get(n as usize) {
Some(hunk) if self.inverted => hunk.invert(),
Some(hunk) => hunk.clone(),
None => Hunk::NONE,
@@ -189,7 +212,7 @@ impl FileHunks<'_> {
}
pub fn len(&self) -> u32 {
- self.hunks.len() as u32
+ self.diff.hunks.len() as u32
}
pub fn is_empty(&self) -> bool {
@@ -204,19 +227,20 @@ impl FileHunks<'_> {
};
let res = self
+ .diff
.hunks
.binary_search_by_key(&line, |hunk| hunk_range(hunk).start);
match res {
// Search found a hunk that starts exactly at this line, return the next hunk if it exists.
- Ok(pos) if pos + 1 == self.hunks.len() => None,
+ Ok(pos) if pos + 1 == self.diff.hunks.len() => None,
Ok(pos) => Some(pos as u32 + 1),
// No hunk starts exactly at this line, so the search returns
// the position where a hunk starting at this line should be inserted.
// That position is exactly the position of the next hunk or the end
// of the list if no such hunk exists
- Err(pos) if pos == self.hunks.len() => None,
+ Err(pos) if pos == self.diff.hunks.len() => None,
Err(pos) => Some(pos as u32),
}
}
@@ -228,6 +252,7 @@ impl FileHunks<'_> {
|hunk: &Hunk| hunk.after.clone()
};
let res = self
+ .diff
.hunks
.binary_search_by_key(&line, |hunk| hunk_range(hunk).end);
@@ -237,7 +262,7 @@ impl FileHunks<'_> {
// which represents a pure removal.
// Removals are technically empty but are still shown as single line hunks
// and as such we must jump to the previous hunk (if it exists) if we are already inside the removal
- Ok(pos) if !hunk_range(&self.hunks[pos]).is_empty() => Some(pos as u32),
+ Ok(pos) if !hunk_range(&self.diff.hunks[pos]).is_empty() => Some(pos as u32),
// No hunk ends exactly at this line, so the search returns
// the position where a hunk ending at this line should be inserted.
@@ -255,6 +280,7 @@ impl FileHunks<'_> {
};
let res = self
+ .diff
.hunks
.binary_search_by_key(&line, |hunk| hunk_range(hunk).start);
@@ -267,7 +293,7 @@ impl FileHunks<'_> {
// The previous hunk contains this hunk if it exists and doesn't end before this line
Err(0) => None,
Err(pos) => {
- let hunk = hunk_range(&self.hunks[pos - 1]);
+ let hunk = hunk_range(&self.diff.hunks[pos - 1]);
if hunk.end > line || include_removal && hunk.start == line && hunk.is_empty() {
Some(pos as u32 - 1)
} else {
diff --git a/helix-vcs/src/diff/line_cache.rs b/helix-vcs/src/diff/line_cache.rs
index c3ee5daa..8e48250f 100644
--- a/helix-vcs/src/diff/line_cache.rs
+++ b/helix-vcs/src/diff/line_cache.rs
@@ -43,6 +43,14 @@ impl InternedRopeLines {
res
}
+ pub fn doc(&self) -> Rope {
+ self.doc.clone()
+ }
+
+ pub fn diff_base(&self) -> Rope {
+ self.diff_base.clone()
+ }
+
/// Updates the `diff_base` and optionally the document if `doc` is not None
pub fn update_diff_base(&mut self, diff_base: Rope, doc: Option<Rope>) {
self.interned.clear();
diff --git a/helix-vcs/src/diff/worker.rs b/helix-vcs/src/diff/worker.rs
index f4bb4dbf..5406446f 100644
--- a/helix-vcs/src/diff/worker.rs
+++ b/helix-vcs/src/diff/worker.rs
@@ -10,7 +10,7 @@ use tokio::sync::Notify;
use tokio::time::{timeout, timeout_at, Duration};
use crate::diff::{
- Event, RenderLock, ALGORITHM, DIFF_DEBOUNCE_TIME_ASYNC, DIFF_DEBOUNCE_TIME_SYNC,
+ DiffInner, Event, RenderLock, ALGORITHM, DIFF_DEBOUNCE_TIME_ASYNC, DIFF_DEBOUNCE_TIME_SYNC,
};
use super::line_cache::InternedRopeLines;
@@ -21,7 +21,7 @@ mod test;
pub(super) struct DiffWorker {
pub channel: UnboundedReceiver<Event>,
- pub hunks: Arc<Mutex<Vec<Hunk>>>,
+ pub diff: Arc<Mutex<DiffInner>>,
pub new_hunks: Vec<Hunk>,
pub redraw_notify: Arc<Notify>,
pub diff_finished_notify: Arc<Notify>,
@@ -46,7 +46,7 @@ impl DiffWorker {
if let Some(lines) = interner.interned_lines() {
self.perform_diff(lines);
}
- self.apply_hunks();
+ self.apply_hunks(interner.diff_base(), interner.doc());
while let Some(event) = self.channel.recv().await {
let (doc, diff_base) = self.accumulate_events(event).await;
@@ -70,15 +70,18 @@ impl DiffWorker {
#[cfg(not(test))]
tokio::task::block_in_place(process_accumulated_events);
- self.apply_hunks();
+ self.apply_hunks(interner.diff_base(), interner.doc());
}
}
/// update the hunks (used by the gutter) by replacing it with `self.new_hunks`.
/// `self.new_hunks` is always empty after this function runs.
/// To improve performance this function tries to reuse the allocation of the old diff previously stored in `self.line_diffs`
- fn apply_hunks(&mut self) {
- swap(&mut *self.hunks.lock(), &mut self.new_hunks);
+ fn apply_hunks(&mut self, diff_base: Rope, doc: Rope) {
+ let mut diff = self.diff.lock();
+ diff.diff_base = diff_base;
+ diff.doc = doc;
+ swap(&mut diff.hunks, &mut self.new_hunks);
self.diff_finished_notify.notify_waiters();
self.new_hunks.clear();
}
diff --git a/helix-vcs/src/diff/worker/test.rs b/helix-vcs/src/diff/worker/test.rs
index 14442426..6a68d987 100644
--- a/helix-vcs/src/diff/worker/test.rs
+++ b/helix-vcs/src/diff/worker/test.rs
@@ -12,12 +12,12 @@ impl DiffHandle {
)
}
async fn into_diff(self, handle: JoinHandle<()>) -> Vec<Hunk> {
- let hunks = self.hunks;
+ let diff = self.diff;
// dropping the channel terminates the task
drop(self.channel);
handle.await.unwrap();
- let hunks = hunks.lock();
- Vec::clone(&*hunks)
+ let diff = diff.lock();
+ Vec::clone(&diff.hunks)
}
}