Fancy fzf on neovim
Tags: vim, productivity
Published: 2020-06-06 16:29:27

After neovim 4.0 and vim 8.1, both of them have an amazing feature: popup window.
That's take a look how it makes fzf better.

This is how fzf looks in terminal buffer.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h82wwucko0rye0nol386.gif)

This is how fzf looks in popup window.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/305xh1swntm2ck39ozng.gif)

There are two reason why I prefer popup window.
1. The position of cursor doesn't move.
2. Looks more like a "menu".



## Configure fzf to use popup window
Thanks to the author of fzf, fzf has supported the popup window.
```
let g:fzf_layout = { 'window': { 'width': 0.8, 'height': 0.5, 'highlight': 'Comment' } }
```
When the window entry is a dictionary, fzf will treat the value as the attribute of popup window. Here are some attributes you can set

**Required**
- width: float range [0 ~ 1]                                                                                                                                          
- height: float range [0 ~ 1]
                                                                                                                                            
**Optional**
                                                                                                                                                                
- yoffset: float default 0.5 range [0 ~ 1]                                                                                                                               
- xoffset: float default 0.5 range [0 ~ 1]                                                                                                                               
- highlight: [string]: Highlight group for border                                                                                                        
- border: [string default rounded]: Border style
 
Avaliable Border Style: rounded: / sharp / horizontal / vertical / top / bottom / left / right 

## Customize the colors
If you have set colors in FZF_DEFAULT_OPTS, then you don't have to worry this. If not, you can set in shell or neovim.

You can find those elements which can be customized here: https://github.com/junegunn/fzf/blob/a9fba1c8496f7352de55b9fe5f36f23872e5a364/README-VIM.md#L140

**shell**
```
export FZF_DEFAULT_OPTS='
    --color fg:14,fg+:3,hl:5,hl+:5,bg:-1,bg+:-1
    --color info:6,prompt:6,spinner:1,pointer:3
'
```
Well, yes, pass two '--color' to fzf is legal.

**neovim**
It's a little harder than in shell. You need to set `g:fzf_colors`
```
let g:fzf_colors =
  \ { 'fg+':     ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
  \ 'bg+':     ['bg', 'CursorLine', 'CursorColumn'] }

```
*Uh...what are them ?*

For example
```
'bg+':     ['bg', 'CursorLine', 'CursorColumn']
```
The logic is 
1. FZF will color 'bg+' with the 'bg' of highlight group 'CursorLine'. 
2. If 'CursorLine' doesn't have 'bg', then find in  'CursorColumn' and so on. 
3. If none of them have 'bg', use default value.

If you don't like to use an unrelated highlight group like me, you can create new ones for fzf.
```
hi! fzf_fg ctermfg=14                                                                                                                                                       
hi! fzf_fgp ctermfg=3                                                                                                                                                       
hi! fzf_hl ctermfg=5                                                                                                                                                        
hi! fzf_hlp ctermfg=5                                                                                                                                                       
hi! fzf_info ctermfg=6                                                                                                                                                      
hi! fzf_prompt ctermfg=6                                                                                                                                                    
hi! fzf_spinner ctermfg=6                                                                                                                                                   
hi! fzf_pointer ctermfg=3
```
```
let g:fzf_colors = {                                                                                                                                                        
  \ 'fg':      ['fg', 'fzf_fg'],                                                                                                                                            
  \ 'hl':      ['fg', 'fzf_hl'],                                                                                                                                            
  \ 'fg+':     ['fg', 'fzf_fgp'],                                                                                                                                           
  \ 'hl+':     ['fg', 'fzf_hlp'],                                                                                                                                           
  \ 'info':    ['fg', 'fzf_info'],                                                                                                                                          
  \ 'prompt':  ['fg', 'fzf_prompt'],                                                                                                                                        
  \ 'pointer': ['fg', 'fzf_pointer'],                                                                                                                                       
  \ 'spinner': ['fg', 'fzf_spinner'] }
```
By the way, you can also do this to the highlight attribute of g:fzf_layout.

FZF will generate the color setting from `g:fzf_colors`. To check the generated result, use this vim command
```
:echo fzf#wrap()
``` 
If enerything is good, fzf will trans `g:fzf_colors` to the format of FZF_DEFAULT_OPTS
```
{'options': '''--color=info:6,spinner:6,hl:5,fg:14,fg+:3,pointer:3,prompt:6,hl+:5''  --expect=ctrl-v,ctrl-x,ctrl-t', 'sink*': func
tion('283'), 'window': {'highlight': 'fzf_popup', 'width': 0.8, 'height': 0.5}, '_action': {'ctrl-v': 'vsplit', 'ctrl-x': 'split',
 'ctrl-t': 'tab split'}}
```


## More
*Well, how do I know the color number ?*

If you use 256 color, you can reference this cheat sheet: https://jonasjacek.github.io/colors/ 

Or this tiny script
```
for i in {0..255}; do
    printf "\x1b[38;5;${i}m%-9s\x1b[0m" "colour${i}"
    if (( $i % 5 == 0 )); then                            
        printf "\n"                                   
    else                                                  
        printf " "                                    
    fi                                                    
done       
```

## Reference
https://github.com/junegunn/fzf/blob/a9fba1c8496f7352de55b9fe5f36f23872e5a364/README-VIM.md#L140
https://jonasjacek.github.io/colors/