mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-22 12:05:11 +00:00
Merge pull request #820 from skyline75489/chesterliu/dev/win-support
Initial support for Windows
This commit is contained in:
commit
f3ca1fe6f7
@ -31,9 +31,11 @@ scoped_threadpool = "0.1"
|
|||||||
term_grid = "0.2.0"
|
term_grid = "0.2.0"
|
||||||
terminal_size = "0.1.16"
|
terminal_size = "0.1.16"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
users = "0.11"
|
|
||||||
zoneinfo_compiled = "0.5.1"
|
zoneinfo_compiled = "0.5.1"
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
users = "0.11"
|
||||||
|
|
||||||
[dependencies.datetime]
|
[dependencies.datetime]
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -111,6 +111,13 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also hide _prefix files on Windows because it's used by old applications
|
||||||
|
// as an alternative to dot-prefix files.
|
||||||
|
#[cfg(windows)]
|
||||||
|
if ! self.dotfiles && filename.starts_with('_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if self.git_ignoring {
|
if self.git_ignoring {
|
||||||
let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default();
|
let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default();
|
||||||
if git_status.unstaged == GitStatus::Ignored {
|
if git_status.unstaged == GitStatus::Ignored {
|
||||||
|
@ -296,6 +296,7 @@ impl Git {
|
|||||||
/// Paths need to be absolute for them to be compared properly, otherwise
|
/// Paths need to be absolute for them to be compared properly, otherwise
|
||||||
/// you’d ask a repo about “./README.md” but it only knows about
|
/// you’d ask a repo about “./README.md” but it only knows about
|
||||||
/// “/vagrant/README.md”, prefixed by the workdir.
|
/// “/vagrant/README.md”, prefixed by the workdir.
|
||||||
|
#[cfg(unix)]
|
||||||
fn reorient(path: &Path) -> PathBuf {
|
fn reorient(path: &Path) -> PathBuf {
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
|
|
||||||
@ -308,6 +309,14 @@ fn reorient(path: &Path) -> PathBuf {
|
|||||||
path.canonicalize().unwrap_or(path)
|
path.canonicalize().unwrap_or(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn reorient(path: &Path) -> PathBuf {
|
||||||
|
let unc_path = path.canonicalize().unwrap();
|
||||||
|
// On Windows UNC path is returned. We need to strip the prefix for it to work.
|
||||||
|
let normal_path = unc_path.as_os_str().to_str().unwrap().trim_left_matches("\\\\?\\");
|
||||||
|
return PathBuf::from(normal_path);
|
||||||
|
}
|
||||||
|
|
||||||
/// The character to display if the file has been modified, but not staged.
|
/// The character to display if the file has been modified, but not staged.
|
||||||
fn working_tree_status(status: git2::Status) -> f::GitStatus {
|
fn working_tree_status(status: git2::Status) -> f::GitStatus {
|
||||||
match status {
|
match status {
|
||||||
|
@ -82,13 +82,27 @@ pub struct Permissions {
|
|||||||
pub setuid: bool,
|
pub setuid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The file's FileAttributes field, available only on Windows.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Attributes {
|
||||||
|
pub archive: bool,
|
||||||
|
pub directory: bool,
|
||||||
|
pub readonly: bool,
|
||||||
|
pub hidden: bool,
|
||||||
|
pub system: bool,
|
||||||
|
pub reparse_point: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// The three pieces of information that are displayed as a single column in
|
/// The three pieces of information that are displayed as a single column in
|
||||||
/// the details view. These values are fused together to make the output a
|
/// the details view. These values are fused together to make the output a
|
||||||
/// little more compressed.
|
/// little more compressed.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct PermissionsPlus {
|
pub struct PermissionsPlus {
|
||||||
pub file_type: Type,
|
pub file_type: Type,
|
||||||
|
#[cfg(unix)]
|
||||||
pub permissions: Permissions,
|
pub permissions: Permissions,
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub attributes: Attributes,
|
||||||
pub xattrs: bool,
|
pub xattrs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
//! Files, and methods and fields to access their metadata.
|
//! Files, and methods and fields to access their metadata.
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
|
use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::fs::MetadataExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
@ -174,6 +177,7 @@ impl<'dir> File<'dir> {
|
|||||||
/// Whether this file is both a regular file *and* executable for the
|
/// Whether this file is both a regular file *and* executable for the
|
||||||
/// current user. An executable file has a different purpose from an
|
/// current user. An executable file has a different purpose from an
|
||||||
/// executable directory, so they should be highlighted differently.
|
/// executable directory, so they should be highlighted differently.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_executable_file(&self) -> bool {
|
pub fn is_executable_file(&self) -> bool {
|
||||||
let bit = modes::USER_EXECUTE;
|
let bit = modes::USER_EXECUTE;
|
||||||
self.is_file() && (self.metadata.permissions().mode() & bit) == bit
|
self.is_file() && (self.metadata.permissions().mode() & bit) == bit
|
||||||
@ -185,21 +189,25 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this file is a named pipe on the filesystem.
|
/// Whether this file is a named pipe on the filesystem.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_pipe(&self) -> bool {
|
pub fn is_pipe(&self) -> bool {
|
||||||
self.metadata.file_type().is_fifo()
|
self.metadata.file_type().is_fifo()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this file is a char device on the filesystem.
|
/// Whether this file is a char device on the filesystem.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_char_device(&self) -> bool {
|
pub fn is_char_device(&self) -> bool {
|
||||||
self.metadata.file_type().is_char_device()
|
self.metadata.file_type().is_char_device()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this file is a block device on the filesystem.
|
/// Whether this file is a block device on the filesystem.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_block_device(&self) -> bool {
|
pub fn is_block_device(&self) -> bool {
|
||||||
self.metadata.file_type().is_block_device()
|
self.metadata.file_type().is_block_device()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this file is a socket on the filesystem.
|
/// Whether this file is a socket on the filesystem.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn is_socket(&self) -> bool {
|
pub fn is_socket(&self) -> bool {
|
||||||
self.metadata.file_type().is_socket()
|
self.metadata.file_type().is_socket()
|
||||||
}
|
}
|
||||||
@ -270,6 +278,7 @@ impl<'dir> File<'dir> {
|
|||||||
/// is uncommon, while you come across directories and other types
|
/// is uncommon, while you come across directories and other types
|
||||||
/// with multiple links much more often. Thus, it should get highlighted
|
/// with multiple links much more often. Thus, it should get highlighted
|
||||||
/// more attentively.
|
/// more attentively.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn links(&self) -> f::Links {
|
pub fn links(&self) -> f::Links {
|
||||||
let count = self.metadata.nlink();
|
let count = self.metadata.nlink();
|
||||||
|
|
||||||
@ -280,6 +289,7 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s inode.
|
/// This file’s inode.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn inode(&self) -> f::Inode {
|
pub fn inode(&self) -> f::Inode {
|
||||||
f::Inode(self.metadata.ino())
|
f::Inode(self.metadata.ino())
|
||||||
}
|
}
|
||||||
@ -287,6 +297,7 @@ impl<'dir> File<'dir> {
|
|||||||
/// This file’s number of filesystem blocks.
|
/// This file’s number of filesystem blocks.
|
||||||
///
|
///
|
||||||
/// (Not the size of each block, which we don’t actually report on)
|
/// (Not the size of each block, which we don’t actually report on)
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn blocks(&self) -> f::Blocks {
|
pub fn blocks(&self) -> f::Blocks {
|
||||||
if self.is_file() || self.is_link() {
|
if self.is_file() || self.is_link() {
|
||||||
f::Blocks::Some(self.metadata.blocks())
|
f::Blocks::Some(self.metadata.blocks())
|
||||||
@ -297,11 +308,13 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The ID of the user that own this file.
|
/// The ID of the user that own this file.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn user(&self) -> f::User {
|
pub fn user(&self) -> f::User {
|
||||||
f::User(self.metadata.uid())
|
f::User(self.metadata.uid())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The ID of the group that owns this file.
|
/// The ID of the group that owns this file.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn group(&self) -> f::Group {
|
pub fn group(&self) -> f::Group {
|
||||||
f::Group(self.metadata.gid())
|
f::Group(self.metadata.gid())
|
||||||
}
|
}
|
||||||
@ -314,6 +327,7 @@ impl<'dir> File<'dir> {
|
|||||||
///
|
///
|
||||||
/// Block and character devices return their device IDs, because they
|
/// Block and character devices return their device IDs, because they
|
||||||
/// usually just have a file size of zero.
|
/// usually just have a file size of zero.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn size(&self) -> f::Size {
|
pub fn size(&self) -> f::Size {
|
||||||
if self.is_directory() {
|
if self.is_directory() {
|
||||||
f::Size::None
|
f::Size::None
|
||||||
@ -335,12 +349,23 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn size(&self) -> f::Size {
|
||||||
|
if self.is_directory() {
|
||||||
|
f::Size::None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f::Size::Some(self.metadata.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This file’s last modified timestamp, if available on this platform.
|
/// This file’s last modified timestamp, if available on this platform.
|
||||||
pub fn modified_time(&self) -> Option<SystemTime> {
|
pub fn modified_time(&self) -> Option<SystemTime> {
|
||||||
self.metadata.modified().ok()
|
self.metadata.modified().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last changed timestamp, if available on this platform.
|
/// This file’s last changed timestamp, if available on this platform.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn changed_time(&self) -> Option<SystemTime> {
|
pub fn changed_time(&self) -> Option<SystemTime> {
|
||||||
let (mut sec, mut nanosec) = (self.metadata.ctime(), self.metadata.ctime_nsec());
|
let (mut sec, mut nanosec) = (self.metadata.ctime(), self.metadata.ctime_nsec());
|
||||||
|
|
||||||
@ -359,6 +384,11 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn changed_time(&self) -> Option<SystemTime> {
|
||||||
|
return self.modified_time()
|
||||||
|
}
|
||||||
|
|
||||||
/// This file’s last accessed timestamp, if available on this platform.
|
/// This file’s last accessed timestamp, if available on this platform.
|
||||||
pub fn accessed_time(&self) -> Option<SystemTime> {
|
pub fn accessed_time(&self) -> Option<SystemTime> {
|
||||||
self.metadata.accessed().ok()
|
self.metadata.accessed().ok()
|
||||||
@ -374,6 +404,7 @@ impl<'dir> File<'dir> {
|
|||||||
/// This is used a the leftmost character of the permissions column.
|
/// This is used a the leftmost character of the permissions column.
|
||||||
/// The file type can usually be guessed from the colour of the file, but
|
/// The file type can usually be guessed from the colour of the file, but
|
||||||
/// ls puts this character there.
|
/// ls puts this character there.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn type_char(&self) -> f::Type {
|
pub fn type_char(&self) -> f::Type {
|
||||||
if self.is_file() {
|
if self.is_file() {
|
||||||
f::Type::File
|
f::Type::File
|
||||||
@ -401,7 +432,21 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn type_char(&self) -> f::Type {
|
||||||
|
if self.is_file() {
|
||||||
|
f::Type::File
|
||||||
|
}
|
||||||
|
else if self.is_directory() {
|
||||||
|
f::Type::Directory
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f::Type::Special
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This file’s permissions, with flags for each bit.
|
/// This file’s permissions, with flags for each bit.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn permissions(&self) -> f::Permissions {
|
pub fn permissions(&self) -> f::Permissions {
|
||||||
let bits = self.metadata.mode();
|
let bits = self.metadata.mode();
|
||||||
let has_bit = |bit| bits & bit == bit;
|
let has_bit = |bit| bits & bit == bit;
|
||||||
@ -425,6 +470,22 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn attributes(&self) -> f::Attributes {
|
||||||
|
let bits = self.metadata.file_attributes();
|
||||||
|
let has_bit = |bit| bits & bit == bit;
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||||
|
f::Attributes {
|
||||||
|
directory: has_bit(0x10),
|
||||||
|
archive: has_bit(0x20),
|
||||||
|
readonly: has_bit(0x1),
|
||||||
|
hidden: has_bit(0x2),
|
||||||
|
system: has_bit(0x4),
|
||||||
|
reparse_point: has_bit(0x400),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this file’s extension is any of the strings that get passed in.
|
/// Whether this file’s extension is any of the strings that get passed in.
|
||||||
///
|
///
|
||||||
/// This will always return `false` if the file has no extension.
|
/// This will always return `false` if the file has no extension.
|
||||||
@ -482,6 +543,7 @@ impl<'dir> FileTarget<'dir> {
|
|||||||
|
|
||||||
/// More readable aliases for the permission bits exposed by libc.
|
/// More readable aliases for the permission bits exposed by libc.
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
|
#[cfg(unix)]
|
||||||
mod modes {
|
mod modes {
|
||||||
|
|
||||||
// The `libc::mode_t` type’s actual type varies, but the value returned
|
// The `libc::mode_t` type’s actual type varies, but the value returned
|
||||||
@ -559,6 +621,7 @@ mod filename_test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(unix)]
|
||||||
fn topmost() {
|
fn topmost() {
|
||||||
assert_eq!("/", File::filename(Path::new("/")))
|
assert_eq!("/", File::filename(Path::new("/")))
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
use crate::fs::DotFilter;
|
use crate::fs::DotFilter;
|
||||||
@ -130,6 +131,7 @@ pub enum SortField {
|
|||||||
|
|
||||||
/// The file’s inode, which usually corresponds to the order in which
|
/// The file’s inode, which usually corresponds to the order in which
|
||||||
/// files were created on the filesystem, more or less.
|
/// files were created on the filesystem, more or less.
|
||||||
|
#[cfg(unix)]
|
||||||
FileInode,
|
FileInode,
|
||||||
|
|
||||||
/// The time the file was modified (the “mtime”).
|
/// The time the file was modified (the “mtime”).
|
||||||
@ -223,6 +225,7 @@ impl SortField {
|
|||||||
Self::Name(AaBbCc) => natord::compare_ignore_case(&a.name, &b.name),
|
Self::Name(AaBbCc) => natord::compare_ignore_case(&a.name, &b.name),
|
||||||
|
|
||||||
Self::Size => a.metadata.len().cmp(&b.metadata.len()),
|
Self::Size => a.metadata.len().cmp(&b.metadata.len()),
|
||||||
|
#[cfg(unix)]
|
||||||
Self::FileInode => a.metadata.ino().cmp(&b.metadata.ino()),
|
Self::FileInode => a.metadata.ino().cmp(&b.metadata.ino()),
|
||||||
Self::ModifiedDate => a.modified_time().cmp(&b.modified_time()),
|
Self::ModifiedDate => a.modified_time().cmp(&b.modified_time()),
|
||||||
Self::AccessedDate => a.accessed_time().cmp(&b.accessed_time()),
|
Self::AccessedDate => a.accessed_time().cmp(&b.accessed_time()),
|
||||||
|
@ -49,12 +49,18 @@ mod theme;
|
|||||||
fn main() {
|
fn main() {
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
|
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger::configure(env::var_os(vars::EXA_DEBUG));
|
logger::configure(env::var_os(vars::EXA_DEBUG));
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
if let Err(e) = ansi_term::enable_ansi_support() {
|
||||||
|
warn!("Failed to enable ANSI support: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
let args: Vec<_> = env::args_os().skip(1).collect();
|
let args: Vec<_> = env::args_os().skip(1).collect();
|
||||||
match Options::parse(args.iter().map(|e| e.as_ref()), &LiveVars) {
|
match Options::parse(args.iter().map(|e| e.as_ref()), &LiveVars) {
|
||||||
OptionsResult::Ok(options, mut input_paths) => {
|
OptionsResult::Ok(options, mut input_paths) => {
|
||||||
|
@ -88,6 +88,7 @@ impl SortField {
|
|||||||
"cr" | "created" => {
|
"cr" | "created" => {
|
||||||
Self::CreatedDate
|
Self::CreatedDate
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
"inode" => {
|
"inode" => {
|
||||||
Self::FileInode
|
Self::FileInode
|
||||||
}
|
}
|
||||||
|
@ -146,8 +146,6 @@ impl Args {
|
|||||||
pub fn parse<'args, I>(&self, inputs: I, strictness: Strictness) -> Result<Matches<'args>, ParseError>
|
pub fn parse<'args, I>(&self, inputs: I, strictness: Strictness) -> Result<Matches<'args>, ParseError>
|
||||||
where I: IntoIterator<Item = &'args OsStr>
|
where I: IntoIterator<Item = &'args OsStr>
|
||||||
{
|
{
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
|
|
||||||
let mut parsing = true;
|
let mut parsing = true;
|
||||||
|
|
||||||
// The results that get built up.
|
// The results that get built up.
|
||||||
@ -159,7 +157,7 @@ impl Args {
|
|||||||
// doesn’t have one in its string so it needs the next one.
|
// doesn’t have one in its string so it needs the next one.
|
||||||
let mut inputs = inputs.into_iter();
|
let mut inputs = inputs.into_iter();
|
||||||
while let Some(arg) = inputs.next() {
|
while let Some(arg) = inputs.next() {
|
||||||
let bytes = arg.as_bytes();
|
let bytes = os_str_to_bytes(arg);
|
||||||
|
|
||||||
// Stop parsing if one of the arguments is the literal string “--”.
|
// Stop parsing if one of the arguments is the literal string “--”.
|
||||||
// This allows a file named “--arg” to be specified by passing in
|
// This allows a file named “--arg” to be specified by passing in
|
||||||
@ -174,7 +172,7 @@ impl Args {
|
|||||||
|
|
||||||
// If the string starts with *two* dashes then it’s a long argument.
|
// If the string starts with *two* dashes then it’s a long argument.
|
||||||
else if bytes.starts_with(b"--") {
|
else if bytes.starts_with(b"--") {
|
||||||
let long_arg_name = OsStr::from_bytes(&bytes[2..]);
|
let long_arg_name = bytes_to_os_str(&bytes[2..]);
|
||||||
|
|
||||||
// If there’s an equals in it, then the string before the
|
// If there’s an equals in it, then the string before the
|
||||||
// equals will be the flag’s name, and the string after it
|
// equals will be the flag’s name, and the string after it
|
||||||
@ -221,7 +219,7 @@ impl Args {
|
|||||||
// If the string starts with *one* dash then it’s one or more
|
// If the string starts with *one* dash then it’s one or more
|
||||||
// short arguments.
|
// short arguments.
|
||||||
else if bytes.starts_with(b"-") && arg != "-" {
|
else if bytes.starts_with(b"-") && arg != "-" {
|
||||||
let short_arg = OsStr::from_bytes(&bytes[1..]);
|
let short_arg = bytes_to_os_str(&bytes[1..]);
|
||||||
|
|
||||||
// If there’s an equals in it, then the argument immediately
|
// If there’s an equals in it, then the argument immediately
|
||||||
// before the equals was the one that has the value, with the
|
// before the equals was the one that has the value, with the
|
||||||
@ -236,7 +234,7 @@ impl Args {
|
|||||||
// it’s an error if any of the first set of arguments actually
|
// it’s an error if any of the first set of arguments actually
|
||||||
// takes a value.
|
// takes a value.
|
||||||
if let Some((before, after)) = split_on_equals(short_arg) {
|
if let Some((before, after)) = split_on_equals(short_arg) {
|
||||||
let (arg_with_value, other_args) = before.as_bytes().split_last().unwrap();
|
let (arg_with_value, other_args) = os_str_to_bytes(before).split_last().unwrap();
|
||||||
|
|
||||||
// Process the characters immediately following the dash...
|
// Process the characters immediately following the dash...
|
||||||
for byte in other_args {
|
for byte in other_args {
|
||||||
@ -291,7 +289,7 @@ impl Args {
|
|||||||
TakesValue::Optional(values) => {
|
TakesValue::Optional(values) => {
|
||||||
if index < bytes.len() - 1 {
|
if index < bytes.len() - 1 {
|
||||||
let remnants = &bytes[index+1 ..];
|
let remnants = &bytes[index+1 ..];
|
||||||
result_flags.push((flag, Some(OsStr::from_bytes(remnants))));
|
result_flags.push((flag, Some(bytes_to_os_str(remnants))));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if let Some(next_arg) = inputs.next() {
|
else if let Some(next_arg) = inputs.next() {
|
||||||
@ -495,19 +493,42 @@ impl fmt::Display for ParseError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn os_str_to_bytes<'b>(s: &'b OsStr) -> &'b [u8]{
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
|
return s.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn bytes_to_os_str<'b>(b: &'b [u8]) -> &'b OsStr{
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
|
return OsStr::from_bytes(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn os_str_to_bytes<'b>(s: &'b OsStr) -> &'b [u8]{
|
||||||
|
return s.to_str().unwrap().as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn bytes_to_os_str<'b>(b: &'b [u8]) -> &'b OsStr{
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
return OsStr::new(str::from_utf8(b).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
/// Splits a string on its `=` character, returning the two substrings on
|
/// Splits a string on its `=` character, returning the two substrings on
|
||||||
/// either side. Returns `None` if there’s no equals or a string is missing.
|
/// either side. Returns `None` if there’s no equals or a string is missing.
|
||||||
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
|
fn split_on_equals(input: &OsStr) -> Option<(&OsStr, &OsStr)> {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
if let Some(index) = os_str_to_bytes(input).iter().position(|elem| *elem == b'=') {
|
||||||
|
let (before, after) = os_str_to_bytes(input).split_at(index);
|
||||||
if let Some(index) = input.as_bytes().iter().position(|elem| *elem == b'=') {
|
|
||||||
let (before, after) = input.as_bytes().split_at(index);
|
|
||||||
|
|
||||||
// The after string contains the = that we need to remove.
|
// The after string contains the = that we need to remove.
|
||||||
if ! before.is_empty() && after.len() >= 2 {
|
if ! before.is_empty() && after.len() >= 2 {
|
||||||
return Some((OsStr::from_bytes(before),
|
return Some((bytes_to_os_str(before),
|
||||||
OsStr::from_bytes(&after[1..])))
|
bytes_to_os_str(&after[1..])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
|
|||||||
let coconut = parent.components().count();
|
let coconut = parent.components().count();
|
||||||
|
|
||||||
if coconut == 1 && parent.has_root() {
|
if coconut == 1 && parent.has_root() {
|
||||||
bits.push(self.colours.symlink_path().paint("/"));
|
bits.push(self.colours.symlink_path().paint(std::path::MAIN_SEPARATOR.to_string()));
|
||||||
}
|
}
|
||||||
else if coconut >= 1 {
|
else if coconut >= 1 {
|
||||||
escape(
|
escape(
|
||||||
@ -235,12 +235,13 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
|
|||||||
self.colours.symlink_path(),
|
self.colours.symlink_path(),
|
||||||
self.colours.control_char(),
|
self.colours.control_char(),
|
||||||
);
|
);
|
||||||
bits.push(self.colours.symlink_path().paint("/"));
|
bits.push(self.colours.symlink_path().paint(std::path::MAIN_SEPARATOR.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The character to be displayed after a file when classifying is on, if
|
/// The character to be displayed after a file when classifying is on, if
|
||||||
/// the file’s type has one associated with it.
|
/// the file’s type has one associated with it.
|
||||||
|
#[cfg(unix)]
|
||||||
fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
|
fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
|
||||||
if file.is_executable_file() {
|
if file.is_executable_file() {
|
||||||
Some("*")
|
Some("*")
|
||||||
@ -262,6 +263,19 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
|
||||||
|
if file.is_directory() {
|
||||||
|
Some("/")
|
||||||
|
}
|
||||||
|
else if file.is_link() {
|
||||||
|
Some("@")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns at least one ANSI-highlighted string representing this file’s
|
/// Returns at least one ANSI-highlighted string representing this file’s
|
||||||
/// name using the given set of colours.
|
/// name using the given set of colours.
|
||||||
///
|
///
|
||||||
@ -301,11 +315,16 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
|
|||||||
|
|
||||||
match self.file {
|
match self.file {
|
||||||
f if f.is_directory() => self.colours.directory(),
|
f if f.is_directory() => self.colours.directory(),
|
||||||
|
#[cfg(unix)]
|
||||||
f if f.is_executable_file() => self.colours.executable_file(),
|
f if f.is_executable_file() => self.colours.executable_file(),
|
||||||
f if f.is_link() => self.colours.symlink(),
|
f if f.is_link() => self.colours.symlink(),
|
||||||
|
#[cfg(unix)]
|
||||||
f if f.is_pipe() => self.colours.pipe(),
|
f if f.is_pipe() => self.colours.pipe(),
|
||||||
|
#[cfg(unix)]
|
||||||
f if f.is_block_device() => self.colours.block_device(),
|
f if f.is_block_device() => self.colours.block_device(),
|
||||||
|
#[cfg(unix)]
|
||||||
f if f.is_char_device() => self.colours.char_device(),
|
f if f.is_char_device() => self.colours.char_device(),
|
||||||
|
#[cfg(unix)]
|
||||||
f if f.is_socket() => self.colours.socket(),
|
f if f.is_socket() => self.colours.socket(),
|
||||||
f if ! f.is_file() => self.colours.special(),
|
f if ! f.is_file() => self.colours.special(),
|
||||||
_ => self.colours.colour_file(self.file),
|
_ => self.colours.colour_file(self.file),
|
||||||
|
@ -7,7 +7,9 @@ pub use self::filetype::Colours as FiletypeColours;
|
|||||||
mod git;
|
mod git;
|
||||||
pub use self::git::Colours as GitColours;
|
pub use self::git::Colours as GitColours;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
mod groups;
|
mod groups;
|
||||||
|
#[cfg(unix)]
|
||||||
pub use self::groups::Colours as GroupColours;
|
pub use self::groups::Colours as GroupColours;
|
||||||
|
|
||||||
mod inode;
|
mod inode;
|
||||||
@ -26,7 +28,9 @@ mod times;
|
|||||||
pub use self::times::Render as TimeRender;
|
pub use self::times::Render as TimeRender;
|
||||||
// times does too
|
// times does too
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
mod users;
|
mod users;
|
||||||
|
#[cfg(unix)]
|
||||||
pub use self::users::Colours as UserColours;
|
pub use self::users::Colours as UserColours;
|
||||||
|
|
||||||
mod octal;
|
mod octal;
|
||||||
|
@ -6,6 +6,7 @@ use crate::output::render::FiletypeColours;
|
|||||||
|
|
||||||
|
|
||||||
impl f::PermissionsPlus {
|
impl f::PermissionsPlus {
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
|
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
|
||||||
let mut chars = vec![ self.file_type.render(colours) ];
|
let mut chars = vec![ self.file_type.render(colours) ];
|
||||||
chars.extend(self.permissions.render(colours, self.file_type.is_regular_file()));
|
chars.extend(self.permissions.render(colours, self.file_type.is_regular_file()));
|
||||||
@ -22,6 +23,17 @@ impl f::PermissionsPlus {
|
|||||||
contents: chars.into(),
|
contents: chars.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
|
||||||
|
let mut chars = vec![ self.attributes.render_type(colours) ];
|
||||||
|
chars.extend(self.attributes.render(colours));
|
||||||
|
|
||||||
|
TextCell {
|
||||||
|
width: DisplayWidth::from(chars.len()),
|
||||||
|
contents: chars.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -76,6 +88,33 @@ impl f::Permissions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl f::Attributes {
|
||||||
|
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> Vec<ANSIString<'static>> {
|
||||||
|
let bit = |bit, chr: &'static str, style: Style| {
|
||||||
|
if bit { style.paint(chr) }
|
||||||
|
else { colours.dash().paint("-") }
|
||||||
|
};
|
||||||
|
|
||||||
|
vec![
|
||||||
|
bit(self.archive, "a", colours.normal()),
|
||||||
|
bit(self.readonly, "r", colours.user_read()),
|
||||||
|
bit(self.hidden, "h", colours.special_user_file()),
|
||||||
|
bit(self.system, "s", colours.special_other()),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_type<C: Colours+FiletypeColours>(&self, colours: &C) -> ANSIString<'static> {
|
||||||
|
if self.reparse_point {
|
||||||
|
return colours.pipe().paint("l")
|
||||||
|
}
|
||||||
|
else if self.directory {
|
||||||
|
return colours.directory().paint("d")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return colours.dash().paint("-")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Colours {
|
pub trait Colours {
|
||||||
fn dash(&self) -> Style;
|
fn dash(&self) -> Style;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
#[cfg(unix)]
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
use datetime::TimeZone;
|
use datetime::TimeZone;
|
||||||
@ -8,6 +9,7 @@ use zoneinfo_compiled::{CompiledData, Result as TZResult};
|
|||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
#[cfg(unix)]
|
||||||
use users::UsersCache;
|
use users::UsersCache;
|
||||||
|
|
||||||
use crate::fs::{File, fields as f};
|
use crate::fs::{File, fields as f};
|
||||||
@ -54,10 +56,12 @@ impl Columns {
|
|||||||
let mut columns = Vec::with_capacity(4);
|
let mut columns = Vec::with_capacity(4);
|
||||||
|
|
||||||
if self.inode {
|
if self.inode {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::Inode);
|
columns.push(Column::Inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.octal {
|
if self.octal {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::Octal);
|
columns.push(Column::Octal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +70,7 @@ impl Columns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.links {
|
if self.links {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::HardLinks);
|
columns.push(Column::HardLinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,14 +79,17 @@ impl Columns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.blocks {
|
if self.blocks {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::Blocks);
|
columns.push(Column::Blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.user {
|
if self.user {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::User);
|
columns.push(Column::User);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.group {
|
if self.group {
|
||||||
|
#[cfg(unix)]
|
||||||
columns.push(Column::Group);
|
columns.push(Column::Group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,12 +124,18 @@ pub enum Column {
|
|||||||
Permissions,
|
Permissions,
|
||||||
FileSize,
|
FileSize,
|
||||||
Timestamp(TimeType),
|
Timestamp(TimeType),
|
||||||
|
#[cfg(unix)]
|
||||||
Blocks,
|
Blocks,
|
||||||
|
#[cfg(unix)]
|
||||||
User,
|
User,
|
||||||
|
#[cfg(unix)]
|
||||||
Group,
|
Group,
|
||||||
|
#[cfg(unix)]
|
||||||
HardLinks,
|
HardLinks,
|
||||||
|
#[cfg(unix)]
|
||||||
Inode,
|
Inode,
|
||||||
GitStatus,
|
GitStatus,
|
||||||
|
#[cfg(unix)]
|
||||||
Octal,
|
Octal,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +150,7 @@ pub enum Alignment {
|
|||||||
impl Column {
|
impl Column {
|
||||||
|
|
||||||
/// Get the alignment this column should use.
|
/// Get the alignment this column should use.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn alignment(self) -> Alignment {
|
pub fn alignment(self) -> Alignment {
|
||||||
match self {
|
match self {
|
||||||
Self::FileSize |
|
Self::FileSize |
|
||||||
@ -147,19 +162,37 @@ impl Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn alignment(&self) -> Alignment {
|
||||||
|
match self {
|
||||||
|
Self::FileSize |
|
||||||
|
Self::GitStatus => Alignment::Right,
|
||||||
|
_ => Alignment::Left,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the text that should be printed at the top, when the user elects
|
/// Get the text that should be printed at the top, when the user elects
|
||||||
/// to have a header row printed.
|
/// to have a header row printed.
|
||||||
pub fn header(self) -> &'static str {
|
pub fn header(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(unix)]
|
||||||
Self::Permissions => "Permissions",
|
Self::Permissions => "Permissions",
|
||||||
|
#[cfg(windows)]
|
||||||
|
Self::Permissions => "Mode",
|
||||||
Self::FileSize => "Size",
|
Self::FileSize => "Size",
|
||||||
Self::Timestamp(t) => t.header(),
|
Self::Timestamp(t) => t.header(),
|
||||||
|
#[cfg(unix)]
|
||||||
Self::Blocks => "Blocks",
|
Self::Blocks => "Blocks",
|
||||||
|
#[cfg(unix)]
|
||||||
Self::User => "User",
|
Self::User => "User",
|
||||||
|
#[cfg(unix)]
|
||||||
Self::Group => "Group",
|
Self::Group => "Group",
|
||||||
|
#[cfg(unix)]
|
||||||
Self::HardLinks => "Links",
|
Self::HardLinks => "Links",
|
||||||
|
#[cfg(unix)]
|
||||||
Self::Inode => "inode",
|
Self::Inode => "inode",
|
||||||
Self::GitStatus => "Git",
|
Self::GitStatus => "Git",
|
||||||
|
#[cfg(unix)]
|
||||||
Self::Octal => "Octal",
|
Self::Octal => "Octal",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,10 +307,12 @@ pub struct Environment {
|
|||||||
tz: Option<TimeZone>,
|
tz: Option<TimeZone>,
|
||||||
|
|
||||||
/// Mapping cache of user IDs to usernames.
|
/// Mapping cache of user IDs to usernames.
|
||||||
|
#[cfg(unix)]
|
||||||
users: Mutex<UsersCache>,
|
users: Mutex<UsersCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn lock_users(&self) -> MutexGuard<'_, UsersCache> {
|
pub fn lock_users(&self) -> MutexGuard<'_, UsersCache> {
|
||||||
self.users.lock().unwrap()
|
self.users.lock().unwrap()
|
||||||
}
|
}
|
||||||
@ -296,12 +331,14 @@ impl Environment {
|
|||||||
let numeric = locale::Numeric::load_user_locale()
|
let numeric = locale::Numeric::load_user_locale()
|
||||||
.unwrap_or_else(|_| locale::Numeric::english());
|
.unwrap_or_else(|_| locale::Numeric::english());
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
let users = Mutex::new(UsersCache::new());
|
let users = Mutex::new(UsersCache::new());
|
||||||
|
|
||||||
Self { numeric, tz, users }
|
Self { numeric, tz, #[cfg(unix)] users }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
fn determine_time_zone() -> TZResult<TimeZone> {
|
fn determine_time_zone() -> TZResult<TimeZone> {
|
||||||
if let Ok(file) = env::var("TZ") {
|
if let Ok(file) = env::var("TZ") {
|
||||||
TimeZone::from_file({
|
TimeZone::from_file({
|
||||||
@ -322,6 +359,31 @@ fn determine_time_zone() -> TZResult<TimeZone> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn determine_time_zone() -> TZResult<TimeZone> {
|
||||||
|
use datetime::zone::{FixedTimespan, FixedTimespanSet, StaticTimeZone, TimeZoneSource};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
Ok(TimeZone(TimeZoneSource::Static(&StaticTimeZone {
|
||||||
|
name: "Unsupported",
|
||||||
|
fixed_timespans: FixedTimespanSet {
|
||||||
|
first: FixedTimespan {
|
||||||
|
offset: 0,
|
||||||
|
is_dst: false,
|
||||||
|
name: Cow::Borrowed("ZONE_A"),
|
||||||
|
},
|
||||||
|
rest: &[(
|
||||||
|
1206838800,
|
||||||
|
FixedTimespan {
|
||||||
|
offset: 3600,
|
||||||
|
is_dst: false,
|
||||||
|
name: Cow::Borrowed("ZONE_B"),
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
},
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ENVIRONMENT: Environment = Environment::load_all();
|
static ref ENVIRONMENT: Environment = Environment::load_all();
|
||||||
}
|
}
|
||||||
@ -388,11 +450,15 @@ impl<'a, 'f> Table<'a> {
|
|||||||
fn permissions_plus(&self, file: &File<'_>, xattrs: bool) -> f::PermissionsPlus {
|
fn permissions_plus(&self, file: &File<'_>, xattrs: bool) -> f::PermissionsPlus {
|
||||||
f::PermissionsPlus {
|
f::PermissionsPlus {
|
||||||
file_type: file.type_char(),
|
file_type: file.type_char(),
|
||||||
|
#[cfg(unix)]
|
||||||
permissions: file.permissions(),
|
permissions: file.permissions(),
|
||||||
|
#[cfg(windows)]
|
||||||
|
attributes: file.attributes(),
|
||||||
xattrs,
|
xattrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
fn octal_permissions(&self, file: &File<'_>) -> f::OctalPermissions {
|
fn octal_permissions(&self, file: &File<'_>) -> f::OctalPermissions {
|
||||||
f::OctalPermissions {
|
f::OctalPermissions {
|
||||||
permissions: file.permissions(),
|
permissions: file.permissions(),
|
||||||
@ -407,24 +473,30 @@ impl<'a, 'f> Table<'a> {
|
|||||||
Column::FileSize => {
|
Column::FileSize => {
|
||||||
file.size().render(self.theme, self.size_format, &self.env.numeric)
|
file.size().render(self.theme, self.size_format, &self.env.numeric)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::HardLinks => {
|
Column::HardLinks => {
|
||||||
file.links().render(self.theme, &self.env.numeric)
|
file.links().render(self.theme, &self.env.numeric)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::Inode => {
|
Column::Inode => {
|
||||||
file.inode().render(self.theme.ui.inode)
|
file.inode().render(self.theme.ui.inode)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::Blocks => {
|
Column::Blocks => {
|
||||||
file.blocks().render(self.theme)
|
file.blocks().render(self.theme)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::User => {
|
Column::User => {
|
||||||
file.user().render(self.theme, &*self.env.lock_users(), self.user_format)
|
file.user().render(self.theme, &*self.env.lock_users(), self.user_format)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::Group => {
|
Column::Group => {
|
||||||
file.group().render(self.theme, &*self.env.lock_users(), self.user_format)
|
file.group().render(self.theme, &*self.env.lock_users(), self.user_format)
|
||||||
}
|
}
|
||||||
Column::GitStatus => {
|
Column::GitStatus => {
|
||||||
self.git_status(file).render(self.theme)
|
self.git_status(file).render(self.theme)
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
Column::Octal => {
|
Column::Octal => {
|
||||||
self.octal_permissions(file).render(self.theme.ui.octal)
|
self.octal_permissions(file).render(self.theme.ui.octal)
|
||||||
}
|
}
|
||||||
|
@ -229,6 +229,7 @@ impl render::GitColours for Theme {
|
|||||||
fn conflicted(&self) -> Style { self.ui.git.conflicted }
|
fn conflicted(&self) -> Style { self.ui.git.conflicted }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
impl render::GroupColours for Theme {
|
impl render::GroupColours for Theme {
|
||||||
fn yours(&self) -> Style { self.ui.users.group_yours }
|
fn yours(&self) -> Style { self.ui.users.group_yours }
|
||||||
fn not_yours(&self) -> Style { self.ui.users.group_not_yours }
|
fn not_yours(&self) -> Style { self.ui.users.group_not_yours }
|
||||||
@ -287,6 +288,7 @@ impl render::SizeColours for Theme {
|
|||||||
fn minor(&self) -> Style { self.ui.size.minor }
|
fn minor(&self) -> Style { self.ui.size.minor }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
impl render::UserColours for Theme {
|
impl render::UserColours for Theme {
|
||||||
fn you(&self) -> Style { self.ui.users.user_you }
|
fn you(&self) -> Style { self.ui.users.user_you }
|
||||||
fn someone_else(&self) -> Style { self.ui.users.user_someone_else }
|
fn someone_else(&self) -> Style { self.ui.users.user_someone_else }
|
||||||
|
Loading…
Reference in New Issue
Block a user