mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-26 22:06:26 +00:00
Merge branch 'long-grid-view'
This commit is contained in:
commit
090cebe669
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -13,7 +13,7 @@ dependencies = [
|
||||
"num_cpus 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"number_prefix 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_grid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_grid 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"users 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -71,7 +71,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.2.12"
|
||||
source = "git+https://github.com/alexcrichton/git2-rs.git#e5a439b13f45ca6b95fbf5f47ccf4b030d37ed1c"
|
||||
source = "git+https://github.com/alexcrichton/git2-rs.git#3a7a990607a766fa65a40b920d70c8289691d2f8"
|
||||
dependencies = [
|
||||
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -87,12 +87,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.2.17"
|
||||
source = "git+https://github.com/alexcrichton/git2-rs.git#e5a439b13f45ca6b95fbf5f47ccf4b030d37ed1c"
|
||||
source = "git+https://github.com/alexcrichton/git2-rs.git#3a7a990607a766fa65a40b920d70c8289691d2f8"
|
||||
dependencies = [
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libssh2-sys 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libz-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -111,7 +111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libz-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -186,7 +186,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -262,7 +262,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "term_grid"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::iter::repeat;
|
||||
|
||||
use ansi_term::Style;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
@ -58,37 +56,37 @@ impl Column {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pad a string with the given number of spaces.
|
||||
fn spaces(length: usize) -> String {
|
||||
repeat(" ").take(length).collect()
|
||||
}
|
||||
|
||||
impl Alignment {
|
||||
/// Pad a string with the given alignment and number of spaces.
|
||||
///
|
||||
/// This doesn't take the width the string *should* be, rather the number
|
||||
/// of spaces to add: this is because the strings are usually full of
|
||||
/// invisible control characters, so getting the displayed width of the
|
||||
/// string is not as simple as just getting its length.
|
||||
pub fn pad_string(&self, string: &str, padding: usize) -> String {
|
||||
match *self {
|
||||
Alignment::Left => format!("{}{}", string, spaces(padding)),
|
||||
Alignment::Right => format!("{}{}", spaces(padding), string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct Cell {
|
||||
pub length: usize,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn empty() -> Cell {
|
||||
Cell {
|
||||
text: String::new(),
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(style: Style, string: &str) -> Cell {
|
||||
Cell {
|
||||
text: style.paint(string).to_string(),
|
||||
length: UnicodeWidthStr::width(string),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_spaces(&mut self, count: usize) {
|
||||
self.length += count;
|
||||
for _ in 0 .. count {
|
||||
self.text.push(' ');
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&mut self, other: &Cell) {
|
||||
self.length += other.length;
|
||||
self.text.push_str(&*other.text);
|
||||
}
|
||||
}
|
||||
|
@ -179,9 +179,10 @@ impl<'dir> Exa<'dir> {
|
||||
|
||||
fn print(&self, dir: Option<&Dir>, files: &[File]) {
|
||||
match self.options.view {
|
||||
View::Grid(g) => g.view(files),
|
||||
View::Details(d) => d.view(dir, files),
|
||||
View::Lines(l) => l.view(files),
|
||||
View::Grid(g) => g.view(files),
|
||||
View::Details(d) => d.view(dir, files),
|
||||
View::GridDetails(gd) => gd.view(dir, files),
|
||||
View::Lines(l) => l.view(files),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
136
src/options.rs
136
src/options.rs
@ -13,7 +13,7 @@ use column::Column::*;
|
||||
use dir::Dir;
|
||||
use feature::Attribute;
|
||||
use file::File;
|
||||
use output::{Grid, Details, Lines};
|
||||
use output::{Grid, Details, GridDetails, Lines};
|
||||
use term::dimensions;
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@ impl Options {
|
||||
opts.optflag("B", "bytes", "list file sizes in bytes, without prefixes");
|
||||
opts.optflag("d", "list-dirs", "list directories as regular files");
|
||||
opts.optflag("g", "group", "show group as well as user");
|
||||
opts.optflag("G", "grid", "display entries in a grid view (default)");
|
||||
opts.optflag("", "group-directories-first", "list directories before other files");
|
||||
opts.optflag("h", "header", "show a header row at the top");
|
||||
opts.optflag("H", "links", "show number of hard links");
|
||||
@ -248,16 +249,17 @@ impl fmt::Display for Misfire {
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum View {
|
||||
Details(Details),
|
||||
Lines(Lines),
|
||||
Grid(Grid),
|
||||
GridDetails(GridDetails),
|
||||
Lines(Lines),
|
||||
}
|
||||
|
||||
impl View {
|
||||
pub fn deduce(matches: &getopts::Matches, filter: FileFilter, dir_action: DirAction) -> Result<View, Misfire> {
|
||||
use self::Misfire::*;
|
||||
|
||||
if matches.opt_present("long") {
|
||||
if matches.opt_present("across") {
|
||||
let long = || {
|
||||
if matches.opt_present("across") && !matches.opt_present("grid") {
|
||||
Err(Useless("across", true, "long"))
|
||||
}
|
||||
else if matches.opt_present("oneline") {
|
||||
@ -272,78 +274,85 @@ impl View {
|
||||
colours: if dimensions().is_some() { Colours::colourful() } else { Colours::plain() },
|
||||
};
|
||||
|
||||
Ok(View::Details(details))
|
||||
Ok(details)
|
||||
}
|
||||
}
|
||||
else if matches.opt_present("binary") {
|
||||
Err(Useless("binary", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("bytes") {
|
||||
Err(Useless("bytes", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("inode") {
|
||||
Err(Useless("inode", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("links") {
|
||||
Err(Useless("links", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("header") {
|
||||
Err(Useless("header", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("blocks") {
|
||||
Err(Useless("blocks", false, "long"))
|
||||
}
|
||||
else if cfg!(feature="git") && matches.opt_present("git") {
|
||||
Err(Useless("git", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("time") {
|
||||
Err(Useless("time", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("tree") {
|
||||
Err(Useless("tree", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("group") {
|
||||
Err(Useless("group", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("level") && !matches.opt_present("recurse") {
|
||||
Err(Useless2("level", "recurse", "tree"))
|
||||
}
|
||||
else if Attribute::feature_implemented() && matches.opt_present("extended") {
|
||||
Err(Useless("extended", false, "long"))
|
||||
}
|
||||
else if let Some((width, _)) = dimensions() {
|
||||
if matches.opt_present("oneline") {
|
||||
if matches.opt_present("across") {
|
||||
Err(Useless("across", true, "oneline"))
|
||||
};
|
||||
|
||||
let long_options_scan = || {
|
||||
for option in &[ "binary", "bytes", "inode", "links", "header", "blocks", "time", "tree", "group" ] {
|
||||
if matches.opt_present(option) {
|
||||
return Err(Useless(option, false, "long"));
|
||||
}
|
||||
}
|
||||
|
||||
if cfg!(feature="git") && matches.opt_present("git") {
|
||||
Err(Useless("git", false, "long"))
|
||||
}
|
||||
else if matches.opt_present("level") && !matches.opt_present("recurse") {
|
||||
Err(Useless2("level", "recurse", "tree"))
|
||||
}
|
||||
else if Attribute::feature_implemented() && matches.opt_present("extended") {
|
||||
Err(Useless("extended", false, "long"))
|
||||
}
|
||||
else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
let other_options_scan = || {
|
||||
if let Some((width, _)) = dimensions() {
|
||||
if matches.opt_present("oneline") {
|
||||
if matches.opt_present("across") {
|
||||
Err(Useless("across", true, "oneline"))
|
||||
}
|
||||
else {
|
||||
let lines = Lines {
|
||||
colours: Colours::colourful(),
|
||||
};
|
||||
|
||||
Ok(View::Lines(lines))
|
||||
}
|
||||
}
|
||||
else {
|
||||
let lines = Lines {
|
||||
colours: Colours::colourful(),
|
||||
let grid = Grid {
|
||||
across: matches.opt_present("across"),
|
||||
console_width: width,
|
||||
colours: Colours::colourful(),
|
||||
};
|
||||
|
||||
Ok(View::Lines(lines))
|
||||
Ok(View::Grid(grid))
|
||||
}
|
||||
}
|
||||
else {
|
||||
let grid = Grid {
|
||||
across: matches.opt_present("across"),
|
||||
console_width: width,
|
||||
colours: Colours::colourful(),
|
||||
// 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.
|
||||
let lines = Lines {
|
||||
colours: Colours::plain(),
|
||||
};
|
||||
|
||||
Ok(View::Grid(grid))
|
||||
Ok(View::Lines(lines))
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("long") {
|
||||
let long_options = try!(long());
|
||||
|
||||
if matches.opt_present("grid") {
|
||||
match other_options_scan() {
|
||||
Ok(View::Grid(grid)) => return Ok(View::GridDetails(GridDetails { grid: grid, details: long_options })),
|
||||
Ok(lines) => return Ok(lines),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
}
|
||||
else {
|
||||
return Ok(View::Details(long_options));
|
||||
}
|
||||
}
|
||||
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.
|
||||
let lines = Lines {
|
||||
colours: Colours::plain(),
|
||||
};
|
||||
|
||||
Ok(View::Lines(lines))
|
||||
}
|
||||
try!(long_options_scan());
|
||||
|
||||
other_options_scan()
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,5 +727,4 @@ mod test {
|
||||
let opts = Options::getopts(&[ "--level".to_string(), "69105".to_string() ]);
|
||||
assert_eq!(opts.unwrap_err(), Misfire::Useless2("level", "recurse", "tree"))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
use std::iter::repeat;
|
||||
use std::string::ToString;
|
||||
|
||||
use colours::Colours;
|
||||
use column::{Alignment, Column, Cell};
|
||||
use dir::Dir;
|
||||
@ -66,14 +69,16 @@ impl Details {
|
||||
|
||||
// Then add files to the table and print it out.
|
||||
self.add_files_to_table(&mut table, files, 0);
|
||||
table.print_table(self.xattr, self.recurse.is_some());
|
||||
for cell in table.print_table(self.xattr, self.recurse.is_some()) {
|
||||
println!("{}", cell.text);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds files to the table - recursively, if the `recurse` option
|
||||
/// is present.
|
||||
fn add_files_to_table<U: Users>(&self, table: &mut Table<U>, src: &[File], depth: usize) {
|
||||
for (index, file) in src.iter().enumerate() {
|
||||
table.add_file(file, depth, index == src.len() - 1);
|
||||
table.add_file(file, depth, index == src.len() - 1, true);
|
||||
|
||||
// There are two types of recursion that exa supports: a tree
|
||||
// view, which is dealt with here, and multiple listings, which is
|
||||
@ -105,7 +110,7 @@ struct Row {
|
||||
|
||||
/// This file's name, in coloured output. The name is treated separately
|
||||
/// from the other cells, as it never requires padding.
|
||||
name: String,
|
||||
name: Cell,
|
||||
|
||||
/// How many directories deep into the tree structure this is. Directories
|
||||
/// on top have depth 0.
|
||||
@ -157,7 +162,7 @@ impl Table<OSUsers> {
|
||||
|
||||
/// Create a new, empty Table object, setting the caching fields to their
|
||||
/// empty states.
|
||||
fn with_options(colours: Colours, columns: Vec<Column>) -> Table<OSUsers> {
|
||||
pub fn with_options(colours: Colours, columns: Vec<Column>) -> Table<OSUsers> {
|
||||
Table {
|
||||
columns: columns,
|
||||
rows: Vec::new(),
|
||||
@ -177,11 +182,11 @@ impl<U> Table<U> where U: Users {
|
||||
/// Add a dummy "header" row to the table, which contains the names of all
|
||||
/// the columns, underlined. This has dummy data for the cases that aren't
|
||||
/// actually used, such as the depth or list of attributes.
|
||||
fn add_header(&mut self) {
|
||||
pub fn add_header(&mut self) {
|
||||
let row = Row {
|
||||
depth: 0,
|
||||
cells: self.columns.iter().map(|c| Cell::paint(self.colours.header, c.header())).collect(),
|
||||
name: self.colours.header.paint("Name").to_string(),
|
||||
name: Cell::paint(self.colours.header, "Name"),
|
||||
last: false,
|
||||
attrs: Vec::new(),
|
||||
children: false,
|
||||
@ -191,11 +196,16 @@ impl<U> Table<U> where U: Users {
|
||||
}
|
||||
|
||||
/// Get the cells for the given file, and add the result to the table.
|
||||
fn add_file(&mut self, file: &File, depth: usize, last: bool) {
|
||||
pub fn add_file(&mut self, file: &File, depth: usize, last: bool, links: bool) {
|
||||
let cells = self.cells_for_file(file);
|
||||
self.add_file_with_cells(cells, file, depth, last, links)
|
||||
}
|
||||
|
||||
pub fn add_file_with_cells(&mut self, cells: Vec<Cell>, file: &File, depth: usize, last: bool, links: bool) {
|
||||
let row = Row {
|
||||
depth: depth,
|
||||
cells: self.cells_for_file(file),
|
||||
name: filename(file, &self.colours),
|
||||
cells: cells,
|
||||
name: Cell { text: filename(file, &self.colours, links), length: file.file_name_width() },
|
||||
last: last,
|
||||
attrs: file.xattrs.clone(),
|
||||
children: file.this.is_some(),
|
||||
@ -206,7 +216,7 @@ impl<U> Table<U> where U: Users {
|
||||
|
||||
/// Use the list of columns to find which cells should be produced for
|
||||
/// this file, per-column.
|
||||
fn cells_for_file(&mut self, file: &File) -> Vec<Cell> {
|
||||
pub fn cells_for_file(&mut self, file: &File) -> Vec<Cell> {
|
||||
self.columns.clone().iter()
|
||||
.map(|c| self.display(file, c))
|
||||
.collect()
|
||||
@ -373,8 +383,9 @@ impl<U> Table<U> where U: Users {
|
||||
}
|
||||
|
||||
/// Print the table to standard output, consuming it in the process.
|
||||
fn print_table(self, xattr: bool, show_children: bool) {
|
||||
pub fn print_table(&self, xattr: bool, show_children: bool) -> Vec<Cell> {
|
||||
let mut stack = Vec::new();
|
||||
let mut cells = Vec::new();
|
||||
|
||||
// Work out the list of column widths by finding the longest cell for
|
||||
// each column, then formatting each cell in that column to be the
|
||||
@ -383,12 +394,21 @@ impl<U> Table<U> where U: Users {
|
||||
.map(|n| self.rows.iter().map(|row| row.cells[n].length).max().unwrap_or(0))
|
||||
.collect();
|
||||
|
||||
for row in self.rows.into_iter() {
|
||||
for row in self.rows.iter() {
|
||||
let mut cell = Cell::empty();
|
||||
|
||||
for (n, width) in column_widths.iter().enumerate() {
|
||||
let padding = width - row.cells[n].length;
|
||||
print!("{} ", self.columns[n].alignment().pad_string(&row.cells[n].text, padding));
|
||||
match self.columns[n].alignment() {
|
||||
Alignment::Left => { cell.append(&row.cells[n]); cell.add_spaces(width - row.cells[n].length); }
|
||||
Alignment::Right => { cell.add_spaces(width - row.cells[n].length); cell.append(&row.cells[n]); }
|
||||
}
|
||||
|
||||
cell.add_spaces(1);
|
||||
}
|
||||
|
||||
let mut filename = String::new();
|
||||
let mut filename_length = 0;
|
||||
|
||||
// A stack tracks which tree characters should be printed. It's
|
||||
// necessary to maintain information about the previously-printed
|
||||
// lines, as the output will change based on whether the
|
||||
@ -398,7 +418,8 @@ impl<U> Table<U> where U: Users {
|
||||
stack[row.depth] = if row.last { TreePart::Corner } else { TreePart::Edge };
|
||||
|
||||
for i in 1 .. row.depth + 1 {
|
||||
print!("{}", self.colours.punctuation.paint(stack[i].ascii_art()));
|
||||
filename.push_str(&*self.colours.punctuation.paint(stack[i].ascii_art()).to_string());
|
||||
filename_length += 4;
|
||||
}
|
||||
|
||||
if row.children {
|
||||
@ -408,24 +429,29 @@ impl<U> Table<U> where U: Users {
|
||||
// If any tree characters have been printed, then add an extra
|
||||
// space, which makes the output look much better.
|
||||
if row.depth != 0 {
|
||||
print!(" ");
|
||||
filename.push(' ');
|
||||
filename_length += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the name without worrying about padding.
|
||||
print!("{}\n", row.name);
|
||||
filename.push_str(&*row.name.text);
|
||||
filename_length += row.name.length;
|
||||
|
||||
if xattr {
|
||||
let width = row.attrs.iter().map(|a| a.name().len()).max().unwrap_or(0);
|
||||
for attr in row.attrs.iter() {
|
||||
let name = attr.name();
|
||||
println!("{}\t{}",
|
||||
Alignment::Left.pad_string(name, width - name.len()),
|
||||
attr.size()
|
||||
)
|
||||
let spaces: String = repeat(" ").take(width - name.len()).collect();
|
||||
filename.push_str(&*format!("\n{}{} {}", name, spaces, attr.size()))
|
||||
}
|
||||
}
|
||||
|
||||
cell.append(&Cell { text: filename, length: filename_length });
|
||||
cells.push(cell);
|
||||
}
|
||||
|
||||
cells
|
||||
}
|
||||
}
|
||||
|
||||
|
118
src/output/grid_details.rs
Normal file
118
src/output/grid_details.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use std::iter::repeat;
|
||||
|
||||
use users::OSUsers;
|
||||
use term_grid as grid;
|
||||
|
||||
use column::{Column, Cell};
|
||||
use dir::Dir;
|
||||
use file::File;
|
||||
use output::details::{Details, Table};
|
||||
use output::grid::Grid;
|
||||
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub struct GridDetails {
|
||||
pub grid: Grid,
|
||||
pub details: Details,
|
||||
}
|
||||
|
||||
impl GridDetails {
|
||||
pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
|
||||
let columns_for_dir = self.details.columns.for_dir(dir);
|
||||
let mut first_table = Table::with_options(self.details.colours, columns_for_dir.clone());
|
||||
let cells: Vec<_> = files.iter().map(|file| first_table.cells_for_file(file)).collect();
|
||||
|
||||
let mut last_working_table = self.make_grid(1, &*columns_for_dir, files, cells.clone());
|
||||
|
||||
for column_count in 2.. {
|
||||
let grid = self.make_grid(column_count, &*columns_for_dir, files, cells.clone());
|
||||
|
||||
let the_grid_fits = {
|
||||
let d = grid.fit_into_columns(column_count);
|
||||
d.is_complete() && d.width() <= self.grid.console_width
|
||||
};
|
||||
|
||||
if the_grid_fits {
|
||||
last_working_table = grid;
|
||||
}
|
||||
else {
|
||||
print!("{}", last_working_table.fit_into_columns(column_count - 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_table(&self, columns_for_dir: &[Column]) -> Table<OSUsers> {
|
||||
let mut table = Table::with_options(self.details.colours, columns_for_dir.into());
|
||||
if self.details.header { table.add_header() }
|
||||
table
|
||||
}
|
||||
|
||||
fn make_grid(&self, column_count: usize, columns_for_dir: &[Column], files: &[File], cells: Vec<Vec<Cell>>) -> grid::Grid {
|
||||
let mut tables: Vec<_> = repeat(()).map(|_| self.make_table(columns_for_dir)).take(column_count).collect();
|
||||
|
||||
let mut num_cells = cells.len();
|
||||
if self.details.header {
|
||||
num_cells += column_count;
|
||||
}
|
||||
|
||||
let original_height = divide_rounding_up(cells.len(), column_count);
|
||||
let height = divide_rounding_up(num_cells, column_count);
|
||||
|
||||
for (i, (file, row)) in files.iter().zip(cells.into_iter()).enumerate() {
|
||||
let index = if self.grid.across {
|
||||
i % column_count
|
||||
}
|
||||
else {
|
||||
i / original_height
|
||||
};
|
||||
|
||||
tables[index].add_file_with_cells(row, file, 0, false, false);
|
||||
}
|
||||
|
||||
let columns: Vec<_> = tables.iter().map(|t| t.print_table(false, false)).collect();
|
||||
|
||||
let direction = if self.grid.across { grid::Direction::LeftToRight }
|
||||
else { grid::Direction::TopToBottom };
|
||||
|
||||
let mut grid = grid::Grid::new(grid::GridOptions {
|
||||
direction: direction,
|
||||
separator_width: 4,
|
||||
});
|
||||
|
||||
if self.grid.across {
|
||||
for row in 0 .. height {
|
||||
for column in columns.iter() {
|
||||
if row < column.len() {
|
||||
let cell = grid::Cell {
|
||||
contents: column[row].text.clone(),
|
||||
width: column[row].length,
|
||||
};
|
||||
|
||||
grid.add(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for column in columns.iter() {
|
||||
for cell in column.iter() {
|
||||
let cell = grid::Cell {
|
||||
contents: cell.text.clone(),
|
||||
width: cell.length,
|
||||
};
|
||||
|
||||
grid.add(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn divide_rounding_up(a: usize, b: usize) -> usize {
|
||||
let mut result = a / b;
|
||||
if a % b != 0 { result += 1; }
|
||||
result
|
||||
}
|
@ -13,7 +13,7 @@ pub struct Lines {
|
||||
impl Lines {
|
||||
pub fn view(&self, files: &[File]) {
|
||||
for file in files {
|
||||
println!("{}", filename(file, &self.colours));
|
||||
println!("{}", filename(file, &self.colours, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,15 @@ use filetype::file_colour;
|
||||
pub use self::details::Details;
|
||||
pub use self::grid::Grid;
|
||||
pub use self::lines::Lines;
|
||||
pub use self::grid_details::GridDetails;
|
||||
|
||||
mod grid;
|
||||
pub mod details;
|
||||
mod lines;
|
||||
mod grid_details;
|
||||
|
||||
|
||||
pub fn filename(file: &File, colours: &Colours) -> String {
|
||||
if file.is_link() {
|
||||
pub fn filename(file: &File, colours: &Colours, links: bool) -> String {
|
||||
if links && file.is_link() {
|
||||
symlink_filename(file, colours)
|
||||
}
|
||||
else {
|
||||
|
Loading…
Reference in New Issue
Block a user