From 10dd4bb705fa21dbfabdafb592c7d58454af01e6 Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Wed, 16 Mar 2022 16:08:14 +0900 Subject: [PATCH 1/4] Improve hover popup behavior --- autoload/fern.vim | 1 + autoload/fern/internal/drawer/hover_popup.vim | 92 +++++++++++-------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/autoload/fern.vim b/autoload/fern.vim index a734161..5b45313 100644 --- a/autoload/fern.vim +++ b/autoload/fern.vim @@ -47,6 +47,7 @@ call s:Config.config(expand(':p'), { \ 'comparators': {}, \ 'drawer_width': 30, \ 'drawer_keep': v:false, + \ 'drawer_hover_popup_delay': 0, \ 'mark_symbol': '*', \}) diff --git a/autoload/fern/internal/drawer/hover_popup.vim b/autoload/fern/internal/drawer/hover_popup.vim index 6729866..eff8ad6 100644 --- a/autoload/fern/internal/drawer/hover_popup.vim +++ b/autoload/fern/internal/drawer/hover_popup.vim @@ -1,10 +1,13 @@ +let s:win = v:null +let s:timer = 0 + function! fern#internal#drawer#hover_popup#init() abort if g:fern#disable_drawer_hover_popup return endif - if !exists('*popup_create') - call fern#logger#warn('hover popup is not supported, popup_create() + if !s:available() + call fern#logger#warn('hover popup is not supported, popup_create() or nvim environment \ does not exist. Disable this message \ with g:fern#disable_drawer_hover_popup.') return @@ -12,52 +15,67 @@ function! fern#internal#drawer#hover_popup#init() abort augroup fern_internal_drawer_hover_popup_init autocmd! * - autocmd CursorMoved call s:cursor_moved_event() + autocmd CursorMoved call timer_stop(s:timer) | call s:hide() | let s:timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show(fern#helper#new()) }) + autocmd BufLeave call timer_stop(s:timer) | call s:hide() augroup END endfunction -function! fern#internal#drawer#hover_popup#calculate_node_char_offset(node) abort - " find line offset where label text begins - let line = getline('.') - let labelbegin = charidx(line, strridx(line, a:node.label)) - let labelbegin = labelbegin < 0 ? 0 : labelbegin - - let windowid = win_getid() - - " get cursor position in drawer window (char- and byte-indexed) - let charpos = getcursorcharpos(windowid) - let pos = getcurpos(windowid) - - " get cursor position relative to screen - let cursorpos = screenpos(windowid, pos[1], pos[2]) - - " calculate screen column where label text begins - return cursorpos['col'] - charpos[2] + labelbegin -endfunction - -function! fern#internal#drawer#hover_popup#should_display_popup() abort - return len(getline('.')) >= winwidth(0) +function! s:available() abort + return has('nvim') || exists('*popup_create') endfunction -function! s:cursor_moved_event() abort - let helper = fern#helper#new() - - if fern#internal#drawer#hover_popup#should_display_popup() - call s:show_popup(helper) +function! s:show(helper) abort + if strdisplaywidth(getline('.')) <= winwidth(0) + return endif -endfunction -function! s:show_popup(helper) abort let node = a:helper.sync.get_cursor_node() if node is# v:null return endif - let label_offset = fern#internal#drawer#hover_popup#calculate_node_char_offset(node) - call popup_create(l:node.label, { - \ 'line': 'cursor', - \ 'col': label_offset + 1, - \ 'moved': 'any', - \}) + let line = getline('.') + if has('nvim') + let s:win = nvim_open_win(nvim_create_buf(v:false, v:true), v:false, { + \ 'relative': 'win', + \ 'bufpos': [line('.') - 2, 0], + \ 'width': strdisplaywidth(substitute(line, '[^[:print:]]*$', '', 'g')), + \ 'height': 1, + \ 'noautocmd': v:true, + \ 'style': 'minimal', + \ }) + else + let ui_width = screenpos(0, line('.'), 1).col - win_screenpos(0)[1] + let s:win = popup_create(line, { + \ 'line': 'cursor', + \ 'col': ui_width + 1, + \ 'maxwidth': strdisplaywidth(substitute(line, '[^[:print:]]*$', '', 'g')), + \ }) + endif + function! s:apply() abort closure + call setbufline('%', 1, line) + setlocal nowrap + setlocal cursorline + call a:helper.fern.renderer.syntax() + call a:helper.fern.renderer.highlight() + syntax clear FernRoot + syntax clear FernRootText + if has('nvim') + setlocal winhighlight=NormalFloat:Normal + endif + endfunction + call win_execute(s:win, 'call s:apply()', v:true) +endfunction + +function! s:hide() abort + if s:win is# v:null + return + endif + if has('nvim') + call nvim_win_hide(s:win) + else + call popup_close(s:win) + endif + let s:win = v:null endfunction From 4f830a0887359cb7e6570f8cce1413323df16a64 Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Tue, 22 Mar 2022 02:02:57 +0900 Subject: [PATCH 2/4] Improve complicated event handling Avoid duplicated line Improve buffer/window options --- autoload/fern/internal/drawer/hover_popup.vim | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/autoload/fern/internal/drawer/hover_popup.vim b/autoload/fern/internal/drawer/hover_popup.vim index eff8ad6..9303f0d 100644 --- a/autoload/fern/internal/drawer/hover_popup.vim +++ b/autoload/fern/internal/drawer/hover_popup.vim @@ -1,5 +1,5 @@ let s:win = v:null -let s:timer = 0 +let s:show_timer = 0 function! fern#internal#drawer#hover_popup#init() abort if g:fern#disable_drawer_hover_popup @@ -15,16 +15,24 @@ function! fern#internal#drawer#hover_popup#init() abort augroup fern_internal_drawer_hover_popup_init autocmd! * - autocmd CursorMoved call timer_stop(s:timer) | call s:hide() | let s:timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show(fern#helper#new()) }) - autocmd BufLeave call timer_stop(s:timer) | call s:hide() + autocmd CursorMoved call s:debounced_show() + autocmd BufLeave call s:hide() augroup END endfunction function! s:available() abort - return has('nvim') || exists('*popup_create') + let has_win = has('nvim') || exists('*popup_create') + return has_win && exists('*win_execute') +endfunction + +function! s:debounced_show() abort + call s:hide() + let s:show_timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show(fern#helper#new()) }) endfunction function! s:show(helper) abort + call s:hide() + if strdisplaywidth(getline('.')) <= winwidth(0) return endif @@ -35,11 +43,12 @@ function! s:show(helper) abort endif let line = getline('.') + let width = strdisplaywidth(substitute(line, '[^[:print:]]*$', '', 'g')) if has('nvim') let s:win = nvim_open_win(nvim_create_buf(v:false, v:true), v:false, { \ 'relative': 'win', \ 'bufpos': [line('.') - 2, 0], - \ 'width': strdisplaywidth(substitute(line, '[^[:print:]]*$', '', 'g')), + \ 'width': width, \ 'height': 1, \ 'noautocmd': v:true, \ 'style': 'minimal', @@ -49,17 +58,18 @@ function! s:show(helper) abort let s:win = popup_create(line, { \ 'line': 'cursor', \ 'col': ui_width + 1, - \ 'maxwidth': strdisplaywidth(substitute(line, '[^[:print:]]*$', '', 'g')), + \ 'maxwidth': width, \ }) endif + function! s:apply() abort closure call setbufline('%', 1, line) - setlocal nowrap - setlocal cursorline call a:helper.fern.renderer.syntax() call a:helper.fern.renderer.highlight() syntax clear FernRoot syntax clear FernRootText + + setlocal nowrap cursorline noswapfile nobuflisted buftype=nofile bufhidden=hide if has('nvim') setlocal winhighlight=NormalFloat:Normal endif @@ -68,11 +78,15 @@ function! s:show(helper) abort endfunction function! s:hide() abort + call timer_stop(s:show_timer) + if s:win is# v:null return endif if has('nvim') - call nvim_win_hide(s:win) + if nvim_win_is_valid(s:win) + call nvim_win_close(s:win, v:true) + endif else call popup_close(s:win) endif From 6011da3bb621ad7bc87780a3520c74784a7317ca Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Wed, 23 Mar 2022 12:49:11 +0900 Subject: [PATCH 3/4] Check fern buffer after debounce --- autoload/fern/internal/drawer/hover_popup.vim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/autoload/fern/internal/drawer/hover_popup.vim b/autoload/fern/internal/drawer/hover_popup.vim index 9303f0d..b97998e 100644 --- a/autoload/fern/internal/drawer/hover_popup.vim +++ b/autoload/fern/internal/drawer/hover_popup.vim @@ -27,17 +27,21 @@ endfunction function! s:debounced_show() abort call s:hide() - let s:show_timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show(fern#helper#new()) }) + let s:show_timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show() }) endfunction -function! s:show(helper) abort +function! s:show() abort + if &filetype !=# 'fern' + return + endif call s:hide() if strdisplaywidth(getline('.')) <= winwidth(0) return endif - let node = a:helper.sync.get_cursor_node() + let helper = fern#helper#new() + let node = helper.sync.get_cursor_node() if node is# v:null return endif @@ -64,8 +68,8 @@ function! s:show(helper) abort function! s:apply() abort closure call setbufline('%', 1, line) - call a:helper.fern.renderer.syntax() - call a:helper.fern.renderer.highlight() + call helper.fern.renderer.syntax() + call helper.fern.renderer.highlight() syntax clear FernRoot syntax clear FernRootText From c28c4abbbbf121e0a6fd46aec612618a69aa778d Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Wed, 23 Mar 2022 12:58:54 +0900 Subject: [PATCH 4/4] Add document for g:fern#drawer_hover_popup_delay --- doc/fern.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/fern.txt b/doc/fern.txt index f598b2e..ff8ffdd 100644 --- a/doc/fern.txt +++ b/doc/fern.txt @@ -417,7 +417,8 @@ VARIABLE *fern-variable* Set 1 to disable popups shown when the name of a node extends beyond the width of the drawer. - Note that this feature is not supported in Neovim. + Note that this feature is required the |win_execute| and + popup/floatwin features. Default: 0 @@ -530,6 +531,11 @@ VARIABLE *fern-variable* open or close. Default: |v:false| +*g:fern#drawer_hover_popup_delay* + A |Number| value to specify the delay time to show the hover popup. + See |g:fern#disable_drawer_hover_popup| + Default: |0| + *g:fern#mark_symbol* A |String| which is used as a mark symbol text. Note that users must restart Vim to apply changes.