Skip to content

Commit 048a572

Browse files
committed
async UI
1 parent 695d34a commit 048a572

1 file changed

Lines changed: 154 additions & 71 deletions

File tree

src/ui.rs

Lines changed: 154 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,28 @@ fn reload_file_tab(tab: &FileTab, left_dir: &str, right_dir: &str) {
192192
tab.left_buf.set_text(&left_content);
193193
tab.right_buf.set_text(&right_content);
194194

195-
let new_chunks = if left_content == right_content {
196-
Vec::new()
197-
} else {
198-
myers::diff_lines(&left_content, &right_content)
199-
};
200-
apply_diff_tags(&tab.left_buf, &tab.right_buf, &new_chunks);
201-
*tab.chunks.borrow_mut() = new_chunks;
202-
tab.gutter.queue_draw();
203-
// Buffer now matches disk — no unsaved changes
204-
tab.left_save.set_sensitive(false);
205-
tab.right_save.set_sensitive(false);
195+
let lb = tab.left_buf.clone();
196+
let rb = tab.right_buf.clone();
197+
let ch = tab.chunks.clone();
198+
let g = tab.gutter.clone();
199+
let ls = tab.left_save.clone();
200+
let rs = tab.right_save.clone();
201+
202+
gtk4::glib::spawn_future_local(async move {
203+
let new_chunks = if left_content == right_content {
204+
Vec::new()
205+
} else {
206+
gio::spawn_blocking(move || myers::diff_lines(&left_content, &right_content))
207+
.await
208+
.unwrap_or_default()
209+
};
210+
apply_diff_tags(&lb, &rb, &new_chunks);
211+
*ch.borrow_mut() = new_chunks;
212+
g.queue_draw();
213+
// Buffer now matches disk — no unsaved changes
214+
ls.set_sensitive(false);
215+
rs.set_sensitive(false);
216+
});
206217
}
207218

208219
// ─── Helpers ───────────────────────────────────────────────────────────────
@@ -1036,20 +1047,29 @@ fn refresh_diff(
10361047
chunks: &Rc<RefCell<Vec<DiffChunk>>>,
10371048
gutter: &DrawingArea,
10381049
) {
1039-
let lt = left_buf.text(&left_buf.start_iter(), &left_buf.end_iter(), false);
1040-
let rt = right_buf.text(&right_buf.start_iter(), &right_buf.end_iter(), false);
1050+
let lt = left_buf.text(&left_buf.start_iter(), &left_buf.end_iter(), false).to_string();
1051+
let rt = right_buf.text(&right_buf.start_iter(), &right_buf.end_iter(), false).to_string();
10411052

10421053
remove_diff_tags(left_buf);
10431054
remove_diff_tags(right_buf);
10441055

1045-
let new_chunks = if lt == rt {
1046-
Vec::new()
1047-
} else {
1048-
myers::diff_lines(&lt, &rt)
1049-
};
1050-
apply_diff_tags(left_buf, right_buf, &new_chunks);
1051-
*chunks.borrow_mut() = new_chunks;
1052-
gutter.queue_draw();
1056+
let lb = left_buf.clone();
1057+
let rb = right_buf.clone();
1058+
let ch = chunks.clone();
1059+
let g = gutter.clone();
1060+
1061+
gtk4::glib::spawn_future_local(async move {
1062+
let new_chunks = if lt == rt {
1063+
Vec::new()
1064+
} else {
1065+
gio::spawn_blocking(move || myers::diff_lines(&lt, &rt))
1066+
.await
1067+
.unwrap_or_default()
1068+
};
1069+
apply_diff_tags(&lb, &rb, &new_chunks);
1070+
*ch.borrow_mut() = new_chunks;
1071+
g.queue_draw();
1072+
});
10531073
}
10541074

10551075
#[allow(clippy::too_many_arguments)]
@@ -1249,13 +1269,7 @@ fn build_diff_view(left_path: &Path, right_path: &Path) -> DiffViewResult {
12491269
right_buf.set_text(&right_content);
12501270

12511271
let identical = left_content == right_content;
1252-
let diff_chunks = if identical {
1253-
Vec::new()
1254-
} else {
1255-
myers::diff_lines(&left_content, &right_content)
1256-
};
1257-
apply_diff_tags(&left_buf, &right_buf, &diff_chunks);
1258-
let chunks = Rc::new(RefCell::new(diff_chunks));
1272+
let chunks = Rc::new(RefCell::new(Vec::new()));
12591273

12601274
let info_msg = if identical {
12611275
Some("Files are identical")
@@ -1346,6 +1360,23 @@ fn build_diff_view(left_path: &Path, right_path: &Path) -> DiffViewResult {
13461360
gutter.add_controller(gesture);
13471361
}
13481362

1363+
// Initial async diff
1364+
if !identical {
1365+
let lb = left_buf.clone();
1366+
let rb = right_buf.clone();
1367+
let ch = chunks.clone();
1368+
let g = gutter.clone();
1369+
gtk4::glib::spawn_future_local(async move {
1370+
let new_chunks =
1371+
gio::spawn_blocking(move || myers::diff_lines(&left_content, &right_content))
1372+
.await
1373+
.unwrap_or_default();
1374+
apply_diff_tags(&lb, &rb, &new_chunks);
1375+
*ch.borrow_mut() = new_chunks;
1376+
g.queue_draw();
1377+
});
1378+
}
1379+
13491380
// Re-diff on any buffer change
13501381
{
13511382
let pending = Rc::new(Cell::new(false));
@@ -2036,31 +2067,48 @@ fn refresh_merge_diffs(
20362067
left_gutter: &DrawingArea,
20372068
right_gutter: &DrawingArea,
20382069
) {
2039-
let lt = left_buf.text(&left_buf.start_iter(), &left_buf.end_iter(), false);
2040-
let mt = middle_buf.text(&middle_buf.start_iter(), &middle_buf.end_iter(), false);
2041-
let rt = right_buf.text(&right_buf.start_iter(), &right_buf.end_iter(), false);
2070+
let lt = left_buf.text(&left_buf.start_iter(), &left_buf.end_iter(), false).to_string();
2071+
let mt = middle_buf.text(&middle_buf.start_iter(), &middle_buf.end_iter(), false).to_string();
2072+
let rt = right_buf.text(&right_buf.start_iter(), &right_buf.end_iter(), false).to_string();
20422073

20432074
remove_diff_tags(left_buf);
20442075
remove_diff_tags(middle_buf);
20452076
remove_diff_tags(right_buf);
20462077

2047-
let new_left = if lt == mt {
2048-
Vec::new()
2049-
} else {
2050-
myers::diff_lines(&lt, &mt)
2051-
};
2052-
let new_right = if mt == rt {
2053-
Vec::new()
2054-
} else {
2055-
myers::diff_lines(&mt, &rt)
2056-
};
2078+
let lb = left_buf.clone();
2079+
let mb = middle_buf.clone();
2080+
let rb = right_buf.clone();
2081+
let lch = left_chunks.clone();
2082+
let rch = right_chunks.clone();
2083+
let lg = left_gutter.clone();
2084+
let rg = right_gutter.clone();
2085+
2086+
gtk4::glib::spawn_future_local(async move {
2087+
let left_identical = lt == mt;
2088+
let right_identical = mt == rt;
2089+
let (new_left, new_right) = gio::spawn_blocking(move || {
2090+
let nl = if left_identical {
2091+
Vec::new()
2092+
} else {
2093+
myers::diff_lines(&lt, &mt)
2094+
};
2095+
let nr = if right_identical {
2096+
Vec::new()
2097+
} else {
2098+
myers::diff_lines(&mt, &rt)
2099+
};
2100+
(nl, nr)
2101+
})
2102+
.await
2103+
.unwrap_or_default();
20572104

2058-
apply_merge_tags(left_buf, middle_buf, right_buf, &new_left, &new_right);
2105+
apply_merge_tags(&lb, &mb, &rb, &new_left, &new_right);
20592106

2060-
*left_chunks.borrow_mut() = new_left;
2061-
*right_chunks.borrow_mut() = new_right;
2062-
left_gutter.queue_draw();
2063-
right_gutter.queue_draw();
2107+
*lch.borrow_mut() = new_left;
2108+
*rch.borrow_mut() = new_right;
2109+
lg.queue_draw();
2110+
rg.queue_draw();
2111+
});
20642112
}
20652113

20662114
fn setup_scroll_sync_3way(
@@ -2180,22 +2228,11 @@ fn build_merge_view(
21802228
middle_buf.set_text(&middle_content);
21812229
right_buf.set_text(&right_content);
21822230

2183-
// Two pairwise diffs
2184-
let lc = if left_content == middle_content {
2185-
Vec::new()
2186-
} else {
2187-
myers::diff_lines(&left_content, &middle_content)
2188-
};
2189-
let rc = if middle_content == right_content {
2190-
Vec::new()
2191-
} else {
2192-
myers::diff_lines(&middle_content, &right_content)
2193-
};
2194-
2195-
apply_merge_tags(&left_buf, &middle_buf, &right_buf, &lc, &rc);
2231+
let left_identical = left_content == middle_content;
2232+
let right_identical = middle_content == right_content;
21962233

2197-
let left_chunks = Rc::new(RefCell::new(lc));
2198-
let right_chunks = Rc::new(RefCell::new(rc));
2234+
let left_chunks = Rc::new(RefCell::new(Vec::new()));
2235+
let right_chunks = Rc::new(RefCell::new(Vec::new()));
21992236

22002237
let left_pane = make_diff_pane(&left_buf, left_path, None);
22012238
let middle_pane = make_diff_pane(&middle_buf, middle_display_path, None);
@@ -2333,6 +2370,40 @@ fn build_merge_view(
23332370
right_gutter.add_controller(gesture);
23342371
}
23352372

2373+
// Initial async diff
2374+
if !left_identical || !right_identical {
2375+
let lb = left_buf.clone();
2376+
let mb = middle_buf.clone();
2377+
let rb = right_buf.clone();
2378+
let lch = left_chunks.clone();
2379+
let rch = right_chunks.clone();
2380+
let lg = left_gutter.clone();
2381+
let rg = right_gutter.clone();
2382+
gtk4::glib::spawn_future_local(async move {
2383+
let (new_left, new_right) = gio::spawn_blocking(move || {
2384+
let nl = if left_identical {
2385+
Vec::new()
2386+
} else {
2387+
myers::diff_lines(&left_content, &middle_content)
2388+
};
2389+
let nr = if right_identical {
2390+
Vec::new()
2391+
} else {
2392+
myers::diff_lines(&middle_content, &right_content)
2393+
};
2394+
(nl, nr)
2395+
})
2396+
.await
2397+
.unwrap_or_default();
2398+
2399+
apply_merge_tags(&lb, &mb, &rb, &new_left, &new_right);
2400+
*lch.borrow_mut() = new_left;
2401+
*rch.borrow_mut() = new_right;
2402+
lg.queue_draw();
2403+
rg.queue_draw();
2404+
});
2405+
}
2406+
23362407
// Re-diff on any buffer change (debounced)
23372408
{
23382409
let pending = Rc::new(Cell::new(false));
@@ -3424,16 +3495,28 @@ fn build_file_window(
34243495
if cur_left.as_str() != left_content || cur_right.as_str() != right_content {
34253496
lb.set_text(&left_content);
34263497
rb.set_text(&right_content);
3427-
let new_chunks = if left_content == right_content {
3428-
Vec::new()
3429-
} else {
3430-
myers::diff_lines(&left_content, &right_content)
3431-
};
3432-
apply_diff_tags(&lb, &rb, &new_chunks);
3433-
*ch.borrow_mut() = new_chunks;
3434-
g.queue_draw();
3435-
l_save.set_sensitive(false);
3436-
r_save.set_sensitive(false);
3498+
let lb = lb.clone();
3499+
let rb = rb.clone();
3500+
let ch = ch.clone();
3501+
let g = g.clone();
3502+
let l_save = l_save.clone();
3503+
let r_save = r_save.clone();
3504+
gtk4::glib::spawn_future_local(async move {
3505+
let new_chunks = if left_content == right_content {
3506+
Vec::new()
3507+
} else {
3508+
gio::spawn_blocking(move || {
3509+
myers::diff_lines(&left_content, &right_content)
3510+
})
3511+
.await
3512+
.unwrap_or_default()
3513+
};
3514+
apply_diff_tags(&lb, &rb, &new_chunks);
3515+
*ch.borrow_mut() = new_chunks;
3516+
g.queue_draw();
3517+
l_save.set_sensitive(false);
3518+
r_save.set_sensitive(false);
3519+
});
34373520
}
34383521
}
34393522
gtk4::glib::ControlFlow::Continue

0 commit comments

Comments
 (0)