Ver código fonte

Merge branch 'main' into dependabot/cargo/num_cpus-1.16.0

Christina Sørensen 2 anos atrás
pai
commit
a030c580dd

+ 1 - 0
.envrc

@@ -0,0 +1 @@
+use flake .

+ 1 - 0
.gitignore

@@ -22,3 +22,4 @@ parts
 prime
 prime
 stage
 stage
 *.snap
 *.snap
+.direnv

+ 8 - 8
Cargo.lock

@@ -87,9 +87,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "git2"
 name = "git2"
-version = "0.16.1"
+version = "0.17.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
+checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
 dependencies = [
 dependencies = [
  "bitflags",
  "bitflags",
  "libc",
  "libc",
@@ -139,15 +139,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 
 [[package]]
 [[package]]
 name = "libc"
 name = "libc"
-version = "0.2.93"
+version = "0.2.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 
 
 [[package]]
 [[package]]
 name = "libgit2-sys"
 name = "libgit2-sys"
-version = "0.14.2+1.5.1"
+version = "0.15.2+1.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
+checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa"
 dependencies = [
 dependencies = [
  "cc",
  "cc",
  "libc",
  "libc",
@@ -327,9 +327,9 @@ dependencies = [
 
 
 [[package]]
 [[package]]
 name = "unicode-width"
 name = "unicode-width"
-version = "0.1.8"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
 
 
 [[package]]
 [[package]]
 name = "url"
 name = "url"

+ 3 - 3
Cargo.toml

@@ -7,9 +7,9 @@ edition = "2021"
 rust-version = "1.70.0"
 rust-version = "1.70.0"
 exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"]
 exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"]
 readme = "README.md"
 readme = "README.md"
-homepage = "https://github.com/cafkafk/eza"
+homepage = "https://github.com/eza-community/eza"
 license = "MIT"
 license = "MIT"
-repository = "https://github.com/cafkafk/eza"
+repository = "https://github.com/eza-community/eza"
 version = "0.10.7"
 version = "0.10.7"
 
 
 
 
@@ -43,7 +43,7 @@ default-features = false
 features = ["format"]
 features = ["format"]
 
 
 [dependencies.git2]
 [dependencies.git2]
-version = "0.16"
+version = "0.17"
 optional = true
 optional = true
 default-features = false
 default-features = false
 
 

+ 9 - 9
README.md

@@ -9,9 +9,9 @@ eza is a modern, maintained replacement for ls, built on [exa](https://github.co
 [![Built with Nix](https://img.shields.io/badge/Built_With-Nix-5277C3.svg?logo=nixos&labelColor=73C3D5)](https://nixos.org)
 [![Built with Nix](https://img.shields.io/badge/Built_With-Nix-5277C3.svg?logo=nixos&labelColor=73C3D5)](https://nixos.org)
 [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
 [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
 
 
-[![Unit tests](https://github.com/cafkafk/eza/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/cafkafk/eza/actions/workflows/unit-tests.yml)
+[![Unit tests](https://github.com/eza-community/eza/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/eza-community/eza/actions/workflows/unit-tests.yml)
 ![Crates.io](https://img.shields.io/crates/v/eza?link=https%3A%2F%2Fcrates.io%2Fcrates%2Feza)
 ![Crates.io](https://img.shields.io/crates/v/eza?link=https%3A%2F%2Fcrates.io%2Fcrates%2Feza)
-![Crates.io](https://img.shields.io/crates/l/eza?link=https%3A%2F%2Fgithub.com%2Fcafkafk%2Feza%2Fblob%2Fmain%2FLICENCE)
+![Crates.io](https://img.shields.io/crates/l/eza?link=https%3A%2F%2Fgithub.com%2Feza-community%2Feza%2Fblob%2Fmain%2FLICENCE)
 
 
 </div>
 </div>
 
 
@@ -31,12 +31,12 @@ By deliberately making some decisions differently, eza attempts to be a more fea
 
 
 **eza** features not in exa (non-exhaustive):
 **eza** features not in exa (non-exhaustive):
 
 
- -   Fixes [“The Grid Bug”](https://github.com/cafkafk/eza/issues/66#issuecomment-1656758327) introduced in exa 2021.
+ -   Fixes [“The Grid Bug”](https://github.com/eza-community/eza/issues/66#issuecomment-1656758327) introduced in exa 2021.
  -   Hyperlink support.
  -   Hyperlink support.
  -   Selinux context output.
  -   Selinux context output.
  -   Git repo status output.
  -   Git repo status output.
  -   Human readable relative dates.
  -   Human readable relative dates.
- -   Several security fixes (see [dependabot](https://github.com/cafkafk/eza/security/dependabot?q=is%3Aclosed))
+ -   Several security fixes (see [dependabot](https://github.com/eza-community/eza/security/dependabot?q=is%3Aclosed))
  -   Many smaller bug fixes/changes!
  -   Many smaller bug fixes/changes!
 
 
 ---
 ---
@@ -49,11 +49,11 @@ By deliberately making some decisions differently, eza attempts to be a more fea
 
 
 If you already have Nix setup with flake support, you can try out eza with the `nix run` command:
 If you already have Nix setup with flake support, you can try out eza with the `nix run` command:
 
 
-    nix run github:cafkafk/eza
+    nix run github:eza-community/eza
 
 
 Nix will build eza and run it. 
 Nix will build eza and run it. 
 
 
-If you want to pass arguments this way, use e.g. `nix run github:cafkafk/eza -- -ol`.
+If you want to pass arguments this way, use e.g. `nix run github:eza-community/eza -- -ol`.
 
 
 <a id="installation">
 <a id="installation">
 <h1>Installation</h1>
 <h1>Installation</h1>
@@ -75,7 +75,7 @@ Cargo will build the `eza` binary and place it in `$HOME/.local/share/cargo/bin/
 
 
 If you already have a Rust environment set up, you can use the `cargo install` command in your local clone of the repo:
 If you already have a Rust environment set up, you can use the `cargo install` command in your local clone of the repo:
 
 
-    git clone https://github.com/cafkafk/eza.git
+    git clone https://github.com/eza-community/eza.git
     cd eza
     cd eza
     cargo install --path .
     cargo install --path .
 
 
@@ -158,7 +158,7 @@ These options are available when running with `--long` (`-l`):
 - **-H**, **--links**: list each file’s number of hard links
 - **-H**, **--links**: list each file’s number of hard links
 - **-i**, **--inode**: list each file’s inode number
 - **-i**, **--inode**: list each file’s inode number
 - **-m**, **--modified**: use the modified timestamp field
 - **-m**, **--modified**: use the modified timestamp field
-- **-S**, **--blocks**: list each file’s number of file system blocks
+- **-S**, **--blocksize**: show size of allocated file system blocks
 - **-t**, **--time=(field)**: which timestamp field to use
 - **-t**, **--time=(field)**: which timestamp field to use
 - **-u**, **--accessed**: use the accessed timestamp field
 - **-u**, **--accessed**: use the accessed timestamp field
 - **-U**, **--created**: use the created timestamp field
 - **-U**, **--created**: use the created timestamp field
@@ -192,7 +192,7 @@ Some of the options accept parameters:
     <img src="https://img.shields.io/badge/rustc-1.63.0+-lightgray.svg" alt="Rust 1.63.0+" />
     <img src="https://img.shields.io/badge/rustc-1.63.0+-lightgray.svg" alt="Rust 1.63.0+" />
 </a>
 </a>
 
 
-<a href="https://github.com/cafkafk/eza/blob/master/LICENCE">
+<a href="https://github.com/eza-community/eza/blob/master/LICENCE">
     <img src="https://img.shields.io/badge/licence-MIT-green" alt="MIT Licence" />
     <img src="https://img.shields.io/badge/licence-MIT-green" alt="MIT Licence" />
 </a>
 </a>
 </h1></a>
 </h1></a>

+ 1 - 1
build.rs

@@ -23,7 +23,7 @@ fn main() -> io::Result<()> {
     #![allow(clippy::write_with_newline)]
     #![allow(clippy::write_with_newline)]
 
 
     let tagline = "eza - A modern, maintained replacement for ls";
     let tagline = "eza - A modern, maintained replacement for ls";
-    let url     = "https://github.com/cafkafk/eza";
+    let url     = "https://github.com/eza-community/eza";
 
 
     let ver =
     let ver =
         if is_debug_build() {
         if is_debug_build() {

+ 1 - 1
completions/fish/eza.fish

@@ -64,7 +64,7 @@ complete -c eza -s g -l group -d "List each file's group"
 complete -c eza -s h -l header -d "Add a header row to each column"
 complete -c eza -s h -l header -d "Add a header row to each column"
 complete -c eza -s H -l links -d "List each file's number of hard links"
 complete -c eza -s H -l links -d "List each file's number of hard links"
 complete -c eza -s i -l inode -d "List each file's inode number"
 complete -c eza -s i -l inode -d "List each file's inode number"
-complete -c eza -s S -l blocks -d "List each file's number of filesystem blocks"
+complete -c eza -s S -l blocksize -d "List each file's size of allocated file system blocks"
 complete -c eza -s t -l time -d "Which timestamp field to list" -x -a "
 complete -c eza -s t -l time -d "Which timestamp field to list" -x -a "
     modified\t'Display modified time'
     modified\t'Display modified time'
     changed\t'Display changed time'
     changed\t'Display changed time'

+ 1 - 1
completions/zsh/_eza

@@ -43,7 +43,7 @@ __eza() {
         {-i,--inode}"[List each file's inode number]" \
         {-i,--inode}"[List each file's inode number]" \
         {-m,--modified}"[Use the modified timestamp field]" \
         {-m,--modified}"[Use the modified timestamp field]" \
         {-n,--numeric}"[List numeric user and group IDs.]" \
         {-n,--numeric}"[List numeric user and group IDs.]" \
-        {-S,--blocks}"[List each file's number of filesystem blocks]" \
+        {-S,--blocksize}"[List each file's size of allocated file system blocks.]" \
         {-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \
         {-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \
         --time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso relative)" \
         --time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso relative)" \
         --no-permissions"[Suppress the permissions field]" \
         --no-permissions"[Suppress the permissions field]" \

+ 1 - 1
flake.nix

@@ -69,7 +69,7 @@
 
 
         # For `nix develop`:
         # For `nix develop`:
         devShells.default = pkgs.mkShell {
         devShells.default = pkgs.mkShell {
-          nativeBuildInputs = with pkgs; [toolchain];
+          nativeBuildInputs = with pkgs; [toolchain just pandoc];
         };
         };
 
 
         # for `nix flake check`
         # for `nix flake check`

+ 5 - 5
man/eza.1.md

@@ -79,7 +79,7 @@ Valid settings are ‘`always`’, ‘`automatic`’, and ‘`never`’.
 : Display entries as hyperlinks
 : Display entries as hyperlinks
 
 
 `-w`, `--width=COLS`
 `-w`, `--width=COLS`
-Set screen width in columns.
+: Set screen width in columns.
 
 
 
 
 FILTERING AND SORTING OPTIONS
 FILTERING AND SORTING OPTIONS
@@ -152,8 +152,8 @@ These options are available when running with `--long` (`-l`):
 `-n`, `--numeric`
 `-n`, `--numeric`
 : List numeric user and group IDs.
 : List numeric user and group IDs.
 
 
-`-S`, `--blocks`
-: List each file’s number of file system blocks.
+`-S`, `--blocksize`
+: List each file’s size of allocated file system blocks.
 
 
 `-t`, `--time=WORD`
 `-t`, `--time=WORD`
 : Which timestamp field to list.
 : Which timestamp field to list.
@@ -267,8 +267,8 @@ AUTHOR
 
 
 eza is maintained by Christina Sørensen and many other contributors.
 eza is maintained by Christina Sørensen and many other contributors.
 
 
-**Source code:** `https://github.com/cafkafk/eza` \
-**Contributors:** `https://github.com/cafkafk/eza/graphs/contributors`
+**Source code:** `https://github.com/eza-community/eza` \
+**Contributors:** `https://github.com/eza-community/eza/graphs/contributors`
 
 
 Our infinite thanks to Benjamin ‘ogham’ Sago and all the other contributors of exa, from which eza was forked.
 Our infinite thanks to Benjamin ‘ogham’ Sago and all the other contributors of exa, from which eza was forked.
 
 

+ 5 - 2
man/eza_colors.5.md

@@ -193,6 +193,9 @@ LIST OF CODES
 `gt`
 `gt`
 : a modified metadata flag in Git
 : a modified metadata flag in Git
 
 
+`gi`
+: an ignored flag in Git
+
 `xx`
 `xx`
 : “punctuation”, including many background UI elements
 : “punctuation”, including many background UI elements
 
 
@@ -271,8 +274,8 @@ AUTHOR
 
 
 eza is maintained by Christina Sørensen and many other contributors.
 eza is maintained by Christina Sørensen and many other contributors.
 
 
-**Source code:** `https://github.com/cafkafk/eza` \
-**Contributors:** `https://github.com/cafkafk/eza/graphs/contributors`
+**Source code:** `https://github.com/eza-community/eza` \
+**Contributors:** `https://github.com/eza-community/eza/graphs/contributors`
 
 
 Our infinite thanks to Benjamin ‘ogham’ Sago and all the other contributors of exa, from which eza was forked.
 Our infinite thanks to Benjamin ‘ogham’ Sago and all the other contributors of exa, from which eza was forked.
 
 

+ 3 - 8
src/fs/fields.rs

@@ -11,14 +11,9 @@
 //! The `output::details` module, among others, uses these types to render and
 //! The `output::details` module, among others, uses these types to render and
 //! display the information as formatted strings.
 //! display the information as formatted strings.
 
 
-// C-style `blkcnt_t` types don’t follow Rust’s rules!
 #![allow(non_camel_case_types)]
 #![allow(non_camel_case_types)]
 #![allow(clippy::struct_excessive_bools)]
 #![allow(clippy::struct_excessive_bools)]
 
 
-
-/// The type of a file’s block count.
-pub type blkcnt_t = u64;
-
 /// The type of a file’s group ID.
 /// The type of a file’s group ID.
 pub type gid_t = u32;
 pub type gid_t = u32;
 
 
@@ -137,12 +132,12 @@ pub struct Links {
 pub struct Inode(pub ino_t);
 pub struct Inode(pub ino_t);
 
 
 
 
-/// The number of blocks that a file takes up on the filesystem, if any.
+/// A file's size of allocated file system blocks.
 #[derive(Copy, Clone)]
 #[derive(Copy, Clone)]
-pub enum Blocks {
+pub enum Blocksize {
 
 
     /// This file has the given number of blocks.
     /// This file has the given number of blocks.
-    Some(blkcnt_t),
+    Some(u64),
 
 
     /// This file isn’t of a type that can take up blocks.
     /// This file isn’t of a type that can take up blocks.
     None,
     None,

+ 7 - 6
src/fs/file.rs

@@ -345,16 +345,17 @@ impl<'dir> File<'dir> {
         f::Inode(self.metadata.ino())
         f::Inode(self.metadata.ino())
     }
     }
 
 
-    /// This file’s number of filesystem blocks.
-    ///
-    /// (Not the size of each block, which we don’t actually report on)
+    /// This actual size the file takes up on disk, in bytes.
     #[cfg(unix)]
     #[cfg(unix)]
-    pub fn blocks(&self) -> f::Blocks {
+    pub fn blocksize(&self) -> f::Blocksize {
         if self.is_file() || self.is_link() {
         if self.is_file() || self.is_link() {
-            f::Blocks::Some(self.metadata.blocks())
+            // Note that metadata.blocks returns the number of blocks
+            // for 512 byte blocks according to the POSIX standard
+            // even though the physical block size may be different.
+            f::Blocksize::Some(self.metadata.blocks() * 512)
         }
         }
         else {
         else {
-            f::Blocks::None
+            f::Blocksize::None
         }
         }
     }
     }
 
 

+ 2 - 2
src/main.rs

@@ -75,7 +75,7 @@ fn main() {
             let writer = io::stdout();
             let writer = io::stdout();
 
 
             let console_width = options.view.width.actual_terminal_width();
             let console_width = options.view.width.actual_terminal_width();
-            let theme = options.theme.to_theme(console_width.is_some());
+            let theme = options.theme.to_theme(terminal_size::terminal_size().is_some());
             let exa = Exa { options, writer, input_paths, theme, console_width, git };
             let exa = Exa { options, writer, input_paths, theme, console_width, git };
 
 
             match exa.run() {
             match exa.run() {
@@ -104,7 +104,7 @@ fn main() {
         }
         }
 
 
         OptionsResult::InvalidOptions(error) => {
         OptionsResult::InvalidOptions(error) => {
-            eprintln!("exa: {error}");
+            eprintln!("eza: {error}");
 
 
             if let Some(s) = error.suggestion() {
             if let Some(s) = error.suggestion() {
                 eprintln!("{s}");
                 eprintln!("{s}");

+ 2 - 2
src/options/flags.rs

@@ -49,7 +49,7 @@ pub static INODE:      Arg = Arg { short: Some(b'i'), long: "inode",      takes_
 pub static LINKS:      Arg = Arg { short: Some(b'H'), long: "links",      takes_value: TakesValue::Forbidden };
 pub static LINKS:      Arg = Arg { short: Some(b'H'), long: "links",      takes_value: TakesValue::Forbidden };
 pub static MODIFIED:   Arg = Arg { short: Some(b'm'), long: "modified",   takes_value: TakesValue::Forbidden };
 pub static MODIFIED:   Arg = Arg { short: Some(b'm'), long: "modified",   takes_value: TakesValue::Forbidden };
 pub static CHANGED:    Arg = Arg { short: None,       long: "changed",    takes_value: TakesValue::Forbidden };
 pub static CHANGED:    Arg = Arg { short: None,       long: "changed",    takes_value: TakesValue::Forbidden };
-pub static BLOCKS:     Arg = Arg { short: Some(b'S'), long: "blocks",     takes_value: TakesValue::Forbidden };
+pub static BLOCKSIZE:  Arg = Arg { short: Some(b'S'), long: "blocksize",  takes_value: TakesValue::Forbidden };
 pub static TIME:       Arg = Arg { short: Some(b't'), long: "time",       takes_value: TakesValue::Necessary(Some(TIMES)) };
 pub static TIME:       Arg = Arg { short: Some(b't'), long: "time",       takes_value: TakesValue::Necessary(Some(TIMES)) };
 pub static ACCESSED:   Arg = Arg { short: Some(b'u'), long: "accessed",   takes_value: TakesValue::Forbidden };
 pub static ACCESSED:   Arg = Arg { short: Some(b'u'), long: "accessed",   takes_value: TakesValue::Forbidden };
 pub static CREATED:    Arg = Arg { short: Some(b'U'), long: "created",    takes_value: TakesValue::Forbidden };
 pub static CREATED:    Arg = Arg { short: Some(b'U'), long: "created",    takes_value: TakesValue::Forbidden };
@@ -84,7 +84,7 @@ pub static ALL_ARGS: Args = Args(&[
     &IGNORE_GLOB, &GIT_IGNORE, &ONLY_DIRS,
     &IGNORE_GLOB, &GIT_IGNORE, &ONLY_DIRS,
 
 
     &BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
     &BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
-    &BLOCKS, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK,
+    &BLOCKSIZE, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK,
     &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &NO_ICONS,
     &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &NO_ICONS,
 
 
     &GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT, &EXTENDED, &OCTAL, &SECURITY_CONTEXT
     &GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT, &EXTENDED, &OCTAL, &SECURITY_CONTEXT

+ 3 - 3
src/options/help.rs

@@ -6,11 +6,11 @@ use crate::options::parser::MatchedFlags;
 
 
 
 
 static USAGE_PART1: &str = "Usage:
 static USAGE_PART1: &str = "Usage:
-  exa [options] [files...]
+  eza [options] [files...]
 
 
 META OPTIONS
 META OPTIONS
   -?, --help         show list of command-line options
   -?, --help         show list of command-line options
-  -v, --version      show version of exa
+  -v, --version      show version of eza
 
 
 DISPLAY OPTIONS
 DISPLAY OPTIONS
   -1, --oneline      display one entry per line
   -1, --oneline      display one entry per line
@@ -51,7 +51,7 @@ LONG VIEW OPTIONS
   -i, --inode              list each file's inode number
   -i, --inode              list each file's inode number
   -m, --modified           use the modified timestamp field
   -m, --modified           use the modified timestamp field
   -n, --numeric            list numeric user and group IDs
   -n, --numeric            list numeric user and group IDs
-  -S, --blocks             show number of file system blocks
+  -S, --blocksize          show size of allocated file system blocks
   -t, --time FIELD         which timestamp field to list (modified, accessed, created)
   -t, --time FIELD         which timestamp field to list (modified, accessed, created)
   -u, --accessed           use the accessed timestamp field
   -u, --accessed           use the accessed timestamp field
   -U, --created            use the created timestamp field
   -U, --created            use the created timestamp field

+ 22 - 22
src/options/view.rs

@@ -82,7 +82,7 @@ impl Mode {
         // user about flags that won’t have any effect.
         // user about flags that won’t have any effect.
         if matches.is_strict() {
         if matches.is_strict() {
             for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
             for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
-                             &flags::HEADER, &flags::BLOCKS, &flags::TIME, &flags::GROUP, &flags::NUMERIC ] {
+                             &flags::HEADER, &flags::BLOCKSIZE, &flags::TIME, &flags::GROUP, &flags::NUMERIC ] {
                 if matches.has(option)? {
                 if matches.has(option)? {
                     return Err(OptionsError::Useless(option, false, &flags::LONG));
                     return Err(OptionsError::Useless(option, false, &flags::LONG));
                 }
                 }
@@ -223,7 +223,7 @@ impl Columns {
         let subdir_git_repos = matches.has(&flags::GIT_REPOS)?;
         let subdir_git_repos = matches.has(&flags::GIT_REPOS)?;
         let subdir_git_repos_no_stat = !subdir_git_repos && matches.has(&flags::GIT_REPOS_NO_STAT)?;
         let subdir_git_repos_no_stat = !subdir_git_repos && matches.has(&flags::GIT_REPOS_NO_STAT)?;
 
 
-        let blocks           = matches.has(&flags::BLOCKS)?;
+        let blocksize        = matches.has(&flags::BLOCKSIZE)?;
         let group            = matches.has(&flags::GROUP)?;
         let group            = matches.has(&flags::GROUP)?;
         let inode            = matches.has(&flags::INODE)?;
         let inode            = matches.has(&flags::INODE)?;
         let links            = matches.has(&flags::LINKS)?;
         let links            = matches.has(&flags::LINKS)?;
@@ -234,7 +234,7 @@ impl Columns {
         let filesize =    ! matches.has(&flags::NO_FILESIZE)?;
         let filesize =    ! matches.has(&flags::NO_FILESIZE)?;
         let user =        ! matches.has(&flags::NO_USER)?;
         let user =        ! matches.has(&flags::NO_USER)?;
 
 
-        Ok(Self { time_types, inode, links, blocks, group, git, subdir_git_repos, subdir_git_repos_no_stat, octal, security_context, permissions, filesize, user })
+        Ok(Self { time_types, inode, links, blocksize, group, git, subdir_git_repos, subdir_git_repos_no_stat, octal, security_context, permissions, filesize, user })
     }
     }
 }
 }
 
 
@@ -375,7 +375,7 @@ mod test {
                                    &flags::TIME,   &flags::MODIFIED, &flags::CHANGED,
                                    &flags::TIME,   &flags::MODIFIED, &flags::CHANGED,
                                    &flags::CREATED, &flags::ACCESSED,
                                    &flags::CREATED, &flags::ACCESSED,
                                    &flags::HEADER, &flags::GROUP,  &flags::INODE, &flags::GIT,
                                    &flags::HEADER, &flags::GROUP,  &flags::INODE, &flags::GIT,
-                                   &flags::LINKS,  &flags::BLOCKS, &flags::LONG,  &flags::LEVEL,
+                                   &flags::LINKS,  &flags::BLOCKSIZE, &flags::LONG,  &flags::LEVEL,
                                    &flags::GRID,   &flags::ACROSS, &flags::ONE_LINE, &flags::TREE,
                                    &flags::GRID,   &flags::ACROSS, &flags::ONE_LINE, &flags::TREE,
                                    &flags::NUMERIC ];
                                    &flags::NUMERIC ];
 
 
@@ -580,26 +580,26 @@ mod test {
         test!(long_across:   Mode <- ["--long", "--across"],   None;  Last => like Ok(Mode::Details(_)));
         test!(long_across:   Mode <- ["--long", "--across"],   None;  Last => like Ok(Mode::Details(_)));
 
 
         // Options that do nothing without --long
         // Options that do nothing without --long
-        test!(just_header:   Mode <- ["--header"],   None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_group:    Mode <- ["--group"],    None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_inode:    Mode <- ["--inode"],    None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_links:    Mode <- ["--links"],    None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_blocks:   Mode <- ["--blocks"],   None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_binary:   Mode <- ["--binary"],   None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_bytes:    Mode <- ["--bytes"],    None;  Last => like Ok(Mode::Grid(_)));
-        test!(just_numeric:  Mode <- ["--numeric"],  None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_header:   Mode <- ["--header"],    None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_group:    Mode <- ["--group"],     None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_inode:    Mode <- ["--inode"],     None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_links:    Mode <- ["--links"],     None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_blocks:   Mode <- ["--blocksize"], None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_binary:   Mode <- ["--binary"],    None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_bytes:    Mode <- ["--bytes"],     None;  Last => like Ok(Mode::Grid(_)));
+        test!(just_numeric:  Mode <- ["--numeric"],   None;  Last => like Ok(Mode::Grid(_)));
 
 
         #[cfg(feature = "git")]
         #[cfg(feature = "git")]
-        test!(just_git:      Mode <- ["--git"],    None;  Last => like Ok(Mode::Grid(_)));
-
-        test!(just_header_2: Mode <- ["--header"],   None;  Complain => err OptionsError::Useless(&flags::HEADER,  false, &flags::LONG));
-        test!(just_group_2:  Mode <- ["--group"],    None;  Complain => err OptionsError::Useless(&flags::GROUP,   false, &flags::LONG));
-        test!(just_inode_2:  Mode <- ["--inode"],    None;  Complain => err OptionsError::Useless(&flags::INODE,   false, &flags::LONG));
-        test!(just_links_2:  Mode <- ["--links"],    None;  Complain => err OptionsError::Useless(&flags::LINKS,   false, &flags::LONG));
-        test!(just_blocks_2: Mode <- ["--blocks"],   None;  Complain => err OptionsError::Useless(&flags::BLOCKS,  false, &flags::LONG));
-        test!(just_binary_2: Mode <- ["--binary"],   None;  Complain => err OptionsError::Useless(&flags::BINARY,  false, &flags::LONG));
-        test!(just_bytes_2:  Mode <- ["--bytes"],    None;  Complain => err OptionsError::Useless(&flags::BYTES,   false, &flags::LONG));
-        test!(just_numeric2: Mode <- ["--numeric"],  None;  Complain => err OptionsError::Useless(&flags::NUMERIC, false, &flags::LONG));
+        test!(just_git:      Mode <- ["--git"],       None;  Last => like Ok(Mode::Grid(_)));
+
+        test!(just_header_2: Mode <- ["--header"],    None;  Complain => err OptionsError::Useless(&flags::HEADER,  false, &flags::LONG));
+        test!(just_group_2:  Mode <- ["--group"],     None;  Complain => err OptionsError::Useless(&flags::GROUP,   false, &flags::LONG));
+        test!(just_inode_2:  Mode <- ["--inode"],     None;  Complain => err OptionsError::Useless(&flags::INODE,   false, &flags::LONG));
+        test!(just_links_2:  Mode <- ["--links"],     None;  Complain => err OptionsError::Useless(&flags::LINKS,   false, &flags::LONG));
+        test!(just_blocks_2: Mode <- ["--blocksize"], None;  Complain => err OptionsError::Useless(&flags::BLOCKSIZE,  false, &flags::LONG));
+        test!(just_binary_2: Mode <- ["--binary"],    None;  Complain => err OptionsError::Useless(&flags::BINARY,  false, &flags::LONG));
+        test!(just_bytes_2:  Mode <- ["--bytes"],     None;  Complain => err OptionsError::Useless(&flags::BYTES,   false, &flags::LONG));
+        test!(just_numeric2: Mode <- ["--numeric"],   None;  Complain => err OptionsError::Useless(&flags::NUMERIC, false, &flags::LONG));
 
 
         #[cfg(feature = "git")]
         #[cfg(feature = "git")]
         test!(just_git_2:    Mode <- ["--git"],    None;  Complain => err OptionsError::Useless(&flags::GIT,    false, &flags::LONG));
         test!(just_git_2:    Mode <- ["--git"],    None;  Complain => err OptionsError::Useless(&flags::GIT,    false, &flags::LONG));

+ 19 - 3
src/output/grid_details.rs

@@ -8,9 +8,10 @@ use term_grid as grid;
 use crate::fs::{Dir, File};
 use crate::fs::{Dir, File};
 use crate::fs::feature::git::GitCache;
 use crate::fs::feature::git::GitCache;
 use crate::fs::filter::FileFilter;
 use crate::fs::filter::FileFilter;
-use crate::output::cell::TextCell;
+use crate::output::cell::{TextCell, DisplayWidth};
 use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
 use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
 use crate::output::file_name::Options as FileStyle;
 use crate::output::file_name::Options as FileStyle;
+use crate::output::file_name::{ShowIcons, EmbedHyperlinks};
 use crate::output::grid::Options as GridOptions;
 use crate::output::grid::Options as GridOptions;
 use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
 use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
 use crate::output::tree::{TreeParams, TreeDepth};
 use crate::output::tree::{TreeParams, TreeDepth};
@@ -153,8 +154,23 @@ impl<'a> Render<'a> {
                        .collect::<Vec<_>>();
                        .collect::<Vec<_>>();
 
 
         let file_names = self.files.iter()
         let file_names = self.files.iter()
-                             .map(|file| self.file_style.for_file(file, self.theme).paint().promote())
-                             .collect::<Vec<_>>();
+            .map(|file| {
+                let filename = self.file_style.for_file(file, self.theme);
+                let contents = filename.paint();
+                let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
+                    (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + (spacing as usize),
+                    (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
+                    (EmbedHyperlinks::Off, _) => *contents.width(),
+                };
+
+                TextCell {
+                    contents,
+                    // with hyperlink escape sequences,
+                    // the actual *contents.width() is larger than actually needed, so we take only the filename
+                    width: DisplayWidth::from(width),
+                }
+            })
+            .collect::<Vec<_>>();
 
 
         let mut last_working_grid = self.make_grid(1, options, &file_names, rows.clone(), &drender);
         let mut last_working_grid = self.make_grid(1, options, &file_names, rows.clone(), &drender);
 
 

+ 104 - 21
src/output/render/blocks.rs

@@ -1,22 +1,67 @@
 use ansi_term::Style;
 use ansi_term::Style;
+use locale::Numeric as NumericLocale;
+use number_prefix::Prefix;
 
 
 use crate::fs::fields as f;
 use crate::fs::fields as f;
-use crate::output::cell::TextCell;
-
-
-impl f::Blocks {
-    pub fn render<C: Colours>(&self, colours: &C) -> TextCell {
-        match self {
-            Self::Some(blk)  => TextCell::paint(colours.block_count(), blk.to_string()),
-            Self::None       => TextCell::blank(colours.no_blocks()),
+use crate::output::cell::{TextCell, DisplayWidth};
+use crate::output::table::SizeFormat;
+
+
+impl f::Blocksize {
+    pub fn render<C: Colours>(self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
+        use number_prefix::NumberPrefix;
+
+        let size = match self {
+            Self::Some(s)             => s,
+            Self::None                => return TextCell::blank(colours.no_blocksize()),
+        };
+
+        let result = match size_format {
+            SizeFormat::DecimalBytes  => NumberPrefix::decimal(size as f64),
+            SizeFormat::BinaryBytes   => NumberPrefix::binary(size as f64),
+            SizeFormat::JustBytes     => {
+
+                // Use the binary prefix to select a style.
+                let prefix = match NumberPrefix::binary(size as f64) {
+                    NumberPrefix::Standalone(_)   => None,
+                    NumberPrefix::Prefixed(p, _)  => Some(p),
+                };
+
+                // But format the number directly using the locale.
+                let string = numerics.format_int(size);
+
+                return TextCell::paint(colours.blocksize(prefix), string);
+            }
+        };
+
+        let (prefix, n) = match result {
+            NumberPrefix::Standalone(b)   => return TextCell::paint(colours.blocksize(None), numerics.format_int(b)),
+            NumberPrefix::Prefixed(p, n)  => (p, n),
+        };
+
+        let symbol = prefix.symbol();
+        let number = if n < 10_f64 {
+            numerics.format_float(n, 1)
+        } else {
+            numerics.format_int(n.round() as isize)
+        };
+
+        TextCell {
+            // symbol is guaranteed to be ASCII since unit prefixes are hardcoded.
+            width: DisplayWidth::from(&*number) + symbol.len(),
+            contents: vec![
+                colours.blocksize(Some(prefix)).paint(number),
+                colours.unit(Some(prefix)).paint(symbol),
+            ].into(),
         }
         }
     }
     }
 }
 }
 
 
 
 
 pub trait Colours {
 pub trait Colours {
-    fn block_count(&self) -> Style;
-    fn no_blocks(&self) -> Style;
+    fn blocksize(&self, prefix: Option<Prefix>) -> Style;
+    fn unit(&self, prefix: Option<Prefix>)      -> Style;
+    fn no_blocksize(&self)                      -> Style;
 }
 }
 
 
 
 
@@ -26,32 +71,70 @@ pub mod test {
     use ansi_term::Colour::*;
     use ansi_term::Colour::*;
 
 
     use super::Colours;
     use super::Colours;
-    use crate::output::cell::TextCell;
+    use crate::output::cell::{TextCell, DisplayWidth};
+    use crate::output::table::SizeFormat;
     use crate::fs::fields as f;
     use crate::fs::fields as f;
 
 
+    use locale::Numeric as NumericLocale;
+    use number_prefix::Prefix;
 
 
     struct TestColours;
     struct TestColours;
 
 
     impl Colours for TestColours {
     impl Colours for TestColours {
-        fn block_count(&self) -> Style { Red.blink() }
-        fn no_blocks(&self)   -> Style { Green.italic() }
+        fn blocksize(&self, _prefix: Option<Prefix>) -> Style { Fixed(66).normal() }
+        fn unit(&self, _prefix: Option<Prefix>)      -> Style { Fixed(77).bold() }
+        fn no_blocksize(&self)                       -> Style { Black.italic() }
     }
     }
 
 
 
 
     #[test]
     #[test]
-    fn blocklessness() {
-        let blox = f::Blocks::None;
-        let expected = TextCell::blank(Green.italic());
+    fn directory() {
+        let directory = f::Blocksize::None;
+        let expected = TextCell::blank(Black.italic());
+        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
+    }
+
 
 
-        assert_eq!(expected, blox.render(&TestColours));
+    #[test]
+    fn file_decimal() {
+        let directory = f::Blocksize::Some(2_100_000);
+        let expected = TextCell {
+            width: DisplayWidth::from(4),
+            contents: vec![
+                Fixed(66).paint("2.1"),
+                Fixed(77).bold().paint("M"),
+            ].into(),
+        };
+
+        assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
     }
     }
 
 
 
 
     #[test]
     #[test]
-    fn blockfulity() {
-        let blox = f::Blocks::Some(3005);
-        let expected = TextCell::paint_str(Red.blink(), "3005");
+    fn file_binary() {
+        let directory = f::Blocksize::Some(1_048_576);
+        let expected = TextCell {
+            width: DisplayWidth::from(5),
+            contents: vec![
+                Fixed(66).paint("1.0"),
+                Fixed(77).bold().paint("Mi"),
+            ].into(),
+        };
+
+        assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
+    }
 
 
-        assert_eq!(expected, blox.render(&TestColours));
+
+    #[test]
+    fn file_bytes() {
+        let directory = f::Blocksize::Some(1_048_576);
+        let expected = TextCell {
+            width: DisplayWidth::from(9),
+            contents: vec![
+                Fixed(66).paint("1,048,576"),
+            ].into(),
+        };
+
+        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
     }
     }
 }
 }

+ 8 - 8
src/output/table.rs

@@ -48,7 +48,7 @@ pub struct Columns {
     // The rest are just on/off
     // The rest are just on/off
     pub inode: bool,
     pub inode: bool,
     pub links: bool,
     pub links: bool,
-    pub blocks: bool,
+    pub blocksize: bool,
     pub group: bool,
     pub group: bool,
     pub git: bool,
     pub git: bool,
     pub subdir_git_repos: bool,
     pub subdir_git_repos: bool,
@@ -89,9 +89,9 @@ impl Columns {
             columns.push(Column::FileSize);
             columns.push(Column::FileSize);
         }
         }
 
 
-        if self.blocks {
+        if self.blocksize {
             #[cfg(unix)]
             #[cfg(unix)]
-            columns.push(Column::Blocks);
+            columns.push(Column::Blocksize);
         }
         }
 
 
         if self.user {
         if self.user {
@@ -148,7 +148,7 @@ pub enum Column {
     FileSize,
     FileSize,
     Timestamp(TimeType),
     Timestamp(TimeType),
     #[cfg(unix)]
     #[cfg(unix)]
-    Blocks,
+    Blocksize,
     #[cfg(unix)]
     #[cfg(unix)]
     User,
     User,
     #[cfg(unix)]
     #[cfg(unix)]
@@ -184,7 +184,7 @@ impl Column {
             Self::FileSize   |
             Self::FileSize   |
             Self::HardLinks  |
             Self::HardLinks  |
             Self::Inode      |
             Self::Inode      |
-            Self::Blocks     |
+            Self::Blocksize  |
             Self::GitStatus  => Alignment::Right,
             Self::GitStatus  => Alignment::Right,
             Self::Timestamp(_) | 
             Self::Timestamp(_) | 
             _                => Alignment::Left,
             _                => Alignment::Left,
@@ -211,7 +211,7 @@ impl Column {
             Self::FileSize      => "Size",
             Self::FileSize      => "Size",
             Self::Timestamp(t)  => t.header(),
             Self::Timestamp(t)  => t.header(),
             #[cfg(unix)]
             #[cfg(unix)]
-            Self::Blocks        => "Blocks",
+            Self::Blocksize     => "Blocksize",
             #[cfg(unix)]
             #[cfg(unix)]
             Self::User          => "User",
             Self::User          => "User",
             #[cfg(unix)]
             #[cfg(unix)]
@@ -515,8 +515,8 @@ impl<'a> Table<'a> {
                 file.inode().render(self.theme.ui.inode)
                 file.inode().render(self.theme.ui.inode)
             }
             }
             #[cfg(unix)]
             #[cfg(unix)]
-            Column::Blocks => {
-                file.blocks().render(self.theme)
+            Column::Blocksize => {
+                file.blocksize().render(self.theme, self.size_format, &self.env.numeric)
             }
             }
             #[cfg(unix)]
             #[cfg(unix)]
             Column::User => {
             Column::User => {

+ 25 - 2
src/theme/mod.rs

@@ -202,8 +202,31 @@ impl ExtensionMappings {
 
 
 
 
 impl render::BlocksColours for Theme {
 impl render::BlocksColours for Theme {
-    fn block_count(&self)  -> Style { self.ui.blocks }
-    fn no_blocks(&self)    -> Style { self.ui.punctuation }
+    fn blocksize(&self, prefix: Option<number_prefix::Prefix>) -> Style {
+        use number_prefix::Prefix::*;
+
+        match prefix {
+            Some(Kilo | Kibi) => self.ui.size.number_kilo,
+            Some(Mega | Mebi) => self.ui.size.number_mega,
+            Some(Giga | Gibi) => self.ui.size.number_giga,
+            Some(_)           => self.ui.size.number_huge,
+            None              => self.ui.size.number_byte,
+        }
+    }
+
+    fn unit(&self, prefix: Option<number_prefix::Prefix>) -> Style {
+        use number_prefix::Prefix::*;
+
+        match prefix {
+            Some(Kilo | Kibi) => self.ui.size.unit_kilo,
+            Some(Mega | Mebi) => self.ui.size.unit_mega,
+            Some(Giga | Gibi) => self.ui.size.unit_giga,
+            Some(_)           => self.ui.size.unit_huge,
+            None              => self.ui.size.unit_byte,
+        }
+    }
+
+    fn no_blocksize(&self) -> Style { self.ui.punctuation }
 }
 }
 
 
 impl render::FiletypeColours for Theme {
 impl render::FiletypeColours for Theme {

+ 1 - 0
src/theme/ui_styles.rs

@@ -199,6 +199,7 @@ impl UiStyles {
             "gd" => self.git.deleted              = pair.to_style(),
             "gd" => self.git.deleted              = pair.to_style(),
             "gv" => self.git.renamed              = pair.to_style(),
             "gv" => self.git.renamed              = pair.to_style(),
             "gt" => self.git.typechange           = pair.to_style(),
             "gt" => self.git.typechange           = pair.to_style(),
+            "gi" => self.git.ignored              = pair.to_style(),
 
 
             "xx" => self.punctuation              = pair.to_style(),
             "xx" => self.punctuation              = pair.to_style(),
             "da" => self.date                     = pair.to_style(),
             "da" => self.date                     = pair.to_style(),

+ 1 - 1
xtests/outputs/help.ansitxt

@@ -41,7 +41,7 @@ LONG VIEW OPTIONS
   -i, --inode              list each file's inode number
   -i, --inode              list each file's inode number
   -m, --modified           use the modified timestamp field
   -m, --modified           use the modified timestamp field
   -n, --numeric            list numeric user and group IDs
   -n, --numeric            list numeric user and group IDs
-  -S, --blocks             show number of file system blocks
+  -S, --blocksize          show size of allocated file system blocks
   -t, --time FIELD         which timestamp field to list (modified, accessed, created)
   -t, --time FIELD         which timestamp field to list (modified, accessed, created)
   -u, --accessed           use the accessed timestamp field
   -u, --accessed           use the accessed timestamp field
   -U, --created            use the created timestamp field
   -U, --created            use the created timestamp field