summaryrefslogtreecommitdiffstats
path: root/src/commands/bulk_rename.rs
blob: 2db758f188d99edd5023c0a7dc031c8b64ebb510 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::io::{BufRead, Write};
use std::path;
use std::process;

use rand::Rng;

use crate::context::JoshutoContext;
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
use crate::window::JoshutoView;
use crate::commands::{JoshutoCommand, JoshutoRunnable, ReloadDirList};

#[derive(Clone, Debug)]
pub struct BulkRename;

impl BulkRename {
    pub fn new() -> Self {
        BulkRename {}
    }
    pub const fn command() -> &'static str {
        "bulk_rename"
    }

    pub fn bulk_rename(context: &mut JoshutoContext) -> JoshutoResult<()> {
        const PREFIX: &str = "joshuto-";
        let editor = match std::env::var("EDITOR") {
            Ok(s) => s,
            Err(_) => return Err(JoshutoError::new(
                JoshutoErrorKind::EnvVarNotPresent,
                String::from("EDITOR environment variable not set"),
            )),
        };

        let curr_tab = &context.tabs[context.curr_tab_index];

        let paths = curr_tab.curr_list.get_selected_paths();
        let mut rand_str = String::with_capacity(PREFIX.len() + 10);
        rand_str.push_str(PREFIX);

        rand::thread_rng()
            .sample_iter(&rand::distributions::Alphanumeric)
            .take(10)
            .for_each(|ch| rand_str.push(ch));

        let mut file_path = path::PathBuf::from("/tmp");
        file_path.push(rand_str);

        {
            let mut file = std::fs::File::create(&file_path)?;
            for path in &paths {
                let file_name = path.file_name().unwrap();
                let file_name_as_bytes = file_name.to_str().unwrap().as_bytes();
                file.write(file_name_as_bytes)?;
                file.write(&['\n' as u8])?;
            }
        }

        let mut command = process::Command::new(editor);
        command.arg(&file_path);

        /* exit curses and launch program */
        {
            ncurses::savetty();
            ncurses::endwin();
            let mut handle = command.spawn()?;
            handle.wait()?;
        }

        let mut paths_renamed: Vec<path::PathBuf> = Vec::with_capacity(paths.len());
        {
            let file = std::fs::File::open(&file_path)?;

            let reader = std::io::BufReader::new(file);
            for line in reader.lines() {
                let line2 = line?;
                let line = line2.trim();
                if line.len() == 0 {
                    continue;
                }
                let path = path::PathBuf::from(line);
                paths_renamed.push(path);
            }
        }

        for (p, q) in paths.iter().zip(paths_renamed.iter()) {
            println!("{:?} -> {:?}", p, q);
        }
        print!("Continue with rename? (y/N): ");
        std::io::stdout().flush()?;

        let mut user_input = String::with_capacity(4);
        std::io::stdin().read_line(&mut user_input)?;
        user_input = user_input.to_lowercase();

        let user_input_trimmed = user_input.trim();
        if user_input_trimmed == "y" || user_input_trimmed == "yes" {
            for (p, q) in paths.iter().zip(paths_renamed.iter()) {
                std::fs::rename(p, q)?;
            }
        }
        std::fs::remove_file(file_path)?;

        /* restore ncurses */
        ncurses::resetty();
        ncurses::refresh();
        ncurses::doupdate();
        Ok(())
    }
}

impl JoshutoCommand for BulkRename {}

impl std::fmt::Display for BulkRename {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", Self::command())
    }
}

impl JoshutoRunnable for BulkRename {
    fn execute(&self, context: &mut JoshutoContext, view: &JoshutoView) -> JoshutoResult<()> {
        Self::bulk_rename(context)?;
        ReloadDirList::reload(context.curr_tab_index, context)?;
        let curr_tab = &mut context.tabs[context.curr_tab_index];
        curr_tab.refresh(view, &context.config_t);
        ncurses::doupdate();
        Ok(())
    }
}