@@ -17,12 +17,9 @@ use crate::{
1717 commands:: {
1818 diff:: { DiffStatistics , NodeDiff } ,
1919 snapshots:: fill_table,
20- tui:: {
21- summary:: BlobInfoRef ,
22- widgets:: {
23- Draw , PopUpPrompt , PopUpText , ProcessEvent , PromptResult , SelectTable , WithBlock ,
24- popup_prompt, popup_text,
25- } ,
20+ tui:: widgets:: {
21+ Draw , PopUpPrompt , PopUpText , ProcessEvent , PromptResult , SelectTable , WithBlock ,
22+ popup_prompt, popup_text,
2623 } ,
2724 } ,
2825 helpers:: bytes_size_to_string,
@@ -51,7 +48,7 @@ Diff Commands:
5148
5249 m : toggle ignoring metadata
5350 d : toggle show only different entries
54- s : compute information for (sub-)dirs
51+ s : compute information for (sub-)dirs and show totals
5552 I : show information about snapshots
5653
5754General Commands:
@@ -64,7 +61,7 @@ General Commands:
6461 " ;
6562
6663#[ derive( Clone ) ]
67- struct DiffNode ( EitherOrBoth < Node > ) ;
64+ pub struct DiffNode ( pub EitherOrBoth < Node > ) ;
6865
6966impl DiffNode {
7067 fn only_subtrees ( & self ) -> Option < Self > {
@@ -87,6 +84,24 @@ impl DiffNode {
8784 fn name ( & self ) -> OsString {
8885 self . 0 . as_ref ( ) . reduce ( |l, _| l) . name ( )
8986 }
87+
88+ pub fn map < ' a , F , T > ( & ' a self , f : F ) -> EitherOrBoth < T >
89+ where
90+ F : Fn ( & ' a Node ) -> T ,
91+ {
92+ self . 0 . as_ref ( ) . map_any ( & f, & f)
93+ }
94+
95+ pub fn try_map < ' a , F , T > ( & ' a self , f : F ) -> Result < EitherOrBoth < T > >
96+ where
97+ F : Fn ( & ' a Node ) -> Result < T > ,
98+ {
99+ Ok ( match self . 0 . as_ref ( ) {
100+ EitherOrBoth :: Left ( a) => EitherOrBoth :: Left ( f ( a) ?) ,
101+ EitherOrBoth :: Right ( b) => EitherOrBoth :: Right ( f ( b) ?) ,
102+ EitherOrBoth :: Both ( a, b) => EitherOrBoth :: Both ( f ( a) ?, f ( b) ?) ,
103+ } )
104+ }
90105}
91106
92107#[ derive( Default ) ]
@@ -234,45 +249,37 @@ impl<'a, P: ProgressBars, S: IndexedFull> Diff<'a, P, S> {
234249 }
235250
236251 fn ls_row ( & self , node : & DiffNode , stat : & mut DiffStatistics ) -> Vec < Text < ' static > > {
237- let node_info = |node : & Node | {
238- let size = node. subtree . map_or ( node. meta . size , |id| {
239- self . summary_map
240- . get ( & id)
241- . map_or ( node. meta . size , |summary| summary. summary . size )
242- } ) ;
243- (
244- bytes_size_to_string ( size) ,
245- node. meta . mtime . map_or_else (
246- || "?" . to_string ( ) ,
247- |t| format ! ( "{}" , t. format( "%Y-%m-%d %H:%M:%S" ) ) ,
248- ) ,
252+ let node_mtime = |node : & Node | {
253+ node. meta . mtime . map_or_else (
254+ || "?" . to_string ( ) ,
255+ |t| t. format ( "%Y-%m-%d %H:%M:%S" ) . to_string ( ) ,
249256 )
250257 } ;
251258
252- let ( left, right) = node. 0 . as_ref ( ) . left_and_right ( ) ;
253- let left_blobs = left. map ( |node| BlobInfoRef :: from_node_or_map ( node, & self . summary_map ) ) ;
254- let right_blobs = right. map ( |node| BlobInfoRef :: from_node_or_map ( node, & self . summary_map ) ) ;
255- let left_only = BlobInfoRef :: text_diff ( & left_blobs, & right_blobs, self . repo ) ;
256- let right_only = BlobInfoRef :: text_diff ( & right_blobs, & left_blobs, self . repo ) ;
259+ let statistics = self
260+ . summary_map
261+ . compute_diff_statistics ( node, self . repo )
262+ . unwrap_or_default ( ) ;
263+
264+ let ( left, right) = statistics. stats . as_ref ( ) . left_and_right ( ) ;
265+
266+ let left_size = left. map_or_else ( String :: new, |s| bytes_size_to_string ( s. summary . size ) ) ;
267+ let right_size = right. map_or_else ( String :: new, |s| bytes_size_to_string ( s. summary . size ) ) ;
268+ let left_only = left. map_or_else ( String :: new, |s| bytes_size_to_string ( s. sizes . repo_size ) ) ;
269+ let right_only =
270+ right. map_or_else ( String :: new, |s| bytes_size_to_string ( s. sizes . repo_size ) ) ;
257271
258272 let changed = self . node_changed ( node) ;
259273 stat. apply ( changed) ;
260274 let name = node. name ( ) ;
261275 let name = format ! ( "{changed} {}" , name. to_string_lossy( ) ) ;
262- let ( left_size, left_mtime) = match & node. 0 {
263- EitherOrBoth :: Left ( node) | EitherOrBoth :: Both ( node, _) => node_info ( node) ,
264- _ => ( String :: new ( ) , String :: new ( ) ) ,
265- } ;
266- let ( right_size, right_mtime) = match & node. 0 {
267- EitherOrBoth :: Right ( node) | EitherOrBoth :: Both ( _, node) => node_info ( node) ,
268- _ => ( String :: new ( ) , String :: new ( ) ) ,
269- } ;
276+ let ( left_mtime, right_mtime) = node. map ( node_mtime) . left_and_right ( ) ;
270277 [
271278 name,
272- left_mtime,
279+ left_mtime. unwrap_or_default ( ) ,
273280 left_size,
274281 left_only,
275- right_mtime,
282+ right_mtime. unwrap_or_default ( ) ,
276283 right_size,
277284 right_only,
278285 ]
@@ -381,7 +388,7 @@ impl<'a, P: ProgressBars, S: IndexedFull> Diff<'a, P, S> {
381388 Ok ( ( ) )
382389 }
383390
384- pub fn compute_summary ( & mut self ) -> Result < ( ) > {
391+ pub fn compute_summary ( & mut self ) -> Result < PopUpTable > {
385392 let pb = self . repo . progress_bars ( ) ;
386393 let p = pb. progress_counter ( "computing (sub)-dir information" ) ;
387394
@@ -399,7 +406,72 @@ impl<'a, P: ProgressBars, S: IndexedFull> Diff<'a, P, S> {
399406
400407 p. finish ( ) ;
401408 self . update_table ( ) ;
402- Ok ( ( ) )
409+
410+ // Compute total sizes diff
411+ let stats = self
412+ . summary_map
413+ . compute_diff_statistics ( & self . node , self . repo )
414+ . unwrap_or_default ( ) ;
415+
416+ fn row_map < ' a , T > (
417+ title : & ' static str ,
418+ n : EitherOrBoth < T > ,
419+ map : fn ( T ) -> String ,
420+ ) -> Vec < Text < ' a > > {
421+ let ( left, right) = n. left_and_right ( ) ;
422+ vec ! [
423+ Text :: from( title) ,
424+ Text :: from( left. map_or_else( String :: new, map) ) ,
425+ Text :: from( right. map_or_else( String :: new, map) ) ,
426+ ]
427+ }
428+
429+ let row_bytes = |title, n : EitherOrBoth < u64 > | row_map ( title, n, bytes_size_to_string) ;
430+ let row_count = |title, n : EitherOrBoth < usize > | row_map ( title, n, |n| n. to_string ( ) ) ;
431+
432+ let mut rows = Vec :: new ( ) ;
433+ let title_left = if self . node . 0 . has_left ( ) {
434+ format ! ( "{}:{}" , self . snapshot_left. id, self . path_left. display( ) )
435+ } else {
436+ format ! ( "({})" , self . snapshot_left. id)
437+ } ;
438+ let title_right = if self . node . 0 . has_right ( ) {
439+ format ! ( "{}:{}" , self . snapshot_right. id, self . path_right. display( ) )
440+ } else {
441+ format ! ( "({})" , self . snapshot_right. id)
442+ } ;
443+ rows. push ( vec ! [
444+ Text :: from( "" ) ,
445+ Text :: from( title_left) ,
446+ Text :: from( title_right) ,
447+ ] ) ;
448+ rows. push ( row_bytes ( "total Size" , stats. summary ( ) . size ( ) ) ) ;
449+ rows. push ( row_count ( "total files" , stats. summary ( ) . files ( ) ) ) ;
450+ rows. push ( row_count ( "total dirs" , stats. summary ( ) . dirs ( ) ) ) ;
451+ rows. push ( vec ! [ Text :: from( String :: new( ) ) ; 3 ] ) ;
452+ rows. push ( row_bytes (
453+ "exclusive size after deduplication" ,
454+ stats. sizes ( ) . dedup_size ( ) ,
455+ ) ) ;
456+ rows. push ( row_bytes (
457+ "shared size after deduplication" ,
458+ stats. both_sizes ( ) . dedup_size ( ) ,
459+ ) ) ;
460+ rows. push ( row_bytes (
461+ "total size after deduplication" ,
462+ stats. total_sizes ( ) . dedup_size ( ) ,
463+ ) ) ;
464+ rows. push ( vec ! [ Text :: from( String :: new( ) ) ; 3 ] ) ;
465+ rows. push ( row_bytes ( "exclusive RepoSize" , stats. sizes ( ) . repo_size ( ) ) ) ;
466+ rows. push ( row_bytes ( "shared RepoSize" , stats. both_sizes ( ) . repo_size ( ) ) ) ;
467+ rows. push ( row_bytes ( "total RepoSize" , stats. total_sizes ( ) . repo_size ( ) ) ) ;
468+ rows. push ( row_map (
469+ "compression ratio" ,
470+ stats. total_sizes ( ) . compression_ratio ( ) ,
471+ |r| format ! ( "{r:.2}" ) ,
472+ ) ) ;
473+
474+ Ok ( popup_table ( "diff total" , rows) )
403475 }
404476
405477 pub fn snapshot_details ( & self ) -> PopUpTable {
@@ -448,7 +520,10 @@ impl<'a, P: ProgressBars, S: IndexedFull> ProcessEvent for Diff<'a, P, S> {
448520 }
449521 Char ( 'm' ) => self . toggle_ignore_metadata ( ) ,
450522 Char ( 'd' ) => self . toggle_ignore_identical ( ) ?,
451- Char ( 's' ) => self . compute_summary ( ) ?,
523+ Char ( 's' ) => {
524+ self . current_screen =
525+ CurrentScreen :: SnapshotDetails ( self . compute_summary ( ) ?) ;
526+ }
452527 Char ( 'I' ) => {
453528 self . current_screen =
454529 CurrentScreen :: SnapshotDetails ( self . snapshot_details ( ) ) ;
0 commit comments