Skip to content

Commit

Permalink
Add an indent sign group
Browse files Browse the repository at this point in the history
  • Loading branch information
dstein64 committed Dec 17, 2024
1 parent d979972 commit 086e194
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ with the same positioning logic as the scrollbar.
* `cursor`: cursor position
* `diagnostics`: errors, warnings, info, and hints
* `folds`: closed folds
* `indent`: unexpected indentation characters (e.g., tabs when `expandtab` is
set)
* `latestchange`: latest change
* `loclist`: items on the location list
* `marks`
Expand Down
14 changes: 14 additions & 0 deletions autoload/scrollview.vim
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ let g:scrollview_folds_priority = get(g:, 'scrollview_folds_priority', 30)
let g:scrollview_folds_symbol =
\ get(g:, 'scrollview_folds_symbol', nr2char(0x25b6))

" *** Indent signs ***
let g:scrollview_indent_spaces_condition =
\ get(g:, 'scrollview_indent_spaces_condition', 'noexpandtab')
let g:scrollview_indent_spaces_priority =
\ get(g:, 'scrollview_indent_spaces_priority', 25)
let g:scrollview_indent_spaces_symbol =
\ get(g:, 'scrollview_indent_spaces_symbol', '-')
let g:scrollview_indent_tabs_condition =
\ get(g:, 'scrollview_indent_tabs_condition', 'expandtab')
let g:scrollview_indent_tabs_priority =
\ get(g:, 'scrollview_indent_tabs_priority', 25)
let g:scrollview_indent_tabs_symbol =
\ get(g:, 'scrollview_indent_tabs_symbol', '>')

" *** Latest change signs ***
let g:scrollview_latestchange_priority =
\ get(g:, 'scrollview_latestchange_priority', 10)
Expand Down
34 changes: 34 additions & 0 deletions doc/scrollview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ Group Information
`cursor` cursor position
`diagnostics` errors, warnings, info, and hints via |vim.diagnostic|
`folds` closed folds
`indent` unexpected indentation characters (e.g., tabs when |expandtab|
is set)
`latestchange` latest change
`loclist` items on the location list
`marks`
Expand Down Expand Up @@ -529,6 +531,38 @@ scrollview_folds_symbol *scrollview_folds_symbol*
out-of-bounds. Considered only when the plugin is
loaded.

scrollview_indent_spaces_condition *scrollview_indent_spaces_condition*
|String| specifying the condition when signs will be
shown for leading spaces. Possible values are `'always'`
`'never'`, `'expandtab'`, and `'noexpandtab'`. Defaults to
`'noexpandtab'`, which will show signs for leading
spaces when the |expandtab| option is off.

scrollview_indent_spaces_priority *scrollview_indent_spaces_priority*
|Number| specifying the priority for indent spaces signs.
Defaults to `25`. Considered only when the plugin is
loaded.

scrollview_indent_spaces_symbol *scrollview_indent_spaces_symbol*
|String| specifying the symbol for indent spaces signs.
Defaults to `'-'`.

scrollview_indent_tabs_condition *scrollview_indent_tabs_condition*
|String| specifying the condition when signs will be
shown for leading tabs. Possible values are `'always'`
`'never'`, `'expandtab'`, and `'noexpandtab'`. Defaults to
`'expandtab'`, which will show signs for leading
tabs when the |expandtab| option is set.

scrollview_indent_tabs_priority *scrollview_indent_tabs_priority*
|Number| specifying the priority for indent tabs signs.
Defaults to `25`. Considered only when the plugin is
loaded.

scrollview_indent_tabs_symbol *scrollview_indent_tabs_symbol*
|String| specifying the symbol for indent tabs signs.
Defaults to `'>'`.

