Skip to content

Commit

Permalink
Use better Rust patterns
Browse files Browse the repository at this point in the history
- Don't use `Option.unwrap()`
- use `&str` whenever possible.
  • Loading branch information
dduan committed Nov 3, 2019
1 parent 123125c commit 7402010
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 57 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.PHONY: check
check:
@cargo check

.PHONY: test
test:
@cargo test

Expand Down
55 changes: 39 additions & 16 deletions src/file_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ pub struct FileTree {
}

impl FileTree {
pub fn new(root_path: String, children: Vec<(String, FileType)>) -> FileTree {
pub fn new(root_path: &str, children: Vec<(String, FileType)>) -> Option<FileTree> {
let mut slab = Slab::new();
let root_id = slab.vacant_entry().key();

let root_prefix_len: usize = Path::new(&root_path)
let root_prefix_len: usize = Path::new(root_path)
.components()
.filter(|c| match c {
Component::CurDir => false,
Expand All @@ -120,23 +120,35 @@ impl FileTree {
let root = Box::new(File {
id: root_id,
parent: None,
display_name: root_path.clone(),
path: root_path.clone(),
display_name: root_path.to_string(),
path: root_path.to_string(),
file_type: FileType::Directory,
data: TypeSpecficData::Directory(HashMap::new()),
});
slab.insert(root);

for (path, meta) in children {
let data: TypeSpecficData = match meta {
let data_option: Option<TypeSpecficData> = match meta {
FileType::Link => {
let link_path = fs::read_link(path.clone()).unwrap();
TypeSpecficData::Link(link_path.to_str().unwrap().to_string())
fs::read_link(&path)
.ok()
.and_then(|path| {
path
.to_str()
.map(|x| x.to_string())
})
.map(|path| TypeSpecficData::Link(path))
}
FileType::Directory => TypeSpecficData::Directory(HashMap::new()),
FileType::File => TypeSpecficData::File,
FileType::Directory => Some(TypeSpecficData::Directory(HashMap::new())),
FileType::File => Some(TypeSpecficData::File),
};

if data_option.is_none() {
return None
}

let data = data_option.unwrap();

let mut ancestry: Vec<Component> = Path::new(&path)
.components()
.filter(|c| {
Expand All @@ -148,14 +160,25 @@ impl FileTree {
})
.skip(root_prefix_len)
.collect();
let path_name = ancestry.pop().unwrap().as_os_str().to_str().unwrap().to_string();

let ancestor = ancestry
.pop()
.map(|x| x.as_os_str())
.and_then(|x| x.to_str())
.map(|x| x.to_string());

if ancestor.is_none() {
continue
}

let path_name = ancestor.unwrap();

// Handle intermidiary directories.
let mut current_acestor_id = root_id;
let mut current_ancestor_path = PathBuf::new();
current_ancestor_path.push(&root_path);
for ancestor_name in ancestry {
let display_name = ancestor_name.clone().as_os_str().to_str().unwrap().to_string();
let display_name = ancestor_name.clone().as_os_str().to_string_lossy().into_owned();
if let Some(child_key) = slab[current_acestor_id].child_key(&display_name) {
current_acestor_id = child_key;
} else {
Expand All @@ -165,7 +188,7 @@ impl FileTree {
id: new_id,
parent: Some(current_acestor_id),
display_name: display_name.clone(),
path: current_ancestor_path.to_str().unwrap().to_string(),
path: current_ancestor_path.to_string_lossy().into_owned(),
file_type: FileType::Directory,
data: TypeSpecficData::Directory(HashMap::new()),
}));
Expand All @@ -187,10 +210,10 @@ impl FileTree {
slab[current_acestor_id].add_child(&path_name, new_id);
}

FileTree {
Some(FileTree {
storage: slab,
root_id: root_id,
}
})
}

pub fn get(&self, id: usize) -> &File {
Expand All @@ -213,12 +236,12 @@ mod test {
#[test]
fn tree_construction() {
let tree = FileTree::new(
".".to_string(),
".",
vec![
("a".to_string(), FileType::File),
("b/c/d".to_string(), FileType::File),
],
);
).unwrap();

let root = tree.get(tree.root_id);
assert!(root.is_dir());
Expand Down
18 changes: 12 additions & 6 deletions src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,19 @@ fn format_file(
}
}

pub fn format_paths(root_path: String, children: Vec<(String, FileType)>) -> Vec<FormattedEntry> {
let tree = FileTree::new(root_path, children);
pub fn format_paths(root_path: &str, children: Vec<(String, FileType)>) -> Vec<FormattedEntry> {
let mut history = HashMap::new();
let mut result = Vec::new();
let root = tree.get_root();
format_file(&tree, root, &mut history, &mut result);
result
match FileTree::new(root_path, children) {
Some(tree) => {
let root = tree.get_root();
format_file(&tree, root, &mut history, &mut result);
result
},
None => {
Vec::new()
}
}
}

#[cfg(test)]
Expand All @@ -102,7 +108,7 @@ mod test {
#[test]
fn formatting_works() {
let formatted = super::format_paths(
".".to_string(),
".",
vec![
("a".to_string(), FileType::File),
(
Expand Down
48 changes: 28 additions & 20 deletions src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ use std::io::Write;
use std::path::Path;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

fn color_print<T>(text: T, color: Color)
where
T: Display,
{
fn color_print<T>(text: T, color: Color) -> bool where T: Display {
if atty::is(atty::Stream::Stdout) {
let stdout = BufferWriter::stdout(ColorChoice::Auto);
let mut buffer = stdout.buffer();
let mut spec = ColorSpec::new();
spec.set_fg(Some(color));
buffer.set_color(&spec).unwrap();
write!(&mut buffer, "{}", text).expect("");
buffer.reset().unwrap();
stdout.print(&buffer).expect("stdout print failure");
buffer
.set_color(&spec)
.and_then(|_| write!(&mut buffer, "{}", text))
.and_then(|_| buffer.reset())
.and_then(|_| stdout.print(&buffer))
.is_ok()
} else {
print!("{}", text);
true
}
}

Expand Down Expand Up @@ -56,22 +56,30 @@ pub fn print_entries(entries: &Vec<FormattedEntry>, create_alias: bool) {
}
}

pub fn create_edit_aliases(editor: &String, entries: &Vec<FormattedEntry>) {
pub fn create_edit_aliases(editor: &str, entries: &Vec<FormattedEntry>) {
let user = env::var("USER").unwrap_or("".to_string());
let alias_file = format!("/tmp/tre_aliases_{}", &user);
let alias_file = Path::new(&alias_file);
let file = File::create(&alias_file);
let alias_file_path = Path::new(&alias_file);
let file = File::create(&alias_file_path);
if !file.is_ok() {
eprintln!("[tre] failed to open {}", alias_file.to_str().unwrap());
eprintln!("[tre] failed to open {}", alias_file);
return
}
let mut alias_file = file.unwrap();

for (index, entry) in entries.iter().enumerate() {
writeln!(
&mut alias_file,
"alias e{}=\"eval '{} \\\"{}\\\"'\"",
index, editor, entry.path
)
.expect("[tre] failed to write to alias file.");
if let Some(mut alias_file) = file.ok() {
for (index, entry) in entries.iter().enumerate() {
let result = writeln!(
&mut alias_file,
"alias e{}=\"eval '{} \\\"{}\\\"'\"",
index, editor, entry.path
);

if !result.is_ok() {
eprintln!("[tre] failed to write to alias file.");
}
}
} else {
eprintln!("[tre] failed to open {}", alias_file);
}

}
25 changes: 14 additions & 11 deletions src/path_finders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ use std::fs;
use std::process::Command;
use walkdir::{DirEntry, WalkDir};

pub fn find_all_paths(root: &String) -> Vec<(String, FileType)> {
pub fn find_all_paths(root: &str) -> Vec<(String, FileType)> {
let mut result: Vec<(String, FileType)> = Vec::new();
for entry in WalkDir::new(root).into_iter().filter_map(|e| e.ok()) {
if let Ok(meta) = entry.metadata() {
let path = entry.path().to_str().unwrap().to_string();
if &path != root {
result.push((path, FileType::new(meta)))
if let Some(path) = entry.path().to_str() {
let path = path.to_string();
if &path != root {
result.push((path, FileType::new(meta)))
}
}
}
}
result
}

fn is_hidden(entry: &DirEntry) -> bool {
entry
.file_name()
Expand All @@ -23,7 +26,7 @@ fn is_hidden(entry: &DirEntry) -> bool {
.unwrap_or(false)
}

pub fn find_non_hidden_paths(root: &String) -> Vec<(String, FileType)> {
pub fn find_non_hidden_paths(root: &str) -> Vec<(String, FileType)> {
let walker = WalkDir::new(root).into_iter();
let mut result: Vec<(String, FileType)> = Vec::new();

Expand All @@ -32,18 +35,18 @@ pub fn find_non_hidden_paths(root: &String) -> Vec<(String, FileType)> {
.filter_map(|e| e.ok())
{
if let Ok(meta) = entry.metadata() {
let path = entry.path().to_str().unwrap().to_string();
if &path != root {
result.push((path, FileType::new(meta)))
if let Some(path) = entry.path().to_str() {
let path = path.to_string();
if &path != root {
result.push((path, FileType::new(meta)))
}
}
} else {
println!("falied to get meta");
}
}
result
}

pub fn find_non_git_ignored_paths(root: &String) -> Vec<(String, FileType)> {
pub fn find_non_git_ignored_paths(root: &str) -> Vec<(String, FileType)> {
if let Ok(git_output) = Command::new("git").arg("ls-files").arg(root).output() {
if git_output.status.success() {
if let Ok(paths_buf) = String::from_utf8(git_output.stdout) {
Expand Down
8 changes: 4 additions & 4 deletions src/tre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,16 @@ pub fn run(option: RunOption) {
return;
}
Mode::FollowGitIgnore => {
paths = path_finders::find_non_git_ignored_paths(&root);
paths = path_finders::find_non_git_ignored_paths(root);
}
Mode::ExcludeHiddenFiles => {
paths = path_finders::find_non_hidden_paths(&root);
paths = path_finders::find_non_hidden_paths(root);
}
Mode::ShowAllFiles => {
paths = path_finders::find_all_paths(&root);
paths = path_finders::find_all_paths(root);
}
}
let format_result = formatting::format_paths(root.to_string(), paths);
let format_result = formatting::format_paths(root, paths);

if let Some(editor) = option.editor {
output::print_entries(&format_result, true);
Expand Down

0 comments on commit 7402010

Please sign in to comment.