Skip to content

Commit

Permalink
[vim] Popup window support for both Vim and Neovim
Browse files Browse the repository at this point in the history
e.g.
  let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }

Based on the code from junegunn/fzf.vim#821 (comment)
by @lacygoill.
  • Loading branch information
junegunn committed Feb 3, 2020
1 parent 293dd76 commit 7ceb58b
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 61 deletions.
56 changes: 20 additions & 36 deletions README-VIM.md
Expand Up @@ -184,6 +184,7 @@ The following table summarizes the available options.
| `dir` | string | Working directory |
| `up`/`down`/`left`/`right` | number/string | (Layout) Window position and size (e.g. `20`, `50%`) |
| `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new`) |
| `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |

`options` entry can be either a string or a list. For simple cases, string
should suffice, but prefer to use list type to avoid escaping issues.
Expand All @@ -193,6 +194,16 @@ call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
```

When `window` entry is a dictionary, fzf will start in a popup window. The
following options are allowed:

- Required:
- `width` [float]
- `height` [float]
- Optional:
- `highlight` [string default `'Comment'`]: Highlight group for border
- `rounded` [boolean default `v:true`]: Use rounded border

`fzf#wrap`
----------

Expand Down Expand Up @@ -276,44 +287,17 @@ The latest versions of Vim and Neovim include builtin terminal emulator
- On Terminal Vim with a non-default layout
- `call fzf#run({'left': '30%'})` or `let g:fzf_layout = {'left': '30%'}`

#### Starting fzf in Neovim floating window
#### Starting fzf in a popup window

```vim
" Using floating windows of Neovim to start fzf
if has('nvim')
function! FloatingFZF(width, height, border_highlight)
function! s:create_float(hl, opts)
let buf = nvim_create_buf(v:false, v:true)
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
let win = nvim_open_win(buf, v:true, opts)
call setwinvar(win, '&winhighlight', 'NormalFloat:'.a:hl)
call setwinvar(win, '&colorcolumn', '')
return buf
endfunction
" Size and position
let width = float2nr(&columns * a:width)
let height = float2nr(&lines * a:height)
let row = float2nr((&lines - height) / 2)
let col = float2nr((&columns - width) / 2)
" Border
let top = '╭' . repeat('─', width - 2) . '╮'
let mid = '│' . repeat(' ', width - 2) . '│'
let bot = '╰' . repeat('─', width - 2) . '╯'
let border = [top] + repeat([mid], height - 2) + [bot]
" Draw frame
let s:frame = s:create_float(a:border_highlight, {'row': row, 'col': col, 'width': width, 'height': height})
call nvim_buf_set_lines(s:frame, 0, -1, v:true, border)
" Draw viewport
call s:create_float('Normal', {'row': row + 1, 'col': col + 2, 'width': width - 4, 'height': height - 2})
autocmd BufWipeout <buffer> execute 'bwipeout' s:frame
endfunction
let g:fzf_layout = { 'window': 'call FloatingFZF(0.9, 0.6, "Comment")' }
endif
" Required:
" - width [float]
" - height [float]
"
" Optional:
" - highlight [string default 'Comment']: Highlight group for border
" - rounded [boolean default v:true]: Use rounded border
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
```

#### Hide statusline
Expand Down
47 changes: 23 additions & 24 deletions doc/fzf.txt
@@ -1,4 +1,4 @@
fzf.txt fzf Last change: November 23 2019
fzf.txt fzf Last change: February 3 2020
FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
==============================================================================

Expand All @@ -11,7 +11,7 @@ FZF - TABLE OF CONTENTS *fzf* *fzf-to
fzf#wrap
Tips
fzf inside terminal buffer
Starting fzf in Neovim floating window
Starting fzf in a popup window
Hide statusline
License

Expand Down Expand Up @@ -204,6 +204,7 @@ The following table summarizes the available options.
`dir` | string | Working directory
`up` / `down` / `left` / `right` | number/string | (Layout) Window position and size (e.g. `20` , `50%` )
`window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `verticalaboveleft30new` )
`window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}` )
---------------------------+---------------+----------------------------------------------------------------------

`options` entry can be either a string or a list. For simple cases, string
Expand All @@ -212,6 +213,16 @@ should suffice, but prefer to use list type to avoid escaping issues.
call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
<
When `window` entry is a dictionary, fzf will start in a popup window. The
following options are allowed:

- Required:
- `width` [float]
- `height` [float]
- Optional:
- `highlight` [string default `'Comment'`]: Highlight group for border
- `rounded` [boolean default `v:true`]: Use rounded border


FZF#WRAP
==============================================================================
Expand Down Expand Up @@ -291,29 +302,17 @@ The latest versions of Vim and Neovim include builtin terminal emulator
- `callfzf#run({'left': '30%'})` or `letg:fzf_layout= {'left': '30%'}`


Starting fzf in Neovim floating window~
*fzf-starting-fzf-in-neovim-floating-window*
Starting fzf in a popup window~
*fzf-starting-fzf-in-a-popup-window*
>
" Using floating windows of Neovim to start fzf
if has('nvim')
let $FZF_DEFAULT_OPTS .= ' --border --margin=0,2'
function! FloatingFZF()
let width = float2nr(&columns * 0.9)
let height = float2nr(&lines * 0.6)
let opts = { 'relative': 'editor',
\ 'row': (&lines - height) / 2,
\ 'col': (&columns - width) / 2,
\ 'width': width,
\ 'height': height }
let win = nvim_open_win(nvim_create_buf(v:false, v:true), v:true, opts)
call setwinvar(win, '&winhighlight', 'NormalFloat:Normal')
endfunction
let g:fzf_layout = { 'window': 'call FloatingFZF()' }
endif
" Required:
" - width [float]
" - height [float]
"
" Optional:
" - highlight [string default 'Comment']: Highlight group for border
" - rounded [boolean default v:true]: Use rounded border
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
<

Hide statusline~
Expand Down
69 changes: 68 additions & 1 deletion plugin/fzf.vim
Expand Up @@ -650,7 +650,11 @@ function! s:split(dict)
let ppos = s:getpos()
try
if s:present(a:dict, 'window')
execute 'keepalt' a:dict.window
if type(a:dict.window) == type({})
call s:popup(a:dict.window)
else
execute 'keepalt' a:dict.window
endif
elseif !s:splittable(a:dict)
execute (tabpagenr()-1).'tabnew'
else
Expand Down Expand Up @@ -798,6 +802,69 @@ function! s:callback(dict, lines) abort
endif
endfunction

if has('nvim')
function s:create_popup(hl, opts) abort
let buf = nvim_create_buf(v:false, v:true)
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
let border = has_key(opts, 'border') ? remove(opts, 'border') : []
let win = nvim_open_win(buf, v:true, opts)
call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl)
call setwinvar(win, '&colorcolumn', '')
if !empty(border)
call nvim_buf_set_lines(buf, 0, -1, v:true, border)
endif
return buf
endfunction
else
function! s:create_popup(hl, opts) abort
let is_frame = has_key(a:opts, 'border')
let buf = is_frame ? '' : term_start(&shell, #{hidden: 1})
let id = popup_create(buf, #{
\ line: a:opts.row,
\ col: a:opts.col,
\ minwidth: a:opts.width,
\ minheight: a:opts.height,
\ zindex: 50 - is_frame,
\ })

if is_frame
call setwinvar(id, '&wincolor', a:hl)
call setbufline(winbufnr(id), 1, a:opts.border)
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
else
execute 'autocmd BufWipeout * ++once bwipeout! '..buf
endif
return winbufnr(id)
endfunction
endif

function! s:popup(opts) abort
" Size and position
let width = float2nr(&columns * a:opts.width)
let height = float2nr(&lines * a:opts.height)
let row = float2nr((&lines - height) / 2)
let col = float2nr((&columns - width) / 2)

" Border
let edges = get(a:opts, 'rounded', 1) ? ['', '', '', ''] : ['', '', '', '']
let bar = repeat('', width - 2)
let top = edges[0] .. bar .. edges[1]
let mid = '' .. repeat(' ', width - 2) .. ''
let bot = edges[2] .. bar .. edges[3]
let border = [top] + repeat([mid], height - 2) + [bot]

let highlight = get(a:opts, 'highlight', 'Comment')
let frame = s:create_popup(highlight, {
\ 'row': row, 'col': col, 'width': width, 'height': height, 'border': border
\ })
call s:create_popup('Normal', {
\ 'row': row + 1, 'col': col + 2, 'width': width - 4, 'height': height - 2
\ })
if has('nvim')
execute 'autocmd BufWipeout <buffer> bwipeout '..frame
endif
endfunction

let s:default_action = {
\ 'ctrl-t': 'tab split',
\ 'ctrl-x': 'split',
Expand Down

10 comments on commit 7ceb58b

@sluongng
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is awesome 👍

@markwu
Copy link

@markwu markwu commented on 7ceb58b Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I use let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }, but nvim/vim (master head) just shows me errors.

:FzfFiles

處理 function fzf#vim#files[15]..<SNR>194_fzf[18]..fzf#run[64]..<SNR>113_execute_term[3]..<SNR>113_split 時發生錯誤:
行    9:
E731: using Dictionary as a String

@junegunn
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mark64 It means that your Vim is not loading the latest version of this fzf plugin file. See https://github.com/junegunn/fzf.vim#installation

@markwu
Copy link

@markwu markwu commented on 7ceb58b Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. I use brew version of fzf. I think I should install it from github directly. Thanks!

@markwu
Copy link

@markwu markwu commented on 7ceb58b Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works! It's so awesome. Thank you.

@ahmedelgabri
Copy link

@ahmedelgabri ahmedelgabri commented on 7ceb58b Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting this error in vim 8.2

VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Feb  3 2020 01:40:55)                                                                                                                                                
macOS version                                                                                                                                                                                                    
Included patches: 1-200
Error detected while processing function fzf#vim#files[15]..<SNR>41_fzf[18]..fzf#run[64]..<SNR>29_execute_term:                                                                                                   
line   67:                                                                                                                                                                                                      
E948: Job still running (add ! to end the job)

Then it opens a window with a sh shell instead of my default zsh

Minimal vimrc

call plug#begin('~/.vim/plugged')
Plug 'junegunn/fzf'
Plug 'junegunn/fzf.vim'
call plug#end()
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }

Screen Shot 2020-02-04 at 11 30 17

@llhhaa
Copy link

@llhhaa llhhaa commented on 7ceb58b Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also getting the above error, with the latest Vim, fzf (installed via Plug), and fzf.vim.

@junegunn
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0896036 should help.

@llhhaa
Copy link

@llhhaa llhhaa commented on 7ceb58b Feb 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Issue fixed for me.

@muminoff
Copy link

@muminoff muminoff commented on 7ceb58b Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@junegunn This feature is cool but is there any possibility to use the current color scheme for the preview part? They are different.

Please sign in to comment.