just playing with tangled
at gvimdiff 2.1 kB view raw
1use std::path::Path; 2use std::sync::Mutex; 3use std::time::Duration; 4use std::time::Instant; 5 6use crossterm::terminal::Clear; 7use crossterm::terminal::ClearType; 8use jj_lib::repo_path::RepoPath; 9 10use crate::text_util; 11use crate::ui::OutputGuard; 12use crate::ui::ProgressOutput; 13use crate::ui::Ui; 14 15pub const UPDATE_HZ: u32 = 30; 16pub const INITIAL_DELAY: Duration = Duration::from_millis(250); 17 18pub fn snapshot_progress(ui: &Ui) -> Option<impl Fn(&RepoPath) + use<>> { 19 struct State { 20 guard: Option<OutputGuard>, 21 output: ProgressOutput<std::io::Stderr>, 22 next_display_time: Instant, 23 } 24 25 let output = ui.progress_output()?; 26 27 // Don't clutter the output during fast operations. 28 let next_display_time = Instant::now() + INITIAL_DELAY; 29 let state = Mutex::new(State { 30 guard: None, 31 output, 32 next_display_time, 33 }); 34 35 Some(move |path: &RepoPath| { 36 let mut state = state.lock().unwrap(); 37 let now = Instant::now(); 38 if now < state.next_display_time { 39 // Future work: Display current path after exactly, say, 250ms has elapsed, to 40 // better handle large single files 41 return; 42 } 43 state.next_display_time = now + Duration::from_secs(1) / UPDATE_HZ; 44 45 if state.guard.is_none() { 46 state.guard = Some( 47 state 48 .output 49 .output_guard(format!("\r{}", Clear(ClearType::CurrentLine))), 50 ); 51 } 52 53 let line_width = state.output.term_width().map(usize::from).unwrap_or(80); 54 let max_path_width = line_width.saturating_sub(13); // Account for "Snapshotting " 55 let fs_path = path.to_fs_path_unchecked(Path::new("")); 56 let (display_path, _) = 57 text_util::elide_start(fs_path.to_str().unwrap(), "...", max_path_width); 58 59 _ = write!( 60 state.output, 61 "\r{}Snapshotting {display_path}", 62 Clear(ClearType::CurrentLine), 63 ); 64 _ = state.output.flush(); 65 }) 66}