Skip to content

Commit 0223877

Browse files
committed
store document and diff base in Diff
1 parent 0dbee95 commit 0223877

File tree

5 files changed

+63
-26
lines changed

5 files changed

+63
-26
lines changed

helix-vcs/src/diff.rs

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,18 @@ struct Event {
2828
render_lock: Option<RenderLock>,
2929
}
3030

31+
#[derive(Clone, Debug, Default)]
32+
struct DiffInner {
33+
diff_base: Rope,
34+
doc: Rope,
35+
hunks: Vec<Hunk>,
36+
}
37+
3138
#[derive(Clone, Debug)]
3239
pub struct DiffHandle {
3340
channel: UnboundedSender<Event>,
3441
render_lock: Arc<RwLock<()>>,
35-
hunks: Arc<Mutex<Vec<Hunk>>>,
42+
diff: Arc<Mutex<DiffInner>>,
3643
inverted: bool,
3744
}
3845

@@ -47,18 +54,18 @@ impl DiffHandle {
4754
redraw_handle: RedrawHandle,
4855
) -> (DiffHandle, JoinHandle<()>) {
4956
let (sender, receiver) = unbounded_channel();
50-
let hunks: Arc<Mutex<Vec<Hunk>>> = Arc::default();
57+
let diff: Arc<Mutex<DiffInner>> = Arc::default();
5158
let worker = DiffWorker {
5259
channel: receiver,
53-
hunks: hunks.clone(),
60+
diff: diff.clone(),
5461
new_hunks: Vec::default(),
5562
redraw_notify: redraw_handle.0,
5663
diff_finished_notify: Arc::default(),
5764
};
5865
let handle = tokio::spawn(worker.run(diff_base, doc));
5966
let differ = DiffHandle {
6067
channel: sender,
61-
hunks,
68+
diff,
6269
inverted: false,
6370
render_lock: redraw_handle.1,
6471
};
@@ -69,9 +76,9 @@ impl DiffHandle {
6976
self.inverted = !self.inverted;
7077
}
7178

72-
pub fn hunks(&self) -> FileHunks {
73-
FileHunks {
74-
hunks: self.hunks.lock(),
79+
pub fn read(&self) -> Diff {
80+
Diff {
81+
diff: self.diff.lock(),
7582
inverted: self.inverted,
7683
}
7784
}
@@ -168,28 +175,44 @@ impl Hunk {
168175
/// A list of changes in a file sorted in ascending
169176
/// non-overlapping order
170177
#[derive(Debug)]
171-
pub struct FileHunks<'a> {
172-
hunks: MutexGuard<'a, Vec<Hunk>>,
178+
pub struct Diff<'a> {
179+
diff: MutexGuard<'a, DiffInner>,
173180
inverted: bool,
174181
}
175182

176-
impl FileHunks<'_> {
183+
impl Diff<'_> {
184+
pub fn diff_base(&self) -> &Rope {
185+
if self.inverted {
186+
&self.diff.doc
187+
} else {
188+
&self.diff.diff_base
189+
}
190+
}
191+
192+
pub fn doc(&self) -> &Rope {
193+
if self.inverted {
194+
&self.diff.diff_base
195+
} else {
196+
&self.diff.doc
197+
}
198+
}
199+
177200
pub fn is_inverted(&self) -> bool {
178201
self.inverted
179202
}
180203

181204
/// Returns the `Hunk` for the `n`th change in this file.
182205
/// if there is no `n`th change `Hunk::NONE` is returned instead.
183206
pub fn nth_hunk(&self, n: u32) -> Hunk {
184-
match self.hunks.get(n as usize) {
207+
match self.diff.hunks.get(n as usize) {
185208
Some(hunk) if self.inverted => hunk.invert(),
186209
Some(hunk) => hunk.clone(),
187210
None => Hunk::NONE,
188211
}
189212
}
190213

191214
pub fn len(&self) -> u32 {
192-
self.hunks.len() as u32
215+
self.diff.hunks.len() as u32
193216
}
194217

195218
pub fn is_empty(&self) -> bool {
@@ -204,19 +227,20 @@ impl FileHunks<'_> {
204227
};
205228

206229
let res = self
230+
.diff
207231
.hunks
208232
.binary_search_by_key(&line, |hunk| hunk_range(hunk).start);
209233

210234
match res {
211235
// Search found a hunk that starts exactly at this line, return the next hunk if it exists.
212-
Ok(pos) if pos + 1 == self.hunks.len() => None,
236+
Ok(pos) if pos + 1 == self.diff.hunks.len() => None,
213237
Ok(pos) => Some(pos as u32 + 1),
214238

215239
// No hunk starts exactly at this line, so the search returns
216240
// the position where a hunk starting at this line should be inserted.
217241
// That position is exactly the position of the next hunk or the end
218242
// of the list if no such hunk exists
219-
Err(pos) if pos == self.hunks.len() => None,
243+
Err(pos) if pos == self.diff.hunks.len() => None,
220244
Err(pos) => Some(pos as u32),
221245
}
222246
}
@@ -228,6 +252,7 @@ impl FileHunks<'_> {
228252
|hunk: &Hunk| hunk.after.clone()
229253
};
230254
let res = self
255+
.diff
231256
.hunks
232257
.binary_search_by_key(&line, |hunk| hunk_range(hunk).end);
233258

@@ -237,7 +262,7 @@ impl FileHunks<'_> {
237262
// which represents a pure removal.
238263
// Removals are technically empty but are still shown as single line hunks
239264
// and as such we must jump to the previous hunk (if it exists) if we are already inside the removal
240-
Ok(pos) if !hunk_range(&self.hunks[pos]).is_empty() => Some(pos as u32),
265+
Ok(pos) if !hunk_range(&self.diff.hunks[pos]).is_empty() => Some(pos as u32),
241266

242267
// No hunk ends exactly at this line, so the search returns
243268
// the position where a hunk ending at this line should be inserted.
@@ -255,6 +280,7 @@ impl FileHunks<'_> {
255280
};
256281

257282
let res = self
283+
.diff
258284
.hunks
259285
.binary_search_by_key(&line, |hunk| hunk_range(hunk).start);
260286

@@ -267,7 +293,7 @@ impl FileHunks<'_> {
267293
// The previous hunk contains this hunk if it exists and doesn't end before this line
268294
Err(0) => None,
269295
Err(pos) => {
270-
let hunk = hunk_range(&self.hunks[pos - 1]);
296+
let hunk = hunk_range(&self.diff.hunks[pos - 1]);
271297
if hunk.end > line || include_removal && hunk.start == line && hunk.is_empty() {
272298
Some(pos as u32 - 1)
273299
} else {

helix-vcs/src/diff/line_cache.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ impl InternedRopeLines {
4343
res
4444
}
4545

46+
pub fn doc(&self) -> Rope {
47+
self.doc.clone()
48+
}
49+
50+
pub fn diff_base(&self) -> Rope {
51+
self.diff_base.clone()
52+
}
53+
4654
/// Updates the `diff_base` and optionally the document if `doc` is not None
4755
pub fn update_diff_base(&mut self, diff_base: Rope, doc: Option<Rope>) {
4856
self.interned.clear();

helix-vcs/src/diff/worker.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use tokio::sync::Notify;
1010
use tokio::time::{timeout, timeout_at, Duration};
1111

1212
use crate::diff::{
13-
Event, RenderLock, ALGORITHM, DIFF_DEBOUNCE_TIME_ASYNC, DIFF_DEBOUNCE_TIME_SYNC,
13+
DiffInner, Event, RenderLock, ALGORITHM, DIFF_DEBOUNCE_TIME_ASYNC, DIFF_DEBOUNCE_TIME_SYNC,
1414
};
1515

1616
use super::line_cache::InternedRopeLines;
@@ -21,7 +21,7 @@ mod test;
2121

2222
pub(super) struct DiffWorker {
2323
pub channel: UnboundedReceiver<Event>,
24-
pub hunks: Arc<Mutex<Vec<Hunk>>>,
24+
pub diff: Arc<Mutex<DiffInner>>,
2525
pub new_hunks: Vec<Hunk>,
2626
pub redraw_notify: Arc<Notify>,
2727
pub diff_finished_notify: Arc<Notify>,
@@ -46,7 +46,7 @@ impl DiffWorker {
4646
if let Some(lines) = interner.interned_lines() {
4747
self.perform_diff(lines);
4848
}
49-
self.apply_hunks();
49+
self.apply_hunks(interner.diff_base(), interner.doc());
5050
while let Some(event) = self.channel.recv().await {
5151
let (doc, diff_base) = self.accumulate_events(event).await;
5252

@@ -70,15 +70,18 @@ impl DiffWorker {
7070
#[cfg(not(test))]
7171
tokio::task::block_in_place(process_accumulated_events);
7272

73-
self.apply_hunks();
73+
self.apply_hunks(interner.diff_base(), interner.doc());
7474
}
7575
}
7676

7777
/// update the hunks (used by the gutter) by replacing it with `self.new_hunks`.
7878
/// `self.new_hunks` is always empty after this function runs.
7979
/// To improve performance this function tries to reuse the allocation of the old diff previously stored in `self.line_diffs`
80-
fn apply_hunks(&mut self) {
81-
swap(&mut *self.hunks.lock(), &mut self.new_hunks);
80+
fn apply_hunks(&mut self, diff_base: Rope, doc: Rope) {
81+
let mut diff = self.diff.lock();
82+
diff.diff_base = diff_base;
83+
diff.doc = doc;
84+
swap(&mut diff.hunks, &mut self.new_hunks);
8285
self.diff_finished_notify.notify_waiters();
8386
self.new_hunks.clear();
8487
}

helix-vcs/src/diff/worker/test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ impl DiffHandle {
1212
)
1313
}
1414
async fn into_diff(self, handle: JoinHandle<()>) -> Vec<Hunk> {
15-
let hunks = self.hunks;
15+
let diff = self.diff;
1616
// dropping the channel terminates the task
1717
drop(self.channel);
1818
handle.await.unwrap();
19-
let hunks = hunks.lock();
20-
Vec::clone(&*hunks)
19+
let diff = diff.lock();
20+
Vec::clone(&diff.hunks)
2121
}
2222
}
2323

helix-view/src/gutter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub fn diff<'doc>(
9696
let deleted = theme.get("diff.minus");
9797
let modified = theme.get("diff.delta");
9898
if let Some(diff_handle) = doc.diff_handle() {
99-
let hunks = diff_handle.hunks();
99+
let hunks = diff_handle.read();
100100
let mut hunk_i = 0;
101101
let mut hunk = hunks.nth_hunk(hunk_i);
102102
Box::new(move |line: usize, _selected: bool, out: &mut String| {

0 commit comments

Comments
 (0)