mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-02-02 10:38:24 +00:00
Improve matching of Git status entries to files
The challenge is that the paths returned from libgit2's status listing are from the perspective of the Git repository and thus effectively relative to the working tree root, while the other paths we're manipulating are (potentially) relative to our current working directory. So, if those two aren't identical (if running from outside the working tree, or from a subdirectory), the paths won't match up. A reasonably reliable way around this is to resolve both types of paths to absolute paths before comparing them. This fixes #15 at a basic level, anyway. What still doesn't work: referring to the working tree or one of its descendants via a symlink. For that, we'd probably need to fully resolve symlinks in the file path. (The unwrap_or()'s are messy and will probably just result in missing status information, but then, what information could you hope to get without having both a current working directory and a Git working tree?)
This commit is contained in:
parent
a4e17193d9
commit
6e19563879
@ -75,7 +75,7 @@ impl Dir {
|
||||
/// Container of Git statuses for all the files in this folder's Git repository.
|
||||
#[cfg(feature="git")]
|
||||
struct Git {
|
||||
statuses: Vec<(Vec<u8>, git2::Status)>,
|
||||
statuses: Vec<(Path, git2::Status)>,
|
||||
}
|
||||
|
||||
#[cfg(feature="git")]
|
||||
@ -85,8 +85,9 @@ impl Git {
|
||||
/// the files' statuses if one is found.
|
||||
fn scan(path: &Path) -> Result<Git, git2::Error> {
|
||||
let repo = try!(git2::Repository::discover(path));
|
||||
let workdir = repo.workdir().unwrap_or(Path::new("."));
|
||||
let statuses = try!(repo.statuses(None)).iter()
|
||||
.map(|e| (e.path_bytes().to_vec(), e.status()))
|
||||
.map(|e| (workdir.join(e.path_bytes()), e.status()))
|
||||
.collect();
|
||||
Ok(Git { statuses: statuses })
|
||||
}
|
||||
@ -94,7 +95,7 @@ impl Git {
|
||||
/// Get the status for the file at the given path, if present.
|
||||
fn status(&self, path: &Path) -> String {
|
||||
let status = self.statuses.iter()
|
||||
.find(|p| p.0 == path.as_vec());
|
||||
.find(|p| &p.0 == path);
|
||||
match status {
|
||||
Some(&(_, s)) => ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s) ]).to_string(),
|
||||
None => GREY.paint("--").to_string(),
|
||||
@ -106,7 +107,7 @@ impl Git {
|
||||
/// directories, which don't really have an 'official' status.
|
||||
fn dir_status(&self, dir: &Path) -> String {
|
||||
let s = self.statuses.iter()
|
||||
.filter(|p| p.0.starts_with(dir.as_vec()))
|
||||
.filter(|p| dir.is_ancestor_of(&p.0))
|
||||
.fold(git2::Status::empty(), |a, b| a | b.1);
|
||||
|
||||
ANSIStrings( &[Git::index_status(s), Git::working_tree_status(s)] ).to_string()
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::old_io::{fs, IoResult};
|
||||
use std::old_io as io;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::env::current_dir;
|
||||
|
||||
use ansi_term::{ANSIString, ANSIStrings, Colour, Style};
|
||||
use ansi_term::Style::Plain;
|
||||
@ -415,7 +416,8 @@ impl<'a> File<'a> {
|
||||
|
||||
fn git_status(&self) -> Cell {
|
||||
let status = match self.dir {
|
||||
Some(d) => d.git_status(&self.path, self.stat.kind == io::FileType::Directory),
|
||||
Some(d) => d.git_status(¤t_dir().unwrap_or(Path::new(".")).join(&self.path),
|
||||
self.stat.kind == io::FileType::Directory),
|
||||
None => GREY.paint("--").to_string(),
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user