Repository: eza-community/eza (language: rust)

Issue:
bug: incorrect grid width when using --hyperlink --classify
If eza does something unexpected, or its output looks wrong, or it displays an error on the screen, or if it outright crashes, then please include the following information in your report:

- The version of eza being used (`eza --version`)
- The command-line arguments you are using
- Your operating system and hardware platform

If it’s a crash, please include the full text of the crash that gets printed to the screen. If you’re seeing unexpected behaviour, a screenshot of the issue will help a lot.

---
![shot-2023-09-12-101825](https://github.com/eza-community/eza/assets/763350/fc08db9e-16e9-43d8-baf0-48f2fd78dfbd)

This version is packaged by Arch Linux.


Discussion / hints:

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 8036dd320..47c19e4ec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -118,6 +118,8 @@ vendored-openssl = ["git2/vendored-openssl"]
 vendored-libgit2 = ["git2/vendored-libgit2"]
 # Should only be used inside of flake.nix
 nix = []
+# Should only be used inside of flake.nix locally (not on CI)
+nix-local = []
 
 
 # make dev builds faster by excluding debug symbols
diff --git a/Justfile b/Justfile
index 956b656e7..0d94bc0fd 100644
--- a/Justfile
+++ b/Justfile
@@ -272,7 +272,7 @@ gen_test_dir:
 #
 # Required nix, likely won't work on windows.
 @itest:
-    nix build -L ./#trycmd
+    nix build -L ./#trycmd-local
 
 # Runs integration tests in nix sandbox, and dumps outputs.
 #
diff --git a/flake.nix b/flake.nix
index f383d3278..8de8d1e00 100644
--- a/flake.nix
+++ b/flake.nix
@@ -124,6 +124,22 @@
             inherit buildInputs;
           };
 
