Files
nvim-tree.lua/lua/nvim-tree/api/impl.lua
Uanela Como c760c92667 feat(#1549): p will paste files from another nvim-tree instance, gp will cut/paste (#3336)
* feat: add copy absolute path with protocol into public api

* feat: add helper get_basename into node

* feat: add gby keymap, and allow visual mode for copy.basename|absolute_path

* feat(clipboard): add opts for adding protocol in reg operations

* feat(api): allow visual operation in absolute_path*

* feat: add paste with protocol to keymap+api

* feat: add paste with protocol to clipboard

* feat: add configurable clipboard protocol

* fix: filter descendant nodes on copy_absolute_path_with_protocol

* refactor: change clip protocol keymaps to bgy and bgp

* wip

* fix(clipboad): correctly show the number of copied nodes on bgy

* chore: remove bgy, bgp and add gp + gx

* chore: update api/fs.lua and api impl.lua to match new keymaps

* fix: correctly pass the function to new keymaps

* chore: remove use_protocol and use use_register + cut options

* chore: update docs

* chore: move node:get_basename to cliboard_

* chore(clipboard): remove vim.cmd workaround in favor of vim.fn.setreg

* chore: use newline as separator instead of comma

* refactor(clipboard): simplify copying node attribute and allow all to work in visual mode

* refactor(keymap): remove gx, use gp to move

* feat(clipboard): always copy/cut to register and make `p` pick local data or register data

* refactor(docs): update api docs and rename paste_while_cutting to move

* fix: correctly format keymaps

* chore: regenerate docs

* fix: remove unused apis

* chore: copy clipboard.data to register on copy/cut

* chore: revert copy_node_attribute

* refactor: remove visual mode from copy.basename|filename|path

* chore: update docs

* chore: add fs.move api and update docs

* chore: destroy dummy nodes and prevent empty paths nodes parsing

* fix: _meta/api/fs.lua and docs

* fix(clipboard): destroy dummy nodes from register on paste

* fix(clipboard): correctly check for local paste operation
2026-07-01 10:11:03 +10:00

261 lines
16 KiB
Lua

---Hydrates API meta functions with their implementations.
---For startup performance reasons, all API implementation's requires must be
---done at call time, not when this module is required.
local M = {}
---Walk the entire API, hydrating all functions with the error notification.
---Do not hydrate classes i.e. anything with a metatable.
---@param api table not properly typed to prevent LSP from referencing implementations
local function hydrate_not_setup(api)
for k, v in pairs(api) do
if type(v) == "function" then
api[k] = function()
require("nvim-tree.notify").error("nvim-tree setup not called")
end
elseif type(v) == "table" and not getmetatable(v) then
hydrate_not_setup(v)
end
end
end
---Returns the node under the cursor.
---@return Node?
local function node_at_cursor()
local e = require("nvim-tree.core").get_explorer()
return e and e:get_node_at_cursor() or nil
end
---Returns the visually selected nodes, if we are in visual mode.
---@return Node[]?
local function visual_nodes()
local utils = require("nvim-tree.utils")
return utils.is_visual_mode() and utils.get_visual_nodes() or nil
end
---Injects:
---- n: n or node at cursor
---@param fn fun(n?: Node, ...): any
---@return fun(n?: Node, ...): any
local function _n(fn)
return function(n, ...)
return fn(n or node_at_cursor(), ...)
end
end
---Injects:
---- n: visual nodes or n or node at cursor
---@param fn fun(n?: Node|Node[], ...): any
---@return fun(n?: Node|Node[], ...): any
local function _v(fn)
return function(n, ...)
return fn(visual_nodes() or n or node_at_cursor(), ...)
end
end
---Injects:
---- e: Explorer instance
---Does nothing when no explorer instance.
---@param fn fun(e: Explorer, ...): any
---@return fun(e: Explorer, ...): any
local function e_(fn)
return function(...)
local e = require("nvim-tree.core").get_explorer()
if e then
return fn(e, ...)
end
end
end
---Injects:
---- e: Explorer instance
---- n: n or node at cursor
---Does nothing when no explorer instance.
---@param fn fun(e: Explorer, n?: Node, ...): any
---@return fun(e: Explorer, n?: Node, ...): any
local function en(fn)
return function(n, ...)
local e = require("nvim-tree.core").get_explorer()
if e then
return fn(e, n or node_at_cursor(), ...)
end
end
end
---Injects:
---- e: Explorer instance
---- n: visual nodes or n or node at cursor
---Does nothing when no explorer instance.
---@param fn fun(e: Explorer, n?: Node|Node[], ...): any
---@return fun(e: Explorer, n?: Node|Node[], ...): any
local function ev(fn)
return function(n, ...)
local e = require("nvim-tree.core").get_explorer()
if e then
return fn(e, visual_nodes() or n or node_at_cursor(), ...)
end
end
end
---NOP function wrapper, exists for formatting purposes only.
---@param fn fun(...): any
---@return fun(...): any
local function __(fn)
return function(...)
return fn(...)
end
end
---Hydrates API meta functions pre-setup:
--- Pre-setup functions will be hydrated with their implementation.
--- Post-setup functions will notify error: "nvim-tree setup not called"
--- All classes will be hydrated with their implementations.
---Called once when api is first required
---@param api table not properly typed to prevent LSP from referencing implementations
function M.hydrate_pre_setup(api)
hydrate_not_setup(api)
api.appearance.hi_test = __(function() require("nvim-tree.appearance.hi-test")() end)
api.commands.get = __(function() return require("nvim-tree.commands").get() end)
api.config.default = __(function() return require("nvim-tree.config").d_clone() end)
api.events.subscribe = __(function(event_name, handler) require("nvim-tree.events").subscribe(event_name, handler) end)
api.map.keymap.default = __(function() return require("nvim-tree.keymap").get_keymap_default() end)
api.map.on_attach.default = __(function(bufnr) require("nvim-tree.keymap").on_attach_default(bufnr) end)
api.Decorator = require("nvim-tree.renderer.decorator")
-- Map any legacy functions to implementations above or to meta
require("nvim-tree.legacy").map_api(api)
end
---Re-hydrates all API functions with implementations, replacing any "nvim-tree setup not called" error functions.
---Called explicitly after nvim-tree setup
---@param api table not properly typed to prevent LSP from referencing implementations
function M.hydrate_post_setup(api)
-- Parameter naming conventions:
-- `e` explorer
-- `n` node
-- `o` opts
api.config.global = __(function() return require("nvim-tree.config").g_clone() end)
api.config.user = __(function() return require("nvim-tree.config").u_clone() end)
api.filter.custom.toggle = e_(function(e) e.filters:toggle("custom") end)
api.filter.dotfiles.toggle = e_(function(e) e.filters:toggle("dotfiles") end)
api.filter.git.clean.toggle = e_(function(e) e.filters:toggle("git_clean") end)
api.filter.git.ignored.toggle = e_(function(e) e.filters:toggle("git_ignored") end)
api.filter.live.clear = e_(function(e) e.live_filter:clear_filter() end)
api.filter.live.start = e_(function(e) e.live_filter:start_filtering() end)
api.filter.no_bookmark.toggle = e_(function(e) e.filters:toggle("no_bookmark") end)
api.filter.no_buffer.toggle = e_(function(e) e.filters:toggle("no_buffer") end)
api.filter.toggle = e_(function(e) e.filters:toggle() end)
api.fs.clear_clipboard = e_(function(e) e.clipboard:clear_clipboard() end)
api.fs.copy.absolute_path = ev(function(e, n) e.clipboard:copy_absolute_path(n) end)
api.fs.copy.basename = en(function(e, n) e.clipboard:copy_basename(n) end)
api.fs.copy.filename = en(function(e, n) e.clipboard:copy_filename(n) end)
api.fs.copy.relative_path = en(function(e, n) e.clipboard:copy_path(n) end)
api.fs.copy.node = ev(function(e, n) e.clipboard:copy(n) end)
api.fs.create = _n(function(n) require("nvim-tree.actions.fs.create-file").fn(n) end)
api.fs.cut = ev(function(e, n) e.clipboard:cut(n) end)
api.fs.paste = en(function(e, n) e.clipboard:paste(n) end)
api.fs.move = en(function(e, n) e.clipboard:paste(n, { cut = true }) end)
api.fs.print_clipboard = e_(function(e) e.clipboard:print_clipboard() end)
api.fs.remove = _v(function(n) require("nvim-tree.actions.fs.remove-file").fn(n) end)
api.fs.rename = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_node(n) end)
api.fs.rename_basename = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_basename(n) end)
api.fs.rename_full = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_full(n) end)
api.fs.rename_node = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_node(n) end)
api.fs.rename_sub = _n(function(n) require("nvim-tree.actions.fs.rename-file").rename_sub(n) end)
api.fs.trash = _v(function(n) require("nvim-tree.actions.fs.trash").fn(n) end)
api.git.reload = e_(function(e) e:reload_git() end)
api.map.keymap.current = __(function() return require("nvim-tree.keymap").get_keymap() end)
api.marks.bulk.delete = e_(function(e) e.marks:bulk_delete() end)
api.marks.bulk.move = e_(function(e) e.marks:bulk_move() end)
api.marks.bulk.trash = e_(function(e) e.marks:bulk_trash() end)
api.marks.clear = e_(function(e) e.marks:clear() end)
api.marks.get = en(function(e, n) return e.marks:get(n) end)
api.marks.list = e_(function(e) return e.marks:list() end)
api.marks.navigate.next = e_(function(e) e.marks:navigate_next() end)
api.marks.navigate.prev = e_(function(e) e.marks:navigate_prev() end)
api.marks.navigate.select = e_(function(e) e.marks:navigate_select() end)
api.marks.toggle = ev(function(e, n) e.marks:toggle(n) end)
api.node.buffer.delete = _n(function(n, o) require("nvim-tree.actions.node.buffer").delete(n, o) end)
api.node.buffer.wipe = _n(function(n, o) require("nvim-tree.actions.node.buffer").wipe(n, o) end)
api.node.collapse = _n(function(n, o) require("nvim-tree.actions.tree.collapse").node(n, o) end)
api.node.expand = en(function(e, n, o) e:expand_node(n, o) end)
api.node.navigate.diagnostics.next = __(function() require("nvim-tree.actions.moves.item").diagnostics_next() end)
api.node.navigate.diagnostics.next_recursive = __(function() require("nvim-tree.actions.moves.item").diagnostics_next_recursive() end)
api.node.navigate.diagnostics.prev = __(function() require("nvim-tree.actions.moves.item").diagnostics_prev() end)
api.node.navigate.diagnostics.prev_recursive = __(function() require("nvim-tree.actions.moves.item").diagnostics_prev_recursive() end)
api.node.navigate.git.next = __(function() require("nvim-tree.actions.moves.item").git_next() end)
api.node.navigate.git.next_recursive = __(function() require("nvim-tree.actions.moves.item").git_next_recursive() end)
api.node.navigate.git.next_skip_gitignored = __(function() require("nvim-tree.actions.moves.item").git_next_skip_gitignored() end)
api.node.navigate.git.prev = __(function() require("nvim-tree.actions.moves.item").git_prev() end)
api.node.navigate.git.prev_recursive = __(function() require("nvim-tree.actions.moves.item").git_prev_recursive() end)
api.node.navigate.git.prev_skip_gitignored = __(function() require("nvim-tree.actions.moves.item").git_prev_skip_gitignored() end)
api.node.navigate.opened.next = __(function() require("nvim-tree.actions.moves.item").opened_next() end)
api.node.navigate.opened.prev = __(function() require("nvim-tree.actions.moves.item").opened_prev() end)
api.node.navigate.parent = _n(function(n) require("nvim-tree.actions.moves.parent").move(n) end)
api.node.navigate.parent_close = _n(function(n) require("nvim-tree.actions.moves.parent").move_close(n) end)
api.node.navigate.sibling.first = _n(function(n) require("nvim-tree.actions.moves.sibling").first(n) end)
api.node.navigate.sibling.last = _n(function(n) require("nvim-tree.actions.moves.sibling").last(n) end)
api.node.navigate.sibling.next = _n(function(n) require("nvim-tree.actions.moves.sibling").next(n) end)
api.node.navigate.sibling.prev = _n(function(n) require("nvim-tree.actions.moves.sibling").prev(n) end)
api.node.open.drop = _n(function(n) require("nvim-tree.actions.node.open-file").drop(n) end)
api.node.open.edit = _n(function(n, o) require("nvim-tree.actions.node.open-file").edit(n, o) end)
api.node.open.horizontal = _n(function(n, o) require("nvim-tree.actions.node.open-file").horizontal(n, o) end)
api.node.open.horizontal_no_picker = _n(function(n, o)
require("nvim-tree.actions.node.open-file").horizontal_no_picker(n,
o)
end)
api.node.open.no_window_picker = _n(function(n, o) require("nvim-tree.actions.node.open-file").no_window_picker(n, o) end)
api.node.open.preview = _n(function(n, o) require("nvim-tree.actions.node.open-file").preview(n, o) end)
api.node.open.preview_no_picker = _n(function(n, o) require("nvim-tree.actions.node.open-file").preview_no_picker(n, o) end)
api.node.open.replace_tree_buffer = _n(function(n) require("nvim-tree.actions.node.open-file").replace_tree_buffer(n) end)
api.node.open.tab = _n(function(n, o) require("nvim-tree.actions.node.open-file").tab(n, o) end)
api.node.open.tab_drop = _n(function(n) require("nvim-tree.actions.node.open-file").tab_drop(n) end)
api.node.open.toggle_group_empty = _n(function(n) require("nvim-tree.actions.node.open-file").toggle_group_empty(n) end)
api.node.open.vertical = _n(function(n, o) require("nvim-tree.actions.node.open-file").vertical(n, o) end)
api.node.open.vertical_no_picker = _n(function(n, o) require("nvim-tree.actions.node.open-file").vertical_no_picker(n, o) end)
api.node.run.cmd = _n(function(n) require("nvim-tree.actions.node.run-command").run_file_command(n) end)
api.node.run.system = _n(function(n) require("nvim-tree.actions.node.system-open").fn(n) end)
api.node.show_info_popup = _n(function(n) require("nvim-tree.actions.node.file-popup").toggle_file_info(n) end)
api.tree.change_root = __(function(path) require("nvim-tree.actions.tree.change-dir").fn(path) end)
api.tree.change_root_to_node = en(function(e, n) e:change_dir_to_node(n) end)
api.tree.change_root_to_parent = en(function(e, n) e:dir_up(n) end)
api.tree.close = __(function() require("nvim-tree.view").close() end)
api.tree.close_in_all_tabs = __(function() require("nvim-tree.view").close_all_tabs() end)
api.tree.close_in_this_tab = __(function() require("nvim-tree.view").close_this_tab_only() end)
api.tree.collapse_all = __(function(o) require("nvim-tree.actions.tree.collapse").all(o) end)
api.tree.expand_all = en(function(e, n, o) e:expand_all(n, o) end)
api.tree.find_file = __(function(o) require("nvim-tree.actions.tree.find-file").fn(o) end)
api.tree.focus = __(function(o) require("nvim-tree.actions.tree.open").fn(o) end)
api.tree.get_node_under_cursor = en(function(e) return e:get_node_at_cursor() end)
api.tree.get_nodes = en(function(e) return e:get_nodes() end)
api.tree.is_tree_buf = __(function(bufnr) return require("nvim-tree.utils").is_nvim_tree_buf(bufnr) end)
api.tree.is_visible = __(function(o) return require("nvim-tree.view").is_visible(o) end)
api.tree.open = __(function(o) require("nvim-tree.actions.tree.open").fn(o) end)
api.tree.reload = e_(function(e) e:reload_explorer() end)
api.tree.reload_git = e_(function(e) e:reload_git() end)
api.tree.resize = __(function(o) require("nvim-tree.actions.tree.resize").fn(o) end)
api.tree.search_node = __(function() require("nvim-tree.actions.finders.search-node").fn() end)
api.tree.toggle = __(function(o) require("nvim-tree.actions.tree.toggle").fn(o) end)
api.tree.toggle_help = __(function() require("nvim-tree.help").toggle() end)
api.tree.winid = __(function(o) return require("nvim-tree.view").winid(o) end)
-- Map all legacy functions to implementations
require("nvim-tree.legacy").map_api(api)
end
return M