summaryrefslogtreecommitdiffstats
path: root/src/copy_move.rs
blob: 1675da8d71eb80578955188b037e4eca6cbdb9bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use std::fmt::Write;
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;

use fs_extra;
use indicatif::{InMemoryTerm, ProgressBar, ProgressDrawTarget, ProgressState, ProgressStyle};
use tuikit::prelude::{Attr, Color, Effect, Event, Term};

use crate::fm_error::FmResult;

fn setup(
    action: String,
    height: usize,
    width: usize,
) -> FmResult<(InMemoryTerm, ProgressBar, fs_extra::dir::CopyOptions)> {
    let in_mem = InMemoryTerm::new(height as u16, width as u16);
    let pb = ProgressBar::with_draw_target(
        Some(100),
        ProgressDrawTarget::term_like(Box::new(in_mem.clone())),
    );
    pb.set_style(
        ProgressStyle::with_template(
            "{spinner} {action} [{elapsed}] [{wide_bar}] {percent}% ({eta})",
        )
        .unwrap()
        .with_key("eta", |state: &ProgressState, w: &mut dyn Write| {
            write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()
        })
        .with_key("action", move |_: &ProgressState, w: &mut dyn Write| {
            write!(w, "{}", &action).unwrap()
        })
        .progress_chars("#>-"),
    );
    let options = fs_extra::dir::CopyOptions::new();
    Ok((in_mem, pb, options))
}

fn handle_progress_display(
    in_mem: &InMemoryTerm,
    pb: &ProgressBar,
    term: &Arc<Term>,
    process_info: fs_extra::TransitProcess,
) -> fs_extra::dir::TransitProcessResult {
    pb.set_position(100 * process_info.copied_bytes / process_info.total_bytes);
    let _ = term.print_with_attr(
        1,
        0,
        &in_mem.to_owned().contents(),
        Attr {
            fg: Color::CYAN,
            bg: Color::default(),
            effect: Effect::REVERSE | Effect::BOLD,
        },
    );
    let _ = term.present();
    fs_extra::dir::TransitProcessResult::ContinueOrAbort
}

pub fn copy(sources: Vec<PathBuf>, dest: String, term: Arc<Term>) -> FmResult<()> {
    let c_term = term.clone();
    let (height, width) = term.term_size()?;
    let (in_mem, pb, options) = setup("copy".to_owned(), height, width)?;
    let handle_progress = move |process_info: fs_extra::TransitProcess| {
        handle_progress_display(&in_mem, &pb, &term, process_info)
    };
    let _ = thread::spawn(move || {
        fs_extra::copy_items_with_progress(&sources, &dest, &options, handle_progress)
            .unwrap_or_default();
        let _ = c_term.send_event(Event::User(()));
    });
    Ok(())
}

pub fn mover(sources: Vec<PathBuf>, dest: String, term: Arc<Term>) -> FmResult<()> {
    let c_term = term.clone();
    let (height, width) = term.term_size()?;
    let (in_mem, pb, options) = setup("move".to_owned(), height, width)?;
    let handle_progress = move |process_info: fs_extra::TransitProcess| {
        handle_progress_display(&in_mem, &pb, &term, process_info)
    };
    let _ = thread::spawn(move || {
        fs_extra::move_items_with_progress(&sources, dest, &options, handle_progress)
            .unwrap_or_default();
        let _ = c_term.send_event(Event::User(()));
    });
    Ok(())
}