Compare commits

...

56 Commits

Author SHA1 Message Date
uanela
ee173eb666 Merge branch 'chore/remove-operation-between-instances-protocol' of https://github.com/nvim-tree/nvim-tree.lua into feat/add-download-from-path 2026-06-30 14:57:10 +02:00
uanela
9cad29b466 fix(clipboard): destroy dummy nodes from register on paste 2026-06-30 14:55:12 +02:00
uanela
91a288ca57 Merge branch 'feat/add-download-from-path' of https://github.com/nvim-tree/nvim-tree.lua into feat/add-download-from-path 2026-06-29 08:30:01 +02:00
uanela
582bc35ce2 Merge branch 'chore/remove-operation-between-instances-protocol' of https://github.com/nvim-tree/nvim-tree.lua into feat/add-download-from-path 2026-06-29 08:29:38 +02:00
uanela
cb58a0721c fix: _meta/api/fs.lua and docs 2026-06-25 10:27:26 +02:00
uanela
4b13775b45 chore: destroy dummy nodes and prevent empty paths nodes parsing 2026-06-25 10:14:57 +02:00
uanela
4fcbafea04 chore: add fs.move api and update docs 2026-06-25 10:14:16 +02:00
uanela
1b6737155a chore: update docs 2026-06-22 09:06:33 +02:00
uanela
30c5036368 Merge branch 'chore/remove-operation-between-instances-protocol' of https://github.com/nvim-tree/nvim-tree.lua into chore/remove-operation-between-instances-protocol 2026-06-22 09:02:31 +02:00
uanela
f10f779baf refactor: remove visual mode from copy.basename|filename|path 2026-06-22 09:00:31 +02:00
uanela
062a2d2800 chore: revert copy_node_attribute 2026-06-22 08:59:51 +02:00
uanela
4bd13ec53b chore: copy clipboard.data to register on copy/cut 2026-06-22 08:58:50 +02:00
uanela
fa2b18661c fix: remove unused apis 2026-06-22 08:57:05 +02:00
Uanela Como
5eba88e119 Merge branch 'master' into chore/remove-operation-between-instances-protocol 2026-06-22 07:55:41 +02:00
dependabot[bot]
8e8be709c9 chore(deps): bump actions/checkout from 6 to 7 (#3340)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-20 13:16:28 +10:00
Uanela Como
0522defa11 Correct is_nodes_array return logic
Fix is_nodes_array function to correctly identify node arrays.
2026-06-18 11:39:07 +02:00
Uanela Como
9c782a19ae Update lua/nvim-tree/actions/fs/clipboard.lua
Co-authored-by: gegoune <69750637+gegoune@users.noreply.github.com>
2026-06-18 11:30:20 +02:00
uanela
f8fa340acc chore: add ... when showing Downloading message 2026-06-18 11:09:28 +02:00
uanela
8d1adf0e1d Merge branch 'chore/remove-operation-between-instances-protocol' of https://github.com/nvim-tree/nvim-tree.lua into feat/add-download-from-path 2026-06-18 11:07:53 +02:00
uanela
b1662a5d06 chore: regenerate docs 2026-06-18 11:01:35 +02:00
uanela
859f733ea3 fix: correctly format keymaps 2026-06-18 10:57:55 +02:00
uanela
887e6c129e refactor(docs): update api docs and rename paste_while_cutting to move 2026-06-18 10:52:10 +02:00
uanela
6f1b818356 feat(clipboard): always copy/cut to register and make p pick local data or register data 2026-06-18 10:31:05 +02:00
uanela
356c083687 refactor(keymap): remove gx, use gp to move 2026-06-18 10:30:09 +02:00
uanela
f79cdcb708 refactor(clipboard): simplify copying node attribute and allow all to work in visual mode 2026-06-18 10:02:52 +02:00
uanela
ba8e7a1c56 chore: use newline as separator instead of comma 2026-06-18 09:12:14 +02:00
uanela
a7e647bf83 chore(clipboard): remove vim.cmd workaround in favor of vim.fn.setreg 2026-06-18 09:05:28 +02:00
uanela
4f787e0db3 chore: move node:get_basename to cliboard_ 2026-06-18 08:23:50 +02:00
Uanela Como
43f01b5281 Merge branch 'master' into chore/remove-operation-between-instances-protocol 2026-06-15 11:49:49 +02:00
Alexander Courtis
fb343438d4 docs: generated help fields are sorted as of v0.12.3 (#3337)
* doc: generated help fields are sorted as of v0.12.3

* ci: add weekly trigger for CI job
2026-06-15 12:30:16 +10:00
uanela
b5750c8c86 feat: add download feat when gp 2026-06-15 02:25:12 +02:00
uanela
27f5254cab chore: update docs 2026-06-15 00:50:13 +02:00
uanela
073fac1056 chore: remove use_protocol and use use_register + cut options 2026-06-15 00:43:23 +02:00
uanela
0fd8cfadf5 fix: correctly pass the function to new keymaps 2026-06-15 00:41:48 +02:00
uanela
a9253ded6f chore: update api/fs.lua and api impl.lua to match new keymaps 2026-06-15 00:25:47 +02:00
uanela
77325e556c chore: remove bgy, bgp and add gp + gx 2026-06-15 00:10:03 +02:00
uanela
2c56cc6a1a fix(clipboad): correctly show the number of copied nodes on bgy 2026-06-11 17:20:09 +02:00
uanela
885b4d9ec3 wip 2026-06-11 16:59:17 +02:00
uanela
877e726a77 refactor: change clip protocol keymaps to bgy and bgp 2026-06-11 16:57:54 +02:00
uanela
b9e9b7a67c fix: filter descendant nodes on copy_absolute_path_with_protocol 2026-06-11 16:36:20 +02:00
uanela
38ada46881 feat: add configurable clipboard protocol 2026-06-11 16:34:57 +02:00
uanela
cdc7b28c76 feat: add paste with protocol to clipboard 2026-06-11 15:42:31 +02:00
uanela
f2269a1be7 feat: add paste with protocol to keymap+api 2026-06-11 15:41:20 +02:00
uanela
b98e0c4ba4 feat(api): allow visual operation in absolute_path* 2026-06-11 10:15:11 +02:00
uanela
89edce64c1 feat(clipboard): add opts for adding protocol in reg operations 2026-06-11 10:14:19 +02:00
uanela
058e5081cd feat: add gby keymap, and allow visual mode for copy.basename|absolute_path 2026-06-11 10:11:10 +02:00
uanela
c842a086a3 feat: add helper get_basename into node 2026-06-11 10:08:41 +02:00
uanela
ddbc033b90 feat: add copy absolute path with protocol into public api 2026-06-11 10:07:58 +02:00
Sean McCollum
82f58063d6 docs: spelling error (#3333) 2026-06-08 14:32:39 +10:00
Alexander Courtis
07f541fcaa fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function (#3329)
* fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function

* fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function

* fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function

* fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function

* fix(#3327): pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function
2026-05-16 08:49:14 +10:00
Alexander Courtis
f9bfc0059e fix(#3324): deprecated BufModifiedSet event replaced by OptionSet event for Nvim 0.13+ (#3325)
* fix(#3324): deprecated BufModifiedSet event replaced by OptionSet event for Nvim 0.13+

* fix(#3324): deprecated BufModifiedSet event replaced by OptionSet event for Nvim 0.13+

* ci: remove help-check for Nvim nightly
2026-05-01 08:31:56 +10:00
dependabot[bot]
24cfcc9437 chore(deps): bump googleapis/release-please-action from 4 to 5 (#3319)
Bumps [googleapis/release-please-action](https://github.com/googleapis/release-please-action) from 4 to 5.
- [Release notes](https://github.com/googleapis/release-please-action/releases)
- [Changelog](https://github.com/googleapis/release-please-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/release-please-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: googleapis/release-please-action
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-26 09:20:37 +10:00
dependabot[bot]
5f65bd3d93 chore(deps): bump leafo/gh-actions-lua from 12 to 13 (#3320)
Bumps [leafo/gh-actions-lua](https://github.com/leafo/gh-actions-lua) from 12 to 13.
- [Release notes](https://github.com/leafo/gh-actions-lua/releases)
- [Commits](https://github.com/leafo/gh-actions-lua/compare/v12...v13)

---
updated-dependencies:
- dependency-name: leafo/gh-actions-lua
  dependency-version: '13'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2026-04-26 09:18:06 +10:00
Alexander Courtis
5a1d08bc0c docs: remove lintdoc from help-check, skip the name checker during help-update (#3322)
* docs: remove lintdoc from help-check, skip the name checker during help-update

* docs: test new help-check

* Revert "docs: test new help-check"

This reverts commit 52128372ca.
2026-04-26 09:16:14 +10:00
Tomasz N
d277467fc0 fix(#3312): correct cursor when full name shown, requires nvim 0.12.2+ (#3316)
fix(full-name): lower `zindex` to get consistent cursor shape

See https://github.com/neovim/neovim/pull/39054
2026-04-16 10:51:29 +10:00
Alexander Courtis
509962f21a docs: update to 0.12 help format, remove blank line help suppression (#3314)
doc: update to 0.12 help format, remove blank line help suppression
2026-04-07 11:09:12 +10:00
16 changed files with 567 additions and 402 deletions

View File

@@ -5,6 +5,8 @@ on:
push:
branches: [master]
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # weekly on sundays
permissions:
contents: read
@@ -24,10 +26,10 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: install lua ${{ matrix.lua_version }}
uses: leafo/gh-actions-lua@v12
uses: leafo/gh-actions-lua@v13
with:
luaVersion: ${{ matrix.lua_version }}
@@ -58,7 +60,7 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: install nvim ${{ matrix.nvim_version }}
uses: rhysd/action-setup-vim@v1
@@ -87,11 +89,12 @@ jobs:
- run: make format-check
- name: build Nvim from source
if: ${{ matrix.nvim_version == 'stable' }}
run: |
mkdir -p "${DIR_NVIM_SRC}"
curl -L "https://github.com/neovim/neovim/archive/refs/tags/${{ matrix.nvim_version }}.tar.gz" | tar zx --directory "${DIR_NVIM_SRC}/.."
cd "${DIR_NVIM_SRC}"
make doc
make lintdoc
- run: make help-check
if: ${{ matrix.nvim_version == 'stable' }}

View File

@@ -10,7 +10,7 @@ jobs:
luarocks-upload:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: LuaRocks Upload
uses: nvim-neorocks/luarocks-tag-release@v7
env:

View File

@@ -14,9 +14,9 @@ jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
- uses: googleapis/release-please-action@v5
id: release
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: tag major and minor versions
if: ${{ steps.release.outputs.release_created }}
run: |

View File

@@ -184,7 +184,7 @@ make help-update
- Generate config classes `*nvim-tree-config*`
- Generate API `*nvim-tree-api*`
## Checking And Linting
## Checking
This is run in CI. Commit or stage your changes and run:
@@ -194,7 +194,6 @@ make help-check
- Re-runs `make help-update`
- Checks that `git diff` is empty, to ensure that all content has been generated. This is why a stage or commit is necessary.
- Lints `doc/nvim-tree-lua.txt` using `scripts/vimdoc.sh lintdoc` to check for no broken links etc.
# Windows

View File

@@ -43,11 +43,9 @@ help-update:
#
# CI
# --ignore-blank-lines is used as nightly has removed unnecessary blank lines that stable (0.11.5) currently inserts
#
help-check: help-update
scripts/vimdoc.sh lintdoc
git diff --ignore-blank-lines --exit-code doc/nvim-tree-lua.txt
git diff --exit-code doc/nvim-tree-lua.txt
.PHONY: all lint style check luacheck style-check style-doc luals format-fix format-check help-update help-check

File diff suppressed because it is too large Load Diff

View File

@@ -59,13 +59,25 @@ function nvim_tree.api.fs.create(node) end
function nvim_tree.api.fs.cut(node) end
---
---Paste from the nvim-tree clipboard.
---Paste files from:
---- current nvim-tree clipboard (if present)
---- another nvim-tree instance via system clipboard
---
---If {node} is a file it will pasted in the parent directory.
---
---@param node? nvim_tree.api.Node
function nvim_tree.api.fs.paste(node) end
---
---Paste while cutting files from:
---- current nvim-tree clipboard (if present)
---- another nvim-tree instance via system clipboard
---
---If {node} is a file it will pasted in the parent directory.
---
---@param node? nvim_tree.api.Node
function nvim_tree.api.fs.move(node) end
---
---Print the contents of the nvim-tree clipboard.
---

View File

@@ -16,6 +16,12 @@ nvim_tree.api.node.open = {}
---@field focus? boolean
---
---Switch to window with selected file if it exists, otherwise open, see [:drop]
---
---@param node? nvim_tree.api.Node directory or file
function nvim_tree.api.node.open.drop(node) end
---
---- file: open as per [nvim_tree.config.actions.open_file]
---- directory: expand or collapse
@@ -29,31 +35,36 @@ function nvim_tree.api.node.open.edit(node, opts) end
---Open file in a new horizontal split.
---
---@param node? nvim_tree.api.Node file
function nvim_tree.api.node.open.horizontal(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.horizontal(node, opts) end
---
---Open file in a new horizontal split without using the window picker.
---
---@param node? nvim_tree.api.Node file
function nvim_tree.api.node.open.horizontal_no_picker(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.horizontal_no_picker(node, opts) end
---
---Open file without using the window picker.
---
---@param node? nvim_tree.api.Node file
function nvim_tree.api.node.open.no_window_picker(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.no_window_picker(node, opts) end
---
---Open file with ['bufhidden'] set to `delete`.
---
---@param node? nvim_tree.api.Node directory or file
function nvim_tree.api.node.open.preview(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.preview(node, opts) end
---
---Open file with ['bufhidden'] set to `delete` without using the window picker.
---
---@param node? nvim_tree.api.Node directory or file
function nvim_tree.api.node.open.preview_no_picker(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.preview_no_picker(node, opts) end
---
---Open file in place: in the nvim-tree window.
@@ -65,10 +76,11 @@ function nvim_tree.api.node.open.replace_tree_buffer(node) end
---Open file in a new tab.
---
---@param node? nvim_tree.api.Node directory or file
function nvim_tree.api.node.open.tab(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.tab(node, opts) end
---
---Switch to tab containing window with selected file if it exists. Open file in new tab otherwise.
---Switch to tab containing window with selected file if it exists, otherwise open in new tab, see [:drop]
---
---@param node? nvim_tree.api.Node directory or file
function nvim_tree.api.node.open.tab_drop(node) end
@@ -83,13 +95,15 @@ function nvim_tree.api.node.open.toggle_group_empty(node) end
---Open file in a new vertical split.
---
---@param node? nvim_tree.api.Node file
function nvim_tree.api.node.open.vertical(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.vertical(node, opts) end
---
---Open file in a new vertical split without using the window picker.
---
---@param node? nvim_tree.api.Node file
function nvim_tree.api.node.open.vertical_no_picker(node) end
---@param opts? nvim_tree.api.node.open.Opts optional
function nvim_tree.api.node.open.vertical_no_picker(node, opts) end
---
---@class nvim_tree.api.node.buffer.RemoveOpts

View File

@@ -3,7 +3,7 @@ error("Cannot require a meta file")
---Filters may be applied to the tree to exlude the display of file/directories.
---Filters may be applied to the tree to exclude the display of file/directories.
---
---Multiple filters may be applied at once.
---

View File

@@ -9,6 +9,7 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn
local Class = require("nvim-tree.classic")
local DirectoryNode = require("nvim-tree.node.directory")
local FileNode = require("nvim-tree.node.file")
local Node = require("nvim-tree.node")
---@alias ClipboardAction "copy" | "cut"
@@ -176,28 +177,37 @@ function Clipboard:bulk_clipboard(nodes, from, to, verb)
self.explorer.renderer:draw()
end
---@private
---@param node_or_nodes Node|Node[]
---@return boolean
function Clipboard:is_nodes_array(node_or_nodes)
return type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node)
end
---Copy one or more nodes
---@param node_or_nodes Node|Node[]
function Clipboard:copy(node_or_nodes)
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
if self:is_nodes_array(node_or_nodes) == false then
utils.array_remove(self.data.cut, node_or_nodes)
toggle(node_or_nodes, self.data.copy)
self.explorer.renderer:draw()
else
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.cut, self.data.copy, "added to")
end
self:copy_absolute_path(self.data.copy, { notify = false })
end
---Cut one or more nodes
---@param node_or_nodes Node|Node[]
function Clipboard:cut(node_or_nodes)
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
if self:is_nodes_array(node_or_nodes) == false then
utils.array_remove(self.data.copy, node_or_nodes)
toggle(node_or_nodes, self.data.cut)
self.explorer.renderer:draw()
else
self:bulk_clipboard(utils.filter_descendant_nodes(node_or_nodes), self.data.copy, self.data.cut, "cut to")
end
self:copy_absolute_path(self.data.cut, { notify = false })
end
---Clear clipboard for action and reload to reflect filesystem changes from paste.
@@ -304,6 +314,40 @@ function Clipboard:resolve_conflicts(conflict, destination, action, action_fn)
end)
end
--- Transforms the copied absolute paths on register to node
---@private
function Clipboard:get_nodes_from_reg()
local content = vim.fn.getreg(self.reg)
if #content == 0 then
return {}
end
local nodes = {}
local absolute_paths = vim.split(content:sub(1, #content), "\n")
for _, absolute_path in ipairs(absolute_paths) do
if absolute_path:match("^%s*(.-)%s*s") then
local node_args = { absolute_path = absolute_path, name = vim.fn.fnamemodify(absolute_path, ":t"), explorer = self.explorer }
if absolute_path:sub(-1) == "/" then
node_args.name = vim.fn.fnamemodify(absolute_path:sub(1, -2), ":t")
table.insert(nodes, DirectoryNode(node_args))
else
table.insert(nodes, FileNode(node_args))
end
end
end
return nodes
end
---@param nodes Node[]
---@private
function Clipboard:destroy_nodes(nodes)
for _, n in ipairs(nodes) do
n:destroy()
end
end
---Paste cut or copy with batch conflict resolution.
---@private
---@param node Node
@@ -318,7 +362,9 @@ function Clipboard:do_paste(node, action, action_fn)
node = dir:last_group_node()
end
end
local clip = self.data[action]
local is_local = #self.data[action] > 0
local clip = is_local and self.data[action] or self:get_nodes_from_reg()
if #clip == 0 then
return
end
@@ -328,6 +374,9 @@ function Clipboard:do_paste(node, action, action_fn)
if not stats and err_name ~= "ENOENT" then
log.line("copy_paste", "do_paste fs_stat '%s' failed '%s'", destination, err)
notify.error("Could not " .. action .. " " .. notify.render_path(destination) .. " - " .. (err or "???"))
if ~is_local then
self:destroy_nodes(clip)
end
return
end
local is_dir = stats and stats.type == "directory"
@@ -350,7 +399,18 @@ function Clipboard:do_paste(node, action, action_fn)
-- Paste non-conflicting items immediately
for _, item in ipairs(no_conflict) do
do_paste_one(item.node.absolute_path, item.dest, action, action_fn)
local absolute_path = item.node.absolute_path
if absolute_path:sub(1, #"http") == "http" then
notify.info("Downloading " .. absolute_path .. " to " .. item.dest .. "...")
local result = vim.fn.system({ "curl", "-sL", absolute_path, "-o", item.dest })
if vim.v.shell_error == 0 then
notify.info("Downloaded " .. absolute_path .. " successfully at " .. item.dest)
else
notify.error("Error downloading " .. absolute_path .. ": " .. result)
end
else
do_paste_one(absolute_path, item.dest, action, action_fn)
end
end
-- Resolve conflicts in batch
@@ -359,6 +419,10 @@ function Clipboard:do_paste(node, action, action_fn)
else
self:finish_paste(action)
end
if ~is_local then
self:destroy_nodes(clip)
end
end
---@param source string
@@ -386,10 +450,12 @@ end
---Paste cut (if present) or copy (if present)
---@param node Node
function Clipboard:paste(node)
if self.data.cut[1] ~= nil then
---@param opts? { cut?: boolean }
function Clipboard:paste(node, opts)
opts = opts and opts or {}
if self.data.cut[1] ~= nil or opts.cut == true then
self:do_paste(node, "cut", do_cut)
elseif self.data.copy[1] ~= nil then
else
self:do_paste(node, "copy", do_copy)
end
end
@@ -413,17 +479,15 @@ function Clipboard:print_clipboard()
end
---@param content string
function Clipboard:copy_to_reg(content)
-- manually firing TextYankPost does not set vim.v.event
-- workaround: create a scratch buffer with the clipboard contents and send a yank command
local temp_buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_text(temp_buf, 0, 0, 0, 0, { content })
vim.api.nvim_buf_call(temp_buf, function()
vim.cmd(string.format('normal! "%sy$', self.reg))
end)
vim.api.nvim_buf_delete(temp_buf, {})
---@param message? string
---@param opts? { notify?: boolean }
function Clipboard:copy_to_reg(content, message, opts)
opts = opts and opts or {}
vim.fn.setreg(self.reg, type(content) == "table" and content or { content }, "v")
notify.info(string.format("Copied %s to %s clipboard!", content, self.clipboard_name))
if opts.notify ~= false then
notify.info(message or string.format("Copied %s to %s clipboard!", content, self.clipboard_name))
end
end
---@param node Node
@@ -437,18 +501,20 @@ function Clipboard:copy_filename(node)
end
end
---@private
---@param node Node
function Clipboard:copy_basename(node)
---@return string
function Clipboard:get_absolute_path(node)
if node.name == ".." then
-- root
self:copy_to_reg(vim.fn.fnamemodify(self.explorer.absolute_path, ":t:r"))
else
-- node
self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r"))
node = self.explorer
end
local absolute_path = node.absolute_path
return node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
end
---@param node Node
---@return string|nil
function Clipboard:copy_path(node)
if node.name == ".." then
-- root
@@ -470,15 +536,44 @@ function Clipboard:copy_path(node)
end
end
---@param node Node
function Clipboard:copy_absolute_path(node)
if node.name == ".." then
node = self.explorer
---@param node_or_nodes Node|Node[]
---@param opts? { notify?: boolean }
function Clipboard:copy_absolute_path(node_or_nodes, opts)
opts = opts and opts or {}
local content
local is_single = self:is_nodes_array(node_or_nodes) == false
if is_single then
local node = #node_or_nodes == 1 and node_or_nodes[0] or node_or_nodes
content = self:get_absolute_path(node)
else
node_or_nodes = utils.filter_descendant_nodes(node_or_nodes)
content = {}
for _, node in ipairs(node_or_nodes) do
table.insert(content, self:get_absolute_path(node))
end
end
local absolute_path = node.absolute_path
local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
self:copy_to_reg(content)
if content ~= nil then
local message = nil
if not is_single then
message = string.format("%s %s copied to register", #content, #content > 1 and "absolute paths" or "absolute path")
end
self:copy_to_reg(content, message, opts)
end
end
---@param node Node
function Clipboard:copy_basename(node)
if node.name == ".." then
-- root
self:copy_to_reg(vim.fn.fnamemodify(node.explorer.absolute_path, ":t:r"))
else
-- node
self:copy_to_reg(vim.fn.fnamemodify(node.name, ":r"))
end
end
---Node is cut. Will not be copied.

View File

@@ -10,10 +10,6 @@ local DirectoryNode = require("nvim-tree.node.directory")
local FileLinkNode = require("nvim-tree.node.file-link")
local RootNode = require("nvim-tree.node.root")
---@class NodeEditOpts
---@field quit_on_open boolean|nil default false
---@field focus boolean|nil default true
---@alias NodeOpenFileMode ""|"change_dir"|"drop"|"edit"|"edit_in_place"|"edit_no_picker"|"preview"|"preview_no_picker"|"split"|"split_no_picker"|"tab_drop"|"tabnew"|"toggle_group_empty"|"vsplit"|"vsplit_no_picker"
local M = {}
@@ -416,7 +412,7 @@ end
---@param mode string
---@param node Node
---@param edit_opts NodeEditOpts?
---@param edit_opts nvim_tree.api.node.open.Opts?
local function edit(mode, node, edit_opts)
local file_link = node:as(FileLinkNode)
local path = file_link and file_link.link_to or node.absolute_path
@@ -432,7 +428,7 @@ local function edit(mode, node, edit_opts)
end
local mode_unsupported_focus = mode == "drop" or mode == "tab_drop" or mode == "edit_in_place"
local focus = edit_opts.focus == nil or edit_opts.focus == true
local focus = edit_opts.focus == nil or edit_opts.focus == false
if not mode_unsupported_focus and not focus then
-- if mode == "tabnew" a new tab will be opened and we need to focus back to the previous tab
if mode == "tabnew" then
@@ -445,7 +441,7 @@ end
---@param node Node
---@param mode NodeOpenFileMode
---@param toggle_group boolean?
---@param edit_opts NodeEditOpts?
---@param edit_opts nvim_tree.api.node.open.Opts?
local function open_or_expand_or_dir_up(node, mode, toggle_group, edit_opts)
local root = node:as(RootNode)
local dir = node:as(DirectoryNode)
@@ -468,18 +464,21 @@ function M.toggle_group_empty(node)
end
---@param node Node
function M.preview(node)
open_or_expand_or_dir_up(node, "preview")
---@param opts nvim_tree.api.node.open.Opts?
function M.preview(node, opts)
open_or_expand_or_dir_up(node, "preview", false, opts)
end
---@param node Node
function M.preview_no_picker(node)
open_or_expand_or_dir_up(node, "preview_no_picker")
---@param opts nvim_tree.api.node.open.Opts?
function M.preview_no_picker(node, opts)
open_or_expand_or_dir_up(node, "preview_no_picker", false, opts)
end
---@param node Node
function M.edit(node)
open_or_expand_or_dir_up(node, "edit")
---@param opts nvim_tree.api.node.open.Opts?
function M.edit(node, opts)
open_or_expand_or_dir_up(node, "edit", false, opts)
end
---@param node Node
@@ -498,33 +497,39 @@ function M.replace_tree_buffer(node)
end
---@param node Node
function M.no_window_picker(node)
open_or_expand_or_dir_up(node, "edit_no_picker")
---@param opts nvim_tree.api.node.open.Opts?
function M.no_window_picker(node, opts)
open_or_expand_or_dir_up(node, "edit_no_picker", false, opts)
end
---@param node Node
function M.vertical(node)
open_or_expand_or_dir_up(node, "vsplit")
---@param opts nvim_tree.api.node.open.Opts?
function M.vertical(node, opts)
open_or_expand_or_dir_up(node, "vsplit", false, opts)
end
---@param node Node
function M.vertical_no_picker(node)
open_or_expand_or_dir_up(node, "vsplit_no_picker")
---@param opts nvim_tree.api.node.open.Opts?
function M.vertical_no_picker(node, opts)
open_or_expand_or_dir_up(node, "vsplit_no_picker", false, opts)
end
---@param node Node
function M.horizontal(node)
open_or_expand_or_dir_up(node, "split")
---@param opts nvim_tree.api.node.open.Opts?
function M.horizontal(node, opts)
open_or_expand_or_dir_up(node, "split", false, opts)
end
---@param node Node
function M.horizontal_no_picker(node)
open_or_expand_or_dir_up(node, "split_no_picker")
---@param opts nvim_tree.api.node.open.Opts?
function M.horizontal_no_picker(node, opts)
open_or_expand_or_dir_up(node, "split_no_picker", false, opts)
end
---@param node Node
function M.tab(node)
open_or_expand_or_dir_up(node, "tabnew")
---@param opts nvim_tree.api.node.open.Opts?
function M.tab(node, opts)
open_or_expand_or_dir_up(node, "tabnew", false, opts)
end
return M

View File

@@ -136,6 +136,11 @@ end
---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)
@@ -150,14 +155,15 @@ function M.hydrate_post_setup(api)
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 = en(function(e, n) e.clipboard:copy_absolute_path(n) 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.node = ev(function(e, n) e.clipboard:copy(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)
@@ -182,10 +188,10 @@ function M.hydrate_post_setup(api)
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, opts) require("nvim-tree.actions.node.buffer").delete(n, opts) end)
api.node.buffer.wipe = _n(function(n, opts) require("nvim-tree.actions.node.buffer").wipe(n, opts) end)
api.node.collapse = _n(function(n, opts) require("nvim-tree.actions.tree.collapse").node(n, opts) end)
api.node.expand = en(function(e, n, opts) e:expand_node(n, opts) 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)
@@ -205,18 +211,21 @@ function M.hydrate_post_setup(api)
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) require("nvim-tree.actions.node.open-file").edit(n) end)
api.node.open.horizontal = _n(function(n) require("nvim-tree.actions.node.open-file").horizontal(n) end)
api.node.open.horizontal_no_picker = _n(function(n) require("nvim-tree.actions.node.open-file").horizontal_no_picker(n) end)
api.node.open.no_window_picker = _n(function(n) require("nvim-tree.actions.node.open-file").no_window_picker(n) end)
api.node.open.preview = _n(function(n) require("nvim-tree.actions.node.open-file").preview(n) end)
api.node.open.preview_no_picker = _n(function(n) require("nvim-tree.actions.node.open-file").preview_no_picker(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) require("nvim-tree.actions.node.open-file").tab(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) require("nvim-tree.actions.node.open-file").vertical(n) end)
api.node.open.vertical_no_picker = _n(function(n) require("nvim-tree.actions.node.open-file").vertical_no_picker(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)
@@ -227,22 +236,22 @@ function M.hydrate_post_setup(api)
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(opts) require("nvim-tree.actions.tree.collapse").all(opts) end)
api.tree.expand_all = en(function(e, n, opts) e:expand_all(n, opts) end)
api.tree.find_file = __(function(opts) require("nvim-tree.actions.tree.find-file").fn(opts) end)
api.tree.focus = __(function(opts) require("nvim-tree.actions.tree.open").fn(opts) 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(opts) return require("nvim-tree.view").is_visible(opts) end)
api.tree.open = __(function(opts) require("nvim-tree.actions.tree.open").fn(opts) 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(opts) require("nvim-tree.actions.tree.resize").fn(opts) 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(opts) require("nvim-tree.actions.tree.toggle").fn(opts) 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(opts) return require("nvim-tree.view").winid(opts) 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)

View File

@@ -181,15 +181,30 @@ function Explorer:create_autocmds()
end
if self.opts.modified.enable then
vim.api.nvim_create_autocmd({ "BufModifiedSet", "BufWritePost" }, {
group = self.augroup_id,
callback = function()
utils.debounce("Buf:modified_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
buffers.reload_modified()
self.renderer:draw()
end)
end,
})
local function on_modified_or_buf_write()
utils.debounce("Buf:modified_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
buffers.reload_modified()
self.renderer:draw()
end)
end
if vim.fn.has("nvim-0.13") == 1 then
vim.api.nvim_create_autocmd({ "OptionSet", }, {
group = self.augroup_id,
pattern = "modified",
callback = on_modified_or_buf_write,
})
vim.api.nvim_create_autocmd({ "BufWritePost" }, {
group = self.augroup_id,
callback = on_modified_or_buf_write,
})
else
-- BufModifiedSet event was removed in 0.13: it was a specific case of OptionSet
vim.api.nvim_create_autocmd({ "BufModifiedSet", "BufWritePost" }, { ---@diagnostic disable-line: assign-type-mismatch
group = self.augroup_id,
callback = on_modified_or_buf_write,
})
end
end
end

View File

@@ -90,7 +90,7 @@ function M.on_attach_default(bufnr)
vim.keymap.set("n", "F", api.filter.live.clear, opts("Live Filter: Clear"))
vim.keymap.set("n", "f", api.filter.live.start, opts("Live Filter: Start"))
vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help"))
vim.keymap.set("n", "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
vim.keymap.set({ "n", "x" }, "gy", api.fs.copy.absolute_path, opts("Copy Absolute Path"))
vim.keymap.set("n", "ge", api.fs.copy.basename, opts("Copy Basename"))
vim.keymap.set("n", "H", api.filter.dotfiles.toggle, opts("Toggle Filter: Dotfiles"))
vim.keymap.set("n", "I", api.filter.git.ignored.toggle, opts("Toggle Filter: Git Ignored"))
@@ -102,6 +102,7 @@ function M.on_attach_default(bufnr)
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
vim.keymap.set("n", "O", api.node.open.no_window_picker, opts("Open: No Window Picker"))
vim.keymap.set("n", "p", api.fs.paste, opts("Paste"))
vim.keymap.set("n", "gp", api.fs.move, opts("Move"))
vim.keymap.set("n", "P", api.node.navigate.parent, opts("Parent Directory"))
vim.keymap.set("n", "q", api.tree.close, opts("Close"))
vim.keymap.set("n", "r", api.fs.rename, opts("Rename"))

View File

@@ -76,6 +76,7 @@ function M.show()
height = 1,
noautocmd = true,
style = "minimal",
zindex = 40,
border = "none"
})
vim.wo[M.popup_win].winhl = view_state.Active.winopts.winhl

View File

@@ -1,26 +1,17 @@
#!/usr/bin/env sh
# Wrapper around Nvim make targets:
# Wrapper around Nvim make doc target:
#
# make doc - gen_vimdoc.lua
# Generates doc/nvim-tree-lua.txt
# Uses nvim-tree sources defined in scripts/vimdoc_config.lua
# Shims above into src/gen/gen_vimdoc.lua, replacing Nvim's config.
#
# make lintdoc - lintdoc.lua
# Validates doc/nvim-tree-lua.txt
# Desired:
# - tags valid
# - links valid
# Also:
# - brand spelling, notably Nvim and Lua
# Generates doc/nvim-tree-lua.txt
# Uses nvim-tree sources defined in scripts/vimdoc_config.lua
# Shims above into src/gen/gen_vimdoc.lua, replacing Nvim's config.
#
# There are some hardcoded expectations which we work around as commented.
set -e
if [ $# -ne 1 ] || [ "${1}" != "doc" ] && [ "${1}" != "lintdoc" ]; then
echo "usage: ${0} <doc|lintdoc>" 1>&2
if [ $# -ne 1 ] || [ "${1}" != "doc" ]; then
echo "usage: ${0} <doc>" 1>&2
exit 1
fi
@@ -38,7 +29,7 @@ fi
if [ ! -d "${DIR_NVIM_SRC}" ]; then
cat << EOM
Nvim source v0.11+ is required to run ${0}
Nvim stable source is required to run ${0}
Unavailable: ${DIR_NVIM_SRC_DEF} or \$DIR_NVIM_SRC=${DIR_NVIM_SRC}
@@ -84,7 +75,15 @@ if [ "${1}" = "doc" ]; then
# modify gen_vimdoc.lua to use our config, backing up original
cp "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua" "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua.org"
sed -i -E 's/spairs\(config\)/spairs\(require("gen.vimdoc_config")\)/g' "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua"
sed -i -E '
# use our config
s/spairs\(config\)/spairs\(require("gen.vimdoc_config") --[[injected by nvim-tree]]\)/g ;
# remove the name linter
s/(^run\(\)$)/\n--injected by nvim-tree\nlint.lint_names = function\(\)\nend\n\n\1 --/g
' "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua"
# leave a generic placeholder to bridge between nvim.gen_vimdoc.Config
echo "---@brief placeholder" > "${DIR_NVIM_SRC}/runtime/lua/placeholder.lua"