├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets └── dive.gif └── src ├── core ├── config.rs ├── mod.rs └── search.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 19 | dependencies = [ 20 | "hermit-abi", 21 | "libc", 22 | "winapi", 23 | ] 24 | 25 | [[package]] 26 | name = "autocfg" 27 | version = "1.1.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 30 | 31 | [[package]] 32 | name = "cfg-if" 33 | version = "1.0.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 36 | 37 | [[package]] 38 | name = "colored" 39 | version = "2.0.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 42 | dependencies = [ 43 | "atty", 44 | "lazy_static", 45 | "winapi", 46 | ] 47 | 48 | [[package]] 49 | name = "crossbeam" 50 | version = "0.8.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" 53 | dependencies = [ 54 | "cfg-if", 55 | "crossbeam-channel", 56 | "crossbeam-deque", 57 | "crossbeam-epoch", 58 | "crossbeam-queue", 59 | "crossbeam-utils", 60 | ] 61 | 62 | [[package]] 63 | name = "crossbeam-channel" 64 | version = "0.5.2" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" 67 | dependencies = [ 68 | "cfg-if", 69 | "crossbeam-utils", 70 | ] 71 | 72 | [[package]] 73 | name = "crossbeam-deque" 74 | version = "0.8.1" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 77 | dependencies = [ 78 | "cfg-if", 79 | "crossbeam-epoch", 80 | "crossbeam-utils", 81 | ] 82 | 83 | [[package]] 84 | name = "crossbeam-epoch" 85 | version = "0.9.7" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" 88 | dependencies = [ 89 | "cfg-if", 90 | "crossbeam-utils", 91 | "lazy_static", 92 | "memoffset", 93 | "scopeguard", 94 | ] 95 | 96 | [[package]] 97 | name = "crossbeam-queue" 98 | version = "0.3.4" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" 101 | dependencies = [ 102 | "cfg-if", 103 | "crossbeam-utils", 104 | ] 105 | 106 | [[package]] 107 | name = "crossbeam-utils" 108 | version = "0.8.7" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" 111 | dependencies = [ 112 | "cfg-if", 113 | "lazy_static", 114 | ] 115 | 116 | [[package]] 117 | name = "dive" 118 | version = "0.1.0" 119 | dependencies = [ 120 | "colored", 121 | "jwalk", 122 | "regex", 123 | ] 124 | 125 | [[package]] 126 | name = "either" 127 | version = "1.6.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 130 | 131 | [[package]] 132 | name = "hermit-abi" 133 | version = "0.1.19" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 136 | dependencies = [ 137 | "libc", 138 | ] 139 | 140 | [[package]] 141 | name = "jwalk" 142 | version = "0.6.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "172752e853a067cbce46427de8470ddf308af7fd8ceaf9b682ef31a5021b6bb9" 145 | dependencies = [ 146 | "crossbeam", 147 | "rayon", 148 | ] 149 | 150 | [[package]] 151 | name = "lazy_static" 152 | version = "1.4.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 155 | 156 | [[package]] 157 | name = "libc" 158 | version = "0.2.119" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" 161 | 162 | [[package]] 163 | name = "memchr" 164 | version = "2.4.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 167 | 168 | [[package]] 169 | name = "memoffset" 170 | version = "0.6.5" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 173 | dependencies = [ 174 | "autocfg", 175 | ] 176 | 177 | [[package]] 178 | name = "num_cpus" 179 | version = "1.13.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 182 | dependencies = [ 183 | "hermit-abi", 184 | "libc", 185 | ] 186 | 187 | [[package]] 188 | name = "rayon" 189 | version = "1.5.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 192 | dependencies = [ 193 | "autocfg", 194 | "crossbeam-deque", 195 | "either", 196 | "rayon-core", 197 | ] 198 | 199 | [[package]] 200 | name = "rayon-core" 201 | version = "1.9.1" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 204 | dependencies = [ 205 | "crossbeam-channel", 206 | "crossbeam-deque", 207 | "crossbeam-utils", 208 | "lazy_static", 209 | "num_cpus", 210 | ] 211 | 212 | [[package]] 213 | name = "regex" 214 | version = "1.5.5" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" 217 | dependencies = [ 218 | "aho-corasick", 219 | "memchr", 220 | "regex-syntax", 221 | ] 222 | 223 | [[package]] 224 | name = "regex-syntax" 225 | version = "0.6.25" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 228 | 229 | [[package]] 230 | name = "scopeguard" 231 | version = "1.1.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 234 | 235 | [[package]] 236 | name = "winapi" 237 | version = "0.3.9" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 240 | dependencies = [ 241 | "winapi-i686-pc-windows-gnu", 242 | "winapi-x86_64-pc-windows-gnu", 243 | ] 244 | 245 | [[package]] 246 | name = "winapi-i686-pc-windows-gnu" 247 | version = "0.4.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 250 | 251 | [[package]] 252 | name = "winapi-x86_64-pc-windows-gnu" 253 | version = "0.4.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 256 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "divecli" 3 | version = "0.1.1" 4 | edition = "2021" 5 | license = "MIT" 6 | readme = "README.md" 7 | repository = "https://github.com/ffaanngg/dive" 8 | homepage = "https://github.com/ffaanngg/dive" 9 | description = "🔎 Search millions of files at lightning-fast speeds to find what you are looking for!" 10 | exclude = ["assets/*"] 11 | 12 | [[bin]] 13 | path = "src/main.rs" 14 | name = "dive" 15 | 16 | [dependencies] 17 | jwalk = "0.6.0" 18 | colored = "2" 19 | regex = "1" 20 | 21 | [profile.release] 22 | opt-level = 3 23 | lto = true 24 | codegen-units = 1 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Shiv 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dive 2 | 3 | 🔎 Search millions of files at lightning-fast speeds to find what you are looking for! 4 | 5 | ### [Download](https://github.com/ffaanngg/dive/releases/download/Stable/dive.exe) 6 | 7 | ## Dive in action! 8 | ![Dive in action!](assets/dive.gif) 9 | 10 | ## Reference 11 | 12 | The CLI takes in 2 arguments, the first being the `regex` expression for matching the filename and the second being the directory to search in. If the directory is not mentioned, the root directory of your system is chosen and all the files in your system are searched. 13 | 14 | If there are any permission errors while searching, they are simply ignored. 15 | 16 | 17 | -------------------------------------------------------------------------------- /assets/dive.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shhivv/dive/57ad5c535b3b76c311e41b06c00c9a229f3e1fe7/assets/dive.gif -------------------------------------------------------------------------------- /src/core/config.rs: -------------------------------------------------------------------------------- 1 | use colored::*; 2 | use std::process; 3 | 4 | fn get_default_path() -> Option { 5 | if cfg!(target_os = "linux") { 6 | return Some(String::from("/")); 7 | } else if cfg!(target_os = "windows") { 8 | return Some(String::from("C:\\")); 9 | } else { 10 | return None; 11 | } 12 | } 13 | 14 | pub struct Config { 15 | pub path: String, 16 | pub regex_expr: String, 17 | } 18 | 19 | impl Config { 20 | pub fn new(args: Vec) -> Self { 21 | let mut args_iter = args.into_iter(); 22 | 23 | let pathname; 24 | let regex_expr; 25 | 26 | args_iter.next(); // Advance the first argument to ignore the file call 27 | 28 | match args_iter.next() { 29 | Some(file) => regex_expr = file, 30 | None => { 31 | eprintln!("File not specified"); 32 | process::exit(1) 33 | } 34 | } 35 | 36 | match args_iter.next() { 37 | Some(arg) => { 38 | pathname = arg; 39 | } 40 | None => { 41 | let path = get_default_path(); 42 | match path { 43 | Some(path) => { 44 | println!( 45 | "{}", 46 | "Path not specified. Searching your entire computer.".yellow() 47 | ); 48 | pathname = path; 49 | } 50 | None => { 51 | eprintln!("{}", "Could not determine root directory for your system.".red()); 52 | process::exit(1); 53 | } 54 | } 55 | } 56 | } 57 | 58 | Self { 59 | path: pathname, 60 | regex_expr, 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod search; 3 | 4 | pub use config::*; 5 | pub use search::*; 6 | -------------------------------------------------------------------------------- /src/core/search.rs: -------------------------------------------------------------------------------- 1 | use crate::core::Config; 2 | use colored::*; 3 | use jwalk::WalkDir; 4 | use regex::Regex; 5 | use std::process; 6 | use std::time::Instant; 7 | 8 | pub struct Search { 9 | pub searched: u64, 10 | pub elasped: u64, 11 | pub found: u64, 12 | } 13 | 14 | impl Search { 15 | pub fn query(config: Config) -> Self { 16 | let walker = WalkDir::new(config.path) 17 | .follow_links(true) 18 | .skip_hidden(false); 19 | 20 | let re = Regex::new(config.regex_expr.as_str()); 21 | 22 | let expr = match re { 23 | Ok(expr) => expr, 24 | Err(_) => { 25 | eprintln!("{}", "Invalid Regex found".red()); 26 | process::exit(1); 27 | } 28 | }; 29 | 30 | let mut searched = 0; 31 | let mut found = 0; 32 | 33 | let start = Instant::now(); 34 | 35 | for entry in walker { 36 | if let Ok(entry) = entry { 37 | searched += 1; 38 | if expr.is_match(entry.file_name.to_str().unwrap()) { 39 | found += 1; 40 | println!("{}", format!("{}", entry.path().display()).green()) 41 | } 42 | } 43 | } 44 | 45 | let elasped = start.elapsed().as_secs(); 46 | 47 | Self { 48 | searched, 49 | elasped, 50 | found, 51 | } 52 | } 53 | 54 | pub fn results(self) -> String { 55 | format!( 56 | "\nSearched over {} items in {} seconds and found {} {}", 57 | self.searched.to_string().blue(), 58 | self.elasped.to_string().green(), 59 | self.found.to_string().green(), 60 | if self.found == 1 { 61 | "file or folder" 62 | } else { 63 | "files or folders" 64 | } 65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod core; 2 | 3 | use crate::core::{Config, Search}; 4 | 5 | fn main() { 6 | let config: Config = Config::new(std::env::args().collect::>()); 7 | 8 | println!(); 9 | 10 | println!("{}", Search::query(config).results()); 11 | } 12 | --------------------------------------------------------------------------------