Skip to content
This repository was archived by the owner on Aug 16, 2025. It is now read-only.
2 changes: 2 additions & 0 deletions lua/sidebar-nvim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ end
-- @param opts table
-- @param opts.section_index number
-- @param opts.cursor_at_content boolean
-- @param opts.query table data sent to the section (if found) to refine the location
-- @param opts.section_line_offset number
function M.focus(opts)
lib.focus(opts)
end
Expand Down
115 changes: 96 additions & 19 deletions lua/sidebar-nvim/builtin/files.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ local icons = {
local yanked_files = {}
local cut_files = {}
local open_directories = {}
local focused_file_path = nil

local section_index = nil

local history = { position = 0, groups = {} }
local trash_dir = luv.os_homedir() .. "/.local/share/Trash/files/"
Expand Down Expand Up @@ -113,18 +116,27 @@ local function build_loclist(group, directory, level)
selected = { text = " *", hl = "SidebarNvimFilesCut" }
end

local name_hl = nil
if
focused_file_path ~= nil
and vim.fn.fnamemodify(node.path, ":.") == vim.fn.fnamemodify(focused_file_path, ":.")
then
name_hl = "SidebarNvimFocusedFile"
end

loclist_items[#loclist_items + 1] = {
group = group,
left = {
{ text = string.rep(" ", level) .. icon.text .. " ", hl = icon.hl },
{ text = node.name },
{ text = node.name, hl = name_hl },
selected,
},
name = node.name,
path = node.path,
type = node.type,
parent = node.parent,
node = node,
id = node.path,
}
elseif node.type == "directory" then
local icon
Expand Down Expand Up @@ -167,12 +179,75 @@ local function build_loclist(group, directory, level)
return loclist_items
end

local function update(group, directory)
local function update_current_dir(group, directory)
local node = { path = directory, children = scan_dir(directory) }

loclist:set_items(build_loclist(group, node, 0), { remove_groups = true })
end

local function update(_)
local cwd = vim.fn.getcwd()
local group = utils.shortest_path(cwd)

open_directories[cwd] = true

update_current_dir(group, cwd)
end

local function focus(filename, opts)
opts = vim.tbl_deep_extend("force", { move_cursor = false }, opts or {})

local parent_path
-- reset the open directories
open_directories = {}

if filename == nil then
filename = vim.fn.expand("%:p")
parent_path = vim.fn.expand("%:p:h")
else
filename = vim.fn.expand(filename)
filename = vim.fn.fnamemodify(filename, ":p")
parent_path = vim.fn.fnamemodify(filename, ":p:h")
end

local cwd = vim.fn.getcwd()
local relative_path = vim.fn.fnamemodify(parent_path, ":.")

-- if the file is at the root, then ignore parent folders
if cwd ~= relative_path then
local components = vim.split(relative_path, "/")

local sub_path = cwd

for _, component in ipairs(components) do
sub_path = sub_path .. "/" .. component

-- check wether we are outside of the current dir, in this case we have nothing to show. exit
if vim.fn.isdirectory(sub_path) == 0 then
return
end

open_directories[sub_path] = true
end
end

focused_file_path = filename

if opts.move_cursor then
require("sidebar-nvim.lib").run_after_next_draw(function()
local line = loclist:get_line_at_id(filename)
require("sidebar-nvim.lib").focus({
section_index = section_index,
cursor_at_content = true,
section_line_offset = line,
})
end)
end

update() --P(path)
require("sidebar-nvim.lib").update()
end

local function exec(group)
for _, op in ipairs(group.operations) do
op.exec()
Expand Down Expand Up @@ -263,26 +338,25 @@ end
return {
title = "Files",
icon = config["files"].icon,
setup = function(_)
vim.api.nvim_exec(
[[
augroup sidebar_nvim_files_update
autocmd!
autocmd ShellCmdPost * lua require'sidebar-nvim.builtin.files'.update()
autocmd BufLeave term://* lua require'sidebar-nvim.builtin.files'.update()
augroup END
]],
false
setup = function(ctx)
section_index = ctx.section_index
vim.api.nvim_create_augroup("sidebar_nvim_files_update", { clear = true })
vim.api.nvim_create_autocmd({ "ShellCmdPost" }, { group = "sidebar_nvim_files_update", callback = update })
vim.api.nvim_create_autocmd(
{ "BufLeave" },
{ group = "sidebar_nvim_files_update", pattern = "term://*", callback = update }
)
end,
update = function(_)
local cwd = vim.fn.getcwd()
local group = utils.shortest_path(cwd)

open_directories[cwd] = true

update(group, cwd)
if config["files"].follow then
vim.api.nvim_create_autocmd({ "BufEnter", "BufLeave" }, {
group = "sidebar_nvim_files_update",
callback = function(event)
focus(event.file)
end,
})
end
end,
update = update,
draw = function(ctx)
local lines = {}
local hl = {}
Expand All @@ -298,9 +372,12 @@ return {
SidebarNvimFilesDirectory = "SidebarNvimSectionTitle",
SidebarNvimFilesYanked = "SidebarNvimLabel",
SidebarNvimFilesCut = "DiagnosticError",
SidebarNvimFocusedFile = "CursorLine",
},
},

focus = focus,

bindings = {
-- delete
["d"] = function(line)
Expand Down
19 changes: 18 additions & 1 deletion lua/sidebar-nvim/components/loclist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ function Loclist:new(o)
o = vim.tbl_deep_extend("force", vim.deepcopy(Loclist.DEFAULT_OPTIONS), o or {}, {
-- table(line_number -> group ref)
_group_indexes = {},
-- table(line__number -> item ref)
-- table(line_number -> item ref)
_location_indexes = {},
-- table(id -> line_number)
_line_by_ids = {},
-- used to keep the group list stable
_group_keys = {},
})
Expand All @@ -56,6 +58,7 @@ end
-- |--|- (string) item.left[n].text = "abc"
-- |--|- (string) item.left[n].hl = "<highlight group>"
-- |- (number) item.order items are sorted based on order within each group
-- |- (any) item.id a unique id across the whole loclist, this is used for fast lookups. The id must also be unique between groups. If no id is specified, a random id is assigned
function Loclist:add_item(item)
if not self.groups[item.group] then
self.groups[item.group] = { is_closed = self.groups_initially_closed or false }
Expand All @@ -65,6 +68,10 @@ function Loclist:add_item(item)
table.insert(self._group_keys, item.group)
end

if item.id == nil then
item.id = math.random(1000000)
end

local group_tbl = self.groups[item.group]
group_tbl[#group_tbl + 1] = item

Expand Down Expand Up @@ -169,6 +176,7 @@ function Loclist:draw_group(ctx, group_name, with_label, section_lines, section_

for _, item in ipairs(group) do
self._location_indexes[#section_lines] = item
self._line_by_ids[item.id] = #section_lines
local line = ""

if with_label then
Expand Down Expand Up @@ -241,6 +249,7 @@ end
function Loclist:draw(ctx, section_lines, section_hl)
self._group_indexes = {}
self._location_indexes = {}
self._line_by_ids = {}

if #self._group_keys == 1 and self.omit_single_group then
self:draw_group(ctx, self._group_keys[1], false, section_lines, section_hl)
Expand All @@ -260,6 +269,14 @@ function Loclist:get_location_at(line)
return location
end

-- returns the line of where the item id is placed
-- if there is no item with the requested id, return nil.
-- @see Loclist:add_item
-- @param (any) id
function Loclist:get_line_at_id(id)
return self._line_by_ids[id]
end

-- toggles the group open/close that is printed on line `line`
-- if there is no group at `line`, then do nothing
-- @param (number) line
Expand Down
46 changes: 33 additions & 13 deletions lua/sidebar-nvim/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ local first_init_done = false

local M = {}

M.State = { section_line_indexes = {} }
M.State = { section_line_indexes = {}, after_draw_call_queue = {} }

M.timer = nil

Expand All @@ -32,6 +32,14 @@ local function loop()

updater.draw()
_redraw()

for _, fn in ipairs(M.State.after_draw_call_queue) do
local ret = pcall(fn)
if not ret then
utils.echo_warning("after_draw_call failed")
end
end
M.State.after_draw_call_queue = {}
end

local function _start_timer(should_delay)
Expand Down Expand Up @@ -78,6 +86,10 @@ function M.update()
_start_timer(true)
end

function M.run_after_next_draw(fn)
table.insert(M.State.after_draw_call_queue, fn)
end

function M.open(opts)
view.open(opts or { focus = false })
M.update()
Expand Down Expand Up @@ -115,13 +127,9 @@ end
-- @param opts table
-- @param opts.section_index number
-- @param opts.cursor_at_content boolean
-- @param opts.section_line_offset number
function M.focus(opts)
if view.is_win_open() then
local winnr = view.get_winnr()
view.focus(winnr)
else
M.open({ focus = true })
end
local cursor = nil

if opts and opts.section_index then
local content_only = true
Expand All @@ -130,11 +138,21 @@ function M.focus(opts)
content_only = false
end

local cursor = M.find_cursor_at_section_index(opts.section_index, { content_only = content_only })
cursor = M.find_cursor_at_section_index(
opts.section_index,
{ content_only = content_only, section_line_offset = opts.section_line_offset }
)
end

if cursor then
api.nvim_win_set_cursor(0, cursor)
end
if view.is_win_open() then
local winnr = view.get_winnr(nil)
view.focus(winnr)
else
M.open({ focus = true })
end

if cursor then
api.nvim_win_set_cursor(0, cursor)
end
end

Expand Down Expand Up @@ -206,16 +224,18 @@ end
-- @param index number
-- @param opts table
-- @param |- opts.content_only boolean whether the cursor should be placed at the first line of content or the section title
-- @param |- opts.section_line_offset number
-- @return table with cursor {line: number, col: number}
-- @return nil
function M.find_cursor_at_section_index(index, opts)
opts = opts or { content_only = false }
opts = vim.tbl_deep_extend("force", { content_only = false, section_line_offset = 0 }, opts or {})

local cursor = { 0, 0 }

for section_index, section_line_index in ipairs(M.State.section_line_indexes) do
if section_index == index then
local start_line = get_start_line(opts.content_only, section_line_index)
local content_only = opts.content_only
local start_line = get_start_line(content_only, section_line_index) + opts.section_line_offset

cursor[1] = start_line
return cursor
Expand Down
9 changes: 4 additions & 5 deletions lua/sidebar-nvim/updater.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local utils = require("sidebar-nvim.utils")
local utils_sections = require("sidebar-nvim.utils_sections")
local view = require("sidebar-nvim.view")
local config = require("sidebar-nvim.config")
local profile = require("sidebar-nvim.profile")
Expand All @@ -17,8 +18,8 @@ function M.setup()

local ctx = { width = view.get_width() }

for section_index, section_data in ipairs(config.sections) do
local section = utils.resolve_section(section_index, section_data)
for section_index, section in utils_sections.section_iterator() do
ctx.section_index = section_index
if section then
local hl_def = section.highlights or {}

Expand Down Expand Up @@ -65,9 +66,7 @@ function M.draw()

local draw_ctx = { width = view.View.width }

for section_index, section_data in pairs(config.sections) do
local section = utils.resolve_section(section_index, section_data)

for section_index, section in utils_sections.section_iterator() do
if section ~= nil then
local section_lines = profile.run("draw.sections." .. section_index, section.draw, draw_ctx)
local data = { lines = section_lines, section = section }
Expand Down
21 changes: 21 additions & 0 deletions lua/sidebar-nvim/utils_sections.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
local utils = require("sidebar-nvim.utils")
local config = require("sidebar-nvim.config")

local M = {}

function M.section_iterator()
local i = 0
return function()
i = i + 1
if i <= #config.sections then
local section = utils.resolve_section(i, config.sections[i])
return i, section
end
end
end

function M.get_section_at_index(index)
return utils.resolve_section(index, config.sections[index])
end

return M
1 change: 1 addition & 0 deletions plugin/sidebar-nvim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ command! SidebarNvimClose lua require'sidebar-nvim'.close()
command! SidebarNvimToggle lua require'sidebar-nvim'.toggle()
command! SidebarNvimUpdate lua require'sidebar-nvim'.update()
command! SidebarNvimFocus lua require'sidebar-nvim'.focus()
command! SidebarNvimFilesFind lua require'sidebar-nvim.builtin.files'.focus('%', { move_cursor = true })
command! -nargs=1 SidebarNvimResize lua require'sidebar-nvim'.resize(<args>)

let &cpo = s:save_cpo
Expand Down