diff --git a/autoload/SpaceVim/layers/ui.vim b/autoload/SpaceVim/layers/ui.vim index 89aa620fe..95d78f25f 100644 --- a/autoload/SpaceVim/layers/ui.vim +++ b/autoload/SpaceVim/layers/ui.vim @@ -7,6 +7,14 @@ "============================================================================= scriptencoding utf-8 + +if exists('s:enable_sidebar') + finish +else + let s:enable_sidebar = 0 + let s:enable_scrollbar = 0 +endif + function! SpaceVim#layers#ui#plugins() abort let plugins = [ \ [g:_spacevim_root_dir . 'bundle/indentLine', {'merged' : 0}], @@ -50,6 +58,14 @@ function! SpaceVim#layers#ui#config() abort noremap :TagbarToggle endif + if s:enable_scrollbar + augroup spacevim_layer_ui + autocmd! + autocmd BufEnter,CursorMoved,VimResized,FocusGained * call SpaceVim#plugins#scrollbar#show() + autocmd BufLeave,FocusLost * call SpaceVim#plugins#scrollbar#clear() + augroup end + endif + if !empty(g:spacevim_windows_smartclose) call SpaceVim#mapping#def('nnoremap ', g:spacevim_windows_smartclose, ':call SpaceVim#mapping#SmartClose()', \ 'smart-close-windows', @@ -397,12 +413,13 @@ function! s:win_resize_transient_state() abort endfunction -let s:enable_sidebar = 0 - function! SpaceVim#layers#ui#set_variable(var) abort let s:enable_sidebar = get(a:var, \ 'enable_sidebar', \ 0) + let s:enable_scrollbar = get(a:var, + \ 'enable_scrollbar', + \ 0) endfunction diff --git a/autoload/SpaceVim/plugins/scrollbar.vim b/autoload/SpaceVim/plugins/scrollbar.vim new file mode 100644 index 000000000..3c39bcec7 --- /dev/null +++ b/autoload/SpaceVim/plugins/scrollbar.vim @@ -0,0 +1,185 @@ +"============================================================================= +" scrollbar.vim --- scrollbar support for SpaceVim +" Copyright (c) 2016-2019 Wang Shidong & Contributors +" Author: Wang Shidong < wsdjeg@outlook.com > +" URL: https://spacevim.org +" License: GPLv3 +"============================================================================= + +let s:VIM = SpaceVim#api#import('vim') + +scriptencoding utf-8 + +let s:default = { + \ 'max_size' : 10, + \ 'min_size' : 3, + \ 'width' : 1, + \ 'right_offset' : 1, + \ 'excluded_filetypes' : [], + \ 'shape' : { + \ 'head' : '▲', + \ 'body' : '█', + \ 'tail' : '▼', + \ }, + \ 'highlight' : { + \ 'head' : 'Normal', + \ 'body' : 'Normal', + \ 'tail' : 'Normal', + \ } + \ } + + +" vim script do not support metatable function + +function! s:get(key) abort + let val = get(g:, 'scrollbar_' . a:key, v:null) + if val ==# v:null + return s:default[a:key] + endif + if s:VIM.is_dict(val) + let val = extend(val, s:default[a:key], 'keep') + endif + return val +endfunction + + +let s:ns_id = nvim_create_namespace('scrollbar') + + +function! s:gen_bar_lines(size) abort + let shape = s:get('shape') + let lines = [shape.head] + for _ in range(2, a:size - 1) + call add(lines, shape.body) + endfor + call add(lines, shape.tail) + return lines +endfunction + + +function! s:fix_size(size) abort + return max([s:get('min_size'), min([s:get('max_size'), a:size])]) +endfunction + + +function! s:buf_get_var(bufnr, name) abort + try + let var = nvim_buf_get_var(a:bufnr, a:name) + return var + catch + + endtry +endfunction + +function! s:add_highlight(bufnr, size) abort + let highlight = s:get('highlight') + call nvim_buf_add_highlight(a:bufnr, s:ns_id, highlight.head, 0, 0, -1) + for i in range(1, a:size - 2) + call nvim_buf_add_highlight(a:bufnr, s:ns_id, highlight.body, i, 0, -1) + endfor + call nvim_buf_add_highlight(a:bufnr, s:ns_id, highlight.tail, a:size - 1, 0, -1) +endfunction + +let s:next_index = 0 +function! s:next_buf_index() abort + let s:next_index += 1 + return s:next_index - 1 +endfunction + +function! s:create_buf(size, lines) abort + noautocmd let bufnr = nvim_create_buf(0, 1) + noautocmd call nvim_buf_set_option(bufnr, 'filetype', 'scrollbar') + noautocmd call nvim_buf_set_name(bufnr, 'scrollbar_' . s:next_buf_index()) + noautocmd call nvim_buf_set_lines(bufnr, 0, a:size, 0, a:lines) + + call s:add_highlight(bufnr, a:size) + return bufnr +endfunction + +function! SpaceVim#plugins#scrollbar#show(...) abort + let winnr = get(a:000, 0, 0) + let bufnr = get(a:000, 1, 0) + let win_config = nvim_win_get_config(winnr) + + " ignore other floating windows + if win_config.relative !=# '' + return + endif + + let excluded_filetypes = s:get('excluded_filetypes') + let filetype = nvim_buf_get_option(bufnr, 'filetype') + + if filetype == '' || index(excluded_filetypes, filetype) !=# -1 + return + endif + + let total = line('$') + let height = nvim_win_get_height(winnr) + if total <= height + call SpaceVim#plugins#scrollbar#clear() + return + endif + + let cursor = nvim_win_get_cursor(winnr) + let curr_line = cursor[0] + let bar_size = height * height / total + let bar_size = s:fix_size(bar_size) + + let width = nvim_win_get_width(winnr) + let col = width - s:get('width') - s:get('right_offset') + let row = (height - bar_size) * (curr_line * 1.0 / total) + + let opts = { + \ 'style' : 'minimal', + \ 'relative' : 'win', + \ 'win' : winnr, + \ 'width' : s:get('width'), + \ 'height' : bar_size, + \ 'row' : row, + \ 'col' : col, + \ 'focusable' : 0, + \ } + let [bar_winnr, bar_bufnr] = [0, 0] + let state = s:buf_get_var(bufnr, 'scrollbar_state') + if !empty(state) + let bar_bufnr = state.bufnr + if !has_key(state, 'winnr') + noautocmd let bar_winnr = nvim_open_win(bar_bufnr, 0, opts) + else + let bar_winnr = state.winnr + endif + if state.size !=# bar_size + noautocmd call nvim_buf_set_lines(bar_bufnr, 0, -1, 0, []) + let bar_lines = s:gen_bar_lines(bar_size) + noautocmd call nvim_buf_set_lines(bar_bufnr, 0, bar_size, 0, bar_lines) + noautocmd call s:add_highlight(bar_bufnr, bar_size) + endif + noautocmd call nvim_win_set_config(bar_winnr, opts) + else + let bar_lines = s:gen_bar_lines(bar_size) + let bar_bufnr = s:create_buf(bar_size, bar_lines) + let bar_winnr = nvim_open_win(bar_bufnr, 0, opts) + call nvim_win_set_option(bar_winnr, 'winhl', 'Normal:ScrollbarWinHighlight') + endif + call nvim_buf_set_var(bufnr, 'scrollbar_state', { + \ 'winnr' : bar_winnr, + \ 'bufnr' : bar_bufnr, + \ 'size' : bar_size, + \ }) + return [bar_winnr, bar_bufnr] + +endfunction + +function! SpaceVim#plugins#scrollbar#clear(...) abort + let bufnr = get(a:000, 1, 0) + let state = s:buf_get_var(bufnr, 'scrollbar_state') + if !empty(state) && has_key(state, 'winnr') + noautocmd call nvim_win_close(state.winnr, 1) + noautocmd call nvim_buf_set_var(bufnr, 'scrollbar_state', { + \ 'size' : state.size, + \ 'bufnr' : state.bufnr, + \ }) + endif + +endfunction + diff --git a/docs/cn/layers/ui.md b/docs/cn/layers/ui.md index cf0b56f88..bd88c9aea 100644 --- a/docs/cn/layers/ui.md +++ b/docs/cn/layers/ui.md @@ -10,6 +10,7 @@ lang: zh - [模块描述](#模块描述) - [启用模块](#启用模块) +- [模块选项](#模块选项) - [集成插件](#集成插件) @@ -27,6 +28,11 @@ SpaceVim ui 模块提供了一个 IDE-like 的界面,包括状态栏、文件 name = "ui" ``` +## 模块选项 + +- `enable_scrollbar`:启用/禁用悬浮滚动条,默认为禁用的,该功能需要 Neovim 的悬浮窗口支持。 + + ## 集成插件 - [mhinz/vim-startify](https://github.com/mhinz/vim-startify) diff --git a/docs/layers/ui.md b/docs/layers/ui.md index 066fcd462..3f2ed2ee4 100644 --- a/docs/layers/ui.md +++ b/docs/layers/ui.md @@ -9,6 +9,7 @@ description: "Awesome UI layer for SpaceVim, provide IDE-like UI for neovim and - [Description](#description) - [Install](#install) +- [Layer Options](#layer-options) - [Plugins](#plugins) - [Tips](#tips) @@ -27,6 +28,14 @@ To use this configuration layer, update custom configuration file with: name = "ui" ``` +## Layer Options + +- `enable_scrollbar`: Enable/disable floating scrollbar of current buffer. Disabled by default. + This feature requires neovim's floating window. + + + + ## Plugins - [startify](https://github.com/mhinz/vim-startify): welcome page, default key binding is `SPC a s`.