Merge pull request #52 from kristijanhusak/feature/cut-copy-paste

Add cut,copy and paste functionality.
This commit is contained in:
Kiyan Yazdani
2020-07-21 17:16:08 +02:00
committed by GitHub
7 changed files with 159 additions and 1 deletions

View File

@@ -93,6 +93,9 @@ highlight LuaTreeFolderIcon guibg=blue
- type `a` to add a file. Adding a directory requires leaving a leading `/` at the end of the path. - type `a` to add a file. Adding a directory requires leaving a leading `/` at the end of the path.
> you can add multiple directories by doing foo/bar/baz/f and it will add foo bar and baz directories and f as a file > you can add multiple directories by doing foo/bar/baz/f and it will add foo bar and baz directories and f as a file
- type `r` to rename a file - type `r` to rename a file
- type `x` to add/remove file/directory to cut clipboard
- type `c` to add/remove file/directory to copy clipboard
- type `p` to paste from clipboard. Cut clipboard has precedence over copy (will prompt for confirmation)
- type `d` to delete a file (will prompt for confirmation) - type `d` to delete a file (will prompt for confirmation)
- if the file is a directory, `<CR>` will open the directory otherwise it will open the file in the buffer near the tree - if the file is a directory, `<CR>` will open the directory otherwise it will open the file in the buffer near the tree
- if the file is a symlink, `<CR>` will follow the symlink (if the target is a file) - if the file is a symlink, `<CR>` will follow the symlink (if the target is a file)

View File

@@ -45,6 +45,10 @@ It will also open the leafs of the tree leading to the file in the buffer
(if you opened a file with something else than the LuaTree, like `fzf` or (if you opened a file with something else than the LuaTree, like `fzf` or
`:split`) `:split`)
|:LuaTreeClipboard| *:LuaTreeClipboard*
Print clipboard content for both cut and copy
============================================================================== ==============================================================================
OPTIONS *nvim-tree-options* OPTIONS *nvim-tree-options*
@@ -136,6 +140,10 @@ INFORMATIONS *nvim-tree-info*
- type 'a' to add a file - type 'a' to add a file
- type 'r' to rename a file - type 'r' to rename a file
- type 'x' to add/remove file/directory to cut clipboard
- type 'c' to add/remove file/directory to copy clipboard
- type 'p' to paste from clipboard. Cut clipboard has precedence over copy
(will prompt for confirmation)
- type 'd' to delete a file (will prompt for confirmation) - type 'd' to delete a file (will prompt for confirmation)
- if the file is a directory, '<CR>' will open the directory - if the file is a directory, '<CR>' will open the directory
@@ -166,7 +174,10 @@ default keybindings will be applied to undefined keys.
\ preview: '<Tab>', \ preview: '<Tab>',
\ create: 'a', \ create: 'a',
\ remove: 'd', \ remove: 'd',
\ rename: 'r' \ rename: 'r',
\ cut: 'x',
\ copy: 'c',
\ paste: 'p',
\ } \ }
|Features| *nvim-tree-features* |Features| *nvim-tree-features*

View File

@@ -55,6 +55,9 @@ function M.get_bindings()
create = keybindings.create or 'a', create = keybindings.create or 'a',
remove = keybindings.remove or 'd', remove = keybindings.remove or 'd',
rename = keybindings.rename or 'r', rename = keybindings.rename or 'r',
cut = keybindings.cut or 'x',
copy = keybindings.copy or 'c',
paste = keybindings.paste or 'p',
} }
end end

View File

@@ -3,6 +3,10 @@ local luv = vim.loop
local open_mode = luv.constants.O_CREAT + luv.constants.O_WRONLY + luv.constants.O_TRUNC local open_mode = luv.constants.O_CREAT + luv.constants.O_WRONLY + luv.constants.O_TRUNC
local M = {} local M = {}
local clipboard = {
move = {},
copy = {}
}
local function clear_prompt() local function clear_prompt()
vim.api.nvim_command('normal :esc<CR>') vim.api.nvim_command('normal :esc<CR>')
@@ -109,6 +113,95 @@ local function remove_dir(cwd)
return luv.fs_rmdir(cwd) return luv.fs_rmdir(cwd)
end 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, t = 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_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
local dest_stats = luv.fs_stat(dest)
local should_process = true
if dest_stats then
local ans = vim.fn.input(dest..' already exists, overwrite ? y/n: ')
clear_prompt()
should_process = ans:match('^y')
end
if should_process then
local success, msg = action_fn(entry.absolute_path, dest)
if not success then
api.nvim_err_writeln('Could not '..action_type..' '..entry.absolute_path..' - '..msg)
end
end
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) function M.remove(node)
if node.name == '..' then return end if node.name == '..' then return end
@@ -153,4 +246,38 @@ function M.rename(node)
refresh_tree() refresh_tree()
end 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 return M

View File

@@ -210,6 +210,9 @@ local function set_mappings()
[bindings.remove] = 'on_keypress("remove")'; [bindings.remove] = 'on_keypress("remove")';
[bindings.rename] = 'on_keypress("rename")'; [bindings.rename] = 'on_keypress("rename")';
[bindings.preview] = 'on_keypress("preview")'; [bindings.preview] = 'on_keypress("preview")';
[bindings.cut] = 'on_keypress("cut")';
[bindings.copy] = 'on_keypress("copy")';
[bindings.paste] = 'on_keypress("paste")';
gx = "xdg_open()"; gx = "xdg_open()";
} }

View File

@@ -38,6 +38,12 @@ function M.on_keypress(mode)
return fs.remove(node) return fs.remove(node)
elseif mode == 'rename' then elseif mode == 'rename' then
return fs.rename(node) return fs.rename(node)
elseif mode == 'copy' then
return fs.copy(node)
elseif mode == 'cut' then
return fs.cut(node)
elseif mode == 'paste' then
return fs.paste(node)
end end
if mode == 'preview' then if mode == 'preview' then
@@ -73,6 +79,10 @@ function M.refresh()
lib.refresh_tree() lib.refresh_tree()
end end
function M.print_clipboard()
fs.print_clipboard()
end
function M.on_enter() function M.on_enter()
local bufnr = api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local bufname = api.nvim_buf_get_name(bufnr) local bufname = api.nvim_buf_get_name(bufnr)

View File

@@ -22,6 +22,7 @@ command! LuaTreeOpen lua require'tree'.open()
command! LuaTreeClose lua require'tree'.close() command! LuaTreeClose lua require'tree'.close()
command! LuaTreeToggle lua require'tree'.toggle() command! LuaTreeToggle lua require'tree'.toggle()
command! LuaTreeRefresh lua require'tree'.refresh() command! LuaTreeRefresh lua require'tree'.refresh()
command! LuaTreeClipboard lua require'tree'.print_clipboard()
command! LuaTreeFindFile lua require'tree'.find_file() command! LuaTreeFindFile lua require'tree'.find_file()
let &cpo = s:save_cpo let &cpo = s:save_cpo