exa/src/output/file_name.rs

150 lines
5.8 KiB
Rust
Raw Normal View History

use ansi_term::{ANSIString, Style};
use fs::{File, FileTarget};
use output::Colours;
use output::escape;
use output::cell::TextCellContents;
pub struct FileName<'a, 'dir: 'a> {
file: &'a File<'dir>,
colours: &'a Colours,
}
impl<'a, 'dir> FileName<'a, 'dir> {
pub fn new(file: &'a File<'dir>, colours: &'a Colours) -> FileName<'a, 'dir> {
FileName {
file: file,
colours: colours,
}
}
pub fn file_name(&self, links: bool, classify: bool) -> TextCellContents {
let mut bits = Vec::new();
if self.file.dir.is_none() {
if let Some(parent) = self.file.path.parent() {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
escape(parent.to_string_lossy().to_string(), &mut bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
}
if !self.file.name.is_empty() {
for bit in self.coloured_file_name() {
bits.push(bit);
}
}
if links && self.file.is_link() {
match self.file.link_target() {
FileTarget::Ok(target) => {
bits.push(Style::default().paint(" "));
bits.push(self.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(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
escape(parent.to_string_lossy().to_string(), &mut bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
if !target.name.is_empty() {
let target = FileName::new(&target, self.colours);
for bit in target.coloured_file_name() {
bits.push(bit);
}
}
},
FileTarget::Broken(broken_path) => {
bits.push(Style::default().paint(" "));
bits.push(self.colours.broken_arrow.paint("->"));
bits.push(Style::default().paint(" "));
bits.push(self.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 let Some(class) = self.classify_char() {
bits.push(Style::default().paint(class));
}
}
bits.into()
}
fn classify_char(&self) -> Option<&'static str> {
if self.file.is_executable_file() {
Some("*")
} else if self.file.is_directory() {
Some("/")
} else if self.file.is_pipe() {
Some("|")
} else if self.file.is_link() {
Some("@")
} else if self.file.is_socket() {
Some("=")
} else {
None
}
}
/// Returns at least one ANSI-highlighted string representing this files
/// name using the given set of colours.
///
/// Ordinarily, this will be just one string: the files complete name,
/// coloured according to its file type. If the name contains control
/// characters such as newlines or escapes, though, we cant just print them
/// to the screen directly, because then therell be newlines in weird places.
///
/// So in that situation, those characters will be escaped and highlighted in
/// a different colour.
fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
2017-05-01 14:43:27 +00:00
let file_style = self.style();
let mut bits = Vec::new();
escape(self.file.name.clone(), &mut bits, file_style, self.colours.control_char);
bits
}
2017-05-01 14:43:27 +00:00
pub fn style(&self) -> Style {
match self.file {
f if f.is_directory() => self.colours.filetypes.directory,
f if f.is_executable_file() => self.colours.filetypes.executable,
f if f.is_link() => self.colours.filetypes.symlink,
f if f.is_pipe() => self.colours.filetypes.pipe,
f if f.is_char_device()
| f.is_block_device() => self.colours.filetypes.device,
f if f.is_socket() => self.colours.filetypes.socket,
f if !f.is_file() => self.colours.filetypes.special,
f if f.is_immediate() => self.colours.filetypes.immediate,
f if f.is_image() => self.colours.filetypes.image,
f if f.is_video() => self.colours.filetypes.video,
f if f.is_music() => self.colours.filetypes.music,
f if f.is_lossless() => self.colours.filetypes.lossless,
f if f.is_crypto() => self.colours.filetypes.crypto,
f if f.is_document() => self.colours.filetypes.document,
f if f.is_compressed() => self.colours.filetypes.compressed,
f if f.is_temp() => self.colours.filetypes.temp,
f if f.is_compiled() => self.colours.filetypes.compiled,
_ => self.colours.filetypes.normal,
}
}
}