+          # TODO: add conditionally to checks.
+          # Run `nix build .#trycmd` to run integration tests
+          trycmd-local = naersk'.buildPackage {
+            src = ./.;
+            mode = "test";
+            doCheck = true;
+            # No reason to wait for release build
+            release = false;
+            # buildPhase files differ between dep and main phase
+            singleStep = true;
+            # set itests files creation date to unix epoch
+            buildPhase = ''touch --date=@0 tests/itest/*'';
+            cargoTestOptions = opts: opts ++ ["--features nix" "--features nix-local"];
+            inherit buildInputs;
+          };
+
           # Run `nix build .#trydump` to dump testing files
           trydump = naersk'.buildPackage {
             src = ./.;
@@ -135,7 +151,7 @@
             singleStep = true;
             # set itests files creation date to unix epoch
             buildPhase = ''touch --date=@0 tests/itest/*; rm tests/cmd/*.stdout || echo; rm tests/cmd/*.stderr || echo;'';
-            cargoTestOptions = opts: opts ++ ["--features nix"];
+            cargoTestOptions = opts: opts ++ ["--features nix" "--features nix-local"];
             TRYCMD = "dump";
             postInstall = ''
               cp dump $out -r
diff --git a/src/output/file_name.rs b/src/output/file_name.rs
index 232207573..11bc18913 100644
--- a/src/output/file_name.rs
+++ b/src/output/file_name.rs
@@ -314,7 +314,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     /// The character to be displayed after a file when classifying is on, if
     /// the file’s type has one associated with it.
     #[cfg(unix)]
-    fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
+    pub(crate) fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
         if file.is_executable_file() {
             Some("*")
         } else if file.is_directory() {
@@ -331,7 +331,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
     }
 
     #[cfg(windows)]
-    fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
+    pub(crate) fn classify_char(&self, file: &File<'_>) -> Option<&'static str> {
         if file.is_directory() {
             Some("/")
         } else if file.is_link() {
diff --git a/src/output/grid.rs b/src/output/grid.rs
index d84d1ec2e..cd0d900e3 100644
--- a/src/output/grid.rs
+++ b/src/output/grid.rs
@@ -4,7 +4,7 @@ use term_grid as tg;
 
 use crate::fs::filter::FileFilter;
 use crate::fs::File;
-use crate::output::file_name::Options as FileStyle;
+use crate::output::file_name::{Classify, Options as FileStyle};
 use crate::output::file_name::{EmbedHyperlinks, ShowIcons};
 use crate::theme::Theme;
 
@@ -44,11 +44,29 @@ impl<'a> Render<'a> {
         self.filter.sort_files(&mut self.files);
         for file in &self.files {
             let filename = self.file_style.for_file(file, self.theme);
+
+            // Calculate classification width
+            let classification_width =
+                if let Classify::AddFileIndicators = filename.options.classify {
+                    match filename.classify_char(file) {
+                        Some(s) => s.len(),
+                        None => 0,
+                    }
+                } else {
+                    0
+                };
+
             let contents = filename.paint();
-            #[rustfmt::skip]
-            let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) {
-                (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + spacing,
-                (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(),
+            let width = match (
+                filename.options.embed_hyperlinks,
+                filename.options.show_icons,
+            ) {
+                (EmbedHyperlinks::On, ShowIcons::On(spacing)) => {
+                    filename.bare_width() + classification_width + 1 + spacing
+                }
+                (EmbedHyperlinks::On, ShowIcons::Off) => {
+                    filename.bare_width() + classification_width
+                }
                 (EmbedHyperlinks::Off, _) => *contents.width(),
             };
 


Test patch:
diff --git a/tests/cli_tests.rs b/tests/cli_tests.rs
index d6c6e436a..cf1027adc 100644
--- a/tests/cli_tests.rs
+++ b/tests/cli_tests.rs
@@ -20,3 +20,9 @@ fn cli_windows_tests() {
 fn cli_nix_tests() {
     trycmd::TestCases::new().case("tests/cmd/*_nix.toml");
 }
+
+#[test]
+#[cfg(feature = "nix-local")]
+fn cli_nix_local_tests() {
+    trycmd::TestCases::new().case("tests/cmd/*_nix_local.toml");
+}
diff --git a/tests/cmd/classify-hyperlink-width-50_nix_local.stderr b/tests/cmd/classify-hyperlink-width-50_nix_local.stderr
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/cmd/classify-hyperlink-width-50_nix_local.stdout b/tests/cmd/classify-hyperlink-width-50_nix_local.stdout
new file mode 100644
index 000000000..1a79ff3fa
--- /dev/null
+++ b/tests/cmd/classify-hyperlink-width-50_nix_local.stdout
@@ -0,0 +1,5 @@
+]8;;file:///build/source/tests/itest/a/a]8;;/  ]8;;file:///build/source/tests/itest/exa/exa]8;;//  ]8;;file:///build/source/tests/itest/image.jpg.img.c.rs.log.png/image.jpg.img.c.rs.log.png]8;;/  ]8;;file:///build/source/tests/itest/m/m]8;;/  ]8;;file:///build/source/tests/itest/vagrant/vagrant]8;;//
+]8;;file:///build/source/tests/itest/b/b]8;;/  ]8;;file:///build/source/tests/itest/f/f]8;;/     ]8;;file:///build/source/tests/itest/index.svg/index.svg]8;;/                   ]8;;file:///build/source/tests/itest/n/n]8;;/  
+]8;;file:///build/source/tests/itest/c/c]8;;/  ]8;;file:///build/source/tests/itest/g/g]8;;/     ]8;;file:///build/source/tests/itest/j/j]8;;/                           ]8;;file:///build/source/tests/itest/o/o]8;;/  
+]8;;file:///build/source/tests/itest/d/d]8;;/  ]8;;file:///build/source/tests/itest/h/h]8;;/     ]8;;file:///build/source/tests/itest/k/k]8;;/                           ]8;;file:///build/source/tests/itest/p/p]8;;/  
+]8;;file:///build/source/tests/itest/e/e]8;;/  ]8;;file:///build/source/tests/itest/i/i]8;;/     ]8;;file:///build/source/tests/itest/l/l]8;;/                           ]8;;file:///build/source/tests/itest/q/q]8;;/  
diff --git a/tests/cmd/classify-hyperlink-width-50_nix_local.toml b/tests/cmd/classify-hyperlink-width-50_nix_local.toml
new file mode 100644
index 000000000..f5ae718f4
--- /dev/null
+++ b/tests/cmd/classify-hyperlink-width-50_nix_local.toml
@@ -0,0 +1,2 @@
+bin.name = "eza"
+args = "tests/itest/ --width 50 --classify --hyperlink"