From fd334e5ad0c616987d1b9114890a59c97165cf83 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 13 Jun 2024 19:13:38 -0400 Subject: [PATCH] Add a changelist sign group --- README.md | 2 + autoload/scrollview.vim | 14 ++++ doc/scrollview.txt | 30 ++++++++ doc/tags | 6 ++ lua/scrollview/signs/changelist.lua | 114 ++++++++++++++++++++++++++++ plugin/scrollview.vim | 4 + 6 files changed, 170 insertions(+) create mode 100644 lua/scrollview/signs/changelist.lua diff --git a/README.md b/README.md index 6b3a6ae..6d217ad 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ There is built-in support for various types of signs (referred to as "sign groups"), listed below. The functionality is similar to the sign column, but with the same positioning logic as the scrollbar. + +* `changelist`: change list items (previous, current, and next) * `conflicts`: git merge conflicts * `cursor`: cursor position * `diagnostics`: errors, warnings, info, and hints diff --git a/autoload/scrollview.vim b/autoload/scrollview.vim index 388c13b..8cbdde3 100644 --- a/autoload/scrollview.vim +++ b/autoload/scrollview.vim @@ -76,6 +76,20 @@ let g:scrollview_signs_overflow = get(g:, 'scrollview_signs_overflow', 'left') let g:scrollview_signs_show_in_folds = \ get(g:, 'scrollview_signs_show_in_folds', v:false) +" *** Change list signs *** +let g:scrollview_changelist_previous_priority = + \ get(g:, 'scrollview_changelist_previous_priority', 15) +let g:scrollview_changelist_previous_symbol = + \ get(g:, 'scrollview_changelist_previous_symbol', nr2char(0x1f894)) +let g:scrollview_changelist_current_priority = + \ get(g:, 'scrollview_changelist_current_priority', 10) +let g:scrollview_changelist_current_symbol = + \ get(g:, 'scrollview_changelist_current_symbol', '@') +let g:scrollview_changelist_next_priority = + \ get(g:, 'scrollview_changelist_next_priority', 5) +let g:scrollview_changelist_next_symbol = + \ get(g:, 'scrollview_changelist_next_symbol', nr2char(0x1f896)) + " *** Conflict signs *** let g:scrollview_conflicts_bottom_priority = \ get(g:, 'scrollview_conflicts_bottom_priority', 80) diff --git a/doc/scrollview.txt b/doc/scrollview.txt index d0c6a47..4c83bd0 100644 --- a/doc/scrollview.txt +++ b/doc/scrollview.txt @@ -150,6 +150,7 @@ Built-in Sign Groups ~ *scrollview-signs-built-in* Group Information ----- ----------- +`changelist` change list items (previous, current, and next) `conflicts` git merge conflicts `cursor` cursor position `diagnostics` errors, warnings, info, and hints via |vim.diagnostic| @@ -315,6 +316,35 @@ scrollview_signs_show_in_folds *scrollview_signs_show_in_folds* *scrollview-signs-built-in-config* Configuration Variables for Built-in Sign Groups ~ +scrollview_changelist_previous_priority *scrollview_changelist_previous_priority* + |Number| specifying the priority for the previous item + changelist sign. Defaults to `15`. Considered only when + the plugin is loaded. + +scrollview_changelist_previous_symbol *scrollview_changelist_previous_symbol* + |String| specifying the symbol for the previous item + changelist sign. Defaults to a left-pointing arrow in a + triangle. + +scrollview_changelist_current_priority *scrollview_changelist_current_priority* + |Number| specifying the priority for the current item + changelist sign. Defaults to `10`. Considered only when + the plugin is loaded. + +scrollview_changelist_current_symbol *scrollview_changelist_current_symbol* + |String| specifying the symbol for the current item + changelist sign. Defaults to `'@'`. + +scrollview_changelist_next_priority *scrollview_changelist_next_priority* + |Number| specifying the priority for the next item + changelist sign. Defaults to `5`. Considered only when + the plugin is loaded. + +scrollview_changelist_next_symbol *scrollview_changelist_next_symbol* + |String| specifying the symbol for the next item + changelist sign. Defaults to a right-pointing arrow in + a triangle. + scrollview_conflicts_bottom_priority *scrollview_conflicts_bottom_priority* |Number| specifying the priority for conflict bottom signs. Defaults to `80`. Considered only when the diff --git a/doc/tags b/doc/tags index 053bafb..4fecd53 100644 --- a/doc/tags +++ b/doc/tags @@ -44,6 +44,12 @@ scrollview_always_show scrollview.txt /*scrollview_always_show* scrollview_auto_mouse scrollview.txt /*scrollview_auto_mouse* scrollview_base scrollview.txt /*scrollview_base* scrollview_byte_limit scrollview.txt /*scrollview_byte_limit* +scrollview_changelist_current_priority scrollview.txt /*scrollview_changelist_current_priority* +scrollview_changelist_current_symbol scrollview.txt /*scrollview_changelist_current_symbol* +scrollview_changelist_next_priority scrollview.txt /*scrollview_changelist_next_priority* +scrollview_changelist_next_symbol scrollview.txt /*scrollview_changelist_next_symbol* +scrollview_changelist_previous_priority scrollview.txt /*scrollview_changelist_previous_priority* +scrollview_changelist_previous_symbol scrollview.txt /*scrollview_changelist_previous_symbol* scrollview_character scrollview.txt /*scrollview_character* scrollview_column scrollview.txt /*scrollview_column* scrollview_conflicts_bottom_priority scrollview.txt /*scrollview_conflicts_bottom_priority* diff --git a/lua/scrollview/signs/changelist.lua b/lua/scrollview/signs/changelist.lua new file mode 100644 index 0000000..d6ddfb9 --- /dev/null +++ b/lua/scrollview/signs/changelist.lua @@ -0,0 +1,114 @@ +local api = vim.api +local fn = vim.fn +local scrollview = require('scrollview') + +local M = {} + +local PREVIOUS = 0 +local CURRENT = 1 +local NEXT = 2 + +function M.init(enable) + if api.nvim_create_autocmd == nil then + return + end + + local group = 'changelist' + + local spec_data = { + [PREVIOUS] = { + vim.g.scrollview_changelist_previous_priority, + vim.g.scrollview_changelist_previous_symbol, + 'ScrollViewChangeListPrevious' + }, + [CURRENT] = { + vim.g.scrollview_changelist_current_priority, + vim.g.scrollview_changelist_current_symbol, + 'ScrollViewChangeListCurrent' + }, + [NEXT] = { + vim.g.scrollview_changelist_next_priority, + vim.g.scrollview_changelist_next_symbol, + 'ScrollViewChangeListNext' + }, + } + local names = {} -- maps direction to registration name + for direction, item in pairs(spec_data) do + local priority, symbol, highlight = unpack(item) + local registration = scrollview.register_sign_spec({ + group = group, + highlight = highlight, + priority = priority, + symbol = symbol, + }) + names[direction] = registration.name + end + scrollview.set_sign_group_state(group, enable) + + -- Refresh scrollbars after jumping through the change list. + scrollview.register_key_sequence_callback('g;', 'nv', scrollview.refresh) + scrollview.register_key_sequence_callback('g,', 'nv', scrollview.refresh) + + api.nvim_create_autocmd('User', { + pattern = 'ScrollViewRefresh', + callback = function() + if not scrollview.is_sign_group_active(group) then return end + -- Track visited buffers, to prevent duplicate computation when multiple + -- windows are showing the same buffer. + local visited = {} + for _, winid in ipairs(scrollview.get_sign_eligible_windows()) do + local bufnr = api.nvim_win_get_buf(winid) + if not visited[bufnr] then + local bufvars = vim.b[bufnr] + for direction, name in pairs(names) do + -- luacheck: ignore 122 (setting read-only field b.?.? of global vim) + bufvars[name] = {} + local locations, position = unpack(fn.getchangelist(bufnr)) + position = position + 1 + if direction == PREVIOUS + and #locations > 0 + and position - 1 > 0 + and position - 1 <= #locations then + bufvars[name] = {locations[position - 1].lnum} + end + if direction == CURRENT + and #locations > 0 + and position > 0 + and position <= #locations then + bufvars[name] = {locations[position].lnum} + end + if direction == NEXT + and #locations > 0 + and position + 1 > 0 + and position + 1 <= #locations then + bufvars[name] = {locations[position + 1].lnum} + end + end + visited[bufnr] = true + end + end + end + }) + + api.nvim_create_autocmd('InsertLeave', { + callback = function() + if not scrollview.is_sign_group_active(group) then return end + scrollview.refresh() + end + }) + + api.nvim_create_autocmd('InsertEnter', { + callback = function() + if not scrollview.is_sign_group_active(group) then return end + api.nvim_create_autocmd('TextChangedI', { + callback = function() + if not scrollview.is_sign_group_active(group) then return end + scrollview.refresh() + end, + once = true + }) + end + }) +end + +return M diff --git a/plugin/scrollview.vim b/plugin/scrollview.vim index 182fecc..b9eca9f 100644 --- a/plugin/scrollview.vim +++ b/plugin/scrollview.vim @@ -23,6 +23,10 @@ endif " E.g., the following will use custom highlight colors. " :highlight ScrollView ctermbg=159 guibg=LightCyan highlight default link ScrollView Visual +highlight default link ScrollViewChangeListPrevious SpecialKey +highlight default link ScrollViewChangeListCurrent SpecialKey +highlight default link ScrollViewChangeListNext SpecialKey +highlight default link ScrollViewConflictsMiddle DiffAdd highlight default link ScrollViewConflictsTop DiffAdd highlight default link ScrollViewConflictsMiddle DiffAdd highlight default link ScrollViewConflictsBottom DiffAdd