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..b97998e 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:show_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,85 @@ 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 s:debounced_show() + autocmd BufLeave 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 +function! s:available() abort + let has_win = has('nvim') || exists('*popup_create') + return has_win && exists('*win_execute') endfunction -function! fern#internal#drawer#hover_popup#should_display_popup() abort - return len(getline('.')) >= winwidth(0) +function! s:debounced_show() abort + call s:hide() + let s:show_timer = timer_start(g:fern#drawer_hover_popup_delay, { -> s:show() }) endfunction -function! s:cursor_moved_event() abort - let helper = fern#helper#new() +function! s:show() abort + if &filetype !=# 'fern' + return + endif + call s:hide() - if fern#internal#drawer#hover_popup#should_display_popup() - call s:show_popup(helper) + if strdisplaywidth(getline('.')) <= winwidth(0) + return endif -endfunction -function! s:show_popup(helper) abort - 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 - 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('.') + 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': width, + \ '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': width, + \ }) + endif + + function! s:apply() abort closure + call setbufline('%', 1, line) + call helper.fern.renderer.syntax() + call 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 + endfunction + call win_execute(s:win, 'call s:apply()', v:true) +endfunction + +function! s:hide() abort + call timer_stop(s:show_timer) + + if s:win is# v:null + return + endif + if has('nvim') + if nvim_win_is_valid(s:win) + call nvim_win_close(s:win, v:true) + endif + else + call popup_close(s:win) + endif + let s:win = v:null endfunction 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.