├── LICENSE ├── README.md ├── lua └── scrollbar.lua └── plugin └── scrollbar.vim /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Olivier Roques 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvim-scrollbar 2 | 3 | A simple and fast scrollbar for Neovim. It is deliberately feature-less and will 4 | remain so. 5 | 6 | ![demo](https://user-images.githubusercontent.com/23409060/188606407-c4465f38-e66d-46c7-a7ff-ac8a40fb1e73.gif) 7 | 8 | ## Installation 9 | With [packer.nvim](https://github.com/wbthomason/packer.nvim): 10 | ```lua 11 | use {'ojroques/nvim-scrollbar'} 12 | ``` 13 | 14 | With [paq-nvim](https://github.com/savq/paq-nvim): 15 | ```lua 16 | paq {'ojroques/nvim-scrollbar'} 17 | ``` 18 | 19 | ## Usage 20 | In your *init.lua*: 21 | ```lua 22 | require('scrollbar').setup {} 23 | ``` 24 | 25 | If you're using a *.vimrc* or *init.vim*: 26 | ```vim 27 | lua require('scrollbar').setup {} 28 | ``` 29 | 30 | ## Configuration 31 | You can pass options to the `setup()` function. Here are all available options 32 | with their default settings: 33 | ```lua 34 | M.options = { 35 | symbol_bar = {' ', 'TermCursor'}, -- Bar symbol and highlight group 36 | priority = 10, -- Priority of scrollbar (low value = high priority) 37 | exclude_buftypes = {}, -- Buftypes to exclude 38 | exclude_filetypes = { -- Filetypes to exclude 39 | 'qf', 40 | }, 41 | render_events = { -- Events triggering the redraw of the bar 42 | 'BufWinEnter', 43 | 'CmdwinLeave', 44 | 'TabEnter', 45 | 'TermEnter', 46 | 'TextChanged', 47 | 'VimResized', 48 | 'WinEnter', 49 | 'WinScrolled', 50 | }, 51 | } 52 | ``` 53 | 54 | ## Related plugins 55 | * [petertriho's nvim-scrollbar](https://github.com/petertriho/nvim-scrollbar): a 56 | scrollbar for Neovim with more features. 57 | * [vim-scrollstatus](https://github.com/ojroques/vim-scrollstatus): a Vim plugin 58 | (also compatible with Neovim) to display a scrollbar in the statusline. 59 | 60 | ## License 61 | [LICENSE](./LICENSE) 62 | -------------------------------------------------------------------------------- /lua/scrollbar.lua: -------------------------------------------------------------------------------- 1 | -- nvim-scrollbar 2 | -- By Olivier Roques 3 | -- github.com/ojroques 4 | 5 | -------------------- VARIABLES ----------------------------- 6 | local namespace = vim.api.nvim_create_namespace('scrollbar') 7 | local state = { 8 | win_height = -1, 9 | nb_lines = -1, 10 | nb_visible_lines = -1, 11 | first_visible_line = -1, 12 | last_visible_line = -1, 13 | bar_start = -1, 14 | bar_end = -1, 15 | } 16 | local M = {} 17 | 18 | -------------------- OPTIONS ------------------------------- 19 | M.options = { 20 | symbol_bar = {' ', 'TermCursor'}, -- Bar symbol and highlight group 21 | priority = 10, -- Priority of virtual text 22 | exclude_buftypes = {}, -- Buftypes to exclude 23 | exclude_filetypes = { -- Filetypes to exclude 24 | 'qf', 25 | }, 26 | render_events = { -- Events triggering the redraw of the bar 27 | 'BufWinEnter', 28 | 'CmdwinLeave', 29 | 'TabEnter', 30 | 'TermEnter', 31 | 'TextChanged', 32 | 'VimResized', 33 | 'WinEnter', 34 | 'WinScrolled', 35 | }, 36 | } 37 | 38 | -------------------- HELPERS ------------------------------- 39 | local function same_nb_lines() 40 | return vim.api.nvim_buf_line_count(0) == state.nb_lines 41 | end 42 | 43 | local function same_window() 44 | local same_head = vim.fn.line('w0') - 1 == state.first_visible_line 45 | local same_tail = vim.fn.line('w$') - 1 == state.last_visible_line 46 | return same_head and same_tail 47 | end 48 | 49 | -------------------- SCROLLBAR ----------------------------- 50 | local function is_excluded(bufnr) 51 | local buftype = vim.fn.getbufvar(bufnr, '&buftype') 52 | local filetype = vim.fn.getbufvar(bufnr, '&filetype') 53 | local excluded = false 54 | excluded = excluded or vim.fn.buflisted(bufnr) == 0 55 | excluded = excluded or vim.tbl_contains(M.options.exclude_buftypes, buftype) 56 | excluded = excluded or vim.tbl_contains(M.options.exclude_filetypes, filetype) 57 | return excluded 58 | end 59 | 60 | local function get_bar_start(win_height, nb_lines, first_visible_line) 61 | local bar_start = math.floor(win_height * (first_visible_line / nb_lines)) 62 | return math.min(win_height - 1, bar_start) 63 | end 64 | 65 | local function get_bar_end(win_height, nb_lines, nb_visible_lines, bar_start) 66 | local bar_size = math.floor(win_height * (nb_visible_lines / nb_lines) + 0.5) 67 | return math.min(win_height - 1, bar_start + bar_size) 68 | end 69 | 70 | local function draw_bar(s) 71 | local extmark_opts = { 72 | virt_text = {M.options.symbol_bar}, 73 | virt_text_pos = 'right_align', 74 | priority = M.options.priority, 75 | } 76 | 77 | vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1) 78 | 79 | for line = s.first_visible_line + s.bar_start, s.first_visible_line + s.bar_end do 80 | if line > s.nb_lines - 1 then 81 | break 82 | end 83 | vim.api.nvim_buf_set_extmark(0, namespace, line, -1, extmark_opts) 84 | end 85 | end 86 | 87 | function M.render() 88 | if is_excluded(vim.api.nvim_get_current_buf()) then 89 | vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1) 90 | return 91 | end 92 | 93 | state.win_height = vim.api.nvim_win_get_height(0) 94 | 95 | if vim.fn.line('w$') < vim.fn.line('w0') then 96 | return 97 | end 98 | 99 | if same_nb_lines() and same_window() then 100 | return 101 | end 102 | 103 | if not same_nb_lines() then 104 | state.nb_lines = vim.api.nvim_buf_line_count(0) 105 | end 106 | 107 | if not same_window() then 108 | state.first_visible_line = vim.fn.line('w0') - 1 109 | state.last_visible_line = vim.fn.line('w$') - 1 110 | state.nb_visible_lines = state.last_visible_line - state.first_visible_line + 1 111 | end 112 | 113 | state.bar_start = get_bar_start(state.win_height, state.nb_lines, state.first_visible_line) 114 | state.bar_end = get_bar_end(state.win_height, state.nb_lines, state.nb_visible_lines, state.bar_start) 115 | 116 | draw_bar(state) 117 | end 118 | 119 | -------------------- SETUP ----------------------------- 120 | local function set_scrollbar() 121 | local fmt_string = 'autocmd %s * lua require("scrollbar").render()' 122 | vim.cmd('augroup scrollbar') 123 | vim.cmd('autocmd!') 124 | vim.cmd(string.format(fmt_string, table.concat(M.options.render_events, ','))) 125 | vim.cmd('augroup END') 126 | end 127 | 128 | function M.setup(user_options) 129 | if user_options then 130 | M.options = vim.tbl_extend('force', M.options, user_options) 131 | end 132 | set_scrollbar() 133 | end 134 | 135 | ------------------------------------------------------------ 136 | return M 137 | -------------------------------------------------------------------------------- /plugin/scrollbar.vim: -------------------------------------------------------------------------------- 1 | " nvim-scrollbar 2 | " By Olivier Roques 3 | " github.com/ojroques 4 | 5 | if exists('g:loaded_scrollbar') 6 | finish 7 | endif 8 | 9 | let g:loaded_scrollbar = 1 10 | --------------------------------------------------------------------------------