Skip to content

Commit

Permalink
Use new io + path + fs libraries (LOTS OF CHANGES)
Browse files Browse the repository at this point in the history
Exa now uses the new IO, Path, and Filesystem libraries that have been out for a while now.

Unfortunately, the new libraries don't *entirely* cover the range of the old libraries just yet: in particular, to become more cross-platform, the data in `UnstableFileStat` isn't available in the Unix `MetadataExt` yet. Much of this is contained in rust-lang/rfcs#1044 (which is due to be implemented in rust-lang/rust#14711), but it's not *entirely* there yet.

As such, this commits a serious loss of functionality: no symlink viewing, no hard links or blocks, or users or groups. Also, some of the code could now be optimised. I just wanted to commit this to sort out most of the 'teething problems' of having a different path system in advance.

Here's an example problem that took ages to fix for you, just because you read this far: when I first got exa to compile, it worked mostly fine, except calling `exa` by itself didn't list the current directory. I traced where the command-line options were being generated, to where files and directories were sorted, to where the threads were spawned... and the problem turned out to be that it was using the full path as the file name, rather than just the last component, and these paths happened to begin with `.`, so it thought they were dotfiles.
  • Loading branch information
ogham committed Apr 23, 2015
1 parent eee49ec commit adbaa51
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 216 deletions.
110 changes: 77 additions & 33 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/column.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::iter::repeat;
use unicode::str::UnicodeStr;

use ansi_term::Style;

Expand Down
24 changes: 12 additions & 12 deletions src/dir.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use std::old_io::{fs, IoResult};
use std::old_path::GenericPath;
use std::old_path::posix::Path;

use feature::Git;
use file::{File, GREY};

use std::io;
use std::fs;
use std::path::{Path, PathBuf};

/// A **Dir** provides a cached list of the file paths in a directory that's
/// being listed.
///
/// This object gets passed to the Files themselves, in order for them to
/// check the existence of surrounding files, then highlight themselves
/// accordingly. (See `File#get_source_files`)
pub struct Dir {
contents: Vec<Path>,
path: Path,
contents: Vec<PathBuf>,
path: PathBuf,
git: Option<Git>,
}

Expand All @@ -22,10 +22,10 @@ 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 {
contents: paths,
path: path.clone(),
pub fn readdir(path: &Path) -> io::Result<Dir> {
fs::read_dir(path).map(|dir_obj| Dir {
contents: dir_obj.map(|entry| entry.unwrap().path()).collect(),
path: path.to_path_buf(),
git: Git::scan(path).ok(),
})
}
Expand All @@ -50,11 +50,11 @@ impl Dir {

/// Whether this directory contains a file with the given path.
pub fn contains(&self, path: &Path) -> bool {
self.contents.contains(path)
self.contents.iter().any(|ref p| p.as_path() == path)
}

/// Append a path onto the path specified by this directory.
pub fn join(&self, child: Path) -> Path {
pub fn join(&self, child: &Path) -> PathBuf {
self.path.join(child)
}

Expand Down
25 changes: 9 additions & 16 deletions src/feature/git.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::old_path::GenericPath;
use std::old_path::posix::Path;
use std::path::{Path, PathBuf};

use ansi_term::{ANSIString, ANSIStrings};
use ansi_term::Colour::*;
Expand All @@ -9,38 +8,31 @@ use file::GREY;

/// Container of Git statuses for all the files in this folder's Git repository.
pub struct Git {
statuses: Vec<(Path, git2::Status)>,
statuses: Vec<(PathBuf, git2::Status)>,
}

impl Git {

/// Discover a Git repository on or above this directory, scanning it for
/// the files' statuses if one is found.
pub fn scan(path: &Path) -> Result<Git, git2::Error> {
use std::os::unix::ffi::OsStrExt;
use std::ffi::AsOsStr;

// TODO: libgit2-rs uses the new Path module, but exa still uses the
// old_path one, and will have to continue to do so until the new IO
// module gets a bit more developed. So we have to turn Paths into
// old_path::Paths. Yes, this is hacky, but hopefully temporary.
let new_path = path.as_os_str();
let repo = try!(git2::Repository::discover(new_path));
let repo = try!(git2::Repository::discover(path));
let workdir = match repo.workdir() {
Some(w) => Path::new(w.as_os_str().as_bytes()),
Some(w) => w,
None => return Ok(Git { statuses: vec![] }), // bare repo
};

let statuses = try!(repo.statuses(None)).iter()
.map(|e| (workdir.join(e.path_bytes()), e.status()))
.map(|e| (workdir.join(Path::new(e.path().unwrap())), e.status()))
.collect();

Ok(Git { statuses: statuses })
}

/// Get the status for the file at the given path, if present.
pub fn status(&self, path: &Path) -> String {
let status = self.statuses.iter()
.find(|p| &p.0 == path);
.find(|p| p.0.as_path() == path);
match status {
Some(&(_, s)) => ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s) ]).to_string(),
None => GREY.paint("--").to_string(),
Expand All @@ -52,7 +44,7 @@ impl Git {
/// directories, which don't really have an 'official' status.
pub fn dir_status(&self, dir: &Path) -> String {
let s = self.statuses.iter()
.filter(|p| dir.is_ancestor_of(&p.0))
.filter(|p| p.0.starts_with(dir))
.fold(git2::Status::empty(), |a, b| a | b.1);

ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s)] ).to_string()
Expand Down Expand Up @@ -83,3 +75,4 @@ impl Git {
}
}
}

Loading

0 comments on commit adbaa51

Please sign in to comment.