mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-02-02 18:48:24 +00:00
List files and directories separately
This finally fixes the issue where trying to list a file causes a crash. Also, tidy up some of the uses of references.
This commit is contained in:
parent
c7417e0bca
commit
cbd2f1fa37
@ -24,7 +24,7 @@ impl<'a> Dir<'a> {
|
||||
let mut files = vec![];
|
||||
|
||||
for path in self.contents.iter() {
|
||||
match File::from_path(path, self) {
|
||||
match File::from_path(path.clone(), Some(self)) {
|
||||
Ok(file) => files.push(file),
|
||||
Err(e) => println!("{}: {}", path.display(), e),
|
||||
}
|
||||
|
46
src/exa.rs
46
src/exa.rs
@ -5,6 +5,8 @@ extern crate ansi_term;
|
||||
extern crate unicode;
|
||||
|
||||
use std::os;
|
||||
use std::io::fs;
|
||||
use std::io::FileType::TypeDirectory;
|
||||
|
||||
use file::File;
|
||||
use dir::Dir;
|
||||
@ -34,14 +36,24 @@ fn main() {
|
||||
};
|
||||
}
|
||||
|
||||
fn exa(opts: &Options) {
|
||||
let mut first = true;
|
||||
|
||||
fn exa(opts: &Options) {
|
||||
// It's only worth printing out directory names if the user supplied
|
||||
// more than one of them.
|
||||
let print_dir_names = opts.dirs.len() > 1;
|
||||
let print_dir_names = opts.path_strs.len() > 1;
|
||||
let (dir_strs, file_strs) = opts.path_strs.clone().partition(|n| fs::stat(&Path::new(n)).unwrap().kind == TypeDirectory);
|
||||
|
||||
for dir_name in opts.dirs.clone().into_iter() {
|
||||
let mut first = file_strs.is_empty();
|
||||
let mut files = vec![];
|
||||
for f in file_strs.iter() {
|
||||
match File::from_path(Path::new(f), None) {
|
||||
Ok(file) => files.push(file),
|
||||
Err(e) => println!("{}: {}", f, e),
|
||||
}
|
||||
}
|
||||
|
||||
view(opts, files);
|
||||
|
||||
for dir_name in dir_strs.into_iter() {
|
||||
if first {
|
||||
first = false;
|
||||
}
|
||||
@ -52,17 +64,13 @@ fn exa(opts: &Options) {
|
||||
match Dir::readdir(Path::new(dir_name.clone())) {
|
||||
Ok(dir) => {
|
||||
let unsorted_files = dir.files();
|
||||
let files: Vec<&File> = opts.transform_files(&unsorted_files);
|
||||
let files: Vec<File> = opts.transform_files(unsorted_files);
|
||||
|
||||
if print_dir_names {
|
||||
println!("{}:", dir_name);
|
||||
}
|
||||
|
||||
match opts.view {
|
||||
View::Details(ref cols) => details_view(opts, cols, files),
|
||||
View::Lines => lines_view(files),
|
||||
View::Grid(across, width) => grid_view(across, width, files),
|
||||
}
|
||||
view(opts, files);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}: {}", dir_name, e);
|
||||
@ -72,13 +80,21 @@ fn exa(opts: &Options) {
|
||||
}
|
||||
}
|
||||
|
||||
fn lines_view(files: Vec<&File>) {
|
||||
fn view(options: &Options, files: Vec<File>) {
|
||||
match options.view {
|
||||
View::Details(ref cols) => details_view(options, cols, files),
|
||||
View::Lines => lines_view(files),
|
||||
View::Grid(across, width) => grid_view(across, width, files),
|
||||
}
|
||||
}
|
||||
|
||||
fn lines_view(files: Vec<File>) {
|
||||
for file in files.iter() {
|
||||
println!("{}", file.file_name());
|
||||
}
|
||||
}
|
||||
|
||||
fn grid_view(across: bool, console_width: uint, files: Vec<&File>) {
|
||||
fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
|
||||
let max_column_length = files.iter().map(|f| f.file_name_width()).max().unwrap_or(0);
|
||||
let num_columns = (console_width + 1) / (max_column_length + 1);
|
||||
let count = files.len();
|
||||
@ -101,7 +117,7 @@ fn grid_view(across: bool, console_width: uint, files: Vec<&File>) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file = files[num];
|
||||
let ref file = files[num];
|
||||
let file_name = file.name.clone();
|
||||
let styled_name = file.file_colour().paint(file_name.as_slice());
|
||||
if x == num_columns - 1 {
|
||||
@ -115,7 +131,7 @@ fn grid_view(across: bool, console_width: uint, files: Vec<&File>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<&File>) {
|
||||
fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<File>) {
|
||||
// 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
|
||||
|
19
src/file.rs
19
src/file.rs
@ -23,15 +23,15 @@ pub static GREY: Colour = Fixed(244);
|
||||
|
||||
pub struct File<'a> {
|
||||
pub name: String,
|
||||
pub dir: &'a Dir<'a>,
|
||||
pub dir: Option<&'a Dir<'a>>,
|
||||
pub ext: Option<String>,
|
||||
pub path: &'a Path,
|
||||
pub path: Path,
|
||||
pub stat: io::FileStat,
|
||||
pub parts: Vec<SortPart>,
|
||||
}
|
||||
|
||||
impl<'a> File<'a> {
|
||||
pub fn from_path(path: &'a Path, parent: &'a Dir) -> IoResult<File<'a>> {
|
||||
pub fn from_path(path: Path, parent: Option<&'a Dir<'a>>) -> IoResult<File<'a>> {
|
||||
let v = path.filename().unwrap(); // fails if / or . or ..
|
||||
let filename = String::from_utf8(v.to_vec()).unwrap_or_else(|_| panic!("Name was not valid UTF-8"));
|
||||
|
||||
@ -39,8 +39,8 @@ impl<'a> File<'a> {
|
||||
// symbolic links. Otherwise, the stat() call will fail if it
|
||||
// encounters a link that's target is non-existent.
|
||||
|
||||
fs::lstat(path).map(|stat| File {
|
||||
path: path,
|
||||
fs::lstat(&path).map(|stat| File {
|
||||
path: path.clone(),
|
||||
dir: parent,
|
||||
stat: stat,
|
||||
name: filename.clone(),
|
||||
@ -158,9 +158,12 @@ impl<'a> File<'a> {
|
||||
let name = self.name.as_slice();
|
||||
let displayed_name = self.file_colour().paint(name);
|
||||
if self.stat.kind == io::TypeSymlink {
|
||||
match fs::readlink(self.path) {
|
||||
match fs::readlink(&self.path) {
|
||||
Ok(path) => {
|
||||
let target_path = if path.is_absolute() { path } else { self.dir.path.join(path) };
|
||||
let target_path = match self.dir {
|
||||
Some(dir) => dir.path.join(path),
|
||||
None => path,
|
||||
};
|
||||
format!("{} {}", displayed_name, self.target_file_name_and_arrow(target_path))
|
||||
}
|
||||
Err(_) => displayed_name,
|
||||
@ -180,7 +183,7 @@ impl<'a> File<'a> {
|
||||
let filename = String::from_utf8_lossy(v).to_string();
|
||||
|
||||
let link_target = fs::stat(&target_path).map(|stat| File {
|
||||
path: &target_path,
|
||||
path: target_path.clone(),
|
||||
dir: self.dir,
|
||||
stat: stat,
|
||||
name: filename.clone(),
|
||||
|
@ -126,7 +126,7 @@ impl<'a> HasType for File<'a> {
|
||||
if source_files.len() == 0 {
|
||||
return Normal;
|
||||
}
|
||||
else if source_files.iter().any(|path| self.dir.contains(path)) {
|
||||
else if source_files.iter().any(|path| self.dir.map(|d| d.contains(path)).unwrap_or(false)) {
|
||||
return Temp;
|
||||
}
|
||||
else {
|
||||
|
@ -31,12 +31,12 @@ pub enum View {
|
||||
}
|
||||
|
||||
pub struct Options {
|
||||
pub header: bool,
|
||||
pub path_strs: Vec<String>,
|
||||
pub reverse: bool,
|
||||
pub show_invisibles: bool,
|
||||
pub sort_field: SortField,
|
||||
pub reverse: bool,
|
||||
pub dirs: Vec<String>,
|
||||
pub view: View,
|
||||
pub header: bool,
|
||||
}
|
||||
|
||||
|
||||
@ -60,11 +60,11 @@ impl Options {
|
||||
match getopts::getopts(args.tail(), opts) {
|
||||
Err(f) => Err(f),
|
||||
Ok(ref matches) => Ok(Options {
|
||||
show_invisibles: matches.opt_present("all"),
|
||||
reverse: matches.opt_present("reverse"),
|
||||
header: matches.opt_present("header"),
|
||||
path_strs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
|
||||
reverse: matches.opt_present("reverse"),
|
||||
show_invisibles: matches.opt_present("all"),
|
||||
sort_field: matches.opt_str("sort").map(|word| SortField::from_word(word)).unwrap_or(SortField::Name),
|
||||
dirs: if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
|
||||
view: Options::view(matches),
|
||||
})
|
||||
}
|
||||
@ -111,8 +111,7 @@ impl Options {
|
||||
}
|
||||
|
||||
columns.push(FileName);
|
||||
|
||||
return columns;
|
||||
columns
|
||||
}
|
||||
|
||||
fn should_display(&self, f: &File) -> bool {
|
||||
@ -124,9 +123,9 @@ impl Options {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_files<'a>(&self, unordered_files: &'a Vec<File<'a>>) -> Vec<&'a File<'a>> {
|
||||
let mut files: Vec<&'a File<'a>> = unordered_files.iter()
|
||||
.filter(|&f| self.should_display(f))
|
||||
pub fn transform_files<'a>(&self, unordered_files: Vec<File<'a>>) -> Vec<File<'a>> {
|
||||
let mut files: Vec<File<'a>> = unordered_files.into_iter()
|
||||
.filter(|f| self.should_display(f))
|
||||
.collect();
|
||||
|
||||
match self.sort_field {
|
||||
@ -145,6 +144,6 @@ impl Options {
|
||||
files.reverse();
|
||||
}
|
||||
|
||||
return files;
|
||||
files
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user