"====================================================================== " " preview.vim - " " Created by skywind on 2020/01/11 " Last Modified: 2021/12/13 22:32 " "====================================================================== " vim: set noet fenc=utf-8 ff=unix sts=4 sw=4 ts=4 : "---------------------------------------------------------------------- " private object "---------------------------------------------------------------------- let s:private = {'winid': -1, 'background': -1, 'state':0} "---------------------------------------------------------------------- " position to a proper location "---------------------------------------------------------------------- function! s:around_cursor(width, height) let cursor_pos = quickui#core#cursor_pos() let row = cursor_pos[0] - a:height let col = cursor_pos[1] + 1 if quickui#core#in_screen(row, col, a:width, a:height) return [row, col] endif if col + a:width - 1 > &columns let col = col - (1 + a:width) if quickui#core#in_screen(row, col, a:width, a:height) return [row, col] endif endif if row < 1 let row = row + (1 + a:height) if quickui#core#in_screen(row, col, a:width, a:height) return [row, col] endif endif if cursor_pos[0] - a:height - 2 < 1 let row = cursor_pos[0] + 1 else let row = cursor_pos[0] - a:height endif if cursor_pos[1] + a:width + 2 < &columns let col = cursor_pos[1] + 1 else let col = cursor_pos[1] - a:width endif return quickui#core#screen_fit(row, col, a:width, a:height) endfunc "---------------------------------------------------------------------- " create preview window "---------------------------------------------------------------------- function! quickui#preview#display(content, opts) call quickui#preview#close() if type(a:content) == v:t_string && filereadable(a:content) == 0 call quickui#utils#errmsg('E212: Can not open file: '. a:content) return -1 endif let s:private.state = 0 if type(a:content) == v:t_string silent let source = bufadd(a:content) silent call bufload(source) elseif type(a:content) == v:t_list let source = a:content endif let winid = -1 let title = '' if has_key(a:opts, 'title') && (a:opts.title != '') let title = ' ' . a:opts.title .' ' endif let w = get(a:opts, 'w', -1) let h = get(a:opts, 'h', -1) let w = (w < 0)? 50 : w let h = (h < 0)? 10 : h let border = get(a:opts, 'border', g:quickui#style#border) let button = (get(a:opts, 'close', '') == 'button')? 1 : 0 let color = get(a:opts, 'color', 'QuickPreview') let p = s:around_cursor(w + (border? 2 : 0), h + (border? 2 : 0)) if has_key(a:opts, 'col') let p[0] = get(a:opts, 'line', get(a:opts, 'row', 1)) let p[1] = get(a:opts, 'col', 1) endif if has('nvim') == 0 let winid = popup_create(source, {'wrap':1, 'mapping':0, 'hidden':1}) let opts = {'maxwidth':w, 'maxheight':h, 'minwidth':w, 'minheight':h} call popup_move(winid, opts) let opts = {'close':'button'} let opts.border = border? [1,1,1,1,1,1,1,1,1] : repeat([0], 9) let opts.resize = 0 let opts.highlight = color let opts.borderchars = quickui#core#border_vim(border) if get(a:opts, 'persist', 0) == 0 let opts.moved = 'any' endif let opts.drag = 1 let opts.line = p[0] let opts.col = p[1] if title != '' let opts.title = title endif let opts.callback = function('s:popup_exit') " let opts.fixed = 'true' if has_key(a:opts, 'bordercolor') let c = a:opts.bordercolor let opts.borderhighlight = [c, c, c, c] endif call popup_setoptions(winid, opts) let s:private.winid = winid call popup_show(winid) else let opts = {'focusable':0, 'style':'minimal', 'relative':'editor'} let opts.width = w let opts.height = h let opts.row = p[0] let opts.col = p[1] if has_key(a:opts, 'focusable') let opts.focusable = a:opts.focusable endif if type(source) == v:t_number let bid = source else let bid = quickui#core#scratch_buffer('preview', source) endif if has('nvim-0.6.0') let opts.noautocmd = 1 endif let winid = nvim_open_win(bid, 0, opts) let s:private.winid = winid let high = 'Normal:'.color.',NonText:'.color.',EndOfBuffer:'.color call nvim_win_set_option(winid, 'winhl', high) let s:private.background = -1 if border > 0 && get(g:, 'quickui_nvim_simulate_border', 1) != 0 let back = quickui#utils#make_border(w, h, border, title, button) let nbid = quickui#core#scratch_buffer('previewborder', back) let op = {'relative':'editor', 'focusable':0, 'style':'minimal'} let op.width = w + 2 let op.height = h + 2 let pos = nvim_win_get_config(winid) let op.row = pos.row - 1 let op.col = pos.col - 1 let bordercolor = get(a:opts, 'bordercolor', color) if has('nvim-0.6.0') let op.noautocmd = 1 endif let background = nvim_open_win(nbid, 0, op) call nvim_win_set_option(background, 'winhl', 'Normal:'. bordercolor) let s:private.background = background endif endif let cmdlist = ['setlocal signcolumn=no norelativenumber'] if get(a:opts, 'number', 1) == 0 let cmdlist += ['setlocal nonumber'] else let cmdlist += ['setlocal number'] endif let cursor = get(a:opts, 'cursor', -1) if cursor > 0 let cmdlist += ['exec "normal! gg' . cursor . 'Gzz"'] endif if has_key(a:opts, 'syntax') let cmdlist += ['setl ft=' . fnameescape(a:opts.syntax) ] endif let cmdlist += ['silent! setlocal scrolloff=0'] call setbufvar(winbufnr(winid), '__quickui_cursor__', cursor) call quickui#core#win_execute(winid, cmdlist) call quickui#utils#update_cursor(winid) let s:private.state = 1 if has('nvim') if get(a:opts, 'persist', 0) == 0 autocmd CursorMoved ++once call s:autoclose_preview_window() endif endif return winid endfunc "---------------------------------------------------------------------- " exit callback "---------------------------------------------------------------------- function! s:popup_exit(winid, code) let s:private.winid = -1 let s:private.state = 0 endfunc "---------------------------------------------------------------------- " close window "---------------------------------------------------------------------- function! quickui#preview#close() if s:private.winid >= 0 if has('nvim') == 0 call popup_close(s:private.winid, 0) let s:private.winid = -1 else call nvim_win_close(s:private.winid, 0) let s:private.winid = -1 if s:private.background >= 0 call nvim_win_close(s:private.background, 0) let s:private.background = -1 endif endif endif let s:private.state = 0 endfunc "---------------------------------------------------------------------- " return state "---------------------------------------------------------------------- function! quickui#preview#visible() return s:private.state endfunc "---------------------------------------------------------------------- " quit "---------------------------------------------------------------------- function! s:autoclose_preview_window() if s:private.state != 0 if s:private.winid >= 0 call quickui#preview#close() endif endif endfunc "---------------------------------------------------------------------- " scroll preview window "---------------------------------------------------------------------- function! quickui#preview#scroll(offset) if s:private.state != 0 let winid = s:private.winid if s:private.winid >= 0 noautocmd call quickui#utils#scroll(winid, a:offset) noautocmd call quickui#utils#update_cursor(winid) endif endif endfunc "---------------------------------------------------------------------- " press esc to close "---------------------------------------------------------------------- function! s:press_esc() exec "nunmap " call quickui#preview#close() endfunc "---------------------------------------------------------------------- " preview file "---------------------------------------------------------------------- function! quickui#preview#open(content, opts) call quickui#preview#close() if type(a:content) == v:t_string && filereadable(a:content) == 0 call quickui#utils#errmsg('E484: Cannot open file ' . a:content) return -1 endif let opts = {} let opts.w = get(g:, 'quickui_preview_w', g:quickui#style#preview_w) let opts.h = get(g:, 'quickui_preview_h', g:quickui#style#preview_h) let opts.number = get(a:opts, 'number', g:quickui#style#preview_number) let opts.cursor = get(a:opts, 'cursor', -1) let title = has_key(a:opts, 'title')? (' ' .. a:opts.title) : '' if type(a:content) == v:t_string let name = fnamemodify(a:content, ':p:t') let opts.title = 'Preview: ' . name . title else let opts.title = 'Preview' .. ((title == '')? '' : (':' .. title)) endif if g:quickui#style#preview_bordercolor != '' let opts.bordercolor = g:quickui#style#preview_bordercolor endif let opts.persist = get(a:opts, 'persist', 0) let opts.focusable = get(g:, 'quickui_preview_focusable', 1) if has_key(a:opts, 'syntax') let opts.syntax = a:opts.syntax endif if has_key(a:opts, 'col') let opts.col = a:opts.col let opts.line = get(a:opts, 'line', get(a:opts, 'row')) endif if has_key(a:opts, 'w') let opts.w = a:opts.w let opts.h = get(a:opts, 'h', opts.h) endif let hr = quickui#preview#display(a:content, opts) exec "nnoremap :call press_esc()" return hr endfunc