mirror of
https://github.com/sharkdp/fd
synced 2024-11-05 16:58:21 +00:00
Re-write in rust
This commit is contained in:
parent
04892d2290
commit
12bfee0bec
7 changed files with 244 additions and 105 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,6 +1,2 @@
|
|||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
build
|
||||
fnd
|
||||
target/
|
||||
**/*.rs.bk
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.1.0)
|
||||
|
||||
project(fnd CXX)
|
||||
|
||||
find_package(Boost 1.60 REQUIRED COMPONENTS system filesystem)
|
||||
include_directories( ${Boost_INCLUDE_DIR} )
|
||||
|
||||
file(GLOB SOURCES "src/*.cpp")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
|
||||
|
||||
add_executable(fnd ${SOURCES})
|
||||
|
||||
target_compile_features(fnd PRIVATE cxx_range_for)
|
||||
|
||||
target_link_libraries(fnd ${Boost_LIBRARIES})
|
||||
|
||||
install(TARGETS fnd DESTINATION bin)
|
143
Cargo.lock
generated
Normal file
143
Cargo.lock
generated
Normal file
|
@ -0,0 +1,143 @@
|
|||
[root]
|
||||
name = "fd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
|
||||
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
|
||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
|
||||
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
|
||||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "fd"
|
||||
version = "0.1.0"
|
||||
authors = ["David Peter <mail@david-peter.de>"]
|
||||
|
||||
[dependencies]
|
||||
getopts = "0.2"
|
||||
regex = "0.2"
|
||||
walkdir = "1"
|
30
README.md
30
README.md
|
@ -1,36 +1,30 @@
|
|||
# fnd
|
||||
# fd
|
||||
A modern, convenient and fast replacement for `find`.
|
||||
|
||||
**Features:**
|
||||
* Easy syntax. `fnd PATTERN` instead of `find -iname '*PATTERN*'`.
|
||||
* Easy syntax: `fd PATTERN` instead of `find -iname '*PATTERN*'`.
|
||||
* Colored output.
|
||||
* Regular expressions.
|
||||
* The command name is *25%* shorter than `find` :-).
|
||||
* The command name is *50%* shorter than `find` :-).
|
||||
|
||||
## Examples
|
||||
``` bash
|
||||
> fnd
|
||||
> fd
|
||||
README.md
|
||||
src
|
||||
src/fnd.cpp
|
||||
README.md
|
||||
src/main.rs
|
||||
Cargo.toml
|
||||
LICENSE
|
||||
CMakeLists.txt
|
||||
Cargo.lock
|
||||
|
||||
> fnd cpp
|
||||
src/fnd.cpp
|
||||
> fd rs
|
||||
src/main.rs
|
||||
|
||||
> fnd '[A-Z].*'
|
||||
README.md
|
||||
> fd '^[A-Z]+$'
|
||||
LICENSE
|
||||
CMakeLists.txt
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
* g++ `>=4.9`
|
||||
* boost `>=1.60`
|
||||
|
||||
## Build
|
||||
```bash
|
||||
cmake .
|
||||
make
|
||||
cargo build
|
||||
```
|
||||
|
|
63
src/fnd.cpp
63
src/fnd.cpp
|
@ -1,63 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
static const std::string ANSI_PURPLE = "\x1b[35;06m";
|
||||
static const std::string ANSI_CYAN = "\x1b[36;01m";
|
||||
static const std::string ANSI_RESET = "\x1b[0m";
|
||||
|
||||
void printPath(const fs::path& path) {
|
||||
if (fs::is_symlink(path)) {
|
||||
std::cout << ANSI_PURPLE;
|
||||
} else if (fs::is_directory(path)) {
|
||||
std::cout << ANSI_CYAN;
|
||||
}
|
||||
|
||||
std::cout << path.string();
|
||||
|
||||
std::cout << ANSI_RESET << std::endl;
|
||||
}
|
||||
|
||||
void findFiles(const std::regex& pattern) {
|
||||
const fs::path& currentPath = fs::current_path();
|
||||
|
||||
for (auto& entry: fs::recursive_directory_iterator(currentPath)) {
|
||||
const fs::path& path = entry.path().lexically_relative(currentPath);
|
||||
|
||||
if (std::regex_search(path.string(), pattern)) {
|
||||
printPath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string argument;
|
||||
|
||||
if (argc == 1) {
|
||||
argument = "";
|
||||
} else if (argc == 2) {
|
||||
argument = argv[1];
|
||||
}
|
||||
|
||||
if (argc > 2 || argument == "-h" || argument == "--help") {
|
||||
std::cerr << "Usage: fnd [PATTERN]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// try to parse the argument as a regex
|
||||
try {
|
||||
std::regex::flag_type flags = std::regex_constants::ECMAScript
|
||||
| std::regex_constants::icase;
|
||||
std::regex re(argument, flags);
|
||||
|
||||
findFiles(re);
|
||||
}
|
||||
catch (const std::regex_error& e) {
|
||||
std::cerr << "Regex error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
78
src/main.rs
Normal file
78
src/main.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
extern crate walkdir;
|
||||
extern crate regex;
|
||||
extern crate getopts;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::io::Write;
|
||||
use std::process;
|
||||
use std::error::Error;
|
||||
|
||||
use walkdir::{WalkDir, DirEntry, WalkDirIterator};
|
||||
use regex::Regex;
|
||||
use getopts::Options;
|
||||
|
||||
fn is_hidden(entry: &DirEntry) -> bool {
|
||||
entry.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.starts_with("."))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn scan(root: &Path, pattern: &Regex) {
|
||||
let walker = WalkDir::new(root).into_iter();
|
||||
for entry in walker.filter_entry(|e| !is_hidden(e))
|
||||
.filter_map(|e| e.ok()) {
|
||||
if entry.path() == root {
|
||||
continue;
|
||||
}
|
||||
|
||||
let path_relative = entry.path().strip_prefix(root).unwrap();
|
||||
let path_str = match path_relative.to_str() {
|
||||
Some(s) => s,
|
||||
None => continue
|
||||
};
|
||||
match pattern.find(path_str) {
|
||||
Some(_) =>
|
||||
println!("{}", path_str),
|
||||
None =>
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error<T: Error>(err: &T) -> ! {
|
||||
writeln!(&mut std::io::stderr(), "{}", err.description())
|
||||
.expect("Failed writing to stderr");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
let mut opts = Options::new();
|
||||
opts.optflag("h", "help", "print this help message");
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => { m }
|
||||
Err(f) => { error(&f) }
|
||||
};
|
||||
|
||||
if matches.opt_present("h") {
|
||||
let brief = "Usage: fd [PATTERN]";
|
||||
print!("{}", opts.usage(&brief));
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let empty = String::new();
|
||||
let pattern = matches.free.get(0).unwrap_or(&empty);
|
||||
|
||||
let current_dir_buf = env::current_dir()
|
||||
.expect("Could not get current directory!");
|
||||
let current_dir = current_dir_buf.as_path();
|
||||
|
||||
match Regex::new(pattern) {
|
||||
Ok(re) =>
|
||||
scan(current_dir, &re),
|
||||
Err(err) => error(&err)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue