# Fuzzy finding improved

So sometimes something on the command line is not exactly the way I want it.  Sometimes it gives me that itch that won't go away and whispers in the back of my mind, "fix it", "fix it now", "fix it now or the world will end".  So I took a bit of time to make [fzf](https://github.com/junegunn/fzf) work the way I wanted it to today.

+ First itch, *"No way to control recursion depth."*
    * Which is fine given `fzf`'s design choices.  But sometimes I just need to be able to find a file in a specific directory and the sub-directories are less important or sometimes might contain similar but wrong files.

> Leverage the well designed `fzf` app with *nix magic.

 Luckily shell aliases can contain all sorts of complex logic and chained apps to get what you want, in this case:

 ```bash
 alias fz="find . -maxdepth 1 | sed 's/^\.\///g' | fzf"
 ```

 And tada!  Now we can just use `fz` to search the current directory thanks to the `-maxdepth` argument.  The `sed` one liner strips the leading `./` that `find` includes in the output stream for a cleaner experience.

 Combine that with the [bat](https://github.com/sharkdp/bat) as a viewer to preview our files and we're starting to get somewhere.

 ```bash
 alias fz="find . -maxdepth 1 | sed 's/^\.\///g' | fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}'"
 ```

 + Second itch, *"Directories don't show anything useful in the preview."*
     * So we don't want endless recursion but having an idea of what is in each directory on our current file level via the preview would be useful.
> In fact the [tree](https://www.tecmint.com/linux-tree-command-examples/) output set to a depth limit would be perfect.

So bat doesn't include such conditional logic, but that's fine as it's built to do one thing and do it well.  And the preview is just a command to execute and show the output, so we can really put anything in there.  So I started a script to do the preview that opens the input and makes decisions on how to output on it.

*opener.bash*
```bash
#!/usr/bin/env bash

if [ -d "$1" ]; then
    tree -a -C -L 3 "$1"
else
    bat --color=always --style=numbers --line-range=:500 {} "$1"
fi
```

So just `chmod a+x` on the script and symlink that script into `~/.local/bin` which is in my `$PATH` (essentially installing it).  I usually drop the extension from command line scripts for convenience so the symlinking command looks like this:

```bash
ln -s $HOME/code/opener/opener.bash $HOME/.local/bin/opener
```

Then we update the alias to use the script, which ends up being much cleaner:

```bash
alias fz="find . -maxdepth 1 | sed 's/^\.\///g' | fzf --preview 'opener {}'
```

And **bam!**  Now we can see text files and directories in the preview pane of `fzf`.

+ Third itch, *"Binary files show me nothing useful in the preview."*
    * Ok, so normally I'd use a hex editor to get some idea of what is in a binary before jumping to something like [Ghidra](https://ghidra-sre.org/) to really see what's going on.  Usually there are some important clues in the very beginning of the binary that could be useful.

So I can include a test to try and determine if a file is a binary in the `opener` script.  The `file` command has some magic to help with this.  And there is a nifty Rust crate called [hexyl](https://github.com/sharkdp/hexyl) that I haven't had an opportunity to use yet that will let me read just first 4kB of a binary and display it in a *wonderous rainbow of colors*.  So this is how it shook out:

```bash
#!/usr/bin/env bash

if [ -d "$1" ]; then
        tree -a -C -L 3 "$1"
else
        BAT_TEST=$(file --mime "$1")
        if [[ $BAT_TEST == *binary ]] ; then
                hexyl -n 4kB "$1"
        else
                bat --color=always --style=numbers --line-range=:500 "$1"
        fi
fi
```

The binary test using `file` gets the mime output, which conveniently ends in "binary" if it thinks the file is a binary, so we can store that in the `BAT_TEST` variable and test for it with the conditional and run `hexyl` or else run `bat`.

Short, simple, fast and maybe even useful in more ways than I originally intended.  Now the preview script shows something useful for every file it highlights and I have enough focus to narrow down to just where I am working.  So in some ways this is a replacement for `ls` (which is a bit strange as I already have 2 of those).  But it satisfies my desire for a tool that is more forensic, gives a lot more information up front and can reveal clues to what is going on in whatever file store I happen to be looking in.

Itch scratched.

Code and instructions are here: [opener](https://github.com/gatewaynode/opener)
