@@ -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
20662114fn 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