aboutsummaryrefslogtreecommitdiff
path: root/helix-vcs/src/diff.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-vcs/src/diff.rs')
-rw-r--r--helix-vcs/src/diff.rs58
1 files changed, 42 insertions, 16 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 {