remove old code
This commit is contained in:
parent
c2403bc5cd
commit
c7cfeb39bf
@ -1,84 +0,0 @@
|
||||
local api = vim.api
|
||||
local config = require'lib.config'
|
||||
|
||||
local M = {}
|
||||
|
||||
local function get_color_from_hl(hl_name, fallback)
|
||||
local id = vim.api.nvim_get_hl_id_by_name(hl_name)
|
||||
if not id then return fallback end
|
||||
|
||||
local hl = vim.api.nvim_get_hl_by_id(id, true)
|
||||
if not hl or not hl.foreground then return fallback end
|
||||
|
||||
return hl.foreground
|
||||
end
|
||||
|
||||
local function get_colors()
|
||||
return {
|
||||
red = vim.g.terminal_color_1 or get_color_from_hl('Keyword', 'Red'),
|
||||
green = vim.g.terminal_color_2 or get_color_from_hl('Character', 'Green'),
|
||||
yellow = vim.g.terminal_color_3 or get_color_from_hl('PreProc', 'Yellow'),
|
||||
blue = vim.g.terminal_color_4 or get_color_from_hl('Include', 'Blue'),
|
||||
purple = vim.g.terminal_color_5 or get_color_from_hl('Define', 'Purple'),
|
||||
cyan = vim.g.terminal_color_6 or get_color_from_hl('Conditional', 'Cyan'),
|
||||
dark_red = vim.g.terminal_color_9 or get_color_from_hl('Keyword', 'DarkRed'),
|
||||
orange = vim.g.terminal_color_11 or get_color_from_hl('Number', 'Orange'),
|
||||
}
|
||||
end
|
||||
|
||||
local function get_hl_groups()
|
||||
local colors = get_colors()
|
||||
|
||||
return {
|
||||
IndentMarker = { fg = '#8094b4' },
|
||||
Symlink = { gui = 'bold', fg = colors.cyan },
|
||||
FolderIcon = { fg = '#8094b4' },
|
||||
RootFolder = { fg = colors.purple },
|
||||
|
||||
ExecFile = { gui = 'bold', fg = colors.green },
|
||||
SpecialFile = { gui = 'bold,underline', fg = colors.yellow },
|
||||
ImageFile = { gui = 'bold', fg = colors.purple },
|
||||
|
||||
GitDirty = { fg = colors.dark_red },
|
||||
GitDeleted = { fg = colors.dark_red },
|
||||
GitStaged = { fg = colors.green },
|
||||
GitMerge = { fg = colors.orange },
|
||||
GitRenamed = { fg = colors.purple },
|
||||
GitNew = { fg = colors.yellow }
|
||||
}
|
||||
end
|
||||
|
||||
local function get_links()
|
||||
return {
|
||||
FolderName = 'Directory',
|
||||
Normal = 'Normal',
|
||||
EndOfBuffer = 'EndOfBuffer',
|
||||
CursorLine = 'CursorLine',
|
||||
VertSplit = 'VertSplit',
|
||||
CursorColumn = 'CursorColumn',
|
||||
FileDirty = 'LuaTreeGitDirty',
|
||||
FileNew = 'LuaTreeGitNew',
|
||||
FileRenamed = 'LuaTreeGitRenamed',
|
||||
FileMerge = 'LuaTreeGitMerge',
|
||||
FileStaged = 'LuaTreeGitStaged',
|
||||
FileDeleted = 'LuaTreeGitDeleted',
|
||||
}
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
if config.get_icon_state().show_file_icon then
|
||||
require'nvim-web-devicons'.setup()
|
||||
end
|
||||
local higlight_groups = get_hl_groups()
|
||||
for k, d in pairs(higlight_groups) do
|
||||
local gui = d.gui or 'NONE'
|
||||
api.nvim_command('hi def LuaTree'..k..' gui='..gui..' guifg='..d.fg)
|
||||
end
|
||||
|
||||
local links = get_links()
|
||||
for k, d in pairs(links) do
|
||||
api.nvim_command('hi def link LuaTree'..k..' '..d)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,92 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
function M.get_icon_state()
|
||||
local show_icons = vim.g.lua_tree_show_icons or { git = 1, folders = 1, files = 1 }
|
||||
local icons = {
|
||||
default = "",
|
||||
symlink = "",
|
||||
git_icons = {
|
||||
unstaged = "✗",
|
||||
staged = "✓",
|
||||
unmerged = "",
|
||||
renamed = "➜",
|
||||
untracked = "★",
|
||||
deleted = ""
|
||||
},
|
||||
folder_icons = {
|
||||
default = "",
|
||||
open = ""
|
||||
}
|
||||
}
|
||||
|
||||
local user_icons = vim.g.lua_tree_icons
|
||||
if user_icons then
|
||||
if user_icons.default then
|
||||
icons.default = user_icons.default
|
||||
icons.symlink = user_icons.default
|
||||
end
|
||||
if user_icons.symlink then
|
||||
icons.symlink = user_icons.symlink
|
||||
end
|
||||
for key, val in pairs(user_icons.git or {}) do
|
||||
if icons.git_icons[key] then
|
||||
icons.git_icons[key] = val
|
||||
end
|
||||
end
|
||||
for key, val in pairs(user_icons.folder or {}) do
|
||||
if icons.folder_icons[key] then
|
||||
icons.folder_icons[key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
show_file_icon = show_icons.files == 1 and vim.g.nvim_web_devicons == 1,
|
||||
show_folder_icon = show_icons.folders == 1,
|
||||
show_git_icon = show_icons.git == 1,
|
||||
icons = icons
|
||||
}
|
||||
end
|
||||
|
||||
function M.get_bindings()
|
||||
local keybindings = vim.g.lua_tree_bindings or {}
|
||||
return {
|
||||
edit = keybindings.edit or {'<CR>', 'o'},
|
||||
edit_vsplit = keybindings.edit_vsplit or '<C-v>',
|
||||
edit_split = keybindings.edit_split or '<C-x>',
|
||||
edit_tab = keybindings.edit_tab or '<C-t>',
|
||||
preview = keybindings.preview or '<Tab>',
|
||||
toggle_ignored = keybindings.toggle_ignored or 'I',
|
||||
toggle_dotfiles = keybindings.toggle_dotfiles or 'H',
|
||||
refresh = keybindings.refresh or 'R',
|
||||
cd = keybindings.cd or '<C-]>',
|
||||
create = keybindings.create or 'a',
|
||||
remove = keybindings.remove or 'd',
|
||||
rename = keybindings.rename or 'r',
|
||||
cut = keybindings.cut or 'x',
|
||||
copy = keybindings.copy or 'c',
|
||||
paste = keybindings.paste or 'p',
|
||||
prev_git_item = keybindings.prev_git_item or '[c',
|
||||
next_git_item = keybindings.next_git_item or ']c',
|
||||
}
|
||||
end
|
||||
|
||||
function M.window_options()
|
||||
local opts = {}
|
||||
opts.winhl = 'EndOfBuffer:LuaTreeEndOfBuffer,Normal:LuaTreeNormal,CursorLine:LuaTreeCursorLine,VertSplit:LuaTreeVertSplit'
|
||||
if vim.g.lua_tree_side == 'right' then
|
||||
opts.side = 'L'
|
||||
opts.open_command = 'h'
|
||||
opts.preview_command = 'l'
|
||||
opts.split_command = 'nosplitright'
|
||||
else
|
||||
opts.side = 'H'
|
||||
opts.open_command = 'l'
|
||||
opts.preview_command = 'h'
|
||||
opts.split_command = 'splitright'
|
||||
end
|
||||
|
||||
return opts
|
||||
end
|
||||
|
||||
return M
|
||||
295
lua/lib/fs.lua
295
lua/lib/fs.lua
@ -1,295 +0,0 @@
|
||||
local api = vim.api
|
||||
local luv = vim.loop
|
||||
local open_mode = luv.constants.O_CREAT + luv.constants.O_WRONLY + luv.constants.O_TRUNC
|
||||
|
||||
local M = {}
|
||||
local clipboard = {
|
||||
move = {},
|
||||
copy = {}
|
||||
}
|
||||
|
||||
local function clear_prompt()
|
||||
vim.api.nvim_command('normal :esc<CR>')
|
||||
end
|
||||
|
||||
local function refresh_tree()
|
||||
vim.api.nvim_command(":LuaTreeRefresh")
|
||||
end
|
||||
|
||||
local function create_file(file)
|
||||
luv.fs_open(file, "w", open_mode, vim.schedule_wrap(function(err, fd)
|
||||
if err then
|
||||
api.nvim_err_writeln('Could not create file '..file)
|
||||
else
|
||||
-- FIXME: i don't know why but libuv keeps creating file with executable permissions
|
||||
-- this is why we need to chmod to default file permissions
|
||||
luv.fs_chmod(file, 420)
|
||||
luv.fs_close(fd)
|
||||
api.nvim_out_write('File '..file..' was properly created\n')
|
||||
refresh_tree()
|
||||
end
|
||||
end))
|
||||
end
|
||||
|
||||
local function get_num_entries(iter)
|
||||
local i = 0
|
||||
for _ in iter do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
function M.create(node)
|
||||
if node.name == '..' then return end
|
||||
|
||||
local add_into
|
||||
if node.entries ~= nil then
|
||||
add_into = node.absolute_path..'/'
|
||||
else
|
||||
add_into = node.absolute_path:sub(0, -(#node.name + 1))
|
||||
end
|
||||
|
||||
local ans = vim.fn.input('Create file '..add_into)
|
||||
clear_prompt()
|
||||
if not ans or #ans == 0 then return end
|
||||
|
||||
if not ans:match('/') then
|
||||
return create_file(add_into..ans)
|
||||
end
|
||||
|
||||
-- create a foler for each element until / and create a file when element is not ending with /
|
||||
-- if element is ending with / and it's the last element, we need to manually refresh
|
||||
local relpath = ''
|
||||
local idx = 0
|
||||
local num_entries = get_num_entries(ans:gmatch('[^/]+/?'))
|
||||
for path in ans:gmatch('[^/]+/?') do
|
||||
idx = idx + 1
|
||||
relpath = relpath..path
|
||||
if relpath:match('.*/$') then
|
||||
local success = luv.fs_mkdir(add_into..relpath, 493)
|
||||
if not success then
|
||||
api.nvim_err_writeln('Could not create folder '..add_into..relpath)
|
||||
return
|
||||
end
|
||||
if idx == num_entries then
|
||||
api.nvim_out_write('Folder '..add_into..relpath..' was properly created\n')
|
||||
refresh_tree()
|
||||
end
|
||||
else
|
||||
create_file(add_into..relpath)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clear_buffer(absolute_path)
|
||||
for _, buf in pairs(api.nvim_list_bufs()) do
|
||||
if api.nvim_buf_get_name(buf) == absolute_path then
|
||||
api.nvim_command(':bd! '..buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_dir(cwd)
|
||||
local handle = luv.fs_scandir(cwd)
|
||||
if type(handle) == 'string' then
|
||||
return api.nvim_err_writeln(handle)
|
||||
end
|
||||
|
||||
while true do
|
||||
local name, t = luv.fs_scandir_next(handle)
|
||||
if not name then break end
|
||||
|
||||
local new_cwd = cwd..'/'..name
|
||||
if t == 'directory' then
|
||||
local success = remove_dir(new_cwd)
|
||||
if not success then return false end
|
||||
else
|
||||
local success = luv.fs_unlink(new_cwd)
|
||||
if not success then return false end
|
||||
clear_buffer(new_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
return luv.fs_rmdir(cwd)
|
||||
end
|
||||
|
||||
local function do_copy(source, destination)
|
||||
local source_stats = luv.fs_stat(source)
|
||||
|
||||
if source_stats and source_stats.type == 'file' then
|
||||
return luv.fs_copyfile(source, destination)
|
||||
end
|
||||
|
||||
local handle = luv.fs_scandir(source)
|
||||
|
||||
if type(handle) == 'string' then
|
||||
return false, handle
|
||||
end
|
||||
|
||||
luv.fs_mkdir(destination, source_stats.mode)
|
||||
|
||||
while true do
|
||||
local name, _ = luv.fs_scandir_next(handle)
|
||||
if not name then break end
|
||||
|
||||
local new_name = source..'/'..name
|
||||
local new_destination = destination..'/'..name
|
||||
local success, msg = do_copy(new_name, new_destination)
|
||||
if not success then return success, msg end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function do_single_paste(source, dest, action_type, action_fn)
|
||||
local dest_stats = luv.fs_stat(dest)
|
||||
local should_process = true
|
||||
local should_rename = false
|
||||
if dest_stats then
|
||||
ans = vim.fn.input(dest..' already exists, overwrite ? y/n/r(ename): ')
|
||||
clear_prompt()
|
||||
should_process = ans:match('^y')
|
||||
should_rename = ans:match('^r')
|
||||
end
|
||||
|
||||
if should_rename then
|
||||
new_dest = vim.fn.input('New name: ', dest)
|
||||
return do_single_paste(source, new_dest, action_type, action_fn)
|
||||
end
|
||||
|
||||
if should_process then
|
||||
local success, errmsg = action_fn(source, dest)
|
||||
if not success then
|
||||
api.nvim_err_writeln('Could not '..action_type..' '..source..' - '..errmsg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function do_paste(node, action_type, action_fn)
|
||||
if node.name == '..' then return end
|
||||
local clip = clipboard[action_type]
|
||||
if #clip == 0 then return end
|
||||
|
||||
local destination = node.absolute_path
|
||||
local stats = luv.fs_stat(destination)
|
||||
local is_dir = stats and stats.type == 'directory'
|
||||
|
||||
if not is_dir then
|
||||
destination = vim.fn.fnamemodify(destination, ':p:h')
|
||||
elseif not node.open then
|
||||
destination = vim.fn.fnamemodify(destination, ':p:h:h')
|
||||
end
|
||||
|
||||
local msg = #clip..' entries'
|
||||
|
||||
if #clip == 1 then
|
||||
msg = clip[1].absolute_path
|
||||
end
|
||||
|
||||
local ans = vim.fn.input(action_type..' '..msg..' to '..destination..'? y/n: ')
|
||||
clear_prompt()
|
||||
if not ans:match('^y') then
|
||||
return api.nvim_out_write('Canceled.\n')
|
||||
end
|
||||
|
||||
for _, entry in ipairs(clip) do
|
||||
local dest = destination..'/'..entry.name
|
||||
do_single_paste(entry.absolute_path, dest, action_type, action_fn)
|
||||
end
|
||||
|
||||
clipboard[action_type] = {}
|
||||
return refresh_tree()
|
||||
end
|
||||
|
||||
local function add_to_clipboard(node, clip)
|
||||
if node.name == '..' then return end
|
||||
|
||||
for idx, entry in ipairs(clip) do
|
||||
if entry.absolute_path == node.absolute_path then
|
||||
table.remove(clip, idx)
|
||||
return api.nvim_out_write(node.absolute_path..' removed to clipboard.\n')
|
||||
end
|
||||
end
|
||||
table.insert(clip, node)
|
||||
api.nvim_out_write(node.absolute_path..' added to clipboard.\n')
|
||||
end
|
||||
|
||||
function M.remove(node)
|
||||
if node.name == '..' then return end
|
||||
|
||||
local ans = vim.fn.input("Remove " ..node.name.. " ? y/n: ")
|
||||
clear_prompt()
|
||||
if ans:match('^y') then
|
||||
if node.entries ~= nil then
|
||||
local success = remove_dir(node.absolute_path)
|
||||
if not success then
|
||||
return api.nvim_err_writeln('Could not remove '..node.name)
|
||||
end
|
||||
api.nvim_out_write(node.name..' has been removed\n')
|
||||
else
|
||||
local success = luv.fs_unlink(node.absolute_path)
|
||||
if not success then
|
||||
return api.nvim_err_writeln('Could not remove '..node.name)
|
||||
end
|
||||
api.nvim_out_write(node.name..' has been removed\n')
|
||||
clear_buffer(node.absolute_path)
|
||||
end
|
||||
refresh_tree()
|
||||
end
|
||||
end
|
||||
|
||||
function M.rename(node)
|
||||
if node.name == '..' then return end
|
||||
|
||||
local new_name = vim.fn.input("Rename " ..node.name.. " to ", node.absolute_path)
|
||||
clear_prompt()
|
||||
if not new_name or #new_name == 0 then return end
|
||||
|
||||
local success = luv.fs_rename(node.absolute_path, new_name) --, vim.schedule_wrap(rename_callback(node, ans)))
|
||||
if not success then
|
||||
return api.nvim_err_writeln('Could not rename '..node.absolute_path..' to '..new_name)
|
||||
end
|
||||
api.nvim_out_write(node.absolute_path..' ➜ '..new_name..'\n')
|
||||
for _, buf in pairs(api.nvim_list_bufs()) do
|
||||
if api.nvim_buf_get_name(buf) == node.absolute_path then
|
||||
api.nvim_buf_set_name(buf, new_name)
|
||||
end
|
||||
end
|
||||
refresh_tree()
|
||||
end
|
||||
|
||||
function M.copy(node)
|
||||
add_to_clipboard(node, clipboard.copy)
|
||||
end
|
||||
|
||||
function M.cut(node)
|
||||
add_to_clipboard(node, clipboard.move)
|
||||
end
|
||||
|
||||
function M.paste(node)
|
||||
if clipboard.move[1] ~= nil then
|
||||
return do_paste(node, 'move', luv.fs_rename)
|
||||
end
|
||||
|
||||
return do_paste(node, 'copy', do_copy)
|
||||
end
|
||||
|
||||
function M.print_clipboard()
|
||||
local content = {}
|
||||
if #clipboard.move > 0 then
|
||||
table.insert(content, 'Cut')
|
||||
for _, item in pairs(clipboard.move) do
|
||||
table.insert(content, ' * '..item.absolute_path)
|
||||
end
|
||||
end
|
||||
if #clipboard.copy > 0 then
|
||||
table.insert(content, 'Copy')
|
||||
for _, item in pairs(clipboard.copy) do
|
||||
table.insert(content, ' * '..item.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
return api.nvim_out_write(table.concat(content, '\n')..'\n')
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,92 +0,0 @@
|
||||
local utils = require'lib.utils'
|
||||
local M = {}
|
||||
|
||||
local roots = {}
|
||||
|
||||
local not_git = 'not a git repo'
|
||||
|
||||
local function update_root_status(root)
|
||||
local status = vim.fn.systemlist('cd "'..root..'" && git status --porcelain=v1 -u')
|
||||
roots[root] = {}
|
||||
|
||||
for _, v in pairs(status) do
|
||||
local head = v:sub(0, 2)
|
||||
local body = v:sub(4, -1)
|
||||
if body:match('%->') ~= nil then
|
||||
body = body:gsub('^.* %-> ', '')
|
||||
end
|
||||
roots[root][body] = head
|
||||
end
|
||||
end
|
||||
|
||||
function M.reload_roots()
|
||||
for root, status in pairs(roots) do
|
||||
if status ~= not_git then
|
||||
update_root_status(root)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_git_root(path)
|
||||
if roots[path] then
|
||||
return path, roots[path]
|
||||
end
|
||||
|
||||
for name, status in pairs(roots) do
|
||||
if status ~= not_git then
|
||||
if path:match(utils.path_to_matching_str(name)) then
|
||||
return name, status
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function create_root(cwd)
|
||||
local git_root = vim.fn.system('cd "'..cwd..'" && git rev-parse --show-toplevel')
|
||||
|
||||
if not git_root or #git_root == 0 or git_root:match('fatal') then
|
||||
roots[cwd] = not_git
|
||||
return false
|
||||
end
|
||||
|
||||
update_root_status(git_root:sub(0, -2))
|
||||
return true
|
||||
end
|
||||
|
||||
function M.update_status(entries, cwd)
|
||||
local git_root, git_status = get_git_root(cwd)
|
||||
if not git_root then
|
||||
if not create_root(cwd) then
|
||||
return
|
||||
end
|
||||
git_root, git_status = get_git_root(cwd)
|
||||
elseif git_status == not_git then
|
||||
return
|
||||
end
|
||||
|
||||
local matching_cwd = utils.path_to_matching_str(git_root..'/')
|
||||
for _, node in pairs(entries) do
|
||||
local relpath = node.absolute_path:gsub(matching_cwd, '')
|
||||
if node.entries ~= nil then
|
||||
relpath = relpath..'/'
|
||||
node.git_status = nil
|
||||
end
|
||||
|
||||
local status = git_status[relpath]
|
||||
if status then
|
||||
node.git_status = status
|
||||
elseif node.entries ~= nil then
|
||||
local matcher = '^'..utils.path_to_matching_str(relpath)
|
||||
for key, entry_status in pairs(git_status) do
|
||||
if key:match(matcher) then
|
||||
node.git_status = entry_status
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
node.git_status = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
329
lua/lib/lib.lua
329
lua/lib/lib.lua
@ -1,329 +0,0 @@
|
||||
local api = vim.api
|
||||
local luv = vim.loop
|
||||
|
||||
local renderer = require'lib.renderer'
|
||||
local config = require'lib.config'
|
||||
local git = require'lib.git'
|
||||
local pops = require'lib.populate'
|
||||
local populate = pops.populate
|
||||
local refresh_entries = pops.refresh_entries
|
||||
|
||||
local window_opts = config.window_options()
|
||||
|
||||
local M = {}
|
||||
|
||||
M.Tree = {
|
||||
entries = {},
|
||||
buf_name = 'LuaTree',
|
||||
cwd = nil,
|
||||
win_width = vim.g.lua_tree_width or 30,
|
||||
win_width_allow_resize = vim.g.lua_tree_width_allow_resize,
|
||||
loaded = false,
|
||||
bufnr = nil,
|
||||
winnr = function()
|
||||
for _, i in ipairs(api.nvim_list_wins()) do
|
||||
if api.nvim_buf_get_name(api.nvim_win_get_buf(i)):match('.*/'..M.Tree.buf_name..'$') then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end,
|
||||
options = {
|
||||
'noswapfile',
|
||||
'norelativenumber',
|
||||
'nonumber',
|
||||
'nolist',
|
||||
'winfixwidth',
|
||||
'winfixheight',
|
||||
'nofoldenable',
|
||||
'nospell',
|
||||
'foldmethod=manual',
|
||||
'foldcolumn=0'
|
||||
}
|
||||
}
|
||||
|
||||
function M.init(with_open, with_render)
|
||||
M.Tree.cwd = luv.cwd()
|
||||
populate(M.Tree.entries, M.Tree.cwd, M.Tree)
|
||||
|
||||
local stat = luv.fs_stat(M.Tree.cwd)
|
||||
M.Tree.last_modified = stat.mtime.sec
|
||||
|
||||
if with_open then
|
||||
M.open()
|
||||
end
|
||||
|
||||
if with_render then
|
||||
renderer.draw(M.Tree, true)
|
||||
M.Tree.loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
local function get_node_at_line(line)
|
||||
local index = 2
|
||||
local function iter(entries)
|
||||
for _, node in ipairs(entries) do
|
||||
if index == line then
|
||||
return node
|
||||
end
|
||||
index = index + 1
|
||||
if node.open == true then
|
||||
local child = iter(node.entries)
|
||||
if child ~= nil then return child end
|
||||
end
|
||||
end
|
||||
end
|
||||
return iter
|
||||
end
|
||||
|
||||
function M.get_node_at_cursor()
|
||||
local cursor = api.nvim_win_get_cursor(M.Tree.winnr())
|
||||
local line = cursor[1]
|
||||
if line == 1 and M.Tree.cwd ~= "/" then
|
||||
return { name = ".." }
|
||||
end
|
||||
|
||||
if M.Tree.cwd == "/" then
|
||||
line = line + 1
|
||||
end
|
||||
return get_node_at_line(line)(M.Tree.entries)
|
||||
end
|
||||
|
||||
function M.unroll_dir(node)
|
||||
node.open = not node.open
|
||||
if #node.entries > 0 then
|
||||
renderer.draw(M.Tree, true)
|
||||
else
|
||||
populate(node.entries, node.absolute_path)
|
||||
renderer.draw(M.Tree, true)
|
||||
end
|
||||
end
|
||||
|
||||
local function refresh_git(node)
|
||||
git.update_status(node.entries, node.absolute_path or node.cwd)
|
||||
for _, entry in pairs(node.entries) do
|
||||
if entry.entries ~= nil then
|
||||
refresh_git(entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO update only entries where directory has changed
|
||||
local function refresh_nodes(node)
|
||||
refresh_entries(node.entries, node.absolute_path or node.cwd)
|
||||
for _, entry in ipairs(node.entries) do
|
||||
if entry.entries and entry.open then
|
||||
refresh_nodes(entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.refresh_tree()
|
||||
-- local stat = luv.fs_stat(M.Tree.cwd)
|
||||
-- if stat.mtime.sec ~= M.Tree.last_modified then
|
||||
refresh_nodes(M.Tree)
|
||||
-- end
|
||||
if config.get_icon_state().show_git_icon or vim.g.lua_tree_git_hl then
|
||||
git.reload_roots()
|
||||
refresh_git(M.Tree)
|
||||
end
|
||||
if M.win_open() then
|
||||
renderer.draw(M.Tree, true)
|
||||
else
|
||||
M.Tree.loaded = false
|
||||
end
|
||||
end
|
||||
|
||||
function M.set_index_and_redraw(fname)
|
||||
local i
|
||||
if M.Tree.cwd == '/' then
|
||||
i = 0
|
||||
else
|
||||
i = 1
|
||||
end
|
||||
local reload = false
|
||||
|
||||
local function iter(entries)
|
||||
for _, entry in ipairs(entries) do
|
||||
i = i + 1
|
||||
if entry.absolute_path == fname then
|
||||
return i
|
||||
end
|
||||
|
||||
if fname:match(entry.match_path..'/') ~= nil then
|
||||
if #entry.entries == 0 then
|
||||
reload = true
|
||||
populate(entry.entries, entry.absolute_path)
|
||||
end
|
||||
if entry.open == false then
|
||||
reload = true
|
||||
entry.open = true
|
||||
end
|
||||
if iter(entry.entries) ~= nil then
|
||||
return i
|
||||
end
|
||||
elseif entry.open == true then
|
||||
iter(entry.entries)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local index = iter(M.Tree.entries)
|
||||
if not M.win_open() then
|
||||
M.Tree.loaded = false
|
||||
return
|
||||
end
|
||||
renderer.draw(M.Tree, reload)
|
||||
if index then
|
||||
api.nvim_win_set_cursor(M.Tree.winnr(), {index, 0})
|
||||
end
|
||||
end
|
||||
|
||||
local function check_and_open_split()
|
||||
if #api.nvim_list_wins() == 1 then
|
||||
api.nvim_command("vnew")
|
||||
end
|
||||
end
|
||||
|
||||
function M.open_file(mode, filename)
|
||||
api.nvim_command('noautocmd wincmd '..window_opts.open_command)
|
||||
if mode == 'preview' then
|
||||
check_and_open_split()
|
||||
api.nvim_command(string.format("edit %s", filename))
|
||||
api.nvim_command('noautocmd wincmd '..window_opts.preview_command)
|
||||
else
|
||||
if mode == 'edit' then
|
||||
check_and_open_split()
|
||||
end
|
||||
api.nvim_command(string.format("%s %s", mode, filename))
|
||||
end
|
||||
if not M.Tree.win_width_allow_resize then
|
||||
local cur_win = api.nvim_get_current_win()
|
||||
M.win_focus()
|
||||
api.nvim_command('vertical resize '..M.Tree.win_width)
|
||||
M.win_focus(cur_win)
|
||||
end
|
||||
if vim.g.lua_tree_quit_on_open then
|
||||
M.close()
|
||||
end
|
||||
end
|
||||
|
||||
function M.change_dir(foldername)
|
||||
api.nvim_command('cd '..foldername)
|
||||
M.Tree.entries = {}
|
||||
M.init(false, M.Tree.bufnr ~= nil)
|
||||
end
|
||||
|
||||
local function set_mapping(buf, key, fn)
|
||||
api.nvim_buf_set_keymap(buf, 'n', key, ':lua require"tree".'..fn..'<cr>', {
|
||||
nowait = true, noremap = true, silent = true
|
||||
})
|
||||
end
|
||||
|
||||
local function set_mappings()
|
||||
if vim.g.lua_tree_disable_keybindings == 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local buf = M.Tree.bufnr
|
||||
local bindings = config.get_bindings()
|
||||
|
||||
local mappings = {
|
||||
['<2-LeftMouse>'] = 'on_keypress("edit")';
|
||||
['<2-RightMouse>'] = 'on_keypress("cd")';
|
||||
[bindings.cd] = 'on_keypress("cd")';
|
||||
[bindings.edit] = 'on_keypress("edit")';
|
||||
[bindings.edit_vsplit] = 'on_keypress("vsplit")';
|
||||
[bindings.edit_split] = 'on_keypress("split")';
|
||||
[bindings.edit_tab] = 'on_keypress("tabnew")';
|
||||
[bindings.toggle_ignored] = 'on_keypress("toggle_ignored")';
|
||||
[bindings.toggle_dotfiles] = 'on_keypress("toggle_dotfiles")';
|
||||
[bindings.refresh] = 'on_keypress("refresh")';
|
||||
[bindings.create] = 'on_keypress("create")';
|
||||
[bindings.remove] = 'on_keypress("remove")';
|
||||
[bindings.rename] = 'on_keypress("rename")';
|
||||
[bindings.preview] = 'on_keypress("preview")';
|
||||
[bindings.cut] = 'on_keypress("cut")';
|
||||
[bindings.copy] = 'on_keypress("copy")';
|
||||
[bindings.paste] = 'on_keypress("paste")';
|
||||
[bindings.prev_git_item] = 'on_keypress("prev_git_item")';
|
||||
[bindings.next_git_item] = 'on_keypress("next_git_item")';
|
||||
gx = "xdg_open()";
|
||||
}
|
||||
|
||||
for k,v in pairs(mappings) do
|
||||
if type(k) == 'table' then
|
||||
for _, key in pairs(k) do
|
||||
set_mapping(buf, key, v)
|
||||
end
|
||||
else
|
||||
set_mapping(buf, k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function create_buf()
|
||||
local options = {
|
||||
bufhidden = 'wipe';
|
||||
buftype = 'nofile';
|
||||
modifiable = false;
|
||||
}
|
||||
|
||||
M.Tree.bufnr = api.nvim_create_buf(false, true)
|
||||
api.nvim_buf_set_name(M.Tree.bufnr, M.Tree.buf_name)
|
||||
|
||||
for opt, val in pairs(options) do
|
||||
api.nvim_buf_set_option(M.Tree.bufnr, opt, val)
|
||||
end
|
||||
set_mappings()
|
||||
end
|
||||
|
||||
local function create_win()
|
||||
api.nvim_command("vsplit")
|
||||
api.nvim_command("wincmd "..window_opts.side)
|
||||
api.nvim_command("vertical resize "..M.Tree.win_width)
|
||||
end
|
||||
|
||||
function M.close()
|
||||
if #api.nvim_list_wins() == 1 then
|
||||
return vim.cmd ':q!'
|
||||
end
|
||||
api.nvim_win_close(M.Tree.winnr(), true)
|
||||
M.Tree.bufnr = nil
|
||||
end
|
||||
|
||||
function M.open()
|
||||
create_buf()
|
||||
create_win()
|
||||
api.nvim_win_set_buf(M.Tree.winnr(), M.Tree.bufnr)
|
||||
|
||||
for _, opt in pairs(M.Tree.options) do
|
||||
api.nvim_command('setlocal '..opt)
|
||||
end
|
||||
|
||||
renderer.draw(M.Tree, not M.Tree.loaded)
|
||||
M.Tree.loaded = true
|
||||
|
||||
api.nvim_buf_set_option(M.Tree.bufnr, 'filetype', M.Tree.buf_name)
|
||||
api.nvim_command('setlocal '..window_opts.split_command)
|
||||
end
|
||||
|
||||
function M.win_open()
|
||||
return M.Tree.winnr() ~= nil
|
||||
end
|
||||
|
||||
function M.win_focus(winnr)
|
||||
local wnr = winnr or M.Tree.winnr()
|
||||
api.nvim_set_current_win(wnr)
|
||||
end
|
||||
|
||||
function M.toggle_ignored()
|
||||
pops.show_ignored = not pops.show_ignored
|
||||
return M.refresh_tree()
|
||||
end
|
||||
|
||||
function M.toggle_dotfiles()
|
||||
pops.show_dotfiles = not pops.show_dotfiles
|
||||
return M.refresh_tree()
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,209 +0,0 @@
|
||||
local config = require'lib.config'
|
||||
local git = require'lib.git'
|
||||
local icon_config = config.get_icon_state()
|
||||
|
||||
local api = vim.api
|
||||
local luv = vim.loop
|
||||
|
||||
local M = {
|
||||
show_ignored = false,
|
||||
show_dotfiles = vim.g.lua_tree_hide_dotfiles ~= 1,
|
||||
}
|
||||
|
||||
local path_to_matching_str = require'lib.utils'.path_to_matching_str
|
||||
|
||||
local function dir_new(cwd, name)
|
||||
local absolute_path = cwd..'/'..name
|
||||
local stat = luv.fs_stat(absolute_path)
|
||||
return {
|
||||
name = name,
|
||||
absolute_path = absolute_path,
|
||||
-- TODO: last modified could also involve atime and ctime
|
||||
last_modified = stat.mtime.sec,
|
||||
match_name = path_to_matching_str(name),
|
||||
match_path = path_to_matching_str(absolute_path),
|
||||
open = false,
|
||||
entries = {}
|
||||
}
|
||||
end
|
||||
|
||||
local function file_new(cwd, name)
|
||||
local absolute_path = cwd..'/'..name
|
||||
local is_exec = luv.fs_access(absolute_path, 'X')
|
||||
return {
|
||||
name = name,
|
||||
absolute_path = absolute_path,
|
||||
executable = is_exec,
|
||||
extension = vim.fn.fnamemodify(name, ':e') or "",
|
||||
match_name = path_to_matching_str(name),
|
||||
match_path = path_to_matching_str(absolute_path),
|
||||
}
|
||||
end
|
||||
|
||||
-- TODO-INFO: sometimes fs_realpath returns nil
|
||||
-- I expect this be a bug in glibc, because it fails to retrieve the path for some
|
||||
-- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails
|
||||
-- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong.
|
||||
-- So we need to check for link_to ~= nil when adding new links to the main tree
|
||||
local function link_new(cwd, name)
|
||||
local absolute_path = cwd..'/'..name
|
||||
local link_to = luv.fs_realpath(absolute_path)
|
||||
return {
|
||||
name = name,
|
||||
absolute_path = absolute_path,
|
||||
link_to = link_to,
|
||||
match_name = path_to_matching_str(name),
|
||||
match_path = path_to_matching_str(absolute_path),
|
||||
}
|
||||
end
|
||||
|
||||
local function gen_ignore_check()
|
||||
local ignore_list = {}
|
||||
if vim.g.lua_tree_ignore and #vim.g.lua_tree_ignore > 0 then
|
||||
for _, entry in pairs(vim.g.lua_tree_ignore) do
|
||||
ignore_list[entry] = true
|
||||
end
|
||||
end
|
||||
|
||||
return function(path)
|
||||
local ignore_path = not M.show_ignored and ignore_list[path] == true
|
||||
local ignore_dotfiles = not M.show_dotfiles and path:sub(1, 1) == '.'
|
||||
return ignore_path or ignore_dotfiles
|
||||
end
|
||||
end
|
||||
|
||||
local should_ignore = gen_ignore_check()
|
||||
|
||||
function M.refresh_entries(entries, cwd)
|
||||
local handle = luv.fs_scandir(cwd)
|
||||
if type(handle) == 'string' then
|
||||
api.nvim_err_writeln(handle)
|
||||
return
|
||||
end
|
||||
|
||||
local named_entries = {}
|
||||
local cached_entries = {}
|
||||
local entries_idx = {}
|
||||
for i, node in ipairs(entries) do
|
||||
cached_entries[i] = node.name
|
||||
entries_idx[node.name] = i
|
||||
named_entries[node.name] = node
|
||||
end
|
||||
|
||||
local dirs = {}
|
||||
local links = {}
|
||||
local files = {}
|
||||
local new_entries = {}
|
||||
|
||||
while true do
|
||||
local name, t = luv.fs_scandir_next(handle)
|
||||
if not name then break end
|
||||
|
||||
if not should_ignore(name) then
|
||||
if t == 'directory' then
|
||||
table.insert(dirs, name)
|
||||
new_entries[name] = true
|
||||
elseif t == 'file' then
|
||||
table.insert(files, name)
|
||||
new_entries[name] = true
|
||||
elseif t == 'link' then
|
||||
table.insert(links, name)
|
||||
new_entries[name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local idx = 1
|
||||
for _, name in ipairs(cached_entries) do
|
||||
if not new_entries[name] then
|
||||
table.remove(entries, idx, idx + 1)
|
||||
else
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
|
||||
local all = {
|
||||
{ entries = dirs, fn = dir_new, check = function(_, abs) return luv.fs_access(abs, 'R') end },
|
||||
{ entries = links, fn = link_new, check = function(name) return name ~= nil end },
|
||||
{ entries = files, fn = file_new, check = function() return true end }
|
||||
}
|
||||
|
||||
local prev = nil
|
||||
local change_prev
|
||||
for _, e in ipairs(all) do
|
||||
for _, name in ipairs(e.entries) do
|
||||
change_prev = true
|
||||
if not named_entries[name] then
|
||||
local n = e.fn(cwd, name)
|
||||
if e.check(n.link_to, n.absolute_path) then
|
||||
idx = 1
|
||||
if prev then
|
||||
idx = entries_idx[prev] + 1
|
||||
end
|
||||
table.insert(entries, idx, n)
|
||||
entries_idx[name] = idx
|
||||
cached_entries[idx] = name
|
||||
else
|
||||
change_prev = false
|
||||
end
|
||||
end
|
||||
if change_prev then prev = name end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.populate(entries, cwd)
|
||||
local handle = luv.fs_scandir(cwd)
|
||||
if type(handle) == 'string' then
|
||||
api.nvim_err_writeln(handle)
|
||||
return
|
||||
end
|
||||
|
||||
local dirs = {}
|
||||
local links = {}
|
||||
local files = {}
|
||||
|
||||
while true do
|
||||
local name, t = luv.fs_scandir_next(handle)
|
||||
if not name then break end
|
||||
|
||||
if not should_ignore(name) then
|
||||
if t == 'directory' then
|
||||
table.insert(dirs, name)
|
||||
elseif t == 'file' then
|
||||
table.insert(files, name)
|
||||
elseif t == 'link' then
|
||||
table.insert(links, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Create Nodes --
|
||||
|
||||
for _, dirname in ipairs(dirs) do
|
||||
local dir = dir_new(cwd, dirname)
|
||||
if luv.fs_access(dir.absolute_path, 'R') then
|
||||
table.insert(entries, dir)
|
||||
end
|
||||
end
|
||||
|
||||
for _, linkname in ipairs(links) do
|
||||
local link = link_new(cwd, linkname)
|
||||
if link.link_to ~= nil then
|
||||
table.insert(entries, link)
|
||||
end
|
||||
end
|
||||
|
||||
for _, filename in ipairs(files) do
|
||||
local file = file_new(cwd, filename)
|
||||
table.insert(entries, file)
|
||||
end
|
||||
|
||||
if (not icon_config.show_git_icon) and vim.g.lua_tree_git_hl ~= 1 then
|
||||
return
|
||||
end
|
||||
|
||||
git.update_status(entries, cwd)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,297 +0,0 @@
|
||||
local colors = require'lib.colors'
|
||||
local config = require'lib.config'
|
||||
local utils = require'lib.utils'
|
||||
|
||||
local api = vim.api
|
||||
|
||||
local lines = {}
|
||||
local hl = {}
|
||||
local index = 0
|
||||
local namespace_id = api.nvim_create_namespace('LuaTreeHighlights')
|
||||
|
||||
local icon_state = config.get_icon_state()
|
||||
|
||||
local get_folder_icon = function() return "" end
|
||||
local set_folder_hl = function(line, depth, git_icon_len, _, hl_group)
|
||||
table.insert(hl, {hl_group, line, depth+git_icon_len, -1})
|
||||
end
|
||||
|
||||
if icon_state.show_folder_icon then
|
||||
get_folder_icon = function(open)
|
||||
if open then
|
||||
return icon_state.icons.folder_icons.open .. " "
|
||||
else
|
||||
return icon_state.icons.folder_icons.default .. " "
|
||||
end
|
||||
end
|
||||
set_folder_hl = function(line, depth, icon_len, name_len, hl_group)
|
||||
table.insert(hl, {hl_group, line, depth+icon_len, depth+icon_len+name_len})
|
||||
table.insert(hl, {'LuaTreeFolderIcon', line, depth, depth+icon_len})
|
||||
end
|
||||
end
|
||||
|
||||
local get_file_icon = function() return icon_state.icons.default end
|
||||
if icon_state.show_file_icon then
|
||||
local web_devicons = require'nvim-web-devicons'
|
||||
|
||||
get_file_icon = function(fname, extension, line, depth)
|
||||
local icon, hl_group = web_devicons.get_icon(fname, extension)
|
||||
|
||||
if icon then
|
||||
if hl_group then
|
||||
table.insert(hl, { hl_group, line, depth, depth + #icon })
|
||||
end
|
||||
return icon.." "
|
||||
else
|
||||
return #icon_state.icons.default > 0 and icon_state.icons.default.." " or ""
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local get_symlink_icon = function() return icon_state.icons.symlink end
|
||||
if icon_state.show_file_icon then
|
||||
get_symlink_icon = function()
|
||||
return #icon_state.icons.symlink > 0 and icon_state.icons.symlink.." " or ""
|
||||
end
|
||||
end
|
||||
|
||||
local get_special_icon = function() return icon_state.icons.default end
|
||||
if icon_state.show_file_icon then
|
||||
get_special_icon = function()
|
||||
return #icon_state.icons.default > 0 and icon_state.icons.default.." " or ""
|
||||
end
|
||||
end
|
||||
|
||||
local get_git_icons = function() return "" end
|
||||
local get_git_hl = function() return end
|
||||
|
||||
if vim.g.lua_tree_git_hl == 1 then
|
||||
local git_hl = {
|
||||
["M "] = { { hl = "LuaTreeFileStaged" } },
|
||||
[" M"] = { { hl = "LuaTreeFileDirty" } },
|
||||
["MM"] = {
|
||||
{ hl = "LuaTreeFileStaged" },
|
||||
{ hl = "LuaTreeFileDirty" }
|
||||
},
|
||||
["A "] = {
|
||||
{ hl = "LuaTreeFileStaged" },
|
||||
{ hl = "LuaTreeFileNew" }
|
||||
},
|
||||
["AD"] = {
|
||||
{ hl = "LuaTreeFileStaged" },
|
||||
{ hl = "LuaTreeFileDeleted" }
|
||||
},
|
||||
["AM"] = {
|
||||
{ hl = "LuaTreeFileStaged" },
|
||||
{ hl = "LuaTreeFileNew" },
|
||||
{ hl = "LuaTreeFileDirty" }
|
||||
},
|
||||
["??"] = { { hl = "LuaTreeFileNew" } },
|
||||
["R "] = { { hl = "LuaTreeFileRenamed" } },
|
||||
["UU"] = { { hl = "LuaTreeFileMerge" } },
|
||||
[" D"] = { { hl = "LuaTreeFileDeleted" } },
|
||||
["D "] = {
|
||||
{ hl = "LuaTreeFileDeleted" },
|
||||
{ hl = "LuaTreeFileStaged" }
|
||||
},
|
||||
dirty = { { hl = "LuaTreeFileDirty" } },
|
||||
}
|
||||
get_git_hl = function(node)
|
||||
local git_status = node.git_status
|
||||
if not git_status then return end
|
||||
|
||||
local icons = git_hl[git_status]
|
||||
|
||||
if icons == nil then
|
||||
utils.echo_warning('Unrecognized git state "'..git_status..'". Please open up an issue on https://github.com/kyazdani42/nvim-tree.lua/issues with this message.')
|
||||
icons = git_hl.dirty
|
||||
end
|
||||
|
||||
-- TODO: how would we determine hl color when multiple git status are active ?
|
||||
return icons[1].hl
|
||||
-- return icons[#icons].hl
|
||||
end
|
||||
end
|
||||
|
||||
if icon_state.show_git_icon then
|
||||
local git_icon_state = {
|
||||
["M "] = { { icon = icon_state.icons.git_icons.staged, hl = "LuaTreeGitStaged" } },
|
||||
[" M"] = { { icon = icon_state.icons.git_icons.unstaged, hl = "LuaTreeGitDirty" } },
|
||||
["MM"] = {
|
||||
{ icon = icon_state.icons.git_icons.staged, hl = "LuaTreeGitStaged" },
|
||||
{ icon = icon_state.icons.git_icons.unstaged, hl = "LuaTreeGitDirty" }
|
||||
},
|
||||
["A "] = {
|
||||
{ icon = icon_state.icons.git_icons.staged, hl = "LuaTreeGitStaged" },
|
||||
{ icon = icon_state.icons.git_icons.untracked, hl = "LuaTreeGitNew" }
|
||||
},
|
||||
["AM"] = {
|
||||
{ icon = icon_state.icons.git_icons.staged, hl = "LuaTreeGitStaged" },
|
||||
{ icon = icon_state.icons.git_icons.untracked, hl = "LuaTreeGitNew" },
|
||||
{ icon = icon_state.icons.git_icons.unstaged, hl = "LuaTreeGitDirty" }
|
||||
},
|
||||
["??"] = { { icon = icon_state.icons.git_icons.untracked, hl = "LuaTreeGitNew" } },
|
||||
["R "] = { { icon = icon_state.icons.git_icons.renamed, hl = "LuaTreeGitRenamed" } },
|
||||
["UU"] = { { icon = icon_state.icons.git_icons.unmerged, hl = "LuaTreeGitMerge" } },
|
||||
[" D"] = { { icon = icon_state.icons.git_icons.deleted, hl = "LuaTreeGitDeleted" } },
|
||||
dirty = { { icon = icon_state.icons.git_icons.unstaged, hl = "LuaTreeGitDirty" } },
|
||||
}
|
||||
|
||||
get_git_icons = function(node, line, depth, icon_len)
|
||||
local git_status = node.git_status
|
||||
if not git_status then return "" end
|
||||
|
||||
local icon = ""
|
||||
local icons = git_icon_state[git_status]
|
||||
if not icons then
|
||||
if vim.g.lua_tree_git_hl ~= 1 then
|
||||
utils.echo_warning('Unrecognized git state "'..git_status..'". Please open up an issue on https://github.com/kyazdani42/nvim-tree.lua/issues with this message.')
|
||||
end
|
||||
icons = git_icon_state.dirty
|
||||
end
|
||||
for _, v in ipairs(icons) do
|
||||
table.insert(hl, { v.hl, line, depth+icon_len+#icon, depth+icon_len+#icon+#v.icon })
|
||||
icon = icon..v.icon.." "
|
||||
end
|
||||
|
||||
return icon
|
||||
end
|
||||
end
|
||||
|
||||
local get_padding = function(depth)
|
||||
return string.rep(' ', depth)
|
||||
end
|
||||
|
||||
if vim.g.lua_tree_indent_markers == 1 then
|
||||
get_padding = function(depth, idx, tree, _, markers)
|
||||
local padding = ""
|
||||
if depth ~= 0 then
|
||||
local rdepth = depth/2
|
||||
markers[rdepth] = idx ~= #tree.entries
|
||||
for i=1,rdepth do
|
||||
if idx == #tree.entries and i == rdepth then
|
||||
padding = padding..'└ '
|
||||
elseif markers[i] then
|
||||
padding = padding..'│ '
|
||||
else
|
||||
padding = padding..' '
|
||||
end
|
||||
end
|
||||
end
|
||||
return padding
|
||||
end
|
||||
end
|
||||
|
||||
local picture = {
|
||||
jpg = true,
|
||||
jpeg = true,
|
||||
png = true,
|
||||
gif = true,
|
||||
}
|
||||
|
||||
local special = {
|
||||
["Cargo.toml"] = true,
|
||||
Makefile = true,
|
||||
["README.md"] = true,
|
||||
["readme.md"] = true,
|
||||
}
|
||||
|
||||
local root_folder_modifier = vim.g.lua_tree_root_folder_modifier or ':~'
|
||||
|
||||
local function update_draw_data(tree, depth, markers)
|
||||
if tree.cwd and tree.cwd ~= '/' then
|
||||
local root_name = vim.fn.fnamemodify(tree.cwd, root_folder_modifier):gsub('/$', '').."/.."
|
||||
table.insert(lines, root_name)
|
||||
table.insert(hl, {'LuaTreeRootFolder', index, 0, string.len(root_name)})
|
||||
index = 1
|
||||
end
|
||||
|
||||
for idx, node in ipairs(tree.entries) do
|
||||
local padding = get_padding(depth, idx, tree, node, markers)
|
||||
local offset = string.len(padding)
|
||||
if depth > 0 then
|
||||
table.insert(hl, { 'LuaTreeIndentMarker', index, 0, offset })
|
||||
end
|
||||
|
||||
local git_hl = get_git_hl(node)
|
||||
|
||||
if node.entries then
|
||||
local icon = get_folder_icon(node.open)
|
||||
local git_icon = get_git_icons(node, index, offset, #icon+1) or ""
|
||||
-- INFO: this is mandatory in order to keep gui attributes (bold/italics)
|
||||
set_folder_hl(index, offset, #icon, #node.name+#git_icon, 'LuaTreeFolderName')
|
||||
if git_hl then
|
||||
set_folder_hl(index, offset, #icon, #node.name+#git_icon, git_hl)
|
||||
end
|
||||
index = index + 1
|
||||
if node.open then
|
||||
table.insert(lines, padding..icon..git_icon..node.name)
|
||||
update_draw_data(node, depth + 2, markers)
|
||||
else
|
||||
table.insert(lines, padding..icon..git_icon..node.name)
|
||||
end
|
||||
elseif node.link_to then
|
||||
local icon = get_symlink_icon()
|
||||
local link_hl = git_hl or 'LuaTreeSymlink'
|
||||
table.insert(hl, { link_hl, index, offset, -1 })
|
||||
table.insert(lines, padding..icon..node.name.." ➛ "..node.link_to)
|
||||
index = index + 1
|
||||
|
||||
else
|
||||
local icon
|
||||
local git_icons
|
||||
if special[node.name] then
|
||||
icon = get_special_icon()
|
||||
git_icons = get_git_icons(node, index, offset, 0)
|
||||
table.insert(hl, {'LuaTreeSpecialFile', index, offset+#git_icons, -1})
|
||||
else
|
||||
icon = get_file_icon(node.name, node.extension, index, offset)
|
||||
git_icons = get_git_icons(node, index, offset, #icon)
|
||||
end
|
||||
table.insert(lines, padding..icon..git_icons..node.name)
|
||||
|
||||
if node.executable then
|
||||
table.insert(hl, {'LuaTreeExecFile', index, offset+#icon+#git_icons, -1 })
|
||||
elseif picture[node.extension] then
|
||||
table.insert(hl, {'LuaTreeImageFile', index, offset+#icon+#git_icons, -1 })
|
||||
end
|
||||
|
||||
if git_hl then
|
||||
table.insert(hl, {git_hl, index, offset+#icon+#git_icons, -1 })
|
||||
end
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.draw(tree, reload)
|
||||
if not tree.bufnr then return end
|
||||
api.nvim_buf_set_option(tree.bufnr, 'modifiable', true)
|
||||
local cursor = api.nvim_win_get_cursor(tree.winnr)
|
||||
if reload then
|
||||
index = 0
|
||||
lines = {}
|
||||
hl = {}
|
||||
update_draw_data(tree, 0, {})
|
||||
end
|
||||
|
||||
api.nvim_buf_set_lines(tree.bufnr, 0, -1, false, lines)
|
||||
M.render_hl(tree.bufnr)
|
||||
if #lines >= cursor[1] then
|
||||
api.nvim_win_set_cursor(tree.winnr, cursor)
|
||||
end
|
||||
api.nvim_buf_set_option(tree.bufnr, 'modifiable', false)
|
||||
end
|
||||
|
||||
function M.render_hl(bufnr)
|
||||
if not bufnr then return end
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace_id, 0, -1)
|
||||
for _, data in ipairs(hl) do
|
||||
api.nvim_buf_add_highlight(bufnr, namespace_id, data[1], data[2], data[3], data[4])
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,14 +0,0 @@
|
||||
local M = {}
|
||||
local api = vim.api
|
||||
|
||||
function M.path_to_matching_str(path)
|
||||
return path:gsub('(%-)', '(%%-)'):gsub('(%.)', '(%%.)'):gsub('(%_)', '(%%_)')
|
||||
end
|
||||
|
||||
function M.echo_warning(msg)
|
||||
api.nvim_command('echohl WarningMsg')
|
||||
api.nvim_command("echom '[LuaTree] "..msg:gsub("'", "''").."'")
|
||||
api.nvim_command('echohl None')
|
||||
end
|
||||
|
||||
return M
|
||||
201
lua/tree.lua
201
lua/tree.lua
@ -1,201 +0,0 @@
|
||||
local luv = vim.loop
|
||||
local lib = require'lib.lib'
|
||||
local config = require'lib.config'
|
||||
local colors = require'lib.colors'
|
||||
local renderer = require'lib.renderer'
|
||||
local fs = require'lib.fs'
|
||||
local utils = require'lib.utils'
|
||||
local api = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.toggle()
|
||||
if lib.win_open() then
|
||||
lib.close()
|
||||
else
|
||||
if vim.g.lua_tree_follow == 1 then
|
||||
M.find_file(true)
|
||||
else
|
||||
lib.open()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.close()
|
||||
if lib.win_open() then
|
||||
lib.close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function M.open()
|
||||
if not lib.win_open() then
|
||||
lib.open()
|
||||
end
|
||||
end
|
||||
|
||||
local winopts = config.window_options()
|
||||
function M.tab_change()
|
||||
-- we need defer_fn to make sure we close/open after we enter the tab
|
||||
vim.defer_fn(function()
|
||||
if M.close() then
|
||||
M.open()
|
||||
api.nvim_command('wincmd '..winopts.open_command)
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
|
||||
local function gen_go_to(mode)
|
||||
local icon_state = config.get_icon_state()
|
||||
local flags = mode == 'prev_git_item' and 'b' or ''
|
||||
local icons = table.concat(vim.tbl_values(icon_state.icons.git_icons), '\\|')
|
||||
return function()
|
||||
return icon_state.show_git_icon and vim.fn.search(icons, flags)
|
||||
end
|
||||
end
|
||||
|
||||
local keypress_funcs = {
|
||||
create = fs.create,
|
||||
remove = fs.remove,
|
||||
rename = fs.rename,
|
||||
copy = fs.copy,
|
||||
cut = fs.cut,
|
||||
paste = fs.paste,
|
||||
toggle_ignored = lib.toggle_ignored,
|
||||
toggle_dotfiles = lib.toggle_dotfiles,
|
||||
refresh = lib.refresh_tree,
|
||||
prev_git_item = gen_go_to('prev_git_item'),
|
||||
next_git_item = gen_go_to('next_git_item'),
|
||||
preview = function(node)
|
||||
if node.entries ~= nil or node.name == '..' then return end
|
||||
return lib.open_file('preview', node.absolute_path)
|
||||
end,
|
||||
}
|
||||
|
||||
function M.on_keypress(mode)
|
||||
local node = lib.get_node_at_cursor()
|
||||
if not node then return end
|
||||
|
||||
if keypress_funcs[mode] then
|
||||
return keypress_funcs[mode](node)
|
||||
end
|
||||
|
||||
if node.name == ".." then
|
||||
return lib.change_dir("..")
|
||||
elseif mode == "cd" and node.entries ~= nil then
|
||||
return lib.change_dir(node.absolute_path)
|
||||
elseif mode == "cd" then
|
||||
return
|
||||
end
|
||||
|
||||
if node.link_to then
|
||||
local stat = luv.fs_stat(node.link_to)
|
||||
-- TODO: potentially CD here
|
||||
if stat.type == 'directory' then return end
|
||||
lib.open_file(mode, node.link_to)
|
||||
elseif node.entries ~= nil then
|
||||
lib.unroll_dir(node)
|
||||
else
|
||||
lib.open_file(mode, node.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
function M.refresh()
|
||||
lib.refresh_tree()
|
||||
end
|
||||
|
||||
function M.print_clipboard()
|
||||
fs.print_clipboard()
|
||||
end
|
||||
|
||||
function M.on_enter()
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
|
||||
local stats = luv.fs_stat(bufname)
|
||||
local is_dir = stats and stats.type == 'directory'
|
||||
if is_dir then
|
||||
api.nvim_command('cd '..bufname)
|
||||
end
|
||||
local should_open = vim.g.lua_tree_auto_open == 1 and (bufname == '' or is_dir)
|
||||
colors.setup()
|
||||
lib.init(should_open, should_open)
|
||||
end
|
||||
|
||||
local function is_file_readable(fname)
|
||||
local stat = luv.fs_stat(fname)
|
||||
if not stat or not stat.type == 'file' or not luv.fs_access(fname, 'R') then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
function M.find_file(with_open)
|
||||
local bufname = vim.fn.bufname()
|
||||
local filepath = vim.fn.fnamemodify(bufname, ':p')
|
||||
|
||||
if with_open then
|
||||
M.open()
|
||||
lib.win_focus()
|
||||
end
|
||||
|
||||
if not is_file_readable(filepath) then return end
|
||||
lib.set_index_and_redraw(filepath)
|
||||
end
|
||||
|
||||
function M.on_leave()
|
||||
vim.defer_fn(function()
|
||||
if #api.nvim_list_wins() == 1 and lib.win_open() then
|
||||
api.nvim_command(':qa!')
|
||||
end
|
||||
end, 50)
|
||||
end
|
||||
|
||||
local function update_root_dir()
|
||||
local bufname = api.nvim_buf_get_name(api.nvim_get_current_buf())
|
||||
if not is_file_readable(bufname) or not lib.Tree.cwd then return end
|
||||
|
||||
-- this logic is a hack
|
||||
-- depending on vim-rooter or autochdir, it would not behave the same way when those two are not enabled
|
||||
-- until i implement multiple workspaces/project, it should stay like this
|
||||
if bufname:match(utils.path_to_matching_str(lib.Tree.cwd)) then
|
||||
return
|
||||
end
|
||||
local new_cwd = luv.cwd()
|
||||
if lib.Tree.cwd == new_cwd then return end
|
||||
|
||||
lib.change_dir(new_cwd)
|
||||
end
|
||||
|
||||
function M.buf_enter()
|
||||
update_root_dir()
|
||||
if vim.g.lua_tree_follow == 1 then
|
||||
M.find_file(false)
|
||||
end
|
||||
end
|
||||
|
||||
function M.reset_highlight()
|
||||
colors.setup()
|
||||
renderer.render_hl(lib.Tree.bufnr)
|
||||
end
|
||||
|
||||
function M.xdg_open()
|
||||
local node = lib.get_node_at_cursor()
|
||||
-- TODO: this should open symlink targets
|
||||
if not node or node.entries or node.link_to then return end
|
||||
|
||||
local cmd
|
||||
if vim.fn.has('unix') == 1 then
|
||||
cmd = 'xdg-open'
|
||||
else
|
||||
cmd = 'open'
|
||||
end
|
||||
|
||||
vim.loop.spawn(cmd, {args={node.absolute_path}}, vim.schedule_wrap(function(code)
|
||||
if code ~= 0 then
|
||||
api.nvim_err_writeln("Could not open "..node.absolute_path)
|
||||
end
|
||||
end))
|
||||
end
|
||||
|
||||
M.on_enter()
|
||||
|
||||
return M
|
||||
Loading…
Reference in New Issue
Block a user