From 0bb2a99f557b89bf6f3791bb36c3466e73b8c11f Mon Sep 17 00:00:00 2001 From: kiyan42 Date: Mon, 10 Feb 2020 14:22:51 +0100 Subject: [PATCH] FS api - change vim root and update tree - create / rename / delete file and folders --- README.md | 14 ++++++--- lua/lib/file.lua | 49 ++++++++++++++++++++---------- lua/lib/format.lua | 5 ++- lua/tree.lua | 76 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 109 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 4ee51ee8..592b768e 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,17 @@ - [x] moving around the file structure like any basic tree - [x] open file in current buffer or in split with FzF like bindings (CR, C-v, C-x) - [x] icons for files -- [ ] add / delete file in directory + +- [x] change directory base +- [x] add / rename / delete file in directory +- [ ] update tree when altering the FS + - [ ] syntax highlighting - [ ] simple git integration (color of file changing when staged/changed) + - [ ] quickly find file in the directory structure - [ ] update tree automatically on window change -## TOFIX - -- [ ] handle permissions properly -- [ ] buffer / window should always stay on the left and never disappear (open a file with only the tree open to reproduce this bug) +- [ ] handle permissions properly (TODO: display error on Read access denied) +- [ ] buffer / window should always stay on the left and never change size (open a file with only the tree open to reproduce this bug) +- [ ] buffer / window should not disappear when only the tree is opened diff --git a/lua/lib/file.lua b/lua/lib/file.lua index 55781149..8f4b96b5 100644 --- a/lua/lib/file.lua +++ b/lua/lib/file.lua @@ -1,5 +1,8 @@ local api = vim.api local buf, win +local system = function(v) api.nvim_call_function('system', { v }) end + +local EDIT_FILE = nil local function scratch_buffer() buf = api.nvim_create_buf(false, true) @@ -49,7 +52,7 @@ local function scratch_buffer() api.nvim_command('au BufWipeout exe "silent bwipeout! "'..border_buf) end -local function set_mappings(path) +local function set_mappings(edit_type) local chars = { 'a', 'b', 'd', 'e', 'f', 'h', 'l', 'j', 'q', 'k', 'g', 'i', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' } @@ -62,7 +65,13 @@ local function set_mappings(path) end -- TODO: launch different functions here - api.nvim_buf_set_keymap(buf, 'i', '', ":lua require'lib/file'.add_file(vim.api.nvim_get_current_line())", { nowait = true, noremap = true, silent = true }) + if edit_type == 'add' then + api.nvim_buf_set_keymap(buf, 'i', '', ":lua require'lib/file'.add_file(vim.api.nvim_get_current_line())", { nowait = true, noremap = true, silent = true }) + elseif edit_type == 'rename' then + api.nvim_buf_set_keymap(buf, 'i', '', ":lua require'lib/file'.rename_file(vim.api.nvim_get_current_line())", { nowait = true, noremap = true, silent = true }) + elseif edit_type == 'delete' then + api.nvim_buf_set_keymap(buf, 'i', '', ":lua require'lib/file'.remove_file(vim.api.nvim_get_current_line())", { nowait = true, noremap = true, silent = true }) + end api.nvim_buf_set_keymap(buf, 'i', '', ":q!", { nowait = true, noremap = true, silent = true }) api.nvim_buf_set_keymap(buf, 'i', '', ":q!", { nowait = true, noremap = true, silent = true }) api.nvim_buf_set_keymap(buf, 'i', '', ":q!", { nowait = true, noremap = true, silent = true }) @@ -74,39 +83,47 @@ local function update_view(...) api.nvim_command('startinsert!') end -local function wrapper(path, ...) +local function wrapper(edit_type, ...) scratch_buffer() update_view(...) - set_mappings(path) + set_mappings(edit_type) end local function edit_add(path) - wrapper(path, { "Create File", path }) + wrapper("add", { "Create File", path }) end -local function edit_remove(filename, path, isdir) - local name = "File" - if isdir == true then name = "Directory" end - wrapper(path .. filename, { "Remove " .. name .. " " .. filename .. " ?", "y/n: " }) +local function edit_remove(filename, path) + EDIT_FILE = path .. filename + wrapper("delete", { "Remove " .. filename .. " ?", "y/n: " }) end -local function edit_rename(filename, path, isdir) - local name = "File" - if isdir == true then name = "Directory" end - wrapper(path .. filename, { "Rename " .. name, path .. filename }) +local function edit_rename(filename, path) + EDIT_FILE = path .. filename + wrapper("rename", { "Rename " .. path, path .. filename }) end local function add_file(path) - print(path) + if string.match(path, '.*/$') then + system('mkdir -p ' .. path) + else + system('touch ' .. path) + end api.nvim_command("q!") end -local function remove_file(path, confirm) - print(path) +local function remove_file(confirmation) + if string.match(confirmation, '^y/n: y.*$') ~= nil then + system('rm -rf ' .. EDIT_FILE) + end + EDIT_FILE = nil api.nvim_command("q!") end local function rename_file(path) + system('mv '..EDIT_FILE..' '..path) + EDIT_FILE = nil + api.nvim_command("q!") end return { diff --git a/lua/lib/format.lua b/lua/lib/format.lua index 7de296db..d9c1e323 100644 --- a/lua/lib/format.lua +++ b/lua/lib/format.lua @@ -41,7 +41,10 @@ local function format_tree(tree) for i, node in pairs(tree) do local padding = get_padding(node.depth) - local icon = get_icon(node.path .. node.name, node.dir, node.open) + local icon = "" + if node.icon == true then + icon = get_icon(node.path .. node.name, node.dir, node.open) + end dirs[i] = padding .. icon .. node.name end diff --git a/lua/tree.lua b/lua/tree.lua index 4c701d70..28d99215 100644 --- a/lua/tree.lua +++ b/lua/tree.lua @@ -2,11 +2,10 @@ local lib_file = require 'lib/file' local format = require 'lib/format'.format_tree local api = vim.api -local function sys(v) return api.nvim_call_function('system', { v }) end local function syslist(v) return api.nvim_call_function('systemlist', { v }) end --- get rid of \n and add leading '/' -local ROOT_PATH = string.sub(sys('pwd'), 1, -2) .. '/' +local ROOT_PATH = vim.loop.cwd() .. '/' +local Tree = {} local BUF_NAME = '_LuaTree_' local function is_dir(path) @@ -14,6 +13,21 @@ local function is_dir(path) return stat and stat.type == 'directory' or false end +local function check_dir_access(path) + return vim.loop.fs_access(path, 'R') == true +end + +local function list_dirs(path) + if path == nil then + return syslist('ls') + elseif check_dir_access(path) == false then + -- TODO: display an error here (permission denied) + return {} + else + return syslist('ls ' .. path) + end +end + local function sort_dirs(dirs) local sorted_tree = {} for _, node in pairs(dirs) do @@ -27,7 +41,7 @@ local function sort_dirs(dirs) return sorted_tree end -local function create_dirs(path, depth, dirs) +local function create_nodes(path, depth, dirs) local tree = {} if not string.find(path, '^.*/$') then path = path .. '/' end @@ -38,14 +52,30 @@ local function create_dirs(path, depth, dirs) name = name, depth = depth, dir = is_dir(path .. name), - open = false -- only relevant when its a dir + open = false, -- only relevant when its a dir + icon = true } end return sort_dirs(tree) end -local Tree = create_dirs(ROOT_PATH, 0, syslist('ls')) + +local function init_tree() + Tree = create_nodes(ROOT_PATH, 0, list_dirs()) + if ROOT_PATH ~= '/' then + table.insert(Tree, 1, { + path = ROOT_PATH, + name = '..', + depth = 0, + dir = true, + open = false, + icon = false + }) + end +end + +init_tree() local function get_buf() local regex = '.*'..BUF_NAME..'$'; @@ -104,15 +134,19 @@ local function close() api.nvim_win_close(win, true) end -local function update_view() +local function update_view(update_cursor) local buf = get_buf(); if not buf then return end - local cursor_pos = api.nvim_win_get_cursor(0) + local cursor = api.nvim_win_get_cursor(0) + api.nvim_buf_set_option(buf, 'modifiable', true) api.nvim_buf_set_lines(buf, 0, -1, false, format(Tree)) api.nvim_buf_set_option(buf, 'modifiable', false) - api.nvim_win_set_cursor(0, cursor_pos) + + if update_cursor == true then + api.nvim_win_set_cursor(0, cursor) + end end local function is_win_open() @@ -123,7 +157,22 @@ local function open_file(open_type) local tree_index = api.nvim_win_get_cursor(0)[1] local node = Tree[tree_index] - if node.dir == true then + if node.name == '..' then + api.nvim_command('cd ..') + if vim.loop.cwd() == '/' then + ROOT_PATH = '/' + else + ROOT_PATH = vim.loop.cwd() .. '/' + end + init_tree() + update_view() + elseif open_type == 'chdir' then + if node.dir == false or check_dir_access(node.path .. node.name) == false then return end + api.nvim_command('cd ' .. node.path .. node.name) + ROOT_PATH = vim.loop.cwd() .. '/' + init_tree() + update_view() + elseif node.dir == true then local index = tree_index + 1; node.open = not node.open local next_node = Tree[index] @@ -133,14 +182,14 @@ local function open_file(open_type) next_node = Tree[index] end else - local dirlist = syslist('ls ' .. node.path .. node.name) - local child_dirs = create_dirs(node.path .. node.name .. '/', node.depth + 1, dirlist) + local dirlist = list_dirs(node.path .. node.name) + local child_dirs = create_nodes(node.path .. node.name .. '/', node.depth + 1, dirlist) for i, n in pairs(child_dirs) do table.insert(Tree, tree_index + i, n) end end - update_view() + update_view(true) else api.nvim_command('wincmd l | '..open_type..' '.. node.path .. node.name) end @@ -154,6 +203,7 @@ local function set_mappings() [''] = 'open_file("edit")'; [''] = 'open_file("vsplit")'; [''] = 'open_file("split")'; + [''] = 'open_file("chdir")'; a = 'edit_file("add")'; d = 'edit_file("delete")'; r = 'edit_file("rename")';