local fuzpath = require 'fuzpath'
local id = { name = 1, count = 2 }
local function insert(tbl, val)
table.insert(tbl, { val, 1 })
end
local function compare(rec1, rec2)
return rec1[id.count] > rec2[id.count]
end
local function readfile(name)
local ret = {}
local fp = io.open(name, 'r')
if not fp then return {} end
for line in fp:lines() do
table.insert(ret, vim.split(line, ','))
end
fp:close()
table.sort(ret, compare)
return ret
end
local logfile = vim.fn.stdpath('data') .. '/cdtrack/dir.log'
local dirs_table = readfile(logfile)
local function getcol(self, n)
return vim.tbl_map(function(row)
return row[n]
end, self)
end
local cwd = vim.uv.cwd()
if not vim.tbl_contains(getcol(dirs_table, id.name), cwd) then
insert(dirs_table, cwd)
end
local function finddirrecord(dirs, dir)
for _, rec in ipairs(dirs) do
if rec[id.name] == dir then
return _
end
end
end
local function update_record(dirs, dir)
local index = finddirrecord(dirs, dir)
if index then
dirs[index][id.count] = dirs[index][id.count] + 1
else
insert(dirs, dir)
end
end
local function normalize_path(dir)
local isrel = dir:sub(1, 1) ~= '/'
local base = isrel and vim.uv.cwd() .. '/' or ''
return vim.fs.normalize(base .. dir)
end
local function rm_nonexistpath(pathtbl)
local i = 1
while i <= #pathtbl do
if vim.uv.fs_stat(pathtbl[i]) then
i = i + 1
else
table.remove(pathtbl, i)
end
end
return pathtbl
end
local function findmatch(trigger)
local matched = fuzpath.fuzpath(getcol(dirs_table, id.name), trigger)
return rm_nonexistpath(matched)
end
local function cdtrack(input)
local dir = normalize_path(input)
if not vim.uv.fs_stat(dir) then
local candidates = findmatch(input)
if #candidates == 0 then
print('No such directory ' .. dir)
return
end
if #candidates == 1 then
dir = candidates[1]
else
vim.ui.select(candidates, { prompt = 'Select Directory:' }, function(choise)
dir = choise
end)
end
end
vim.cmd.cd(dir)
end
vim.api.nvim_create_user_command('Z', function(opts)
cdtrack(opts.fargs[1])
end, { nargs = 1, bar = true, complete = findmatch })
vim.keymap.set('n', 'Zf', function()
vim.ui.input({ prompt = 'cdtrack: ', complete = findmatch }, cdtrack)
end)
vim.api.nvim_create_autocmd('DirChanged', {
callback = function()
update_record(dirs_table, vim.uv.cwd())
end
})
vim.api.nvim_create_autocmd('VimLeave', {
callback = function()
if vim.fn.mkdir(vim.fn.fnamemodify(logfile, ':p:h'), 'p') ~= 1 then return end
local buf = table.concat(vim.tbl_map(function(row)
return table.concat(row, ',')
end, dirs_table), '\n')
local fp = io.open(logfile, 'w')
if not fp then return end fp:write(buf)
fp:close()
end
})