mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-01-13 17:02:58 +00:00
Move the functions in output to their own module
It didn’t feel quite right to have stand-alone functions in the module root file, which is usually just reserved for modules and exports.
This commit is contained in:
parent
3ebc22580a
commit
79feeba67d
@ -101,7 +101,7 @@ use output::colours::Colours;
|
|||||||
use output::column::{Alignment, Column, Columns, SizeFormat};
|
use output::column::{Alignment, Column, Columns, SizeFormat};
|
||||||
use output::cell::{TextCell, DisplayWidth};
|
use output::cell::{TextCell, DisplayWidth};
|
||||||
use output::tree::TreeTrunk;
|
use output::tree::TreeTrunk;
|
||||||
use super::filename;
|
use output::file_name::filename;
|
||||||
|
|
||||||
|
|
||||||
/// With the **Details** view, the output gets formatted into columns, with
|
/// With the **Details** view, the output gets formatted into columns, with
|
||||||
|
145
src/output/file_name.rs
Normal file
145
src/output/file_name.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
use ansi_term::{ANSIString, Style};
|
||||||
|
|
||||||
|
use fs::{File, FileTarget};
|
||||||
|
use output::Colours;
|
||||||
|
use output::cell::TextCellContents;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
|
||||||
|
let mut bits = Vec::new();
|
||||||
|
|
||||||
|
// TODO: This long function could do with some splitting up.
|
||||||
|
|
||||||
|
if file.dir.is_none() {
|
||||||
|
if let Some(parent) = file.path.parent() {
|
||||||
|
let coconut = parent.components().count();
|
||||||
|
|
||||||
|
if coconut == 1 && parent.has_root() {
|
||||||
|
bits.push(colours.symlink_path.paint("/"));
|
||||||
|
}
|
||||||
|
else if coconut >= 1 {
|
||||||
|
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
|
||||||
|
bits.push(colours.symlink_path.paint("/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !file.name.is_empty() {
|
||||||
|
for bit in coloured_file_name(file, colours) {
|
||||||
|
bits.push(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if links && file.is_link() {
|
||||||
|
match file.link_target() {
|
||||||
|
FileTarget::Ok(target) => {
|
||||||
|
bits.push(Style::default().paint(" "));
|
||||||
|
bits.push(colours.punctuation.paint("->"));
|
||||||
|
bits.push(Style::default().paint(" "));
|
||||||
|
|
||||||
|
if let Some(parent) = target.path.parent() {
|
||||||
|
let coconut = parent.components().count();
|
||||||
|
|
||||||
|
if coconut == 1 && parent.has_root() {
|
||||||
|
bits.push(colours.symlink_path.paint("/"));
|
||||||
|
}
|
||||||
|
else if coconut >= 1 {
|
||||||
|
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
|
||||||
|
bits.push(colours.symlink_path.paint("/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !target.name.is_empty() {
|
||||||
|
bits.push(file_colour(colours, &target).paint(target.name));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
FileTarget::Broken(broken_path) => {
|
||||||
|
bits.push(Style::default().paint(" "));
|
||||||
|
bits.push(colours.broken_arrow.paint("->"));
|
||||||
|
bits.push(Style::default().paint(" "));
|
||||||
|
bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
|
||||||
|
},
|
||||||
|
|
||||||
|
FileTarget::Err(_) => {
|
||||||
|
// Do nothing -- the error gets displayed on the next line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if classify {
|
||||||
|
if file.is_executable_file() {
|
||||||
|
bits.push(Style::default().paint("*"));
|
||||||
|
} else if file.is_directory() {
|
||||||
|
bits.push(Style::default().paint("/"));
|
||||||
|
} else if file.is_pipe() {
|
||||||
|
bits.push(Style::default().paint("|"));
|
||||||
|
} else if file.is_link() {
|
||||||
|
bits.push(Style::default().paint("@"));
|
||||||
|
} else if file.is_socket() {
|
||||||
|
bits.push(Style::default().paint("="));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bits.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns at least one ANSI-highlighted string representing this file’s
|
||||||
|
/// name using the given set of colours.
|
||||||
|
///
|
||||||
|
/// Ordinarily, this will be just one string: the file’s complete name,
|
||||||
|
/// coloured according to its file type. If the name contains control
|
||||||
|
/// characters such as newlines or escapes, though, we can’t just print them
|
||||||
|
/// to the screen directly, because then there’ll be newlines in weird places.
|
||||||
|
///
|
||||||
|
/// So in that situation, those characters will be escaped and highlighted in
|
||||||
|
/// a different colour.
|
||||||
|
fn coloured_file_name<'a>(file: &File, colours: &Colours) -> Vec<ANSIString<'a>> {
|
||||||
|
let colour = file_colour(colours, file);
|
||||||
|
let mut bits = Vec::new();
|
||||||
|
|
||||||
|
if file.name.chars().all(|c| c >= 0x20 as char) {
|
||||||
|
bits.push(colour.paint(file.name.clone()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for c in file.name.chars() {
|
||||||
|
// The `escape_default` method on `char` is *almost* what we want here, but
|
||||||
|
// it still escapes non-ASCII UTF-8 characters, which are still printable.
|
||||||
|
|
||||||
|
if c >= 0x20 as char {
|
||||||
|
// TODO: This allocates way too much,
|
||||||
|
// hence the `all` check above.
|
||||||
|
let mut s = String::new();
|
||||||
|
s.push(c);
|
||||||
|
bits.push(colour.paint(s));
|
||||||
|
} else {
|
||||||
|
let s = c.escape_default().collect::<String>();
|
||||||
|
bits.push(colours.control_char.paint(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_colour(colours: &Colours, file: &File) -> Style {
|
||||||
|
match file {
|
||||||
|
f if f.is_directory() => colours.filetypes.directory,
|
||||||
|
f if f.is_executable_file() => colours.filetypes.executable,
|
||||||
|
f if f.is_link() => colours.filetypes.symlink,
|
||||||
|
f if f.is_pipe() => colours.filetypes.pipe,
|
||||||
|
f if f.is_char_device()
|
||||||
|
| f.is_block_device() => colours.filetypes.device,
|
||||||
|
f if f.is_socket() => colours.filetypes.socket,
|
||||||
|
f if !f.is_file() => colours.filetypes.special,
|
||||||
|
f if f.is_immediate() => colours.filetypes.immediate,
|
||||||
|
f if f.is_image() => colours.filetypes.image,
|
||||||
|
f if f.is_video() => colours.filetypes.video,
|
||||||
|
f if f.is_music() => colours.filetypes.music,
|
||||||
|
f if f.is_lossless() => colours.filetypes.lossless,
|
||||||
|
f if f.is_crypto() => colours.filetypes.crypto,
|
||||||
|
f if f.is_document() => colours.filetypes.document,
|
||||||
|
f if f.is_compressed() => colours.filetypes.compressed,
|
||||||
|
f if f.is_temp() => colours.filetypes.temp,
|
||||||
|
f if f.is_compiled() => colours.filetypes.compiled,
|
||||||
|
_ => colours.filetypes.normal,
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ use term_grid as grid;
|
|||||||
use fs::File;
|
use fs::File;
|
||||||
use output::DisplayWidth;
|
use output::DisplayWidth;
|
||||||
use output::colours::Colours;
|
use output::colours::Colours;
|
||||||
use super::filename;
|
use output::file_name::filename;
|
||||||
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
|
@ -4,7 +4,7 @@ use ansi_term::ANSIStrings;
|
|||||||
|
|
||||||
use fs::File;
|
use fs::File;
|
||||||
|
|
||||||
use super::filename;
|
use output::file_name::filename;
|
||||||
use super::colours::Colours;
|
use super::colours::Colours;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
use ansi_term::{ANSIString, Style};
|
|
||||||
|
|
||||||
use fs::{File, FileTarget};
|
|
||||||
|
|
||||||
pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
|
pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
|
||||||
pub use self::colours::Colours;
|
pub use self::colours::Colours;
|
||||||
pub use self::details::Details;
|
pub use self::details::Details;
|
||||||
@ -17,143 +13,4 @@ pub mod column;
|
|||||||
mod cell;
|
mod cell;
|
||||||
mod colours;
|
mod colours;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
pub mod file_name;
|
||||||
|
|
||||||
pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
|
|
||||||
let mut bits = Vec::new();
|
|
||||||
|
|
||||||
// TODO: This long function could do with some splitting up.
|
|
||||||
|
|
||||||
if file.dir.is_none() {
|
|
||||||
if let Some(parent) = file.path.parent() {
|
|
||||||
let coconut = parent.components().count();
|
|
||||||
|
|
||||||
if coconut == 1 && parent.has_root() {
|
|
||||||
bits.push(colours.symlink_path.paint("/"));
|
|
||||||
}
|
|
||||||
else if coconut >= 1 {
|
|
||||||
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
|
|
||||||
bits.push(colours.symlink_path.paint("/"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !file.name.is_empty() {
|
|
||||||
for bit in coloured_file_name(file, colours) {
|
|
||||||
bits.push(bit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if links && file.is_link() {
|
|
||||||
match file.link_target() {
|
|
||||||
FileTarget::Ok(target) => {
|
|
||||||
bits.push(Style::default().paint(" "));
|
|
||||||
bits.push(colours.punctuation.paint("->"));
|
|
||||||
bits.push(Style::default().paint(" "));
|
|
||||||
|
|
||||||
if let Some(parent) = target.path.parent() {
|
|
||||||
let coconut = parent.components().count();
|
|
||||||
|
|
||||||
if coconut == 1 && parent.has_root() {
|
|
||||||
bits.push(colours.symlink_path.paint("/"));
|
|
||||||
}
|
|
||||||
else if coconut >= 1 {
|
|
||||||
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
|
|
||||||
bits.push(colours.symlink_path.paint("/"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !target.name.is_empty() {
|
|
||||||
bits.push(file_colour(colours, &target).paint(target.name));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
FileTarget::Broken(broken_path) => {
|
|
||||||
bits.push(Style::default().paint(" "));
|
|
||||||
bits.push(colours.broken_arrow.paint("->"));
|
|
||||||
bits.push(Style::default().paint(" "));
|
|
||||||
bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
|
|
||||||
},
|
|
||||||
|
|
||||||
FileTarget::Err(_) => {
|
|
||||||
// Do nothing -- the error gets displayed on the next line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if classify {
|
|
||||||
if file.is_executable_file() {
|
|
||||||
bits.push(Style::default().paint("*"));
|
|
||||||
} else if file.is_directory() {
|
|
||||||
bits.push(Style::default().paint("/"));
|
|
||||||
} else if file.is_pipe() {
|
|
||||||
bits.push(Style::default().paint("|"));
|
|
||||||
} else if file.is_link() {
|
|
||||||
bits.push(Style::default().paint("@"));
|
|
||||||
} else if file.is_socket() {
|
|
||||||
bits.push(Style::default().paint("="));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bits.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns at least one ANSI-highlighted string representing this file’s
|
|
||||||
/// name using the given set of colours.
|
|
||||||
///
|
|
||||||
/// Ordinarily, this will be just one string: the file’s complete name,
|
|
||||||
/// coloured according to its file type. If the name contains control
|
|
||||||
/// characters such as newlines or escapes, though, we can’t just print them
|
|
||||||
/// to the screen directly, because then there’ll be newlines in weird places.
|
|
||||||
///
|
|
||||||
/// So in that situation, those characters will be escaped and highlighted in
|
|
||||||
/// a different colour.
|
|
||||||
fn coloured_file_name<'a>(file: &File, colours: &Colours) -> Vec<ANSIString<'a>> {
|
|
||||||
let colour = file_colour(colours, file);
|
|
||||||
let mut bits = Vec::new();
|
|
||||||
|
|
||||||
if file.name.chars().all(|c| c >= 0x20 as char) {
|
|
||||||
bits.push(colour.paint(file.name.clone()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for c in file.name.chars() {
|
|
||||||
// The `escape_default` method on `char` is *almost* what we want here, but
|
|
||||||
// it still escapes non-ASCII UTF-8 characters, which are still printable.
|
|
||||||
|
|
||||||
if c >= 0x20 as char {
|
|
||||||
// TODO: This allocates way too much,
|
|
||||||
// hence the `all` check above.
|
|
||||||
let mut s = String::new();
|
|
||||||
s.push(c);
|
|
||||||
bits.push(colour.paint(s));
|
|
||||||
} else {
|
|
||||||
let s = c.escape_default().collect::<String>();
|
|
||||||
bits.push(colours.control_char.paint(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bits
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_colour(colours: &Colours, file: &File) -> Style {
|
|
||||||
match file {
|
|
||||||
f if f.is_directory() => colours.filetypes.directory,
|
|
||||||
f if f.is_executable_file() => colours.filetypes.executable,
|
|
||||||
f if f.is_link() => colours.filetypes.symlink,
|
|
||||||
f if f.is_pipe() => colours.filetypes.pipe,
|
|
||||||
f if f.is_char_device()
|
|
||||||
| f.is_block_device() => colours.filetypes.device,
|
|
||||||
f if f.is_socket() => colours.filetypes.socket,
|
|
||||||
f if !f.is_file() => colours.filetypes.special,
|
|
||||||
f if f.is_immediate() => colours.filetypes.immediate,
|
|
||||||
f if f.is_image() => colours.filetypes.image,
|
|
||||||
f if f.is_video() => colours.filetypes.video,
|
|
||||||
f if f.is_music() => colours.filetypes.music,
|
|
||||||
f if f.is_lossless() => colours.filetypes.lossless,
|
|
||||||
f if f.is_crypto() => colours.filetypes.crypto,
|
|
||||||
f if f.is_document() => colours.filetypes.document,
|
|
||||||
f if f.is_compressed() => colours.filetypes.compressed,
|
|
||||||
f if f.is_temp() => colours.filetypes.temp,
|
|
||||||
f if f.is_compiled() => colours.filetypes.compiled,
|
|
||||||
_ => colours.filetypes.normal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user