Repository: sharkdp/fd (language: rust)

Issue:
Colourful output on Windows (in Git Bash)
I've seen the talks leading up to colour output support, namely #129 #137

However, [`bat`](http://github.com/sharkdp/bat) works and emits a colourful output, by default. Below is `bat ~/Desktop/desktop.ini`:

![`bat` output with colours working](https://user-images.githubusercontent.com/1969470/63160946-42dfe780-c01f-11e9-8b67-8cab4a74f0db.png)

It seems colourful output *can* be supported.

I'm using Git Bash 2.20-something. Git Bash can be set up to run with *MinTTY*, which gets you a nice terminal emulator, unlike that of the default `cmd`. Git Bash is the nicest and best way to get Bash shell environment running for Windows, and this is like the only Shell I use on Windows, so it's surprising that if `bat` colours work, `fd` does not.


Discussion / hints:
Thank you for the feedback.

How do you run `fd`? What does the output look like? On Windows, the `LS_COLORS` environment variable is typically not set, so we would only expect to get (default) colors for directories (and symlinks).

Could you try to run `fd --color=always …` and pipe the output to a file? This way, we could see if any ANSI escape codes are generated.
Meanwhile, I checked, and the output of `bat` in a standard `cmd.exe` looks ugly. So this request could be specific to Git Bash.

I have `LS_COLORS`, because this is a Bash shell running inside a Windows process.

Both `fd` and `fd --color=always` produces the same output:
![image](https://user-images.githubusercontent.com/1969470/63256470-edeade00-c277-11e9-839f-5204122146d5.png)

Could you please run
```
fd --color=always > output.txt
```
and check if the `output.txt` file includes ANSI escape sequences?

If not, could you please show the content of `LS_COLORS`?
No escape sequences, only normal characters.

> 17:59 ~ $ echo $LS_COLORS
> `rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01: or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32 :*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=0 1;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*. zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.x z=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31 :*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01 ;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz =01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:* .jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm =01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35: *.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=0 1;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:* .m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01; 35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl= 01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.o gv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36 :*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=0 0;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:`



(I guess this is just a copy-and-paste error, but there shouldn't be any spaces in `$LS_COLORS`)

Could you please run `fd` in a folder where you would definitely expect some entries to be colorized (e.g. with subdirectories)? In your screenshot above, I wouldn't expect anything to be colorized.
Note that the comment on  #129 about termcolor does not apply any more: termcolor supports truecolors and ansi256 colors.
@sharkdp I had no better idea to put it up on GitHub because the output is a single line, which would look idiotic with a horizontal scrollbar.
This is the default `LS_COLOURS` you get on a Debian(?)-based machine? I use no customisations to it, none of my (userspace) `.bash` or `.profile` files contain any changes from that.

Ran it with subdirectories. No escape sequences or anything is printed. Ran it with hidden directories, something with `README.md`, it's all the same.

Feels like the binary doesn't want to output colours at all.

`bat`'s output is full of escape sequences, to the point that the `bat` binary works with this MinTTY shell, but doesn't work at all with the traditional `cmd.exe`, the escape sequences garble the output up.
Which Windows version are you on?

Could you please show the output of (run this in a new, temporary directory):
```bash
mkdir test_directory
touch test.md test.txt

fd --color=always | cat -A
echo
export LS_COLORS="di=01;34:*.md=01;31"
fd --color=always | cat -A
```
![image](https://user-images.githubusercontent.com/1969470/65061880-1b13d480-d97b-11e9-8bfa-37b795bdcbba.png)

Win7 x64 SP1 updated a few months ago.

The terminal emulator is not the standard `cmd.exe` it's coming from MinTTY via *Git Bash* `git version 2.20.1.windows.1`.
Ok, thank you.

The reason that this happens is the following:
https://github.com/sharkdp/fd/blob/b027b2c32285253b5866f934acc66fcd695ea649/src/main.rs#L125-L129

https://github.com/sharkdp/fd/blob/b027b2c32285253b5866f934acc66fcd695ea649/src/main.rs#L133-L134

If you have `--color=always`, `colored_output` should be `true` first. But then, in the second part which is only enabled on Windows, we call `ansi_term::enable_ansi_support()` which enables ANSI escape sequences in PowerShell/`cmd.exe` on Windows 10(!). If this function fails (presumably on Windows 7), the `.is_ok()` call returns `false`, and `colored_output` is set to `false` for the remainder of the `fd` run.

So even though your terminal emulator would actually already support ANSI escape sequences, `fd` switches off color support because "enabling ANSI escape sequences" failed.

I think there are a few ways forward:

* Ignore the result of `ansi_term::enable_ansi_support().is_ok()` if `--color=always` is enabled. However, this would force users MinTTY users to use `--color=always` all the time, which is not a good idea (when you want to pipe the `fd` output to another program).
* Use an (existing?) environment variable to toggle between using `enable_ansi_support()` or not. That would certainly work, but would add additional documentation overhead and would not work out of the box.
* Add special handling for Windows terminal emulators like MinTTY which would basically skip the whole `enable_ansi_support()` part. If there is an easy way to detect such terminals (without adding specific detection logic for each and every terminal emulator), that would be a good solution.
* Try to move this kind of logic into `ansi_term`...?
* ....
You have managed to turn off escape sequences in `bat` when its output is going away on a pipe. Same logic could work here, and thus you don't need to specify `always` and use it as a default *unless* a pipe happens?
Yes, of course. We already do this. That's the `_ => atty::is(Stream::Stdout)` part which triggers in the "auto" case and checks whether `Stdout` is connected to a TTY (interactive terminal).

The problem is the second part. So far, we wanted to *disable* color support on Windows if `ansi_term::enable_ansi_support()` failed. This is useful for old Windows versions with `cmd.exe`, for example.
The way that `bat` "solves" this is another possibility:

* Simply ignore the result of `ansi_term::enable_ansi_support().is_ok()` in all cases. This would mean that colors would show up on MinTTY. However, it would also mean that ANSI escape sequences show up in `cmd.exe` (and PowerShell?) on older Windows versions.
Just ran into this.

I think `fd` is trying to be too smart here.

`fd` needs to account for situations where users operating doesnt support
ANSI (Windows 7, 8), but their terminal does (Mintty).

Currently that case is not handled. `fd` assumes that if users OS doesnt have
built in support, then they have no way to see color, regardless of what 3rd
party solutions might exist.

Im not sure how to fix it, but `fd` should be accounting for a users terminal
capabilities rather than OS capabilities.

I would be okay with the `bat` solution. This would be a regression for users with old Windows versions, but I guess if we have to choose, we rather provide a good default behavior for users with a recent version of Windows.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56d2f1853..5f60095c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,13 @@
 
 ## Changes
 
+- Colored output will now be enabled by default on older Windows versions.
+  This allows the use of colored output if the terminal supports it (e.g.
+  MinTTY, Git Bash). On the other hand, this will be a regression for users
+  on older Windows versions with terminals that do not support ANSI escape
+  sequences. Affected users can use an alias `fd="fd --color=never"` to
+  continue using `fd` without colors. There is no change of behavior for
+  Windows 10. See #469.
 - When using `--glob` in combination with `--full-path`, a `*` character does not match a path
   separation character (`/` or `\\`) anymore. You can use `**` for that. This allows things like
   `fd -p -g '/some/base/path/*/*/*.txt'` which would previously match to arbitrary depths (instead
diff --git a/src/main.rs b/src/main.rs
index 1e4aefd16..5bfd08072 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -147,7 +147,7 @@ fn run() -> Result<ExitCode> {
     let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());
 
     #[cfg(windows)]
-    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();
+    ansi_term::enable_ansi_support().ok();
 
     let ls_colors = if colored_output {
         Some(LsColors::from_env().unwrap_or_default())


Test patch: