Skip to content

Commit

Permalink
fix(indent): simplify indent guide logic and never overwrite blanks. F…
Browse files Browse the repository at this point in the history
…ixes #334
  • Loading branch information
folke committed Dec 18, 2024
1 parent 56e877f commit 282be8b
Showing 1 changed file with 20 additions and 59 deletions.
79 changes: 20 additions & 59 deletions lua/snacks/indent.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ local defaults = {

local config = Snacks.config.get("scope", defaults)
local ns = vim.api.nvim_create_namespace("snacks_indent")
local cache_extmarks = {} ---@type table<string, vim.api.keyset.set_extmark|false>
local cache_extmarks = {} ---@type table<string, vim.api.keyset.set_extmark[]>
local debug_timer = assert((vim.uv or vim.loop).new_timer())
local cache_underline = {} ---@type table<string, boolean>
local states = {} ---@type table<number, snacks.indent.State>
Expand Down Expand Up @@ -142,8 +142,7 @@ end
--- the given indent level, left column and shiftwidth
---@param indent number
---@param state snacks.indent.State
local function get_extmark(indent, state)
local space = state.space
local function get_extmarks(indent, state)
local key = indent
.. ":"
.. state.leftcol
Expand All @@ -152,66 +151,34 @@ local function get_extmark(indent, state)
.. ":"
.. state.indent_offset
.. ":"
.. space
.. ":"
.. (state.breakindent and "bi" or "")
if cache_extmarks[key] ~= nil then
if cache_extmarks[key] then
return cache_extmarks[key]
end
stats.extmarks = stats.extmarks + 1

local sw = state.shiftwidth
indent = math.floor(indent / sw) * sw -- align to shiftwidth
indent = indent - state.leftcol -- adjust for visible indents
local rem = indent % sw -- remaining spaces of the first partially visible indent
indent = math.floor(indent / sw) -- full visible indents
local offset = math.max(math.floor((state.indent_offset - state.leftcol + sw) / sw), 0) -- offset for the scope

-- hide if indent is 0 and no remaining spaces
if indent < 1 and rem == 0 then
cache_extmarks[key] = false
return false
end

local hidden = math.ceil(state.leftcol / sw) -- level of the last hidden indent
local blank = space:rep(sw - vim.api.nvim_strwidth(config.indent.char))

local text = {} ---@type string[][]
text[1] = rem > 0 and { (space):rep(rem), get_hl(hidden, config.blank.hl) } or nil

for i = 1, indent do
if i >= offset then
text[#text + 1] = { config.indent.char, get_hl(i + hidden, config.indent.hl) }
else
text[#text + 1] = { space, get_hl(i + hidden, config.blank.hl) }
local offset = math.max(math.floor(state.indent_offset / sw), 0) -- offset for the scope
cache_extmarks[key] = {}

for i = 1 + offset, indent do
local col = (i - 1) * sw - state.leftcol
if col >= 0 then
table.insert(cache_extmarks[key], {
virt_text = { { config.indent.char, get_hl(i + 1, config.indent.hl) } },
virt_text_pos = "overlay",
virt_text_win_col = col,
hl_mode = "combine",
priority = config.indent.priority,
ephemeral = true,
virt_text_repeat_linebreak = state.breakindent,
})
end
text[#text + 1] = { blank, get_hl(i + hidden, config.blank.hl) }
end

cache_extmarks[key] = {
virt_text = text,
virt_text_pos = "overlay",
virt_text_win_col = 0,
hl_mode = "combine",
priority = config.indent.priority,
ephemeral = true,
virt_text_repeat_linebreak = state.breakindent,
}
return cache_extmarks[key]
end

local function get_listchars(win)
local chars = vim.wo[win].list and vim.wo[win].listchars
local ret = {} ---@type table<string, string>
for _, o in ipairs(chars and vim.split(chars, ",") or {}) do
local k, v = o:match("(.-):(.+)")
if k then
ret[k] = v
end
end
return ret
end

---@param win number
---@param buf number
---@param top number
Expand All @@ -236,11 +203,8 @@ local function get_state(win, buf, top, bottom)
indents = prev and prev.indents or { [0] = 0 },
blanks = prev and prev.blanks or {},
indent_offset = 0, -- the start column of the indent guides
listchars = get_listchars(win),
breakindent = vim.wo[win].breakindent and vim.wo[win].wrap,
space = " ",
}
state.space = config.indent.blank or state.listchars.lead or state.listchars.space or " "
state.shiftwidth = state.shiftwidth == 0 and vim.bo[buf].tabstop or state.shiftwidth
states[win] = state
return state
Expand Down Expand Up @@ -302,8 +266,8 @@ function M.on_win(win, buf, top, bottom)
current_indent = indent
end
indent = math.min(indent, parent_indent + state.shiftwidth)
local opts = show_indent and indent > 0 and get_extmark(indent, state)
if opts then
local extmarks = show_indent and indent > 0 and get_extmarks(indent, state)
for _, opts in ipairs(extmarks or {}) do
vim.api.nvim_buf_set_extmark(buf, ns, l - 1, 0, opts)
end
end
Expand Down Expand Up @@ -414,9 +378,6 @@ function M.render_chunk(scope, state)
end
add(l, char.corner_top .. (char.horizontal):rep(i - col - 1))
elseif l == scope.to then -- bottom line
if state.breakindent then
add(l, char.vertical .. (state.space):rep(i - col - 2), true)
end
add(l, char.corner_bottom .. (char.horizontal):rep(i - col - 2) .. char.arrow)
elseif i and i > col then -- middle line
add(l, char.vertical, state.breakindent)
Expand Down

0 comments on commit 282be8b

Please sign in to comment.