Get terminal width for grid view (resolve #1)

This commit is contained in:
Ben S 2014-07-22 15:41:20 +01:00
parent b1560edb85
commit cf3e32c9c1
4 changed files with 66 additions and 13 deletions

View File

@ -2,10 +2,7 @@
extern crate regex; extern crate regex;
#[phase(plugin)] extern crate regex_macros; #[phase(plugin)] extern crate regex_macros;
extern crate ansi_term; extern crate ansi_term;
extern crate unicode; extern crate unicode;
use std::char::UnicodeChar;
use std::iter::AdditiveIterator;
use std::os; use std::os;
@ -25,6 +22,7 @@ pub mod filetype;
pub mod unix; pub mod unix;
pub mod options; pub mod options;
pub mod sort; pub mod sort;
pub mod term;
fn main() { fn main() {
let args = os::args(); let args = os::args();
@ -66,20 +64,12 @@ fn exa(opts: &Options) {
} }
} }
fn width(string: &str) -> uint {
string.as_slice().chars()
.map(|c| c.width(true))
.filter(|o| o.is_some())
.map(|o| o.unwrap())
.sum()
}
fn grid_view(options: &Options, across: bool, dir: Dir) { fn grid_view(options: &Options, across: bool, dir: Dir) {
let unsorted_files = dir.files(); let unsorted_files = dir.files();
let files: Vec<&File> = options.transform_files(&unsorted_files); let files: Vec<&File> = options.transform_files(&unsorted_files);
let max_column_length = files.iter().map(|f| width(f.name.as_slice())).max().unwrap(); let max_column_length = files.iter().map(|f| f.file_name_width()).max().unwrap();
let console_width = 80; let (console_width, _) = term::dimensions().unwrap_or((80, 24));
let num_columns = (console_width + 1) / (max_column_length + 1); let num_columns = (console_width + 1) / (max_column_length + 1);
let count = files.len(); let count = files.len();

View File

@ -1,5 +1,6 @@
use std::io::{fs, IoResult}; use std::io::{fs, IoResult};
use std::io; use std::io;
use unicode::str::UnicodeStrSlice;
use ansi_term::{Paint, Colour, Plain, Style, Red, Green, Yellow, Blue, Purple, Cyan, Fixed}; use ansi_term::{Paint, Colour, Plain, Style, Red, Green, Yellow, Blue, Purple, Cyan, Fixed};
@ -157,6 +158,10 @@ impl<'a> File<'a> {
} }
} }
pub fn file_name_width(&self) -> uint {
self.name.as_slice().width(false)
}
fn target_file_name_and_arrow(&self, target_path: Path) -> String { fn target_file_name_and_arrow(&self, target_path: Path) -> String {
let v = target_path.filename().unwrap(); let v = target_path.filename().unwrap();
let filename = String::from_utf8_lossy(v).to_string(); let filename = String::from_utf8_lossy(v).to_string();

57
src/term.rs Normal file
View File

@ -0,0 +1,57 @@
mod c {
#![allow(non_camel_case_types)]
extern crate libc;
pub use self::libc::{
c_int,
c_ushort,
c_ulong,
STDOUT_FILENO,
};
use std::mem::zeroed;
// Getting the terminal size is done using an ioctl command that
// takes the file handle to the terminal (which in our case is
// stdout), and populates a structure with the values.
pub struct winsize {
pub ws_row: c_ushort,
pub ws_col: c_ushort,
}
// Unfortunately the actual command is not standardised...
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
static TIOCGWINSZ: c_ulong = 0x5413;
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
static TIOCGWINSZ: c_ulong = 0x40087468;
extern {
pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}
pub fn dimensions() -> winsize {
unsafe {
let mut window: winsize = zeroed();
ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window as *mut winsize);
window
}
}
}
pub fn dimensions() -> Option<(uint, uint)> {
let w = c::dimensions();
// If either of the dimensions is 0 then the command failed,
// usually because output isn't to a terminal (instead to a file
// or pipe or something)
if w.ws_col == 0 || w.ws_row == 0 {
None
}
else {
Some((w.ws_col as uint, w.ws_row as uint))
}
}

View File

@ -39,6 +39,7 @@ mod c {
pub fn getuid() -> libc::c_int; pub fn getuid() -> libc::c_int;
} }
} }
pub struct Unix { pub struct Unix {
user_names: HashMap<u32, Option<String>>, // mapping of user IDs to user names user_names: HashMap<u32, Option<String>>, // mapping of user IDs to user names
group_names: HashMap<u32, Option<String>>, // mapping of groups IDs to group names group_names: HashMap<u32, Option<String>>, // mapping of groups IDs to group names