2016-04-17 19:38:37 +00:00
|
|
|
|
use std::env::var_os;
|
|
|
|
|
|
|
|
|
|
use output::Colours;
|
2017-07-24 07:34:50 +00:00
|
|
|
|
use output::{View, Mode, grid, details};
|
2017-07-05 20:01:01 +00:00
|
|
|
|
use output::table::{TimeTypes, Environment, SizeFormat, Options as TableOptions};
|
2017-07-08 11:11:11 +00:00
|
|
|
|
use output::file_name::{Classify, FileStyle};
|
2017-07-05 23:01:45 +00:00
|
|
|
|
use output::time::TimeFormat;
|
2017-07-26 16:48:18 +00:00
|
|
|
|
|
|
|
|
|
use options::{flags, Misfire};
|
|
|
|
|
use options::parser::Matches;
|
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
use fs::feature::xattr;
|
2017-07-26 16:48:18 +00:00
|
|
|
|
use info::filetype::FileExtensions;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
|
2017-06-25 11:31:46 +00:00
|
|
|
|
impl View {
|
|
|
|
|
|
|
|
|
|
/// Determine which view to use and all of that view’s arguments.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
pub fn deduce(matches: &Matches) -> Result<View, Misfire> {
|
2017-07-08 11:11:11 +00:00
|
|
|
|
let mode = Mode::deduce(matches)?;
|
|
|
|
|
let colours = Colours::deduce(matches)?;
|
|
|
|
|
let style = FileStyle::deduce(matches);
|
|
|
|
|
Ok(View { mode, colours, style })
|
2017-06-25 11:31:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Mode {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
2017-06-25 13:59:38 +00:00
|
|
|
|
/// Determine the mode from the command-line arguments.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
pub fn deduce(matches: &Matches) -> Result<Mode, Misfire> {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
use options::misfire::Misfire::*;
|
|
|
|
|
|
|
|
|
|
let long = || {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if matches.has(&flags::ACROSS) && !matches.has(&flags::GRID) {
|
|
|
|
|
Err(Useless(&flags::ACROSS, true, &flags::LONG))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
2017-07-26 16:48:18 +00:00
|
|
|
|
else if matches.has(&flags::ONE_LINE) {
|
|
|
|
|
Err(Useless(&flags::ONE_LINE, true, &flags::LONG))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-26 07:38:56 +00:00
|
|
|
|
Ok(details::Options {
|
2017-07-05 20:01:01 +00:00
|
|
|
|
table: Some(TableOptions::deduce(matches)?),
|
2017-07-26 16:48:18 +00:00
|
|
|
|
header: matches.has(&flags::HEADER),
|
|
|
|
|
xattr: xattr::ENABLED && matches.has(&flags::EXTENDED),
|
2017-06-26 07:38:56 +00:00
|
|
|
|
})
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let long_options_scan = || {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
|
|
|
|
|
&flags::HEADER, &flags::BLOCKS, &flags::TIME, &flags::GROUP ] {
|
|
|
|
|
if matches.has(option) {
|
|
|
|
|
return Err(Useless(*option, false, &flags::LONG));
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if cfg!(feature="git") && matches.has(&flags::GIT) {
|
|
|
|
|
Err(Useless(&flags::GIT, false, &flags::LONG))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
2017-07-26 16:48:18 +00:00
|
|
|
|
else if matches.has(&flags::LEVEL) && !matches.has(&flags::RECURSE) && !matches.has(&flags::TREE) {
|
|
|
|
|
Err(Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
2017-07-26 16:48:18 +00:00
|
|
|
|
else if xattr::ENABLED && matches.has(&flags::EXTENDED) {
|
|
|
|
|
Err(Useless(&flags::EXTENDED, false, &flags::LONG))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let other_options_scan = || {
|
2017-06-25 13:51:44 +00:00
|
|
|
|
if let Some(width) = TerminalWidth::deduce()?.width() {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if matches.has(&flags::ONE_LINE) {
|
|
|
|
|
if matches.has(&flags::ACROSS) {
|
|
|
|
|
Err(Useless(&flags::ACROSS, true, &flags::ONE_LINE))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-25 13:59:38 +00:00
|
|
|
|
Ok(Mode::Lines)
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-26 16:48:18 +00:00
|
|
|
|
else if matches.has(&flags::TREE) {
|
2017-06-25 23:53:48 +00:00
|
|
|
|
let details = details::Options {
|
2017-07-05 20:01:01 +00:00
|
|
|
|
table: None,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
header: false,
|
|
|
|
|
xattr: false,
|
|
|
|
|
};
|
|
|
|
|
|
2017-06-25 13:59:38 +00:00
|
|
|
|
Ok(Mode::Details(details))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-25 23:53:48 +00:00
|
|
|
|
let grid = grid::Options {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
across: matches.has(&flags::ACROSS),
|
2016-04-17 19:38:37 +00:00
|
|
|
|
console_width: width,
|
|
|
|
|
};
|
|
|
|
|
|
2017-06-25 13:59:38 +00:00
|
|
|
|
Ok(Mode::Grid(grid))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// If the terminal width couldn’t be matched for some reason, such
|
|
|
|
|
// as the program’s stdout being connected to a file, then
|
|
|
|
|
// fallback to the lines view.
|
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if matches.has(&flags::TREE) {
|
2017-06-25 23:53:48 +00:00
|
|
|
|
let details = details::Options {
|
2017-07-05 20:01:01 +00:00
|
|
|
|
table: None,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
header: false,
|
|
|
|
|
xattr: false,
|
|
|
|
|
};
|
|
|
|
|
|
2017-06-25 13:59:38 +00:00
|
|
|
|
Ok(Mode::Details(details))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-25 13:59:38 +00:00
|
|
|
|
Ok(Mode::Lines)
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if matches.has(&flags::LONG) {
|
2017-06-26 07:38:56 +00:00
|
|
|
|
let details = long()?;
|
2017-07-26 16:48:18 +00:00
|
|
|
|
if matches.has(&flags::GRID) {
|
2017-06-26 07:38:56 +00:00
|
|
|
|
match other_options_scan()? {
|
|
|
|
|
Mode::Grid(grid) => return Ok(Mode::GridDetails(grid, details)),
|
|
|
|
|
others => return Ok(others),
|
|
|
|
|
};
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-06-26 07:38:56 +00:00
|
|
|
|
return Ok(Mode::Details(details));
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-26 16:35:50 +00:00
|
|
|
|
long_options_scan()?;
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
other_options_scan()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// The width of the terminal requested by the user.
|
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
|
enum TerminalWidth {
|
|
|
|
|
|
|
|
|
|
/// The user requested this specific number of columns.
|
|
|
|
|
Set(usize),
|
|
|
|
|
|
|
|
|
|
/// The terminal was found to have this number of columns.
|
|
|
|
|
Terminal(usize),
|
|
|
|
|
|
|
|
|
|
/// The user didn’t request any particular terminal width.
|
|
|
|
|
Unset,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TerminalWidth {
|
|
|
|
|
|
|
|
|
|
/// Determine a requested terminal width from the command-line arguments.
|
|
|
|
|
///
|
|
|
|
|
/// Returns an error if a requested width doesn’t parse to an integer.
|
2016-04-17 20:01:30 +00:00
|
|
|
|
fn deduce() -> Result<TerminalWidth, Misfire> {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
if let Some(columns) = var_os("COLUMNS").and_then(|s| s.into_string().ok()) {
|
|
|
|
|
match columns.parse() {
|
|
|
|
|
Ok(width) => Ok(TerminalWidth::Set(width)),
|
|
|
|
|
Err(e) => Err(Misfire::FailedParse(e)),
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-25 13:51:44 +00:00
|
|
|
|
else if let Some(width) = *TERM_WIDTH {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
Ok(TerminalWidth::Terminal(width))
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Ok(TerminalWidth::Unset)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-25 11:49:22 +00:00
|
|
|
|
fn width(&self) -> Option<usize> {
|
2016-04-17 19:38:37 +00:00
|
|
|
|
match *self {
|
2017-06-25 11:49:22 +00:00
|
|
|
|
TerminalWidth::Set(width) |
|
|
|
|
|
TerminalWidth::Terminal(width) => Some(width),
|
|
|
|
|
TerminalWidth::Unset => None,
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-05 19:16:04 +00:00
|
|
|
|
impl TableOptions {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<Self, Misfire> {
|
2017-07-05 19:16:04 +00:00
|
|
|
|
Ok(TableOptions {
|
2017-07-05 20:01:01 +00:00
|
|
|
|
env: Environment::load_all(),
|
2017-07-05 22:27:48 +00:00
|
|
|
|
time_format: TimeFormat::deduce(matches)?,
|
2017-03-26 16:35:50 +00:00
|
|
|
|
size_format: SizeFormat::deduce(matches)?,
|
|
|
|
|
time_types: TimeTypes::deduce(matches)?,
|
2017-07-26 16:48:18 +00:00
|
|
|
|
inode: matches.has(&flags::INODE),
|
|
|
|
|
links: matches.has(&flags::LINKS),
|
|
|
|
|
blocks: matches.has(&flags::BLOCKS),
|
|
|
|
|
group: matches.has(&flags::GROUP),
|
|
|
|
|
git: cfg!(feature="git") && matches.has(&flags::GIT),
|
2016-04-17 19:38:37 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl SizeFormat {
|
|
|
|
|
|
|
|
|
|
/// Determine which file size to use in the file size column based on
|
|
|
|
|
/// the user’s options.
|
|
|
|
|
///
|
|
|
|
|
/// The default mode is to use the decimal prefixes, as they are the
|
|
|
|
|
/// most commonly-understood, and don’t involve trying to parse large
|
|
|
|
|
/// strings of digits in your head. Changing the format to anything else
|
|
|
|
|
/// involves the `--binary` or `--bytes` flags, and these conflict with
|
|
|
|
|
/// each other.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<SizeFormat, Misfire> {
|
|
|
|
|
let binary = matches.has(&flags::BINARY);
|
|
|
|
|
let bytes = matches.has(&flags::BYTES);
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
match (binary, bytes) {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
(true, true ) => Err(Misfire::Conflict(&flags::BINARY, &flags::BYTES)),
|
2016-04-17 19:38:37 +00:00
|
|
|
|
(true, false) => Ok(SizeFormat::BinaryBytes),
|
|
|
|
|
(false, true ) => Ok(SizeFormat::JustBytes),
|
|
|
|
|
(false, false) => Ok(SizeFormat::DecimalBytes),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-05 22:27:48 +00:00
|
|
|
|
impl TimeFormat {
|
|
|
|
|
|
|
|
|
|
/// Determine how time should be formatted in timestamp columns.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<TimeFormat, Misfire> {
|
2017-07-05 23:39:54 +00:00
|
|
|
|
pub use output::time::{DefaultFormat, ISOFormat};
|
|
|
|
|
const STYLES: &[&str] = &["default", "long-iso", "full-iso", "iso"];
|
2017-07-05 23:01:45 +00:00
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
let word = match matches.get(&flags::TIME_STYLE) {
|
|
|
|
|
Some(w) => w,
|
|
|
|
|
None => return Ok(TimeFormat::DefaultFormat(DefaultFormat::new())),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if word == "default" {
|
|
|
|
|
Ok(TimeFormat::DefaultFormat(DefaultFormat::new()))
|
|
|
|
|
}
|
|
|
|
|
else if word == "iso" {
|
|
|
|
|
Ok(TimeFormat::ISOFormat(ISOFormat::new()))
|
|
|
|
|
}
|
|
|
|
|
else if word == "long-iso" {
|
|
|
|
|
Ok(TimeFormat::LongISO)
|
|
|
|
|
}
|
|
|
|
|
else if word == "full-iso" {
|
|
|
|
|
Ok(TimeFormat::FullISO)
|
2017-07-05 23:01:45 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
Err(Misfire::bad_argument(&flags::TIME_STYLE, word, STYLES))
|
2017-07-05 23:01:45 +00:00
|
|
|
|
}
|
2017-07-05 22:27:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-17 19:38:37 +00:00
|
|
|
|
impl TimeTypes {
|
|
|
|
|
|
|
|
|
|
/// Determine which of a file’s time fields should be displayed for it
|
|
|
|
|
/// based on the user’s options.
|
|
|
|
|
///
|
|
|
|
|
/// There are two separate ways to pick which fields to show: with a
|
|
|
|
|
/// flag (such as `--modified`) or with a parameter (such as
|
|
|
|
|
/// `--time=modified`). An error is signaled if both ways are used.
|
|
|
|
|
///
|
|
|
|
|
/// It’s valid to show more than one column by passing in more than one
|
|
|
|
|
/// option, but passing *no* options means that the user just wants to
|
|
|
|
|
/// see the default set.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<TimeTypes, Misfire> {
|
|
|
|
|
let possible_word = matches.get(&flags::TIME);
|
|
|
|
|
let modified = matches.has(&flags::MODIFIED);
|
|
|
|
|
let created = matches.has(&flags::CREATED);
|
|
|
|
|
let accessed = matches.has(&flags::ACCESSED);
|
2016-04-17 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
if let Some(word) = possible_word {
|
|
|
|
|
if modified {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
return Err(Misfire::Useless(&flags::MODIFIED, true, &flags::TIME));
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else if created {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
return Err(Misfire::Useless(&flags::CREATED, true, &flags::TIME));
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else if accessed {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
return Err(Misfire::Useless(&flags::ACCESSED, true, &flags::TIME));
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
static TIMES: &[&str] = &["modified", "accessed", "created"];
|
|
|
|
|
if word == "mod" || word == "modified" {
|
|
|
|
|
Ok(TimeTypes { accessed: false, modified: true, created: false })
|
|
|
|
|
}
|
|
|
|
|
else if word == "acc" || word == "accessed" {
|
|
|
|
|
Ok(TimeTypes { accessed: true, modified: false, created: false })
|
|
|
|
|
}
|
|
|
|
|
else if word == "cr" || word == "created" {
|
|
|
|
|
Ok(TimeTypes { accessed: false, modified: false, created: true })
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Err(Misfire::bad_argument(&flags::TIME, word, TIMES))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if modified || created || accessed {
|
2017-05-18 21:43:32 +00:00
|
|
|
|
Ok(TimeTypes { accessed, modified, created })
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Ok(TimeTypes::default())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Under what circumstances we should display coloured, rather than plain,
|
|
|
|
|
/// output to the terminal.
|
|
|
|
|
///
|
|
|
|
|
/// By default, we want to display the colours when stdout can display them.
|
|
|
|
|
/// Turning them on when output is going to, say, a pipe, would make programs
|
|
|
|
|
/// such as `grep` or `more` not work properly. So the `Automatic` mode does
|
|
|
|
|
/// this check and only displays colours when they can be truly appreciated.
|
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
|
enum TerminalColours {
|
|
|
|
|
|
|
|
|
|
/// Display them even when output isn’t going to a terminal.
|
|
|
|
|
Always,
|
|
|
|
|
|
|
|
|
|
/// Display them when output is going to a terminal, but not otherwise.
|
|
|
|
|
Automatic,
|
|
|
|
|
|
|
|
|
|
/// Never display them, even when output is going to a terminal.
|
|
|
|
|
Never,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for TerminalColours {
|
|
|
|
|
fn default() -> TerminalColours {
|
|
|
|
|
TerminalColours::Automatic
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TerminalColours {
|
|
|
|
|
|
|
|
|
|
/// Determine which terminal colour conditions to use.
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<TerminalColours, Misfire> {
|
2017-06-23 21:58:07 +00:00
|
|
|
|
const COLOURS: &[&str] = &["always", "auto", "never"];
|
|
|
|
|
|
2017-07-26 16:48:18 +00:00
|
|
|
|
let word = match matches.get(&flags::COLOR).or_else(|| matches.get(&flags::COLOUR)) {
|
|
|
|
|
Some(w) => w,
|
|
|
|
|
None => return Ok(TerminalColours::default()),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if word == "always" {
|
|
|
|
|
Ok(TerminalColours::Always)
|
|
|
|
|
}
|
|
|
|
|
else if word == "auto" || word == "automatic" {
|
|
|
|
|
Ok(TerminalColours::Automatic)
|
|
|
|
|
}
|
|
|
|
|
else if word == "never" {
|
|
|
|
|
Ok(TerminalColours::Never)
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
Err(Misfire::bad_argument(&flags::COLOR, word, COLOURS))
|
2016-04-17 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-07 14:31:00 +00:00
|
|
|
|
|
|
|
|
|
|
2017-06-25 13:51:44 +00:00
|
|
|
|
impl Colours {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Result<Colours, Misfire> {
|
2017-06-25 13:51:44 +00:00
|
|
|
|
use self::TerminalColours::*;
|
|
|
|
|
|
|
|
|
|
let tc = TerminalColours::deduce(matches)?;
|
|
|
|
|
if tc == Always || (tc == Automatic && TERM_WIDTH.is_some()) {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
let scale = matches.has(&flags::COLOR_SCALE) || matches.has(&flags::COLOUR_SCALE);
|
2017-06-25 13:51:44 +00:00
|
|
|
|
Ok(Colours::colourful(scale))
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Ok(Colours::plain())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-05-07 14:31:00 +00:00
|
|
|
|
|
2017-07-08 11:11:11 +00:00
|
|
|
|
impl FileStyle {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> FileStyle {
|
2017-07-08 11:11:11 +00:00
|
|
|
|
let classify = Classify::deduce(matches);
|
2017-07-10 13:01:38 +00:00
|
|
|
|
let exts = FileExtensions;
|
|
|
|
|
FileStyle { classify, exts }
|
2017-07-08 11:11:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-07 14:31:00 +00:00
|
|
|
|
impl Classify {
|
2017-07-26 16:48:18 +00:00
|
|
|
|
fn deduce(matches: &Matches) -> Classify {
|
|
|
|
|
if matches.has(&flags::CLASSIFY) { Classify::AddFileIndicators }
|
|
|
|
|
else { Classify::JustFilenames }
|
2017-05-07 14:31:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-25 13:51:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gets, then caches, the width of the terminal that exa is running in.
|
|
|
|
|
// This gets used multiple times above, with no real guarantee of order,
|
|
|
|
|
// so it’s easier to just cache it the first time it runs.
|
|
|
|
|
lazy_static! {
|
|
|
|
|
static ref TERM_WIDTH: Option<usize> = {
|
|
|
|
|
use term::dimensions;
|
|
|
|
|
dimensions().map(|t| t.0)
|
|
|
|
|
};
|
|
|
|
|
}
|