Neovim quick file switcher
1---@module 'snacks'
2
3local log = require("javelin.log")
4
5local Data = {}
6
7---@type JavelinConfig
8local options
9
10local data_dir
11local data_cache = {}
12
13---@param path string
14---@return string
15local function hash_path(path)
16 return vim.fn.sha256(vim.fn.resolve(path))
17end
18
19---@param root_path string
20local function get_data_file(root_path)
21 return vim.fn.resolve(data_dir .. "/" .. hash_path(root_path))
22end
23
24---@param root_path string
25---@param path string
26---@return string
27local function normalize_path(root_path, path)
28 root_path = root_path .. "/"
29 if vim.startswith(path, root_path) then
30 return path:sub(#root_path + 1)
31 end
32
33 return path
34end
35
36---@param root_path string
37---@param list string[]
38---@return string[]
39local function normalize_list(root_path, list)
40 local new_list = {}
41 for _, path in ipairs(list) do
42 if path ~= "" then
43 table.insert(new_list, path)
44 end
45 end
46
47 for i, path in ipairs(new_list) do
48 new_list[i] = normalize_path(root_path, path)
49 end
50
51 return new_list
52end
53
54---@param root_path string
55local function load(root_path)
56 local data_file = get_data_file(root_path)
57 if not vim.uv.fs_stat(data_file) then
58 return {}
59 end
60
61 return normalize_list(root_path, vim.fn.readfile(data_file))
62end
63
64---@param root_path string
65local function write(root_path)
66 vim.fn.writefile(Data.get_list(root_path), get_data_file(root_path))
67end
68
69---@param root_path string
70---@param path string
71local function add_path(root_path, path)
72 local list = Data.get_list(root_path)
73 path = normalize_path(root_path, vim.fn.fnamemodify(path, ":~"))
74
75 if vim.tbl_contains(list, path) then
76 log.warn("File already in list: " .. path)
77 return
78 end
79
80 table.insert(list, path)
81 write(root_path)
82end
83
84---@param root_path string
85---@return string[]
86function Data.get_list(root_path)
87 local hash = hash_path(root_path)
88 if data_cache[hash] == nil then
89 data_cache[hash] = load(root_path)
90 end
91
92 return data_cache[hash]
93end
94
95---@return string[]
96function Data.get_current()
97 return Data.get_list(Data.get_root())
98end
99
100function Data.add_current()
101 local filename = vim.api.nvim_buf_get_name(0)
102 local buftype = vim.api.nvim_get_option_value("buftype", { buf = 0 })
103
104 if filename ~= "" and buftype == "" then
105 add_path(Data.get_root(), filename)
106 else
107 log.warn("Cannot add this buffer")
108 end
109end
110
111---@param root_path string
112---@param lines string[]
113function Data.update(root_path, lines)
114 data_cache[hash_path(root_path)] = normalize_list(root_path, lines)
115 write(root_path)
116end
117
118---@return string
119function Data.get_root()
120 local root = vim.fn.getcwd()
121
122 if options.use_git_root then
123 local git_root = Snacks.git.get_root(root)
124 if git_root then
125 root = git_root
126 end
127 end
128
129 return vim.fn.fnamemodify(root, ":~")
130end
131
132function Data.setup(opt)
133 options = opt
134
135 data_dir = vim.fn.resolve(vim.fn.stdpath("data") .. "/javelin")
136 if not vim.uv.fs_stat(data_dir) then
137 vim.uv.fs_mkdir(data_dir, tonumber("755", 8))
138 end
139end
140
141return Data