Skip to content

Commit 2a5cd54

Browse files
committed
feat: rewrite git management with sqlite
use `tami5/sqlite.nvim` to store git informations. Run git small commands in system and run git status management in a libuv job. This allows to fetch millions of status and add them partially in the database to avoid destroying the lua memory with huge tables. The paths can then be retrieved partially to apply updates.
1 parent 86e6dc6 commit 2a5cd54

File tree

9 files changed

+393
-214
lines changed

9 files changed

+393
-214
lines changed

Diff for: lua/nvim-tree.lua

+9-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ local function setup_autocommands(opts)
379379
""" reset highlights when colorscheme is changed
380380
au ColorScheme * lua require'nvim-tree'.reset_highlight()
381381
382-
au BufWritePost * lua require'nvim-tree'.refresh()
382+
au BufWritePost * lua require'nvim-tree.lib'.refresh_tree(true)
383383
au User FugitiveChanged,NeogitStatusRefreshed lua require'nvim-tree'.refresh()
384384
]]
385385

@@ -436,6 +436,13 @@ local DEFAULT_OPTS = {
436436
error = "",
437437
}
438438
},
439+
git = {
440+
enable = true,
441+
show_highlights = false,
442+
show_icons = true,
443+
icon_placement = 'left',
444+
ignore = true,
445+
}
439446
}
440447

441448
function M.setup(conf)
@@ -464,6 +471,7 @@ function M.setup(conf)
464471
require'nvim-tree.colors'.setup()
465472
require'nvim-tree.view'.setup(opts.view or {})
466473
require'nvim-tree.diagnostics'.setup(opts)
474+
require'nvim-tree.git'.setup(opts)
467475

468476
setup_autocommands(opts)
469477
setup_vim_commands()

Diff for: lua/nvim-tree/git.lua

-168
This file was deleted.

Diff for: lua/nvim-tree/git/db.lua

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
local _, sqlite = pcall(require, 'sqlite')
2+
3+
local uv = vim.loop
4+
local utils = require'nvim-tree.utils'
5+
6+
local Db = {}
7+
Db.__index = Db
8+
9+
local function create_uri()
10+
local cache = vim.fn.stdpath "cache"
11+
local path = utils.path_join({cache, "nvim-tree-sqlite-"..uv.random(2)})
12+
while uv.fs_access(path, 'R') do
13+
path = utils.path_join({cache, "nvim-tree-sqlite-"..uv.random(2)})
14+
end
15+
return path
16+
end
17+
18+
local function init_db()
19+
local uri = create_uri()
20+
local db = sqlite {
21+
uri = uri,
22+
statuses = {
23+
path = "text",
24+
status = "text",
25+
},
26+
}
27+
db:open()
28+
vim.cmd [[
29+
augroup NvimTreeSqlite
30+
au VimLeavePre * lua require'nvim-tree.git'.cleanup()
31+
augroup END
32+
]]
33+
return db, uri
34+
end
35+
36+
function Db.new()
37+
local db, uri = init_db()
38+
return setmetatable({
39+
db = db,
40+
uri = uri,
41+
insertion_cache = {}
42+
}, Db)
43+
end
44+
45+
function Db:cleanup()
46+
self.db:close()
47+
uv.fs_unlink(self.uri)
48+
end
49+
50+
function Db:insert_cache()
51+
if #self.insertion_cache == 0 then
52+
return
53+
end
54+
self.db:insert("statuses", self.insertion_cache)
55+
self.insertion_cache = {}
56+
end
57+
58+
function Db:insert(path, status)
59+
if #self.insertion_cache < 2000 then
60+
return table.insert(self.insertion_cache, { path = path, status = status })
61+
else
62+
self:insert_cache()
63+
end
64+
end
65+
66+
function Db:get_from_path(cwd)
67+
local query = "select * from statuses where path LIKE ?"
68+
local statuses = self.db:eval(query, cwd..'%')
69+
if type(statuses) == "table" then
70+
return statuses
71+
else
72+
return {}
73+
end
74+
end
75+
76+
function Db:clean_paths(cwd)
77+
self.db:eval("delete from statuses where path LIKE ?", cwd..'%')
78+
end
79+
80+
return Db

Diff for: lua/nvim-tree/git/init.lua

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
local utils = require'nvim-tree.git.utils'
2+
local updater = require'nvim-tree.git.tree-update'
3+
local Runner = require'nvim-tree.git.runner'
4+
5+
local M = {
6+
db = nil,
7+
toplevels = {},
8+
}
9+
10+
function M.handle_update(node)
11+
return function()
12+
local filter_ignored = M.config.ignore and not require'nvim-tree.populate'.show_ignored
13+
updater.update(M.db, node, filter_ignored)
14+
require'nvim-tree.lib'.redraw()
15+
end
16+
end
17+
18+
function M.set_toplevel(path, toplevel)
19+
if not M.config.enable then
20+
return
21+
end
22+
toplevel = toplevel or utils.get_toplevel(path)
23+
if not toplevel or M.toplevels[toplevel] ~= nil then
24+
return
25+
end
26+
27+
M.toplevels[toplevel] = utils.show_untracked(toplevel)
28+
end
29+
30+
function M.run_git_status(toplevel, node)
31+
local show_untracked = M.toplevels[toplevel]
32+
local runner = Runner.new {
33+
db = M.db,
34+
toplevel = toplevel,
35+
show_untracked = show_untracked,
36+
with_ignored = M.config.ignore
37+
}
38+
39+
runner:run(M.handle_update(node))
40+
end
41+
42+
function M.run(node)
43+
if not M.config.enable then
44+
return
45+
end
46+
47+
local toplevel = utils.get_toplevel(node.absolute_path)
48+
if not toplevel then
49+
return
50+
end
51+
52+
if M.toplevels[toplevel] == nil then
53+
M.set_toplevel(nil, toplevel)
54+
M.run_git_status(toplevel, node)
55+
else
56+
M.handle_update(node)()
57+
end
58+
end
59+
60+
local function check_sqlite()
61+
local has_sqlite = pcall(require, 'sqlite')
62+
if M.config.enable and not has_sqlite then
63+
local info = "[NvimTree] Git integration requires sqlite.lua to be installed (see :help nvim-tree-git)"
64+
require'nvim-tree.utils'.echo_warning(info)
65+
M.config.enable = false
66+
end
67+
end
68+
69+
function M.reload()
70+
if not M.config.enable then
71+
return
72+
end
73+
74+
for toplevel, show_untracked in pairs(M.toplevels) do
75+
local runner = Runner.new {
76+
db = M.db,
77+
toplevel = toplevel,
78+
show_untracked = show_untracked,
79+
with_ignored = M.config.ignore
80+
}
81+
local tree = require'nvim-tree.lib'.Tree
82+
local node
83+
if tree.cwd == toplevel then
84+
node = { entries = tree.entries, absolute_path = tree.cwd }
85+
else
86+
node = require'nvim-tree.utils'.find_node(tree.entries, function(n)
87+
return toplevel == n.absolute_path
88+
end)
89+
end
90+
if node then
91+
runner:run(M.handle_update(node))
92+
end
93+
end
94+
end
95+
96+
function M.cleanup()
97+
M.db:cleanup()
98+
end
99+
100+
function M.setup(opts)
101+
M.config = {}
102+
M.config.enable = opts.git.enable
103+
M.config.show_highlights = opts.git.show_highlights
104+
M.config.show_icons = opts.git.show_icons
105+
M.config.icon_placement = opts.git.placement
106+
M.config.ignore = opts.git.ignore
107+
check_sqlite()
108+
109+
if M.config.enable then
110+
M.db = require'nvim-tree.git.db'.new()
111+
end
112+
end
113+
114+
return M

0 commit comments

Comments
 (0)