From daf814589b169a8152bc52cbc699afd49281ab1d Mon Sep 17 00:00:00 2001 From: wsdjeg Date: Sat, 23 Sep 2023 20:33:31 +0800 Subject: [PATCH] feat(scrollbar): implement scrollbar in lua --- autoload/SpaceVim/plugins/scrollbar.vim | 15 +++ lua/spacevim/plugin/scrollbar.lua | 161 ++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 lua/spacevim/plugin/scrollbar.lua diff --git a/autoload/SpaceVim/plugins/scrollbar.vim b/autoload/SpaceVim/plugins/scrollbar.vim index 8dc02a0ce..0e4714738 100644 --- a/autoload/SpaceVim/plugins/scrollbar.vim +++ b/autoload/SpaceVim/plugins/scrollbar.vim @@ -6,6 +6,21 @@ " License: GPLv3 "============================================================================= +if has('nvim-0.9.0') + function! SpaceVim#plugins#scrollbar#usable() abort + return luaeval('require("spacevim.plugin.scrollbar").usable()') + endfunction + function! SpaceVim#plugins#scrollbar#show() abort + lua require('spacevim.plugin.scrollbar').show() + endfunction + function! SpaceVim#plugins#scrollbar#clear(...) abort + lua require('spacevim.plugin.scrollbar').clear() + endfunction + finish +endif + + + let s:VIM = SpaceVim#api#import('vim') let s:BUF = SpaceVim#api#import('vim#buffer') let s:WIN = SpaceVim#api#import('vim#window') diff --git a/lua/spacevim/plugin/scrollbar.lua b/lua/spacevim/plugin/scrollbar.lua new file mode 100644 index 000000000..964c3022d --- /dev/null +++ b/lua/spacevim/plugin/scrollbar.lua @@ -0,0 +1,161 @@ +--============================================================================= +-- scrollbar.lua --- scrollbar for SpaceVim +-- Copyright (c) 2016-2022 Wang Shidong & Contributors +-- Author: Wang Shidong < wsdjeg@outlook.com > +-- URL: https://spacevim.org +-- License: GPLv3 +--============================================================================= + +local M = {} + +local win = require('spacevim.api.vim.window') + +local default_conf = { + max_size = 10, + min_size = 3, + width = 1, + right_offset = 1, + excluded_filetypes = { + 'startify', + 'git-commit', + 'leaderf', + 'NvimTree', + 'tagbar', + 'defx', + 'neo-tree', + 'qf', + }, + shape = { + head = '▲', + body = '█', + tail = '▼', + }, + highlight = { + head = 'Normal', + body = 'Normal', + tail = 'Normal', + }, +} +local function get(opt) + + return default_conf[opt] + +end + +local scrollbar_bufnr = -1 +local scrollbar_winid = -1 +local scrollbar_size = -1 +local ns_id = vim.api.nvim_create_namespace('scrollbar') + +local function add_highlight(bufnr, size) + local highlight = get('highlight') + vim.api.nvim_buf_add_highlight(bufnr, ns_id, highlight.head, 0, 0, -1) + for i = 1, size - 2 do + vim.api.nvim_buf_add_highlight(bufnr, ns_id, highlight.body, i, 0, -1) + end + vim.api.nvim_buf_add_highlight(bufnr, ns_id, highlight.tail, size - 1, 0, -1) +end + +local function fix_size(size) + return math.max(get('min_size'), math.min(get('max_size'), math.floor(size + 0.5))) +end + +local function gen_bar_lines(size) + local shape = get('shape') + local lines = { shape.head } + for _ = 2, size - 1 do + table.insert(lines, shape.body) + end + table.insert(lines, shape.tail) + return lines +end + +local function create_scrollbar_buffer(size, lines) + if not vim.api.nvim_buf_is_valid(scrollbar_bufnr) then + scrollbar_bufnr = vim.api.nvim_create_buf(false, true) + end + vim.api.nvim_buf_set_lines(scrollbar_bufnr, 0, -1, false, lines) + add_highlight(scrollbar_bufnr, size) + return scrollbar_bufnr +end + +function M.show() + local saved_ei = vim.o.eventignore + vim.o.eventignore = 'all' + local winnr = vim.fn.winnr() + local bufnr = vim.fn.bufnr() + local winid = vim.fn.win_getid() + if win.is_float(winid) then + M.clear() + vim.o.eventignore = saved_ei + return + end + + local total = vim.api.nvim_buf_line_count(bufnr) + local height = vim.fn.winheight(winnr) + + if total <= height then + M.clear() + vim.o.eventignore = saved_ei + return + end + + local curr_line = vim.fn.line('w0') + local bar_size = fix_size(height * height / total) + local width = vim.fn.winwidth(winnr) + local col = width - get('width') - get('right_offset') + local precision = height - bar_size + local each_line = (total - height) * 1.0 / precision + local visble_line = vim.fn.min({ curr_line, total - height + 1 }) + local row + if each_line >= 1 then + row = vim.fn.float2nr(visble_line / each_line) + else + row = vim.fn.float2nr(visble_line / each_line - 1 / each_line) + end + + local opts = { + style = 'minimal', + relative = 'win', + win = winid, + width = get('width'), + height = bar_size, + row = row, + col = vim.fn.float2nr(col), + focusable = false, + zindex = 10, + } + + if win.is_float(scrollbar_winid) then + if bar_size ~= scrollbar_size then + scrollbar_size = bar_size + local bar_lines = gen_bar_lines(bar_size) + vim.api.nvim_buf_set_lines(scrollbar_bufnr, 0, -1, false, bar_lines) + add_highlight(scrollbar_bufnr, bar_size) + end + vim.api.nvim_win_set_config(scrollbar_winid, opts) + else + scrollbar_size = bar_size + local bar_lines = gen_bar_lines(bar_size) + scrollbar_bufnr = create_scrollbar_buffer(bar_size, bar_lines) + scrollbar_winid = vim.api.nvim_open_win(scrollbar_bufnr, false, opts) + vim.fn.setwinvar( + vim.fn.win_id2win(scrollbar_winid), + '&winhighlight', + 'Normal:ScrollbarWinHighlight' + ) + end + vim.o.eventignore = saved_ei +end + +function M.clear() + if vim.api.nvim_win_is_valid(scrollbar_winid) then + vim.api.nvim_win_close(scrollbar_winid, true) + end +end + +function M.usable() + return true +end + +return M