scrollview_latestchange_priority *scrollview_latestchange_priority*
|Number| specifying the priority for latestchange signs.
Defaults to `10`. Considered only when the plugin is
Expand Down
6 changes: 6 additions & 0 deletions doc/tags
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ scrollview_hide_bar_for_insert scrollview.txt /*scrollview_hide_bar_for_insert*
scrollview_hide_on_intersect scrollview.txt /*scrollview_hide_on_intersect*
scrollview_hover scrollview.txt /*scrollview_hover*
scrollview_include_end_region scrollview.txt /*scrollview_include_end_region*
scrollview_indent_spaces_condition scrollview.txt /*scrollview_indent_spaces_condition*
scrollview_indent_spaces_priority scrollview.txt /*scrollview_indent_spaces_priority*
scrollview_indent_spaces_symbol scrollview.txt /*scrollview_indent_spaces_symbol*
scrollview_indent_tabs_condition scrollview.txt /*scrollview_indent_tabs_condition*
scrollview_indent_tabs_priority scrollview.txt /*scrollview_indent_tabs_priority*
scrollview_indent_tabs_symbol scrollview.txt /*scrollview_indent_tabs_symbol*
scrollview_latestchange_priority scrollview.txt /*scrollview_latestchange_priority*
scrollview_latestchange_symbol scrollview.txt /*scrollview_latestchange_symbol*
scrollview_line_limit scrollview.txt /*scrollview_line_limit*
Expand Down
178 changes: 178 additions & 0 deletions lua/scrollview/signs/indent.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
local api = vim.api
local fn = vim.fn
local scrollview = require('scrollview')
local utils = require('scrollview.utils')

local M = {}

local SPACES = 0
local TABS = 1

local should_show = function(option, expandtab)
if option == 'always' then
return true
elseif option == 'never' then
return false
elseif option == 'expandtab' then
return expandtab
elseif option == 'noexpandtab' then
return not expandtab
else
-- Unknown option. Don't show.
return false
end
end

function M.init(enable)
if api.nvim_create_autocmd == nil then
return
end

local group = 'indent'
scrollview.register_sign_group(group)
local names = {
[SPACES] = scrollview.register_sign_spec({
group = group,
highlight = 'ScrollViewIndentSpaces',
priority = vim.g.scrollview_indent_spaces_priority,
symbol = vim.g.scrollview_indent_spaces_symbol,
variant = 'spaces',
}).name,
[TABS] = scrollview.register_sign_spec({
group = group,
highlight = 'ScrollViewIndentTabs',
priority = vim.g.scrollview_indent_tabs_priority,
symbol = vim.g.scrollview_indent_tabs_symbol,
variant = 'tabs',
}).name,
}

scrollview.set_sign_group_state(group, enable)

scrollview.set_sign_group_callback(group, function()
-- 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)
local expandtab = api.nvim_buf_get_option(bufnr, 'expandtab')
if not visited[bufnr] then
local bufvars = vim.b[bufnr]
local lines = {
[SPACES] = {},
[TABS] = {},
}
local changedtick = vim.b[bufnr].changedtick
local changedtick_cached = bufvars.scrollview_indent_changedtick_cached
local bufnr_cached = bufvars.scrollview_indent_bufnr_cached
local spaces_condition_cached =
bufvars.scrollview_indent_spaces_condition_cached
local tabs_condition_cached =
bufvars.scrollview_indent_tabs_condition_cached
local expandtab_cached =
bufvars.scrollview_indent_expandtab_option_cached
local cache_hit = changedtick_cached == changedtick
and bufnr_cached == bufnr
and expandtab_cached == expandtab
and spaces_condition_cached == vim.g.scrollview_indent_spaces_condition
and tabs_condition_cached == vim.g.scrollview_indent_tabs_condition
if cache_hit then
lines[SPACES] = bufvars.scrollview_indent_spaces_cached
lines[TABS] = bufvars.scrollview_indent_tabs_cached
else
local line_count = api.nvim_buf_line_count(bufnr)
local show_spaces_signs =
should_show(vim.g.scrollview_indent_spaces_condition, expandtab)
local show_tabs_signs =
should_show(vim.g.scrollview_indent_tabs_condition, expandtab)
for line = 1, line_count do
local str = fn.getbufline(bufnr, line)[1]
local sub = string.sub(str, 1, 1)
if sub == ' ' then
if show_spaces_signs then
table.insert(lines[SPACES], line)
end
elseif sub == '\t' then
if show_tabs_signs then
table.insert(lines[TABS], line)
end
end
end
-- luacheck: ignore 122 (setting read-only field b.?.? of global vim)
bufvars.scrollview_indent_expandtab_option_cached = expandtab
-- luacheck: ignore 122 (setting read-only field b.?.? of global vim)
bufvars.scrollview_indent_spaces_condition_cached =
vim.g.scrollview_indent_spaces_condition
-- luacheck: ignore 122 (setting read-only field b.?.? of global vim)
bufvars.scrollview_indent_tabs_condition_cached =
vim.g.scrollview_indent_tabs_condition
-- luacheck: ignore 122 (setting read-only field w.?.? of global vim)
bufvars.scrollview_indent_changedtick_cached = changedtick
-- luacheck: ignore 122 (setting read-only field w.?.? of global vim)
bufvars.scrollview_indent_bufnr_cached = bufnr
-- luacheck: ignore 122 (setting read-only field w.?.? of global vim)
bufvars.scrollview_indent_spaces_cached = lines[SPACES]
-- luacheck: ignore 122 (setting read-only field w.?.? of global vim)
bufvars.scrollview_indent_tabs_cached = lines[TABS]
end
-- luacheck: ignore 122 (setting read-only field w.?.? of global vim)
bufvars[names[SPACES]] = lines[SPACES]
bufvars[names[TABS]] = lines[TABS]
visited[bufnr] = true
end
end
end)

api.nvim_create_autocmd('TextChangedI', {
callback = function()
if not scrollview.is_sign_group_active(group) then return end
local bufnr = api.nvim_get_current_buf()
local expandtab = api.nvim_buf_get_option(bufnr, 'expandtab')
local line = fn.line('.')
local str = fn.getbufline(bufnr, line)[1]
local sub = string.sub(str, 1, 1)
for _, mode in ipairs({SPACES, TABS}) do
local expect_sign = false
if mode == SPACES then
local show_signs =
should_show(vim.g.scrollview_indent_spaces_condition, expandtab)
expect_sign = sub == ' ' and show_signs
elseif mode == TABS then
local show_tabs =
should_show(vim.g.scrollview_indent_tabs_condition, expandtab)
expect_sign = sub == '\t' and show_tabs
else
error('Unknown mode: ' .. mode)
end
local lines = vim.b[bufnr][names[mode]]
local idx = -1
if lines ~= nil then
idx = utils.binary_search(lines, line)
if lines[idx] ~= line then
idx = -1
end
end
local has_sign = idx ~= -1
if expect_sign ~= has_sign then
scrollview.refresh()
break
end
end
end
})

api.nvim_create_autocmd('OptionSet', {
pattern = 'expandtab',
callback = function()
if not scrollview.is_sign_group_active(group) then return end
if vim.g.scrollview_indent_spaces_condition == 'expandtab'
or vim.g.scrollview_indent_spaces_condition == 'noexpandtab'
or vim.g.scrollview_indent_tabs_condition == 'expandtab'
or vim.g.scrollview_indent_tabs_condition == 'noexpandtab' then
scrollview.refresh()
end
end
})
end

return M
2 changes: 2 additions & 0 deletions plugin/scrollview.vim
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ if has('nvim-0.9.2')
else
highlight default link ScrollViewHover WildMenu
endif
highlight default link ScrollViewIndentSpaces LineNr
highlight default link ScrollViewIndentTabs LineNr
highlight default link ScrollViewLatestChange SpecialKey
highlight default link ScrollViewLocList LineNr
highlight default link ScrollViewMarks Identifier
Expand Down

0 comments on commit 086e194

Please sign in to comment.