mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-26 13:56:27 +00:00
Recurse into directories
This commit is contained in:
parent
3242cb216a
commit
5611a5768a
@ -21,11 +21,11 @@ impl Dir {
|
||||
/// Create a new Dir object filled with all the files in the directory
|
||||
/// pointed to by the given path. Fails if the directory can't be read, or
|
||||
/// isn't actually a directory.
|
||||
pub fn readdir(path: Path) -> IoResult<Dir> {
|
||||
fs::readdir(&path).map(|paths| Dir {
|
||||
pub fn readdir(path: &Path) -> IoResult<Dir> {
|
||||
fs::readdir(path).map(|paths| Dir {
|
||||
contents: paths,
|
||||
path: path.clone(),
|
||||
git: Git::scan(&path).ok(),
|
||||
git: Git::scan(path).ok(),
|
||||
})
|
||||
}
|
||||
|
||||
|
57
src/main.rs
57
src/main.rs
@ -25,37 +25,24 @@ pub mod output;
|
||||
pub mod term;
|
||||
|
||||
fn exa(options: &Options) {
|
||||
let mut dirs: Vec<String> = vec![];
|
||||
let mut dirs: Vec<Path> = vec![];
|
||||
let mut files: Vec<File> = vec![];
|
||||
|
||||
// It's only worth printing out directory names if the user supplied
|
||||
// more than one of them.
|
||||
let mut count = 0;
|
||||
|
||||
let mut stack = options.path_strs.clone();
|
||||
|
||||
// Separate the user-supplied paths into directories and files.
|
||||
// Files are shown first, and then each directory is expanded
|
||||
// and listed second.
|
||||
loop {
|
||||
let file = match stack.pop() {
|
||||
None => break,
|
||||
Some(f) => f,
|
||||
};
|
||||
|
||||
let path = Path::new(file.clone());
|
||||
for file in options.path_strs.iter() {
|
||||
let path = Path::new(file);
|
||||
match fs::stat(&path) {
|
||||
Ok(stat) => {
|
||||
if stat.kind == FileType::Directory {
|
||||
match options.dir_action {
|
||||
DirAction::AsFile => files.push(File::with_stat(stat, &path, None)),
|
||||
DirAction::List => dirs.push(file.clone()),
|
||||
DirAction::Recurse => { /* todo */ },
|
||||
}
|
||||
if stat.kind == FileType::Directory && options.dir_action != DirAction::AsFile {
|
||||
dirs.push(path);
|
||||
}
|
||||
else {
|
||||
// May as well reuse the stat result from earlier
|
||||
// instead of just using File::from_path().
|
||||
files.push(File::with_stat(stat, &path, None));
|
||||
}
|
||||
}
|
||||
@ -68,10 +55,19 @@ fn exa(options: &Options) {
|
||||
let mut first = files.is_empty();
|
||||
|
||||
if !files.is_empty() {
|
||||
options.view(None, files);
|
||||
options.view(None, &files[]);
|
||||
}
|
||||
|
||||
for dir_name in dirs.iter() {
|
||||
// Directories are put on a stack rather than just being iterated through,
|
||||
// as the vector can change as more directories are added.
|
||||
loop {
|
||||
let dir_path = match dirs.pop() {
|
||||
None => break,
|
||||
Some(f) => f,
|
||||
};
|
||||
|
||||
// Put a gap between directories, or between the list of files and the
|
||||
// first directory.
|
||||
if first {
|
||||
first = false;
|
||||
}
|
||||
@ -79,19 +75,30 @@ fn exa(options: &Options) {
|
||||
print!("\n");
|
||||
}
|
||||
|
||||
match Dir::readdir(Path::new(dir_name.clone())) {
|
||||
match Dir::readdir(&dir_path) {
|
||||
Ok(ref dir) => {
|
||||
let unsorted_files = dir.files();
|
||||
let files: Vec<File> = options.transform_files(unsorted_files);
|
||||
|
||||
if count > 1 {
|
||||
println!("{}:", dir_name);
|
||||
// When recursing, add any directories to the dirs stack
|
||||
// backwards: the *last* element of the stack is used each
|
||||
// time, so by inserting them backwards, they get displayed in
|
||||
// the correct sort order.
|
||||
if options.dir_action == DirAction::Recurse {
|
||||
for dir in files.iter().filter(|f| f.stat.kind == FileType::Directory).rev() {
|
||||
dirs.push(dir.path.clone());
|
||||
}
|
||||
}
|
||||
|
||||
options.view(Some(dir), files);
|
||||
if count > 1 {
|
||||
println!("{}:", dir_path.display());
|
||||
}
|
||||
count += 1;
|
||||
|
||||
options.view(Some(dir), &files[]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}: {}", dir_name, e);
|
||||
println!("{}: {}", dir_path.display(), e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
@ -74,7 +74,7 @@ impl Options {
|
||||
}
|
||||
|
||||
/// Display the files using this Option's View.
|
||||
pub fn view(&self, dir: Option<&Dir>, files: Vec<File>) {
|
||||
pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
|
||||
self.view.view(dir, files)
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ pub enum View {
|
||||
}
|
||||
|
||||
impl View {
|
||||
pub fn view(&self, dir: Option<&Dir>, files: Vec<File>) {
|
||||
pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
|
||||
match *self {
|
||||
View::Grid(across, width) => grid_view(across, width, files),
|
||||
View::Details(ref cols, header) => details_view(&*cols.for_dir(dir), files, header),
|
||||
@ -28,13 +28,13 @@ impl View {
|
||||
}
|
||||
|
||||
/// The lines view literally just displays each file, line-by-line.
|
||||
fn lines_view(files: Vec<File>) {
|
||||
fn lines_view(files: &[File]) {
|
||||
for file in files.iter() {
|
||||
println!("{}", file.file_name_view().text);
|
||||
}
|
||||
}
|
||||
|
||||
fn fit_into_grid(across: bool, console_width: usize, files: &Vec<File>) -> Option<(usize, Vec<usize>)> {
|
||||
fn fit_into_grid(across: bool, console_width: usize, files: &[File]) -> Option<(usize, Vec<usize>)> {
|
||||
// TODO: this function could almost certainly be optimised...
|
||||
// surely not *all* of the numbers of lines are worth searching through!
|
||||
|
||||
@ -86,8 +86,8 @@ fn fit_into_grid(across: bool, console_width: usize, files: &Vec<File>) -> Optio
|
||||
return None;
|
||||
}
|
||||
|
||||
fn grid_view(across: bool, console_width: usize, files: Vec<File>) {
|
||||
if let Some((num_lines, widths)) = fit_into_grid(across, console_width, &files) {
|
||||
fn grid_view(across: bool, console_width: usize, files: &[File]) {
|
||||
if let Some((num_lines, widths)) = fit_into_grid(across, console_width, files) {
|
||||
for y in range(0, num_lines) {
|
||||
for x in range(0, widths.len()) {
|
||||
let num = if across {
|
||||
@ -122,7 +122,7 @@ fn grid_view(across: bool, console_width: usize, files: Vec<File>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn details_view(columns: &[Column], files: Vec<File>, header: bool) {
|
||||
fn details_view(columns: &[Column], files: &[File], header: bool) {
|
||||
// The output gets formatted into columns, which looks nicer. To
|
||||
// do this, we have to write the results into a table, instead of
|
||||
// displaying each file immediately, then calculating the maximum
|
||||
|
Loading…
Reference in New Issue
Block a user