mirror of
https://github.com/nvim-tree/nvim-tree.lua.git
synced 2026-07-28 15:59:44 +05:30
Compare commits
191 Commits
nvim-tree-
...
27aeba9b03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27aeba9b03 | ||
|
|
cf18a662cd | ||
|
|
a797d5e201 | ||
|
|
35d3511e7a | ||
|
|
7ff7040bf6 | ||
|
|
531b807b8f | ||
|
|
c760c92667 | ||
|
|
0d1176b4c5 | ||
|
|
8e8be709c9 | ||
|
|
85a743b8f1 | ||
|
|
68992ee244 | ||
|
|
fb343438d4 | ||
|
|
82f58063d6 | ||
|
|
07f541fcaa | ||
|
|
f9bfc0059e | ||
|
|
24cfcc9437 | ||
|
|
5f65bd3d93 | ||
|
|
5a1d08bc0c | ||
|
|
d277467fc0 | ||
|
|
509962f21a | ||
|
|
85d1145ac7 | ||
|
|
7adc5679fe | ||
|
|
31503ad5d8 | ||
|
|
02ccbcd4af | ||
|
|
3603f069ff | ||
|
|
4cbe79526f | ||
|
|
b548cfef00 | ||
|
|
ec0efb06b0 | ||
|
|
43a3bb4b26 | ||
|
|
6eaf74c991 | ||
|
|
3d385d3346 | ||
|
|
f37ebac811 | ||
|
|
dfeeb12aaa | ||
|
|
e16cd38962 | ||
|
|
2eefa8303b | ||
|
|
b3772adec8 | ||
|
|
9197f3ee3f | ||
|
|
e1ad8b9683 | ||
|
|
4b30847c91 | ||
|
|
c8d8d515c2 | ||
|
|
c988e28942 | ||
|
|
018a078c1e | ||
|
|
ae16aab5fd | ||
|
|
87594aa7c8 | ||
|
|
e49b0d9bfa | ||
|
|
1b5d96696b | ||
|
|
5499299746 | ||
|
|
e11ce83ed9 | ||
|
|
5dd95eaa23 | ||
|
|
fa3c45875f | ||
|
|
516f95e8ef | ||
|
|
1df1960d0e | ||
|
|
2f1010ca77 | ||
|
|
0f4d2d6998 | ||
|
|
118057ebd2 | ||
|
|
c0b18e4879 | ||
|
|
037d89e60f | ||
|
|
c07ce43527 | ||
|
|
89d9621aa4 | ||
|
|
b93dbb9b58 | ||
|
|
1701e41b07 | ||
|
|
5757bcf044 | ||
|
|
869fc957ed | ||
|
|
ca8d82fff2 | ||
|
|
a0db8bf7d6 | ||
|
|
c89215d6a1 | ||
|
|
e66994d40d | ||
|
|
b8b44b6a24 | ||
|
|
b63d3679a8 | ||
|
|
8298117311 | ||
|
|
eb33612bff | ||
|
|
59088b96a3 | ||
|
|
776a5cdfac | ||
|
|
3fb91e18a7 | ||
|
|
81ede55c47 | ||
|
|
1eda256939 | ||
|
|
68c67adfab | ||
|
|
64e2192f52 | ||
|
|
e397756d2a | ||
|
|
87d096a39c | ||
|
|
01b2e8e5f7 | ||
|
|
e179ad2f83 | ||
|
|
f92cc3a91c | ||
|
|
fefa335f1c | ||
|
|
b70a741f5a | ||
|
|
f4fa6ebd3c | ||
|
|
f0e9951778 | ||
|
|
feb901a09e | ||
|
|
321bc61580 | ||
|
|
442513648c | ||
|
|
000ca6bcdd | ||
|
|
1b876db049 | ||
|
|
0a52012d61 | ||
|
|
a4699c0904 | ||
|
|
9b289abd69 | ||
|
|
dd2364d680 | ||
|
|
9a05b9e9f9 | ||
|
|
0a7fcdf3f8 | ||
|
|
65bae44922 | ||
|
|
a9156c0139 | ||
|
|
10db6943cb | ||
|
|
543ed3cac2 | ||
|
|
2a386fe567 | ||
|
|
b0b49552c9 | ||
|
|
8eb5e0bfd1 | ||
|
|
0a06f65bf0 | ||
|
|
d54a1875a9 | ||
|
|
aa087788d7 | ||
|
|
d87b41ca53 | ||
|
|
6b5b366596 | ||
|
|
ae595611fb | ||
|
|
05d8172ebf | ||
|
|
1c733e8c19 | ||
|
|
ebcaccda1c | ||
|
|
cbc3165e08 | ||
|
|
bd54d1d33c | ||
|
|
25d16aab7d | ||
|
|
e4cd856ebf | ||
|
|
e7d1b7dadc | ||
|
|
ea5097a1e2 | ||
|
|
582ae48c9e | ||
|
|
be5b788f2d | ||
|
|
64bb47f868 | ||
|
|
c24c0470d9 | ||
|
|
3a63717d3d | ||
|
|
5bea2b3752 | ||
|
|
c3c1935942 | ||
|
|
44d9b58f11 | ||
|
|
c09ff35de5 | ||
|
|
6709463b2d | ||
|
|
b69914325a | ||
|
|
3281f331f7 | ||
|
|
80523101f0 | ||
|
|
70825f23db | ||
|
|
d05881f65f | ||
|
|
fee1da8897 | ||
|
|
db7403243d | ||
|
|
fca0b67c0b | ||
|
|
d529a99f88 | ||
|
|
39bc630816 | ||
|
|
aae01853dd | ||
|
|
68fc4c20f5 | ||
|
|
f7b76cd1a7 | ||
|
|
c3d9b1779f | ||
|
|
db8d7ac1f5 | ||
|
|
6b4be1dc0c | ||
|
|
375e38673b | ||
|
|
7a4ff1a516 | ||
|
|
ca7c4c33ca | ||
|
|
1f3ffd6af1 | ||
|
|
f7c65e11d6 | ||
|
|
28eac2801b | ||
|
|
c7639482a1 | ||
|
|
2ee1c5e17f | ||
|
|
3fc8de198c | ||
|
|
610a1c189b | ||
|
|
c22124b374 | ||
|
|
2156bc08c9 | ||
|
|
82ab19ebf7 | ||
|
|
120ba58254 | ||
|
|
00dff482f9 | ||
|
|
8f974879a0 | ||
|
|
14039337a5 | ||
|
|
e4bc05b415 | ||
|
|
3cddd28177 | ||
|
|
6e5a204ca6 | ||
|
|
f3efc25e56 | ||
|
|
8760d76c1d | ||
|
|
077af9f990 | ||
|
|
68be6df2fc | ||
|
|
63c7ad9037 | ||
|
|
9b82ff9bba | ||
|
|
2a268f631d | ||
|
|
f5f6789299 | ||
|
|
ce09bfb95f | ||
|
|
0fede9f813 | ||
|
|
1c9553a19f | ||
|
|
ca0904e4c5 | ||
|
|
5ad87620ec | ||
|
|
50e919426a | ||
|
|
010ae0365a | ||
|
|
38aac09151 | ||
|
|
c9104a5d07 | ||
|
|
4a9e82d10a | ||
|
|
4520c0355c | ||
|
|
1ae1c33ce1 | ||
|
|
9650e735ba | ||
|
|
59a8a6ae5e | ||
|
|
0429f286b3 | ||
|
|
8405ecfbd6 | ||
|
|
0ae9ad4ded |
@@ -4,9 +4,21 @@ root = true
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[nvim-tree-lua.txt]
|
||||
max_line_length = 78
|
||||
|
||||
# keep these in sync with .luarc.json
|
||||
# .editorconfig is used within nvim, overriding .luarc.json
|
||||
# .luarc.json is used by style check
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
max_line_length = 140
|
||||
indent_size = 2
|
||||
|
||||
# EmmyLuaCodeStyle specific, see
|
||||
# https://github.com/CppCXY/EmmyLuaCodeStyle/blob/master/lua.template.editorconfig
|
||||
continuation_indent = 2
|
||||
quote_style = double
|
||||
call_arg_parentheses = always
|
||||
space_before_closure_open_parenthesis = false
|
||||
align_continuous_similar_call_args = true
|
||||
|
||||
22
.github/ISSUE_TEMPLATE/nvt-min.lua
vendored
22
.github/ISSUE_TEMPLATE/nvt-min.lua
vendored
@@ -1,12 +1,12 @@
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
|
||||
vim.cmd [[set runtimepath=$VIMRUNTIME]]
|
||||
vim.cmd [[set packpath=/tmp/nvt-min/site]]
|
||||
vim.cmd([[set runtimepath=$VIMRUNTIME]])
|
||||
vim.cmd([[set packpath=/tmp/nvt-min/site]])
|
||||
local package_root = "/tmp/nvt-min/site/pack"
|
||||
local install_path = package_root .. "/packer/start/packer.nvim"
|
||||
local function load_plugins()
|
||||
require("packer").startup {
|
||||
require("packer").startup({
|
||||
{
|
||||
"wbthomason/packer.nvim",
|
||||
"nvim-tree/nvim-tree.lua",
|
||||
@@ -18,21 +18,21 @@ local function load_plugins()
|
||||
compile_path = install_path .. "/plugin/packer_compiled.lua",
|
||||
display = { non_interactive = true },
|
||||
},
|
||||
}
|
||||
})
|
||||
end
|
||||
if vim.fn.isdirectory(install_path) == 0 then
|
||||
print "Installing nvim-tree and dependencies."
|
||||
vim.fn.system { "git", "clone", "--depth=1", "https://github.com/wbthomason/packer.nvim", install_path }
|
||||
print("Installing nvim-tree and dependencies.")
|
||||
vim.fn.system({ "git", "clone", "--depth=1", "https://github.com/wbthomason/packer.nvim", install_path })
|
||||
end
|
||||
load_plugins()
|
||||
require("packer").sync()
|
||||
vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua setup()]]
|
||||
vim.cmd([[autocmd User PackerComplete ++once echo "Ready!" | lua setup()]])
|
||||
vim.opt.termguicolors = true
|
||||
vim.opt.cursorline = true
|
||||
|
||||
-- MODIFY NVIM-TREE SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
|
||||
_G.setup = function()
|
||||
require("nvim-tree").setup {}
|
||||
require("nvim-tree").setup({})
|
||||
end
|
||||
|
||||
-- UNCOMMENT this block for diagnostics issues, substituting pattern and cmd as appropriate.
|
||||
@@ -41,7 +41,11 @@ end
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "lua",
|
||||
callback = function()
|
||||
vim.lsp.start { cmd = { "lua-language-server" } }
|
||||
vim.lsp.start {
|
||||
name = "my-luals",
|
||||
cmd = { "lua-language-server" },
|
||||
root_dir = vim.loop.cwd(),
|
||||
}
|
||||
end,
|
||||
})
|
||||
]]
|
||||
|
||||
82
.github/workflows/ci.yml
vendored
82
.github/workflows/ci.yml
vendored
@@ -5,6 +5,8 @@ on:
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly on sundays
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -20,73 +22,79 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
lua_version: [ 5.1 ]
|
||||
luacheck_version: [ 1.2.0 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- uses: leafo/gh-actions-lua@v10
|
||||
- name: install lua ${{ matrix.lua_version }}
|
||||
uses: leafo/gh-actions-lua@v13
|
||||
with:
|
||||
luaVersion: ${{ matrix.lua_version }}
|
||||
|
||||
- uses: leafo/gh-actions-luarocks@v4
|
||||
- name: install luarocks
|
||||
uses: leafo/gh-actions-luarocks@v6
|
||||
|
||||
- run: luarocks install luacheck 1.1.1
|
||||
- name: install luacheck ${{ matrix.luacheck_version }}
|
||||
run: luarocks install luacheck ${{ matrix.luacheck_version }}
|
||||
|
||||
- run: make lint
|
||||
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ matrix.stylua_version }}-${{ github.head_ref || github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
stylua_version: [ 0.19.1 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: stylua
|
||||
uses: JohnnyMorganz/stylua-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ matrix.stylua_version }}
|
||||
args: --check lua
|
||||
|
||||
- run: make style-doc
|
||||
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ matrix.nvim_version }}-${{ matrix.luals_version }}-${{ github.head_ref || github.ref_name }}
|
||||
group: ${{ github.workflow }}-${{ matrix.nvim_version }}-${{ matrix.luals_version }}-${{ matrix.emmyluacodestyle_version }}-${{ github.head_ref || github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
nvim_version: [ stable, nightly ]
|
||||
luals_version: [ 3.10.5 ]
|
||||
luals_version: [ 3.15.0 ]
|
||||
emmyluacodestyle_version: [ 1.6.0 ]
|
||||
|
||||
env:
|
||||
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
|
||||
DIR_NVIM_SRC: /home/runner/src/neovim-${{ matrix.nvim_version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- uses: rhysd/action-setup-vim@v1
|
||||
- name: install nvim ${{ matrix.nvim_version }}
|
||||
uses: rhysd/action-setup-vim@v1
|
||||
with:
|
||||
neovim: true
|
||||
version: ${{ matrix.nvim_version }}
|
||||
|
||||
- name: install luals
|
||||
- name: install lua-language-server ${{ matrix.luals_version }}
|
||||
run: |
|
||||
mkdir -p luals
|
||||
curl -L "https://github.com/LuaLS/lua-language-server/releases/download/${{ matrix.luals_version }}/lua-language-server-${{ matrix.luals_version }}-linux-x64.tar.gz" | tar zx --directory luals
|
||||
echo "luals/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- run: echo "luals/bin" >> "$GITHUB_PATH"
|
||||
- name: install EmmyLuaCodeStyle ${{ matrix.emmyluacodestyle_version }}
|
||||
run: |
|
||||
mkdir -p EmmyLuaCodeStyle
|
||||
curl -L "https://github.com/CppCXY/EmmyLuaCodeStyle/releases/download/${{ matrix.emmyluacodestyle_version }}/linux-x64.tar.gz" | tar zx --directory EmmyLuaCodeStyle
|
||||
echo "EmmyLuaCodeStyle/linux-x64/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: make check
|
||||
env:
|
||||
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
|
||||
run: make check
|
||||
- run: make check
|
||||
|
||||
- run: make style
|
||||
|
||||
- run: make style-doc
|
||||
|
||||
- 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
|
||||
|
||||
- run: make help-check
|
||||
if: ${{ matrix.nvim_version == 'stable' }}
|
||||
|
||||
6
.github/workflows/luarocks-release.yml
vendored
6
.github/workflows/luarocks-release.yml
vendored
@@ -1,14 +1,16 @@
|
||||
name: Luarocks Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
luarocks-upload:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: LuaRocks Upload
|
||||
uses: nvim-neorocks/luarocks-tag-release@v7
|
||||
env:
|
||||
|
||||
6
.github/workflows/release-please.yml
vendored
6
.github/workflows/release-please.yml
vendored
@@ -14,15 +14,15 @@ jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
- uses: googleapis/release-please-action@v5
|
||||
id: release
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: tag major and minor versions
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
run: |
|
||||
git config user.name github-actions[bot]
|
||||
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||
git remote add gh-token "https://${{ secrets.GITHUB_TOKEN }}@github.com/google-github-actions/release-please-action.git"
|
||||
git remote add gh-token "https://${{ secrets.GITHUB_TOKEN }}@github.com/googleapis/release-please-action.git"
|
||||
git tag -d v${{ steps.release.outputs.major }} || true
|
||||
git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true
|
||||
git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} || true
|
||||
|
||||
2
.github/workflows/semantic-pr-subject.yml
vendored
2
.github/workflows/semantic-pr-subject.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
||||
semantic-pr-subject:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5.5.3
|
||||
- uses: amannn/action-semantic-pull-request@v6.1.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
make
|
||||
|
||||
11
.luacheckrc
11
.luacheckrc
@@ -1,14 +1,15 @@
|
||||
-- vim: ft=lua tw=80
|
||||
local M = {}
|
||||
|
||||
-- Don't report unused self arguments of methods.
|
||||
self = false
|
||||
M.self = false
|
||||
|
||||
ignore = {
|
||||
M.ignore = {
|
||||
"631", -- max_line_length
|
||||
}
|
||||
|
||||
-- Global objects defined by the C code
|
||||
globals = {
|
||||
M.globals = {
|
||||
"vim",
|
||||
"TreeExplorer"
|
||||
}
|
||||
|
||||
return M
|
||||
|
||||
16
.luarc.json
16
.luarc.json
@@ -7,6 +7,18 @@
|
||||
"${3rd}/luv/library"
|
||||
]
|
||||
},
|
||||
"format": {
|
||||
"defaultConfig": {
|
||||
"indent_style": "space",
|
||||
"max_line_length": "140",
|
||||
"indent_size": "2",
|
||||
"continuation_indent": "2",
|
||||
"quote_style": "double",
|
||||
"call_arg_parentheses": "always",
|
||||
"space_before_closure_open_parenthesis": "false",
|
||||
"align_continuous_similar_call_args": "true"
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"libraryFiles": "Disable",
|
||||
"globals": [],
|
||||
@@ -33,13 +45,13 @@
|
||||
"empty-block": "Any",
|
||||
"global-element": "Any",
|
||||
"global-in-nil-env": "Any",
|
||||
"incomplete-signature-doc": "None",
|
||||
"incomplete-signature-doc": "Any",
|
||||
"inject-field": "Any",
|
||||
"invisible": "Any",
|
||||
"lowercase-global": "Any",
|
||||
"missing-fields": "Any",
|
||||
"missing-global-doc": "Any",
|
||||
"missing-local-export-doc": "None",
|
||||
"missing-local-export-doc": "Any",
|
||||
"missing-parameter": "Any",
|
||||
"missing-return": "Any",
|
||||
"missing-return-value": "Any",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "1.7.0"
|
||||
".": "1.18.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
column_width = 140
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferDouble"
|
||||
call_parentheses = "None"
|
||||
255
CHANGELOG.md
255
CHANGELOG.md
@@ -1,5 +1,260 @@
|
||||
# Changelog
|
||||
|
||||
## [1.18.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.17.0...nvim-tree-v1.18.0) (2026-07-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#1549:** p will paste files from another nvim-tree instance, gp will cut/paste ([#3336](https://github.com/nvim-tree/nvim-tree.lua/issues/3336)) ([c760c92](https://github.com/nvim-tree/nvim-tree.lua/commit/c760c92667fe5febf99e2a5bb8a543b0208c743b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3312:** correct cursor when full name shown, requires nvim 0.12.2+ ([#3316](https://github.com/nvim-tree/nvim-tree.lua/issues/3316)) ([d277467](https://github.com/nvim-tree/nvim-tree.lua/commit/d277467fc0d1d0e2bca88165a1de6b526f9f6fe8))
|
||||
* **#3324:** deprecated BufModifiedSet event replaced by OptionSet event for Nvim 0.13+ ([#3325](https://github.com/nvim-tree/nvim-tree.lua/issues/3325)) ([f9bfc00](https://github.com/nvim-tree/nvim-tree.lua/commit/f9bfc0059eca24546b69a7006110463da4808f8f))
|
||||
* **#3327:** pass nvim_tree.api.node.open.Opts to all applicable nvim_tree.api.node.open function ([#3329](https://github.com/nvim-tree/nvim-tree.lua/issues/3329)) ([07f541f](https://github.com/nvim-tree/nvim-tree.lua/commit/07f541fcaa4a5ae019598240362449ab7e9812b3))
|
||||
* **full-name:** lower `zindex` to get consistent cursor shape ([d277467](https://github.com/nvim-tree/nvim-tree.lua/commit/d277467fc0d1d0e2bca88165a1de6b526f9f6fe8))
|
||||
|
||||
## [1.17.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.16.0...nvim-tree-v1.17.0) (2026-04-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#3292:** add nvim_tree.config.filesystem_watchers.whitelist_dirs - strongly recommended for windows ([#3298](https://github.com/nvim-tree/nvim-tree.lua/issues/3298)) ([6eaf74c](https://github.com/nvim-tree/nvim-tree.lua/commit/6eaf74c9919d121d2806ac3c20e757e66bd29c31))
|
||||
* **#3310:** minimum neovim version 0.10 ([#3311](https://github.com/nvim-tree/nvim-tree.lua/issues/3311)) ([7adc567](https://github.com/nvim-tree/nvim-tree.lua/commit/7adc5679feb439275255aa9e95c434cca206d10c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3257:** error when calling api.tree.find_file ([#3304](https://github.com/nvim-tree/nvim-tree.lua/issues/3304)) ([b548cfe](https://github.com/nvim-tree/nvim-tree.lua/commit/b548cfef00a79f0b3e3af24f91ae6bd14f22af95))
|
||||
* **#3293:** marks.bulk operations filter descendant nodes ([#3294](https://github.com/nvim-tree/nvim-tree.lua/issues/3294)) ([f37ebac](https://github.com/nvim-tree/nvim-tree.lua/commit/f37ebac81164e1445c499cdd6de86e6d8e5d57e4))
|
||||
* **#3301:** setup with empty config fails ([#3303](https://github.com/nvim-tree/nvim-tree.lua/issues/3303)) ([ec0efb0](https://github.com/nvim-tree/nvim-tree.lua/commit/ec0efb06b0abfa56492acfc8c34ac8958d18601e))
|
||||
* system open native requires nvim 0.10 ([#3309](https://github.com/nvim-tree/nvim-tree.lua/issues/3309)) ([02ccbcd](https://github.com/nvim-tree/nvim-tree.lua/commit/02ccbcd4af9a7fa159251f721d763c0d16f91703))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **#3231:** decrease setup time: optimise setup and defer requires until tree open ([#3308](https://github.com/nvim-tree/nvim-tree.lua/issues/3308)) ([31503ad](https://github.com/nvim-tree/nvim-tree.lua/commit/31503ad5d869fca61461d82a9126f62480ecb0ab))
|
||||
* **#3257:** remove setup for actions modules, full-name and explorer ([#3299](https://github.com/nvim-tree/nvim-tree.lua/issues/3299)) ([43a3bb4](https://github.com/nvim-tree/nvim-tree.lua/commit/43a3bb4b26b4578a704f24bb6a4889b454c0eb65))
|
||||
* **#3257:** remove setup for modules: buffers, diagnostics, git, help, keymap, lib, watcher ([#3295](https://github.com/nvim-tree/nvim-tree.lua/issues/3295)) ([3d385d3](https://github.com/nvim-tree/nvim-tree.lua/commit/3d385d3346e4883d60dc37cf642bd47bed78a46e))
|
||||
* **#3257:** remove setup for renderer, log, appearance ([#3307](https://github.com/nvim-tree/nvim-tree.lua/issues/3307)) ([3603f06](https://github.com/nvim-tree/nvim-tree.lua/commit/3603f069ff783c31986894a56c2a6755331b0802))
|
||||
* **#3257:** remove setup for view, extracting view-state ([#3306](https://github.com/nvim-tree/nvim-tree.lua/issues/3306)) ([4cbe795](https://github.com/nvim-tree/nvim-tree.lua/commit/4cbe79526f8bc0bdb1a500d261dc5cc1be4e77d5))
|
||||
|
||||
## [1.16.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.15.0...nvim-tree-v1.16.0) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#2994:** add visual mode operations: copy, cut, delete, trash, toggle bookmark ([#3268](https://github.com/nvim-tree/nvim-tree.lua/issues/3268)) ([9197f3e](https://github.com/nvim-tree/nvim-tree.lua/commit/9197f3ee3f0c9a754aab5b16500db6d7da5f68fd))
|
||||
* add default <Del> mapping for api.fs.remove ([#3238](https://github.com/nvim-tree/nvim-tree.lua/issues/3238)) ([ca8d82f](https://github.com/nvim-tree/nvim-tree.lua/commit/ca8d82fff26cb12ced239713e3222f4a9dcd0da0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **##3288:** restore single-item paste conflict prompts ([#3289](https://github.com/nvim-tree/nvim-tree.lua/issues/3289)) ([b3772ad](https://github.com/nvim-tree/nvim-tree.lua/commit/b3772adec8db61ba9098c5624a0823a77be3a23d))
|
||||
* **#3178:** handle Windows paths in ignore_dirs and add .zig-cache to defaults ([#3261](https://github.com/nvim-tree/nvim-tree.lua/issues/3261)) ([5499299](https://github.com/nvim-tree/nvim-tree.lua/commit/5499299746b95c49ef4fc89b30c29a79b577881f))
|
||||
* **#3187:** prevent closing the last non-floating window when deleting files ([#3282](https://github.com/nvim-tree/nvim-tree.lua/issues/3282)) ([018a078](https://github.com/nvim-tree/nvim-tree.lua/commit/018a078c1e149bcd0c4e65c92aabb8e12501d769))
|
||||
* **#3198:** add filesystem_watchers.max_events to handle runaway filesystem events on PowerShell ([#3232](https://github.com/nvim-tree/nvim-tree.lua/issues/3232)) ([c07ce43](https://github.com/nvim-tree/nvim-tree.lua/commit/c07ce43527e5f0242121f4eb1feb7ac0ecea8275))
|
||||
* **#3248:** bookmark filter shows contents of marked directories ([#3249](https://github.com/nvim-tree/nvim-tree.lua/issues/3249)) ([5757bcf](https://github.com/nvim-tree/nvim-tree.lua/commit/5757bcf0447d22d8f78826bc5c59b28da2824c3b))
|
||||
* **#3251:** pass git.timeout to all vim.system git calls ([#3277](https://github.com/nvim-tree/nvim-tree.lua/issues/3277)) ([e49b0d9](https://github.com/nvim-tree/nvim-tree.lua/commit/e49b0d9bfa70989cf8b5abf5557f51e6e57f68d6))
|
||||
* **#3265:** rename module api.health to api.appearance, to avoid :checkhealth detection ([#3266](https://github.com/nvim-tree/nvim-tree.lua/issues/3266)) ([1df1960](https://github.com/nvim-tree/nvim-tree.lua/commit/1df1960d0e3a26643a4100f64fa03b991b9f4b85))
|
||||
* **#3267:** renderer.icons.*_placement 'right_align' at the right hand edge, not the right of the name ([#3270](https://github.com/nvim-tree/nvim-tree.lua/issues/3270)) ([fa3c458](https://github.com/nvim-tree/nvim-tree.lua/commit/fa3c45875f9b1f56ace57711c6f2ac22484ed956))
|
||||
* **#3281:** fix a bug when a view width of -1 is returned from a function ([#3283](https://github.com/nvim-tree/nvim-tree.lua/issues/3283)) ([c988e28](https://github.com/nvim-tree/nvim-tree.lua/commit/c988e289428d9202b28ba27479647033c7dd2956))
|
||||
* allow 0 (unlimited) filesystem_watchers.max_events which is the new default, except for windows at 1000 ([#3279](https://github.com/nvim-tree/nvim-tree.lua/issues/3279)) ([87594aa](https://github.com/nvim-tree/nvim-tree.lua/commit/87594aa7c8808701b418b285e9adf690acead201))
|
||||
* increase filesystem_watchers.max_events from 100 to 1000 ([#3263](https://github.com/nvim-tree/nvim-tree.lua/issues/3263)) ([0f4d2d6](https://github.com/nvim-tree/nvim-tree.lua/commit/0f4d2d6998dc324d54d6adce94186bee43725afb))
|
||||
* restore bookmark filter for marked directories ([5757bcf](https://github.com/nvim-tree/nvim-tree.lua/commit/5757bcf0447d22d8f78826bc5c59b28da2824c3b))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **#3284:** re-draw instead of refreshing the tree when a buffer is modified ([#3285](https://github.com/nvim-tree/nvim-tree.lua/issues/3285)) ([c8d8d51](https://github.com/nvim-tree/nvim-tree.lua/commit/c8d8d515c29f0f0b1a352e0d75616f74f42fc03b))
|
||||
|
||||
## [1.15.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.14.0...nvim-tree-v1.15.0) (2026-01-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#1826:** add diagnostics.diagnostic_opts: vim.diagnostic.Opts will override diagnostics.severity and diagnostics.icons ([#3190](https://github.com/nvim-tree/nvim-tree.lua/issues/3190)) ([fefa335](https://github.com/nvim-tree/nvim-tree.lua/commit/fefa335f1c8f690eb668a1efd18ee4fc6d64cd3e))
|
||||
* **#1851:** add bookmarks.persist, default path: vim.fn.stdpath("data") .. "/nvim-tree-bookmarks.json", disabled by default ([#3033](https://github.com/nvim-tree/nvim-tree.lua/issues/3033)) ([c89215d](https://github.com/nvim-tree/nvim-tree.lua/commit/c89215d6a1107a3c0c134750be48657ba8e6a9aa))
|
||||
* **#3213:** add `view.width.lines_excluded` option ([776a5cd](https://github.com/nvim-tree/nvim-tree.lua/commit/776a5cdfac948b490e06f1d1d22c4cb986e40699))
|
||||
* **#3213:** add view.width.lines_excluded option ([#3214](https://github.com/nvim-tree/nvim-tree.lua/issues/3214)) ([776a5cd](https://github.com/nvim-tree/nvim-tree.lua/commit/776a5cdfac948b490e06f1d1d22c4cb986e40699))
|
||||
* add NvimTreeFilter filetype ([64e2192](https://github.com/nvim-tree/nvim-tree.lua/commit/64e2192f5250796aa4a7f33c6ad888515af50640))
|
||||
* load command definitions at nvim startup ([#3211](https://github.com/nvim-tree/nvim-tree.lua/issues/3211)) ([1eda256](https://github.com/nvim-tree/nvim-tree.lua/commit/1eda2569394f866360e61f590f1796877388cb8a))
|
||||
* load command definitions in `plugin` directory ([1eda256](https://github.com/nvim-tree/nvim-tree.lua/commit/1eda2569394f866360e61f590f1796877388cb8a))
|
||||
* set filter input filetype to NvimTreeFilter ([#3207](https://github.com/nvim-tree/nvim-tree.lua/issues/3207)) ([64e2192](https://github.com/nvim-tree/nvim-tree.lua/commit/64e2192f5250796aa4a7f33c6ad888515af50640))
|
||||
* use `add_trailing` also for symlink destination ([81ede55](https://github.com/nvim-tree/nvim-tree.lua/commit/81ede55c47528ff7c81b2a498fbee61b298c4e2f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3226:** set &swapfile=false before setting tree buffer name, avoiding any potential collisions with a swapfile ([#3227](https://github.com/nvim-tree/nvim-tree.lua/issues/3227)) ([8298117](https://github.com/nvim-tree/nvim-tree.lua/commit/8298117311a1f23f039c278e4e4977ab80a15e33))
|
||||
* api.tree.change_root_to_node on a file now changes directory to parent as per documentation ([#3228](https://github.com/nvim-tree/nvim-tree.lua/issues/3228)) ([b8b44b6](https://github.com/nvim-tree/nvim-tree.lua/commit/b8b44b6a2494d086a9177251a119f9daec6cace8))
|
||||
* correctly assign extmarks to lines when computing tree window width in `grow` when `nvim-tree.view.width.lines_excluded` contains "root" ([e66994d](https://github.com/nvim-tree/nvim-tree.lua/commit/e66994d40db2d57c91bf9aeaee8bf7ab8b1131f6))
|
||||
* incorrect window width when right_align icons present ([#3239](https://github.com/nvim-tree/nvim-tree.lua/issues/3239)) ([e66994d](https://github.com/nvim-tree/nvim-tree.lua/commit/e66994d40db2d57c91bf9aeaee8bf7ab8b1131f6))
|
||||
* prevent NvimTree to be alternate buffer when tab open ([#3205](https://github.com/nvim-tree/nvim-tree.lua/issues/3205)) ([e397756](https://github.com/nvim-tree/nvim-tree.lua/commit/e397756d2a79d74314ea4cd3efc41300e91c0ff0))
|
||||
* renderer.add_trailing applies to symlink destination ([#3217](https://github.com/nvim-tree/nvim-tree.lua/issues/3217)) ([81ede55](https://github.com/nvim-tree/nvim-tree.lua/commit/81ede55c47528ff7c81b2a498fbee61b298c4e2f))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **commands:** defer module loading ([#3210](https://github.com/nvim-tree/nvim-tree.lua/issues/3210)) ([68c67ad](https://github.com/nvim-tree/nvim-tree.lua/commit/68c67adfabfd1ce923839570507ef2e81ab8a408))
|
||||
|
||||
## [1.14.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.13.0...nvim-tree-v1.14.0) (2025-08-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#2685:** highlight git new tracked with NvimTreeGitFileNewHL ([#3176](https://github.com/nvim-tree/nvim-tree.lua/issues/3176)) ([0a52012](https://github.com/nvim-tree/nvim-tree.lua/commit/0a52012d611f3c1492b8d2aba363fabf734de91d))
|
||||
* **#2789:** add optional function expand_until to api.tree.expand_all and api.node.expand ([#3166](https://github.com/nvim-tree/nvim-tree.lua/issues/3166)) ([1b876db](https://github.com/nvim-tree/nvim-tree.lua/commit/1b876db04903b93c78c97fd3f3dd85d59eeef5ff))
|
||||
* **#2826:** allow only one window with nvim-tree buffer per tab ([#3174](https://github.com/nvim-tree/nvim-tree.lua/issues/3174)) ([dd2364d](https://github.com/nvim-tree/nvim-tree.lua/commit/dd2364d6802f7f57a98acb8b545ed484c6697626))
|
||||
* **#3157:** add view.cursorlineopt ([#3158](https://github.com/nvim-tree/nvim-tree.lua/issues/3158)) ([8eb5e0b](https://github.com/nvim-tree/nvim-tree.lua/commit/8eb5e0bfd1c4da6efc03ab0c1ccf463dbaae831e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3077:** deleting a directory containing symlinked directory will delete the contents of the linked directory ([#3168](https://github.com/nvim-tree/nvim-tree.lua/issues/3168)) ([10db694](https://github.com/nvim-tree/nvim-tree.lua/commit/10db6943cb40625941a35235eeb385ffdfbf827a))
|
||||
* **#3157:** add view.cursorlineopt ([8eb5e0b](https://github.com/nvim-tree/nvim-tree.lua/commit/8eb5e0bfd1c4da6efc03ab0c1ccf463dbaae831e))
|
||||
* **#3172:** live filter exception ([#3173](https://github.com/nvim-tree/nvim-tree.lua/issues/3173)) ([0a7fcdf](https://github.com/nvim-tree/nvim-tree.lua/commit/0a7fcdf3f8ba208f4260988a198c77ec11748339))
|
||||
* invalid window id for popup info window ([#3147](https://github.com/nvim-tree/nvim-tree.lua/issues/3147)) ([d54a187](https://github.com/nvim-tree/nvim-tree.lua/commit/d54a1875a91e1a705795ea26074795210b92ce7f))
|
||||
* **picker:** exclude full_name window id from the choice ([#3165](https://github.com/nvim-tree/nvim-tree.lua/issues/3165)) ([543ed3c](https://github.com/nvim-tree/nvim-tree.lua/commit/543ed3cac212dc3993ef9f042f6c0812e34ddd43))
|
||||
* window picker ignore hidden window ([#3145](https://github.com/nvim-tree/nvim-tree.lua/issues/3145)) ([d87b41c](https://github.com/nvim-tree/nvim-tree.lua/commit/d87b41ca537e2131622d48a6c25ccf2fbe0e5d62))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **#3171:** cache toplevel for untracked ([#3185](https://github.com/nvim-tree/nvim-tree.lua/issues/3185)) ([4425136](https://github.com/nvim-tree/nvim-tree.lua/commit/442513648c6936e754c3308a1c58591a399493e5))
|
||||
* **#3171:** use vim.system() instead of vim.fn.system() to execute git toplevel ([#3175](https://github.com/nvim-tree/nvim-tree.lua/issues/3175)) ([9a05b9e](https://github.com/nvim-tree/nvim-tree.lua/commit/9a05b9e9f928856ca23dbf876fab372003180c3f))
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* **#3180, #3177:** invalid group or tabpage ([#3181](https://github.com/nvim-tree/nvim-tree.lua/issues/3181)) ([9b289ab](https://github.com/nvim-tree/nvim-tree.lua/commit/9b289abd6998e30fd24cbc9919e0b0cbed6364ce))
|
||||
* **#3180, #3177:** resolve live filter failures ([#3183](https://github.com/nvim-tree/nvim-tree.lua/issues/3183)) ([a4699c0](https://github.com/nvim-tree/nvim-tree.lua/commit/a4699c0904103e7767334f6da05f5c2ea5514845))
|
||||
|
||||
## [1.13.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.12.0...nvim-tree-v1.13.0) (2025-06-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#3113:** add renderer.icons.folder_arrow_padding ([#3114](https://github.com/nvim-tree/nvim-tree.lua/issues/3114)) ([ea5097a](https://github.com/nvim-tree/nvim-tree.lua/commit/ea5097a1e2702b4827cb7380e7fa0bd6da87699c))
|
||||
* **#3132:** add api.node.expand and api.node.collapse ([#3133](https://github.com/nvim-tree/nvim-tree.lua/issues/3133)) ([ae59561](https://github.com/nvim-tree/nvim-tree.lua/commit/ae595611fb2225f2041996c042aa4e4b8663b41e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* "Invalid buffer id" on closing nvim-tree window ([#3129](https://github.com/nvim-tree/nvim-tree.lua/issues/3129)) ([25d16aa](https://github.com/nvim-tree/nvim-tree.lua/commit/25d16aab7d29ca940a9feb92e6bb734697417009))
|
||||
* **#2746:** background and right aligned icons in floating windows ([#3128](https://github.com/nvim-tree/nvim-tree.lua/issues/3128)) ([cbc3165](https://github.com/nvim-tree/nvim-tree.lua/commit/cbc3165e08893bb499da035c6f6f9d1512b57664))
|
||||
* **#3117:** allow changing filename's casing ([bd54d1d](https://github.com/nvim-tree/nvim-tree.lua/commit/bd54d1d33c20d8630703b9842480291588dbad07))
|
||||
* **#3117:** windows: change file/dir case ([#3135](https://github.com/nvim-tree/nvim-tree.lua/issues/3135)) ([bd54d1d](https://github.com/nvim-tree/nvim-tree.lua/commit/bd54d1d33c20d8630703b9842480291588dbad07))
|
||||
* **#3122:** remove redundant vim.validate ([#3123](https://github.com/nvim-tree/nvim-tree.lua/issues/3123)) ([e7d1b7d](https://github.com/nvim-tree/nvim-tree.lua/commit/e7d1b7dadc62fe2eccc17d814354b0a5688621ce))
|
||||
* **#3124:** fix icon padding for "right_align" placements, notably for dotfiles ([#3125](https://github.com/nvim-tree/nvim-tree.lua/issues/3125)) ([e4cd856](https://github.com/nvim-tree/nvim-tree.lua/commit/e4cd856ebf4fec51db10c69d63e43224b701cbce))
|
||||
* **#3124:** prevent empty icons_right_align response from breaking padding ([e4cd856](https://github.com/nvim-tree/nvim-tree.lua/commit/e4cd856ebf4fec51db10c69d63e43224b701cbce))
|
||||
* **#3134:** setting one glyph to "" no longer disables others ([#3136](https://github.com/nvim-tree/nvim-tree.lua/issues/3136)) ([ebcaccd](https://github.com/nvim-tree/nvim-tree.lua/commit/ebcaccda1c575fa19a8087445276e6671e2b9b37))
|
||||
* **#3143:** actions.open_file.window_picker.exclude applies when not using window picker ([#3144](https://github.com/nvim-tree/nvim-tree.lua/issues/3144)) ([05d8172](https://github.com/nvim-tree/nvim-tree.lua/commit/05d8172ebf9cdb2d140cf25b75625374fbc3df7f))
|
||||
* fixes [#3134](https://github.com/nvim-tree/nvim-tree.lua/issues/3134) ([ebcaccd](https://github.com/nvim-tree/nvim-tree.lua/commit/ebcaccda1c575fa19a8087445276e6671e2b9b37))
|
||||
* invalid buffer issue ([25d16aa](https://github.com/nvim-tree/nvim-tree.lua/commit/25d16aab7d29ca940a9feb92e6bb734697417009))
|
||||
|
||||
## [1.12.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.11.0...nvim-tree-v1.12.0) (2025-04-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add TreePreOpen event ([#3105](https://github.com/nvim-tree/nvim-tree.lua/issues/3105)) ([c24c047](https://github.com/nvim-tree/nvim-tree.lua/commit/c24c0470d9de277fbebecd718f33561ed7c90298))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3101:** when renderer.highlight_opened_files = "none" do not reload on BufUnload and BufReadPost ([#3102](https://github.com/nvim-tree/nvim-tree.lua/issues/3102)) ([5bea2b3](https://github.com/nvim-tree/nvim-tree.lua/commit/5bea2b37523a31288e0fcab42f3be5c1bd4516bb))
|
||||
* explicitly set `border` to `"none"` in full name float ([#3094](https://github.com/nvim-tree/nvim-tree.lua/issues/3094)) ([c3c1935](https://github.com/nvim-tree/nvim-tree.lua/commit/c3c193594213c5e2f89ec5d7729cad805f76b256))
|
||||
* reliably dispatch exactly one TreeOpen and TreeClose events ([#3107](https://github.com/nvim-tree/nvim-tree.lua/issues/3107)) ([3a63717](https://github.com/nvim-tree/nvim-tree.lua/commit/3a63717d3d332d8f39aaf65be7a0e4c2265af021))
|
||||
|
||||
## [1.11.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.10.0...nvim-tree-v1.11.0) (2025-02-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#1984:** add quit_on_open and focus opts to various api.node.open functions ([#3054](https://github.com/nvim-tree/nvim-tree.lua/issues/3054)) ([3281f33](https://github.com/nvim-tree/nvim-tree.lua/commit/3281f331f7f0bef13eb00fb2d5a9d28b2f6155a2))
|
||||
* **#3037:** add API node.buffer.delete, node.buffer.wipe ([#3040](https://github.com/nvim-tree/nvim-tree.lua/issues/3040)) ([fee1da8](https://github.com/nvim-tree/nvim-tree.lua/commit/fee1da88972f5972a8296813f6c00d7598325ebd))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3045:** wipe scratch buffers for full name and show info popups ([#3050](https://github.com/nvim-tree/nvim-tree.lua/issues/3050)) ([fca0b67](https://github.com/nvim-tree/nvim-tree.lua/commit/fca0b67c0b5a31727fb33addc4d9c100736a2894))
|
||||
* **#3059:** test for presence of new 0.11 API vim.hl.range ([#3060](https://github.com/nvim-tree/nvim-tree.lua/issues/3060)) ([70825f2](https://github.com/nvim-tree/nvim-tree.lua/commit/70825f23db61ecd900c4cfea169bffe931926a9d))
|
||||
* arithmetic on nil value error on first git project open ([#3064](https://github.com/nvim-tree/nvim-tree.lua/issues/3064)) ([8052310](https://github.com/nvim-tree/nvim-tree.lua/commit/80523101f0ae48b7f1990e907b685a3d79776c01))
|
||||
* stl and stlnc fillchars are hidden in window picker ([b699143](https://github.com/nvim-tree/nvim-tree.lua/commit/b69914325a945ee5157f0d21047210b42af5776e))
|
||||
* window picker: hide fillchars: stl and stlnc ([#3066](https://github.com/nvim-tree/nvim-tree.lua/issues/3066)) ([b699143](https://github.com/nvim-tree/nvim-tree.lua/commit/b69914325a945ee5157f0d21047210b42af5776e))
|
||||
|
||||
## [1.10.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.9.0...nvim-tree-v1.10.0) (2025-01-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add node.open.vertical_no_picker, node.open.horizontal_no_picker ([#3031](https://github.com/nvim-tree/nvim-tree.lua/issues/3031)) ([68fc4c2](https://github.com/nvim-tree/nvim-tree.lua/commit/68fc4c20f5803444277022c681785c5edd11916d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#3015:** dynamic width no longer truncates on right_align icons ([#3022](https://github.com/nvim-tree/nvim-tree.lua/issues/3022)) ([f7b76cd](https://github.com/nvim-tree/nvim-tree.lua/commit/f7b76cd1a75615c8d6254fc58bedd2a7304eb7d8))
|
||||
* **#3018:** error when focusing nvim-tree when in terminal mode ([#3019](https://github.com/nvim-tree/nvim-tree.lua/issues/3019)) ([db8d7ac](https://github.com/nvim-tree/nvim-tree.lua/commit/db8d7ac1f524fc6f808764b29fa695c51e014aa6))
|
||||
* **#3041:** use vim.diagnostic.get for updating diagnostics ([#3042](https://github.com/nvim-tree/nvim-tree.lua/issues/3042)) ([aae0185](https://github.com/nvim-tree/nvim-tree.lua/commit/aae01853ddbd790d1efd6ff04ff96cf38c02c95f))
|
||||
* Can't re-enter normal mode from terminal mode ([db8d7ac](https://github.com/nvim-tree/nvim-tree.lua/commit/db8d7ac1f524fc6f808764b29fa695c51e014aa6))
|
||||
* hijack directory "BufEnter", "BufNewFile" events are nested ([#3044](https://github.com/nvim-tree/nvim-tree.lua/issues/3044)) ([39bc630](https://github.com/nvim-tree/nvim-tree.lua/commit/39bc63081605c1d4b974131ebecaea11e8a8595f))
|
||||
* view.width functions may return strings ([#3020](https://github.com/nvim-tree/nvim-tree.lua/issues/3020)) ([6b4be1d](https://github.com/nvim-tree/nvim-tree.lua/commit/6b4be1dc0cd4d5d5b8e8b56b510a75016e99746f))
|
||||
|
||||
## [1.9.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.8.0...nvim-tree-v1.9.0) (2024-12-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#2948:** add custom decorators, :help nvim-tree-decorators ([#2996](https://github.com/nvim-tree/nvim-tree.lua/issues/2996)) ([7a4ff1a](https://github.com/nvim-tree/nvim-tree.lua/commit/7a4ff1a516fe92a5ed6b79d7ce31ea4d8f341a72))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#2954:** more efficient LSP updates, increase diagnostics.debounce_delay from 50ms to 500ms ([#3007](https://github.com/nvim-tree/nvim-tree.lua/issues/3007)) ([1f3ffd6](https://github.com/nvim-tree/nvim-tree.lua/commit/1f3ffd6af145af2a4930a61c50f763264922c3fe))
|
||||
* **#2990:** Do not check if buffer is buflisted in diagnostics.update() ([#2998](https://github.com/nvim-tree/nvim-tree.lua/issues/2998)) ([28eac28](https://github.com/nvim-tree/nvim-tree.lua/commit/28eac2801b201f301449e976d7a9e8cfde053ba3))
|
||||
* **#3009:** nvim < 0.10 apply view options locally ([#3010](https://github.com/nvim-tree/nvim-tree.lua/issues/3010)) ([ca7c4c3](https://github.com/nvim-tree/nvim-tree.lua/commit/ca7c4c33cac2ad66ec69d45e465379716ef0cc97))
|
||||
* **api:** correct argument types in `wrap_node` and `wrap_node_or_nil` ([#3006](https://github.com/nvim-tree/nvim-tree.lua/issues/3006)) ([f7c65e1](https://github.com/nvim-tree/nvim-tree.lua/commit/f7c65e11d695a084ca10b93df659bb7e68b71f9f))
|
||||
|
||||
## [1.8.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.7.1...nvim-tree-v1.8.0) (2024-11-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#2819:** add actions.open_file.relative_path, default enabled, following successful experiment ([#2995](https://github.com/nvim-tree/nvim-tree.lua/issues/2995)) ([2ee1c5e](https://github.com/nvim-tree/nvim-tree.lua/commit/2ee1c5e17fdfbf5013af31b1410e4a5f28f4cadd))
|
||||
* **#2938:** add default filesystem_watchers.ignore_dirs = { "/.ccls-cache", "/build", "/node_modules", "/target", } ([#2940](https://github.com/nvim-tree/nvim-tree.lua/issues/2940)) ([010ae03](https://github.com/nvim-tree/nvim-tree.lua/commit/010ae0365aafd6275c478d932515d2e8e897b7bb))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#2945:** stack overflow on api.git.reload or fugitive event with watchers disabled ([#2949](https://github.com/nvim-tree/nvim-tree.lua/issues/2949)) ([5ad8762](https://github.com/nvim-tree/nvim-tree.lua/commit/5ad87620ec9d1190d15c88171a3f0122bc16b0fe))
|
||||
* **#2947:** root is never a dotfile, so that it doesn't propagate to children ([#2958](https://github.com/nvim-tree/nvim-tree.lua/issues/2958)) ([f5f6789](https://github.com/nvim-tree/nvim-tree.lua/commit/f5f67892996b280ae78b1b0a2d07c4fa29ae0905))
|
||||
* **#2951:** highlights incorrect following cancelled pick ([#2952](https://github.com/nvim-tree/nvim-tree.lua/issues/2952)) ([1c9553a](https://github.com/nvim-tree/nvim-tree.lua/commit/1c9553a19f70df3dcb171546a3d5e034531ef093))
|
||||
* **#2954:** resolve occasional tree flashing on diagnostics, set tree buffer options in deterministic order ([#2980](https://github.com/nvim-tree/nvim-tree.lua/issues/2980)) ([82ab19e](https://github.com/nvim-tree/nvim-tree.lua/commit/82ab19ebf79c1839d7351f2fed213d1af13a598e))
|
||||
* **#2961:** windows: escape brackets and parentheses when opening file ([#2962](https://github.com/nvim-tree/nvim-tree.lua/issues/2962)) ([63c7ad9](https://github.com/nvim-tree/nvim-tree.lua/commit/63c7ad9037fb7334682dd0b3a177cee25c5c8a0f))
|
||||
* **#2969:** After a rename, the node loses selection ([#2974](https://github.com/nvim-tree/nvim-tree.lua/issues/2974)) ([1403933](https://github.com/nvim-tree/nvim-tree.lua/commit/14039337a563f4efd72831888f332a15585f0ea1))
|
||||
* **#2972:** error on :colorscheme ([#2973](https://github.com/nvim-tree/nvim-tree.lua/issues/2973)) ([6e5a204](https://github.com/nvim-tree/nvim-tree.lua/commit/6e5a204ca659bb8f2a564df75df2739edec03cb0))
|
||||
* **#2976:** use vim.loop to preserve neovim 0.9 compatibility ([#2977](https://github.com/nvim-tree/nvim-tree.lua/issues/2977)) ([00dff48](https://github.com/nvim-tree/nvim-tree.lua/commit/00dff482f9a8fb806a54fd980359adc6cd45d435))
|
||||
* **#2978:** grouped folder not showing closed icon ([#2979](https://github.com/nvim-tree/nvim-tree.lua/issues/2979)) ([120ba58](https://github.com/nvim-tree/nvim-tree.lua/commit/120ba58254835d412bbc91cffe847e9be835fadd))
|
||||
* **#2981:** windows: root changed when navigating with LSP ([#2982](https://github.com/nvim-tree/nvim-tree.lua/issues/2982)) ([c22124b](https://github.com/nvim-tree/nvim-tree.lua/commit/c22124b37409bee6d1a0da77f4f3a1526f7a204d))
|
||||
* symlink file icons rendered when renderer.icons.show.file = false, folder.symlink* was incorrectly rendered as folder.default|open ([#2983](https://github.com/nvim-tree/nvim-tree.lua/issues/2983)) ([2156bc0](https://github.com/nvim-tree/nvim-tree.lua/commit/2156bc08c982d3c4b4cfc2b8fd7faeff58a88e10))
|
||||
|
||||
## [1.7.1](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.7.0...nvim-tree-v1.7.1) (2024-09-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#2794:** sshfs compatibility ([#2922](https://github.com/nvim-tree/nvim-tree.lua/issues/2922)) ([9650e73](https://github.com/nvim-tree/nvim-tree.lua/commit/9650e735baad0d39505f4cb4867a60f02858536a))
|
||||
* **#2928:** nil explorer in parent move action ([#2929](https://github.com/nvim-tree/nvim-tree.lua/issues/2929)) ([0429f28](https://github.com/nvim-tree/nvim-tree.lua/commit/0429f286b350c65118d66b646775bf187936fa47))
|
||||
* **#2930:** empty groups expanded on reload ([#2935](https://github.com/nvim-tree/nvim-tree.lua/issues/2935)) ([4520c03](https://github.com/nvim-tree/nvim-tree.lua/commit/4520c0355cc561830ee2cf90dc37a2a75abf7995))
|
||||
* invalid explorer on open ([#2927](https://github.com/nvim-tree/nvim-tree.lua/issues/2927)) ([59a8a6a](https://github.com/nvim-tree/nvim-tree.lua/commit/59a8a6ae5e9d3eae99d08ab655d12fd51d5d17f3))
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* **#2794:** sshfs compatibility ([#2920](https://github.com/nvim-tree/nvim-tree.lua/issues/2920)) ([8405ecf](https://github.com/nvim-tree/nvim-tree.lua/commit/8405ecfbd6bb08a94ffc9c68fef211eea56e8a3b))
|
||||
|
||||
## [1.7.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.6.1...nvim-tree-v1.7.0) (2024-09-21)
|
||||
|
||||
|
||||
|
||||
195
CONTRIBUTING.md
195
CONTRIBUTING.md
@@ -2,17 +2,49 @@
|
||||
|
||||
Thank you for contributing.
|
||||
|
||||
See [Development](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development) for environment setup, tips and tools.
|
||||
See [wiki: Development](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development) for environment setup, tips and tools.
|
||||
|
||||
<!--
|
||||
https://github.com/jonschlinkert/markdown-toc
|
||||
markdown-toc --maxdepth=2 -i CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [Tools](#tools)
|
||||
- [Quality](#quality)
|
||||
* [lint](#lint)
|
||||
* [style](#style)
|
||||
* [format-fix](#format-fix)
|
||||
* [check](#check)
|
||||
* [format-check](#format-check)
|
||||
- [Diagnostics](#diagnostics)
|
||||
- [Backwards Compatibility](#backwards-compatibility)
|
||||
- [:help Documentation](#help-documentation)
|
||||
* [Generated Content](#generated-content)
|
||||
* [Updating And Generating](#updating-and-generating)
|
||||
* [Checking And Linting](#checking-and-linting)
|
||||
- [Windows](#windows)
|
||||
- [Pull Request](#pull-request)
|
||||
* [Subject](#subject)
|
||||
- [AI Usage Policy: Highly Discouraged](#ai-usage-policy-highly-discouraged)
|
||||
* [nvim-tree Is A Community Project](#nvim-tree-is-a-community-project)
|
||||
* [The Burden Of Review Must Not Increase](#the-burden-of-review-must-not-increase)
|
||||
* [AI Generated PR Rules](#ai-generated-pr-rules)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
# Tools
|
||||
|
||||
Following are used during CI and strongly recommended during local development.
|
||||
|
||||
Language server: [luals](https://luals.github.io)
|
||||
|
||||
Lint: [luacheck](https://github.com/lunarmodules/luacheck/)
|
||||
|
||||
Style: [StyLua](https://github.com/JohnnyMorganz/StyLua)
|
||||
nvim-tree migrated from stylua to EmmyLuaCodeStyle ~2024/10. `vim.lsp.buf.format()` may be used as it is the default formatter for luals, using an embedded [EmmyLuaCodeStyle](https://github.com/CppCXY/EmmyLuaCodeStyle)
|
||||
|
||||
Language server: [luals](https://luals.github.io)
|
||||
Formatting: [EmmyLuaCodeStyle](https://github.com/CppCXY/EmmyLuaCodeStyle): `CodeFormat` executable
|
||||
|
||||
You can install them via you OS package manager e.g. `pacman`, `brew` or other via other package managers such as `cargo` or `luarocks`
|
||||
|
||||
@@ -34,17 +66,19 @@ make lint
|
||||
|
||||
## style
|
||||
|
||||
1. Runs stylua using `.stylua.toml` settings
|
||||
1. Runs `scripts/doc-comments.sh` to validate annotated documentation
|
||||
1. Runs lua language server `codestyle-check` only, using `.luarc.json` settings
|
||||
1. Runs `scripts/doc-comments.sh` to normalise annotated documentation
|
||||
|
||||
```sh
|
||||
make style
|
||||
```
|
||||
|
||||
You can automatically fix stylua issues via:
|
||||
## format-fix
|
||||
|
||||
You can automatically fix most style issues using `CodeFormat`:
|
||||
|
||||
```sh
|
||||
make style-fix
|
||||
make format-fix
|
||||
```
|
||||
|
||||
## check
|
||||
@@ -61,32 +95,113 @@ Assumes `$VIMRUNTIME` is `/usr/share/nvim/runtime`. Adjust as necessary e.g.
|
||||
VIMRUNTIME="/my/path/to/runtime" make check
|
||||
```
|
||||
|
||||
If `lua-language-server` is not available or `--check` doesn't function (e.g. Arch Linux 3.9.1-1) you can manually install it as per `ci.yml` e.g.
|
||||
If `lua-language-server` is not available or `--check` doesn't function (e.g. Arch Linux 3.9.1-1) you can manually install it as per `ci.yml` using its current `luals_version` e.g.
|
||||
|
||||
```sh
|
||||
mkdir luals
|
||||
curl -L "https://github.com/LuaLS/lua-language-server/releases/download/3.9.1/lua-language-server-3.9.1-linux-x64.tar.gz" | tar zx --directory luals
|
||||
curl -L "https://github.com/LuaLS/lua-language-server/releases/download/3.15.0/lua-language-server-3.15.0-linux-x64.tar.gz" | tar zx --directory luals
|
||||
|
||||
PATH="luals/bin:${PATH}" make check
|
||||
```
|
||||
|
||||
# Adding New Actions
|
||||
## format-check
|
||||
|
||||
To add a new action, add a file in `actions/name-of-the-action.lua`. You should export a `setup` function if some configuration is needed.
|
||||
This is run in CI. Commit or stage your changes and run:
|
||||
|
||||
Once you did, you should run `make help-update`
|
||||
```sh
|
||||
make format-check
|
||||
```
|
||||
|
||||
# Documentation
|
||||
- Re-runs `make format-fix`
|
||||
- Checks that `git diff` is empty, to ensure that all content has been generated. This is why a stage or commit is necessary.
|
||||
|
||||
## Opts
|
||||
# Diagnostics
|
||||
|
||||
When adding new options, you should declare the defaults in the main `nvim-tree.lua` file.
|
||||
Diagnostics issues may not be suppressed. See [luals](https://luals.github.io) documentation for details on how to structure the code and comments.
|
||||
|
||||
Documentation for options should also be added to `nvim-tree-opts` in `doc/nvim-tree-lua.txt`
|
||||
Suppressions are permitted only in the following cases:
|
||||
|
||||
## API
|
||||
- Backwards compatibility shims
|
||||
- neovim API metadata incorrect, awaiting upstream fix
|
||||
- classic class framework
|
||||
|
||||
When adding or changing API please update :help nvim-tree-api
|
||||
# Backwards Compatibility
|
||||
|
||||
Whenever new neovim API is introduced, please ensure that it is available in older versions. See `:help deprecated.txt` and `$VIMRUNTIME/lua/vim/_meta/api.lua`
|
||||
|
||||
See `nvim-tree.setup` for the oldest supported version of neovim. If the API is not availble in that version, a backwards compatibility shim must be used e.g.
|
||||
|
||||
```lua
|
||||
if vim.fn.has("nvim-0.11") == 1 and vim.hl and vim.hl.range then
|
||||
vim.hl.range(0, ns_id, details.hl_group, { 0, col }, { 0, details.end_col, }, {})
|
||||
else
|
||||
vim.api.nvim_buf_add_highlight(0, ns_id, details.hl_group, 0, col, details.end_col) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
```
|
||||
|
||||
# :help Documentation
|
||||
|
||||
Please update or add to `doc/nvim-tree-lua.txt` as needed.
|
||||
|
||||
## Generated Content
|
||||
|
||||
`doc/nvim-tree-lua.txt` content starting at `*nvim-tree-config*` will be replaced with generated content. Do not manually edit that content.
|
||||
|
||||
### API and Config
|
||||
|
||||
Help is generated for:
|
||||
- `nvim_tree.config` classes from `lua/nvim-tree/_meta/config/`
|
||||
- `nvim_tree.api` functions from `lua/nvim-tree/_meta/api/`
|
||||
|
||||
Please add or update documentation when you make changes, see `:help dev-lua-doc` for docstring format.
|
||||
|
||||
`scripts/vimdoc_config.lua` contains the manifest of help sources.
|
||||
|
||||
### Config And Mappings
|
||||
|
||||
Help is updated for:
|
||||
- Default keymap at `keymap.on_attach_default`
|
||||
- Default config at `--- config-default-start`
|
||||
|
||||
## Updating And Generating
|
||||
|
||||
Nvim sources are required. You will be prompted with instructions on fetching and using the sources.
|
||||
|
||||
See comments at the start of each script for complete details.
|
||||
|
||||
```sh
|
||||
make help-update
|
||||
```
|
||||
|
||||
- `scripts/help-defaults.sh`
|
||||
- Update config defaults `*nvim-tree-config-default*`
|
||||
- Update default mappings:
|
||||
- `*nvim-tree-mappings-default*`
|
||||
- `*nvim-tree-quickstart-help*`
|
||||
|
||||
- `scripts/vimdoc.sh doc`
|
||||
- Remove content starting at `*nvim-tree-config*`
|
||||
- Generate config classes `*nvim-tree-config*`
|
||||
- Generate API `*nvim-tree-api*`
|
||||
|
||||
## Checking
|
||||
|
||||
This is run in CI. Commit or stage your changes and run:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
# Windows
|
||||
|
||||
Please note that nvim-tree team members do not have access to nor expertise with Windows.
|
||||
|
||||
You will need to be an active participant during development and raise a PR to resolve any issues that may arise.
|
||||
|
||||
Please ensure that windows specific features and fixes are behind the appropriate feature flag, see [wiki: OS Feature Flags](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development#os-feature-flags)
|
||||
|
||||
# Pull Request
|
||||
|
||||
@@ -94,6 +209,8 @@ Please reference any issues in the description e.g. "resolves #1234", which will
|
||||
|
||||
Please check "allow edits by maintainers" to allow nvim-tree developers to make small changes such as documentation tweaks.
|
||||
|
||||
Do not enable or use any AI review tools (e.g. Copilot) on the Pull Request.
|
||||
|
||||
## Subject
|
||||
|
||||
The merge commit message will be the subject of the PR.
|
||||
@@ -118,3 +235,45 @@ Available types:
|
||||
If in doubt, look at previous commits.
|
||||
|
||||
See also [The Conventional Commits ultimate cheatsheet](https://gist.github.com/gabrielecanepa/fa6cca1a8ae96f77896fe70ddee65527)
|
||||
|
||||
# AI Usage Policy: Highly Discouraged
|
||||
|
||||
## nvim-tree Is A Community Project
|
||||
|
||||
nvim-tree is a work of passion, building a community of free thinking individuals who contribute highly polished, elegant and maintainable code. Community members range from novices to professionals and all are welcome. Teaching, encouraging and celebrating the growth of less experienced developers is of great importance.
|
||||
|
||||
AI generated code is discouraged as this doesn't match these nvim-tree values.
|
||||
|
||||
Human PR reviews will always be prioritised over AI generated PRs.
|
||||
|
||||
## The Burden Of Review Must Not Increase
|
||||
|
||||
There must be a human in the loop at all times. The contributor is the author of and is fully accountable for AI generated contributions.
|
||||
|
||||
AI generated PRs have low, or even non-existent entry level. Human generated PRs require you to be motivated, do research, familiarise yourself with code, make effort to write the code and test it.
|
||||
|
||||
Low effort or unqualified code increases the burden of review and testing on maintainers, who are limited in time.
|
||||
|
||||
Contributors must:
|
||||
|
||||
- Read and review all generated code and documentation before raising a PR
|
||||
- Fully understand all code and documentation
|
||||
- Be able to answer any questions during review
|
||||
|
||||
## AI Generated PR Rules
|
||||
|
||||
The PR description and comments must be written by the contributor, with no AI assistance beyond grammar or English translations.
|
||||
|
||||
The description must:
|
||||
|
||||
- Describe the solution design, justifying all decisions
|
||||
- Clearly state which AI was used
|
||||
- List which code and documentation was written by a human and which was written by AI
|
||||
- Detail all testing performed
|
||||
|
||||
There must be far greater than usual number of detailed, explicit comments:
|
||||
|
||||
- File level: overview of the changes made
|
||||
- Line level: 1-2 comments per function/method
|
||||
|
||||
Do not enable or use any AI review tools (e.g. Copilot) on the Pull Request.
|
||||
|
||||
25
Makefile
25
Makefile
@@ -5,7 +5,7 @@ all: lint style check
|
||||
#
|
||||
lint: luacheck
|
||||
|
||||
style: stylua style-doc
|
||||
style: style-check style-doc
|
||||
|
||||
check: luals
|
||||
|
||||
@@ -13,28 +13,33 @@ check: luals
|
||||
# subtasks
|
||||
#
|
||||
luacheck:
|
||||
luacheck -q lua
|
||||
luacheck --codes --quiet lua --exclude-files "**/_meta/**"
|
||||
|
||||
stylua:
|
||||
stylua lua --check
|
||||
style-check:
|
||||
scripts/luals-check.sh codestyle-check
|
||||
|
||||
style-doc:
|
||||
scripts/doc-comments.sh
|
||||
|
||||
luals:
|
||||
@scripts/luals-check.sh
|
||||
scripts/luals-check.sh
|
||||
|
||||
#
|
||||
# fixes
|
||||
# format
|
||||
#
|
||||
style-fix:
|
||||
stylua lua
|
||||
format-fix:
|
||||
CodeFormat format --config .editorconfig --workspace lua
|
||||
|
||||
format-check:
|
||||
CodeFormat format --config .editorconfig --workspace lua
|
||||
git diff --exit-code lua
|
||||
|
||||
#
|
||||
# utility
|
||||
#
|
||||
help-update:
|
||||
scripts/help-update.sh
|
||||
scripts/vimdoc.sh doc
|
||||
scripts/help-defaults.sh
|
||||
|
||||
#
|
||||
# CI
|
||||
@@ -43,5 +48,5 @@ help-check: help-update
|
||||
git diff --exit-code doc/nvim-tree-lua.txt
|
||||
|
||||
|
||||
.PHONY: all lint style check luacheck stylua style-doc luals style-fix help-update help-check
|
||||
.PHONY: all lint style check luacheck style-check style-doc luals format-fix format-check help-update help-check
|
||||
|
||||
|
||||
220
README.md
220
README.md
@@ -15,7 +15,9 @@
|
||||
|
||||
(Live) filtering
|
||||
|
||||
Cut, copy, paste, rename, delete, create
|
||||
Rename, delete, create
|
||||
|
||||
Cut, copy, paste locally and between instances
|
||||
|
||||
Highly customisable
|
||||
|
||||
@@ -26,93 +28,123 @@ Take a look at the [wiki](https://github.com/nvim-tree/nvim-tree.lua/wiki) for S
|
||||
|
||||
Questions and general support: [Discussions](https://github.com/nvim-tree/nvim-tree.lua/discussions)
|
||||
|
||||
## Requirements
|
||||
<!--
|
||||
https://github.com/jonschlinkert/markdown-toc
|
||||
markdown-toc --maxdepth=2 -i README.md
|
||||
-->
|
||||
|
||||
[neovim >=0.9.0](https://github.com/neovim/neovim/wiki/Installing-Neovim)
|
||||
<!-- toc -->
|
||||
|
||||
- [Requirements](#requirements)
|
||||
- [Installing](#installing)
|
||||
- [Quick Start](#quick-start)
|
||||
* [Setup](#setup)
|
||||
* [Help](#help)
|
||||
* [Custom Mappings](#custom-mappings)
|
||||
* [Highlight Groups](#highlight-groups)
|
||||
- [Commands](#commands)
|
||||
- [Roadmap](#roadmap)
|
||||
- [API](#api)
|
||||
- [Contributing](#contributing)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Team](#team)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
# Requirements
|
||||
|
||||
[Nvim >= 0.10](https://github.com/neovim/neovim/wiki/Installing-Neovim). At least `n - 0.1` stable Nvim compatibility is guaranteed. You may use a `compat-nvim-0.X` tag for earlier Nvim versions, however they will receive no updates or support.
|
||||
|
||||
[nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) is optional and used to display file icons. It requires a [patched font](https://www.nerdfonts.com/). Your terminal emulator must be configured to use that font, usually "Hack Nerd Font"
|
||||
|
||||
## Install
|
||||
# Installing
|
||||
|
||||
Please install via your preferred package manager. See [Installation](https://github.com/nvim-tree/nvim-tree.lua/wiki/Installation) for specific package manager instructions.
|
||||
|
||||
`nvim-tree/nvim-tree.lua`
|
||||
Please install via your preferred package manager. See [Installation](https://github.com/nvim-tree/nvim-tree.lua/wiki/Installation) for some specific package manager instructions.
|
||||
|
||||
Major or minor versions may be specified via tags: `v<MAJOR>` e.g. `v1` or `v<MAJOR>.<MINOR>` e.g. `v1.23`
|
||||
|
||||
`nvim-tree/nvim-web-devicons` optional, for file icons
|
||||
# Quick Start
|
||||
|
||||
Install the plugins via your package manager:
|
||||
`"nvim-tree/nvim-tree.lua"`
|
||||
`"nvim-tree/nvim-web-devicons"`
|
||||
|
||||
Disabling [netrw](https://neovim.io/doc/user/pi_netrw.html) is strongly advised, see [:help nvim-tree-netrw](doc/nvim-tree-lua.txt)
|
||||
|
||||
## Quick Start
|
||||
## Setup
|
||||
|
||||
### Setup
|
||||
Setup the plugin in your `init.lua`.
|
||||
|
||||
Setup the plugin in your `init.lua`
|
||||
See [:help nvim-tree-setup](doc/nvim-tree-lua.txt) and [:help nvim-tree-config-default](doc/nvim-tree-lua.txt)
|
||||
|
||||
```lua
|
||||
-- disable netrw at the very start of your init.lua
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
-- disable netrw at the very start of your init.lua
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
|
||||
-- optionally enable 24-bit colour
|
||||
vim.opt.termguicolors = true
|
||||
-- optionally enable 24-bit colour
|
||||
vim.opt.termguicolors = true
|
||||
|
||||
-- empty setup using defaults
|
||||
require("nvim-tree").setup()
|
||||
-- empty setup using defaults
|
||||
require("nvim-tree").setup()
|
||||
|
||||
-- OR setup with some options
|
||||
require("nvim-tree").setup({
|
||||
sort = {
|
||||
sorter = "case_sensitive",
|
||||
},
|
||||
view = {
|
||||
width = 30,
|
||||
},
|
||||
renderer = {
|
||||
group_empty = true,
|
||||
},
|
||||
filters = {
|
||||
dotfiles = true,
|
||||
},
|
||||
})
|
||||
-- OR setup with a config
|
||||
|
||||
---@type nvim_tree.config
|
||||
local config = {
|
||||
sort = {
|
||||
sorter = "case_sensitive",
|
||||
},
|
||||
view = {
|
||||
width = 30,
|
||||
},
|
||||
renderer = {
|
||||
group_empty = true,
|
||||
},
|
||||
filters = {
|
||||
dotfiles = true,
|
||||
},
|
||||
}
|
||||
require("nvim-tree").setup(config)
|
||||
```
|
||||
|
||||
### Help
|
||||
## Help
|
||||
|
||||
Open the tree: `:NvimTreeOpen`
|
||||
|
||||
Show the mappings: `g?`
|
||||
|
||||
### Custom Mappings
|
||||
## Custom Mappings
|
||||
|
||||
[:help nvim-tree-mappings-default](doc/nvim-tree-lua.txt) are applied by default however you may customise via |nvim-tree.on_attach| e.g.
|
||||
[:help nvim-tree-mappings-default](doc/nvim-tree-lua.txt) are applied by default however you may customise via [:help nvim_tree.config](doc/nvim-tree-lua.txt) `{on_attach}` e.g.
|
||||
|
||||
```lua
|
||||
local function my_on_attach(bufnr)
|
||||
local api = require "nvim-tree.api"
|
||||
local function my_on_attach(bufnr)
|
||||
local api = require "nvim-tree.api"
|
||||
|
||||
local function opts(desc)
|
||||
return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
|
||||
local function opts(desc)
|
||||
return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
|
||||
end
|
||||
|
||||
-- default mappings
|
||||
api.map.on_attach.default(bufnr)
|
||||
|
||||
-- custom mappings
|
||||
vim.keymap.set("n", "<C-t>", api.tree.change_root_to_parent, opts("Up"))
|
||||
vim.keymap.set("n", "?", api.tree.toggle_help, opts("Help"))
|
||||
end
|
||||
|
||||
-- default mappings
|
||||
api.config.mappings.default_on_attach(bufnr)
|
||||
|
||||
-- custom mappings
|
||||
vim.keymap.set('n', '<C-t>', api.tree.change_root_to_parent, opts('Up'))
|
||||
vim.keymap.set('n', '?', api.tree.toggle_help, opts('Help'))
|
||||
end
|
||||
|
||||
-- pass to setup along with your other options
|
||||
require("nvim-tree").setup {
|
||||
---
|
||||
on_attach = my_on_attach,
|
||||
---
|
||||
}
|
||||
-- pass to setup along with your other config
|
||||
require("nvim-tree").setup({
|
||||
---
|
||||
on_attach = my_on_attach,
|
||||
---
|
||||
})
|
||||
```
|
||||
|
||||
### Highlight
|
||||
## Highlight Groups
|
||||
|
||||
See [:help nvim-tree-highlight-groups](doc/nvim-tree-lua.txt)
|
||||
|
||||
Run `:NvimTreeHiTest` to show all the highlights that nvim-tree uses.
|
||||
|
||||
@@ -120,65 +152,93 @@ They can be customised before or after setup is called and will be immediately
|
||||
applied at runtime. e.g.
|
||||
|
||||
```lua
|
||||
vim.cmd([[
|
||||
:hi NvimTreeExecFile guifg=#ffa0a0
|
||||
:hi NvimTreeSpecialFile guifg=#ff80ff gui=underline
|
||||
:hi NvimTreeSymlink guifg=Yellow gui=italic
|
||||
:hi link NvimTreeImageFile Title
|
||||
]])
|
||||
vim.cmd([[
|
||||
:hi NvimTreeExecFile guifg=#ffa0a0
|
||||
:hi NvimTreeSpecialFile guifg=#ff80ff gui=underline
|
||||
:hi NvimTreeSymlink guifg=Yellow gui=italic
|
||||
:hi link NvimTreeImageFile Title
|
||||
]])
|
||||
```
|
||||
See [:help nvim-tree-highlight](doc/nvim-tree-lua.txt) for details.
|
||||
|
||||
## Commands
|
||||
# Commands
|
||||
|
||||
See [:help nvim-tree-commands](doc/nvim-tree-lua.txt)
|
||||
|
||||
Basic commands:
|
||||
Some commands may be executed with a bang `!` or take a `path` string argument.
|
||||
|
||||
`:NvimTreeToggle` Open or close the tree. Takes an optional path argument.
|
||||
All commands execute public API.
|
||||
|
||||
`:NvimTreeFocus` Open the tree if it is closed, and then focus on the tree.
|
||||
Some basic commands:
|
||||
|
||||
`:NvimTreeFindFile` Move the cursor in the tree for the current buffer, opening folders if needed.
|
||||
`:NvimTreeFocus` [:help nvim_tree.api.tree.open()](doc/nvim-tree-lua.txt)
|
||||
```lua
|
||||
require("nvim-tree.api").tree.open()
|
||||
```
|
||||
|
||||
`:NvimTreeCollapse` Collapses the nvim-tree recursively.
|
||||
`:NvimTreeToggle` [:help nvim_tree.api.tree.toggle()](doc/nvim-tree-lua.txt)
|
||||
```lua
|
||||
require("nvim-tree.api").tree.toggle({
|
||||
path = "<args>",
|
||||
find_file = false,
|
||||
update_root = false,
|
||||
focus = true,
|
||||
})
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
`:NvimTreeFindFile` [:help nvim_tree.api.tree.find_file()](doc/nvim-tree-lua.txt)
|
||||
```lua
|
||||
require("nvim-tree.api").tree.find_file({
|
||||
open = true,
|
||||
update_root = "<bang>",
|
||||
focus = true,
|
||||
})
|
||||
```
|
||||
|
||||
`:NvimTreeCollapse` [:help nvim_tree.api.tree.collapse_all()](doc/nvim-tree-lua.txt)
|
||||
|
||||
```lua
|
||||
require("nvim-tree.api").tree.collapse_all({
|
||||
keep_buffers = false
|
||||
})
|
||||
```
|
||||
|
||||
# Roadmap
|
||||
|
||||
nvim-tree is stable and new major features will not be added. The focus is on existing user experience.
|
||||
|
||||
Users are encouraged to add their own custom features via the public [API](#api).
|
||||
|
||||
Development is focused on:
|
||||
* Bug fixes
|
||||
* Performance
|
||||
* Quality of Life improvements
|
||||
* API / Events
|
||||
* Enhancements to existing features
|
||||
- Bug fixes
|
||||
- Performance
|
||||
- Quality of Life improvements
|
||||
- API / Events
|
||||
- Enhancements to existing features
|
||||
- Multi-instance capabilities
|
||||
|
||||
## API
|
||||
# API
|
||||
|
||||
nvim-tree exposes a public API. This is non breaking, with additions made as necessary. See [:help nvim-tree-api](doc/nvim-tree-lua.txt)
|
||||
|
||||
See wiki [Recipes](https://github.com/nvim-tree/nvim-tree.lua/wiki/Recipes) and [Tips](https://github.com/nvim-tree/nvim-tree.lua/wiki/Tips) for ideas and inspiration.
|
||||
|
||||
Please raise a [feature request](https://github.com/nvim-tree/nvim-tree.lua/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=) if the API is insufficient for your needs. [Contributions](#Contributing) are always welcome.
|
||||
Please raise a [feature request](https://github.com/nvim-tree/nvim-tree.lua/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=) if the API is insufficient for your needs. Contributions are always welcome, see below.
|
||||
|
||||
You may also subscribe to events that nvim-tree will dispatch in a variety of situations, see [:help nvim-tree-events](doc/nvim-tree-lua.txt)
|
||||
|
||||
## Contributing
|
||||
# Contributing
|
||||
|
||||
PRs are always welcome. See [wiki](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development) to get started.
|
||||
PRs are always welcome. See [CONTRIBUTING](CONTRIBUTING.md) and [wiki: Development](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development) to get started.
|
||||
|
||||
See [bug](https://github.com/nvim-tree/nvim-tree.lua/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and [PR Please](https://github.com/nvim-tree/nvim-tree.lua/issues?q=is%3Aopen+is%3Aissue+label%3A%22PR+please%22) issues if you are looking for some work to get you started.
|
||||
|
||||
## Screenshots
|
||||
# Screenshots
|
||||
|
||||
See [Showcases](https://github.com/nvim-tree/nvim-tree.lua/wiki/Showcases) wiki page for examples of user's configurations with sources.
|
||||
|
||||
Please add your own!
|
||||
|
||||
## Team
|
||||
# Team
|
||||
|
||||
* [@alex-courtis](https://github.com/alex-courtis) Arch Linux
|
||||
* [@gegoune](https://github.com/gegoune) macOS
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,876 +1,56 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local log = require "nvim-tree.log"
|
||||
local appearance = require "nvim-tree.appearance"
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local actions = require "nvim-tree.actions"
|
||||
local core = require "nvim-tree.core"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local M = {}
|
||||
|
||||
local _config = {}
|
||||
---`require("nvim-tree").setup` must be called once to initialise nvim-tree.
|
||||
---
|
||||
---Call again to apply a change in configuration without restarting Nvim.
|
||||
---
|
||||
---See :help nvim-tree-setup
|
||||
---
|
||||
---@param config_user? nvim_tree.config subset, uses defaults when nil
|
||||
function M.setup(config_user)
|
||||
local api = require("nvim-tree.api")
|
||||
local api_impl = require("nvim-tree.api.impl")
|
||||
local appearance = require("nvim-tree.appearance")
|
||||
local autocmd = require("nvim-tree.autocmd")
|
||||
local config = require("nvim-tree.config")
|
||||
local log = require("nvim-tree.log")
|
||||
local view_state = require("nvim-tree.view-state")
|
||||
|
||||
local M = {
|
||||
init_root = "",
|
||||
}
|
||||
|
||||
--- Update the tree root to a directory or the directory containing
|
||||
---@param path string relative or absolute
|
||||
---@param bufnr number|nil
|
||||
function M.change_root(path, bufnr)
|
||||
-- skip if current file is in ignore_list
|
||||
if type(bufnr) == "number" then
|
||||
local ft
|
||||
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
ft = vim.api.nvim_get_option_value("filetype", { buf = bufnr }) or ""
|
||||
else
|
||||
ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
|
||||
for _, value in pairs(_config.update_focused_file.update_root.ignore_list) do
|
||||
if utils.str_find(path, value) or utils.str_find(ft, value) then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- don't find inexistent
|
||||
if vim.fn.filereadable(path) == 0 then
|
||||
-- Nvim version check
|
||||
if vim.fn.has("nvim-0.10") == 0 then
|
||||
require("nvim-tree.notify").warn(
|
||||
"nvim-tree.lua requires Nvim >= 0.10. You may use a compat-nvim-0.X tag for earlier Nvim versions, however they will receive no updates or support.")
|
||||
return
|
||||
end
|
||||
|
||||
local cwd = core.get_cwd()
|
||||
if cwd == nil then
|
||||
return
|
||||
end
|
||||
-- validate and merge with defaults as config.g
|
||||
config.setup(config_user)
|
||||
|
||||
local vim_cwd = vim.fn.getcwd()
|
||||
-- optionally create the log file
|
||||
log.start()
|
||||
|
||||
-- test if in vim_cwd
|
||||
if utils.path_relative(path, vim_cwd) ~= path then
|
||||
if vim_cwd ~= cwd then
|
||||
actions.root.change_dir.fn(vim_cwd)
|
||||
end
|
||||
return
|
||||
end
|
||||
-- test if in cwd
|
||||
if utils.path_relative(path, cwd) ~= path then
|
||||
return
|
||||
end
|
||||
|
||||
-- otherwise test M.init_root
|
||||
if _config.prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then
|
||||
actions.root.change_dir.fn(M.init_root)
|
||||
return
|
||||
end
|
||||
-- otherwise root_dirs
|
||||
for _, dir in pairs(_config.root_dirs) do
|
||||
dir = vim.fn.fnamemodify(dir, ":p")
|
||||
if utils.path_relative(path, dir) ~= path then
|
||||
actions.root.change_dir.fn(dir)
|
||||
return
|
||||
end
|
||||
end
|
||||
-- finally fall back to the folder containing the file
|
||||
actions.root.change_dir.fn(vim.fn.fnamemodify(path, ":p:h"))
|
||||
end
|
||||
|
||||
function M.tab_enter()
|
||||
if view.is_visible { any_tabpage = true } then
|
||||
local bufname = vim.api.nvim_buf_get_name(0)
|
||||
|
||||
local ft
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
ft = vim.api.nvim_get_option_value("filetype", { buf = 0 }) or ""
|
||||
else
|
||||
ft = vim.api.nvim_buf_get_option(0, "ft") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
|
||||
for _, filter in ipairs(M.config.tab.sync.ignore) do
|
||||
if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then
|
||||
return
|
||||
end
|
||||
end
|
||||
view.open { focus_tree = false }
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.open_on_directory()
|
||||
local should_proceed = _config.hijack_directories.auto_open or view.is_visible()
|
||||
if not should_proceed then
|
||||
return
|
||||
end
|
||||
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
local bufname = vim.api.nvim_buf_get_name(buf)
|
||||
if vim.fn.isdirectory(bufname) ~= 1 then
|
||||
return
|
||||
end
|
||||
|
||||
actions.root.change_dir.force_dirchange(bufname, true)
|
||||
end
|
||||
|
||||
function M.place_cursor_on_node()
|
||||
local ok, search = pcall(vim.fn.searchcount)
|
||||
if ok and search and search.exact_match == 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local node = lib.get_node_at_cursor()
|
||||
if not node or node.name == ".." then
|
||||
return
|
||||
end
|
||||
node = utils.get_parent_of_group(node)
|
||||
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local cursor = vim.api.nvim_win_get_cursor(0)
|
||||
local idx = vim.fn.stridx(line, node.name)
|
||||
|
||||
if idx >= 0 then
|
||||
vim.api.nvim_win_set_cursor(0, { cursor[1], idx })
|
||||
end
|
||||
end
|
||||
|
||||
---@return table
|
||||
function M.get_config()
|
||||
return M.config
|
||||
end
|
||||
|
||||
---@param disable_netrw boolean
|
||||
---@param hijack_netrw boolean
|
||||
local function manage_netrw(disable_netrw, hijack_netrw)
|
||||
if hijack_netrw then
|
||||
vim.cmd "silent! autocmd! FileExplorer *"
|
||||
vim.cmd "autocmd VimEnter * ++once silent! autocmd! FileExplorer *"
|
||||
end
|
||||
if disable_netrw then
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string|nil
|
||||
function M.change_dir(name)
|
||||
if name then
|
||||
actions.root.change_dir.fn(name)
|
||||
end
|
||||
|
||||
if _config.update_focused_file.update_root.enable then
|
||||
actions.tree.find_file.fn()
|
||||
end
|
||||
end
|
||||
|
||||
---@param opts table
|
||||
local function setup_autocommands(opts)
|
||||
local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true })
|
||||
local function create_nvim_tree_autocmd(name, custom_opts)
|
||||
local default_opts = { group = augroup_id }
|
||||
vim.api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts))
|
||||
end
|
||||
|
||||
-- reset and draw (highlights) when colorscheme is changed
|
||||
create_nvim_tree_autocmd("ColorScheme", {
|
||||
callback = function()
|
||||
appearance.setup()
|
||||
view.reset_winhl()
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- prevent new opened file from opening in the same window as nvim-tree
|
||||
create_nvim_tree_autocmd("BufWipeout", {
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
if not utils.is_nvim_tree_buf(0) then
|
||||
return
|
||||
end
|
||||
if opts.actions.open_file.eject then
|
||||
view._prevent_buffer_override()
|
||||
else
|
||||
view.abandon_current_window()
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
create_nvim_tree_autocmd("BufWritePost", {
|
||||
callback = function()
|
||||
if opts.auto_reload_on_write and not opts.filesystem_watchers.enable then
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
create_nvim_tree_autocmd("BufReadPost", {
|
||||
callback = function(data)
|
||||
-- update opened file buffers
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
if
|
||||
(explorer.filters.config.filter_no_buffer or explorer.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == ""
|
||||
then
|
||||
utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function()
|
||||
explorer:reload_explorer()
|
||||
end)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
create_nvim_tree_autocmd("BufUnload", {
|
||||
callback = function(data)
|
||||
-- update opened file buffers
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
if
|
||||
(explorer.filters.config.filter_no_buffer or explorer.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == ""
|
||||
then
|
||||
utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function()
|
||||
explorer:reload_explorer()
|
||||
end)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
create_nvim_tree_autocmd("User", {
|
||||
pattern = { "FugitiveChanged", "NeogitStatusRefreshed" },
|
||||
callback = function()
|
||||
if not opts.filesystem_watchers.enable and opts.git.enable then
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:reload_git()
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
if opts.tab.sync.open then
|
||||
create_nvim_tree_autocmd("TabEnter", { callback = vim.schedule_wrap(M.tab_enter) })
|
||||
end
|
||||
if opts.hijack_cursor then
|
||||
create_nvim_tree_autocmd("CursorMoved", {
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
if utils.is_nvim_tree_buf(0) then
|
||||
M.place_cursor_on_node()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
if opts.sync_root_with_cwd then
|
||||
create_nvim_tree_autocmd("DirChanged", {
|
||||
callback = function()
|
||||
M.change_dir(vim.loop.cwd())
|
||||
end,
|
||||
})
|
||||
end
|
||||
if opts.update_focused_file.enable then
|
||||
create_nvim_tree_autocmd("BufEnter", {
|
||||
callback = function(event)
|
||||
local exclude = opts.update_focused_file.exclude
|
||||
if type(exclude) == "function" and exclude(event) then
|
||||
return
|
||||
end
|
||||
utils.debounce("BufEnter:find_file", opts.view.debounce_delay, function()
|
||||
actions.tree.find_file.fn()
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if opts.hijack_directories.enable then
|
||||
create_nvim_tree_autocmd({ "BufEnter", "BufNewFile" }, { callback = M.open_on_directory })
|
||||
end
|
||||
|
||||
create_nvim_tree_autocmd("BufEnter", {
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
if utils.is_nvim_tree_buf(0) then
|
||||
if vim.fn.getcwd() ~= core.get_cwd() or (opts.reload_on_bufenter and not opts.filesystem_watchers.enable) then
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
if opts.view.centralize_selection then
|
||||
create_nvim_tree_autocmd("BufEnter", {
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
vim.schedule(function()
|
||||
vim.api.nvim_buf_call(0, function()
|
||||
vim.cmd [[norm! zz]]
|
||||
end)
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if opts.diagnostics.enable then
|
||||
create_nvim_tree_autocmd("DiagnosticChanged", {
|
||||
callback = function()
|
||||
log.line("diagnostics", "DiagnosticChanged")
|
||||
require("nvim-tree.diagnostics").update()
|
||||
end,
|
||||
})
|
||||
create_nvim_tree_autocmd("User", {
|
||||
pattern = "CocDiagnosticChange",
|
||||
callback = function()
|
||||
log.line("diagnostics", "CocDiagnosticChange")
|
||||
require("nvim-tree.diagnostics").update()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if opts.view.float.enable and opts.view.float.quit_on_focus_loss then
|
||||
create_nvim_tree_autocmd("WinLeave", {
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
if utils.is_nvim_tree_buf(0) then
|
||||
view.close()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if opts.modified.enable then
|
||||
create_nvim_tree_autocmd({ "BufModifiedSet", "BufWritePost" }, {
|
||||
callback = function()
|
||||
utils.debounce("Buf:modified", opts.view.debounce_delay, function()
|
||||
require("nvim-tree.buffers").reload_modified()
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
|
||||
on_attach = "default",
|
||||
hijack_cursor = false,
|
||||
auto_reload_on_write = true,
|
||||
disable_netrw = false,
|
||||
hijack_netrw = true,
|
||||
hijack_unnamed_buffer_when_opening = false,
|
||||
root_dirs = {},
|
||||
prefer_startup_root = false,
|
||||
sync_root_with_cwd = false,
|
||||
reload_on_bufenter = false,
|
||||
respect_buf_cwd = false,
|
||||
select_prompts = false,
|
||||
sort = {
|
||||
sorter = "name",
|
||||
folders_first = true,
|
||||
files_first = false,
|
||||
},
|
||||
view = {
|
||||
centralize_selection = false,
|
||||
cursorline = true,
|
||||
debounce_delay = 15,
|
||||
side = "left",
|
||||
preserve_window_proportions = false,
|
||||
number = false,
|
||||
relativenumber = false,
|
||||
signcolumn = "yes",
|
||||
width = 30,
|
||||
float = {
|
||||
enable = false,
|
||||
quit_on_focus_loss = true,
|
||||
open_win_config = {
|
||||
relative = "editor",
|
||||
border = "rounded",
|
||||
width = 30,
|
||||
height = 30,
|
||||
row = 1,
|
||||
col = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
add_trailing = false,
|
||||
group_empty = false,
|
||||
full_name = false,
|
||||
root_folder_label = ":~:s?$?/..?",
|
||||
indent_width = 2,
|
||||
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
|
||||
hidden_display = "none",
|
||||
symlink_destination = true,
|
||||
highlight_git = "none",
|
||||
highlight_diagnostics = "none",
|
||||
highlight_opened_files = "none",
|
||||
highlight_modified = "none",
|
||||
highlight_hidden = "none",
|
||||
highlight_bookmarks = "none",
|
||||
highlight_clipboard = "name",
|
||||
indent_markers = {
|
||||
enable = false,
|
||||
inline_arrows = true,
|
||||
icons = {
|
||||
corner = "└",
|
||||
edge = "│",
|
||||
item = "│",
|
||||
bottom = "─",
|
||||
none = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
web_devicons = {
|
||||
file = {
|
||||
enable = true,
|
||||
color = true,
|
||||
},
|
||||
folder = {
|
||||
enable = false,
|
||||
color = true,
|
||||
},
|
||||
},
|
||||
git_placement = "before",
|
||||
modified_placement = "after",
|
||||
hidden_placement = "after",
|
||||
diagnostics_placement = "signcolumn",
|
||||
bookmarks_placement = "signcolumn",
|
||||
padding = " ",
|
||||
symlink_arrow = " ➛ ",
|
||||
show = {
|
||||
file = true,
|
||||
folder = true,
|
||||
folder_arrow = true,
|
||||
git = true,
|
||||
modified = true,
|
||||
hidden = false,
|
||||
diagnostics = true,
|
||||
bookmarks = true,
|
||||
},
|
||||
glyphs = {
|
||||
default = "",
|
||||
symlink = "",
|
||||
bookmark = "",
|
||||
modified = "●",
|
||||
hidden = "",
|
||||
folder = {
|
||||
arrow_closed = "",
|
||||
arrow_open = "",
|
||||
default = "",
|
||||
open = "",
|
||||
empty = "",
|
||||
empty_open = "",
|
||||
symlink = "",
|
||||
symlink_open = "",
|
||||
},
|
||||
git = {
|
||||
unstaged = "✗",
|
||||
staged = "✓",
|
||||
unmerged = "",
|
||||
renamed = "➜",
|
||||
untracked = "★",
|
||||
deleted = "",
|
||||
ignored = "◌",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
hijack_directories = {
|
||||
enable = true,
|
||||
auto_open = true,
|
||||
},
|
||||
update_focused_file = {
|
||||
enable = false,
|
||||
update_root = {
|
||||
enable = false,
|
||||
ignore_list = {},
|
||||
},
|
||||
exclude = false,
|
||||
},
|
||||
system_open = {
|
||||
cmd = "",
|
||||
args = {},
|
||||
},
|
||||
git = {
|
||||
enable = true,
|
||||
show_on_dirs = true,
|
||||
show_on_open_dirs = true,
|
||||
disable_for_dirs = {},
|
||||
timeout = 400,
|
||||
cygwin_support = false,
|
||||
},
|
||||
diagnostics = {
|
||||
enable = false,
|
||||
show_on_dirs = false,
|
||||
show_on_open_dirs = true,
|
||||
debounce_delay = 50,
|
||||
severity = {
|
||||
min = vim.diagnostic.severity.HINT,
|
||||
max = vim.diagnostic.severity.ERROR,
|
||||
},
|
||||
icons = {
|
||||
hint = "",
|
||||
info = "",
|
||||
warning = "",
|
||||
error = "",
|
||||
},
|
||||
},
|
||||
modified = {
|
||||
enable = false,
|
||||
show_on_dirs = true,
|
||||
show_on_open_dirs = true,
|
||||
},
|
||||
filters = {
|
||||
enable = true,
|
||||
git_ignored = true,
|
||||
dotfiles = false,
|
||||
git_clean = false,
|
||||
no_buffer = false,
|
||||
no_bookmark = false,
|
||||
custom = {},
|
||||
exclude = {},
|
||||
},
|
||||
live_filter = {
|
||||
prefix = "[FILTER]: ",
|
||||
always_show_folders = true,
|
||||
},
|
||||
filesystem_watchers = {
|
||||
enable = true,
|
||||
debounce_delay = 50,
|
||||
ignore_dirs = {},
|
||||
},
|
||||
actions = {
|
||||
use_system_clipboard = true,
|
||||
change_dir = {
|
||||
enable = true,
|
||||
global = false,
|
||||
restrict_above_cwd = false,
|
||||
},
|
||||
expand_all = {
|
||||
max_folder_discovery = 300,
|
||||
exclude = {},
|
||||
},
|
||||
file_popup = {
|
||||
open_win_config = {
|
||||
col = 1,
|
||||
row = 1,
|
||||
relative = "cursor",
|
||||
border = "shadow",
|
||||
style = "minimal",
|
||||
},
|
||||
},
|
||||
open_file = {
|
||||
quit_on_open = false,
|
||||
eject = true,
|
||||
resize_window = true,
|
||||
window_picker = {
|
||||
enable = true,
|
||||
picker = "default",
|
||||
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
|
||||
exclude = {
|
||||
filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" },
|
||||
buftype = { "nofile", "terminal", "help" },
|
||||
},
|
||||
},
|
||||
},
|
||||
remove_file = {
|
||||
close_window = true,
|
||||
},
|
||||
},
|
||||
trash = {
|
||||
cmd = "gio trash",
|
||||
},
|
||||
tab = {
|
||||
sync = {
|
||||
open = false,
|
||||
close = false,
|
||||
ignore = {},
|
||||
},
|
||||
},
|
||||
notify = {
|
||||
threshold = vim.log.levels.INFO,
|
||||
absolute_path = true,
|
||||
},
|
||||
help = {
|
||||
sort_by = "key",
|
||||
},
|
||||
ui = {
|
||||
confirm = {
|
||||
remove = true,
|
||||
trash = true,
|
||||
default_yes = false,
|
||||
},
|
||||
},
|
||||
experimental = {
|
||||
actions = {
|
||||
open_file = {
|
||||
relative_path = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
truncate = false,
|
||||
types = {
|
||||
all = false,
|
||||
config = false,
|
||||
copy_paste = false,
|
||||
dev = false,
|
||||
diagnostics = false,
|
||||
git = false,
|
||||
profile = false,
|
||||
watcher = false,
|
||||
},
|
||||
},
|
||||
} -- END_DEFAULT_OPTS
|
||||
|
||||
local function merge_options(conf)
|
||||
return vim.tbl_deep_extend("force", DEFAULT_OPTS, conf or {})
|
||||
end
|
||||
|
||||
local FIELD_SKIP_VALIDATE = {
|
||||
open_win_config = true,
|
||||
}
|
||||
|
||||
local ACCEPTED_TYPES = {
|
||||
on_attach = { "function", "string" },
|
||||
sort = {
|
||||
sorter = { "function", "string" },
|
||||
},
|
||||
view = {
|
||||
width = {
|
||||
"string",
|
||||
"function",
|
||||
"number",
|
||||
"table",
|
||||
min = { "string", "function", "number" },
|
||||
max = { "string", "function", "number" },
|
||||
padding = { "function", "number" },
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
hidden_display = { "function", "string" },
|
||||
group_empty = { "boolean", "function" },
|
||||
root_folder_label = { "function", "string", "boolean" },
|
||||
},
|
||||
update_focused_file = {
|
||||
exclude = { "function" },
|
||||
},
|
||||
git = {
|
||||
disable_for_dirs = { "function" },
|
||||
},
|
||||
filters = {
|
||||
custom = { "function" },
|
||||
},
|
||||
filesystem_watchers = {
|
||||
ignore_dirs = { "function" },
|
||||
},
|
||||
actions = {
|
||||
open_file = {
|
||||
window_picker = {
|
||||
picker = { "function", "string" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local ACCEPTED_STRINGS = {
|
||||
sort = {
|
||||
sorter = { "name", "case_sensitive", "modification_time", "extension", "suffix", "filetype" },
|
||||
},
|
||||
view = {
|
||||
side = { "left", "right" },
|
||||
signcolumn = { "yes", "no", "auto" },
|
||||
},
|
||||
renderer = {
|
||||
hidden_display = { "none", "simple", "all" },
|
||||
highlight_git = { "none", "icon", "name", "all" },
|
||||
highlight_opened_files = { "none", "icon", "name", "all" },
|
||||
highlight_modified = { "none", "icon", "name", "all" },
|
||||
highlight_hidden = { "none", "icon", "name", "all" },
|
||||
highlight_bookmarks = { "none", "icon", "name", "all" },
|
||||
highlight_diagnostics = { "none", "icon", "name", "all" },
|
||||
highlight_clipboard = { "none", "icon", "name", "all" },
|
||||
icons = {
|
||||
git_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
modified_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
hidden_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
diagnostics_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
bookmarks_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
},
|
||||
},
|
||||
help = {
|
||||
sort_by = { "key", "desc" },
|
||||
},
|
||||
}
|
||||
|
||||
---@param conf table|nil
|
||||
local function validate_options(conf)
|
||||
local msg
|
||||
|
||||
---@param user any
|
||||
---@param def any
|
||||
---@param strs table
|
||||
---@param types table
|
||||
---@param prefix string
|
||||
local function validate(user, def, strs, types, prefix)
|
||||
-- if user's option is not a table there is nothing to do
|
||||
if type(user) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
-- only compare tables with contents that are not integer indexed
|
||||
if type(def) ~= "table" or not next(def) or type(next(def)) == "number" then
|
||||
-- unless the field can be a table (and is not a table in default config)
|
||||
if vim.tbl_contains(types, "table") then
|
||||
-- use a dummy default to allow all checks
|
||||
def = {}
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(user) do
|
||||
if not FIELD_SKIP_VALIDATE[k] then
|
||||
local invalid
|
||||
|
||||
if def[k] == nil and types[k] == nil then
|
||||
-- option does not exist
|
||||
invalid = string.format("Unknown option: %s%s", prefix, k)
|
||||
elseif type(v) ~= type(def[k]) then
|
||||
local expected
|
||||
|
||||
if types[k] and #types[k] > 0 then
|
||||
if not vim.tbl_contains(types[k], type(v)) then
|
||||
expected = table.concat(types[k], "|")
|
||||
end
|
||||
else
|
||||
expected = type(def[k])
|
||||
end
|
||||
|
||||
if expected then
|
||||
-- option is of the wrong type
|
||||
invalid = string.format("Invalid option: %s%s. Expected %s, got %s", prefix, k, expected, type(v))
|
||||
end
|
||||
elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then
|
||||
-- option has type `string` but value is not accepted
|
||||
invalid = string.format("Invalid value for field %s%s: '%s'", prefix, k, v)
|
||||
end
|
||||
|
||||
if invalid then
|
||||
if msg then
|
||||
msg = string.format("%s\n%s", msg, invalid)
|
||||
else
|
||||
msg = invalid
|
||||
end
|
||||
user[k] = nil
|
||||
else
|
||||
validate(v, def[k], strs[k] or {}, types[k] or {}, prefix .. k .. ".")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
validate(conf, DEFAULT_OPTS, ACCEPTED_STRINGS, ACCEPTED_TYPES, "")
|
||||
|
||||
if msg then
|
||||
notify.warn(msg .. "\n\nsee :help nvim-tree-opts for available configuration options")
|
||||
end
|
||||
end
|
||||
|
||||
--- Apply OS specific localisations to DEFAULT_OPTS
|
||||
local function localise_default_opts()
|
||||
if utils.is_macos or utils.is_windows then
|
||||
DEFAULT_OPTS.trash.cmd = "trash"
|
||||
end
|
||||
end
|
||||
|
||||
function M.purge_all_state()
|
||||
require("nvim-tree.watcher").purge_watchers()
|
||||
view.close_all_tabs()
|
||||
view.abandon_all_windows()
|
||||
if core.get_explorer() ~= nil then
|
||||
require("nvim-tree.git").purge_state()
|
||||
core.reset_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
---@param conf table|nil
|
||||
function M.setup(conf)
|
||||
if vim.fn.has "nvim-0.9" == 0 then
|
||||
notify.warn "nvim-tree.lua requires Neovim 0.9 or higher"
|
||||
return
|
||||
end
|
||||
|
||||
M.init_root = vim.fn.getcwd()
|
||||
|
||||
localise_default_opts()
|
||||
|
||||
require("nvim-tree.legacy").migrate_legacy_options(conf or {})
|
||||
|
||||
validate_options(conf)
|
||||
|
||||
local opts = merge_options(conf)
|
||||
|
||||
local netrw_disabled = opts.disable_netrw or opts.hijack_netrw
|
||||
|
||||
_config.root_dirs = opts.root_dirs
|
||||
_config.prefer_startup_root = opts.prefer_startup_root
|
||||
_config.update_focused_file = opts.update_focused_file
|
||||
_config.hijack_directories = opts.hijack_directories
|
||||
_config.hijack_directories.enable = _config.hijack_directories.enable and netrw_disabled
|
||||
|
||||
manage_netrw(opts.disable_netrw, opts.hijack_netrw)
|
||||
|
||||
M.config = opts
|
||||
require("nvim-tree.notify").setup(opts)
|
||||
require("nvim-tree.log").setup(opts)
|
||||
|
||||
if log.enabled "config" then
|
||||
-- optionally log the configuration
|
||||
if log.enabled("config") then
|
||||
log.line("config", "default config + user")
|
||||
log.raw("config", "%s\n", vim.inspect(opts))
|
||||
log.raw("config", "%s\n", vim.inspect(config.g))
|
||||
end
|
||||
|
||||
require("nvim-tree.actions").setup(opts)
|
||||
require("nvim-tree.keymap").setup(opts)
|
||||
require("nvim-tree.appearance").setup()
|
||||
require("nvim-tree.diagnostics").setup(opts)
|
||||
require("nvim-tree.explorer").setup(opts)
|
||||
require("nvim-tree.git").setup(opts)
|
||||
require("nvim-tree.git.utils").setup(opts)
|
||||
require("nvim-tree.view").setup(opts)
|
||||
require("nvim-tree.lib").setup(opts)
|
||||
require("nvim-tree.renderer.components").setup(opts)
|
||||
require("nvim-tree.buffers").setup(opts)
|
||||
require("nvim-tree.help").setup(opts)
|
||||
require("nvim-tree.watcher").setup(opts)
|
||||
if M.config.renderer.icons.show.file and pcall(require, "nvim-web-devicons") then
|
||||
require("nvim-web-devicons").setup()
|
||||
-- idempotent highlight definition
|
||||
appearance.highlight()
|
||||
|
||||
-- set the initial view state based on config
|
||||
view_state.initialize()
|
||||
|
||||
-- idempotent au (re)definition
|
||||
autocmd.global()
|
||||
|
||||
-- subsequent calls to setup clear all state
|
||||
if vim.g.NvimTreeSetup == 1 then
|
||||
require("nvim-tree.core").purge_all_state()
|
||||
end
|
||||
|
||||
setup_autocommands(opts)
|
||||
|
||||
if vim.g.NvimTreeSetup ~= 1 then
|
||||
-- first call to setup
|
||||
require("nvim-tree.commands").setup()
|
||||
else
|
||||
-- subsequent calls to setup
|
||||
M.purge_all_state()
|
||||
end
|
||||
-- hydrate post setup API
|
||||
api_impl.hydrate_post_setup(api)
|
||||
|
||||
vim.g.NvimTreeSetup = 1
|
||||
vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" })
|
||||
|
||||
11
lua/nvim-tree/_meta/api/appearance.lua
Normal file
11
lua/nvim-tree/_meta/api/appearance.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { appearance = {} } }
|
||||
|
||||
---
|
||||
---Open a new buffer displaying all nvim-tree highlight groups, their link chain and concrete definition.
|
||||
---
|
||||
---Similar to `:so $VIMRUNTIME/syntax/hitest.vim` as per |:highlight|
|
||||
---
|
||||
function nvim_tree.api.appearance.hi_test() end
|
||||
|
||||
return nvim_tree.api.appearance
|
||||
20
lua/nvim-tree/_meta/api/commands.lua
Normal file
20
lua/nvim-tree/_meta/api/commands.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { commands = {} } }
|
||||
|
||||
---
|
||||
---@class nvim_tree.api.commands.Command
|
||||
---@inlinedoc
|
||||
---
|
||||
---@field name string name of the `:NvimTree*` command
|
||||
---@field command fun(args: vim.api.keyset.create_user_command.command_args) function that the command will execute
|
||||
---@field opts vim.api.keyset.user_command [command-attributes]
|
||||
|
||||
---
|
||||
---Retrieve all [nvim-tree-commands]
|
||||
---
|
||||
---They have been created via [nvim_create_user_command()], see also [lua-guide-commands-create]
|
||||
---
|
||||
---@return nvim_tree.api.commands.Command[]
|
||||
function nvim_tree.api.commands.get() end
|
||||
|
||||
return nvim_tree.api.commands
|
||||
33
lua/nvim-tree/_meta/api/config.lua
Normal file
33
lua/nvim-tree/_meta/api/config.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { config = {} } }
|
||||
|
||||
---
|
||||
---Default nvim-tree config.
|
||||
---
|
||||
---@return nvim_tree.config immutable deep clone
|
||||
function nvim_tree.api.config.default() end
|
||||
|
||||
---
|
||||
---Global current nvim-tree config.
|
||||
---
|
||||
---@return nvim_tree.config immutable deep clone
|
||||
function nvim_tree.api.config.global() end
|
||||
|
||||
---
|
||||
---Reference to config passed to [nvim-tree-setup]
|
||||
---
|
||||
---@return nvim_tree.config? nil when no config passed to setup
|
||||
function nvim_tree.api.config.user() end
|
||||
|
||||
nvim_tree.api.config.mappings = {}
|
||||
|
||||
---@deprecated use `nvim_tree.api.map.keymap.current()`
|
||||
function nvim_tree.api.config.mappings.get_keymap() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.map.keymap.default()`
|
||||
function nvim_tree.api.config.mappings.get_keymap_default() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.map.on_attach.default()`
|
||||
function nvim_tree.api.config.mappings.default_on_attach(bufnr) end
|
||||
|
||||
return nvim_tree.api.config
|
||||
103
lua/nvim-tree/_meta/api/decorator.lua
Normal file
103
lua/nvim-tree/_meta/api/decorator.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
---@meta
|
||||
|
||||
---@brief
|
||||
---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview.
|
||||
---
|
||||
---Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of additive precedence, with later decorators applying additively over earlier.
|
||||
---
|
||||
---You may provide your own in addition to the builtin decorators, see |nvim-tree-class-decorator-example|.
|
||||
---
|
||||
---Decorators may:
|
||||
---- Add icons
|
||||
---- Set a highlight group name for the name or icons
|
||||
---- Override node icon
|
||||
---
|
||||
---To register your decorator:
|
||||
---- Create a class that extends [nvim_tree.api.Decorator]
|
||||
---- Register it by adding the class to [nvim_tree.config.renderer] {decorators}
|
||||
---
|
||||
---Your decorator will be constructed and executed each time the tree is rendered.
|
||||
---
|
||||
---Your class must:
|
||||
---- [nvim_tree.Class:extend()] the interface [nvim_tree.api.Decorator]
|
||||
---- Provide a no-arguments constructor [nvim_tree.Class:new()] that sets the mandatory fields:
|
||||
--- - {enabled}
|
||||
--- - {highlight_range}
|
||||
--- - {icon_placement}
|
||||
---- Call [nvim_tree.api.Decorator:define_sign()] in your constructor when {icon_placement} is `"signcolumn"`
|
||||
---
|
||||
---Your class may:
|
||||
---- Implement methods to provide decorations:
|
||||
--- - [nvim_tree.api.Decorator:highlight_group()]
|
||||
--- - [nvim_tree.api.Decorator:icon_node()]
|
||||
--- - [nvim_tree.api.Decorator:icons()]
|
||||
|
||||
local nvim_tree = { api = {} }
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
---
|
||||
---Text or glyphs with optional highlight group names to apply to it.
|
||||
---
|
||||
---@class nvim_tree.api.highlighted_string
|
||||
---
|
||||
---One or many glyphs/characters.
|
||||
---@field str string
|
||||
---
|
||||
---Highlight group names to apply in order. Empty table for no highlighting.
|
||||
---@field hl string[]
|
||||
|
||||
|
||||
---
|
||||
---Decorator interface
|
||||
---
|
||||
---@class nvim_tree.api.Decorator: nvim_tree.Class
|
||||
---
|
||||
---Enable this decorator.
|
||||
---@field enabled boolean
|
||||
---
|
||||
---What to highlight: [nvim_tree.config.renderer.highlight]
|
||||
---@field highlight_range nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---Where to place the icons: [nvim_tree.config.renderer.icons.placement]
|
||||
---@field icon_placement "none"|nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
local Decorator = Class:extend()
|
||||
nvim_tree.api.Decorator = Decorator
|
||||
|
||||
---
|
||||
---Icon to override for the node.
|
||||
---
|
||||
---Abstract, optional to implement.
|
||||
---
|
||||
---@param node nvim_tree.api.Node
|
||||
---@return nvim_tree.api.highlighted_string? icon `nil` for no override
|
||||
function Decorator:icon_node(node) end
|
||||
|
||||
---
|
||||
---Icons to add to the node as per {icon_placement}
|
||||
---
|
||||
---Abstract, optional to implement.
|
||||
---
|
||||
---@param node nvim_tree.api.Node
|
||||
---@return nvim_tree.api.highlighted_string[]? icons `nil` or empty table for no icons. Only the first glyph of {str} is used when {icon_placement} is `"signcolumn"`
|
||||
function Decorator:icons(node) end
|
||||
|
||||
---
|
||||
---One highlight group that applies additively to the {node} name for {highlight_range}.
|
||||
---
|
||||
---Abstract, optional to implement.
|
||||
---
|
||||
---@param node nvim_tree.api.Node
|
||||
---@return string? highlight group name `nil` when no highlighting to apply to the node
|
||||
function Decorator:highlight_group(node) end
|
||||
|
||||
---
|
||||
---Defines a sign for an icon. This is mandatory and necessary only when {icon_placement} is `"signcolumn"`
|
||||
---
|
||||
---This must be called during your constructor for all icons that you will return from [nvim_tree.api.Decorator:icons()]
|
||||
---
|
||||
---@param icon nvim_tree.api.highlighted_string? does nothing if nil
|
||||
function Decorator:define_sign(icon) end
|
||||
|
||||
return nvim_tree.api.Decorator
|
||||
96
lua/nvim-tree/_meta/api/decorator_example.lua
Normal file
96
lua/nvim-tree/_meta/api/decorator_example.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
---@brief
|
||||
---
|
||||
---A decorator class for nodes named "example", overriding all builtin decorators except for Cut.
|
||||
---- Highlights node name with `IncSearch`
|
||||
---- Creates two icons `"1"` and `"2"` placed after the node name, highlighted with `DiffAdd` and `DiffText`
|
||||
---- Replaces the node icon with `"N"`, highlighted with `Error `
|
||||
---
|
||||
---Create a class file `~/.config/nvim/lua/my-decorator.lua`
|
||||
---
|
||||
---Require and register it during |nvim-tree-setup|:
|
||||
---```lua
|
||||
---
|
||||
--- local MyDecorator = require("my-decorator")
|
||||
---
|
||||
--- require("nvim-tree").setup({
|
||||
--- renderer = {
|
||||
--- decorators = {
|
||||
--- "Git",
|
||||
--- "Open",
|
||||
--- "Hidden",
|
||||
--- "Modified",
|
||||
--- "Bookmark",
|
||||
--- "Diagnostics",
|
||||
--- "Copied",
|
||||
--- MyDecorator,
|
||||
--- "Cut",
|
||||
--- },
|
||||
--- },
|
||||
--- })
|
||||
---```
|
||||
---Contents of `my-decorator.lua`:
|
||||
---```lua
|
||||
---
|
||||
--- ---@class (exact) MyDecorator: nvim_tree.api.Decorator
|
||||
--- ---@field private my_icon1 nvim_tree.api.highlighted_string
|
||||
--- ---@field private my_icon2 nvim_tree.api.highlighted_string
|
||||
--- ---@field private my_icon_node nvim_tree.api.highlighted_string
|
||||
--- ---@field private my_highlight_group string
|
||||
--- local MyDecorator = require("nvim-tree.api").Decorator:extend()
|
||||
---
|
||||
--- ---Mandatory constructor :new() will be called once per tree render, with no arguments.
|
||||
--- function MyDecorator:new()
|
||||
--- self.enabled = true
|
||||
--- self.highlight_range = "name"
|
||||
--- self.icon_placement = "after"
|
||||
---
|
||||
--- -- create your icons and highlights once, applied to every node
|
||||
--- self.my_icon1 = { str = "1", hl = { "DiffAdd" } }
|
||||
--- self.my_icon2 = { str = "2", hl = { "DiffText" } }
|
||||
--- self.my_icon_node = { str = "N", hl = { "Error" } }
|
||||
--- self.my_highlight_group = "IncSearch"
|
||||
---
|
||||
--- -- Define the icon signs only once
|
||||
--- -- Only needed if you are using icon_placement = "signcolumn"
|
||||
--- -- self:define_sign(self.my_icon1)
|
||||
--- -- self:define_sign(self.my_icon2)
|
||||
--- end
|
||||
---
|
||||
--- ---Override node icon
|
||||
--- ---@param node nvim_tree.api.Node
|
||||
--- ---@return nvim_tree.api.highlighted_string? icon_node
|
||||
--- function MyDecorator:icon_node(node)
|
||||
--- if node.name == "example" then
|
||||
--- return self.my_icon_node
|
||||
--- else
|
||||
--- return nil
|
||||
--- end
|
||||
--- end
|
||||
---
|
||||
--- ---Return two icons for DecoratorIconPlacement "after"
|
||||
--- ---@param node nvim_tree.api.Node
|
||||
--- ---@return nvim_tree.api.highlighted_string[]? icons
|
||||
--- function MyDecorator:icons(node)
|
||||
--- if node.name == "example" then
|
||||
--- return { self.my_icon1, self.my_icon2, }
|
||||
--- else
|
||||
--- return nil
|
||||
--- end
|
||||
--- end
|
||||
---
|
||||
--- ---Exactly one highlight group for DecoratorHighlightRange "name"
|
||||
--- ---@param node nvim_tree.api.Node
|
||||
--- ---@return string? highlight_group
|
||||
--- function MyDecorator:highlight_group(node)
|
||||
--- if node.name == "example" then
|
||||
--- return self.my_highlight_group
|
||||
--- else
|
||||
--- return nil
|
||||
--- end
|
||||
--- end
|
||||
---
|
||||
--- return MyDecorator
|
||||
---```
|
||||
26
lua/nvim-tree/_meta/api/deprecated.lua
Normal file
26
lua/nvim-tree/_meta/api/deprecated.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
---@meta
|
||||
-- Deprecated top level API modules.
|
||||
-- Remember to add mappings in legacy.lua `api_map`
|
||||
|
||||
local nvim_tree = { api = {} }
|
||||
|
||||
nvim_tree.api.live_filter = {}
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.live.start()`
|
||||
function nvim_tree.api.live_filter.start() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.live.clear()`
|
||||
function nvim_tree.api.live_filter.clear() end
|
||||
|
||||
nvim_tree.api.diagnostics = {}
|
||||
|
||||
---@deprecated use `nvim_tree.api.appearance.hi_test()`
|
||||
function nvim_tree.api.diagnostics.hi_test() end
|
||||
|
||||
nvim_tree.api.decorator = {}
|
||||
|
||||
---@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.Decorator
|
||||
---@deprecated use `nvim_tree.api.Decorator`
|
||||
nvim_tree.api.decorator.UserDecorator = nvim_tree.api.Decorator
|
||||
|
||||
return nvim_tree.api
|
||||
30
lua/nvim-tree/_meta/api/events.lua
Normal file
30
lua/nvim-tree/_meta/api/events.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { events = {} } }
|
||||
|
||||
---@enum nvim_tree.api.events.Event
|
||||
nvim_tree.api.events.Event = {
|
||||
Ready = "Ready",
|
||||
WillRenameNode = "WillRenameNode",
|
||||
NodeRenamed = "NodeRenamed",
|
||||
TreePreOpen = "TreePreOpen",
|
||||
TreeOpen = "TreeOpen",
|
||||
TreeClose = "TreeClose",
|
||||
WillCreateFile = "WillCreateFile",
|
||||
FileCreated = "FileCreated",
|
||||
WillRemoveFile = "WillRemoveFile",
|
||||
FileRemoved = "FileRemoved",
|
||||
FolderCreated = "FolderCreated",
|
||||
FolderRemoved = "FolderRemoved",
|
||||
Resize = "Resize",
|
||||
TreeAttachedPost = "TreeAttachedPost",
|
||||
TreeRendered = "TreeRendered",
|
||||
}
|
||||
|
||||
---
|
||||
---Register a handler for an event, see [nvim-tree-events].
|
||||
---
|
||||
---@param event_type nvim_tree.api.events.Event [nvim_tree_events_kind]
|
||||
---@param callback fun(payload: table?)
|
||||
function nvim_tree.api.events.subscribe(event_type, callback) end
|
||||
|
||||
return nvim_tree.api.events
|
||||
65
lua/nvim-tree/_meta/api/filter.lua
Normal file
65
lua/nvim-tree/_meta/api/filter.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { filter = {} } }
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {enable} which applies to ALL filters.
|
||||
---
|
||||
function nvim_tree.api.filter.toggle() end
|
||||
|
||||
nvim_tree.api.filter.live = {}
|
||||
|
||||
---
|
||||
---Enter live filter mode. Opens an input window with [filetype] `NvimTreeFilter`
|
||||
---
|
||||
function nvim_tree.api.filter.live.start() end
|
||||
|
||||
---
|
||||
---Exit live filter mode.
|
||||
---
|
||||
function nvim_tree.api.filter.live.clear() end
|
||||
|
||||
nvim_tree.api.filter.git = {}
|
||||
|
||||
nvim_tree.api.filter.git.clean = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {git_clean} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.git.clean.toggle() end
|
||||
|
||||
nvim_tree.api.filter.git.ignored = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {git_ignored} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.git.ignored.toggle() end
|
||||
|
||||
nvim_tree.api.filter.dotfiles = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {dotfiles} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.dotfiles.toggle() end
|
||||
|
||||
nvim_tree.api.filter.no_buffer = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {no_buffer} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.no_buffer.toggle() end
|
||||
|
||||
nvim_tree.api.filter.no_bookmark = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {no_bookmark} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.no_bookmark.toggle() end
|
||||
|
||||
nvim_tree.api.filter.custom = {}
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.filters] {custom} filter.
|
||||
---
|
||||
function nvim_tree.api.filter.custom.toggle() end
|
||||
|
||||
return nvim_tree.api.filter
|
||||
130
lua/nvim-tree/_meta/api/fs.lua
Normal file
130
lua/nvim-tree/_meta/api/fs.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { fs = {} } }
|
||||
|
||||
---
|
||||
---Clear the nvim-tree clipboard.
|
||||
---
|
||||
function nvim_tree.api.fs.clear_clipboard() end
|
||||
|
||||
nvim_tree.api.fs.copy = {}
|
||||
|
||||
---
|
||||
---Copy the absolute path to the system clipboard.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.copy.absolute_path(node) end
|
||||
|
||||
---
|
||||
---Copy the name with extension omitted to the system clipboard.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.copy.basename(node) end
|
||||
|
||||
---
|
||||
---Copy the name to the system clipboard.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.copy.filename(node) end
|
||||
|
||||
---
|
||||
---Copy to the nvim-tree clipboard.
|
||||
---In visual mode, copies all nodes in the visual selection.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.copy.node(node) end
|
||||
|
||||
---
|
||||
---Copy the path relative to the tree root to the system clipboard.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.copy.relative_path(node) end
|
||||
|
||||
---
|
||||
---Prompt to create a file or directory.
|
||||
---
|
||||
---When {node} is a file it will be created in the parent directory.
|
||||
---
|
||||
---Use a trailing `"/"` to create a directory e.g. `"foo/"`
|
||||
---
|
||||
---Multiple directories/files may be created e.g. `"foo/bar/baz"`
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.create(node) end
|
||||
|
||||
---
|
||||
---Cut to the nvim-tree clipboard.
|
||||
---In visual mode, cuts all nodes in the visual selection.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.cut(node) end
|
||||
|
||||
---
|
||||
---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.
|
||||
---
|
||||
function nvim_tree.api.fs.print_clipboard() end
|
||||
|
||||
---
|
||||
---Delete from the file system.
|
||||
---In visual mode, deletes all nodes in the visual selection with a single prompt.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.remove(node) end
|
||||
|
||||
---
|
||||
---Prompt to rename by name.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.rename(node) end
|
||||
|
||||
---
|
||||
---Prompt to rename by name with extension omitted.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.rename_basename(node) end
|
||||
|
||||
---
|
||||
---Prompt to rename by absolute path.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.rename_full(node) end
|
||||
|
||||
---
|
||||
---Prompt to rename.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.rename_node(node) end
|
||||
|
||||
---
|
||||
---Prompt to rename by absolute path with name omitted.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.rename_sub(node) end
|
||||
|
||||
---
|
||||
---Trash as per |nvim_tree.config.trash|.
|
||||
---In visual mode, trashes all nodes in the visual selection with a single prompt.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node
|
||||
function nvim_tree.api.fs.trash(node) end
|
||||
|
||||
return nvim_tree.api.fs
|
||||
9
lua/nvim-tree/_meta/api/git.lua
Normal file
9
lua/nvim-tree/_meta/api/git.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { git = {} } }
|
||||
|
||||
---
|
||||
---Update the git status of the entire tree.
|
||||
---
|
||||
function nvim_tree.api.git.reload() end
|
||||
|
||||
return nvim_tree.api.git
|
||||
26
lua/nvim-tree/_meta/api/map.lua
Normal file
26
lua/nvim-tree/_meta/api/map.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { map = {} } }
|
||||
|
||||
nvim_tree.api.map.keymap = {}
|
||||
|
||||
---
|
||||
---Retrieve all buffer local mappings for nvim-tree. These are the mappings that are applied by [nvim_tree.config] {on_attach}, which may include default mappings.
|
||||
---
|
||||
---@return vim.api.keyset.get_keymap[]
|
||||
function nvim_tree.api.map.keymap.current() end
|
||||
|
||||
---
|
||||
--- Retrieves the buffer local mappings for nvim-tree that are applied by [nvim_tree.api.map.on_attach.default()]
|
||||
---
|
||||
---@return vim.api.keyset.get_keymap[]
|
||||
function nvim_tree.api.map.keymap.default() end
|
||||
|
||||
nvim_tree.api.map.on_attach = {}
|
||||
|
||||
---
|
||||
---Apply all [nvim-tree-mappings-default]. Call from your [nvim_tree.config] {on_attach}.
|
||||
---
|
||||
---@param bufnr integer use the `bufnr` passed to {on_attach}
|
||||
function nvim_tree.api.map.on_attach.default(bufnr) end
|
||||
|
||||
return nvim_tree.api.map
|
||||
63
lua/nvim-tree/_meta/api/marks.lua
Normal file
63
lua/nvim-tree/_meta/api/marks.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { marks = {} } }
|
||||
|
||||
---
|
||||
---Return the node if it is marked.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file or directory
|
||||
---@return nvim_tree.api.Node?
|
||||
function nvim_tree.api.marks.get(node) end
|
||||
|
||||
---
|
||||
---Retrieve all marked nodes.
|
||||
---
|
||||
---@return nvim_tree.api.Node[]
|
||||
function nvim_tree.api.marks.list() end
|
||||
|
||||
---
|
||||
---Toggle mark. In visual mode, toggles all nodes in the visual selection.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file or directory
|
||||
function nvim_tree.api.marks.toggle(node) end
|
||||
|
||||
---
|
||||
---Clear all marks.
|
||||
---
|
||||
function nvim_tree.api.marks.clear() end
|
||||
|
||||
nvim_tree.api.marks.bulk = {}
|
||||
|
||||
---
|
||||
---Delete all marked, prompting if [nvim_tree.config.ui.confirm] {remove}
|
||||
---
|
||||
function nvim_tree.api.marks.bulk.delete() end
|
||||
|
||||
---
|
||||
---Delete all marked, prompting if [nvim_tree.config.ui.confirm] {trash}
|
||||
---
|
||||
function nvim_tree.api.marks.bulk.trash() end
|
||||
|
||||
---
|
||||
---Prompts for a directory to move all marked nodes into.
|
||||
---
|
||||
function nvim_tree.api.marks.bulk.move() end
|
||||
|
||||
nvim_tree.api.marks.navigate = {}
|
||||
|
||||
---
|
||||
---Navigate to the next marked node, wraps.
|
||||
---
|
||||
function nvim_tree.api.marks.navigate.next() end
|
||||
|
||||
---
|
||||
---Navigate to the previous marked node, wraps.
|
||||
---
|
||||
function nvim_tree.api.marks.navigate.prev() end
|
||||
|
||||
---
|
||||
---Prompts for selection of a marked node, sorted by absolute paths.
|
||||
---A folder will be focused, a file will be opened.
|
||||
---
|
||||
function nvim_tree.api.marks.navigate.select() end
|
||||
|
||||
return nvim_tree.api.marks
|
||||
299
lua/nvim-tree/_meta/api/node.lua
Normal file
299
lua/nvim-tree/_meta/api/node.lua
Normal file
@@ -0,0 +1,299 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { node = {} } }
|
||||
|
||||
nvim_tree.api.node.open = {}
|
||||
|
||||
---
|
||||
---@class nvim_tree.api.node.open.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Quits the tree when opening the file.
|
||||
---(default: false)
|
||||
---@field quit_on_open? boolean
|
||||
---
|
||||
---Keep focus in the tree when opening the file.
|
||||
---(default: false)
|
||||
---@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
|
||||
---- root: change directory up
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
---@param opts? nvim_tree.api.node.open.Opts optional
|
||||
function nvim_tree.api.node.open.edit(node, opts) end
|
||||
|
||||
---
|
||||
---Open file in a new horizontal split.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
---@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.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file
|
||||
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
|
||||
---@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, 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
|
||||
|
||||
---
|
||||
---Toggle [nvim_tree.config.renderer] {group_empty} for a directory. Needs {group_empty} set.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory
|
||||
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
|
||||
---@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
|
||||
---@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
|
||||
---@inlinedoc
|
||||
---
|
||||
---Proceed even if the buffer is modified.
|
||||
---(default: false)
|
||||
---@field force? boolean
|
||||
|
||||
|
||||
nvim_tree.api.node.buffer = {}
|
||||
|
||||
---
|
||||
---Deletes node's related buffer, if one exists. Executes [:bdelete] or [:bdelete]!
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file
|
||||
---@param opts? nvim_tree.api.node.buffer.RemoveOpts
|
||||
function nvim_tree.api.node.buffer.delete(node, opts) end
|
||||
|
||||
---
|
||||
---Wipes node's related buffer, if one exists. Executes [:bwipe] or [:bwipe]!
|
||||
---
|
||||
---@param node? nvim_tree.api.Node file
|
||||
---@param opts? nvim_tree.api.node.buffer.RemoveOpts optional
|
||||
function nvim_tree.api.node.buffer.wipe(node, opts) end
|
||||
|
||||
---
|
||||
---Collapse the tree under a directory or a file's parent directory.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
---@param opts? nvim_tree.api.node.collapse.Opts optional
|
||||
function nvim_tree.api.node.collapse(node, opts) end
|
||||
|
||||
---@class nvim_tree.api.node.collapse.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Do not collapse nodes with open buffers.
|
||||
---(default: false)
|
||||
---@field keep_buffers? boolean
|
||||
|
||||
---
|
||||
---Recursively expand all nodes under a directory or a file's parent directory.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
---@param opts? nvim_tree.api.node.expand.Opts optional
|
||||
function nvim_tree.api.node.expand(node, opts) end
|
||||
|
||||
---@class nvim_tree.api.node.expand.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Return `true` if `node` should be expanded. `expansion_count` is the total number of folders expanded.
|
||||
---@field expand_until? fun(expansion_count: integer, node: Node): boolean
|
||||
|
||||
|
||||
nvim_tree.api.node.navigate = {}
|
||||
|
||||
---
|
||||
---Navigate to the parent directory of the node.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.parent(node) end
|
||||
|
||||
---
|
||||
---Navigate to the parent directory of the node, closing it.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.parent_close(node) end
|
||||
|
||||
nvim_tree.api.node.navigate.diagnostics = {}
|
||||
|
||||
---
|
||||
---Navigate to the next item showing diagnostic status.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.diagnostics.next(node) end
|
||||
|
||||
---
|
||||
---Navigate to the next item showing diagnostic status, recursively. Needs [nvim_tree.config.diagnostics] {show_on_dirs}
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.diagnostics.next_recursive(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous item showing diagnostic status.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.diagnostics.prev(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous item showing diagnostic status, recursively. Needs [nvim_tree.config.diagnostics] {show_on_dirs}
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.diagnostics.prev_recursive(node) end
|
||||
|
||||
nvim_tree.api.node.navigate.git = {}
|
||||
|
||||
---
|
||||
---Navigate to the next item showing git status.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.next(node) end
|
||||
|
||||
---
|
||||
---Navigate to the next item showing git status, recursively. Needs [nvim_tree.config.git] {show_on_dirs}
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.next_recursive(node) end
|
||||
|
||||
---
|
||||
---Navigate to the next item showing git status, skipping `.gitignore`
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.next_skip_gitignored(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous item showing git status.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.prev(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous item showing git status, recursively. Needs [nvim_tree.config.git] {show_on_dirs}
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.prev_recursive(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous item showing git status, skipping `.gitignore`
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.git.prev_skip_gitignored(node) end
|
||||
|
||||
nvim_tree.api.node.navigate.opened = {}
|
||||
|
||||
---
|
||||
---Navigate to the next [bufloaded()] file.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.opened.next(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous [bufloaded()] file.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.opened.prev(node) end
|
||||
|
||||
nvim_tree.api.node.navigate.sibling = {}
|
||||
|
||||
---
|
||||
---Navigate to the first node in the current node's folder.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.sibling.first(node) end
|
||||
|
||||
---
|
||||
---Navigate to the last node in the current node's folder.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.sibling.last(node) end
|
||||
|
||||
---
|
||||
---Navigate to the next node in the current node's folder, wraps.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.sibling.next(node) end
|
||||
|
||||
---
|
||||
---Navigate to the previous node in the current node's folder, wraps.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.navigate.sibling.prev(node) end
|
||||
|
||||
nvim_tree.api.node.run = {}
|
||||
|
||||
---
|
||||
---Enter [cmdline] with the full path of the node and the cursor at the start of the line.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.run.cmd(node) end
|
||||
|
||||
---
|
||||
---Open with the system default handler: [vim.ui.open()].
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.run.system(node) end
|
||||
|
||||
---
|
||||
---Open a popup window showing: fullpath, size, accessed, modified, created.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.node.show_info_popup(node) end
|
||||
|
||||
return nvim_tree.api.node
|
||||
253
lua/nvim-tree/_meta/api/tree.lua
Normal file
253
lua/nvim-tree/_meta/api/tree.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
---@meta
|
||||
local nvim_tree = { api = { tree = {} } }
|
||||
|
||||
---
|
||||
---Open the tree, focusing it if already open.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.open.Opts optional
|
||||
function nvim_tree.api.tree.open(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.open.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Root directory for the tree
|
||||
---@field path? string
|
||||
---
|
||||
---Open the tree in the current window
|
||||
---(default: false)
|
||||
---@field current_window? boolean
|
||||
---
|
||||
---Open the tree in the specified [window-ID], overrides {current_window}
|
||||
---@field winid? integer
|
||||
---
|
||||
---Find the current buffer.
|
||||
---(default: false)
|
||||
---@field find_file? boolean
|
||||
---
|
||||
---Update root following {find_file}, see [nvim_tree.config.update_focused_file] {update_root}
|
||||
---(default: false)
|
||||
---@field update_root? boolean
|
||||
|
||||
---
|
||||
---Open or close the tree.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.toggle.Opts optional
|
||||
function nvim_tree.api.tree.toggle(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.toggle.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Root directory for the tree
|
||||
---@field path? string
|
||||
---
|
||||
---Open the tree in the current window
|
||||
---(default: false)
|
||||
---@field current_window? boolean
|
||||
---
|
||||
---Open the tree in the specified [window-ID], overrides {current_window}
|
||||
---@field winid? integer
|
||||
---
|
||||
---Find the current buffer.
|
||||
---(default: false)
|
||||
---@field find_file? boolean
|
||||
---
|
||||
---Update root following {find_file}, see [nvim_tree.config.update_focused_file] {update_root}
|
||||
---(default: false)
|
||||
---@field update_root? boolean
|
||||
---
|
||||
---Focus the tree when opening.
|
||||
---(default: true)
|
||||
---@field focus? boolean
|
||||
|
||||
---
|
||||
---Close the tree, affecting all tabs as per [nvim_tree.config.tab.sync] {close}
|
||||
---
|
||||
function nvim_tree.api.tree.close() end
|
||||
|
||||
---
|
||||
---Close the tree in this tab only.
|
||||
---
|
||||
function nvim_tree.api.tree.close_in_this_tab() end
|
||||
|
||||
---
|
||||
---Close the tree in all tabs.
|
||||
---
|
||||
function nvim_tree.api.tree.close_in_all_tabs() end
|
||||
|
||||
---
|
||||
---Focus the tree, opening it if necessary. Retained for compatibility, use [nvim_tree.api.tree.open()] with no arguments instead.
|
||||
---
|
||||
function nvim_tree.api.tree.focus() end
|
||||
|
||||
---
|
||||
---Refresh the tree. Does nothing if closed.
|
||||
---
|
||||
function nvim_tree.api.tree.reload() end
|
||||
|
||||
---
|
||||
---Resize the tree, persisting the new size. Resets to [nvim_tree.config.view] {width} when no {opts} provided.
|
||||
---
|
||||
---Only one option is supported, priority order: {width}, {absolute}, {relative}.
|
||||
---
|
||||
---{absolute} and {relative} do nothing when [nvim_tree.config.view] {width} is a function.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.resize.Opts optional
|
||||
function nvim_tree.api.tree.resize(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.resize.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---New [nvim_tree.config.view] {width} value.
|
||||
---@field width? nvim_tree.config.view.width.spec|nvim_tree.config.view.width
|
||||
---
|
||||
---Set the width.
|
||||
---@field absolute? integer
|
||||
---
|
||||
---Increase or decrease the width.
|
||||
---@field relative? integer
|
||||
|
||||
---
|
||||
---Change the tree's root to a path.
|
||||
---
|
||||
---@param path? string absolute or relative path.
|
||||
function nvim_tree.api.tree.change_root(path) end
|
||||
|
||||
---
|
||||
---Change the tree's root to a folder node or the parent of a file node.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.tree.change_root_to_node(node) end
|
||||
|
||||
---
|
||||
---Change the tree's root to the parent of a node.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory or file
|
||||
function nvim_tree.api.tree.change_root_to_parent(node) end
|
||||
|
||||
---
|
||||
---Retrieve the currently focused node.
|
||||
---
|
||||
---@return nvim_tree.api.Node? nil if tree is not visible.
|
||||
function nvim_tree.api.tree.get_node_under_cursor() end
|
||||
|
||||
---
|
||||
---Retrieve a hierarchical list of all the nodes.
|
||||
---
|
||||
---@return nvim_tree.api.Node[]
|
||||
function nvim_tree.api.tree.get_nodes() end
|
||||
|
||||
---
|
||||
---Find and focus a file or folder in the tree. Finds current buffer unless otherwise specified.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.find_file.Opts optional
|
||||
function nvim_tree.api.tree.find_file(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.find_file.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Absolute/relative path OR `bufnr` to find.
|
||||
---@field buf? string|integer
|
||||
---
|
||||
---Open the tree if necessary.
|
||||
---(default: false)
|
||||
---@field open? boolean
|
||||
---
|
||||
---Requires {open}: open in the current window.
|
||||
---(default: false)
|
||||
---@field current_window? boolean
|
||||
---
|
||||
---Open the tree in the specified [window-ID], overrides {current_window}
|
||||
---@field winid? integer
|
||||
---
|
||||
---Update root after find, see [nvim_tree.config.update_focused_file] {update_root}
|
||||
---(default: false)
|
||||
---@field update_root? boolean
|
||||
---
|
||||
---Focus the tree window.
|
||||
---(default: false)
|
||||
---@field focus? boolean
|
||||
|
||||
---
|
||||
---Open the search dialogue.
|
||||
---
|
||||
function nvim_tree.api.tree.search_node() end
|
||||
|
||||
---
|
||||
---Collapse the tree.
|
||||
---
|
||||
---@param opts? nvim_tree.api.node.collapse.Opts optional
|
||||
function nvim_tree.api.tree.collapse_all(opts) end
|
||||
|
||||
---
|
||||
---Recursively expand all nodes under the tree root or specified folder.
|
||||
---
|
||||
---@param node? nvim_tree.api.Node directory
|
||||
---@param opts? nvim_tree.api.node.expand.Opts optional
|
||||
function nvim_tree.api.tree.expand_all(node, opts) end
|
||||
|
||||
---
|
||||
---Toggle help view.
|
||||
---
|
||||
function nvim_tree.api.tree.toggle_help() end
|
||||
|
||||
---
|
||||
---Checks if a buffer is an nvim-tree.
|
||||
---
|
||||
---@param bufnr? integer 0 or nil for current buffer.
|
||||
---
|
||||
---@return boolean
|
||||
function nvim_tree.api.tree.is_tree_buf(bufnr) end
|
||||
|
||||
---
|
||||
---Checks if nvim-tree is visible on the current, specified or any tab.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.is_visible.Opts optional
|
||||
---@return boolean
|
||||
function nvim_tree.api.tree.is_visible(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.is_visible.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
--- [tab-ID] 0 or nil for current.
|
||||
---@field tabpage? integer
|
||||
---
|
||||
---Visible on any tab.
|
||||
---(default: false)
|
||||
---@field any_tabpage? boolean
|
||||
|
||||
---
|
||||
---Retrieve the window of the open tree.
|
||||
---
|
||||
---@param opts? nvim_tree.api.tree.winid.Opts optional
|
||||
---@return integer? [window-ID], nil if tree is not visible.
|
||||
function nvim_tree.api.tree.winid(opts) end
|
||||
|
||||
---@class nvim_tree.api.tree.winid.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---[tab-ID] 0 or nil for current.
|
||||
---@field tabpage? integer
|
||||
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.toggle()`
|
||||
function nvim_tree.api.tree.toggle_enable_filters() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.git.ignored.toggle()`
|
||||
function nvim_tree.api.tree.toggle_gitignore_filter() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.git.clean.toggle()`
|
||||
function nvim_tree.api.tree.toggle_git_clean_filter() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.no_buffer.toggle()`
|
||||
function nvim_tree.api.tree.toggle_no_buffer_filter() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.custom.toggle()`
|
||||
function nvim_tree.api.tree.toggle_custom_filter() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.dotfiles.toggle()`
|
||||
function nvim_tree.api.tree.toggle_hidden_filter() end
|
||||
|
||||
---@deprecated use `nvim_tree.api.filter.no_bookmark.toggle()`
|
||||
function nvim_tree.api.tree.toggle_no_bookmark_filter() end
|
||||
|
||||
return nvim_tree.api.tree
|
||||
38
lua/nvim-tree/_meta/classes.lua
Normal file
38
lua/nvim-tree/_meta/classes.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
---
|
||||
---File
|
||||
---
|
||||
---@class (exact) nvim_tree.api.FileNode: nvim_tree.api.Node
|
||||
---@field extension string
|
||||
|
||||
---
|
||||
---Directory
|
||||
---
|
||||
---@class (exact) nvim_tree.api.DirectoryNode: nvim_tree.api.Node
|
||||
---@field has_children boolean
|
||||
---@field nodes nvim_tree.api.Node[]
|
||||
---@field open boolean
|
||||
|
||||
---
|
||||
---Root Directory
|
||||
---
|
||||
---@class (exact) nvim_tree.api.RootNode: nvim_tree.api.DirectoryNode
|
||||
|
||||
---
|
||||
---Link mixin
|
||||
---
|
||||
---@class (exact) nvim_tree.api.LinkNode
|
||||
---@field link_to string
|
||||
---@field fs_stat_target uv.fs_stat.result
|
||||
|
||||
---
|
||||
---File Link
|
||||
---
|
||||
---@class (exact) nvim_tree.api.FileLinkNode: nvim_tree.api.FileNode, nvim_tree.api.LinkNode
|
||||
|
||||
---
|
||||
---DirectoryLink
|
||||
---
|
||||
---@class (exact) nvim_tree.api.DirectoryLinkNode: nvim_tree.api.DirectoryNode, nvim_tree.api.LinkNode
|
||||
133
lua/nvim-tree/_meta/config.lua
Normal file
133
lua/nvim-tree/_meta/config.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
-- Root class {field}s are documented manually above "Fields:" as there is insufficent room for them in the column.
|
||||
|
||||
|
||||
|
||||
---Arguments to pass to [nvim-tree-setup].
|
||||
---
|
||||
---When a value is not present/nil, the default will be used.
|
||||
---
|
||||
---{on_attach} Runs when creating the nvim-tree buffer. Use this to set your [nvim-tree-mappings]. When not a function, [nvim-tree-mappings-default] will be used.
|
||||
---
|
||||
---{hijack_cursor} keep the cursor on the first letter of the filename when moving in the tree.
|
||||
---
|
||||
---{auto_reload_on_write} reload the explorer every time a buffer is written to.
|
||||
---
|
||||
---{disable_netrw} completely disables [netrw], see [nvim-tree-netrw] for details. It is strongly advised to eagerly disable netrw, due to race conditions at vim startup.
|
||||
---
|
||||
---{hijack_netrw} hijacks netrw windows, ignored when {disable_netrw}.
|
||||
---
|
||||
---{hijack_unnamed_buffer_when_opening} opens in place of the unnamed buffer if it's empty.
|
||||
---
|
||||
---{root_dirs} preferred root directories, requires [nvim_tree.config.update_focused_file.update_root].
|
||||
---
|
||||
---{prefer_startup_root} prefer startup root directory when updating root directory of the tree. Requires [nvim_tree.config.update_focused_file.update_root].
|
||||
---
|
||||
---{sync_root_with_cwd} changes the tree root directory on [DirChanged] and refreshes the tree.
|
||||
---
|
||||
---{reload_on_bufenter} automatically reloads the tree on [BufEnter] nvim-tree.
|
||||
---
|
||||
---{respect_buf_cwd} changes the [current-directory] of nvim-tree to that of new buffer's when opening nvim-tree.
|
||||
---
|
||||
---{select_prompts} uses [vim.ui.select()] style prompts. Necessary when using a UI prompt decorator such as dressing.nvim or telescope-ui-select.nvim
|
||||
---@class nvim_tree.config
|
||||
---
|
||||
---(default: `default`)
|
||||
---@field on_attach? "default"|(fun(bufnr: integer))
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field hijack_cursor? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field auto_reload_on_write? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field disable_netrw? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field hijack_netrw? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field hijack_unnamed_buffer_when_opening? boolean
|
||||
---
|
||||
---(default: `{}`)
|
||||
---@field root_dirs? string[]
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field prefer_startup_root? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field sync_root_with_cwd? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field reload_on_bufenter? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field respect_buf_cwd? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field select_prompts? boolean
|
||||
---
|
||||
---[nvim_tree.config.sort]
|
||||
---@field sort? nvim_tree.config.sort
|
||||
---
|
||||
---[nvim_tree.config.view]
|
||||
---@field view? nvim_tree.config.view
|
||||
---
|
||||
---[nvim_tree.config.renderer]
|
||||
---@field renderer? nvim_tree.config.renderer
|
||||
---
|
||||
---[nvim_tree.config.hijack_directories]
|
||||
---@field hijack_directories? nvim_tree.config.hijack_directories
|
||||
---
|
||||
---[nvim_tree.config.update_focused_file]
|
||||
---@field update_focused_file? nvim_tree.config.update_focused_file
|
||||
---
|
||||
---[nvim_tree.config.git]
|
||||
---@field git? nvim_tree.config.git
|
||||
---
|
||||
---[nvim_tree.config.diagnostics]
|
||||
---@field diagnostics? nvim_tree.config.diagnostics
|
||||
---
|
||||
---[nvim_tree.config.modified]
|
||||
---@field modified? nvim_tree.config.modified
|
||||
---
|
||||
---[nvim_tree.config.filters]
|
||||
---@field filters? nvim_tree.config.filters
|
||||
---
|
||||
---[nvim_tree.config.live_filter]
|
||||
---@field live_filter? nvim_tree.config.live_filter
|
||||
---
|
||||
---[nvim_tree.config.filesystem_watchers]
|
||||
---@field filesystem_watchers? nvim_tree.config.filesystem_watchers
|
||||
---
|
||||
---[nvim_tree.config.actions]
|
||||
---@field actions? nvim_tree.config.actions
|
||||
---
|
||||
---[nvim_tree.config.trash]
|
||||
---@field trash? nvim_tree.config.trash
|
||||
---
|
||||
---[nvim_tree.config.tab]
|
||||
---@field tab? nvim_tree.config.tab
|
||||
---
|
||||
---[nvim_tree.config.bookmarks]
|
||||
---@field bookmarks? nvim_tree.config.bookmarks
|
||||
---
|
||||
---[nvim_tree.config.notify]
|
||||
---@field notify? nvim_tree.config.notify
|
||||
---
|
||||
---[nvim_tree.config.help]
|
||||
---@field help? nvim_tree.config.help
|
||||
---
|
||||
---[nvim_tree.config.ui]
|
||||
---@field ui? nvim_tree.config.ui
|
||||
---
|
||||
---[nvim_tree.config.experimental]
|
||||
---@field experimental? nvim_tree.config.experimental
|
||||
---
|
||||
---[nvim_tree.config.log]
|
||||
---@field log? nvim_tree.config.log
|
||||
140
lua/nvim-tree/_meta/config/actions.lua
Normal file
140
lua/nvim-tree/_meta/config/actions.lua
Normal file
@@ -0,0 +1,140 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---@class nvim_tree.config.actions
|
||||
---
|
||||
---Use the system clipboard for copy/paste. Copied text will be stored in registers `+` (system), otherwise, it will be stored in `1` and `"`
|
||||
---(default: `true`)
|
||||
---@field use_system_clipboard? boolean
|
||||
---
|
||||
---[nvim_tree.config.actions.change_dir]
|
||||
---@field change_dir? nvim_tree.config.actions.change_dir
|
||||
---
|
||||
---[nvim_tree.config.actions.expand_all]
|
||||
---@field expand_all? nvim_tree.config.actions.expand_all
|
||||
---
|
||||
---[nvim_tree.config.actions.file_popup]
|
||||
---@field file_popup? nvim_tree.config.actions.file_popup
|
||||
---
|
||||
---[nvim_tree.config.actions.open_file]
|
||||
---@field open_file? nvim_tree.config.actions.open_file
|
||||
---
|
||||
---[nvim_tree.config.actions.remove_file]
|
||||
---@field remove_file? nvim_tree.config.actions.remove_file
|
||||
|
||||
|
||||
|
||||
--- vim [current-directory] behaviour
|
||||
---@class nvim_tree.config.actions.change_dir
|
||||
---
|
||||
---Change the working directory when changing directories in the tree
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Use `:cd` instead of `:lcd` when changing directories.
|
||||
---(default: `false`)
|
||||
---@field global? boolean
|
||||
---
|
||||
--- Restrict changing to a directory above the global cwd.
|
||||
---(default: `false`)
|
||||
---@field restrict_above_cwd? boolean
|
||||
|
||||
|
||||
|
||||
---Configure [nvim_tree.api.tree.expand_all()] and [nvim_tree.api.node.expand()]
|
||||
---@class nvim_tree.config.actions.expand_all
|
||||
---
|
||||
---Limit the number of folders being explored when expanding every folder. Avoids hanging Nvim when running this action on very large folders.
|
||||
---(default: `300`)
|
||||
---@field max_folder_discovery? integer
|
||||
---
|
||||
---A list of directories that should not be expanded automatically e.g `{ ".git", "target", "build" }`
|
||||
---(default: `{}`)
|
||||
---@field exclude? string[]
|
||||
|
||||
|
||||
|
||||
---{file_popup} floating window.
|
||||
---
|
||||
---{open_win_config} is passed to [nvim_open_win()], default:
|
||||
---```lua
|
||||
--- {
|
||||
--- col = 1,
|
||||
--- row = 1,
|
||||
--- relative = "cursor",
|
||||
--- border = "shadow",
|
||||
--- style = "minimal",
|
||||
--- }
|
||||
---```
|
||||
---You shouldn't define {width} and {height} values here. They will be overridden to fit the file_popup content.
|
||||
---@class nvim_tree.config.actions.file_popup
|
||||
---
|
||||
---(default: `{ col = 1, row = 1, relative = "cursor", border = "shadow", style = "minimal", }`)
|
||||
---@field open_win_config? vim.api.keyset.win_config
|
||||
|
||||
|
||||
|
||||
---Opening files.
|
||||
---@class nvim_tree.config.actions.open_file
|
||||
---
|
||||
---Closes the explorer when opening a file
|
||||
---(default: `false`)
|
||||
---@field quit_on_open? boolean
|
||||
---
|
||||
---Prevent new opened file from opening in the same window as the tree.
|
||||
---(default: `true`)
|
||||
---@field eject? boolean
|
||||
---
|
||||
---Resizes the tree when opening a file
|
||||
---(default: `true`)
|
||||
---@field resize_window? boolean
|
||||
---
|
||||
---[nvim_tree.config.actions.open_file.window_picker]
|
||||
---@field window_picker? nvim_tree.config.actions.open_file.window_picker
|
||||
|
||||
|
||||
|
||||
---A window picker will be shown when there are multiple windows available to open a file. It will show a single character identifier in each window's status line.
|
||||
---
|
||||
---When it is not enabled the file will open in the window from which you last opened the tree, obeying {exclude}
|
||||
---
|
||||
---You may define a {picker} function that should return the window id that will open the node, or `nil` if an invalid window is picked or user cancelled the action. The picker may create a new window.
|
||||
---
|
||||
---@class nvim_tree.config.actions.open_file.window_picker
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Change the default window picker or define your own.
|
||||
---(default: `"default"`)
|
||||
---@field picker? "default"|(fun(): integer)
|
||||
---
|
||||
---Identifier characters to use.
|
||||
---(default: `"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"`)
|
||||
---@field chars? string
|
||||
---
|
||||
---[nvim_tree.config.actions.open_file.window_picker.exclude]
|
||||
---@field exclude? nvim_tree.config.actions.open_file.window_picker.exclude
|
||||
|
||||
|
||||
|
||||
---Tables of buffer option names mapped to a list of option values. Windows containing matching buffers will not be:
|
||||
--- - available when using a window picker
|
||||
--- - selected when not using a window picker
|
||||
---@class nvim_tree.config.actions.open_file.window_picker.exclude
|
||||
---
|
||||
---(default: `{ "notify", "lazy", "qf", "diff", "fugitive", "fugitiveblame", }`)
|
||||
---@field filetype? string[]
|
||||
---
|
||||
---(default: `{ "nofile", "terminal", "help", }`)
|
||||
---@field buftype? string[]
|
||||
|
||||
|
||||
---Removing files.
|
||||
---@class nvim_tree.config.actions.remove_file
|
||||
---
|
||||
---Close any window that displays a file when removing that file from the tree.
|
||||
---(default: `true`)
|
||||
---@field close_window? boolean
|
||||
13
lua/nvim-tree/_meta/config/bookmarks.lua
Normal file
13
lua/nvim-tree/_meta/config/bookmarks.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
---Optionally {persist} bookmarks to a json file:
|
||||
---- `true` use default: `stdpath("data") .. "/nvim-tree-bookmarks.json"`
|
||||
---- `false` do not persist
|
||||
---- `string` absolute path of your choice
|
||||
---
|
||||
---@class nvim_tree.config.bookmarks
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field persist? boolean|string
|
||||
10
lua/nvim-tree/_meta/config/default.lua
Normal file
10
lua/nvim-tree/_meta/config/default.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
---@brief
|
||||
---Following is the default configuration, see |nvim_tree.config| for details.
|
||||
---
|
||||
---```lua
|
||||
---
|
||||
--- ---@type nvim_tree.config
|
||||
--- local config = {
|
||||
--- config-default-injection-placeholder
|
||||
--- }
|
||||
---```
|
||||
65
lua/nvim-tree/_meta/config/diagnostics.lua
Normal file
65
lua/nvim-tree/_meta/config/diagnostics.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Integrate with [lsp] or COC diagnostics.
|
||||
---
|
||||
---See [nvim-tree-icons-highlighting].
|
||||
---
|
||||
---@class nvim_tree.config.diagnostics
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Idle milliseconds between diagnostic event and tree update.
|
||||
---(default: `500`)
|
||||
---@field debounce_delay? integer
|
||||
---
|
||||
---Show diagnostic icons on parent directories.
|
||||
---(default: `false`)
|
||||
---@field show_on_dirs? boolean
|
||||
---
|
||||
---Show diagnostics icons on directories that are open. Requires {show_on_dirs}.
|
||||
---(default: `true`)
|
||||
---@field show_on_open_dirs? boolean
|
||||
---
|
||||
---Global [vim.diagnostic.Opts] overrides {severity} and {icons}
|
||||
---(default: `false`)
|
||||
---@field diagnostic_opts? boolean
|
||||
---
|
||||
---@field severity? nvim_tree.config.diagnostics.severity
|
||||
---
|
||||
---@field icons? nvim_tree.config.diagnostics.icons
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.diagnostics.severity]()
|
||||
---@class nvim_tree.config.diagnostics.severity
|
||||
---@inlinedoc
|
||||
---
|
||||
---[vim.diagnostic.severity]
|
||||
---(default: HINT)
|
||||
---@field min? vim.diagnostic.Severity
|
||||
---
|
||||
---[vim.diagnostic.severity]
|
||||
---(default: ERROR)
|
||||
---@field max? vim.diagnostic.Severity
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.diagnostics.icons]()
|
||||
---@class nvim_tree.config.diagnostics.icons
|
||||
---@inlinedoc
|
||||
---
|
||||
---(default: `""` )
|
||||
---@field hint? string
|
||||
---
|
||||
---(default: `""` )
|
||||
---@field info? string
|
||||
---
|
||||
---(default: `""` )
|
||||
---@field warning? string
|
||||
---
|
||||
---(default: `""` )
|
||||
---@field error? string
|
||||
19
lua/nvim-tree/_meta/config/experimental.lua
Normal file
19
lua/nvim-tree/_meta/config/experimental.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Experimental features that may become default or optional functionality.
|
||||
---
|
||||
---In the event of a problem please disable the experiment and raise an issue.
|
||||
---
|
||||
---@class nvim_tree.config.experimental
|
||||
---
|
||||
---Restore nvim-tree buffers when restoring vim sessions (requires 0.13+).
|
||||
---(default: `false`)
|
||||
---@field session_restore_nvim? boolean
|
||||
--Example below for future reference:
|
||||
--
|
||||
--Buffers opened by nvim-tree will use with relative paths instead of absolute.
|
||||
--(default: false)
|
||||
--@field relative_path? boolean
|
||||
47
lua/nvim-tree/_meta/config/filesystem_watchers.lua
Normal file
47
lua/nvim-tree/_meta/config/filesystem_watchers.lua
Normal file
@@ -0,0 +1,47 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Use file system watchers (libuv `uv_fs_event_t`) to monitor the filesystem for changes and update the tree.
|
||||
---
|
||||
---With this feature, the tree will be partially updated on specific directory changes, resulting in better performance.
|
||||
---
|
||||
---Blacklist watching absolute directory paths via {ignore_dirs} and optionally whitelist via {whitelist_dirs}:
|
||||
---- A table of |regular-expression| that will be passed to `vim.fn.match`
|
||||
--- - Backslashes must be escaped e.g. `"my-proj/\\.build$"`
|
||||
--- - Literal backslashes must be double escaped to avoid |/magic| e.g. `"C:\\\\src\\\\my-proj"`
|
||||
---- OR a `fun(path: string): boolean` that is passed an absolute path:
|
||||
--- - {ignore_dirs}: return `true` to disable
|
||||
--- - {whitelist_dirs}: return `true` to enable
|
||||
---
|
||||
---{whitelist_dirs} is STRONGLY recommended for windows: [nvim-tree-os-specific].
|
||||
---
|
||||
---After {max_events} consecutive filesystem events on a single directory with an interval < {debounce_delay}:
|
||||
---- The filesystem watcher will be disabled for that directory.
|
||||
---- A warning notification will be shown.
|
||||
---- Consider adding this directory to {ignore_dirs}
|
||||
---
|
||||
---By default, {max_events} is only enabled for windows.
|
||||
---
|
||||
---@class nvim_tree.config.filesystem_watchers
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Idle milliseconds between filesystem change and tree update.
|
||||
---(default: `50`)
|
||||
---@field debounce_delay? integer
|
||||
---
|
||||
---Disable for specific directories.
|
||||
---(default: `{ "/.ccls-cache", "/build", "/node_modules", "/target", "/.zig-cache"}`)
|
||||
---@field ignore_dirs? string[]|(fun(path: string): boolean)
|
||||
---
|
||||
---Optionally enable only for specific directories.
|
||||
---(default: `{}`)
|
||||
---@field whitelist_dirs? string[]|(fun(path: string): boolean)
|
||||
---
|
||||
---Disable for a single directory after {max_events} consecutive events with an interval < {debounce_delay}.
|
||||
---Set to 0 to allow unlimited consecutive events.
|
||||
---(default: `0` or `1000` on windows)
|
||||
---@field max_events? integer
|
||||
60
lua/nvim-tree/_meta/config/filters.lua
Normal file
60
lua/nvim-tree/_meta/config/filters.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Filters may be applied to the tree to exclude the display of file/directories.
|
||||
---
|
||||
---Multiple filters may be applied at once.
|
||||
---
|
||||
---Filters can be set at startup or toggled live via API with default mappings.
|
||||
---
|
||||
---`I `{git_ignored}` `|nvim_tree.api.filter.git.ignored.toggle()|
|
||||
---Ignore files based on `.gitignore`. Requires |nvim_tree.config.git|
|
||||
---
|
||||
---`H `{dotfiles}` `|nvim_tree.api.filter.dotfiles.toggle()|
|
||||
---Filter dotfiles: files/directories starting with a `.`
|
||||
---
|
||||
---`C `{git_clean}` `|nvim_tree.api.filter.git.clean.toggle()|
|
||||
---Filter files with no git status. `.gitignore` files will not be filtered when {git_ignored}, as they are effectively dirty.
|
||||
---
|
||||
---`B `{no_buffer}` `|nvim_tree.api.filter.no_buffer.toggle()|
|
||||
---Filter files that have no |buflisted()| buffer. For performance reasons buffer delete/wipe may not be immediately shown. A reload or filesystem event will always result in an update.
|
||||
---
|
||||
---`M `{no_bookmark}` `|nvim_tree.api.filter.no_bookmark.toggle()|
|
||||
---Filter files that are not bookmarked. Enabling this is not useful as there is no means yet to persist bookmarks.
|
||||
---
|
||||
---`U `{custom}` `|nvim_tree.api.filter.custom.toggle()|
|
||||
---Disable specific file/directory names via:
|
||||
---- a list of backslash escaped |regular-expression| e.g. `"^\\.git""`
|
||||
---- a function passed the absolute path of the directory.
|
||||
---
|
||||
---All filters including live filter may be disabled via {enable} and toggled with |nvim_tree.api.filter.toggle()|
|
||||
---
|
||||
---Files/directories may be {exclude}d from filtering: they will always be shown, overriding {git_ignored}, {dotfiles} and {custom}.
|
||||
---@class nvim_tree.config.filters
|
||||
---
|
||||
---Enable all filters.
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field git_ignored? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field dotfiles? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field git_clean? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field no_buffer? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field no_bookmark? boolean
|
||||
---
|
||||
---(default: `{}`)
|
||||
---@field custom? string[]|(fun(absolute_path: string): boolean)
|
||||
---
|
||||
---(default: `{}`)
|
||||
---@field exclude? string[]
|
||||
39
lua/nvim-tree/_meta/config/git.lua
Normal file
39
lua/nvim-tree/_meta/config/git.lua
Normal file
@@ -0,0 +1,39 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Git operations are run in the background thus status may not immediately appear.
|
||||
---
|
||||
---Processes will be killed if they exceed {timeout} ms. Git integration will be disabled following 5 timeouts and you will be notified.
|
||||
---
|
||||
---Git integration may be disabled for git top-level directories via {disable_for_dirs}:
|
||||
--- - A list of relative paths evaluated with [fnamemodify()] `:p` OR
|
||||
--- - A function that is passed an absolute path and returns `true` to disable
|
||||
---
|
||||
---See [nvim-tree-icons-highlighting].
|
||||
---
|
||||
---@class nvim_tree.config.git
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Show status icons of children when directory itself has no status icon
|
||||
---(default: `true`)
|
||||
---@field show_on_dirs? boolean
|
||||
---
|
||||
---Show status icons of children on directories that are open. Requires {show_on_dirs}.
|
||||
---(default: `true`)
|
||||
---@field show_on_open_dirs? boolean
|
||||
---
|
||||
---Disable for top level paths.
|
||||
---(default: `{}`)
|
||||
---@field disable_for_dirs? string[]|(fun(path: string): boolean)
|
||||
---
|
||||
---`git` processes timeout milliseconds.
|
||||
---(default: `400`)
|
||||
---@field timeout? integer
|
||||
---
|
||||
---Use `cygpath` if available to resolve paths for git.
|
||||
---(Default: `false`)
|
||||
---@field cygwin_support? boolean
|
||||
16
lua/nvim-tree/_meta/config/help.lua
Normal file
16
lua/nvim-tree/_meta/config/help.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---{sort_by} [nvim_tree.config.help.sort_by]()
|
||||
---
|
||||
---Sort help entries alphabetically by:
|
||||
---- `"key"`: map lhs
|
||||
---- `"desc"`: description
|
||||
---@alias nvim_tree.config.help.sort_by "key"|"desc"
|
||||
---
|
||||
---@class nvim_tree.config.help
|
||||
---
|
||||
---(default: `"key"`)
|
||||
---@field sort_by? nvim_tree.config.help.sort_by
|
||||
19
lua/nvim-tree/_meta/config/hijack_directories.lua
Normal file
19
lua/nvim-tree/_meta/config/hijack_directories.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Hijack directory buffers by replacing the directory buffer with the tree.
|
||||
---
|
||||
---Disable this option if you use vim-dirvish or dirbuf.nvim.
|
||||
---
|
||||
---If [nvim_tree.config] {hijack_netrw} and {disable_netrw} are `false` this feature will be disabled.
|
||||
---
|
||||
---@class nvim_tree.config.hijack_directories
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Open if the tree was previously closed.
|
||||
---(default: `true`)
|
||||
---@field auto_open? boolean
|
||||
18
lua/nvim-tree/_meta/config/live_filter.lua
Normal file
18
lua/nvim-tree/_meta/config/live_filter.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
--- Live filter allows you to filter the tree nodes dynamically using [regular-expression] matching.
|
||||
---
|
||||
--- This feature is bound to the `f` key by default. The filter can be cleared with the `F` key by default.
|
||||
---
|
||||
---@class nvim_tree.config.live_filter
|
||||
---
|
||||
---Prefix of the filter displayed in the buffer.
|
||||
---(default: `"[FILTER]: "`)
|
||||
---@field prefix? string
|
||||
---
|
||||
---Whether to filter folders or not.
|
||||
---(default: `true`)
|
||||
---@field always_show_folders? boolean
|
||||
53
lua/nvim-tree/_meta/config/log.lua
Normal file
53
lua/nvim-tree/_meta/config/log.lua
Normal file
@@ -0,0 +1,53 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Log to a file `nvim-tree.log` in [stdpath()] `log`, usually `${XDG_STATE_HOME}/nvim`
|
||||
---
|
||||
---@class nvim_tree.config.log
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Remove existing log file at startup.
|
||||
---(default: `false`)
|
||||
---@field truncate? boolean
|
||||
---
|
||||
---[nvim_tree.config.log.types]
|
||||
---@field types? nvim_tree.config.log.types
|
||||
|
||||
---Specify which information to log.
|
||||
---@class nvim_tree.config.log.types
|
||||
---
|
||||
---Everything.
|
||||
---(default: `false`)
|
||||
---@field all? boolean
|
||||
---
|
||||
--- Timing of some operations.
|
||||
---(default: `false`)
|
||||
---@field profile? boolean
|
||||
---
|
||||
---Config and mappings, at startup.
|
||||
---(default: `false`)
|
||||
---@field config? boolean
|
||||
---
|
||||
---File copy and paste actions.
|
||||
---(default: `false`)
|
||||
---@field copy_paste? boolean
|
||||
---
|
||||
---Used for local development only. Not useful for users.
|
||||
---(default: `false`)
|
||||
---@field dev? boolean
|
||||
---
|
||||
---LSP and COC processing, verbose.
|
||||
---(default: `false`)
|
||||
---@field diagnostics? boolean
|
||||
---
|
||||
---Git processing, verbose.
|
||||
---(default: `false`)
|
||||
---@field git? boolean
|
||||
---
|
||||
---[nvim_tree.config.filesystem_watchers] processing, verbose.
|
||||
---(default: `false`)
|
||||
---@field watcher? boolean
|
||||
24
lua/nvim-tree/_meta/config/modified.lua
Normal file
24
lua/nvim-tree/_meta/config/modified.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Indicate which files have unsaved modification.
|
||||
---To see modified status in the tree you will need:
|
||||
--- - [nvim_tree.config.renderer.icons.show] {modified} OR
|
||||
--- - [nvim_tree.config.renderer] {highlight_modified}
|
||||
---
|
||||
---See [nvim-tree-icons-highlighting].
|
||||
---
|
||||
---@class nvim_tree.config.modified
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Show modified indication on directory whose children are modified.
|
||||
---(default: `true`)
|
||||
---@field show_on_dirs? boolean
|
||||
---
|
||||
---Show modified indication on open directories. Requires {show_on_dirs}.
|
||||
---(default: `false`)
|
||||
---@field show_on_open_dirs? boolean
|
||||
20
lua/nvim-tree/_meta/config/notify.lua
Normal file
20
lua/nvim-tree/_meta/config/notify.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---nvim-tree |vim.log.levels|
|
||||
---- `ERROR`: hard errors e.g. failure to read from the file system.
|
||||
---- `WARN`: non-fatal errors e.g. unable to system open a file.
|
||||
---- `INFO`: information only e.g. file copy path confirmation.
|
||||
---- `DEBUG`: information for troubleshooting, e.g. failures in some window closing operations.
|
||||
---
|
||||
---@class nvim_tree.config.notify
|
||||
---
|
||||
---Specify minimum notification |vim.log.levels|
|
||||
---(Default: `vim.log.levels.INFO`)
|
||||
---@field threshold? vim.log.levels
|
||||
---
|
||||
---Use absolute paths in FS action notifications, otherwise item names.
|
||||
---(default: `true`)
|
||||
---@field absolute_path? boolean
|
||||
385
lua/nvim-tree/_meta/config/renderer.lua
Normal file
385
lua/nvim-tree/_meta/config/renderer.lua
Normal file
@@ -0,0 +1,385 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Controls the appearance of the tree.
|
||||
---
|
||||
---{highlight_} [nvim_tree.config.renderer.highlight]()
|
||||
---
|
||||
---See [nvim-tree-icons-highlighting]
|
||||
---
|
||||
---- `"none"`: no highlighting
|
||||
---- `"icon"`: icon only
|
||||
---- `"name"`: name only
|
||||
---- `"all"`: icon and name
|
||||
---@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all"
|
||||
---
|
||||
---
|
||||
---
|
||||
---{decorators} [nvim_tree.config.renderer.decorator]()
|
||||
---
|
||||
---See [nvim-tree-icons-highlighting]
|
||||
---
|
||||
---A builtin decorator name `string` or |nvim_tree.api.Decorator| class.
|
||||
---
|
||||
---Builtin decorators in their default order:
|
||||
---- `"Git"`
|
||||
---- `"Open"`
|
||||
---- `"Hidden"`
|
||||
---- `"Modified"`
|
||||
---- `"Bookmark"`
|
||||
---- `"Diagnostics"`
|
||||
---- `"Copied"`
|
||||
---- `"Cut"`
|
||||
---
|
||||
---Specify {decorators} is a list e.g. `{ "Git", MyDecorator, "Cut" }`
|
||||
---
|
||||
---@alias nvim_tree.config.renderer.decorator nvim_tree.api.Decorator|"Git"|"Open"|"Hidden"|"Modified"|"Bookmark"|"Diagnostics"|"Copied"|"Cut"
|
||||
---
|
||||
---
|
||||
---
|
||||
---{root_folder_label} [nvim_tree.config.renderer.root_folder_label]()
|
||||
---
|
||||
---Controls the root folder name and visibility:
|
||||
---- `string`: [filename-modifiers] format string, default `":~:s?$?/..?"`
|
||||
---- `false`: to disable
|
||||
---- `fun(root_cwd: string): string`: return a literal string from root's absolute path e.g.
|
||||
---```lua
|
||||
--- my_root_folder_label = function(path)
|
||||
--- return ".../" .. vim.fn.fnamemodify(path, ":t")
|
||||
--- end
|
||||
---```
|
||||
---@alias nvim_tree.config.renderer.root_folder_label string|false|(fun(root_cwd: string): string)
|
||||
---
|
||||
---
|
||||
---
|
||||
---{hidden_display} [nvim_tree.config.renderer.hidden_display]()
|
||||
---
|
||||
---Summary of hidden nodes, below the last node in the directory, highlighted with `NvimTreeHiddenDisplay`.
|
||||
---- `"none"`: disabled, default
|
||||
---- `"simple"`: total number of hidden files e.g.
|
||||
--- - (3 hidden)
|
||||
---- `"all"`: total and by reason: the filter that hid the node e.g.
|
||||
--- - (14 total git: 5, dotfile: 9)
|
||||
---- `(fun(hidden_stats: nvim_tree.config.renderer.hidden_stats): string)`
|
||||
---
|
||||
---See [nvim_tree.config.renderer.hidden_stats] for details and example.
|
||||
---@alias nvim_tree.config.renderer.hidden_display "none"|"simple"|"all"|(fun(hidden_stats: nvim_tree.config.renderer.hidden_stats): string?)
|
||||
---
|
||||
---
|
||||
---
|
||||
---@class nvim_tree.config.renderer
|
||||
---
|
||||
---Appends a trailing slash to folder and symlink folder target names.
|
||||
---(default: `false`)
|
||||
---@field add_trailing? boolean
|
||||
---
|
||||
---Compact folders that only contain a single folder into one node. Function variant takes the relative path of grouped folders and returns a string to be displayed.
|
||||
---(default: `false`)
|
||||
---@field group_empty? boolean|(fun(relative_path: string): string)
|
||||
---
|
||||
---Display nodes whose name length is wider than the width of nvim-tree window in floating window.
|
||||
---(default: `false`)
|
||||
---@field full_name? boolean
|
||||
---
|
||||
---[nvim_tree.config.renderer.root_folder_label]
|
||||
---(default: `":~:s?$?/..?"`)
|
||||
---@field root_folder_label? nvim_tree.config.renderer.root_folder_label
|
||||
---
|
||||
---Number of spaces for each tree nesting level. Minimum 1.
|
||||
---(default: `2`)
|
||||
---@field indent_width? integer
|
||||
---
|
||||
---[nvim_tree.config.renderer.hidden_display]
|
||||
---(default: `none`)
|
||||
---@field hidden_display? nvim_tree.config.renderer.hidden_display
|
||||
---
|
||||
---Appends an arrow followed by the target of the symlink.
|
||||
---(default: `true`)
|
||||
---@field symlink_destination? boolean
|
||||
---
|
||||
---List in order of additive precedence.
|
||||
---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`)
|
||||
---@field decorators? nvim_tree.config.renderer.decorator[]
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_git? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_opened_files? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_hidden? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_modified? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_bookmarks? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"none"`)
|
||||
---@field highlight_diagnostics? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---(default: `"name"`)
|
||||
---@field highlight_clipboard? nvim_tree.config.renderer.highlight
|
||||
---
|
||||
---Highlight special files and directories with `NvimTreeSpecial*`.
|
||||
---(default: `{ "Cargo.toml", "Makefile", "README.md", "readme.md", }`)
|
||||
---@field special_files? string[]
|
||||
---
|
||||
---[nvim_tree.config.renderer.indent_markers]
|
||||
---@field indent_markers? nvim_tree.config.renderer.indent_markers
|
||||
---
|
||||
---[nvim_tree.config.renderer.icons]
|
||||
---@field icons? nvim_tree.config.renderer.icons
|
||||
|
||||
|
||||
|
||||
---@class nvim_tree.config.renderer.indent_markers
|
||||
---
|
||||
---Display indent markers when folders are open.
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Display folder arrows in the same column as indent marker when using [nvim_tree.config.renderer.icons.padding] {folder_arrow}
|
||||
---(default: `true`)
|
||||
---@field inline_arrows? boolean
|
||||
---
|
||||
---@field icons? nvim_tree.config.renderer.indent_markers.icons
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.indent_markers.icons]()
|
||||
---Before the file/directory, length 1.
|
||||
---@class nvim_tree.config.renderer.indent_markers.icons
|
||||
---@inlinedoc
|
||||
---
|
||||
---(default: `"└"`)
|
||||
---@field corner? string
|
||||
---(default: `"│"`)
|
||||
---@field edge? string
|
||||
---(default: `"│"`)
|
||||
---@field item? string
|
||||
---(default: `"─"`)
|
||||
---@field bottom? string
|
||||
---(default: `" "`)
|
||||
---@field none? string
|
||||
|
||||
|
||||
|
||||
---Icons and separators
|
||||
---
|
||||
---{_placement} [nvim_tree.config.renderer.icons.placement]()
|
||||
---- `"before"`: before file/folder, after the file/folders icons
|
||||
---- `"after"`: after file/folder
|
||||
---- `"signcolumn"`: far left, requires |nvim_tree.config.view| {signcolumn}.
|
||||
---- `"right_align"`: far right
|
||||
---@alias nvim_tree.config.renderer.icons.placement "before"|"after"|"signcolumn"|"right_align"
|
||||
---
|
||||
---
|
||||
---@class nvim_tree.config.renderer.icons
|
||||
---
|
||||
---(default: `before`)
|
||||
---@field git_placement? nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
---(default: `after`)
|
||||
---@field hidden_placement? nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
---(default: `after`)
|
||||
---@field modified_placement? nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
---(default: `signcolumn`)
|
||||
---@field bookmarks_placement? nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
---(default: `signcolumn`)
|
||||
---@field diagnostics_placement? nvim_tree.config.renderer.icons.placement
|
||||
---
|
||||
---@field padding? nvim_tree.config.renderer.icons.padding
|
||||
---
|
||||
---Separator between symlink source and target.
|
||||
---(default: `" ➛ "`)
|
||||
---@field symlink_arrow? string
|
||||
---
|
||||
---[nvim_tree.config.renderer.icons.show]
|
||||
---@field show? nvim_tree.config.renderer.icons.show
|
||||
---
|
||||
---[nvim_tree.config.renderer.icons.glyphs]
|
||||
---@field glyphs? nvim_tree.config.renderer.icons.glyphs
|
||||
---
|
||||
---[nvim_tree.config.renderer.icons.web_devicons]
|
||||
---@field web_devicons? nvim_tree.config.renderer.icons.web_devicons
|
||||
|
||||
|
||||
|
||||
---Configure optional plugin `nvim-tree/nvim-web-devicons`, see [nvim-tree-icons-highlighting].
|
||||
---
|
||||
---@class nvim_tree.config.renderer.icons.web_devicons
|
||||
---
|
||||
---@field file? nvim_tree.config.renderer.icons.web_devicons.file
|
||||
---
|
||||
---@field folder? nvim_tree.config.renderer.icons.web_devicons.folder
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.icons.web_devicons.file]()
|
||||
---@class nvim_tree.config.renderer.icons.web_devicons.file
|
||||
---@inlinedoc
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field color? boolean
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.icons.web_devicons.folder]()
|
||||
---@class nvim_tree.config.renderer.icons.web_devicons.folder
|
||||
---@inlinedoc
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field color? boolean
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.icons.padding]()
|
||||
---@class nvim_tree.config.renderer.icons.padding
|
||||
---@inlinedoc
|
||||
---
|
||||
---Between icon and filename.
|
||||
---(default: `" "`)
|
||||
---@field icon? string
|
||||
---
|
||||
---Between folder arrow icon and file/folder icon.
|
||||
---(default: `" "`)
|
||||
---@field folder_arrow? string
|
||||
|
||||
|
||||
|
||||
---See [nvim-tree-icons-highlighting].
|
||||
---@class nvim_tree.config.renderer.icons.show
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field file? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field folder? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field git? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field modified? boolean
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field hidden? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field diagnostics? boolean
|
||||
---
|
||||
---(default: `true`)
|
||||
---@field bookmarks? boolean
|
||||
---
|
||||
---Show a small arrow before the folder node. Arrow will be a part of the node when using [nvim_tree.config.renderer.indent_markers].
|
||||
---(default: `true`)
|
||||
---@field folder_arrow? boolean
|
||||
|
||||
|
||||
|
||||
---See [nvim-tree-icons-highlighting].
|
||||
---
|
||||
---Glyphs that appear in the sign column must have length <= 2
|
||||
---@class nvim_tree.config.renderer.icons.glyphs
|
||||
---
|
||||
---Files
|
||||
---(default: `""`)
|
||||
---@field default? string
|
||||
---
|
||||
---(default: `""`)
|
||||
---@field symlink? string
|
||||
---
|
||||
---(default: `""`)
|
||||
---@field bookmark? string
|
||||
---
|
||||
---(default: `"●"`)
|
||||
---@field modified? string
|
||||
---
|
||||
---(default: `""`)
|
||||
---@field hidden? string
|
||||
---
|
||||
---@field folder? nvim_tree.config.renderer.icons.glyphs.folder
|
||||
---
|
||||
---@field git? nvim_tree.config.renderer.icons.glyphs.git
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.icons.glyphs.folder]()
|
||||
---@class nvim_tree.config.renderer.icons.glyphs.folder
|
||||
---@inlinedoc
|
||||
---(default: left arrow)
|
||||
---@field arrow_closed? string
|
||||
---(default: down arrow)
|
||||
---@field arrow_open? string
|
||||
---(default: `""`)
|
||||
---@field default? string
|
||||
---(default: `""`)
|
||||
---@field open? string
|
||||
---(default: `""`)
|
||||
---@field empty? string
|
||||
---(default: `""`)
|
||||
---@field empty_open? string
|
||||
---(default: `""`)
|
||||
---@field symlink? string
|
||||
---(default: `""`)
|
||||
---@field symlink_open? string
|
||||
|
||||
|
||||
|
||||
---[nvim_tree.config.renderer.icons.glyphs.git]()
|
||||
---@class nvim_tree.config.renderer.icons.glyphs.git
|
||||
---@inlinedoc
|
||||
---(default: `"✗"`)
|
||||
---@field unstaged? string
|
||||
---(default: `"✓"`)
|
||||
---@field staged? string
|
||||
---(default: `""`)
|
||||
---@field unmerged? string
|
||||
---(default: `"➜"`)
|
||||
---@field renamed? string
|
||||
---(default: `"★"`)
|
||||
---@field untracked? string
|
||||
---(default: `""`)
|
||||
---@field deleted? string
|
||||
---(default: `"◌"`)
|
||||
---@field ignored? string
|
||||
|
||||
---Number of hidden nodes in a directory by reason: the filter that hid the node.
|
||||
---
|
||||
---Passed to your [nvim_tree.config.renderer.hidden_display] function e.g.
|
||||
---```lua
|
||||
---
|
||||
--- ---@param hidden_stats nvim_tree.config.renderer.hidden_stats
|
||||
--- ---@return string? summary
|
||||
--- local my_hidden_display = function(hidden_stats)
|
||||
--- local total_count = 0
|
||||
--- for reason, count in pairs(hidden_stats) do
|
||||
--- total_count = total_count + count
|
||||
--- end
|
||||
---
|
||||
--- if total_count > 0 then
|
||||
--- return "(" .. tostring(total_count) .. " hidden)"
|
||||
--- end
|
||||
--- return nil
|
||||
--- end
|
||||
---```
|
||||
---
|
||||
---@class nvim_tree.config.renderer.hidden_stats
|
||||
---@field bookmark integer
|
||||
---@field buf integer
|
||||
---@field custom integer
|
||||
---@field dotfile integer
|
||||
---@field git integer
|
||||
---@field live_filter integer
|
||||
42
lua/nvim-tree/_meta/config/sort.lua
Normal file
42
lua/nvim-tree/_meta/config/sort.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Sort files within a directory.
|
||||
---
|
||||
---{sorter} presets [nvim_tree.config.sort.Sorter]()
|
||||
---- `"name"`
|
||||
---- `"case_sensitive"` name
|
||||
---- `"modification_time"`
|
||||
---- `"extension"` uses all suffixes e.g. `foo.tar.gz` -> `.tar.gz`
|
||||
---- `"suffix"` uses the last e.g. `foo.tar.gz` -> `.gz`
|
||||
---- `"filetype"` [filetype]
|
||||
---@alias nvim_tree.config.sort.Sorter "name"|"case_sensitive"|"modification_time"|"extension"|"suffix"|"filetype"
|
||||
---
|
||||
---{sorter} may be a function that is passed a list of `nvim_tree.api.Node` to be sorted in place e.g.
|
||||
---```lua
|
||||
---
|
||||
--- ---Sort by name length
|
||||
--- ---@param nodes nvim_tree.api.Node[]
|
||||
--- ---@return nvim_tree.config.sort.Sorter?
|
||||
--- local sorter = function(nodes)
|
||||
--- table.sort(nodes, function(a, b)
|
||||
--- return #a.name < #b.name
|
||||
--- end)
|
||||
--- end
|
||||
---```
|
||||
---{sorter} may be a function that returns a [nvim_tree.config.sort.Sorter]
|
||||
---
|
||||
---@class nvim_tree.config.sort
|
||||
---
|
||||
---(default: `"name"`)
|
||||
---@field sorter? nvim_tree.config.sort.Sorter|(fun(nodes: nvim_tree.api.Node[]): nvim_tree.config.sort.Sorter?)
|
||||
---
|
||||
---Sort folders before files. Has no effect when {sorter} is a function.
|
||||
---(default: `true`)
|
||||
---@field folders_first? boolean
|
||||
---
|
||||
---Sort files before folders. Has no effect when {sorter} is a function. Overrides {folders_first}.
|
||||
---(default: `false`)
|
||||
---@field files_first? boolean
|
||||
26
lua/nvim-tree/_meta/config/tab.lua
Normal file
26
lua/nvim-tree/_meta/config/tab.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---@class nvim_tree.config.tab
|
||||
---
|
||||
---[nvim_tree.config.tab.sync]
|
||||
---@field sync? nvim_tree.config.tab.sync
|
||||
|
||||
|
||||
|
||||
---@class nvim_tree.config.tab.sync
|
||||
---
|
||||
---Opens the tree automatically when switching tabpage or opening a new tabpage if the tree was previously open.
|
||||
---(default: `false`)
|
||||
---@field open? boolean
|
||||
---
|
||||
---Closes the tree across all tabpages when the tree is closed.
|
||||
---(default: `false`)
|
||||
---@field close? boolean
|
||||
---
|
||||
---
|
||||
---List of filetypes or buffer names on new tab that will prevent `open` and `close`
|
||||
---(default: `{}`)
|
||||
---@field ignore? string[]
|
||||
14
lua/nvim-tree/_meta/config/trash.lua
Normal file
14
lua/nvim-tree/_meta/config/trash.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Files may be trashed via an external command that must be installed on your system.
|
||||
--- - linux: `gio trash`, from linux package `glib2`
|
||||
--- - macOS: `trash`, from homebrew package `trash`
|
||||
--- - windows: `trash`, requires `trash-cli` or similar
|
||||
---
|
||||
---@class nvim_tree.config.trash
|
||||
---
|
||||
---(default: `"gio trash"` or `"trash"`)
|
||||
---@field cmd? string
|
||||
26
lua/nvim-tree/_meta/config/ui.lua
Normal file
26
lua/nvim-tree/_meta/config/ui.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---@class nvim_tree.config.ui
|
||||
---
|
||||
---[nvim_tree.config.ui.confirm]
|
||||
---@field confirm? nvim_tree.config.ui.confirm
|
||||
|
||||
|
||||
|
||||
---Confirmation prompts.
|
||||
---@class nvim_tree.config.ui.confirm
|
||||
---
|
||||
---Prompt before removing.
|
||||
---(default: `true`)
|
||||
---@field remove? boolean
|
||||
---
|
||||
---Prompt before trashing.
|
||||
---(default: `true`)
|
||||
---@field trash? boolean
|
||||
---
|
||||
---If `true` the prompt will be `Y/n`, otherwise `y/N`
|
||||
---(default: `false`)
|
||||
---@field default_yes? boolean
|
||||
35
lua/nvim-tree/_meta/config/update_focused_file.lua
Normal file
35
lua/nvim-tree/_meta/config/update_focused_file.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Update the focused file on [BufEnter], uncollapsing folders recursively.
|
||||
---
|
||||
---@class nvim_tree.config.update_focused_file
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---[nvim_tree.config.update_focused_file.update_root]
|
||||
---@field update_root? nvim_tree.config.update_focused_file.update_root
|
||||
---
|
||||
---A function called on [BufEnter] that returns true if the file should not be focused when opening.
|
||||
---(default: `false`)
|
||||
---@field exclude? boolean|(fun(args: vim.api.keyset.create_autocmd.callback_args): boolean)
|
||||
|
||||
|
||||
|
||||
---Update the root directory of the tree if the file is not under the current root directory.
|
||||
---
|
||||
---Prefers vim's cwd and [nvim_tree.config] {root_dirs}, falling back to the directory containing the file.
|
||||
---
|
||||
---Requires [nvim_tree.config.update_focused_file]
|
||||
---
|
||||
---@class nvim_tree.config.update_focused_file.update_root
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---List of buffer names and filetypes that will not update the root dir of the tree if the file isn't found under the current root directory.
|
||||
---(default: `{}`)
|
||||
---@field ignore_list? string[]
|
||||
107
lua/nvim-tree/_meta/config/view.lua
Normal file
107
lua/nvim-tree/_meta/config/view.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
---@meta
|
||||
error("Cannot require a meta file")
|
||||
|
||||
|
||||
|
||||
---Configures the dimensions and appearance of the nvim-tree window.
|
||||
---
|
||||
---The window is "docked" at the left by default, however may be configured to float: [nvim_tree.config.view.float]
|
||||
---
|
||||
---{width} can be a [nvim_tree.config.view.width.spec] for static control or a [nvim_tree.config.view.width] for fully dynamic control based on longest line.
|
||||
---
|
||||
---[nvim_tree.config.view.width.spec]()
|
||||
---- `string`: `x%` string e.g. `30%`
|
||||
---- `integer`: number of columns
|
||||
---- `function`: returns one of the above
|
||||
---@alias nvim_tree.config.view.width.spec string|integer|(fun(): integer|string)
|
||||
---
|
||||
---@class nvim_tree.config.view
|
||||
---
|
||||
---When entering nvim-tree, reposition the view so that the current node is initially centralized, see [zz].
|
||||
---(default: `false`)
|
||||
---@field centralize_selection? boolean
|
||||
---
|
||||
---['cursorline']
|
||||
---(default: `true`)
|
||||
---@field cursorline? boolean
|
||||
---
|
||||
---['cursorlineopt']
|
||||
---(default: `both`)
|
||||
---@field cursorlineopt? string
|
||||
---
|
||||
---Idle milliseconds before some reload / refresh operations. Increase if you experience performance issues around screen refresh.
|
||||
---(default: `15`)
|
||||
---@field debounce_delay? integer
|
||||
---
|
||||
---(default: `"left"`)
|
||||
---@field side? "left"|"right"
|
||||
---
|
||||
---Preserves window proportions when opening a file. If `false`, the height and width of windows other than nvim-tree will be equalized.
|
||||
---(default: `false`)
|
||||
---@field preserve_window_proportions? boolean
|
||||
---
|
||||
---['number']
|
||||
---(default: `false`)
|
||||
---@field number? boolean
|
||||
---
|
||||
---['relativenumber']
|
||||
---(default: `false`)
|
||||
---@field relativenumber? boolean
|
||||
---
|
||||
---['signcolumn']
|
||||
---(default: `"yes"`)
|
||||
---@field signcolumn? "yes"|"auto"|"no"
|
||||
---
|
||||
---(default: `30`)
|
||||
---@field width? nvim_tree.config.view.width.spec|nvim_tree.config.view.width
|
||||
---
|
||||
---[nvim_tree.config.view.float]
|
||||
---@field float? nvim_tree.config.view.float
|
||||
|
||||
|
||||
|
||||
---Configure dynamic width based on longest line.
|
||||
---
|
||||
---@class nvim_tree.config.view.width
|
||||
---
|
||||
---(default: `30`)
|
||||
---@field min? nvim_tree.config.view.width.spec
|
||||
---
|
||||
----1 for unbounded.
|
||||
---(default: `-1`)
|
||||
---@field max? nvim_tree.config.view.width.spec
|
||||
---
|
||||
---Exclude these lines when computing width.
|
||||
---(default: `{ "root" }`)
|
||||
---@field lines_excluded? ("root")[]
|
||||
---
|
||||
---Extra padding to the right.
|
||||
---(default: `1`)
|
||||
---@field padding? nvim_tree.config.view.width.spec
|
||||
|
||||
|
||||
|
||||
---Configure floating window behaviour
|
||||
---
|
||||
---{open_win_config} is passed to [nvim_open_win()], default:
|
||||
---```lua
|
||||
--- {
|
||||
--- relative = "editor",
|
||||
--- border = "rounded",
|
||||
--- width = 30,
|
||||
--- height = 30,
|
||||
--- row = 1,
|
||||
--- col = 1,
|
||||
--- }
|
||||
---```
|
||||
---@class nvim_tree.config.view.float
|
||||
---
|
||||
---(default: `false`)
|
||||
---@field enable? boolean
|
||||
---
|
||||
---Close the floating window when it loses focus.
|
||||
---(default: `true`)
|
||||
---@field quit_on_focus_loss? boolean
|
||||
---
|
||||
---(default: `{ relative = "editor", border = "rounded", width = 30, height = 30, row = 1, col = 1, }`)
|
||||
---@field open_win_config? vim.api.keyset.win_config|(fun(): vim.api.keyset.win_config)
|
||||
@@ -1,8 +1,10 @@
|
||||
local log = require "nvim-tree.log"
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local Iterator = require "nvim-tree.iterators.node-iterator"
|
||||
local log = require("nvim-tree.log")
|
||||
local view = require("nvim-tree.view")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
local Iterator = require("nvim-tree.iterators.node-iterator")
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -17,7 +19,7 @@ function M.fn(path)
|
||||
end
|
||||
|
||||
-- always match against the real path
|
||||
local path_real = vim.loop.fs_realpath(path)
|
||||
local path_real = vim.uv.fs_realpath(path)
|
||||
if not path_real then
|
||||
return
|
||||
end
|
||||
@@ -30,7 +32,7 @@ function M.fn(path)
|
||||
local profile = log.profile_start("find file %s", path_real)
|
||||
|
||||
-- refresh the contents of all parents, expanding groups as needed
|
||||
if utils.get_node_from_path(path_real) == nil then
|
||||
if explorer:get_node_from_path(path_real) == nil then
|
||||
explorer:refresh_parent_nodes_for_path(vim.fn.fnamemodify(path_real, ":h"))
|
||||
end
|
||||
|
||||
@@ -58,25 +60,33 @@ function M.fn(path)
|
||||
local link_match = node.link_to and vim.startswith(path_real, node.link_to .. utils.path_separator)
|
||||
|
||||
if abs_match or link_match then
|
||||
if not node.group_next then
|
||||
node.open = true
|
||||
end
|
||||
if #node.nodes == 0 then
|
||||
core.get_explorer():expand(node)
|
||||
if node.group_next and incremented_line then
|
||||
line = line - 1
|
||||
local dir = node:as(DirectoryNode)
|
||||
if dir then
|
||||
if not dir.group_next then
|
||||
dir.open = true
|
||||
end
|
||||
if #dir.nodes == 0 then
|
||||
core.get_explorer():expand_dir_node(dir)
|
||||
if dir.group_next and incremented_line then
|
||||
line = line - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
:recursor(function(node)
|
||||
return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes)
|
||||
node = node and node:as(DirectoryNode)
|
||||
if node then
|
||||
return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end)
|
||||
:iterate()
|
||||
|
||||
if found and view.is_visible() then
|
||||
explorer.renderer:draw()
|
||||
view.set_cursor { line, 0 }
|
||||
view.set_cursor({ line, 0 })
|
||||
end
|
||||
|
||||
running[path_real] = false
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.find_file = require "nvim-tree.actions.finders.find-file"
|
||||
M.search_node = require "nvim-tree.actions.finders.search-node"
|
||||
|
||||
return M
|
||||
@@ -1,4 +1,4 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local core = require("nvim-tree.core")
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
local M = {}
|
||||
@@ -25,23 +25,23 @@ local function search(search_dir, input_path)
|
||||
|
||||
local filter_status = explorer.filters:prepare()
|
||||
|
||||
handle, _ = vim.loop.fs_scandir(dir)
|
||||
handle, _ = vim.uv.fs_scandir(dir)
|
||||
if not handle then
|
||||
return
|
||||
end
|
||||
|
||||
realpath, _ = vim.loop.fs_realpath(dir)
|
||||
realpath, _ = vim.uv.fs_realpath(dir)
|
||||
if not realpath or vim.tbl_contains(realpaths_searched, realpath) then
|
||||
return
|
||||
end
|
||||
table.insert(realpaths_searched, realpath)
|
||||
|
||||
name, _ = vim.loop.fs_scandir_next(handle)
|
||||
name, _ = vim.uv.fs_scandir_next(handle)
|
||||
while name do
|
||||
path = dir .. "/" .. name
|
||||
|
||||
---@type uv.fs_stat.result|nil
|
||||
stat, _ = vim.loop.fs_stat(path)
|
||||
stat, _ = vim.uv.fs_stat(path)
|
||||
if not stat then
|
||||
break
|
||||
end
|
||||
@@ -59,7 +59,7 @@ local function search(search_dir, input_path)
|
||||
end
|
||||
end
|
||||
|
||||
name, _ = vim.loop.fs_scandir_next(handle)
|
||||
name, _ = vim.uv.fs_scandir_next(handle)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -74,14 +74,8 @@ function M.fn()
|
||||
-- temporarily set &path
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
|
||||
local path_existed, path_opt
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
path_existed, path_opt = pcall(vim.api.nvim_get_option_value, "path", { buf = bufnr })
|
||||
vim.api.nvim_set_option_value("path", core.get_cwd() .. "/**", { buf = bufnr })
|
||||
else
|
||||
path_existed, path_opt = pcall(vim.api.nvim_buf_get_option, bufnr, "path") ---@diagnostic disable-line: deprecated
|
||||
vim.api.nvim_buf_set_option(bufnr, "path", core.get_cwd() .. "/**") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
local path_existed, path_opt = pcall(vim.api.nvim_get_option_value, "path", { buf = bufnr })
|
||||
vim.api.nvim_set_option_value("path", core.get_cwd() .. "/**", { buf = bufnr })
|
||||
|
||||
vim.ui.input({ prompt = "Search: ", completion = "file_in_path" }, function(input_path)
|
||||
if not input_path or input_path == "" then
|
||||
@@ -89,17 +83,9 @@ function M.fn()
|
||||
end
|
||||
-- reset &path
|
||||
if path_existed then
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value("path", path_opt, { buf = bufnr })
|
||||
else
|
||||
vim.api.nvim_buf_set_option(bufnr, "path", path_opt) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
vim.api.nvim_set_option_value("path", path_opt, { buf = bufnr })
|
||||
else
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value("path", nil, { buf = bufnr })
|
||||
else
|
||||
vim.api.nvim_buf_set_option(bufnr, "path", nil) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
vim.api.nvim_set_option_value("path", nil, { buf = bufnr })
|
||||
end
|
||||
|
||||
-- strip trailing slash
|
||||
|
||||
@@ -1,43 +1,47 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local events = require "nvim-tree.events"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local lib = require("nvim-tree.lib")
|
||||
local log = require("nvim-tree.log")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
local events = require("nvim-tree.events")
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
---@enum ACTION
|
||||
local ACTION = {
|
||||
copy = "copy",
|
||||
cut = "cut",
|
||||
}
|
||||
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")
|
||||
|
||||
---@class Clipboard to handle all actions.fs clipboard API
|
||||
---@field config table hydrated user opts.filters
|
||||
---@alias ClipboardAction "copy" | "cut"
|
||||
---@alias ClipboardData table<ClipboardAction, Node[]>
|
||||
|
||||
---@alias ClipboardActionFn fun(source: string, dest: string): boolean, string?
|
||||
|
||||
---@class (exact) Clipboard: nvim_tree.Class
|
||||
---@field private explorer Explorer
|
||||
---@field private data table<ACTION, Node[]>
|
||||
local Clipboard = {}
|
||||
---@field private data ClipboardData
|
||||
---@field private clipboard_name string
|
||||
---@field private reg string
|
||||
local Clipboard = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
---@return Clipboard
|
||||
function Clipboard:new(opts, explorer)
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
data = {
|
||||
[ACTION.copy] = {},
|
||||
[ACTION.cut] = {},
|
||||
},
|
||||
config = {
|
||||
filesystem_watchers = opts.filesystem_watchers,
|
||||
actions = opts.actions,
|
||||
},
|
||||
---@class Clipboard
|
||||
---@overload fun(args: ClipboardArgs): Clipboard
|
||||
|
||||
---@class (exact) ClipboardArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args ClipboardArgs
|
||||
function Clipboard:new(args)
|
||||
self.explorer = args.explorer
|
||||
|
||||
self.data = {
|
||||
copy = {},
|
||||
cut = {},
|
||||
}
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
self.clipboard_name = self.explorer.opts.actions.use_system_clipboard and "system" or "neovim"
|
||||
self.reg = self.explorer.opts.actions.use_system_clipboard and "+" or "1"
|
||||
end
|
||||
|
||||
---@param source string
|
||||
@@ -45,13 +49,11 @@ end
|
||||
---@return boolean
|
||||
---@return string|nil
|
||||
local function do_copy(source, destination)
|
||||
local source_stats, handle
|
||||
local success, errmsg
|
||||
local source_stats, err = vim.uv.fs_stat(source)
|
||||
|
||||
source_stats, errmsg = vim.loop.fs_stat(source)
|
||||
if not source_stats then
|
||||
log.line("copy_paste", "do_copy fs_stat '%s' failed '%s'", source, errmsg)
|
||||
return false, errmsg
|
||||
log.line("copy_paste", "do_copy fs_stat '%s' failed '%s'", source, err)
|
||||
return false, err
|
||||
end
|
||||
|
||||
log.line("copy_paste", "do_copy %s '%s' -> '%s'", source_stats.type, source, destination)
|
||||
@@ -62,116 +64,68 @@ local function do_copy(source, destination)
|
||||
end
|
||||
|
||||
if source_stats.type == "file" then
|
||||
success, errmsg = vim.loop.fs_copyfile(source, destination)
|
||||
local success
|
||||
success, err = vim.uv.fs_copyfile(source, destination)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_copy fs_copyfile failed '%s'", errmsg)
|
||||
return false, errmsg
|
||||
log.line("copy_paste", "do_copy fs_copyfile failed '%s'", err)
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
elseif source_stats.type == "directory" then
|
||||
handle, errmsg = vim.loop.fs_scandir(source)
|
||||
local handle
|
||||
handle, err = vim.uv.fs_scandir(source)
|
||||
if type(handle) == "string" then
|
||||
return false, handle
|
||||
elseif not handle then
|
||||
log.line("copy_paste", "do_copy fs_scandir '%s' failed '%s'", source, errmsg)
|
||||
return false, errmsg
|
||||
log.line("copy_paste", "do_copy fs_scandir '%s' failed '%s'", source, err)
|
||||
return false, err
|
||||
end
|
||||
|
||||
success, errmsg = vim.loop.fs_mkdir(destination, source_stats.mode)
|
||||
local success
|
||||
success, err = vim.uv.fs_mkdir(destination, source_stats.mode)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_copy fs_mkdir '%s' failed '%s'", destination, errmsg)
|
||||
return false, errmsg
|
||||
log.line("copy_paste", "do_copy fs_mkdir '%s' failed '%s'", destination, err)
|
||||
return false, err
|
||||
end
|
||||
|
||||
while true do
|
||||
local name, _ = vim.loop.fs_scandir_next(handle)
|
||||
local name, _ = vim.uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local new_name = utils.path_join { source, name }
|
||||
local new_destination = utils.path_join { destination, name }
|
||||
success, errmsg = do_copy(new_name, new_destination)
|
||||
local new_name = utils.path_join({ source, name })
|
||||
local new_destination = utils.path_join({ destination, name })
|
||||
success, err = do_copy(new_name, new_destination)
|
||||
if not success then
|
||||
return false, errmsg
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
else
|
||||
errmsg = string.format("'%s' illegal file type '%s'", source, source_stats.type)
|
||||
log.line("copy_paste", "do_copy %s", errmsg)
|
||||
return false, errmsg
|
||||
err = string.format("'%s' illegal file type '%s'", source, source_stats.type)
|
||||
log.line("copy_paste", "do_copy %s", err)
|
||||
return false, err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Paste a single item with no conflict handling.
|
||||
---@param source string
|
||||
---@param dest string
|
||||
---@param action ACTION
|
||||
---@param action_fn fun(source: string, dest: string)
|
||||
---@return boolean|nil -- success
|
||||
---@return string|nil -- error message
|
||||
local function do_single_paste(source, dest, action, action_fn)
|
||||
local dest_stats
|
||||
local success, errmsg, errcode
|
||||
local notify_source = notify.render_path(source)
|
||||
|
||||
log.line("copy_paste", "do_single_paste '%s' -> '%s'", source, dest)
|
||||
|
||||
dest_stats, errmsg, errcode = vim.loop.fs_stat(dest)
|
||||
if not dest_stats and errcode ~= "ENOENT" then
|
||||
notify.error("Could not " .. action .. " " .. notify_source .. " - " .. (errmsg or "???"))
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
local function on_process()
|
||||
success, errmsg = action_fn(source, dest)
|
||||
if not success then
|
||||
notify.error("Could not " .. action .. " " .. notify_source .. " - " .. (errmsg or "???"))
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
find_file(utils.path_remove_trailing(dest))
|
||||
end
|
||||
|
||||
if dest_stats then
|
||||
local input_opts = {
|
||||
prompt = "Rename to ",
|
||||
default = dest,
|
||||
completion = "dir",
|
||||
}
|
||||
|
||||
if source == dest then
|
||||
vim.ui.input(input_opts, function(new_dest)
|
||||
utils.clear_prompt()
|
||||
if new_dest then
|
||||
do_single_paste(source, new_dest, action, action_fn)
|
||||
end
|
||||
end)
|
||||
else
|
||||
local prompt_select = "Overwrite " .. dest .. " ?"
|
||||
local prompt_input = prompt_select .. " R(ename)/y/n: "
|
||||
lib.prompt(prompt_input, prompt_select, { "", "y", "n" }, { "Rename", "Yes", "No" }, "nvimtree_overwrite_rename", function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" then
|
||||
on_process()
|
||||
elseif item_short == "" or item_short == "r" then
|
||||
vim.ui.input(input_opts, function(new_dest)
|
||||
utils.clear_prompt()
|
||||
if new_dest then
|
||||
do_single_paste(source, new_dest, action, action_fn)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
on_process()
|
||||
---@param action ClipboardAction
|
||||
---@param action_fn ClipboardActionFn
|
||||
local function do_paste_one(source, dest, action, action_fn)
|
||||
log.line("copy_paste", "do_paste_one '%s' -> '%s'", source, dest)
|
||||
local success, err = action_fn(source, dest)
|
||||
if not success then
|
||||
notify.error("Could not " .. action .. " " .. notify.render_path(source) .. " - " .. (err or "???"))
|
||||
end
|
||||
find_file(utils.path_remove_trailing(dest))
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@param clip table
|
||||
---@param clip ClipboardData
|
||||
local function toggle(node, clip)
|
||||
if node.name == ".." then
|
||||
return
|
||||
@@ -189,49 +143,243 @@ end
|
||||
|
||||
---Clear copied and cut
|
||||
function Clipboard:clear_clipboard()
|
||||
self.data[ACTION.copy] = {}
|
||||
self.data[ACTION.cut] = {}
|
||||
notify.info "Clipboard has been emptied."
|
||||
self.data.copy = {}
|
||||
self.data.cut = {}
|
||||
notify.info("Clipboard has been emptied.")
|
||||
self.explorer.renderer:draw()
|
||||
end
|
||||
|
||||
---Copy one node
|
||||
---@param node Node
|
||||
function Clipboard:copy(node)
|
||||
utils.array_remove(self.data[ACTION.cut], node)
|
||||
toggle(node, self.data[ACTION.copy])
|
||||
---Bulk add/remove nodes to/from a clipboard list.
|
||||
---@private
|
||||
---@param nodes Node[] filtered nodes to operate on
|
||||
---@param from Node[] list to remove from (the opposite clipboard)
|
||||
---@param to Node[] list to add to
|
||||
---@param verb string notification verb ("added to" or "cut to")
|
||||
function Clipboard:bulk_clipboard(nodes, from, to, verb)
|
||||
local added = 0
|
||||
local removed = 0
|
||||
for _, node in ipairs(nodes) do
|
||||
if node.name ~= ".." then
|
||||
utils.array_remove(from, node)
|
||||
if utils.array_remove(to, node) then
|
||||
removed = removed + 1
|
||||
else
|
||||
table.insert(to, node)
|
||||
added = added + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if added > 0 then
|
||||
notify.info(string.format("%d nodes %s clipboard.", added, verb))
|
||||
elseif removed > 0 then
|
||||
notify.info(string.format("%d nodes removed from clipboard.", removed))
|
||||
end
|
||||
self.explorer.renderer:draw()
|
||||
end
|
||||
|
||||
---Cut one node
|
||||
---@param node Node
|
||||
function Clipboard:cut(node)
|
||||
utils.array_remove(self.data[ACTION.copy], node)
|
||||
toggle(node, self.data[ACTION.cut])
|
||||
self.explorer.renderer:draw()
|
||||
---@private
|
||||
---@param node_or_nodes Node|Node[]
|
||||
---@return boolean
|
||||
function Clipboard:is_nodes_array(node_or_nodes)
|
||||
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
---Paste cut or cop
|
||||
---Copy one or more nodes
|
||||
---@param node_or_nodes Node|Node[]
|
||||
function Clipboard:copy(node_or_nodes)
|
||||
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 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.
|
||||
---@private
|
||||
---@param action ClipboardAction
|
||||
function Clipboard:finish_paste(action)
|
||||
self.data[action] = {}
|
||||
self.explorer:reload_explorer()
|
||||
end
|
||||
|
||||
---Resolve conflicting paste items.
|
||||
---Single conflict: per-file prompt with full-path rename (pre-visual-mode behavior).
|
||||
---Multiple conflicts: batch prompt with suffix rename.
|
||||
---@private
|
||||
---@param conflict {node: Node, dest: string}[]
|
||||
---@param destination string
|
||||
---@param action ClipboardAction
|
||||
---@param action_fn ClipboardActionFn
|
||||
function Clipboard:resolve_conflicts(conflict, destination, action, action_fn)
|
||||
if #conflict == 1 then
|
||||
local source = conflict[1].node.absolute_path
|
||||
local dest = conflict[1].dest
|
||||
|
||||
local function rename_prompt(default_dest)
|
||||
vim.ui.input({ prompt = "Rename to ", default = default_dest, completion = "dir" }, function(new_dest)
|
||||
utils.clear_prompt()
|
||||
if not new_dest or new_dest == "" then
|
||||
self:finish_paste(action)
|
||||
return
|
||||
end
|
||||
if vim.uv.fs_stat(new_dest) then
|
||||
self:resolve_conflicts({ { node = conflict[1].node, dest = new_dest } }, destination, action, action_fn)
|
||||
else
|
||||
do_paste_one(source, new_dest, action, action_fn)
|
||||
self:finish_paste(action)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if source == dest then
|
||||
rename_prompt(dest)
|
||||
else
|
||||
local prompt_select = "Overwrite " .. dest .. " ?"
|
||||
lib.prompt(prompt_select .. " R(ename)/y/n: ", prompt_select,
|
||||
{ "", "y", "n" }, { "Rename", "Yes", "No" },
|
||||
"nvimtree_overwrite_rename",
|
||||
function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" then
|
||||
do_paste_one(source, dest, action, action_fn)
|
||||
self:finish_paste(action)
|
||||
elseif item_short == "" or item_short == "r" then
|
||||
rename_prompt(dest)
|
||||
else
|
||||
self:finish_paste(action)
|
||||
end
|
||||
end)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local prompt_select = #conflict .. " file(s) already exist"
|
||||
local prompt_input = prompt_select .. ". R(ename suffix)/y/n: "
|
||||
|
||||
lib.prompt(prompt_input, prompt_select,
|
||||
{ "", "y", "n" },
|
||||
{ "Rename (suffix)", "Overwrite all", "Skip all" },
|
||||
"nvimtree_paste_conflict",
|
||||
function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" then
|
||||
for _, item in ipairs(conflict) do
|
||||
do_paste_one(item.node.absolute_path, item.dest, action, action_fn)
|
||||
end
|
||||
self:finish_paste(action)
|
||||
elseif item_short == "" or item_short == "r" then
|
||||
vim.ui.input({ prompt = "Suffix: " }, function(suffix)
|
||||
utils.clear_prompt()
|
||||
if not suffix or suffix == "" then
|
||||
return
|
||||
end
|
||||
local still_conflict = {}
|
||||
for _, item in ipairs(conflict) do
|
||||
local basename = vim.fn.fnamemodify(item.node.name, ":r")
|
||||
local extension = vim.fn.fnamemodify(item.node.name, ":e")
|
||||
local new_name = extension ~= "" and (basename .. suffix .. "." .. extension) or (item.node.name .. suffix)
|
||||
local new_dest = utils.path_join({ destination, new_name })
|
||||
local stats = vim.uv.fs_stat(new_dest)
|
||||
if stats then
|
||||
table.insert(still_conflict, { node = item.node, dest = new_dest })
|
||||
else
|
||||
do_paste_one(item.node.absolute_path, new_dest, action, action_fn)
|
||||
end
|
||||
end
|
||||
if #still_conflict > 0 then
|
||||
self:resolve_conflicts(still_conflict, destination, action, action_fn)
|
||||
else
|
||||
self:finish_paste(action)
|
||||
end
|
||||
end)
|
||||
else
|
||||
self:finish_paste(action)
|
||||
end
|
||||
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
|
||||
---@param action ACTION
|
||||
---@param action_fn fun(source: string, dest: string)
|
||||
---@param action ClipboardAction
|
||||
---@param action_fn ClipboardActionFn
|
||||
function Clipboard:do_paste(node, action, action_fn)
|
||||
node = lib.get_last_group_node(node)
|
||||
local explorer = core.get_explorer()
|
||||
if node.name == ".." and explorer then
|
||||
node = explorer
|
||||
if node.name == ".." then
|
||||
node = self.explorer
|
||||
else
|
||||
local dir = node:as(DirectoryNode)
|
||||
if dir then
|
||||
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
|
||||
|
||||
local destination = node.absolute_path
|
||||
local stats, errmsg, errcode = vim.loop.fs_stat(destination)
|
||||
if not stats and errcode ~= "ENOENT" then
|
||||
log.line("copy_paste", "do_paste fs_stat '%s' failed '%s'", destination, errmsg)
|
||||
notify.error("Could not " .. action .. " " .. notify.render_path(destination) .. " - " .. (errmsg or "???"))
|
||||
local stats, err, err_name = vim.uv.fs_stat(destination)
|
||||
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 == false then
|
||||
self:destroy_nodes(clip)
|
||||
end
|
||||
return
|
||||
end
|
||||
local is_dir = stats and stats.type == "directory"
|
||||
@@ -239,14 +387,33 @@ function Clipboard:do_paste(node, action, action_fn)
|
||||
destination = vim.fn.fnamemodify(destination, ":p:h")
|
||||
end
|
||||
|
||||
-- Partition into conflict / no-conflict
|
||||
local no_conflict = {}
|
||||
local conflict = {}
|
||||
for _, _node in ipairs(clip) do
|
||||
local dest = utils.path_join { destination, _node.name }
|
||||
do_single_paste(_node.absolute_path, dest, action, action_fn)
|
||||
local dest = utils.path_join({ destination, _node.name })
|
||||
local dest_stats = vim.uv.fs_stat(dest)
|
||||
if dest_stats then
|
||||
table.insert(conflict, { node = _node, dest = dest })
|
||||
else
|
||||
table.insert(no_conflict, { node = _node, dest = dest })
|
||||
end
|
||||
end
|
||||
|
||||
self.data[action] = {}
|
||||
if not self.config.filesystem_watchers.enable then
|
||||
self.explorer:reload_explorer()
|
||||
-- Paste non-conflicting items immediately
|
||||
for _, item in ipairs(no_conflict) do
|
||||
do_paste_one(item.node.absolute_path, item.dest, action, action_fn)
|
||||
end
|
||||
|
||||
-- Resolve conflicts in batch
|
||||
if #conflict > 0 then
|
||||
self:resolve_conflicts(conflict, destination, action, action_fn)
|
||||
else
|
||||
self:finish_paste(action)
|
||||
end
|
||||
|
||||
if is_local == false then
|
||||
self:destroy_nodes(clip)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -263,7 +430,7 @@ local function do_cut(source, destination)
|
||||
end
|
||||
|
||||
events._dispatch_will_rename_node(source, destination)
|
||||
local success, errmsg = vim.loop.fs_rename(source, destination)
|
||||
local success, errmsg = vim.uv.fs_rename(source, destination)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_cut fs_rename failed '%s'", errmsg)
|
||||
return false, errmsg
|
||||
@@ -275,25 +442,27 @@ end
|
||||
|
||||
---Paste cut (if present) or copy (if present)
|
||||
---@param node Node
|
||||
function Clipboard:paste(node)
|
||||
if self.data[ACTION.cut][1] ~= nil then
|
||||
self:do_paste(node, ACTION.cut, do_cut)
|
||||
elseif self.data[ACTION.copy][1] ~= nil then
|
||||
self:do_paste(node, ACTION.copy, do_copy)
|
||||
---@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)
|
||||
else
|
||||
self:do_paste(node, "copy", do_copy)
|
||||
end
|
||||
end
|
||||
|
||||
function Clipboard:print_clipboard()
|
||||
local content = {}
|
||||
if #self.data[ACTION.cut] > 0 then
|
||||
if #self.data.cut > 0 then
|
||||
table.insert(content, "Cut")
|
||||
for _, node in pairs(self.data[ACTION.cut]) do
|
||||
for _, node in pairs(self.data.cut) do
|
||||
table.insert(content, " * " .. (notify.render_path(node.absolute_path)))
|
||||
end
|
||||
end
|
||||
if #self.data[ACTION.copy] > 0 then
|
||||
if #self.data.copy > 0 then
|
||||
table.insert(content, "Copy")
|
||||
for _, node in pairs(self.data[ACTION.copy]) do
|
||||
for _, node in pairs(self.data.copy) do
|
||||
table.insert(content, " * " .. (notify.render_path(node.absolute_path)))
|
||||
end
|
||||
end
|
||||
@@ -302,66 +471,46 @@ function Clipboard:print_clipboard()
|
||||
end
|
||||
|
||||
---@param content string
|
||||
function Clipboard:copy_to_reg(content)
|
||||
local clipboard_name
|
||||
local reg
|
||||
if self.config.actions.use_system_clipboard == true then
|
||||
clipboard_name = "system"
|
||||
reg = "+"
|
||||
else
|
||||
clipboard_name = "neovim"
|
||||
reg = "1"
|
||||
---@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")
|
||||
|
||||
if opts.notify ~= false then
|
||||
notify.info(message or string.format("Copied %s to %s clipboard!", content, self.clipboard_name))
|
||||
end
|
||||
|
||||
-- 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$', reg))
|
||||
end)
|
||||
vim.api.nvim_buf_delete(temp_buf, {})
|
||||
|
||||
notify.info(string.format("Copied %s to %s clipboard!", content, clipboard_name))
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function Clipboard:copy_filename(node)
|
||||
local content
|
||||
|
||||
if node.name == ".." then
|
||||
-- root
|
||||
content = vim.fn.fnamemodify(self.explorer.absolute_path, ":t")
|
||||
self:copy_to_reg(vim.fn.fnamemodify(self.explorer.absolute_path, ":t"))
|
||||
else
|
||||
-- node
|
||||
content = node.name
|
||||
self:copy_to_reg(node.name)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param node Node
|
||||
---@return string
|
||||
function Clipboard:get_absolute_path(node)
|
||||
if node.name == ".." then
|
||||
node = self.explorer
|
||||
end
|
||||
|
||||
self:copy_to_reg(content)
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function Clipboard:copy_basename(node)
|
||||
local content
|
||||
|
||||
if node.name == ".." then
|
||||
-- root
|
||||
content = vim.fn.fnamemodify(self.explorer.absolute_path, ":t:r")
|
||||
else
|
||||
-- node
|
||||
content = vim.fn.fnamemodify(node.name, ":r")
|
||||
end
|
||||
|
||||
self:copy_to_reg(content)
|
||||
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)
|
||||
local content
|
||||
|
||||
if node.name == ".." then
|
||||
-- root
|
||||
content = utils.path_add_trailing ""
|
||||
self:copy_to_reg(utils.path_add_trailing(""))
|
||||
else
|
||||
-- node
|
||||
local absolute_path = node.absolute_path
|
||||
@@ -371,35 +520,66 @@ function Clipboard:copy_path(node)
|
||||
end
|
||||
|
||||
local relative_path = utils.path_relative(absolute_path, cwd)
|
||||
content = node.nodes ~= nil and utils.path_add_trailing(relative_path) or relative_path
|
||||
if node:is(DirectoryNode) then
|
||||
self:copy_to_reg(utils.path_add_trailing(relative_path))
|
||||
else
|
||||
self:copy_to_reg(relative_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@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
|
||||
|
||||
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_absolute_path(node)
|
||||
function Clipboard:copy_basename(node)
|
||||
if node.name == ".." then
|
||||
node = self.explorer
|
||||
-- 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
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
---Node is cut. Will not be copied.
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
function Clipboard:is_cut(node)
|
||||
return vim.tbl_contains(self.data[ACTION.cut], node)
|
||||
return vim.tbl_contains(self.data.cut, node)
|
||||
end
|
||||
|
||||
---Node is copied. Will not be cut.
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
function Clipboard:is_copied(node)
|
||||
return vim.tbl_contains(self.data[ACTION.copy], node)
|
||||
return vim.tbl_contains(self.data.copy, node)
|
||||
end
|
||||
|
||||
return Clipboard
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local core = require "nvim-tree.core"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local utils = require("nvim-tree.utils")
|
||||
local events = require("nvim-tree.events")
|
||||
local core = require("nvim-tree.core")
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
local FileNode = require("nvim-tree.node.file")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param file string
|
||||
local function create_and_notify(file)
|
||||
events._dispatch_will_create_file(file)
|
||||
local ok, fd = pcall(vim.loop.fs_open, file, "w", 420)
|
||||
local ok, fd = pcall(vim.uv.fs_open, file, "w", 420)
|
||||
if not ok or type(fd) ~= "number" then
|
||||
notify.error("Couldn't create file " .. notify.render_path(file))
|
||||
return
|
||||
end
|
||||
vim.loop.fs_close(fd)
|
||||
vim.uv.fs_close(fd)
|
||||
events._dispatch_file_created(file)
|
||||
end
|
||||
|
||||
@@ -30,34 +32,21 @@ local function get_num_nodes(iter)
|
||||
return i
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@return string
|
||||
local function get_containing_folder(node)
|
||||
if node.nodes ~= nil then
|
||||
return utils.path_add_trailing(node.absolute_path)
|
||||
end
|
||||
local node_name_size = #(node.name or "")
|
||||
return node.absolute_path:sub(0, -node_name_size - 1)
|
||||
end
|
||||
|
||||
---@param node Node|nil
|
||||
---@param node Node?
|
||||
function M.fn(node)
|
||||
local cwd = core.get_cwd()
|
||||
if cwd == nil then
|
||||
node = node or core.get_explorer()
|
||||
if not node then
|
||||
return
|
||||
end
|
||||
|
||||
node = node and lib.get_last_group_node(node)
|
||||
if not node or node.name == ".." then
|
||||
node = {
|
||||
absolute_path = cwd,
|
||||
name = "",
|
||||
nodes = core.get_explorer().nodes,
|
||||
open = true,
|
||||
}
|
||||
local dir = node:is(FileNode) and node.parent or node:as(DirectoryNode)
|
||||
if not dir then
|
||||
return
|
||||
end
|
||||
|
||||
local containing_folder = get_containing_folder(node)
|
||||
dir = dir:last_group_node()
|
||||
|
||||
local containing_folder = utils.path_add_trailing(dir.absolute_path)
|
||||
|
||||
local input_opts = {
|
||||
prompt = "Create file ",
|
||||
@@ -72,7 +61,7 @@ function M.fn(node)
|
||||
end
|
||||
|
||||
if utils.file_exists(new_file_path) then
|
||||
notify.warn "Cannot create: file already exists"
|
||||
notify.warn("Cannot create: file already exists")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -87,15 +76,15 @@ function M.fn(node)
|
||||
for path in utils.path_split(new_file_path) do
|
||||
idx = idx + 1
|
||||
local p = utils.path_remove_trailing(path)
|
||||
if #path_to_create == 0 and vim.fn.has "win32" == 1 then
|
||||
path_to_create = utils.path_join { p, path_to_create }
|
||||
if #path_to_create == 0 and vim.fn.has("win32") == 1 then
|
||||
path_to_create = utils.path_join({ p, path_to_create })
|
||||
else
|
||||
path_to_create = utils.path_join { path_to_create, p }
|
||||
path_to_create = utils.path_join({ path_to_create, p })
|
||||
end
|
||||
if is_last_path_file and idx == num_nodes then
|
||||
create_and_notify(path_to_create)
|
||||
elseif not utils.file_exists(path_to_create) then
|
||||
local success = vim.loop.fs_mkdir(path_to_create, 493)
|
||||
local success = vim.uv.fs_mkdir(path_to_create, 493)
|
||||
if not success then
|
||||
notify.error("Could not create folder " .. notify.render_path(path_to_create))
|
||||
is_error = true
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.create_file = require "nvim-tree.actions.fs.create-file"
|
||||
M.remove_file = require "nvim-tree.actions.fs.remove-file"
|
||||
M.rename_file = require "nvim-tree.actions.fs.rename-file"
|
||||
M.trash = require "nvim-tree.actions.fs.trash"
|
||||
|
||||
function M.setup(opts)
|
||||
M.remove_file.setup(opts)
|
||||
M.rename_file.setup(opts)
|
||||
M.trash.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,9 +1,14 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
local view = require "nvim-tree.view"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local core = require("nvim-tree.core")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local events = require("nvim-tree.events")
|
||||
local lib = require("nvim-tree.lib")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local DirectoryLinkNode = require("nvim-tree.node.directory-link")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
local Node = require("nvim-tree.node")
|
||||
local RootNode = require("nvim-tree.node.root")
|
||||
|
||||
local M = {
|
||||
config = {},
|
||||
@@ -11,11 +16,18 @@ local M = {
|
||||
|
||||
---@param windows integer[]
|
||||
local function close_windows(windows)
|
||||
-- Prevent from closing when the win count equals 1 or 2,
|
||||
-- where the win to remove could be the last opened.
|
||||
-- For details see #2503.
|
||||
if view.View.float.enable and #vim.api.nvim_list_wins() < 3 then
|
||||
return
|
||||
-- When floating, prevent closing the last non-floating window.
|
||||
-- For details see #2503, #3187.
|
||||
if config.g.view.float.enable then
|
||||
local non_float_count = 0
|
||||
for _, win in ipairs(vim.api.nvim_list_wins()) do
|
||||
if vim.api.nvim_win_get_config(win).relative == "" then
|
||||
non_float_count = non_float_count + 1
|
||||
end
|
||||
end
|
||||
if non_float_count <= 1 then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
for _, window in ipairs(windows) do
|
||||
@@ -27,19 +39,19 @@ end
|
||||
|
||||
---@param absolute_path string
|
||||
local function clear_buffer(absolute_path)
|
||||
local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 }
|
||||
local bufs = vim.fn.getbufinfo({ bufloaded = 1, buflisted = 1 })
|
||||
for _, buf in pairs(bufs) do
|
||||
if buf.name == absolute_path then
|
||||
local tree_winnr = vim.api.nvim_get_current_win()
|
||||
if buf.hidden == 0 and (#bufs > 1 or view.View.float.enable) then
|
||||
if buf.hidden == 0 and (#bufs > 1 or config.g.view.float.enable) then
|
||||
vim.api.nvim_set_current_win(buf.windows[1])
|
||||
vim.cmd ":bn"
|
||||
vim.cmd(":bn")
|
||||
end
|
||||
vim.api.nvim_buf_delete(buf.bufnr, { force = true })
|
||||
if not view.View.float.quit_on_focus_loss then
|
||||
if not config.g.view.float.quit_on_focus_loss then
|
||||
vim.api.nvim_set_current_win(tree_winnr)
|
||||
end
|
||||
if M.config.actions.remove_file.close_window then
|
||||
if config.g.actions.remove_file.close_window then
|
||||
close_windows(buf.windows)
|
||||
end
|
||||
return
|
||||
@@ -50,31 +62,38 @@ end
|
||||
---@param cwd string
|
||||
---@return boolean|nil
|
||||
local function remove_dir(cwd)
|
||||
local handle, err = vim.loop.fs_scandir(cwd)
|
||||
local handle, err = vim.uv.fs_scandir(cwd)
|
||||
if not handle then
|
||||
notify.error(err)
|
||||
return
|
||||
end
|
||||
|
||||
while true do
|
||||
local name, _ = vim.loop.fs_scandir_next(handle)
|
||||
local name, _ = vim.uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local new_cwd = utils.path_join { cwd, name }
|
||||
local new_cwd = utils.path_join({ cwd, name })
|
||||
|
||||
-- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility
|
||||
local stat = vim.loop.fs_stat(new_cwd)
|
||||
local type = stat and stat.type or nil
|
||||
local stat = vim.uv.fs_stat(new_cwd)
|
||||
-- TODO remove once 0.12 is the minimum neovim version
|
||||
-- path incorrectly specified as an integer, fixed upstream for neovim 0.12 https://github.com/neovim/neovim/pull/33872
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local lstat = vim.uv.fs_lstat(new_cwd)
|
||||
|
||||
if type == "directory" then
|
||||
local type = stat and stat.type or nil
|
||||
-- Checks if file is a link file to ensure deletion of the symlink instead of the file it points to
|
||||
local ltype = lstat and lstat.type or nil
|
||||
|
||||
if type == "directory" and ltype ~= "link" then
|
||||
local success = remove_dir(new_cwd)
|
||||
if not success then
|
||||
return false
|
||||
end
|
||||
else
|
||||
local success = vim.loop.fs_unlink(new_cwd)
|
||||
local success = vim.uv.fs_unlink(new_cwd)
|
||||
if not success then
|
||||
return false
|
||||
end
|
||||
@@ -82,64 +101,58 @@ local function remove_dir(cwd)
|
||||
end
|
||||
end
|
||||
|
||||
return vim.loop.fs_rmdir(cwd)
|
||||
return vim.uv.fs_rmdir(cwd)
|
||||
end
|
||||
|
||||
--- Remove a node, notify errors, dispatch events
|
||||
---@param node Node
|
||||
---@return boolean success
|
||||
function M.remove(node)
|
||||
local notify_node = notify.render_path(node.absolute_path)
|
||||
if node.nodes ~= nil and not node.link_to then
|
||||
if node:is(DirectoryNode) and not node:is(DirectoryLinkNode) then
|
||||
local success = remove_dir(node.absolute_path)
|
||||
if not success then
|
||||
notify.error("Could not remove " .. notify_node)
|
||||
return
|
||||
return false
|
||||
end
|
||||
events._dispatch_folder_removed(node.absolute_path)
|
||||
else
|
||||
events._dispatch_will_remove_file(node.absolute_path)
|
||||
local success = vim.loop.fs_unlink(node.absolute_path)
|
||||
local success = vim.uv.fs_unlink(node.absolute_path)
|
||||
if not success then
|
||||
notify.error("Could not remove " .. notify_node)
|
||||
return
|
||||
return false
|
||||
end
|
||||
events._dispatch_file_removed(node.absolute_path)
|
||||
clear_buffer(node.absolute_path)
|
||||
end
|
||||
notify.info(notify_node .. " was properly removed.")
|
||||
return true
|
||||
end
|
||||
|
||||
---Remove a single node with confirmation.
|
||||
---@param node Node
|
||||
function M.fn(node)
|
||||
if node.name == ".." then
|
||||
local function remove_one(node)
|
||||
if node:is(RootNode) then
|
||||
return
|
||||
end
|
||||
|
||||
local function do_remove()
|
||||
M.remove(node)
|
||||
if M.remove(node) then
|
||||
notify.info(notify.render_path(node.absolute_path) .. " was properly removed.")
|
||||
end
|
||||
local explorer = core.get_explorer()
|
||||
if not M.config.filesystem_watchers.enable and explorer then
|
||||
if not config.g.filesystem_watchers.enable and explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
if M.config.ui.confirm.remove then
|
||||
if config.g.ui.confirm.remove then
|
||||
local prompt_select = "Remove " .. node.name .. "?"
|
||||
local prompt_input, items_short, items_long
|
||||
|
||||
if M.config.ui.confirm.default_yes then
|
||||
prompt_input = prompt_select .. " Y/n: "
|
||||
items_short = { "", "n" }
|
||||
items_long = { "Yes", "No" }
|
||||
else
|
||||
prompt_input = prompt_select .. " y/N: "
|
||||
items_short = { "", "y" }
|
||||
items_long = { "No", "Yes" }
|
||||
end
|
||||
local prompt_input, items_short, items_long = utils.confirm_prompt(prompt_select, config.g.ui.confirm.default_yes)
|
||||
|
||||
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_remove", function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" or item_short == (M.config.ui.confirm.default_yes and "") then
|
||||
if item_short == "y" or item_short == (config.g.ui.confirm.default_yes and "") then
|
||||
do_remove()
|
||||
end
|
||||
end)
|
||||
@@ -148,10 +161,53 @@ function M.fn(node)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config.ui = opts.ui
|
||||
M.config.actions = opts.actions
|
||||
M.config.filesystem_watchers = opts.filesystem_watchers
|
||||
---Remove multiple nodes with a single confirmation prompt.
|
||||
---@param nodes Node[]
|
||||
local function remove_many(nodes)
|
||||
if #nodes == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
nodes = utils.filter_descendant_nodes(nodes)
|
||||
|
||||
local function execute()
|
||||
local removed = 0
|
||||
for _, node in ipairs(nodes) do
|
||||
if not node:is(RootNode) and M.remove(node) then
|
||||
removed = removed + 1
|
||||
end
|
||||
end
|
||||
if removed > 0 then
|
||||
notify.info(string.format("%d nodes properly removed.", removed))
|
||||
end
|
||||
local explorer = core.get_explorer()
|
||||
if not config.g.filesystem_watchers.enable and explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
if config.g.ui.confirm.remove then
|
||||
local prompt_select = string.format("Remove %d selected?", #nodes)
|
||||
local prompt_input, items_short, items_long = utils.confirm_prompt(prompt_select, config.g.ui.confirm.default_yes)
|
||||
|
||||
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_remove", function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" or item_short == (config.g.ui.confirm.default_yes and "") then
|
||||
execute()
|
||||
end
|
||||
end)
|
||||
else
|
||||
execute()
|
||||
end
|
||||
end
|
||||
|
||||
---@param node_or_nodes Node|Node[]
|
||||
function M.fn(node_or_nodes)
|
||||
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
||||
remove_one(node_or_nodes)
|
||||
else
|
||||
remove_many(node_or_nodes)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local core = require("nvim-tree.core")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local events = require("nvim-tree.events")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local config = require("nvim-tree.config")
|
||||
local lib = require("nvim-tree.lib")
|
||||
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {
|
||||
config = {},
|
||||
}
|
||||
@@ -32,7 +35,7 @@ local function err_fmt(from, to, reason)
|
||||
end
|
||||
|
||||
local function rename_file_exists(node, to)
|
||||
if not utils.is_macos then
|
||||
if not config.os.macos then
|
||||
return utils.file_exists(to)
|
||||
end
|
||||
|
||||
@@ -45,7 +48,9 @@ end
|
||||
|
||||
---@param node Node
|
||||
---@param to string
|
||||
function M.rename(node, to)
|
||||
---@param opts? { notify?: boolean }
|
||||
function M.rename(node, to, opts)
|
||||
opts = opts and opts or {}
|
||||
local notify_from = notify.render_path(node.absolute_path)
|
||||
local notify_to = notify.render_path(to)
|
||||
|
||||
@@ -64,22 +69,22 @@ function M.rename(node, to)
|
||||
idx = idx + 1
|
||||
|
||||
local p = utils.path_remove_trailing(path)
|
||||
if #path_to_create == 0 and vim.fn.has "win32" == 1 then
|
||||
path_to_create = utils.path_join { p, path_to_create }
|
||||
if #path_to_create == 0 and vim.fn.has("win32") == 1 then
|
||||
path_to_create = utils.path_join({ p, path_to_create })
|
||||
else
|
||||
path_to_create = utils.path_join { path_to_create, p }
|
||||
path_to_create = utils.path_join({ path_to_create, p })
|
||||
end
|
||||
|
||||
if idx == num_nodes then
|
||||
events._dispatch_will_rename_node(node.absolute_path, to)
|
||||
local success, err = vim.loop.fs_rename(node.absolute_path, to)
|
||||
local success, err = vim.uv.fs_rename(node.absolute_path, to)
|
||||
|
||||
if not success then
|
||||
notify.warn(err_fmt(notify_from, notify_to, err))
|
||||
return
|
||||
end
|
||||
elseif not rename_file_exists(notify_from, path_to_create) then
|
||||
local success = vim.loop.fs_mkdir(path_to_create, 493)
|
||||
local success = vim.uv.fs_mkdir(path_to_create, 493)
|
||||
if not success then
|
||||
notify.error("Could not create folder " .. notify.render_path(path_to_create))
|
||||
is_error = true
|
||||
@@ -90,85 +95,126 @@ function M.rename(node, to)
|
||||
end
|
||||
|
||||
if not is_error then
|
||||
notify.info(string.format("%s -> %s", notify_from, notify_to))
|
||||
if opts.notify ~= false then
|
||||
notify.info(string.format("%s -> %s", notify_from, notify_to))
|
||||
end
|
||||
utils.rename_loaded_buffers(node.absolute_path, to)
|
||||
events._dispatch_node_renamed(node.absolute_path, to)
|
||||
end
|
||||
end
|
||||
|
||||
---@param default_modifier string|nil
|
||||
---@return fun(node: Node, modifier: string)
|
||||
function M.fn(default_modifier)
|
||||
default_modifier = default_modifier or ":t"
|
||||
|
||||
return function(node, modifier)
|
||||
if type(node) ~= "table" then
|
||||
node = lib.get_node_at_cursor()
|
||||
end
|
||||
|
||||
if node == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if type(modifier) ~= "string" then
|
||||
modifier = default_modifier
|
||||
end
|
||||
|
||||
-- support for only specific modifiers have been implemented
|
||||
if not ALLOWED_MODIFIERS[modifier] then
|
||||
notify.warn("Modifier " .. vim.inspect(modifier) .. " is not in allowed list : " .. table.concat(ALLOWED_MODIFIERS, ","))
|
||||
return
|
||||
end
|
||||
|
||||
node = lib.get_last_group_node(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
local namelen = node.name:len()
|
||||
local directory = node.absolute_path:sub(0, namelen * -1 - 1)
|
||||
local default_path
|
||||
local prepend = ""
|
||||
local append = ""
|
||||
default_path = vim.fn.fnamemodify(node.absolute_path, modifier)
|
||||
if modifier:sub(0, 2) == ":t" then
|
||||
prepend = directory
|
||||
end
|
||||
if modifier == ":t:r" then
|
||||
local extension = vim.fn.fnamemodify(node.name, ":e")
|
||||
append = extension:len() == 0 and "" or "." .. extension
|
||||
end
|
||||
if modifier == ":p:h" then
|
||||
default_path = default_path .. "/"
|
||||
end
|
||||
|
||||
local input_opts = {
|
||||
prompt = "Rename to ",
|
||||
default = default_path,
|
||||
completion = "file",
|
||||
}
|
||||
|
||||
vim.ui.input(input_opts, function(new_file_path)
|
||||
utils.clear_prompt()
|
||||
if not new_file_path then
|
||||
return
|
||||
end
|
||||
|
||||
M.rename(node, prepend .. new_file_path .. append)
|
||||
if not M.config.filesystem_watchers.enable then
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
find_file(utils.path_remove_trailing(new_file_path))
|
||||
end)
|
||||
---@param node Node
|
||||
---@param modifier? string
|
||||
local function prompt_to_rename(node, modifier)
|
||||
if not modifier or type(modifier) ~= "string" then
|
||||
modifier = ":t"
|
||||
end
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
|
||||
if type(node) ~= "table" then
|
||||
local node_at_cursor = explorer:get_node_at_cursor()
|
||||
if not node_at_cursor then
|
||||
return
|
||||
end
|
||||
node = node_at_cursor
|
||||
end
|
||||
|
||||
-- support for only specific modifiers have been implemented
|
||||
if not ALLOWED_MODIFIERS[modifier] then
|
||||
notify.warn("Modifier " .. vim.inspect(modifier) .. " is not in allowed list : " .. table.concat(ALLOWED_MODIFIERS, ","))
|
||||
return
|
||||
end
|
||||
|
||||
local dir = node:as(DirectoryNode)
|
||||
if dir then
|
||||
node = dir:last_group_node()
|
||||
end
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
local namelen = node.name:len()
|
||||
local directory = node.absolute_path:sub(0, namelen * -1 - 1)
|
||||
local default_path
|
||||
local prepend = ""
|
||||
local append = ""
|
||||
default_path = vim.fn.fnamemodify(node.absolute_path, modifier)
|
||||
if modifier:sub(0, 2) == ":t" then
|
||||
prepend = directory
|
||||
end
|
||||
if modifier == ":t:r" then
|
||||
local extension = vim.fn.fnamemodify(node.name, ":e")
|
||||
append = extension:len() == 0 and "" or "." .. extension
|
||||
end
|
||||
if modifier == ":p:h" then
|
||||
default_path = default_path .. "/"
|
||||
end
|
||||
|
||||
local input_opts = {
|
||||
prompt = "Rename to ",
|
||||
default = default_path,
|
||||
completion = "file",
|
||||
}
|
||||
|
||||
vim.ui.input(input_opts, function(new_file_path)
|
||||
utils.clear_prompt()
|
||||
if not new_file_path then
|
||||
return
|
||||
end
|
||||
|
||||
local full_new_path = prepend .. new_file_path .. append
|
||||
|
||||
M.rename(node, full_new_path)
|
||||
if not config.g.filesystem_watchers.enable then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
|
||||
find_file(utils.path_remove_trailing(full_new_path))
|
||||
end)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config.filesystem_watchers = opts.filesystem_watchers
|
||||
---@param node Node
|
||||
function M.rename_node(node)
|
||||
prompt_to_rename(node, ":t")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.rename_sub(node)
|
||||
prompt_to_rename(node, ":p:h")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.rename_basename(node)
|
||||
prompt_to_rename(node, ":t:r")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.rename_full(node)
|
||||
prompt_to_rename(node, ":p")
|
||||
end
|
||||
|
||||
---@param nodes Node[]
|
||||
---@param old_part string
|
||||
---@param new_part string
|
||||
function M.bulk_rename(nodes, old_part, new_part)
|
||||
local prompt_select = string.format("Substitute '%s' for '%s' in %s files?", old_part, new_part, #nodes)
|
||||
|
||||
lib.prompt(prompt_select .. " Y/n: ", prompt_select, ({ "", "y" }), { "No", "Yes" }, "nvimtree_bulk_rename", function(answer)
|
||||
utils.clear_prompt()
|
||||
if answer == "n" then return end
|
||||
|
||||
for _, node in ipairs(nodes) do
|
||||
local new_name = node.name:gsub(old_part, new_part)
|
||||
local new_full_path = vim.fn.fnamemodify(node.absolute_path, ":h") .. "/" .. new_name
|
||||
M.rename(node, new_full_path, { notify = false })
|
||||
end
|
||||
|
||||
notify.info(string.format("%s nodes substituted from %s -> %s", #nodes, old_part, new_part))
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local core = require("nvim-tree.core")
|
||||
local lib = require("nvim-tree.lib")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local events = require("nvim-tree.events")
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local DirectoryLinkNode = require("nvim-tree.node.directory-link")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
local Node = require("nvim-tree.node")
|
||||
local RootNode = require("nvim-tree.node.root")
|
||||
|
||||
local M = {
|
||||
config = {},
|
||||
}
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
|
||||
---@param absolute_path string
|
||||
local function clear_buffer(absolute_path)
|
||||
local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 }
|
||||
local bufs = vim.fn.getbufinfo({ bufloaded = 1, buflisted = 1 })
|
||||
for _, buf in pairs(bufs) do
|
||||
if buf.name == absolute_path then
|
||||
if buf.hidden == 0 and #bufs > 1 then
|
||||
local winnr = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_set_current_win(buf.windows[1])
|
||||
vim.cmd ":bn"
|
||||
vim.cmd(":bn")
|
||||
vim.api.nvim_set_current_win(winnr)
|
||||
end
|
||||
vim.api.nvim_buf_delete(buf.bufnr, {})
|
||||
@@ -28,9 +33,9 @@ end
|
||||
|
||||
---@param node Node
|
||||
function M.remove(node)
|
||||
local binary = M.config.trash.cmd:gsub(" .*$", "")
|
||||
local binary = config.g.trash.cmd:gsub(" .*$", "")
|
||||
if vim.fn.executable(binary) == 0 then
|
||||
notify.warn(string.format("trash.cmd '%s' is not an executable.", M.config.trash.cmd))
|
||||
notify.warn(string.format("trash.cmd '%s' is not an executable.", config.g.trash.cmd))
|
||||
return
|
||||
end
|
||||
|
||||
@@ -41,27 +46,27 @@ function M.remove(node)
|
||||
|
||||
-- trashes a path (file or folder)
|
||||
local function trash_path(on_exit)
|
||||
local need_sync_wait = utils.is_windows
|
||||
local job = vim.fn.jobstart(M.config.trash.cmd .. " " .. vim.fn.shellescape(node.absolute_path), {
|
||||
local need_sync_wait = config.os.windows
|
||||
local job = vim.fn.jobstart(config.g.trash.cmd .. " " .. vim.fn.shellescape(node.absolute_path), {
|
||||
detach = not need_sync_wait,
|
||||
on_exit = on_exit,
|
||||
on_stderr = on_stderr,
|
||||
})
|
||||
if need_sync_wait then
|
||||
vim.fn.jobwait { job }
|
||||
vim.fn.jobwait({ job })
|
||||
end
|
||||
end
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
|
||||
if node.nodes ~= nil and not node.link_to then
|
||||
if node:is(DirectoryNode) and not node:is(DirectoryLinkNode) then
|
||||
trash_path(function(_, rc)
|
||||
if rc ~= 0 then
|
||||
notify.warn("trash failed: " .. err_msg .. "; please see :help nvim-tree.trash")
|
||||
return
|
||||
end
|
||||
events._dispatch_folder_removed(node.absolute_path)
|
||||
if not M.config.filesystem_watchers.enable and explorer then
|
||||
if not config.g.filesystem_watchers.enable and explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end)
|
||||
@@ -74,16 +79,17 @@ function M.remove(node)
|
||||
end
|
||||
events._dispatch_file_removed(node.absolute_path)
|
||||
clear_buffer(node.absolute_path)
|
||||
if not M.config.filesystem_watchers.enable and explorer then
|
||||
if not config.g.filesystem_watchers.enable and explorer then
|
||||
explorer:reload_explorer()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---Trash a single node with confirmation.
|
||||
---@param node Node
|
||||
function M.fn(node)
|
||||
if node.name == ".." then
|
||||
local function trash_one(node)
|
||||
if node:is(RootNode) then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -91,23 +97,13 @@ function M.fn(node)
|
||||
M.remove(node)
|
||||
end
|
||||
|
||||
if M.config.ui.confirm.trash then
|
||||
if config.g.ui.confirm.trash then
|
||||
local prompt_select = "Trash " .. node.name .. "?"
|
||||
local prompt_input, items_short, items_long
|
||||
|
||||
if M.config.ui.confirm.default_yes then
|
||||
prompt_input = prompt_select .. " Y/n: "
|
||||
items_short = { "", "n" }
|
||||
items_long = { "Yes", "No" }
|
||||
else
|
||||
prompt_input = prompt_select .. " y/N: "
|
||||
items_short = { "", "y" }
|
||||
items_long = { "No", "Yes" }
|
||||
end
|
||||
local prompt_input, items_short, items_long = utils.confirm_prompt(prompt_select, config.g.ui.confirm.default_yes)
|
||||
|
||||
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_trash", function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" or item_short == (M.config.ui.confirm.default_yes and "") then
|
||||
if item_short == "y" or item_short == (config.g.ui.confirm.default_yes and "") then
|
||||
do_trash()
|
||||
end
|
||||
end)
|
||||
@@ -116,10 +112,45 @@ function M.fn(node)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config.ui = opts.ui
|
||||
M.config.trash = opts.trash
|
||||
M.config.filesystem_watchers = opts.filesystem_watchers
|
||||
---Trash multiple nodes with a single confirmation prompt.
|
||||
---@param nodes Node[]
|
||||
local function trash_many(nodes)
|
||||
if #nodes == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
nodes = utils.filter_descendant_nodes(nodes)
|
||||
|
||||
local function execute()
|
||||
for _, node in ipairs(nodes) do
|
||||
if not node:is(RootNode) then
|
||||
M.remove(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if config.g.ui.confirm.trash then
|
||||
local prompt_select = string.format("Trash %d selected?", #nodes)
|
||||
local prompt_input, items_short, items_long = utils.confirm_prompt(prompt_select, config.g.ui.confirm.default_yes)
|
||||
|
||||
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_trash", function(item_short)
|
||||
utils.clear_prompt()
|
||||
if item_short == "y" or item_short == (config.g.ui.confirm.default_yes and "") then
|
||||
execute()
|
||||
end
|
||||
end)
|
||||
else
|
||||
execute()
|
||||
end
|
||||
end
|
||||
|
||||
---@param node_or_nodes Node|Node[]
|
||||
function M.fn(node_or_nodes)
|
||||
if type(node_or_nodes) == "table" and node_or_nodes.is and node_or_nodes:is(Node) then
|
||||
trash_one(node_or_nodes)
|
||||
else
|
||||
trash_many(node_or_nodes)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.finders = require "nvim-tree.actions.finders"
|
||||
M.fs = require "nvim-tree.actions.fs"
|
||||
M.moves = require "nvim-tree.actions.moves"
|
||||
M.node = require "nvim-tree.actions.node"
|
||||
M.root = require "nvim-tree.actions.root"
|
||||
M.tree = require "nvim-tree.actions.tree"
|
||||
|
||||
function M.setup(opts)
|
||||
M.fs.setup(opts)
|
||||
M.node.setup(opts)
|
||||
M.root.setup(opts)
|
||||
M.tree.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,7 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.item = require "nvim-tree.actions.moves.item"
|
||||
M.parent = require "nvim-tree.actions.moves.parent"
|
||||
M.sibling = require "nvim-tree.actions.moves.sibling"
|
||||
|
||||
return M
|
||||
@@ -1,23 +1,23 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local view = require "nvim-tree.view"
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local explorer_node = require "nvim-tree.explorer.node"
|
||||
local diagnostics = require "nvim-tree.diagnostics"
|
||||
local view = require("nvim-tree.view")
|
||||
local core = require("nvim-tree.core")
|
||||
local diagnostics = require("nvim-tree.diagnostics")
|
||||
|
||||
local FileNode = require("nvim-tree.node.file")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
local MAX_DEPTH = 100
|
||||
|
||||
---Return the status of the node or nil if no status, depending on the type of
|
||||
---status.
|
||||
---@param node table node to inspect
|
||||
---@param what string type of status
|
||||
---@param skip_gitignored boolean default false
|
||||
---@param node Node to inspect
|
||||
---@param what string? type of status
|
||||
---@param skip_gitignored boolean? default false
|
||||
---@return boolean
|
||||
local function status_is_valid(node, what, skip_gitignored)
|
||||
if what == "git" then
|
||||
local git_status = explorer_node.get_git_status(node)
|
||||
return git_status ~= nil and (not skip_gitignored or git_status[1] ~= "!!")
|
||||
local git_xy = node:get_git_xy()
|
||||
return git_xy ~= nil and (not skip_gitignored or git_xy[1] ~= "!!")
|
||||
elseif what == "diag" then
|
||||
local diag_status = diagnostics.get_diag_status(node)
|
||||
return diag_status ~= nil and diag_status.value ~= nil
|
||||
@@ -29,15 +29,16 @@ local function status_is_valid(node, what, skip_gitignored)
|
||||
end
|
||||
|
||||
---Move to the next node that has a valid status. If none found, don't move.
|
||||
---@param where string where to move (forwards or backwards)
|
||||
---@param what string type of status
|
||||
---@param skip_gitignored boolean default false
|
||||
local function move(where, what, skip_gitignored)
|
||||
---@param explorer Explorer
|
||||
---@param where string? where to move (forwards or backwards)
|
||||
---@param what string? type of status
|
||||
---@param skip_gitignored boolean? default false
|
||||
local function move(explorer, where, what, skip_gitignored)
|
||||
local first_node_line = core.get_nodes_starting_line()
|
||||
local nodes_by_line = utils.get_nodes_by_line(core.get_explorer().nodes, first_node_line)
|
||||
local nodes_by_line = explorer:get_nodes_by_line(first_node_line)
|
||||
local iter_start, iter_end, iter_step, cur, first, nex
|
||||
|
||||
local cursor = lib.get_cursor_position()
|
||||
local cursor = explorer:get_cursor_position()
|
||||
if cursor and cursor[1] < first_node_line then
|
||||
cur = cursor[1]
|
||||
end
|
||||
@@ -65,31 +66,33 @@ local function move(where, what, skip_gitignored)
|
||||
end
|
||||
|
||||
if nex then
|
||||
view.set_cursor { nex, 0 }
|
||||
view.set_cursor({ nex, 0 })
|
||||
elseif vim.o.wrapscan and first then
|
||||
view.set_cursor { first, 0 }
|
||||
view.set_cursor({ first, 0 })
|
||||
end
|
||||
end
|
||||
|
||||
---@param node DirectoryNode
|
||||
local function expand_node(node)
|
||||
if not node.open then
|
||||
-- Expand the node.
|
||||
-- Should never collapse since we checked open.
|
||||
lib.expand_or_collapse(node)
|
||||
node:expand_or_collapse(false)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move to the next node recursively.
|
||||
---@param what string type of status
|
||||
---@param skip_gitignored boolean default false
|
||||
local function move_next_recursive(what, skip_gitignored)
|
||||
---@param explorer Explorer
|
||||
---@param what string? type of status
|
||||
---@param skip_gitignored? boolean default false
|
||||
local function move_next_recursive(explorer, what, skip_gitignored)
|
||||
-- If the current node:
|
||||
-- * is a directory
|
||||
-- * and is not the root node
|
||||
-- * and has a git/diag status
|
||||
-- * and is not opened
|
||||
-- expand it.
|
||||
local node_init = lib.get_node_at_cursor()
|
||||
local node_init = explorer:get_node_at_cursor()
|
||||
if not node_init then
|
||||
return
|
||||
end
|
||||
@@ -97,13 +100,14 @@ local function move_next_recursive(what, skip_gitignored)
|
||||
if node_init.name ~= ".." then -- root node cannot have a status
|
||||
valid = status_is_valid(node_init, what, skip_gitignored)
|
||||
end
|
||||
if node_init.nodes ~= nil and valid and not node_init.open then
|
||||
lib.expand_or_collapse(node_init)
|
||||
local node_dir = node_init:as(DirectoryNode)
|
||||
if node_dir and valid and not node_dir.open then
|
||||
node_dir:expand_or_collapse(false)
|
||||
end
|
||||
|
||||
move("next", what, skip_gitignored)
|
||||
move(explorer, "next", what, skip_gitignored)
|
||||
|
||||
local node_cur = lib.get_node_at_cursor()
|
||||
local node_cur = explorer:get_node_at_cursor()
|
||||
if not node_cur then
|
||||
return
|
||||
end
|
||||
@@ -115,20 +119,15 @@ local function move_next_recursive(what, skip_gitignored)
|
||||
|
||||
-- i is used to limit iterations.
|
||||
local i = 0
|
||||
local is_dir = node_cur.nodes ~= nil
|
||||
while is_dir and i < MAX_DEPTH do
|
||||
expand_node(node_cur)
|
||||
local dir_cur = node_cur:as(DirectoryNode)
|
||||
while dir_cur and i < MAX_DEPTH do
|
||||
expand_node(dir_cur)
|
||||
|
||||
move("next", what, skip_gitignored)
|
||||
move(explorer, "next", what, skip_gitignored)
|
||||
|
||||
-- Save current node.
|
||||
node_cur = lib.get_node_at_cursor()
|
||||
-- Update is_dir.
|
||||
if node_cur then
|
||||
is_dir = node_cur.nodes ~= nil
|
||||
else
|
||||
is_dir = false
|
||||
end
|
||||
node_cur = explorer:get_node_at_cursor()
|
||||
dir_cur = node_cur and node_cur:as(DirectoryNode)
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
@@ -149,24 +148,25 @@ end
|
||||
--- 4.4) Call a non-recursive prev.
|
||||
--- 4.5) Save the current node and start back from 4.1.
|
||||
---
|
||||
---@param what string type of status
|
||||
---@param skip_gitignored boolean default false
|
||||
local function move_prev_recursive(what, skip_gitignored)
|
||||
---@param explorer Explorer
|
||||
---@param what string? type of status
|
||||
---@param skip_gitignored boolean? default false
|
||||
local function move_prev_recursive(explorer, what, skip_gitignored)
|
||||
local node_init, node_cur
|
||||
|
||||
-- 1)
|
||||
node_init = lib.get_node_at_cursor()
|
||||
node_init = explorer:get_node_at_cursor()
|
||||
if node_init == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- 2)
|
||||
move("prev", what, skip_gitignored)
|
||||
move(explorer, "prev", what, skip_gitignored)
|
||||
|
||||
node_cur = lib.get_node_at_cursor()
|
||||
node_cur = explorer:get_node_at_cursor()
|
||||
if node_cur == node_init.parent then
|
||||
-- 3)
|
||||
move_prev_recursive(what, skip_gitignored)
|
||||
move_prev_recursive(explorer, what, skip_gitignored)
|
||||
else
|
||||
-- i is used to limit iterations.
|
||||
local i = 0
|
||||
@@ -175,31 +175,33 @@ local function move_prev_recursive(what, skip_gitignored)
|
||||
if
|
||||
node_cur == nil
|
||||
or node_cur == node_init -- we didn't move
|
||||
or not node_cur.nodes -- node is a file
|
||||
or node_cur:is(FileNode) -- node is a file
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
-- 4.2)
|
||||
local node_dir = node_cur
|
||||
expand_node(node_dir)
|
||||
local node_dir = node_cur:as(DirectoryNode)
|
||||
if node_dir then
|
||||
expand_node(node_dir)
|
||||
end
|
||||
|
||||
-- 4.3)
|
||||
if node_init.name == ".." then -- root node
|
||||
view.set_cursor { 1, 0 } -- move to root node (position 1)
|
||||
view.set_cursor({ 1, 0 }) -- move to root node (position 1)
|
||||
else
|
||||
local node_init_line = utils.find_node_line(node_init)
|
||||
local node_init_line = explorer:find_node_line(node_init)
|
||||
if node_init_line < 0 then
|
||||
return
|
||||
end
|
||||
view.set_cursor { node_init_line, 0 }
|
||||
view.set_cursor({ node_init_line, 0 })
|
||||
end
|
||||
|
||||
-- 4.4)
|
||||
move("prev", what, skip_gitignored)
|
||||
move(explorer, "prev", what, skip_gitignored)
|
||||
|
||||
-- 4.5)
|
||||
node_cur = lib.get_node_at_cursor()
|
||||
node_cur = explorer:get_node_at_cursor()
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
@@ -207,36 +209,83 @@ local function move_prev_recursive(what, skip_gitignored)
|
||||
end
|
||||
|
||||
---@class NavigationItemOpts
|
||||
---@field where string
|
||||
---@field what string
|
||||
---@field where string?
|
||||
---@field what string?
|
||||
---@field skip_gitignored boolean?
|
||||
---@field recurse boolean?
|
||||
|
||||
---@param opts NavigationItemOpts
|
||||
---@return fun()
|
||||
function M.fn(opts)
|
||||
return function()
|
||||
local recurse = false
|
||||
local skip_gitignored = false
|
||||
local function item(opts)
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
|
||||
-- recurse only valid for git and diag moves.
|
||||
if (opts.what == "git" or opts.what == "diag") and opts.recurse ~= nil then
|
||||
recurse = opts.recurse
|
||||
end
|
||||
local recurse = false
|
||||
|
||||
if opts.skip_gitignored ~= nil then
|
||||
skip_gitignored = opts.skip_gitignored
|
||||
end
|
||||
-- recurse only valid for git and diag moves.
|
||||
if (opts.what == "git" or opts.what == "diag") and opts.recurse ~= nil then
|
||||
recurse = opts.recurse
|
||||
end
|
||||
|
||||
if not recurse then
|
||||
move(opts.where, opts.what, skip_gitignored)
|
||||
return
|
||||
end
|
||||
if not recurse then
|
||||
move(explorer, opts.where, opts.what, opts.skip_gitignored)
|
||||
return
|
||||
end
|
||||
|
||||
if opts.where == "next" then
|
||||
move_next_recursive(opts.what, skip_gitignored)
|
||||
elseif opts.where == "prev" then
|
||||
move_prev_recursive(opts.what, skip_gitignored)
|
||||
end
|
||||
if opts.where == "next" then
|
||||
move_next_recursive(explorer, opts.what, opts.skip_gitignored)
|
||||
elseif opts.where == "prev" then
|
||||
move_prev_recursive(explorer, opts.what, opts.skip_gitignored)
|
||||
end
|
||||
end
|
||||
|
||||
function M.git_next()
|
||||
item({ where = "next", what = "git" })
|
||||
end
|
||||
|
||||
function M.git_next_skip_gitignored()
|
||||
item({ where = "next", what = "git", skip_gitignored = true })
|
||||
end
|
||||
|
||||
function M.git_next_recursive()
|
||||
item({ where = "next", what = "git", recurse = true })
|
||||
end
|
||||
|
||||
function M.git_prev()
|
||||
item({ where = "prev", what = "git" })
|
||||
end
|
||||
|
||||
function M.git_prev_skip_gitignored()
|
||||
item({ where = "prev", what = "git", skip_gitignored = true })
|
||||
end
|
||||
|
||||
function M.git_prev_recursive()
|
||||
item({ where = "prev", what = "git", recurse = true })
|
||||
end
|
||||
|
||||
function M.diagnostics_next()
|
||||
item({ where = "next", what = "diag" })
|
||||
end
|
||||
|
||||
function M.diagnostics_next_recursive()
|
||||
item({ where = "next", what = "diag", recurse = true })
|
||||
end
|
||||
|
||||
function M.diagnostics_prev()
|
||||
item({ where = "prev", what = "diag" })
|
||||
end
|
||||
|
||||
function M.diagnostics_prev_recursive()
|
||||
item({ where = "prev", what = "diag", recurse = true })
|
||||
end
|
||||
|
||||
function M.opened_next()
|
||||
item({ where = "next", what = "opened" })
|
||||
end
|
||||
|
||||
function M.opened_prev()
|
||||
item({ where = "prev", what = "opened" })
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,45 +1,47 @@
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local view = require("nvim-tree.view")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param should_close boolean|nil
|
||||
---@return fun(node: Node): boolean|nil
|
||||
function M.fn(should_close)
|
||||
should_close = should_close or false
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
|
||||
return function(node)
|
||||
node = lib.get_last_group_node(node)
|
||||
if should_close and node.open then
|
||||
node.open = false
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
---@param node Node
|
||||
---@param should_close boolean
|
||||
local function move(node, should_close)
|
||||
local dir = node:as(DirectoryNode)
|
||||
if dir then
|
||||
dir = dir:last_group_node()
|
||||
if should_close and dir.open then
|
||||
dir.open = false
|
||||
dir.explorer.renderer:draw()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local parent = utils.get_parent_of_group(node).parent
|
||||
local parent = (node:get_parent_of_group() or node).parent
|
||||
|
||||
if not parent or not parent.parent then
|
||||
return view.set_cursor { 1, 0 }
|
||||
end
|
||||
if not parent or not parent.parent then
|
||||
view.set_cursor({ 1, 0 })
|
||||
return
|
||||
end
|
||||
|
||||
local _, line = utils.find_node(core.get_explorer().nodes, function(n)
|
||||
return n.absolute_path == parent.absolute_path
|
||||
end)
|
||||
local _, line = parent.explorer:find_node(function(n)
|
||||
return n.absolute_path == parent.absolute_path
|
||||
end)
|
||||
|
||||
view.set_cursor { line + 1, 0 }
|
||||
if should_close then
|
||||
parent.open = false
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
view.set_cursor({ line + 1, 0 })
|
||||
if should_close then
|
||||
parent.open = false
|
||||
parent.explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.move(node)
|
||||
move(node, false)
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.move_close(node)
|
||||
move(node, true)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,53 +1,75 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local Iterator = require "nvim-tree.iterators.node-iterator"
|
||||
local core = require("nvim-tree.core")
|
||||
local Iterator = require("nvim-tree.iterators.node-iterator")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param direction string
|
||||
---@return fun(node: Node): nil
|
||||
function M.fn(direction)
|
||||
return function(node)
|
||||
if node.name == ".." or not direction then
|
||||
return
|
||||
end
|
||||
---@param node Node
|
||||
---@param direction "next"|"prev"|"first"|"last"
|
||||
local function move(node, direction)
|
||||
if node.name == ".." or not direction then
|
||||
return
|
||||
end
|
||||
|
||||
local first, last, next, prev = nil, nil, nil, nil
|
||||
local found = false
|
||||
local parent = node.parent or core.get_explorer()
|
||||
Iterator.builder(parent.nodes)
|
||||
:recursor(function()
|
||||
return nil
|
||||
end)
|
||||
:applier(function(n)
|
||||
first = first or n
|
||||
last = n
|
||||
if n.absolute_path == node.absolute_path then
|
||||
found = true
|
||||
return
|
||||
end
|
||||
prev = not found and n or prev
|
||||
if found and not next then
|
||||
next = n
|
||||
end
|
||||
end)
|
||||
:iterate()
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
|
||||
local target_node
|
||||
if direction == "first" then
|
||||
target_node = first
|
||||
elseif direction == "last" then
|
||||
target_node = last
|
||||
elseif direction == "next" then
|
||||
target_node = next or first
|
||||
else
|
||||
target_node = prev or last
|
||||
end
|
||||
local first, last, next, prev = nil, nil, nil, nil
|
||||
local found = false
|
||||
local parent = node.parent or explorer
|
||||
Iterator.builder(parent and parent.nodes or {})
|
||||
:recursor(function()
|
||||
return nil
|
||||
end)
|
||||
:applier(function(n)
|
||||
first = first or n
|
||||
last = n
|
||||
if n.absolute_path == node.absolute_path then
|
||||
found = true
|
||||
return
|
||||
end
|
||||
prev = not found and n or prev
|
||||
if found and not next then
|
||||
next = n
|
||||
end
|
||||
end)
|
||||
:iterate()
|
||||
|
||||
if target_node then
|
||||
utils.focus_file(target_node.absolute_path)
|
||||
end
|
||||
local target_node
|
||||
if direction == "first" then
|
||||
target_node = first
|
||||
elseif direction == "last" then
|
||||
target_node = last
|
||||
elseif direction == "next" then
|
||||
target_node = next or first
|
||||
else
|
||||
target_node = prev or last
|
||||
end
|
||||
|
||||
if target_node then
|
||||
explorer:focus_node_or_parent(target_node)
|
||||
end
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.next(node)
|
||||
move(node, "next")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.prev(node)
|
||||
move(node, "prev")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.first(node)
|
||||
move(node, "first")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.last(node)
|
||||
move(node, "last")
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
55
lua/nvim-tree/actions/node/buffer.lua
Normal file
55
lua/nvim-tree/actions/node/buffer.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
-- Copyright 2019 Yazdani Kiyan under MIT License
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param node Node
|
||||
---@param opts? nvim_tree.api.node.buffer.RemoveOpts
|
||||
function M.delete(node, opts)
|
||||
M.delete_buffer("delete", node.absolute_path, opts)
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@param opts? nvim_tree.api.node.buffer.RemoveOpts
|
||||
function M.wipe(node, opts)
|
||||
M.delete_buffer("wipe", node.absolute_path, opts)
|
||||
end
|
||||
|
||||
---@alias ApiNodeDeleteWipeBufferMode '"delete"'|'"wipe"'
|
||||
|
||||
---@param mode ApiNodeDeleteWipeBufferMode
|
||||
---@param filename string
|
||||
---@param opts? nvim_tree.api.node.buffer.RemoveOpts
|
||||
function M.delete_buffer(mode, filename, opts)
|
||||
if type(mode) ~= "string" then
|
||||
mode = "delete"
|
||||
end
|
||||
|
||||
local buf_fn = vim.cmd.bdelete
|
||||
if mode == "wipe" then
|
||||
buf_fn = vim.cmd.bwipe
|
||||
end
|
||||
|
||||
opts = opts or { force = false }
|
||||
|
||||
local notify_node = notify.render_path(filename)
|
||||
|
||||
-- check if buffer for file at cursor exists and if it is loaded
|
||||
local bufnr_at_filename = vim.fn.bufnr(filename)
|
||||
if bufnr_at_filename == -1 or vim.fn.getbufinfo(bufnr_at_filename)[1].loaded == 0 then
|
||||
notify.info("No loaded buffer coincides with " .. notify_node)
|
||||
return
|
||||
end
|
||||
|
||||
local force = opts.force
|
||||
-- check if buffer is modified
|
||||
local buf_modified = vim.fn.getbufinfo(bufnr_at_filename)[1].changed
|
||||
if not force and buf_modified == 1 then
|
||||
notify.error("Buffer for file " .. notify_node .. " is modified")
|
||||
return
|
||||
end
|
||||
|
||||
buf_fn({ filename, bang = force })
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,4 +1,5 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local utils = require("nvim-tree.utils")
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -38,7 +39,7 @@ local function setup_window(node)
|
||||
local max_width = vim.fn.max(vim.tbl_map(function(n)
|
||||
return #n
|
||||
end, lines))
|
||||
local open_win_config = vim.tbl_extend("force", M.open_win_config, {
|
||||
local open_win_config = vim.tbl_extend("force", config.g.actions.file_popup.open_win_config, {
|
||||
width = max_width + 1,
|
||||
height = #lines,
|
||||
noautocmd = true,
|
||||
@@ -50,14 +51,17 @@ local function setup_window(node)
|
||||
file_path = node.absolute_path,
|
||||
}
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[bufnr].bufhidden = "wipe"
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
vim.api.nvim_win_set_buf(winnr, bufnr)
|
||||
end
|
||||
|
||||
function M.close_popup()
|
||||
if current_popup ~= nil then
|
||||
vim.api.nvim_win_close(current_popup.winnr, true)
|
||||
vim.cmd "augroup NvimTreeRemoveFilePopup | au! CursorMoved | augroup END"
|
||||
if vim.api.nvim_win_is_valid(current_popup.winnr) then
|
||||
vim.api.nvim_win_close(current_popup.winnr, true)
|
||||
end
|
||||
vim.cmd("augroup NvimTreeRemoveFilePopup | au! CursorMoved | augroup END")
|
||||
|
||||
current_popup = nil
|
||||
end
|
||||
@@ -86,8 +90,4 @@ function M.toggle_file_info(node)
|
||||
})
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.open_win_config = opts.actions.file_popup.open_win_config
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.file_popup = require "nvim-tree.actions.node.file-popup"
|
||||
M.open_file = require "nvim-tree.actions.node.open-file"
|
||||
M.run_command = require "nvim-tree.actions.node.run-command"
|
||||
M.system_open = require "nvim-tree.actions.node.system-open"
|
||||
|
||||
function M.setup(opts)
|
||||
require("nvim-tree.actions.node.system-open").setup(opts)
|
||||
require("nvim-tree.actions.node.file-popup").setup(opts)
|
||||
require("nvim-tree.actions.node.open-file").setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,8 +1,16 @@
|
||||
-- Copyright 2019 Yazdani Kiyan under MIT License
|
||||
local lib = require "nvim-tree.lib"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local view = require "nvim-tree.view"
|
||||
local lib = require("nvim-tree.lib")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local full_name = require("nvim-tree.renderer.components.full-name")
|
||||
local view = require("nvim-tree.view")
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
local FileLinkNode = require("nvim-tree.node.file-link")
|
||||
local RootNode = require("nvim-tree.node.root")
|
||||
|
||||
---@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 = {}
|
||||
|
||||
@@ -25,13 +33,8 @@ local function usable_win_ids()
|
||||
|
||||
return vim.tbl_filter(function(id)
|
||||
local bufid = vim.api.nvim_win_get_buf(id)
|
||||
for option, v in pairs(M.window_picker.exclude) do
|
||||
local ok, option_value
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
ok, option_value = pcall(vim.api.nvim_get_option_value, option, { buf = bufid })
|
||||
else
|
||||
ok, option_value = pcall(vim.api.nvim_buf_get_option, bufid, option) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
for option, v in pairs(config.g.actions.open_file.window_picker.exclude) do
|
||||
local ok, option_value = pcall(vim.api.nvim_get_option_value, option, { buf = bufid })
|
||||
|
||||
if ok and vim.tbl_contains(v, option_value) then
|
||||
return false
|
||||
@@ -39,21 +42,15 @@ local function usable_win_ids()
|
||||
end
|
||||
|
||||
local win_config = vim.api.nvim_win_get_config(id)
|
||||
return id ~= tree_winid and win_config.focusable and not win_config.external or false
|
||||
return id ~= tree_winid
|
||||
and id ~= full_name.popup_win
|
||||
and win_config.focusable
|
||||
and not win_config.hide
|
||||
and not win_config.external
|
||||
or false
|
||||
end, win_ids)
|
||||
end
|
||||
|
||||
---Find the first window in the tab that is not NvimTree.
|
||||
---@return integer -1 if none available
|
||||
local function first_win_id()
|
||||
local selectable = usable_win_ids()
|
||||
if #selectable > 0 then
|
||||
return selectable[1]
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
---Get user to pick a window in the tab that is not NvimTree.
|
||||
---@return integer|nil -- If a valid window was picked, return its id. If an
|
||||
--- invalid window was picked / user canceled, return nil. If there are
|
||||
@@ -69,16 +66,26 @@ local function pick_win_id()
|
||||
return selectable[1]
|
||||
end
|
||||
|
||||
if #M.window_picker.chars < #selectable then
|
||||
notify.error(string.format("More windows (%d) than actions.open_file.window_picker.chars (%d).", #selectable, #M.window_picker.chars))
|
||||
if #config.g.actions.open_file.window_picker.chars < #selectable then
|
||||
notify.error(string.format("More windows (%d) than actions.open_file.window_picker.chars (%d).", #selectable,
|
||||
#config.g.actions.open_file.window_picker.chars))
|
||||
return nil
|
||||
end
|
||||
|
||||
local i = 1
|
||||
local win_opts = {}
|
||||
local win_opts_selectable = {}
|
||||
local win_opts_unselectable = {}
|
||||
local win_map = {}
|
||||
local laststatus = vim.o.laststatus
|
||||
vim.o.laststatus = 2
|
||||
local fillchars = vim.opt.fillchars:get()
|
||||
local stl = fillchars.stl
|
||||
local stlnc = fillchars.stlnc
|
||||
fillchars.stl = nil
|
||||
fillchars.stlnc = nil
|
||||
vim.opt.fillchars = fillchars
|
||||
fillchars.stl = stl
|
||||
fillchars.stlnc = stlnc
|
||||
|
||||
local tabpage = vim.api.nvim_get_current_tabpage()
|
||||
local win_ids = vim.api.nvim_tabpage_list_wins(tabpage)
|
||||
@@ -89,66 +96,42 @@ local function pick_win_id()
|
||||
|
||||
if laststatus == 3 then
|
||||
for _, win_id in ipairs(not_selectable) do
|
||||
local ok_status, statusline, ok_hl, winhl
|
||||
local ok_status, statusline = pcall(vim.api.nvim_get_option_value, "statusline", { win = win_id })
|
||||
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
ok_status, statusline = pcall(vim.api.nvim_get_option_value, "statusline", { win = win_id })
|
||||
ok_hl, winhl = pcall(vim.api.nvim_get_option_value, "winhl", { win = win_id })
|
||||
else
|
||||
ok_status, statusline = pcall(vim.api.nvim_win_get_option, win_id, "statusline") ---@diagnostic disable-line: deprecated
|
||||
ok_hl, winhl = pcall(vim.api.nvim_win_get_option, win_id, "winhl") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
|
||||
win_opts[win_id] = {
|
||||
win_opts_unselectable[win_id] = {
|
||||
statusline = ok_status and statusline or "",
|
||||
winhl = ok_hl and winhl or "",
|
||||
}
|
||||
|
||||
-- Clear statusline for windows not selectable
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value("statusline", " ", { win = win_id })
|
||||
else
|
||||
vim.api.nvim_win_set_option(win_id, "statusline", " ") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
vim.api.nvim_set_option_value("statusline", " ", { win = win_id })
|
||||
end
|
||||
end
|
||||
|
||||
-- Setup UI
|
||||
for _, id in ipairs(selectable) do
|
||||
local char = M.window_picker.chars:sub(i, i)
|
||||
local char = config.g.actions.open_file.window_picker.chars:sub(i, i)
|
||||
|
||||
local ok_status, statusline, ok_hl, winhl
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
ok_status, statusline = pcall(vim.api.nvim_get_option_value, "statusline", { win = id })
|
||||
ok_hl, winhl = pcall(vim.api.nvim_get_option_value, "winhl", { win = id })
|
||||
else
|
||||
ok_status, statusline = pcall(vim.api.nvim_win_get_option, id, "statusline") ---@diagnostic disable-line: deprecated
|
||||
ok_hl, winhl = pcall(vim.api.nvim_win_get_option, id, "winhl") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
local ok_status, statusline = pcall(vim.api.nvim_get_option_value, "statusline", { win = id })
|
||||
local ok_hl, winhl = pcall(vim.api.nvim_get_option_value, "winhl", { win = id })
|
||||
|
||||
win_opts[id] = {
|
||||
win_opts_selectable[id] = {
|
||||
statusline = ok_status and statusline or "",
|
||||
winhl = ok_hl and winhl or "",
|
||||
}
|
||||
win_map[char] = id
|
||||
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value("statusline", "%=" .. char .. "%=", { win = id })
|
||||
vim.api.nvim_set_option_value("winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker", { win = id })
|
||||
else
|
||||
vim.api.nvim_win_set_option(id, "statusline", "%=" .. char .. "%=") ---@diagnostic disable-line: deprecated
|
||||
vim.api.nvim_win_set_option(id, "winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
vim.api.nvim_set_option_value("statusline", "%=" .. char .. "%=", { win = id })
|
||||
vim.api.nvim_set_option_value("winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker", { win = id })
|
||||
|
||||
i = i + 1
|
||||
if i > #M.window_picker.chars then
|
||||
if i > #config.g.actions.open_file.window_picker.chars then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
vim.cmd "redraw"
|
||||
vim.cmd("redraw")
|
||||
if vim.opt.cmdheight._value ~= 0 then
|
||||
print "Pick window: "
|
||||
print("Pick window: ")
|
||||
end
|
||||
local _, resp = pcall(get_user_input_char)
|
||||
resp = (resp or ""):upper()
|
||||
@@ -156,12 +139,8 @@ local function pick_win_id()
|
||||
|
||||
-- Restore window options
|
||||
for _, id in ipairs(selectable) do
|
||||
for opt, value in pairs(win_opts[id]) do
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value(opt, value, { win = id })
|
||||
else
|
||||
vim.api.nvim_win_set_option(id, opt, value) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
for opt, value in pairs(win_opts_selectable[id]) do
|
||||
vim.api.nvim_set_option_value(opt, value, { win = id })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -169,20 +148,17 @@ local function pick_win_id()
|
||||
for _, id in ipairs(not_selectable) do
|
||||
-- Ensure window still exists at this point
|
||||
if vim.api.nvim_win_is_valid(id) then
|
||||
for opt, value in pairs(win_opts[id]) do
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value(opt, value, { win = id })
|
||||
else
|
||||
vim.api.nvim_win_set_option(id, opt, value) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
for opt, value in pairs(win_opts_unselectable[id]) do
|
||||
vim.api.nvim_set_option_value(opt, value, { win = id })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.o.laststatus = laststatus
|
||||
vim.opt.fillchars = fillchars
|
||||
|
||||
if not vim.tbl_contains(vim.split(M.window_picker.chars, ""), resp) then
|
||||
if not vim.tbl_contains(vim.split(config.g.actions.open_file.window_picker.chars, ""), resp) then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -190,30 +166,38 @@ local function pick_win_id()
|
||||
end
|
||||
|
||||
local function open_file_in_tab(filename)
|
||||
if M.quit_on_open then
|
||||
if config.g.actions.open_file.quit_on_open then
|
||||
view.close()
|
||||
end
|
||||
if M.relative_path then
|
||||
if config.g.actions.open_file.relative_path then
|
||||
filename = utils.path_relative(filename, vim.fn.getcwd())
|
||||
end
|
||||
vim.cmd("tabe " .. vim.fn.fnameescape(filename))
|
||||
vim.cmd.tabnew()
|
||||
vim.bo.bufhidden = "wipe"
|
||||
-- Following vim.fn.tabnew the # buffer may be set to the tree buffer. There is no way to clear the # buffer via vim.fn.setreg as it requires a valid buffer. Clear # by setting it to a new temporary scratch buffer.
|
||||
if utils.is_nvim_tree_buf(vim.fn.bufnr("#")) then
|
||||
local tmpbuf = vim.api.nvim_create_buf(false, true)
|
||||
vim.fn.setreg("#", tmpbuf)
|
||||
vim.api.nvim_buf_delete(tmpbuf, { force = true })
|
||||
end
|
||||
vim.cmd.edit(vim.fn.fnameescape(filename))
|
||||
end
|
||||
|
||||
local function drop(filename)
|
||||
if M.quit_on_open then
|
||||
if config.g.actions.open_file.quit_on_open then
|
||||
view.close()
|
||||
end
|
||||
if M.relative_path then
|
||||
if config.g.actions.open_file.relative_path then
|
||||
filename = utils.path_relative(filename, vim.fn.getcwd())
|
||||
end
|
||||
vim.cmd("drop " .. vim.fn.fnameescape(filename))
|
||||
end
|
||||
|
||||
local function tab_drop(filename)
|
||||
if M.quit_on_open then
|
||||
if config.g.actions.open_file.quit_on_open then
|
||||
view.close()
|
||||
end
|
||||
if M.relative_path then
|
||||
if config.g.actions.open_file.relative_path then
|
||||
filename = utils.path_relative(filename, vim.fn.getcwd())
|
||||
end
|
||||
vim.cmd("tab :drop " .. vim.fn.fnameescape(filename))
|
||||
@@ -237,17 +221,21 @@ end
|
||||
|
||||
local function get_target_winid(mode)
|
||||
local target_winid
|
||||
if not M.window_picker.enable or mode == "edit_no_picker" or mode == "preview_no_picker" then
|
||||
if not config.g.actions.open_file.window_picker.enable or string.find(mode, "no_picker") then
|
||||
target_winid = lib.target_winid
|
||||
|
||||
-- first available window
|
||||
if not vim.tbl_contains(vim.api.nvim_tabpage_list_wins(0), target_winid) then
|
||||
target_winid = first_win_id()
|
||||
local usable_wins = usable_win_ids()
|
||||
-- first available usable window
|
||||
if not vim.tbl_contains(usable_wins, target_winid) then
|
||||
if #usable_wins > 0 then
|
||||
target_winid = usable_wins[1]
|
||||
else
|
||||
target_winid = -1
|
||||
end
|
||||
end
|
||||
else
|
||||
-- pick a window
|
||||
if type(M.window_picker.picker) == "function" then
|
||||
target_winid = M.window_picker.picker()
|
||||
if type(config.g.actions.open_file.window_picker.picker) == "function" then
|
||||
target_winid = config.g.actions.open_file.window_picker.picker()
|
||||
else
|
||||
target_winid = pick_win_id()
|
||||
end
|
||||
@@ -272,6 +260,8 @@ local function set_current_win_no_autocmd(winid, autocmd)
|
||||
vim.opt.eventignore = eventignore
|
||||
end
|
||||
|
||||
---@param filename string
|
||||
---@param mode NodeOpenFileMode
|
||||
local function open_in_new_window(filename, mode)
|
||||
if type(mode) ~= "string" then
|
||||
mode = ""
|
||||
@@ -282,15 +272,20 @@ local function open_in_new_window(filename, mode)
|
||||
return
|
||||
end
|
||||
|
||||
local position = string.find(mode, "no_picker")
|
||||
if position then
|
||||
mode = string.sub(mode, 0, position - 2)
|
||||
end
|
||||
|
||||
-- non-floating, non-nvim-tree windows
|
||||
local win_ids = vim.tbl_filter(function(id)
|
||||
local config = vim.api.nvim_win_get_config(id)
|
||||
local win_config = vim.api.nvim_win_get_config(id)
|
||||
local bufnr = vim.api.nvim_win_get_buf(id)
|
||||
return config and config.relative == "" or utils.is_nvim_tree_buf(bufnr)
|
||||
return win_config and win_config.relative == "" or utils.is_nvim_tree_buf(bufnr)
|
||||
end, vim.api.nvim_list_wins())
|
||||
|
||||
local create_new_window = #win_ids == 1 -- This implies that the nvim-tree window is the only one
|
||||
local new_window_side = (view.View.side == "right") and "aboveleft" or "belowright"
|
||||
local new_window_side = (config.g.view.side == "right") and "aboveleft" or "belowright"
|
||||
|
||||
-- Target is invalid: create new window
|
||||
if not vim.tbl_contains(win_ids, target_winid) then
|
||||
@@ -300,7 +295,7 @@ local function open_in_new_window(filename, mode)
|
||||
|
||||
-- No need to split, as we created a new window.
|
||||
create_new_window = false
|
||||
if mode:match "split$" then
|
||||
if mode:match("split$") then
|
||||
mode = "edit"
|
||||
end
|
||||
elseif not vim.o.hidden then
|
||||
@@ -308,21 +303,16 @@ local function open_in_new_window(filename, mode)
|
||||
-- modified, and create new split if it is.
|
||||
local target_bufid = vim.api.nvim_win_get_buf(target_winid)
|
||||
|
||||
local modified
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
modified = vim.api.nvim_get_option_value("modified", { buf = target_bufid })
|
||||
else
|
||||
modified = vim.api.nvim_buf_get_option(target_bufid, "modified") ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
local modified = vim.api.nvim_get_option_value("modified", { buf = target_bufid })
|
||||
|
||||
if modified then
|
||||
if not mode:match "split$" then
|
||||
if not mode:match("split$") then
|
||||
mode = "vsplit"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (mode == "preview" or mode == "preview_no_picker") and view.View.float.enable then
|
||||
if (mode == "preview" or mode == "preview_no_picker") and config.g.view.float.enable then
|
||||
-- ignore "WinLeave" autocmd on preview
|
||||
-- because the registered "WinLeave"
|
||||
-- will kill the floating window immediately
|
||||
@@ -332,17 +322,17 @@ local function open_in_new_window(filename, mode)
|
||||
end
|
||||
|
||||
local fname
|
||||
if M.relative_path then
|
||||
fname = vim.fn.fnameescape(utils.path_relative(filename, vim.fn.getcwd()))
|
||||
if config.g.actions.open_file.relative_path then
|
||||
fname = utils.escape_special_chars(vim.fn.fnameescape(utils.path_relative(filename, vim.fn.getcwd())))
|
||||
else
|
||||
fname = vim.fn.fnameescape(filename)
|
||||
fname = utils.escape_special_chars(vim.fn.fnameescape(filename))
|
||||
end
|
||||
|
||||
local command
|
||||
if create_new_window then
|
||||
-- generated from vim.api.nvim_parse_cmd("belowright vsplit foo", {})
|
||||
command = { cmd = "vsplit", mods = { split = new_window_side }, args = { fname } }
|
||||
elseif mode:match "split$" then
|
||||
elseif mode:match("split$") then
|
||||
command = { cmd = mode, args = { fname } }
|
||||
else
|
||||
command = { cmd = "edit", args = { fname } }
|
||||
@@ -363,37 +353,37 @@ end
|
||||
|
||||
local function edit_in_current_buf(filename)
|
||||
require("nvim-tree.view").abandon_current_window()
|
||||
if M.relative_path then
|
||||
if config.g.actions.open_file.relative_path then
|
||||
filename = utils.path_relative(filename, vim.fn.getcwd())
|
||||
end
|
||||
vim.cmd("keepalt keepjumps edit " .. vim.fn.fnameescape(filename))
|
||||
end
|
||||
|
||||
---@param mode string
|
||||
---@param mode NodeOpenFileMode
|
||||
---@param filename string
|
||||
---@return nil
|
||||
function M.fn(mode, filename)
|
||||
local fname = utils.escape_special_chars(filename)
|
||||
if type(mode) ~= "string" then
|
||||
mode = ""
|
||||
end
|
||||
|
||||
if mode == "tabnew" then
|
||||
return open_file_in_tab(fname)
|
||||
return open_file_in_tab(filename)
|
||||
end
|
||||
|
||||
if mode == "drop" then
|
||||
return drop(fname)
|
||||
return drop(filename)
|
||||
end
|
||||
|
||||
if mode == "tab_drop" then
|
||||
return tab_drop(fname)
|
||||
return tab_drop(filename)
|
||||
end
|
||||
|
||||
if mode == "edit_in_place" then
|
||||
return edit_in_current_buf(fname)
|
||||
return edit_in_current_buf(filename)
|
||||
end
|
||||
|
||||
local buf_loaded = is_already_loaded(fname)
|
||||
local buf_loaded = is_already_loaded(filename)
|
||||
|
||||
local found_win = utils.get_win_buf_from_path(filename)
|
||||
if found_win and (mode == "preview" or mode == "preview_no_picker") then
|
||||
@@ -401,13 +391,13 @@ function M.fn(mode, filename)
|
||||
end
|
||||
|
||||
if not found_win then
|
||||
open_in_new_window(fname, mode)
|
||||
open_in_new_window(filename, mode)
|
||||
else
|
||||
vim.api.nvim_set_current_win(found_win)
|
||||
vim.bo.bufhidden = ""
|
||||
end
|
||||
|
||||
if M.resize_window then
|
||||
if config.g.actions.open_file.resize_window then
|
||||
view.resize()
|
||||
end
|
||||
|
||||
@@ -415,19 +405,131 @@ function M.fn(mode, filename)
|
||||
return on_preview(buf_loaded)
|
||||
end
|
||||
|
||||
if M.quit_on_open then
|
||||
if config.g.actions.open_file.quit_on_open then
|
||||
view.close()
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.quit_on_open = opts.actions.open_file.quit_on_open
|
||||
M.resize_window = opts.actions.open_file.resize_window
|
||||
M.relative_path = opts.experimental.actions.open_file.relative_path
|
||||
if opts.actions.open_file.window_picker.chars then
|
||||
opts.actions.open_file.window_picker.chars = tostring(opts.actions.open_file.window_picker.chars):upper()
|
||||
---@param mode string
|
||||
---@param node Node
|
||||
---@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
|
||||
local cur_tabpage = vim.api.nvim_get_current_tabpage()
|
||||
|
||||
M.fn(mode, path)
|
||||
|
||||
edit_opts = edit_opts or {}
|
||||
|
||||
local mode_unsupported_quit_on_open = mode == "drop" or mode == "tab_drop" or mode == "edit_in_place"
|
||||
if not mode_unsupported_quit_on_open and edit_opts.quit_on_open then
|
||||
view.close(cur_tabpage)
|
||||
end
|
||||
M.window_picker = opts.actions.open_file.window_picker
|
||||
|
||||
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 == 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
|
||||
vim.cmd(":tabprev")
|
||||
end
|
||||
view.focus()
|
||||
end
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@param mode NodeOpenFileMode
|
||||
---@param toggle_group boolean?
|
||||
---@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)
|
||||
|
||||
if root or node.name == ".." then
|
||||
local explorer = require("nvim-tree.core").get_explorer()
|
||||
if explorer then
|
||||
explorer:change_dir("..")
|
||||
end
|
||||
elseif dir then
|
||||
dir:expand_or_collapse(toggle_group)
|
||||
elseif not toggle_group then
|
||||
edit(mode, node, edit_opts)
|
||||
end
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.toggle_group_empty(node)
|
||||
open_or_expand_or_dir_up(node, "toggle_group_empty", true)
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
function M.drop(node)
|
||||
open_or_expand_or_dir_up(node, "drop")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.tab_drop(node)
|
||||
open_or_expand_or_dir_up(node, "tab_drop")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.replace_tree_buffer(node)
|
||||
open_or_expand_or_dir_up(node, "edit_in_place")
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
---@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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
@@ -1,56 +1,9 @@
|
||||
local notify = require "nvim-tree.notify"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param node Node
|
||||
local function user(node)
|
||||
if #M.config.system_open.cmd == 0 then
|
||||
require("nvim-tree.utils").notify.warn "Cannot open file with system application. Unrecognized platform."
|
||||
return
|
||||
end
|
||||
|
||||
local process = {
|
||||
cmd = M.config.system_open.cmd,
|
||||
args = M.config.system_open.args,
|
||||
errors = "\n",
|
||||
stderr = vim.loop.new_pipe(false),
|
||||
}
|
||||
table.insert(process.args, node.link_to or node.absolute_path)
|
||||
|
||||
local opts = {
|
||||
args = process.args,
|
||||
stdio = { nil, nil, process.stderr },
|
||||
detached = true,
|
||||
}
|
||||
|
||||
process.handle, process.pid = vim.loop.spawn(process.cmd, opts, function(code)
|
||||
process.stderr:read_stop()
|
||||
process.stderr:close()
|
||||
process.handle:close()
|
||||
if code ~= 0 then
|
||||
notify.warn(string.format("system_open failed with return code %d: %s", code, process.errors))
|
||||
end
|
||||
end)
|
||||
|
||||
table.remove(process.args)
|
||||
if not process.handle then
|
||||
notify.warn(string.format("system_open failed to spawn command '%s': %s", process.cmd, process.pid))
|
||||
return
|
||||
end
|
||||
vim.loop.read_start(process.stderr, function(err, data)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
if data then
|
||||
process.errors = process.errors .. data
|
||||
end
|
||||
end)
|
||||
vim.loop.unref(process.handle)
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
local function native(node)
|
||||
function M.fn(node)
|
||||
local _, err = vim.ui.open(node.link_to or node.absolute_path)
|
||||
|
||||
-- err only provided on opener executable not found hence logging path is not useful
|
||||
@@ -59,33 +12,4 @@ local function native(node)
|
||||
end
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
function M.fn(node)
|
||||
M.open(node)
|
||||
end
|
||||
|
||||
-- TODO always use native once 0.10 is the minimum neovim version
|
||||
function M.setup(opts)
|
||||
M.config = {}
|
||||
M.config.system_open = opts.system_open or {}
|
||||
|
||||
if vim.fn.has "nvim-0.10" == 1 and #M.config.system_open.cmd == 0 then
|
||||
M.open = native
|
||||
else
|
||||
M.open = user
|
||||
if #M.config.system_open.cmd == 0 then
|
||||
if utils.is_windows then
|
||||
M.config.system_open = {
|
||||
cmd = "cmd",
|
||||
args = { "/c", "start", '""' },
|
||||
}
|
||||
elseif utils.is_macos then
|
||||
M.config.system_open.cmd = "open"
|
||||
elseif utils.is_unix then
|
||||
M.config.system_open.cmd = "xdg-open"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {
|
||||
current_tab = vim.api.nvim_get_current_tabpage(),
|
||||
}
|
||||
|
||||
---@param name string
|
||||
---@return string|nil
|
||||
local function clean_input_cwd(name)
|
||||
name = vim.fn.fnameescape(name)
|
||||
local cwd = core.get_cwd()
|
||||
if cwd == nil then
|
||||
return
|
||||
end
|
||||
local root_parent_cwd = vim.fn.fnamemodify(utils.path_remove_trailing(cwd), ":h")
|
||||
if name == ".." and root_parent_cwd then
|
||||
return vim.fn.expand(root_parent_cwd)
|
||||
else
|
||||
return vim.fn.expand(name)
|
||||
end
|
||||
end
|
||||
|
||||
---@param new_tabpage integer
|
||||
---@return boolean
|
||||
local function is_window_event(new_tabpage)
|
||||
local is_event_scope_window = vim.v.event.scope == "window" or vim.v.event.changed_window
|
||||
return is_event_scope_window and new_tabpage == M.current_tab
|
||||
end
|
||||
|
||||
---@param foldername string
|
||||
---@return boolean
|
||||
local function prevent_cwd_change(foldername)
|
||||
local is_same_cwd = foldername == core.get_cwd()
|
||||
local is_restricted_above = M.options.restrict_above_cwd and foldername < vim.fn.getcwd(-1, -1)
|
||||
return is_same_cwd or is_restricted_above
|
||||
end
|
||||
|
||||
---@param input_cwd string
|
||||
---@param with_open boolean|nil
|
||||
function M.fn(input_cwd, with_open)
|
||||
if not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
|
||||
local new_tabpage = vim.api.nvim_get_current_tabpage()
|
||||
if is_window_event(new_tabpage) then
|
||||
return
|
||||
end
|
||||
|
||||
local foldername = clean_input_cwd(input_cwd)
|
||||
if foldername == nil or prevent_cwd_change(foldername) then
|
||||
return
|
||||
end
|
||||
|
||||
M.current_tab = new_tabpage
|
||||
M.force_dirchange(foldername, with_open)
|
||||
end
|
||||
|
||||
---@param global boolean
|
||||
---@param path string
|
||||
local function cd(global, path)
|
||||
vim.cmd((global and "cd " or "lcd ") .. vim.fn.fnameescape(path))
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function should_change_dir()
|
||||
return M.options.enable and vim.tbl_isempty(vim.v.event)
|
||||
end
|
||||
|
||||
---@param f function
|
||||
---@return fun(foldername: string, should_open_view: boolean|nil)
|
||||
local function add_profiling_to(f)
|
||||
return function(foldername, should_open_view)
|
||||
local profile = log.profile_start("change dir %s", foldername)
|
||||
f(foldername, should_open_view)
|
||||
log.profile_end(profile)
|
||||
end
|
||||
end
|
||||
|
||||
M.force_dirchange = add_profiling_to(function(foldername, should_open_view)
|
||||
local valid_dir = vim.fn.isdirectory(foldername) == 1 -- prevent problems on non existing dirs
|
||||
if valid_dir then
|
||||
if should_change_dir() then
|
||||
cd(M.options.global, foldername)
|
||||
end
|
||||
core.init(foldername)
|
||||
end
|
||||
|
||||
if should_open_view then
|
||||
require("nvim-tree.lib").open()
|
||||
else
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function M.setup(options)
|
||||
M.options = options.actions.change_dir
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,22 +0,0 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param node Node
|
||||
function M.fn(node)
|
||||
if not node or node.name == ".." then
|
||||
require("nvim-tree.actions.root.change-dir").fn ".."
|
||||
else
|
||||
local cwd = core.get_cwd()
|
||||
if cwd == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local newdir = vim.fn.fnamemodify(utils.path_remove_trailing(cwd), ":h")
|
||||
require("nvim-tree.actions.root.change-dir").fn(newdir)
|
||||
require("nvim-tree.actions.finders.find-file").fn(node.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,10 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.change_dir = require "nvim-tree.actions.root.change-dir"
|
||||
M.dir_up = require "nvim-tree.actions.root.dir-up"
|
||||
|
||||
function M.setup(opts)
|
||||
M.change_dir.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
19
lua/nvim-tree/actions/tree/change-dir.lua
Normal file
19
lua/nvim-tree/actions/tree/change-dir.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
local core = require("nvim-tree.core")
|
||||
local config = require("nvim-tree.config")
|
||||
local find_file = require("nvim-tree.actions.tree.find-file")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param name? string
|
||||
function M.fn(name)
|
||||
local explorer = core.get_explorer()
|
||||
if name and explorer then
|
||||
explorer:change_dir(name)
|
||||
end
|
||||
|
||||
if config.g.update_focused_file.update_root.enable then
|
||||
find_file.fn()
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
68
lua/nvim-tree/actions/tree/change-root.lua
Normal file
68
lua/nvim-tree/actions/tree/change-root.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
--- Update the tree root to a directory or the directory containing
|
||||
---@param path string relative or absolute
|
||||
---@param bufnr number|nil
|
||||
function M.fn(path, bufnr)
|
||||
-- skip if current file is in ignore_list
|
||||
if type(bufnr) == "number" then
|
||||
local ft = vim.api.nvim_get_option_value("filetype", { buf = bufnr }) or ""
|
||||
|
||||
for _, value in pairs(config.g.update_focused_file.update_root.ignore_list) do
|
||||
if utils.str_find(path, value) or utils.str_find(ft, value) then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- don't find inexistent
|
||||
if vim.fn.filereadable(path) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local cwd = core.get_cwd()
|
||||
if cwd == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local vim_cwd = vim.fn.getcwd()
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
|
||||
-- test if in vim_cwd
|
||||
if utils.path_relative(path, vim_cwd) ~= path then
|
||||
if vim_cwd ~= cwd then
|
||||
explorer:change_dir(vim_cwd)
|
||||
end
|
||||
return
|
||||
end
|
||||
-- test if in cwd
|
||||
if utils.path_relative(path, cwd) ~= path then
|
||||
return
|
||||
end
|
||||
|
||||
-- otherwise test init_root
|
||||
if config.g.prefer_startup_root and utils.path_relative(path, config.init_root) ~= path then
|
||||
explorer:change_dir(config.init_root)
|
||||
return
|
||||
end
|
||||
-- otherwise root_dirs
|
||||
for _, dir in pairs(config.g.root_dirs) do
|
||||
dir = vim.fn.fnamemodify(dir, ":p")
|
||||
if utils.path_relative(path, dir) ~= path then
|
||||
explorer:change_dir(dir)
|
||||
return
|
||||
end
|
||||
end
|
||||
-- finally fall back to the folder containing the file
|
||||
explorer:change_dir(vim.fn.fnamemodify(path, ":p:h"))
|
||||
end
|
||||
|
||||
return M
|
||||
81
lua/nvim-tree/actions/tree/collapse.lua
Normal file
81
lua/nvim-tree/actions/tree/collapse.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
local Iterator = require("nvim-tree.iterators.node-iterator")
|
||||
|
||||
local FileNode = require("nvim-tree.node.file")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@return fun(path: string): boolean
|
||||
local function buf_match()
|
||||
local buffer_paths = vim.tbl_map(function(buffer)
|
||||
return vim.api.nvim_buf_get_name(buffer)
|
||||
end, vim.api.nvim_list_bufs())
|
||||
|
||||
return function(path)
|
||||
for _, buffer_path in ipairs(buffer_paths) do
|
||||
local matches = utils.str_find(buffer_path, path)
|
||||
if matches then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
---Collapse a node, root if nil
|
||||
---@param node? Node
|
||||
---@param opts nvim_tree.api.node.collapse.Opts
|
||||
local function collapse(node, opts)
|
||||
local explorer = core.get_explorer()
|
||||
if not explorer then
|
||||
return
|
||||
end
|
||||
|
||||
node = node or explorer
|
||||
|
||||
local node_at_cursor = explorer:get_node_at_cursor()
|
||||
if not node_at_cursor then
|
||||
return
|
||||
end
|
||||
|
||||
local matches = buf_match()
|
||||
|
||||
Iterator.builder({ node:is(FileNode) and node.parent or node:as(DirectoryNode) })
|
||||
:hidden()
|
||||
:applier(function(n)
|
||||
local dir = n:as(DirectoryNode)
|
||||
if dir then
|
||||
dir.open = opts.keep_buffers == true and matches(dir.absolute_path)
|
||||
end
|
||||
end)
|
||||
:recursor(function(n)
|
||||
return n.group_next and { n.group_next } or n.nodes
|
||||
end)
|
||||
:iterate()
|
||||
|
||||
explorer.renderer:draw()
|
||||
explorer:focus_node_or_parent(node_at_cursor)
|
||||
end
|
||||
|
||||
|
||||
---@param opts? nvim_tree.api.node.collapse.Opts|boolean legacy -> opts.keep_buffers
|
||||
function M.all(opts)
|
||||
-- legacy arguments
|
||||
if type(opts) == "boolean" then
|
||||
opts = {
|
||||
keep_buffers = opts,
|
||||
}
|
||||
end
|
||||
|
||||
collapse(nil, opts or {})
|
||||
end
|
||||
|
||||
---@param node? Node
|
||||
---@param opts? nvim_tree.api.node.collapse.Opts
|
||||
function M.node(node, opts)
|
||||
collapse(node, opts or {})
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,12 +1,14 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local view = require "nvim-tree.view"
|
||||
local finders_find_file = require "nvim-tree.actions.finders.find-file"
|
||||
local core = require("nvim-tree.core")
|
||||
local lib = require("nvim-tree.lib")
|
||||
local view = require("nvim-tree.view")
|
||||
local config = require("nvim-tree.config")
|
||||
local finders_find_file = require("nvim-tree.actions.finders.find-file")
|
||||
local change_root = require("nvim-tree.actions.tree.change-root")
|
||||
|
||||
local M = {}
|
||||
|
||||
--- Find file or buffer
|
||||
---@param opts ApiTreeFindFileOpts|nil|boolean legacy -> opts.buf
|
||||
---@param opts? nvim_tree.api.tree.find_file.Opts|boolean legacy -> opts.buf
|
||||
function M.fn(opts)
|
||||
-- legacy arguments
|
||||
if type(opts) == "string" then
|
||||
@@ -49,23 +51,19 @@ function M.fn(opts)
|
||||
end
|
||||
elseif opts.open then
|
||||
-- open
|
||||
lib.open { current_window = opts.current_window, winid = opts.winid }
|
||||
lib.open({ current_window = opts.current_window, winid = opts.winid })
|
||||
if not opts.focus then
|
||||
vim.cmd "noautocmd wincmd p"
|
||||
vim.cmd("noautocmd wincmd p")
|
||||
end
|
||||
end
|
||||
|
||||
-- update root
|
||||
if opts.update_root or M.config.update_focused_file.update_root.enable then
|
||||
require("nvim-tree").change_root(path, bufnr)
|
||||
if opts.update_root or config.g.update_focused_file.update_root.enable then
|
||||
change_root.fn(path, bufnr)
|
||||
end
|
||||
|
||||
-- find
|
||||
finders_find_file.fn(path)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts or {}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.find_file = require "nvim-tree.actions.tree.find-file"
|
||||
M.modifiers = require "nvim-tree.actions.tree.modifiers"
|
||||
M.open = require "nvim-tree.actions.tree.open"
|
||||
M.toggle = require "nvim-tree.actions.tree.toggle"
|
||||
M.resize = require "nvim-tree.actions.tree.resize"
|
||||
|
||||
function M.setup(opts)
|
||||
M.find_file.setup(opts)
|
||||
M.modifiers.setup(opts)
|
||||
M.open.setup(opts)
|
||||
M.toggle.setup(opts)
|
||||
M.resize.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,52 +0,0 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local Iterator = require "nvim-tree.iterators.node-iterator"
|
||||
|
||||
local M = {}
|
||||
|
||||
---@return fun(path: string): boolean
|
||||
local function buf_match()
|
||||
local buffer_paths = vim.tbl_map(function(buffer)
|
||||
return vim.api.nvim_buf_get_name(buffer)
|
||||
end, vim.api.nvim_list_bufs())
|
||||
|
||||
return function(path)
|
||||
for _, buffer_path in ipairs(buffer_paths) do
|
||||
local matches = utils.str_find(buffer_path, path)
|
||||
if matches then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
---@param keep_buffers boolean
|
||||
function M.fn(keep_buffers)
|
||||
local node = lib.get_node_at_cursor()
|
||||
local explorer = core.get_explorer()
|
||||
|
||||
if explorer == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local matches = buf_match()
|
||||
|
||||
Iterator.builder(explorer.nodes)
|
||||
:hidden()
|
||||
:applier(function(n)
|
||||
if n.nodes ~= nil then
|
||||
n.open = keep_buffers == true and matches(n.absolute_path)
|
||||
end
|
||||
end)
|
||||
:recursor(function(n)
|
||||
return n.group_next and { n.group_next } or n.nodes
|
||||
end)
|
||||
:iterate()
|
||||
|
||||
explorer.renderer:draw()
|
||||
utils.focus_node_or_parent(node)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,82 +0,0 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local Iterator = require "nvim-tree.iterators.node-iterator"
|
||||
local notify = require "nvim-tree.notify"
|
||||
local lib = require "nvim-tree.lib"
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param list string[]
|
||||
---@return table
|
||||
local function to_lookup_table(list)
|
||||
local table = {}
|
||||
for _, element in ipairs(list) do
|
||||
table[element] = true
|
||||
end
|
||||
|
||||
return table
|
||||
end
|
||||
|
||||
---@param node Node
|
||||
local function expand(node)
|
||||
node = lib.get_last_group_node(node)
|
||||
node.open = true
|
||||
if #node.nodes == 0 then
|
||||
core.get_explorer():expand(node)
|
||||
end
|
||||
end
|
||||
|
||||
---@param expansion_count integer
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
local function should_expand(expansion_count, node)
|
||||
local should_halt = expansion_count >= M.MAX_FOLDER_DISCOVERY
|
||||
local should_exclude = M.EXCLUDE[node.name]
|
||||
return not should_halt and node.nodes and not node.open and not should_exclude
|
||||
end
|
||||
|
||||
local function gen_iterator()
|
||||
local expansion_count = 0
|
||||
|
||||
return function(parent)
|
||||
if parent.parent and parent.nodes and not parent.open then
|
||||
expansion_count = expansion_count + 1
|
||||
expand(parent)
|
||||
end
|
||||
|
||||
Iterator.builder(parent.nodes)
|
||||
:hidden()
|
||||
:applier(function(node)
|
||||
if should_expand(expansion_count, node) then
|
||||
expansion_count = expansion_count + 1
|
||||
expand(node)
|
||||
end
|
||||
end)
|
||||
:recursor(function(node)
|
||||
return expansion_count < M.MAX_FOLDER_DISCOVERY and (node.group_next and { node.group_next } or (node.open and node.nodes))
|
||||
end)
|
||||
:iterate()
|
||||
|
||||
if expansion_count >= M.MAX_FOLDER_DISCOVERY then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param base_node table
|
||||
function M.fn(base_node)
|
||||
local explorer = core.get_explorer()
|
||||
local node = base_node.nodes and base_node or explorer
|
||||
if gen_iterator()(node) then
|
||||
notify.warn("expansion iteration was halted after " .. M.MAX_FOLDER_DISCOVERY .. " discovered folders")
|
||||
end
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.MAX_FOLDER_DISCOVERY = opts.actions.expand_all.max_folder_discovery
|
||||
M.EXCLUDE = to_lookup_table(opts.actions.expand_all.exclude)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,11 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
M.collapse_all = require "nvim-tree.actions.tree.modifiers.collapse-all"
|
||||
M.expand_all = require "nvim-tree.actions.tree.modifiers.expand-all"
|
||||
M.toggles = require "nvim-tree.actions.tree.modifiers.toggles"
|
||||
|
||||
function M.setup(opts)
|
||||
M.expand_all.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,72 +0,0 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local M = {}
|
||||
|
||||
---@param explorer Explorer
|
||||
local function reload(explorer)
|
||||
local node = lib.get_node_at_cursor()
|
||||
explorer:reload_explorer()
|
||||
utils.focus_node_or_parent(node)
|
||||
end
|
||||
|
||||
local function wrap_explorer(fn)
|
||||
return function(...)
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
return fn(explorer, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function custom(explorer)
|
||||
explorer.filters.config.filter_custom = not explorer.filters.config.filter_custom
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function git_ignored(explorer)
|
||||
explorer.filters.config.filter_git_ignored = not explorer.filters.config.filter_git_ignored
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function git_clean(explorer)
|
||||
explorer.filters.config.filter_git_clean = not explorer.filters.config.filter_git_clean
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function no_buffer(explorer)
|
||||
explorer.filters.config.filter_no_buffer = not explorer.filters.config.filter_no_buffer
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function no_bookmark(explorer)
|
||||
explorer.filters.config.filter_no_bookmark = not explorer.filters.config.filter_no_bookmark
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function dotfiles(explorer)
|
||||
explorer.filters.config.filter_dotfiles = not explorer.filters.config.filter_dotfiles
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function enable(explorer)
|
||||
explorer.filters.config.enable = not explorer.filters.config.enable
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
M.custom = wrap_explorer(custom)
|
||||
M.git_ignored = wrap_explorer(git_ignored)
|
||||
M.git_clean = wrap_explorer(git_clean)
|
||||
M.no_buffer = wrap_explorer(no_buffer)
|
||||
M.no_bookmark = wrap_explorer(no_bookmark)
|
||||
M.dotfiles = wrap_explorer(dotfiles)
|
||||
M.enable = wrap_explorer(enable)
|
||||
|
||||
return M
|
||||
@@ -1,11 +1,14 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local view = require "nvim-tree.view"
|
||||
local finders_find_file = require "nvim-tree.actions.finders.find-file"
|
||||
local lib = require("nvim-tree.lib")
|
||||
local view = require("nvim-tree.view")
|
||||
local core = require("nvim-tree.core")
|
||||
local config = require("nvim-tree.config")
|
||||
local finders_find_file = require("nvim-tree.actions.finders.find-file")
|
||||
local change_root = require("nvim-tree.actions.tree.change-root")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Open the tree, focusing if already open.
|
||||
---@param opts ApiTreeOpenOpts|nil|string legacy -> opts.path
|
||||
---@param opts? nvim_tree.api.tree.open.Opts|string legacy -> opts.path
|
||||
function M.fn(opts)
|
||||
-- legacy arguments
|
||||
if type(opts) == "string" then
|
||||
@@ -29,18 +32,18 @@ function M.fn(opts)
|
||||
view.focus()
|
||||
else
|
||||
-- open
|
||||
lib.open {
|
||||
lib.open({
|
||||
path = opts.path,
|
||||
current_window = opts.current_window,
|
||||
winid = opts.winid,
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
-- find file
|
||||
if M.config.update_focused_file.enable or opts.find_file then
|
||||
if config.g.update_focused_file.enable or opts.find_file then
|
||||
-- update root
|
||||
if opts.update_root then
|
||||
require("nvim-tree").change_root(previous_path, previous_buf)
|
||||
change_root.fn(previous_path, previous_buf)
|
||||
end
|
||||
|
||||
-- find
|
||||
@@ -48,8 +51,42 @@ function M.fn(opts)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts or {}
|
||||
---@param dirname string absolute directory path
|
||||
function M.open_on_directory(dirname)
|
||||
local should_proceed = config.g.hijack_directories.auto_open or view.is_visible()
|
||||
if not should_proceed then
|
||||
return
|
||||
end
|
||||
|
||||
-- instantiate an explorer if there is not one
|
||||
if not core.get_explorer() then
|
||||
core.init(dirname)
|
||||
end
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer:force_dirchange(dirname, true, false)
|
||||
end
|
||||
end
|
||||
|
||||
function M.tab_enter()
|
||||
if view.is_visible({ any_tabpage = true }) then
|
||||
local bufname = vim.api.nvim_buf_get_name(0)
|
||||
|
||||
local ft = vim.api.nvim_get_option_value("filetype", { buf = 0 }) or ""
|
||||
|
||||
for _, filter in ipairs(config.g.tab.sync.ignore) do
|
||||
if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then
|
||||
return
|
||||
end
|
||||
end
|
||||
view.open({ focus_tree = false })
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
local view = require "nvim-tree.view"
|
||||
local view = require("nvim-tree.view")
|
||||
local view_state = require("nvim-tree.view-state")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Resize the tree, persisting the new size.
|
||||
---@param opts ApiTreeResizeOpts|nil
|
||||
---@param opts? nvim_tree.api.tree.resize.Opts
|
||||
function M.fn(opts)
|
||||
if opts == nil then
|
||||
-- reset to config values
|
||||
view.configure_width()
|
||||
view_state.configure_width()
|
||||
view.resize()
|
||||
return
|
||||
end
|
||||
@@ -16,7 +17,7 @@ function M.fn(opts)
|
||||
local width_cfg = options.width
|
||||
|
||||
if width_cfg ~= nil then
|
||||
view.configure_width(width_cfg)
|
||||
view_state.configure_width(width_cfg)
|
||||
view.resize()
|
||||
return
|
||||
end
|
||||
@@ -44,8 +45,4 @@ function M.fn(opts)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts or {}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local view = require "nvim-tree.view"
|
||||
local finders_find_file = require "nvim-tree.actions.finders.find-file"
|
||||
local lib = require("nvim-tree.lib")
|
||||
local view = require("nvim-tree.view")
|
||||
local config = require("nvim-tree.config")
|
||||
local finders_find_file = require("nvim-tree.actions.finders.find-file")
|
||||
local change_root = require("nvim-tree.actions.tree.change-root")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Toggle the tree.
|
||||
---@param opts ApiTreeToggleOpts|nil|boolean legacy -> opts.find_file
|
||||
---@param no_focus string|nil legacy -> opts.focus
|
||||
---@param cwd boolean|nil legacy -> opts.path
|
||||
---@param bang boolean|nil legacy -> opts.update_root
|
||||
---@param opts? nvim_tree.api.tree.toggle.Opts|boolean legacy -> opts.find_file
|
||||
---@param no_focus? string legacy -> opts.focus
|
||||
---@param cwd? boolean legacy -> opts.path
|
||||
---@param bang? boolean legacy -> opts.update_root
|
||||
function M.fn(opts, no_focus, cwd, bang)
|
||||
-- legacy arguments
|
||||
if type(opts) == "boolean" then
|
||||
@@ -45,17 +47,17 @@ function M.fn(opts, no_focus, cwd, bang)
|
||||
view.close()
|
||||
else
|
||||
-- open
|
||||
lib.open {
|
||||
lib.open({
|
||||
path = opts.path,
|
||||
current_window = opts.current_window,
|
||||
winid = opts.winid,
|
||||
}
|
||||
})
|
||||
|
||||
-- find file
|
||||
if M.config.update_focused_file.enable or opts.find_file then
|
||||
if config.g.update_focused_file.enable or opts.find_file then
|
||||
-- update root
|
||||
if opts.update_root then
|
||||
require("nvim-tree").change_root(previous_path, previous_buf)
|
||||
change_root.fn(previous_path, previous_buf)
|
||||
end
|
||||
|
||||
-- find
|
||||
@@ -64,13 +66,9 @@ function M.fn(opts, no_focus, cwd, bang)
|
||||
|
||||
-- restore focus
|
||||
if not opts.focus then
|
||||
vim.cmd "noautocmd wincmd p"
|
||||
vim.cmd("noautocmd wincmd p")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts or {}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,288 +1,101 @@
|
||||
local lib = require "nvim-tree.lib"
|
||||
local core = require "nvim-tree.core"
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local actions = require "nvim-tree.actions"
|
||||
local appearance_diagnostics = require "nvim-tree.appearance.diagnostics"
|
||||
local events = require "nvim-tree.events"
|
||||
local help = require "nvim-tree.help"
|
||||
local keymap = require "nvim-tree.keymap"
|
||||
local notify = require "nvim-tree.notify"
|
||||
---@brief
|
||||
---nvim-tree exposes a public API. This is non breaking, with additions made as necessary.
|
||||
---
|
||||
---Please do not require or use modules other than `nvim-tree.api`, as internal modules will change without notice.
|
||||
---
|
||||
---The API is separated into multiple modules:
|
||||
---
|
||||
---- [nvim-tree-api-appearance]
|
||||
---- [nvim-tree-api-commands]
|
||||
---- [nvim-tree-api-events]
|
||||
---- [nvim-tree-api-filter]
|
||||
---- [nvim-tree-api-fs]
|
||||
---- [nvim-tree-api-git]
|
||||
---- [nvim-tree-api-map]
|
||||
---- [nvim-tree-api-marks]
|
||||
---- [nvim-tree-api-node]
|
||||
---- [nvim-tree-api-tree]
|
||||
---
|
||||
---Modules are accessed via `api.<module>.<function>`
|
||||
---
|
||||
---Example invocation of the `reload` function in the `tree` module:
|
||||
---```lua
|
||||
---
|
||||
---local api = require("nvim-tree.api")
|
||||
---api.tree.reload()
|
||||
---```
|
||||
---Generally, functions accepting a [nvim_tree.api.Node] as their first argument will use the node under the cursor when that argument is not present or nil. Some functions are mode-dependent: when invoked in visual mode they will operate on all nodes in the visual selection instead of a single node. See |nvim-tree-mappings-default| for which mappings support visual mode.
|
||||
---
|
||||
---e.g. the following are functionally identical:
|
||||
---```lua
|
||||
---
|
||||
---api.node.open.edit(nil, { focus = true })
|
||||
---
|
||||
---api.node.open.edit(api.tree.get_node_under_cursor(), { focus = true })
|
||||
---```
|
||||
|
||||
local Api = {
|
||||
tree = {},
|
||||
node = {
|
||||
navigate = {
|
||||
sibling = {},
|
||||
git = {},
|
||||
diagnostics = {},
|
||||
opened = {},
|
||||
},
|
||||
run = {},
|
||||
open = {},
|
||||
},
|
||||
events = {},
|
||||
marks = {
|
||||
bulk = {},
|
||||
navigate = {},
|
||||
},
|
||||
fs = {
|
||||
copy = {},
|
||||
},
|
||||
git = {},
|
||||
live_filter = {},
|
||||
config = {
|
||||
mappings = {},
|
||||
},
|
||||
commands = {},
|
||||
diagnostics = {},
|
||||
|
||||
|
||||
---The Node class is a data class. Instances may be provided by API functions for use as a:
|
||||
---- handle to pass back to API functions e.g. [nvim_tree.api.node.run.cmd()]
|
||||
---- reference in callbacks e.g. [nvim_tree.config.sort.Sorter] {sorter}
|
||||
---
|
||||
---Please do not mutate the contents of any Node object.
|
||||
---
|
||||
---@class nvim_tree.api.Node
|
||||
---@field absolute_path string of the file or directory
|
||||
---@field name string file or directory name
|
||||
---@field parent? nvim_tree.api.DirectoryNode parent directory, nil for root
|
||||
---@field type "file" | "directory" | "link" [uv.fs_stat()] {type}
|
||||
---@field executable boolean file is executable
|
||||
---@field fs_stat? uv.fs_stat.result at time of last tree display, see [uv.fs_stat()]
|
||||
---@field git_status nvim_tree.git.Status? for files and directories
|
||||
---@field diag_severity? lsp.DiagnosticSeverity diagnostic status
|
||||
---@field hidden boolean node is not visible in the tree
|
||||
|
||||
|
||||
|
||||
---
|
||||
---Git statuses for a single node.
|
||||
---
|
||||
---`nvim_tree.git.XY`: 2 character string, see `man 1 git-status` "Short Format"
|
||||
---@alias nvim_tree.git.XY string
|
||||
---
|
||||
---{dir} status is derived from its contents:
|
||||
---- `direct`: inherited from child files
|
||||
---- `indirect`: inherited from child directories
|
||||
---
|
||||
---@class nvim_tree.git.Status
|
||||
---@field file? nvim_tree.git.XY status of a file node
|
||||
---@field dir? table<"direct" | "indirect", nvim_tree.git.XY[]> direct inclusive-or indirect status
|
||||
|
||||
|
||||
|
||||
---
|
||||
---nvim-tree Public API
|
||||
---
|
||||
---@class nvim_tree.api
|
||||
---@nodoc
|
||||
local api = {
|
||||
appearance = require("nvim-tree._meta.api.appearance"),
|
||||
commands = require("nvim-tree._meta.api.commands"),
|
||||
config = require("nvim-tree._meta.api.config"),
|
||||
events = require("nvim-tree._meta.api.events"),
|
||||
filter = require("nvim-tree._meta.api.filter"),
|
||||
fs = require("nvim-tree._meta.api.fs"),
|
||||
git = require("nvim-tree._meta.api.git"),
|
||||
map = require("nvim-tree._meta.api.map"),
|
||||
marks = require("nvim-tree._meta.api.marks"),
|
||||
node = require("nvim-tree._meta.api.node"),
|
||||
tree = require("nvim-tree._meta.api.tree"),
|
||||
|
||||
Decorator = require("nvim-tree._meta.api.decorator"),
|
||||
|
||||
decorator = require("nvim-tree._meta.api.deprecated").decorator, ---@deprecated
|
||||
diagnostics = require("nvim-tree._meta.api.deprecated").diagnostics, ---@deprecated
|
||||
live_filter = require("nvim-tree._meta.api.deprecated").live_filter, ---@deprecated
|
||||
}
|
||||
|
||||
--- Print error when setup not called.
|
||||
--- f function to invoke
|
||||
---@param f function
|
||||
---@return fun(...) : any
|
||||
local function wrap(f)
|
||||
return function(...)
|
||||
if vim.g.NvimTreeSetup == 1 then
|
||||
return f(...)
|
||||
else
|
||||
notify.error "nvim-tree setup not called"
|
||||
end
|
||||
end
|
||||
end
|
||||
require("nvim-tree.api.impl").hydrate_pre_setup(api)
|
||||
|
||||
---Inject the node as the first argument if present otherwise do nothing.
|
||||
---@param fn function function to invoke
|
||||
local function wrap_node(fn)
|
||||
return function(node, ...)
|
||||
node = node or lib.get_node_at_cursor()
|
||||
if node then
|
||||
return fn(node, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Inject the node or nil as the first argument if absent.
|
||||
---@param fn function function to invoke
|
||||
local function wrap_node_or_nil(fn)
|
||||
return function(node, ...)
|
||||
node = node or lib.get_node_at_cursor()
|
||||
return fn(node, ...)
|
||||
end
|
||||
end
|
||||
|
||||
---Invoke a method on the singleton explorer.
|
||||
---Print error when setup not called.
|
||||
---@param explorer_method string explorer method name
|
||||
---@return fun(...) : any
|
||||
local function wrap_explorer(explorer_method)
|
||||
return wrap(function(...)
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
return explorer[explorer_method](explorer, ...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---Invoke a member's method on the singleton explorer.
|
||||
---Print error when setup not called.
|
||||
---@param explorer_member string explorer member name
|
||||
---@param member_method string method name to invoke on member
|
||||
---@return fun(...) : any
|
||||
local function wrap_explorer_member(explorer_member, member_method)
|
||||
return wrap(function(...)
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
return explorer[explorer_member][member_method](explorer[explorer_member], ...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@class ApiTreeOpenOpts
|
||||
---@field path string|nil path
|
||||
---@field current_window boolean|nil default false
|
||||
---@field winid number|nil
|
||||
---@field find_file boolean|nil default false
|
||||
---@field update_root boolean|nil default false
|
||||
|
||||
Api.tree.open = wrap(actions.tree.open.fn)
|
||||
Api.tree.focus = Api.tree.open
|
||||
|
||||
---@class ApiTreeToggleOpts
|
||||
---@field path string|nil
|
||||
---@field current_window boolean|nil default false
|
||||
---@field winid number|nil
|
||||
---@field find_file boolean|nil default false
|
||||
---@field update_root boolean|nil default false
|
||||
---@field focus boolean|nil default true
|
||||
|
||||
Api.tree.toggle = wrap(actions.tree.toggle.fn)
|
||||
Api.tree.close = wrap(view.close)
|
||||
Api.tree.close_in_this_tab = wrap(view.close_this_tab_only)
|
||||
Api.tree.close_in_all_tabs = wrap(view.close_all_tabs)
|
||||
Api.tree.reload = wrap_explorer "reload_explorer"
|
||||
|
||||
---@class ApiTreeResizeOpts
|
||||
---@field width string|function|number|table|nil
|
||||
---@field absolute number|nil
|
||||
---@field relative number|nil
|
||||
|
||||
Api.tree.resize = wrap(actions.tree.resize.fn)
|
||||
|
||||
Api.tree.change_root = wrap(function(...)
|
||||
require("nvim-tree").change_dir(...)
|
||||
end)
|
||||
|
||||
Api.tree.change_root_to_node = wrap_node(function(node)
|
||||
if node.name == ".." then
|
||||
actions.root.change_dir.fn ".."
|
||||
elseif node.nodes ~= nil then
|
||||
actions.root.change_dir.fn(lib.get_last_group_node(node).absolute_path)
|
||||
end
|
||||
end)
|
||||
|
||||
Api.tree.change_root_to_parent = wrap_node(actions.root.dir_up.fn)
|
||||
Api.tree.get_node_under_cursor = wrap(lib.get_node_at_cursor)
|
||||
Api.tree.get_nodes = wrap(lib.get_nodes)
|
||||
|
||||
---@class ApiTreeFindFileOpts
|
||||
---@field buf string|number|nil
|
||||
---@field open boolean|nil default false
|
||||
---@field current_window boolean|nil default false
|
||||
---@field winid number|nil
|
||||
---@field update_root boolean|nil default false
|
||||
---@field focus boolean|nil default false
|
||||
|
||||
Api.tree.find_file = wrap(actions.tree.find_file.fn)
|
||||
Api.tree.search_node = wrap(actions.finders.search_node.fn)
|
||||
Api.tree.collapse_all = wrap(actions.tree.modifiers.collapse_all.fn)
|
||||
Api.tree.expand_all = wrap_node(actions.tree.modifiers.expand_all.fn)
|
||||
Api.tree.toggle_enable_filters = wrap(actions.tree.modifiers.toggles.enable)
|
||||
Api.tree.toggle_gitignore_filter = wrap(actions.tree.modifiers.toggles.git_ignored)
|
||||
Api.tree.toggle_git_clean_filter = wrap(actions.tree.modifiers.toggles.git_clean)
|
||||
Api.tree.toggle_no_buffer_filter = wrap(actions.tree.modifiers.toggles.no_buffer)
|
||||
Api.tree.toggle_custom_filter = wrap(actions.tree.modifiers.toggles.custom)
|
||||
Api.tree.toggle_hidden_filter = wrap(actions.tree.modifiers.toggles.dotfiles)
|
||||
Api.tree.toggle_no_bookmark_filter = wrap(actions.tree.modifiers.toggles.no_bookmark)
|
||||
Api.tree.toggle_help = wrap(help.toggle)
|
||||
Api.tree.is_tree_buf = wrap(utils.is_nvim_tree_buf)
|
||||
|
||||
---@class ApiTreeIsVisibleOpts
|
||||
---@field tabpage number|nil
|
||||
---@field any_tabpage boolean|nil default false
|
||||
|
||||
Api.tree.is_visible = wrap(view.is_visible)
|
||||
|
||||
---@class ApiTreeWinIdOpts
|
||||
---@field tabpage number|nil default nil
|
||||
|
||||
Api.tree.winid = wrap(view.winid)
|
||||
|
||||
Api.fs.create = wrap_node_or_nil(actions.fs.create_file.fn)
|
||||
Api.fs.remove = wrap_node(actions.fs.remove_file.fn)
|
||||
Api.fs.trash = wrap_node(actions.fs.trash.fn)
|
||||
Api.fs.rename_node = wrap_node(actions.fs.rename_file.fn ":t")
|
||||
Api.fs.rename = wrap_node(actions.fs.rename_file.fn ":t")
|
||||
Api.fs.rename_sub = wrap_node(actions.fs.rename_file.fn ":p:h")
|
||||
Api.fs.rename_basename = wrap_node(actions.fs.rename_file.fn ":t:r")
|
||||
Api.fs.rename_full = wrap_node(actions.fs.rename_file.fn ":p")
|
||||
Api.fs.cut = wrap_node(wrap_explorer_member("clipboard", "cut"))
|
||||
Api.fs.paste = wrap_node(wrap_explorer_member("clipboard", "paste"))
|
||||
Api.fs.clear_clipboard = wrap_explorer_member("clipboard", "clear_clipboard")
|
||||
Api.fs.print_clipboard = wrap_explorer_member("clipboard", "print_clipboard")
|
||||
Api.fs.copy.node = wrap_node(wrap_explorer_member("clipboard", "copy"))
|
||||
Api.fs.copy.absolute_path = wrap_node(wrap_explorer_member("clipboard", "copy_absolute_path"))
|
||||
Api.fs.copy.filename = wrap_node(wrap_explorer_member("clipboard", "copy_filename"))
|
||||
Api.fs.copy.basename = wrap_node(wrap_explorer_member("clipboard", "copy_basename"))
|
||||
Api.fs.copy.relative_path = wrap_node(wrap_explorer_member("clipboard", "copy_path"))
|
||||
|
||||
---@param mode string
|
||||
---@param node table
|
||||
local function edit(mode, node)
|
||||
local path = node.absolute_path
|
||||
if node.link_to and not node.nodes then
|
||||
path = node.link_to
|
||||
end
|
||||
actions.node.open_file.fn(mode, path)
|
||||
end
|
||||
|
||||
---@param mode string
|
||||
---@return fun(node: table)
|
||||
local function open_or_expand_or_dir_up(mode, toggle_group)
|
||||
return function(node)
|
||||
if node.name == ".." then
|
||||
actions.root.change_dir.fn ".."
|
||||
elseif node.nodes then
|
||||
lib.expand_or_collapse(node, toggle_group)
|
||||
elseif not toggle_group then
|
||||
edit(mode, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Api.node.open.edit = wrap_node(open_or_expand_or_dir_up "edit")
|
||||
Api.node.open.drop = wrap_node(open_or_expand_or_dir_up "drop")
|
||||
Api.node.open.tab_drop = wrap_node(open_or_expand_or_dir_up "tab_drop")
|
||||
Api.node.open.replace_tree_buffer = wrap_node(open_or_expand_or_dir_up "edit_in_place")
|
||||
Api.node.open.no_window_picker = wrap_node(open_or_expand_or_dir_up "edit_no_picker")
|
||||
Api.node.open.vertical = wrap_node(open_or_expand_or_dir_up "vsplit")
|
||||
Api.node.open.horizontal = wrap_node(open_or_expand_or_dir_up "split")
|
||||
Api.node.open.tab = wrap_node(open_or_expand_or_dir_up "tabnew")
|
||||
Api.node.open.toggle_group_empty = wrap_node(open_or_expand_or_dir_up("toggle_group_empty", true))
|
||||
Api.node.open.preview = wrap_node(open_or_expand_or_dir_up "preview")
|
||||
Api.node.open.preview_no_picker = wrap_node(open_or_expand_or_dir_up "preview_no_picker")
|
||||
|
||||
Api.node.show_info_popup = wrap_node(actions.node.file_popup.toggle_file_info)
|
||||
Api.node.run.cmd = wrap_node(actions.node.run_command.run_file_command)
|
||||
Api.node.run.system = wrap_node(actions.node.system_open.fn)
|
||||
|
||||
Api.node.navigate.sibling.next = wrap_node(actions.moves.sibling.fn "next")
|
||||
Api.node.navigate.sibling.prev = wrap_node(actions.moves.sibling.fn "prev")
|
||||
Api.node.navigate.sibling.first = wrap_node(actions.moves.sibling.fn "first")
|
||||
Api.node.navigate.sibling.last = wrap_node(actions.moves.sibling.fn "last")
|
||||
Api.node.navigate.parent = wrap_node(actions.moves.parent.fn(false))
|
||||
Api.node.navigate.parent_close = wrap_node(actions.moves.parent.fn(true))
|
||||
Api.node.navigate.git.next = wrap_node(actions.moves.item.fn { where = "next", what = "git" })
|
||||
Api.node.navigate.git.next_skip_gitignored = wrap_node(actions.moves.item.fn { where = "next", what = "git", skip_gitignored = true })
|
||||
Api.node.navigate.git.next_recursive = wrap_node(actions.moves.item.fn { where = "next", what = "git", recurse = true })
|
||||
Api.node.navigate.git.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "git" })
|
||||
Api.node.navigate.git.prev_skip_gitignored = wrap_node(actions.moves.item.fn { where = "prev", what = "git", skip_gitignored = true })
|
||||
Api.node.navigate.git.prev_recursive = wrap_node(actions.moves.item.fn { where = "prev", what = "git", recurse = true })
|
||||
Api.node.navigate.diagnostics.next = wrap_node(actions.moves.item.fn { where = "next", what = "diag" })
|
||||
Api.node.navigate.diagnostics.next_recursive = wrap_node(actions.moves.item.fn { where = "next", what = "diag", recurse = true })
|
||||
Api.node.navigate.diagnostics.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "diag" })
|
||||
Api.node.navigate.diagnostics.prev_recursive = wrap_node(actions.moves.item.fn { where = "prev", what = "diag", recurse = true })
|
||||
Api.node.navigate.opened.next = wrap_node(actions.moves.item.fn { where = "next", what = "opened" })
|
||||
Api.node.navigate.opened.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "opened" })
|
||||
|
||||
Api.git.reload = wrap_explorer "reload_git"
|
||||
|
||||
Api.events.subscribe = events.subscribe
|
||||
Api.events.Event = events.Event
|
||||
|
||||
Api.live_filter.start = wrap_explorer_member("live_filter", "start_filtering")
|
||||
Api.live_filter.clear = wrap_explorer_member("live_filter", "clear_filter")
|
||||
|
||||
Api.marks.get = wrap_node(wrap_explorer_member("marks", "get"))
|
||||
Api.marks.list = wrap_explorer_member("marks", "list")
|
||||
Api.marks.toggle = wrap_node(wrap_explorer_member("marks", "toggle"))
|
||||
Api.marks.clear = wrap_explorer_member("marks", "clear")
|
||||
Api.marks.bulk.delete = wrap_explorer_member("marks", "bulk_delete")
|
||||
Api.marks.bulk.trash = wrap_explorer_member("marks", "bulk_trash")
|
||||
Api.marks.bulk.move = wrap_explorer_member("marks", "bulk_move")
|
||||
Api.marks.navigate.next = wrap_explorer_member("marks", "navigate_next")
|
||||
Api.marks.navigate.prev = wrap_explorer_member("marks", "navigate_prev")
|
||||
Api.marks.navigate.select = wrap_explorer_member("marks", "navigate_select")
|
||||
|
||||
Api.config.mappings.get_keymap = wrap(keymap.get_keymap)
|
||||
Api.config.mappings.get_keymap_default = wrap(keymap.get_keymap_default)
|
||||
Api.config.mappings.default_on_attach = keymap.default_on_attach
|
||||
|
||||
Api.diagnostics.hi_test = wrap(appearance_diagnostics.hi_test)
|
||||
|
||||
Api.commands.get = wrap(function()
|
||||
return require("nvim-tree.commands").get()
|
||||
end)
|
||||
|
||||
return Api
|
||||
return api
|
||||
|
||||
260
lua/nvim-tree/api/impl.lua
Normal file
260
lua/nvim-tree/api/impl.lua
Normal file
@@ -0,0 +1,260 @@
|
||||
---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
|
||||
@@ -1,45 +1,49 @@
|
||||
local appearance = require "nvim-tree.appearance"
|
||||
local appearance = require("nvim-tree.appearance")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
-- others with name and links less than this arbitrary value are short
|
||||
local SHORT_LEN = 50
|
||||
|
||||
local M = {}
|
||||
local namespace_hi_test_id = vim.api.nvim_create_namespace("NvimTreeHiTest")
|
||||
|
||||
---@class HighlightDisplay for :NvimTreeHiTest
|
||||
---For :NvimTreeHiTest
|
||||
---@class (exact) HighlightDisplay: nvim_tree.Class
|
||||
---@field group string nvim-tree highlight group name
|
||||
---@field links string link chain to a concretely defined group
|
||||
---@field def string :hi concrete definition after following any links
|
||||
local HighlightDisplay = {}
|
||||
local HighlightDisplay = Class:extend()
|
||||
|
||||
---@param group string nvim-tree highlight group name
|
||||
---@return HighlightDisplay
|
||||
function HighlightDisplay:new(group)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
---@class HighlightDisplay
|
||||
---@overload fun(args: HighlightDisplayArgs): HighlightDisplay
|
||||
|
||||
o.group = group
|
||||
local concrete = o.group
|
||||
---@class (exact) HighlightDisplayArgs
|
||||
---@field group string nvim-tree highlight group name
|
||||
|
||||
---@protected
|
||||
---@param args HighlightDisplayArgs
|
||||
function HighlightDisplay:new(args)
|
||||
self.group = args.group
|
||||
|
||||
local concrete = self.group
|
||||
|
||||
-- maybe follow links
|
||||
local links = {}
|
||||
local link = vim.api.nvim_get_hl(0, { name = o.group }).link
|
||||
local link = vim.api.nvim_get_hl(0, { name = self.group }).link
|
||||
while link do
|
||||
table.insert(links, link)
|
||||
concrete = link
|
||||
link = vim.api.nvim_get_hl(0, { name = link }).link
|
||||
end
|
||||
o.links = table.concat(links, " ")
|
||||
self.links = table.concat(links, " ")
|
||||
|
||||
-- concrete definition
|
||||
local ok, res = pcall(vim.api.nvim_cmd, { cmd = "highlight", args = { concrete } }, { output = true })
|
||||
if ok and type(res) == "string" then
|
||||
o.def = res:gsub(".*xxx *", "")
|
||||
self.def = res:gsub(".*xxx *", "")
|
||||
else
|
||||
o.def = ""
|
||||
self.def = ""
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Render one group.
|
||||
@@ -51,7 +55,12 @@ function HighlightDisplay:render(bufnr, fmt, l)
|
||||
local text = string.format(fmt, self.group, self.links, self.def)
|
||||
|
||||
vim.api.nvim_buf_set_lines(bufnr, l, -1, true, { text })
|
||||
vim.api.nvim_buf_add_highlight(bufnr, -1, self.group, l, 0, #self.group)
|
||||
|
||||
if vim.fn.has("nvim-0.11") == 1 and vim.hl and vim.hl.range then
|
||||
vim.hl.range(bufnr, namespace_hi_test_id, self.group, { l, 0 }, { l, #self.group, }, {})
|
||||
else
|
||||
vim.api.nvim_buf_add_highlight(bufnr, -1, self.group, l, 0, #self.group) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
|
||||
return l + 1
|
||||
end
|
||||
@@ -87,7 +96,7 @@ end
|
||||
|
||||
---Run a test similar to :so $VIMRUNTIME/syntax/hitest.vim
|
||||
---Display all nvim-tree and neovim highlight groups, their link chain and actual definition
|
||||
function M.hi_test()
|
||||
return function()
|
||||
-- create a buffer
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
|
||||
@@ -96,7 +105,7 @@ function M.hi_test()
|
||||
-- nvim-tree groups, ordered
|
||||
local displays = {}
|
||||
for _, highlight_group in ipairs(appearance.HIGHLIGHT_GROUPS) do
|
||||
local display = HighlightDisplay:new(highlight_group.group)
|
||||
local display = HighlightDisplay({ group = highlight_group.group })
|
||||
table.insert(displays, display)
|
||||
end
|
||||
l = render_displays("nvim-tree", displays, bufnr, l)
|
||||
@@ -110,7 +119,7 @@ function M.hi_test()
|
||||
if ok then
|
||||
for group in string.gmatch(out, "(%w*)%s+xxx") do
|
||||
if group:find("NvimTree", 1, true) ~= 1 then
|
||||
local display = HighlightDisplay:new(group)
|
||||
local display = HighlightDisplay({ group = group })
|
||||
if #display.group + #display.links > SHORT_LEN then
|
||||
table.insert(displays_long, display)
|
||||
else
|
||||
@@ -129,13 +138,7 @@ function M.hi_test()
|
||||
render_displays("other, long", displays_long, bufnr, l)
|
||||
|
||||
-- finalise and focus the buffer
|
||||
if vim.fn.has "nvim-0.10" == 1 then
|
||||
vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr })
|
||||
else
|
||||
vim.api.nvim_buf_set_option(bufnr, "modifiable", false) ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr })
|
||||
|
||||
vim.cmd.buffer(bufnr)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -12,126 +12,126 @@ local M = {}
|
||||
M.HIGHLIGHT_GROUPS = {
|
||||
|
||||
-- Standard
|
||||
{ group = "NvimTreeNormal", link = "Normal" },
|
||||
{ group = "NvimTreeNormalFloat", link = "NormalFloat" },
|
||||
{ group = "NvimTreeNormalFloatBorder", link = "FloatBorder" },
|
||||
{ group = "NvimTreeNormalNC", link = "NvimTreeNormal" },
|
||||
{ group = "NvimTreeNormal", link = "Normal" },
|
||||
{ group = "NvimTreeNormalFloat", link = "NormalFloat" },
|
||||
{ group = "NvimTreeNormalFloatBorder", link = "FloatBorder" },
|
||||
{ group = "NvimTreeNormalNC", link = "NvimTreeNormal" },
|
||||
|
||||
{ group = "NvimTreeLineNr", link = "LineNr" },
|
||||
{ group = "NvimTreeWinSeparator", link = "WinSeparator" },
|
||||
{ group = "NvimTreeEndOfBuffer", link = "EndOfBuffer" },
|
||||
{ group = "NvimTreePopup", link = "Normal" },
|
||||
{ group = "NvimTreeSignColumn", link = "NvimTreeNormal" },
|
||||
{ group = "NvimTreeLineNr", link = "LineNr" },
|
||||
{ group = "NvimTreeWinSeparator", link = "WinSeparator" },
|
||||
{ group = "NvimTreeEndOfBuffer", link = "EndOfBuffer" },
|
||||
{ group = "NvimTreePopup", link = "Normal" },
|
||||
{ group = "NvimTreeSignColumn", link = "NvimTreeNormal" },
|
||||
|
||||
{ group = "NvimTreeCursorColumn", link = "CursorColumn" },
|
||||
{ group = "NvimTreeCursorLine", link = "CursorLine" },
|
||||
{ group = "NvimTreeCursorLineNr", link = "CursorLineNr" },
|
||||
{ group = "NvimTreeCursorColumn", link = "CursorColumn" },
|
||||
{ group = "NvimTreeCursorLine", link = "CursorLine" },
|
||||
{ group = "NvimTreeCursorLineNr", link = "CursorLineNr" },
|
||||
|
||||
{ group = "NvimTreeStatusLine", link = "StatusLine" },
|
||||
{ group = "NvimTreeStatusLineNC", link = "StatusLineNC" },
|
||||
{ group = "NvimTreeStatusLine", link = "StatusLine" },
|
||||
{ group = "NvimTreeStatusLineNC", link = "StatusLineNC" },
|
||||
|
||||
-- File Text
|
||||
{ group = "NvimTreeExecFile", link = "Question" },
|
||||
{ group = "NvimTreeImageFile", link = "Question" },
|
||||
{ group = "NvimTreeSpecialFile", link = "Title" },
|
||||
{ group = "NvimTreeSymlink", link = "Underlined" },
|
||||
{ group = "NvimTreeExecFile", link = "Question" },
|
||||
{ group = "NvimTreeImageFile", link = "Question" },
|
||||
{ group = "NvimTreeSpecialFile", link = "Title" },
|
||||
{ group = "NvimTreeSymlink", link = "Underlined" },
|
||||
|
||||
-- Folder Text
|
||||
{ group = "NvimTreeRootFolder", link = "Title" },
|
||||
{ group = "NvimTreeFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeEmptyFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeOpenedFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeSymlinkFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeRootFolder", link = "Title" },
|
||||
{ group = "NvimTreeFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeEmptyFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeOpenedFolderName", link = "Directory" },
|
||||
{ group = "NvimTreeSymlinkFolderName", link = "Directory" },
|
||||
|
||||
-- File Icons
|
||||
{ group = "NvimTreeFileIcon", link = "NvimTreeNormal" },
|
||||
{ group = "NvimTreeSymlinkIcon", link = "NvimTreeNormal" },
|
||||
{ group = "NvimTreeFileIcon", link = "NvimTreeNormal" },
|
||||
{ group = "NvimTreeSymlinkIcon", link = "NvimTreeNormal" },
|
||||
|
||||
-- Folder Icons
|
||||
{ group = "NvimTreeFolderIcon", def = "guifg=#8094b4 ctermfg=Blue" },
|
||||
{ group = "NvimTreeOpenedFolderIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeClosedFolderIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeFolderArrowClosed", link = "NvimTreeIndentMarker" },
|
||||
{ group = "NvimTreeFolderArrowOpen", link = "NvimTreeIndentMarker" },
|
||||
{ group = "NvimTreeFolderIcon", def = "guifg=#8094b4 ctermfg=Blue" },
|
||||
{ group = "NvimTreeOpenedFolderIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeClosedFolderIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeFolderArrowClosed", link = "NvimTreeIndentMarker" },
|
||||
{ group = "NvimTreeFolderArrowOpen", link = "NvimTreeIndentMarker" },
|
||||
|
||||
-- Indent
|
||||
{ group = "NvimTreeIndentMarker", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeIndentMarker", link = "NvimTreeFolderIcon" },
|
||||
|
||||
-- Picker
|
||||
{ group = "NvimTreeWindowPicker", def = "guifg=#ededed guibg=#4493c8 gui=bold ctermfg=White ctermbg=DarkBlue" },
|
||||
{ group = "NvimTreeWindowPicker", def = "guifg=#ededed guibg=#4493c8 gui=bold ctermfg=White ctermbg=DarkBlue" },
|
||||
|
||||
-- LiveFilter
|
||||
{ group = "NvimTreeLiveFilterPrefix", link = "PreProc" },
|
||||
{ group = "NvimTreeLiveFilterValue", link = "ModeMsg" },
|
||||
{ group = "NvimTreeLiveFilterPrefix", link = "PreProc" },
|
||||
{ group = "NvimTreeLiveFilterValue", link = "ModeMsg" },
|
||||
|
||||
-- Clipboard
|
||||
{ group = "NvimTreeCutHL", link = "SpellBad" },
|
||||
{ group = "NvimTreeCopiedHL", link = "SpellRare" },
|
||||
{ group = "NvimTreeCutHL", link = "SpellBad" },
|
||||
{ group = "NvimTreeCopiedHL", link = "SpellRare" },
|
||||
|
||||
-- Bookmark
|
||||
{ group = "NvimTreeBookmarkIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeBookmarkHL", link = "SpellLocal" },
|
||||
{ group = "NvimTreeBookmarkIcon", link = "NvimTreeFolderIcon" },
|
||||
{ group = "NvimTreeBookmarkHL", link = "SpellLocal" },
|
||||
|
||||
-- Modified
|
||||
{ group = "NvimTreeModifiedIcon", link = "Type" },
|
||||
{ group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" },
|
||||
{ group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" },
|
||||
{ group = "NvimTreeModifiedIcon", link = "Type" },
|
||||
{ group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" },
|
||||
{ group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" },
|
||||
|
||||
-- Hidden
|
||||
{ group = "NvimTreeHiddenIcon", link = "Conceal" },
|
||||
{ group = "NvimTreeHiddenFileHL", link = "NvimTreeHiddenIcon" },
|
||||
{ group = "NvimTreeHiddenFolderHL", link = "NvimTreeHiddenFileHL" },
|
||||
{ group = "NvimTreeHiddenIcon", link = "Conceal" },
|
||||
{ group = "NvimTreeHiddenFileHL", link = "NvimTreeHiddenIcon" },
|
||||
{ group = "NvimTreeHiddenFolderHL", link = "NvimTreeHiddenFileHL" },
|
||||
|
||||
-- Hidden Display
|
||||
{ group = "NvimTreeHiddenDisplay", link = "Conceal" },
|
||||
{ group = "NvimTreeHiddenDisplay", link = "Conceal" },
|
||||
|
||||
-- Opened
|
||||
{ group = "NvimTreeOpenedHL", link = "Special" },
|
||||
{ group = "NvimTreeOpenedHL", link = "Special" },
|
||||
|
||||
-- Git Icon
|
||||
{ group = "NvimTreeGitDeletedIcon", link = "Statement" },
|
||||
{ group = "NvimTreeGitDirtyIcon", link = "Statement" },
|
||||
{ group = "NvimTreeGitIgnoredIcon", link = "Comment" },
|
||||
{ group = "NvimTreeGitMergeIcon", link = "Constant" },
|
||||
{ group = "NvimTreeGitNewIcon", link = "PreProc" },
|
||||
{ group = "NvimTreeGitRenamedIcon", link = "PreProc" },
|
||||
{ group = "NvimTreeGitStagedIcon", link = "Constant" },
|
||||
{ group = "NvimTreeGitDeletedIcon", link = "Statement" },
|
||||
{ group = "NvimTreeGitDirtyIcon", link = "Statement" },
|
||||
{ group = "NvimTreeGitIgnoredIcon", link = "Comment" },
|
||||
{ group = "NvimTreeGitMergeIcon", link = "Constant" },
|
||||
{ group = "NvimTreeGitNewIcon", link = "PreProc" },
|
||||
{ group = "NvimTreeGitRenamedIcon", link = "PreProc" },
|
||||
{ group = "NvimTreeGitStagedIcon", link = "Constant" },
|
||||
|
||||
-- Git File Highlight
|
||||
{ group = "NvimTreeGitFileDeletedHL", link = "NvimTreeGitDeletedIcon" },
|
||||
{ group = "NvimTreeGitFileDirtyHL", link = "NvimTreeGitDirtyIcon" },
|
||||
{ group = "NvimTreeGitFileIgnoredHL", link = "NvimTreeGitIgnoredIcon" },
|
||||
{ group = "NvimTreeGitFileMergeHL", link = "NvimTreeGitMergeIcon" },
|
||||
{ group = "NvimTreeGitFileNewHL", link = "NvimTreeGitNewIcon" },
|
||||
{ group = "NvimTreeGitFileRenamedHL", link = "NvimTreeGitRenamedIcon" },
|
||||
{ group = "NvimTreeGitFileStagedHL", link = "NvimTreeGitStagedIcon" },
|
||||
{ group = "NvimTreeGitFileDeletedHL", link = "NvimTreeGitDeletedIcon" },
|
||||
{ group = "NvimTreeGitFileDirtyHL", link = "NvimTreeGitDirtyIcon" },
|
||||
{ group = "NvimTreeGitFileIgnoredHL", link = "NvimTreeGitIgnoredIcon" },
|
||||
{ group = "NvimTreeGitFileMergeHL", link = "NvimTreeGitMergeIcon" },
|
||||
{ group = "NvimTreeGitFileNewHL", link = "NvimTreeGitNewIcon" },
|
||||
{ group = "NvimTreeGitFileRenamedHL", link = "NvimTreeGitRenamedIcon" },
|
||||
{ group = "NvimTreeGitFileStagedHL", link = "NvimTreeGitStagedIcon" },
|
||||
|
||||
-- Git Folder Highlight
|
||||
{ group = "NvimTreeGitFolderDeletedHL", link = "NvimTreeGitFileDeletedHL" },
|
||||
{ group = "NvimTreeGitFolderDirtyHL", link = "NvimTreeGitFileDirtyHL" },
|
||||
{ group = "NvimTreeGitFolderIgnoredHL", link = "NvimTreeGitFileIgnoredHL" },
|
||||
{ group = "NvimTreeGitFolderMergeHL", link = "NvimTreeGitFileMergeHL" },
|
||||
{ group = "NvimTreeGitFolderNewHL", link = "NvimTreeGitFileNewHL" },
|
||||
{ group = "NvimTreeGitFolderRenamedHL", link = "NvimTreeGitFileRenamedHL" },
|
||||
{ group = "NvimTreeGitFolderStagedHL", link = "NvimTreeGitFileStagedHL" },
|
||||
{ group = "NvimTreeGitFolderDeletedHL", link = "NvimTreeGitFileDeletedHL" },
|
||||
{ group = "NvimTreeGitFolderDirtyHL", link = "NvimTreeGitFileDirtyHL" },
|
||||
{ group = "NvimTreeGitFolderIgnoredHL", link = "NvimTreeGitFileIgnoredHL" },
|
||||
{ group = "NvimTreeGitFolderMergeHL", link = "NvimTreeGitFileMergeHL" },
|
||||
{ group = "NvimTreeGitFolderNewHL", link = "NvimTreeGitFileNewHL" },
|
||||
{ group = "NvimTreeGitFolderRenamedHL", link = "NvimTreeGitFileRenamedHL" },
|
||||
{ group = "NvimTreeGitFolderStagedHL", link = "NvimTreeGitFileStagedHL" },
|
||||
|
||||
-- Diagnostics Icon
|
||||
{ group = "NvimTreeDiagnosticErrorIcon", link = "DiagnosticError" },
|
||||
{ group = "NvimTreeDiagnosticWarnIcon", link = "DiagnosticWarn" },
|
||||
{ group = "NvimTreeDiagnosticInfoIcon", link = "DiagnosticInfo" },
|
||||
{ group = "NvimTreeDiagnosticHintIcon", link = "DiagnosticHint" },
|
||||
{ group = "NvimTreeDiagnosticErrorIcon", link = "DiagnosticError" },
|
||||
{ group = "NvimTreeDiagnosticWarnIcon", link = "DiagnosticWarn" },
|
||||
{ group = "NvimTreeDiagnosticInfoIcon", link = "DiagnosticInfo" },
|
||||
{ group = "NvimTreeDiagnosticHintIcon", link = "DiagnosticHint" },
|
||||
|
||||
-- Diagnostics File Highlight
|
||||
{ group = "NvimTreeDiagnosticErrorFileHL", link = "DiagnosticUnderlineError" },
|
||||
{ group = "NvimTreeDiagnosticWarnFileHL", link = "DiagnosticUnderlineWarn" },
|
||||
{ group = "NvimTreeDiagnosticInfoFileHL", link = "DiagnosticUnderlineInfo" },
|
||||
{ group = "NvimTreeDiagnosticHintFileHL", link = "DiagnosticUnderlineHint" },
|
||||
{ group = "NvimTreeDiagnosticErrorFileHL", link = "DiagnosticUnderlineError" },
|
||||
{ group = "NvimTreeDiagnosticWarnFileHL", link = "DiagnosticUnderlineWarn" },
|
||||
{ group = "NvimTreeDiagnosticInfoFileHL", link = "DiagnosticUnderlineInfo" },
|
||||
{ group = "NvimTreeDiagnosticHintFileHL", link = "DiagnosticUnderlineHint" },
|
||||
|
||||
-- Diagnostics Folder Highlight
|
||||
{ group = "NvimTreeDiagnosticErrorFolderHL", link = "NvimTreeDiagnosticErrorFileHL" },
|
||||
{ group = "NvimTreeDiagnosticWarnFolderHL", link = "NvimTreeDiagnosticWarnFileHL" },
|
||||
{ group = "NvimTreeDiagnosticInfoFolderHL", link = "NvimTreeDiagnosticInfoFileHL" },
|
||||
{ group = "NvimTreeDiagnosticHintFolderHL", link = "NvimTreeDiagnosticHintFileHL" },
|
||||
{ group = "NvimTreeDiagnosticWarnFolderHL", link = "NvimTreeDiagnosticWarnFileHL" },
|
||||
{ group = "NvimTreeDiagnosticInfoFolderHL", link = "NvimTreeDiagnosticInfoFileHL" },
|
||||
{ group = "NvimTreeDiagnosticHintFolderHL", link = "NvimTreeDiagnosticHintFileHL" },
|
||||
}
|
||||
|
||||
-- nvim-tree highlight groups to legacy
|
||||
@@ -182,7 +182,8 @@ M.LEGACY_LINKS = {
|
||||
NvimTreeDiagnosticHintFolderHL = "NvimTreeLspDiagnosticsHintFolderText",
|
||||
}
|
||||
|
||||
function M.setup()
|
||||
---Create all highlight groups and links. Idempotent.
|
||||
function M.highlight()
|
||||
-- non-linked
|
||||
for _, g in ipairs(M.HIGHLIGHT_GROUPS) do
|
||||
if g.def then
|
||||
|
||||
213
lua/nvim-tree/autocmd.lua
Normal file
213
lua/nvim-tree/autocmd.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Create all global autocommands after setup.
|
||||
---Idempotent: removes existing autocommands first.
|
||||
---For startup performance reasons, all requires must be done inline during the callback.
|
||||
---Some short circuiting logic is done directly inside the callback to prevent unnecessary requires.
|
||||
function M.global()
|
||||
local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true })
|
||||
|
||||
vim.api.nvim_create_autocmd("BufWipeout", {
|
||||
group = augroup_id,
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
require("nvim-tree.view").wipeout()
|
||||
end,
|
||||
})
|
||||
|
||||
if vim.fn.has("nvim-0.13") == 1 and config.g.experimental.session_restore_nvim then
|
||||
vim.api.nvim_create_autocmd("SessionWritePre", { ---@diagnostic disable-line: param-type-mismatch
|
||||
group = augroup_id,
|
||||
callback = function()
|
||||
-- We must schedule to wait until `vim.v.this_session` is properly updated
|
||||
-- This prevents overwriting the data if a new session is created with a new `:mksession`
|
||||
vim.schedule(require("nvim-tree.session").save)
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("SessionLoadPost", {
|
||||
group = augroup_id,
|
||||
-- Workaround: this event fires multiple times (report upstream),
|
||||
-- failure notifications could show up many times.
|
||||
once = true,
|
||||
callback = function()
|
||||
require("nvim-tree.session").restore()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
if config.g.tab.sync.open then
|
||||
vim.api.nvim_create_autocmd("TabEnter", {
|
||||
group = augroup_id,
|
||||
callback = vim.schedule_wrap(function()
|
||||
require("nvim-tree.actions.tree.open").tab_enter()
|
||||
end)
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.sync_root_with_cwd then
|
||||
vim.api.nvim_create_autocmd("DirChanged", {
|
||||
group = augroup_id,
|
||||
callback = function()
|
||||
require("nvim-tree.actions.tree.change-dir").fn(vim.uv.cwd())
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.update_focused_file.enable then
|
||||
vim.api.nvim_create_autocmd("BufEnter", {
|
||||
group = augroup_id,
|
||||
callback = function(event)
|
||||
if type(config.g.update_focused_file.exclude) == "function" and config.g.update_focused_file.exclude(event) then
|
||||
return
|
||||
end
|
||||
require("nvim-tree.utils").debounce("BufEnter:find_file", config.g.view.debounce_delay, function()
|
||||
require("nvim-tree.actions.tree.find-file").fn()
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.hijack_directories.enable and (config.g.disable_netrw or config.g.hijack_netrw) then
|
||||
vim.api.nvim_create_autocmd({ "BufEnter", "BufNewFile" }, {
|
||||
group = augroup_id,
|
||||
nested = true,
|
||||
callback = function(data)
|
||||
local bufname = vim.api.nvim_buf_get_name(data.buf)
|
||||
if vim.fn.isdirectory(bufname) == 1 then
|
||||
require("nvim-tree.actions.tree.open").open_on_directory(bufname)
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.view.centralize_selection then
|
||||
vim.api.nvim_create_autocmd("BufEnter", {
|
||||
group = augroup_id,
|
||||
pattern = "NvimTree_*",
|
||||
callback = vim.schedule_wrap(function()
|
||||
vim.api.nvim_buf_call(0, function()
|
||||
local is_term_mode = vim.api.nvim_get_mode().mode == "t"
|
||||
if is_term_mode then
|
||||
return
|
||||
end
|
||||
vim.cmd([[norm! zz]])
|
||||
end)
|
||||
end)
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.diagnostics.enable then
|
||||
vim.api.nvim_create_autocmd("DiagnosticChanged", {
|
||||
group = augroup_id,
|
||||
callback = function(ev)
|
||||
require("nvim-tree.diagnostics").update_lsp(ev)
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("User", {
|
||||
group = augroup_id,
|
||||
pattern = "CocDiagnosticChange",
|
||||
callback = function()
|
||||
require("nvim-tree.diagnostics").update_coc()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
if config.g.view.float.enable and config.g.view.float.quit_on_focus_loss then
|
||||
vim.api.nvim_create_autocmd("WinLeave", {
|
||||
group = augroup_id,
|
||||
pattern = "NvimTree_*",
|
||||
callback = function()
|
||||
if require("nvim-tree.utils").is_nvim_tree_buf(0) then
|
||||
require("nvim-tree.view").close()
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- Handles event dispatch when tree is closed by `:q`
|
||||
vim.api.nvim_create_autocmd("WinClosed", {
|
||||
group = augroup_id,
|
||||
pattern = "*",
|
||||
---@param ev vim.api.keyset.create_autocmd.callback_args
|
||||
callback = function(ev)
|
||||
if not vim.api.nvim_buf_is_valid(ev.buf) then
|
||||
return
|
||||
end
|
||||
if vim.api.nvim_get_option_value("filetype", { buf = ev.buf }) == "NvimTree" then
|
||||
require("nvim-tree.events")._dispatch_on_tree_close()
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
if config.g.renderer.full_name then
|
||||
local group = vim.api.nvim_create_augroup("nvim_tree_floating_node", { clear = true })
|
||||
vim.api.nvim_create_autocmd({ "BufLeave", "CursorMoved" }, {
|
||||
group = group,
|
||||
pattern = { "NvimTree_*" },
|
||||
callback = function()
|
||||
require("nvim-tree.renderer.components.full-name").hide()
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd({ "CursorMoved" }, {
|
||||
group = group,
|
||||
pattern = { "NvimTree_*" },
|
||||
callback = function()
|
||||
require("nvim-tree.renderer.components.full-name").show()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("CmdlineLeave", {
|
||||
group = augroup_id,
|
||||
pattern = ":",
|
||||
callback = function(ev)
|
||||
if require("nvim-tree.view").get_bufnr() == ev.buf then
|
||||
local cmd = vim.fn.getcmdline()
|
||||
|
||||
if cmd:match("s([^%w])") then
|
||||
local delimiter = cmd:match("s([^%w])")
|
||||
local escaped_delim = delimiter:gsub("[%%%.%+%-%*%?%^%$%(%)%[%]]", "%%%1")
|
||||
|
||||
-- Looks for: s <delimiter> <old> <delimiter> <new> <delimiter or end>
|
||||
local pattern = "s" .. escaped_delim .. "([^" .. escaped_delim .. "]*)" .. escaped_delim .. "([^" .. escaped_delim .. "]*)"
|
||||
|
||||
local old_part, new_part = cmd:match(pattern)
|
||||
|
||||
local core = require("nvim-tree.core")
|
||||
local explorer = core.get_explorer()
|
||||
local utils = require("nvim-tree.utils")
|
||||
local bulk_rename = require("nvim-tree.actions.fs.rename-file").bulk_rename
|
||||
|
||||
local visual_marker = "'<,'>"
|
||||
local nodes = cmd:sub(1, #visual_marker) == visual_marker and
|
||||
utils.get_visual_nodes({ use_native = true, should_exit = false }) or
|
||||
explorer and explorer:get_nodes_by_line(core.get_nodes_starting_line()) or {}
|
||||
local matching_nodes = {}
|
||||
|
||||
for i = #nodes, 1, -1 do
|
||||
local node = nodes[i]
|
||||
if node and node.name:find(old_part) ~= nil then
|
||||
table.insert(matching_nodes, node)
|
||||
end
|
||||
end
|
||||
|
||||
if #matching_nodes > 0 then
|
||||
bulk_rename(matching_nodes, old_part, new_part)
|
||||
else
|
||||
require("nvim-tree.notify").notify(string.format("Not matching nodes with '%s'", old_part))
|
||||
end
|
||||
|
||||
vim.fn.setcmdline("")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,3 +1,7 @@
|
||||
local config = require("nvim-tree.config")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@type table<string, boolean> record of which file is modified
|
||||
@@ -6,16 +10,14 @@ M._modified = {}
|
||||
---refresh M._modified
|
||||
function M.reload_modified()
|
||||
M._modified = {}
|
||||
local bufs = vim.fn.getbufinfo { bufmodified = 1, buflisted = 1 }
|
||||
local bufs = vim.fn.getbufinfo({ bufmodified = 1, buflisted = 1 })
|
||||
for _, buf in pairs(bufs) do
|
||||
local path = buf.name
|
||||
if path ~= "" then -- not a [No Name] buffer
|
||||
-- mark all the parent as modified as well
|
||||
while
|
||||
M._modified[path] ~= true
|
||||
while M._modified[path] ~= true do
|
||||
-- no need to keep going if already recorded
|
||||
-- This also prevents an infinite loop
|
||||
do
|
||||
M._modified[path] = true
|
||||
path = vim.fn.fnamemodify(path, ":h")
|
||||
end
|
||||
@@ -23,28 +25,36 @@ function M.reload_modified()
|
||||
end
|
||||
end
|
||||
|
||||
---@param node table
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
function M.is_modified(node)
|
||||
return node
|
||||
and M.config.modified.enable
|
||||
and M._modified[node.absolute_path]
|
||||
and (not node.nodes or M.config.modified.show_on_dirs)
|
||||
and (not node.open or M.config.modified.show_on_open_dirs)
|
||||
if not config.g.modified.enable then
|
||||
return false
|
||||
end
|
||||
|
||||
if not M._modified[node.absolute_path] then
|
||||
return false
|
||||
end
|
||||
|
||||
local dir = node:as(DirectoryNode)
|
||||
if dir then
|
||||
if not config.g.modified.show_on_dirs then
|
||||
return false
|
||||
end
|
||||
|
||||
if dir.open and not config.g.modified.show_on_open_dirs then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---A buffer exists for the node's absolute path
|
||||
---@param node table
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
function M.is_opened(node)
|
||||
return node and vim.fn.bufloaded(node.absolute_path) > 0
|
||||
end
|
||||
|
||||
---@param opts table
|
||||
function M.setup(opts)
|
||||
M.config = {
|
||||
modified = opts.modified,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
197
lua/nvim-tree/classic.lua
Normal file
197
lua/nvim-tree/classic.lua
Normal file
@@ -0,0 +1,197 @@
|
||||
--
|
||||
-- classic
|
||||
--
|
||||
-- Copyright (c) 2014, rxi
|
||||
--
|
||||
-- This module is free software; you can redistribute it and/or modify it under
|
||||
-- the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
-- https://github.com/rxi/classic
|
||||
--
|
||||
|
||||
|
||||
---@brief
|
||||
---
|
||||
---nvim-tree uses the https://github.com/rxi/classic class framework adding safe casts, instanceof mixin and conventional destructors.
|
||||
---
|
||||
---The key differences between classic and ordinary Lua classes:
|
||||
---- The constructor [nvim_tree.Class:new()] is not responsible for allocation: `self` is available when the constructor is called.
|
||||
---- Instances are constructed via the `__call` meta method: `SomeClass(args)`
|
||||
---
|
||||
---Classes are conventionally named using camel case e.g. `MyClass`
|
||||
---
|
||||
---Classes are created by extending another class:
|
||||
---```lua
|
||||
---
|
||||
--- local Class = require("nvim-tree.classic")
|
||||
---
|
||||
--- ---@class (exact) Fruit: nvim_tree.Class
|
||||
--- ---@field ...
|
||||
--- local Fruit = Class:extend()
|
||||
---
|
||||
--- ---@class (exact) Apple: Fruit
|
||||
--- ---@field ...
|
||||
--- local Apple = Fruit:extend()
|
||||
---```
|
||||
---
|
||||
---Implementing a constructor [nvim_tree.Class:new()] is optional, however it must call the `super` constructor:
|
||||
---```lua
|
||||
---
|
||||
--- ---@protected
|
||||
--- ---@param args AppleArgs
|
||||
--- function Apple:new(args)
|
||||
---
|
||||
--- ---@type FruitArgs
|
||||
--- local fruit_args = ...
|
||||
---
|
||||
--- Apple.super.new(self, fruit_args)
|
||||
--- ---
|
||||
---```
|
||||
---
|
||||
---Create an instance of a class using the `__call` meta method that will invoke the constructor:
|
||||
---```lua
|
||||
---
|
||||
--- ---@type AppleArgs
|
||||
--- local args = ...
|
||||
---
|
||||
--- local an_apple = Apple(args)
|
||||
--- -- above will call `Apple:new(args)`
|
||||
---```
|
||||
---
|
||||
---In order to strongly type instantiation, the following pattern is used to type the meta method `__call` with arguments and return:
|
||||
---```lua
|
||||
---
|
||||
--- ---@class (exact) Fruit: nvim_tree.Class
|
||||
--- ---@field ...
|
||||
--- local Fruit = Class:extend()
|
||||
---
|
||||
--- ---@class (exact) FruitArgs
|
||||
--- ---@field ...
|
||||
---
|
||||
--- ---@class Fruit
|
||||
--- ---@overload fun(args: FruitArgs): Fruit
|
||||
---
|
||||
--- ---@protected
|
||||
--- ---@param args FruitArgs
|
||||
--- function Fruit:new(args)
|
||||
---```
|
||||
|
||||
---
|
||||
---@class nvim_tree.Class
|
||||
---
|
||||
---Parent class, `Class` for base classes.
|
||||
---@field super nvim_tree.Class
|
||||
---
|
||||
---mixin classes that are implemented.
|
||||
---@field private implements table<nvim_tree.Class, boolean>
|
||||
local Class = {}
|
||||
Class.__index = Class ---@diagnostic disable-line: inject-field
|
||||
|
||||
---
|
||||
---Constructor: `self` has been allocated and is available.
|
||||
---
|
||||
---Super constructor must be called using the form `Child.super.new(self, parent_args)`
|
||||
---
|
||||
---@param ... any constructor arguments
|
||||
function Class:new(...) --luacheck: ignore 212
|
||||
end
|
||||
|
||||
---
|
||||
---Conventional destructor, optional, must be called by the owner.
|
||||
---
|
||||
---Parent destructor must be invoked using the form `Parent.destroy(self)`
|
||||
---
|
||||
function Class:destroy()
|
||||
end
|
||||
|
||||
---
|
||||
---Create a new class by extending another class.
|
||||
---
|
||||
---Base classes extend `Class`
|
||||
---
|
||||
---@return [nvim_tree.Class] child class
|
||||
function Class:extend()
|
||||
local cls = {}
|
||||
for k, v in pairs(self) do
|
||||
if k:find("__") == 1 then
|
||||
cls[k] = v
|
||||
end
|
||||
end
|
||||
cls.__index = cls
|
||||
cls.super = self
|
||||
setmetatable(cls, self)
|
||||
return cls
|
||||
end
|
||||
|
||||
---
|
||||
---Add the methods and fields of a mixin using the form `SomeClass:implement(MixinClass)`
|
||||
---
|
||||
---If the mixin has fields, it must implement a constructor.
|
||||
---
|
||||
---@param mixin nvim_tree.Class
|
||||
function Class:implement(mixin)
|
||||
if not rawget(self, "implements") then
|
||||
-- set on the class itself instead of parents
|
||||
rawset(self, "implements", {})
|
||||
end
|
||||
self.implements[mixin] = true
|
||||
for k, v in pairs(mixin) do
|
||||
if self[k] == nil and type(v) == "function" then
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
---Instance of.
|
||||
---
|
||||
---Test whether an object is {class}, inherits {class} or implements mixin {class}.
|
||||
---
|
||||
---@generic T
|
||||
---@param class T `<T>`
|
||||
---@return boolean
|
||||
function Class:is(class)
|
||||
local mt = getmetatable(self)
|
||||
while mt do
|
||||
if mt == class then
|
||||
return true
|
||||
end
|
||||
if mt.implements and mt.implements[class] then
|
||||
return true
|
||||
end
|
||||
mt = getmetatable(mt)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---
|
||||
---Type safe cast.
|
||||
---
|
||||
---If instance [nvim_tree.Class:is()], cast to {class} and return it, otherwise nil.
|
||||
---
|
||||
---@generic T
|
||||
---@param class T `<T>`
|
||||
---@return T? `<T>`
|
||||
function Class:as(class)
|
||||
return self:is(class) and self or nil
|
||||
end
|
||||
|
||||
---
|
||||
---Constructs an instance: calls [nvim_tree.Class:new()] and returns the new instance.
|
||||
---
|
||||
---@param ... any constructor args
|
||||
---@return nvim_tree.Class
|
||||
function Class:__call(...)
|
||||
local obj = setmetatable({}, self)
|
||||
obj:new(...)
|
||||
return obj
|
||||
end
|
||||
|
||||
---
|
||||
---Utility method to bypass unused param warnings in abstract methods.
|
||||
---
|
||||
---@param ... any
|
||||
function Class:nop(...) --luacheck: ignore 212
|
||||
end
|
||||
|
||||
return Class
|
||||
@@ -1,8 +1,6 @@
|
||||
local api = require "nvim-tree.api"
|
||||
local view = require "nvim-tree.view"
|
||||
|
||||
local M = {}
|
||||
|
||||
---@type nvim_tree.api.commands.Command[]
|
||||
local CMDS = {
|
||||
{
|
||||
name = "NvimTreeOpen",
|
||||
@@ -12,7 +10,7 @@ local CMDS = {
|
||||
complete = "dir",
|
||||
},
|
||||
command = function(c)
|
||||
api.tree.open { path = c.args }
|
||||
require("nvim-tree.api").tree.open({ path = c.args })
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -22,7 +20,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.tree.close()
|
||||
require("nvim-tree.api").tree.close()
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -33,12 +31,12 @@ local CMDS = {
|
||||
complete = "dir",
|
||||
},
|
||||
command = function(c)
|
||||
api.tree.toggle {
|
||||
require("nvim-tree.api").tree.toggle({
|
||||
find_file = false,
|
||||
focus = true,
|
||||
path = c.args,
|
||||
update_root = false,
|
||||
}
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -48,7 +46,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.tree.open()
|
||||
require("nvim-tree.api").tree.open()
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -58,7 +56,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.tree.reload()
|
||||
require("nvim-tree.api").tree.reload()
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -68,7 +66,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.fs.print_clipboard()
|
||||
require("nvim-tree.api").fs.print_clipboard()
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -79,11 +77,11 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function(c)
|
||||
api.tree.find_file {
|
||||
require("nvim-tree.api").tree.find_file({
|
||||
open = true,
|
||||
focus = true,
|
||||
update_root = c.bang,
|
||||
}
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -95,12 +93,12 @@ local CMDS = {
|
||||
complete = "dir",
|
||||
},
|
||||
command = function(c)
|
||||
api.tree.toggle {
|
||||
require("nvim-tree.api").tree.toggle({
|
||||
find_file = true,
|
||||
focus = true,
|
||||
path = c.args,
|
||||
update_root = c.bang,
|
||||
}
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -111,7 +109,12 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function(c)
|
||||
view.resize(c.args)
|
||||
local sign = c.args:sub(1, 1)
|
||||
if sign == "+" or sign == "-" then
|
||||
require("nvim-tree.api").tree.resize({ relative = tonumber(c.args) })
|
||||
else
|
||||
require("nvim-tree.api").tree.resize({ absolute = tonumber(c.args) })
|
||||
end
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -121,7 +124,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.tree.collapse_all(false)
|
||||
require("nvim-tree.api").tree.collapse_all({ keep_buffers = false })
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -131,7 +134,7 @@ local CMDS = {
|
||||
bar = true,
|
||||
},
|
||||
command = function()
|
||||
api.tree.collapse_all(true)
|
||||
require("nvim-tree.api").tree.collapse_all({ keep_buffers = true })
|
||||
end,
|
||||
},
|
||||
{
|
||||
@@ -139,10 +142,13 @@ local CMDS = {
|
||||
opts = {
|
||||
desc = "nvim-tree: highlight test",
|
||||
},
|
||||
command = api.diagnostics.hi_test,
|
||||
command = function()
|
||||
require("nvim-tree.api").appearance.hi_test()
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
---@return nvim_tree.api.commands.Command[]
|
||||
function M.get()
|
||||
return vim.deepcopy(CMDS)
|
||||
end
|
||||
|
||||
600
lua/nvim-tree/config.lua
Normal file
600
lua/nvim-tree/config.lua
Normal file
@@ -0,0 +1,600 @@
|
||||
--This will be required after api, before setup.
|
||||
--This file should have minimal requires that are cheap and have no dependencies or are already required.
|
||||
|
||||
--Short names like g are used rather than getters to keep code brief
|
||||
local M = {
|
||||
---Immutable default config
|
||||
---@type nvim_tree.config
|
||||
d = {},
|
||||
|
||||
---Global current config, nil until setup called, mutable
|
||||
---@type nvim_tree.config?
|
||||
g = nil,
|
||||
|
||||
---Immutable raw user config, nil when no user config passed to setup
|
||||
---@type nvim_tree.config?
|
||||
u = nil,
|
||||
|
||||
---Immutable OS, detected once on first require
|
||||
---@type table<"unix"|"macos"|"wsl"|"windows", boolean>
|
||||
os = nil,
|
||||
|
||||
---Nvim cwd at setup time
|
||||
---@type string
|
||||
init_root = "",
|
||||
}
|
||||
|
||||
M.os = {
|
||||
unix = vim.fn.has("unix") == 1,
|
||||
macos = vim.fn.has("mac") == 1 or vim.fn.has("macunix") == 1,
|
||||
wsl = vim.fn.has("wsl") == 1,
|
||||
-- false for WSL
|
||||
windows = vim.fn.has("win32") == 1 or vim.fn.has("win32unix") == 1,
|
||||
}
|
||||
|
||||
M.d = { -- config-default-start
|
||||
on_attach = "default",
|
||||
hijack_cursor = false,
|
||||
auto_reload_on_write = true,
|
||||
disable_netrw = false,
|
||||
hijack_netrw = true,
|
||||
hijack_unnamed_buffer_when_opening = false,
|
||||
root_dirs = {},
|
||||
prefer_startup_root = false,
|
||||
sync_root_with_cwd = false,
|
||||
reload_on_bufenter = false,
|
||||
respect_buf_cwd = false,
|
||||
select_prompts = false,
|
||||
sort = {
|
||||
sorter = "name",
|
||||
folders_first = true,
|
||||
files_first = false,
|
||||
},
|
||||
view = {
|
||||
centralize_selection = false,
|
||||
cursorline = true,
|
||||
cursorlineopt = "both",
|
||||
debounce_delay = 15,
|
||||
side = "left",
|
||||
preserve_window_proportions = false,
|
||||
number = false,
|
||||
relativenumber = false,
|
||||
signcolumn = "yes",
|
||||
width = 30,
|
||||
float = {
|
||||
enable = false,
|
||||
quit_on_focus_loss = true,
|
||||
open_win_config = {
|
||||
relative = "editor",
|
||||
border = "rounded",
|
||||
width = 30,
|
||||
height = 30,
|
||||
row = 1,
|
||||
col = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
add_trailing = false,
|
||||
group_empty = false,
|
||||
full_name = false,
|
||||
root_folder_label = ":~:s?$?/..?",
|
||||
indent_width = 2,
|
||||
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
|
||||
hidden_display = "none",
|
||||
symlink_destination = true,
|
||||
decorators = { "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", },
|
||||
highlight_git = "none",
|
||||
highlight_diagnostics = "none",
|
||||
highlight_opened_files = "none",
|
||||
highlight_modified = "none",
|
||||
highlight_hidden = "none",
|
||||
highlight_bookmarks = "none",
|
||||
highlight_clipboard = "name",
|
||||
indent_markers = {
|
||||
enable = false,
|
||||
inline_arrows = true,
|
||||
icons = {
|
||||
corner = "└",
|
||||
edge = "│",
|
||||
item = "│",
|
||||
bottom = "─",
|
||||
none = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
web_devicons = {
|
||||
file = {
|
||||
enable = true,
|
||||
color = true,
|
||||
},
|
||||
folder = {
|
||||
enable = false,
|
||||
color = true,
|
||||
},
|
||||
},
|
||||
git_placement = "before",
|
||||
modified_placement = "after",
|
||||
hidden_placement = "after",
|
||||
diagnostics_placement = "signcolumn",
|
||||
bookmarks_placement = "signcolumn",
|
||||
padding = {
|
||||
icon = " ",
|
||||
folder_arrow = " ",
|
||||
},
|
||||
symlink_arrow = " ➛ ",
|
||||
show = {
|
||||
file = true,
|
||||
folder = true,
|
||||
folder_arrow = true,
|
||||
git = true,
|
||||
modified = true,
|
||||
hidden = false,
|
||||
diagnostics = true,
|
||||
bookmarks = true,
|
||||
},
|
||||
glyphs = {
|
||||
default = "",
|
||||
symlink = "",
|
||||
bookmark = "",
|
||||
modified = "●",
|
||||
hidden = "",
|
||||
folder = {
|
||||
arrow_closed = "",
|
||||
arrow_open = "",
|
||||
default = "",
|
||||
open = "",
|
||||
empty = "",
|
||||
empty_open = "",
|
||||
symlink = "",
|
||||
symlink_open = "",
|
||||
},
|
||||
git = {
|
||||
unstaged = "✗",
|
||||
staged = "✓",
|
||||
unmerged = "",
|
||||
renamed = "➜",
|
||||
untracked = "★",
|
||||
deleted = "",
|
||||
ignored = "◌",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
hijack_directories = {
|
||||
enable = true,
|
||||
auto_open = true,
|
||||
},
|
||||
update_focused_file = {
|
||||
enable = false,
|
||||
update_root = {
|
||||
enable = false,
|
||||
ignore_list = {},
|
||||
},
|
||||
exclude = false,
|
||||
},
|
||||
git = {
|
||||
enable = true,
|
||||
show_on_dirs = true,
|
||||
show_on_open_dirs = true,
|
||||
disable_for_dirs = {},
|
||||
timeout = 400,
|
||||
cygwin_support = false,
|
||||
},
|
||||
diagnostics = {
|
||||
enable = false,
|
||||
show_on_dirs = false,
|
||||
show_on_open_dirs = true,
|
||||
debounce_delay = 500,
|
||||
severity = {
|
||||
min = vim.diagnostic.severity.HINT,
|
||||
max = vim.diagnostic.severity.ERROR,
|
||||
},
|
||||
icons = {
|
||||
hint = "",
|
||||
info = "",
|
||||
warning = "",
|
||||
error = "",
|
||||
},
|
||||
diagnostic_opts = false,
|
||||
},
|
||||
modified = {
|
||||
enable = false,
|
||||
show_on_dirs = true,
|
||||
show_on_open_dirs = true,
|
||||
},
|
||||
filters = {
|
||||
enable = true,
|
||||
git_ignored = true,
|
||||
dotfiles = false,
|
||||
git_clean = false,
|
||||
no_buffer = false,
|
||||
no_bookmark = false,
|
||||
custom = {},
|
||||
exclude = {},
|
||||
},
|
||||
live_filter = {
|
||||
prefix = "[FILTER]: ",
|
||||
always_show_folders = true,
|
||||
},
|
||||
filesystem_watchers = {
|
||||
enable = true,
|
||||
debounce_delay = 50,
|
||||
max_events = 0,
|
||||
ignore_dirs = {
|
||||
"/.ccls-cache",
|
||||
"/build",
|
||||
"/node_modules",
|
||||
"/target",
|
||||
"/.zig-cache",
|
||||
},
|
||||
whitelist_dirs = {},
|
||||
},
|
||||
actions = {
|
||||
use_system_clipboard = true,
|
||||
change_dir = {
|
||||
enable = true,
|
||||
global = false,
|
||||
restrict_above_cwd = false,
|
||||
},
|
||||
expand_all = {
|
||||
max_folder_discovery = 300,
|
||||
exclude = {},
|
||||
},
|
||||
file_popup = {
|
||||
open_win_config = {
|
||||
col = 1,
|
||||
row = 1,
|
||||
relative = "cursor",
|
||||
border = "shadow",
|
||||
style = "minimal",
|
||||
},
|
||||
},
|
||||
open_file = {
|
||||
quit_on_open = false,
|
||||
eject = true,
|
||||
resize_window = true,
|
||||
relative_path = true,
|
||||
window_picker = {
|
||||
enable = true,
|
||||
picker = "default",
|
||||
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
|
||||
exclude = {
|
||||
filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" },
|
||||
buftype = { "nofile", "terminal", "help" },
|
||||
},
|
||||
},
|
||||
},
|
||||
remove_file = {
|
||||
close_window = true,
|
||||
},
|
||||
},
|
||||
trash = {
|
||||
cmd = "gio trash",
|
||||
},
|
||||
tab = {
|
||||
sync = {
|
||||
open = false,
|
||||
close = false,
|
||||
ignore = {},
|
||||
},
|
||||
},
|
||||
notify = {
|
||||
threshold = vim.log.levels.INFO,
|
||||
absolute_path = true,
|
||||
},
|
||||
help = {
|
||||
sort_by = "key",
|
||||
},
|
||||
ui = {
|
||||
confirm = {
|
||||
remove = true,
|
||||
trash = true,
|
||||
default_yes = false,
|
||||
},
|
||||
},
|
||||
bookmarks = {
|
||||
persist = false,
|
||||
},
|
||||
experimental = {
|
||||
session_restore_nvim = false
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
truncate = false,
|
||||
types = {
|
||||
all = false,
|
||||
config = false,
|
||||
copy_paste = false,
|
||||
dev = false,
|
||||
diagnostics = false,
|
||||
git = false,
|
||||
profile = false,
|
||||
watcher = false,
|
||||
},
|
||||
},
|
||||
} -- config-default-end
|
||||
|
||||
local FIELD_SKIP_VALIDATE = {
|
||||
open_win_config = true,
|
||||
}
|
||||
|
||||
local ACCEPTED_TYPES = {
|
||||
on_attach = { "function", "string" },
|
||||
sort = {
|
||||
sorter = { "function", "string" },
|
||||
},
|
||||
view = {
|
||||
width = {
|
||||
"string",
|
||||
"function",
|
||||
"number",
|
||||
"table",
|
||||
min = { "string", "function", "number" },
|
||||
max = { "string", "function", "number" },
|
||||
lines_excluded = { "table" },
|
||||
padding = { "function", "number" },
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
hidden_display = { "function", "string" },
|
||||
group_empty = { "boolean", "function" },
|
||||
root_folder_label = { "function", "string", "boolean" },
|
||||
},
|
||||
update_focused_file = {
|
||||
exclude = { "function" },
|
||||
},
|
||||
git = {
|
||||
disable_for_dirs = { "function" },
|
||||
},
|
||||
filters = {
|
||||
custom = { "function" },
|
||||
},
|
||||
filesystem_watchers = {
|
||||
ignore_dirs = { "function" },
|
||||
whitelist_dirs = { "function" },
|
||||
},
|
||||
actions = {
|
||||
open_file = {
|
||||
window_picker = {
|
||||
picker = { "function", "string" },
|
||||
},
|
||||
},
|
||||
},
|
||||
bookmarks = {
|
||||
persist = { "boolean", "string" },
|
||||
},
|
||||
}
|
||||
|
||||
local ACCEPTED_STRINGS = {
|
||||
sort = {
|
||||
sorter = { "name", "case_sensitive", "modification_time", "extension", "suffix", "filetype" },
|
||||
},
|
||||
view = {
|
||||
side = { "left", "right" },
|
||||
signcolumn = { "yes", "no", "auto" },
|
||||
},
|
||||
renderer = {
|
||||
hidden_display = { "none", "simple", "all" },
|
||||
highlight_git = { "none", "icon", "name", "all" },
|
||||
highlight_opened_files = { "none", "icon", "name", "all" },
|
||||
highlight_modified = { "none", "icon", "name", "all" },
|
||||
highlight_hidden = { "none", "icon", "name", "all" },
|
||||
highlight_bookmarks = { "none", "icon", "name", "all" },
|
||||
highlight_diagnostics = { "none", "icon", "name", "all" },
|
||||
highlight_clipboard = { "none", "icon", "name", "all" },
|
||||
icons = {
|
||||
git_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
modified_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
hidden_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
diagnostics_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
bookmarks_placement = { "before", "after", "signcolumn", "right_align" },
|
||||
},
|
||||
},
|
||||
help = {
|
||||
sort_by = { "key", "desc" },
|
||||
},
|
||||
}
|
||||
|
||||
local ACCEPTED_ENUMS = {
|
||||
view = {
|
||||
width = {
|
||||
lines_excluded = { "root", },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
---Validate types and values of the user supplied config.
|
||||
---Warns and removes invalid in place.
|
||||
---@param u nvim_tree.config
|
||||
local function validate_config(u)
|
||||
local msg
|
||||
|
||||
---@param user any
|
||||
---@param def any
|
||||
---@param strs table
|
||||
---@param types table
|
||||
---@param enums table
|
||||
---@param prefix string
|
||||
local function validate(user, def, strs, types, enums, prefix)
|
||||
-- if user's option is not a table there is nothing to do
|
||||
if type(user) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
-- we have hit a leaf enum to validate against - it's an integer indexed table
|
||||
local enum_value = type(enums) == "table" and next(enums) and type(next(enums)) == "number"
|
||||
|
||||
-- only compare tables with contents that are not integer indexed nor enums
|
||||
if not enum_value and (type(def) ~= "table" or not next(def) or type(next(def)) == "number") then
|
||||
-- unless the field can be a table (and is not a table in default config)
|
||||
if vim.tbl_contains(types, "table") then
|
||||
-- use a dummy default to allow all checks
|
||||
def = {}
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(user) do
|
||||
if not FIELD_SKIP_VALIDATE[k] then
|
||||
local invalid
|
||||
|
||||
if enum_value then
|
||||
if not vim.tbl_contains(enums, v) then
|
||||
invalid = string.format("Invalid value for field %s%s: Expected one of enum '%s', got '%s'", prefix, k,
|
||||
table.concat(enums, "'|'"), tostring(v))
|
||||
end
|
||||
else
|
||||
if def[k] == nil and types[k] == nil then
|
||||
-- option does not exist
|
||||
invalid = string.format("Unknown option: %s%s", prefix, k)
|
||||
elseif type(v) ~= type(def[k]) then
|
||||
local expected
|
||||
|
||||
if types[k] and #types[k] > 0 then
|
||||
if not vim.tbl_contains(types[k], type(v)) then
|
||||
expected = table.concat(types[k], "|")
|
||||
end
|
||||
else
|
||||
expected = type(def[k])
|
||||
end
|
||||
|
||||
if expected then
|
||||
-- option is of the wrong type
|
||||
invalid = string.format("Invalid option: %s%s. Expected %s, got %s", prefix, k, expected, type(v))
|
||||
end
|
||||
elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then
|
||||
-- option has type `string` but value is not accepted
|
||||
invalid = string.format("Invalid value for field %s%s: '%s'", prefix, k, v)
|
||||
end
|
||||
end
|
||||
|
||||
if invalid then
|
||||
if msg then
|
||||
msg = string.format("%s\n%s", msg, invalid)
|
||||
else
|
||||
msg = invalid
|
||||
end
|
||||
user[k] = nil
|
||||
elseif not enum_value then
|
||||
validate(v, def[k], strs[k] or {}, types[k] or {}, enums[k] or {}, prefix .. k .. ".")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
validate(u, M.d, ACCEPTED_STRINGS, ACCEPTED_TYPES, ACCEPTED_ENUMS, "")
|
||||
|
||||
if msg then
|
||||
require("nvim-tree.notify").warn(msg .. "\n\nsee :help nvim-tree-config for available configuration options")
|
||||
end
|
||||
end
|
||||
|
||||
---Localise the (default) config with OS specifics
|
||||
---@param d nvim_tree.config
|
||||
local function localise_config(d)
|
||||
-- Trash
|
||||
if M.os.macos or M.os.windows then
|
||||
d.trash.cmd = "trash"
|
||||
end
|
||||
|
||||
-- Watchers
|
||||
if M.os.windows then
|
||||
d.filesystem_watchers.max_events = 1000
|
||||
end
|
||||
end
|
||||
|
||||
---Normalise the (global) config: defaults and user
|
||||
---@param g nvim_tree.config
|
||||
local function process_config(g)
|
||||
--
|
||||
-- Open
|
||||
--
|
||||
g.actions.open_file.window_picker.chars = tostring(g.actions.open_file.window_picker.chars):upper()
|
||||
|
||||
--
|
||||
-- Padding
|
||||
--
|
||||
if g.renderer.indent_width < 1 then
|
||||
g.renderer.indent_width = 1
|
||||
end
|
||||
for k, v in pairs(g.renderer.indent_markers.icons) do
|
||||
if #v == 0 then
|
||||
g.renderer.indent_markers.icons[k] = " "
|
||||
else
|
||||
-- return the first character from the UTF-8 encoded string; we may use utf8.codes from Lua 5.3 when available
|
||||
g.renderer.indent_markers.icons[k] = v:match("[%z\1-\127\194-\244][\128-\191]*")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Hijack and disable netrw if (globally) configured
|
||||
---@param g nvim_tree.config
|
||||
local function manage_netrw(g)
|
||||
if g.hijack_netrw then
|
||||
vim.cmd("silent! autocmd! FileExplorer *")
|
||||
vim.cmd("autocmd VimEnter * ++once silent! autocmd! FileExplorer *")
|
||||
end
|
||||
if g.disable_netrw then
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
end
|
||||
end
|
||||
|
||||
---Validate user config and migrate legacy.
|
||||
---Merge with M.d and persist as M.g
|
||||
---When no user config M.g is set to M.d and M.u is set to nil
|
||||
---@param u? nvim_tree.config user supplied subset of config
|
||||
function M.setup(u)
|
||||
if not u or type(u) ~= "table" then
|
||||
if u then
|
||||
require("nvim-tree.notify").warn(string.format("invalid config type \"%s\" passed to setup, using defaults", type(u)))
|
||||
end
|
||||
M.g = vim.deepcopy(M.d)
|
||||
M.u = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- retain user for reference
|
||||
M.u = vim.deepcopy(u)
|
||||
|
||||
require("nvim-tree.legacy").migrate_config(u)
|
||||
|
||||
validate_config(u)
|
||||
|
||||
-- set global to the validated and populated user config
|
||||
M.g = vim.tbl_deep_extend("force", M.d, u)
|
||||
|
||||
-- process merged config
|
||||
process_config(M.g)
|
||||
|
||||
-- deal with netrw
|
||||
manage_netrw(M.g)
|
||||
|
||||
-- store cwd
|
||||
M.init_root = vim.fn.getcwd()
|
||||
end
|
||||
|
||||
---Deep clone defaults
|
||||
---@return nvim_tree.config
|
||||
function M.d_clone()
|
||||
return vim.deepcopy(M.d)
|
||||
end
|
||||
|
||||
---Deep clone user
|
||||
---@return nvim_tree.config? nil when no config passed to setup
|
||||
function M.u_clone()
|
||||
return vim.deepcopy(M.u)
|
||||
end
|
||||
|
||||
---Deep clone global
|
||||
---@return nvim_tree.config? nil when setup not called
|
||||
function M.g_clone()
|
||||
return vim.deepcopy(M.g)
|
||||
end
|
||||
|
||||
---Immediately localise the defaults once and once only
|
||||
localise_config(M.d)
|
||||
|
||||
return M
|
||||
@@ -1,6 +1,9 @@
|
||||
local events = require "nvim-tree.events"
|
||||
local view = require "nvim-tree.view"
|
||||
local log = require "nvim-tree.log"
|
||||
local events = require("nvim-tree.events")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local view = require("nvim-tree.view")
|
||||
local log = require("nvim-tree.log")
|
||||
local git = require("nvim-tree.git")
|
||||
local watcher = require("nvim-tree.watcher")
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -15,7 +18,21 @@ function M.init(foldername)
|
||||
if TreeExplorer then
|
||||
TreeExplorer:destroy()
|
||||
end
|
||||
TreeExplorer = require("nvim-tree.explorer"):new(foldername)
|
||||
|
||||
local err, path
|
||||
|
||||
if foldername then
|
||||
path, err = vim.uv.fs_realpath(foldername)
|
||||
else
|
||||
path, err = vim.uv.cwd()
|
||||
end
|
||||
if path then
|
||||
TreeExplorer = require("nvim-tree.explorer")({ path = path })
|
||||
else
|
||||
notify.error(err)
|
||||
TreeExplorer = nil
|
||||
end
|
||||
|
||||
if not first_init_done then
|
||||
events._dispatch_ready()
|
||||
first_init_done = true
|
||||
@@ -49,4 +66,16 @@ function M.get_nodes_starting_line()
|
||||
return offset
|
||||
end
|
||||
|
||||
function M.purge_all_state()
|
||||
view.close_all_tabs()
|
||||
view.abandon_all_windows()
|
||||
if TreeExplorer then
|
||||
git.purge_state()
|
||||
TreeExplorer:destroy()
|
||||
M.reset_explorer()
|
||||
end
|
||||
-- purge orphaned that were not destroyed by their nodes
|
||||
watcher.purge_watchers()
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local view = require "nvim-tree.view"
|
||||
local log = require "nvim-tree.log"
|
||||
local config = require("nvim-tree.config")
|
||||
local core = require("nvim-tree.core")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local view = require("nvim-tree.view")
|
||||
local log = require("nvim-tree.log")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {}
|
||||
|
||||
@@ -15,7 +18,7 @@ local COC_SEVERITY_LEVELS = {
|
||||
}
|
||||
|
||||
---Absolute Node path to LSP severity level
|
||||
---@alias NodeSeverities table<string, lsp.DiagnosticSeverity>
|
||||
---@alias NodeSeverities table<string, vim.diagnostic.Severity>
|
||||
|
||||
---@class DiagStatus
|
||||
---@field value lsp.DiagnosticSeverity|nil
|
||||
@@ -35,39 +38,17 @@ local function uniformize_path(path)
|
||||
return utils.canonical_path(path:gsub("\\", "/"))
|
||||
end
|
||||
|
||||
---Marshal severities from LSP. Does nothing when LSP disabled.
|
||||
---@return NodeSeverities
|
||||
local function from_nvim_lsp()
|
||||
local buffer_severity = {}
|
||||
|
||||
-- is_enabled is not present in all 0.10 builds/releases, see #2781
|
||||
local is_enabled = false
|
||||
if vim.fn.has "nvim-0.10" == 1 and type(vim.diagnostic.is_enabled) == "function" then
|
||||
is_enabled = vim.diagnostic.is_enabled()
|
||||
elseif type(vim.diagnostic.is_disabled) == "function" then ---@diagnostic disable-line: deprecated
|
||||
is_enabled = not vim.diagnostic.is_disabled() ---@diagnostic disable-line: deprecated
|
||||
end
|
||||
|
||||
if is_enabled then
|
||||
for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do
|
||||
if diagnostic.severity and diagnostic.bufnr and vim.api.nvim_buf_is_valid(diagnostic.bufnr) then
|
||||
local bufname = uniformize_path(vim.api.nvim_buf_get_name(diagnostic.bufnr))
|
||||
if not buffer_severity[bufname] or diagnostic.severity < buffer_severity[bufname] then
|
||||
buffer_severity[bufname] = diagnostic.severity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return buffer_severity
|
||||
end
|
||||
|
||||
---Severity is within diagnostics.severity.min, diagnostics.severity.max
|
||||
---@param severity lsp.DiagnosticSeverity
|
||||
---@param config table
|
||||
---Alway in range when using vim.diagnostic.Opts:
|
||||
---@see nvim_tree.config.diagnostics.diagnostic_opts
|
||||
---@param severity vim.diagnostic.Severity
|
||||
---@return boolean
|
||||
local function is_severity_in_range(severity, config)
|
||||
return config.max <= severity and severity <= config.min
|
||||
local function is_severity_in_range(severity)
|
||||
if config.g.diagnostics.diagnostic_opts then
|
||||
return true
|
||||
else
|
||||
return severity >= config.g.diagnostics.severity.max and severity <= config.g.diagnostics.severity.min
|
||||
end
|
||||
end
|
||||
|
||||
---Handle any COC exceptions, preventing any propagation
|
||||
@@ -77,7 +58,7 @@ local function handle_coc_exception(err)
|
||||
local notify = true
|
||||
|
||||
-- avoid distractions on interrupts (CTRL-C)
|
||||
if err:find "Vim:Interrupt" or err:find "Keyboard interrupt" then
|
||||
if err:find("Vim:Interrupt") or err:find("Keyboard interrupt") then
|
||||
notify = false
|
||||
end
|
||||
|
||||
@@ -100,7 +81,7 @@ local function from_coc()
|
||||
end
|
||||
|
||||
local ok, diagnostic_list = xpcall(function()
|
||||
return vim.fn.CocAction "diagnosticList"
|
||||
return vim.fn.CocAction("diagnosticList")
|
||||
end, handle_coc_exception)
|
||||
if not ok or type(diagnostic_list) ~= "table" or vim.tbl_isempty(diagnostic_list) then
|
||||
return {}
|
||||
@@ -111,7 +92,7 @@ local function from_coc()
|
||||
local bufname = uniformize_path(diagnostic.file)
|
||||
local coc_severity = COC_SEVERITY_LEVELS[diagnostic.severity]
|
||||
local highest_severity = buffer_severity[bufname] or coc_severity
|
||||
if is_severity_in_range(highest_severity, M.severity) then
|
||||
if is_severity_in_range(highest_severity) then
|
||||
buffer_severity[bufname] = math.min(highest_severity, coc_severity)
|
||||
end
|
||||
end
|
||||
@@ -125,7 +106,7 @@ end
|
||||
local function from_cache(node)
|
||||
local nodepath = uniformize_path(node.absolute_path)
|
||||
local max_severity = nil
|
||||
if not node.nodes then
|
||||
if not node:is(DirectoryNode) then
|
||||
-- direct cache hit for files
|
||||
max_severity = NODE_SEVERITIES[nodepath]
|
||||
else
|
||||
@@ -133,11 +114,8 @@ local function from_cache(node)
|
||||
for bufname, severity in pairs(NODE_SEVERITIES) do
|
||||
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
|
||||
if node_contains_buf then
|
||||
if severity == M.severity.max then
|
||||
if not max_severity or severity < max_severity then
|
||||
max_severity = severity
|
||||
break
|
||||
else
|
||||
max_severity = math.min(max_severity or severity, severity)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -145,27 +123,76 @@ local function from_cache(node)
|
||||
return { value = max_severity, cache_version = NODE_SEVERITIES_VERSION }
|
||||
end
|
||||
|
||||
---Fired on DiagnosticChanged and CocDiagnosticChanged events:
|
||||
---debounced retrieval, cache update, version increment and draw
|
||||
function M.update()
|
||||
if not M.enable then
|
||||
---Fired on DiagnosticChanged for a single buffer.
|
||||
---This will be called on set and reset of diagnostics.
|
||||
---On disabling LSP, a reset event will be sent for all buffers.
|
||||
---@param ev table standard event with data.diagnostics populated
|
||||
function M.update_lsp(ev)
|
||||
log.line("diagnostics", "DiagnosticChanged")
|
||||
if not config.g.diagnostics.enable or not ev or not ev.data or not ev.data.diagnostics then
|
||||
return
|
||||
end
|
||||
utils.debounce("diagnostics", M.debounce_delay, function()
|
||||
local profile = log.profile_start "diagnostics update"
|
||||
if is_using_coc() then
|
||||
NODE_SEVERITIES = from_coc()
|
||||
else
|
||||
NODE_SEVERITIES = from_nvim_lsp()
|
||||
|
||||
local profile_event = log.profile_start("DiagnosticChanged event")
|
||||
|
||||
local diagnostics = vim.diagnostic.get(ev.buf)
|
||||
|
||||
-- use the buffer from the event, as ev.data.diagnostics will be empty on resolved diagnostics
|
||||
local bufname = uniformize_path(vim.api.nvim_buf_get_name(ev.buf))
|
||||
|
||||
---@type vim.diagnostic.Severity?
|
||||
local new_severity = nil
|
||||
|
||||
-- most severe (lowest) severity in user range
|
||||
for _, diagnostic in ipairs(diagnostics) do
|
||||
if is_severity_in_range(diagnostic.severity) then
|
||||
if not new_severity or diagnostic.severity < new_severity then
|
||||
new_severity = diagnostic.severity
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- record delta and schedule a redraw
|
||||
if new_severity ~= NODE_SEVERITIES[bufname] then
|
||||
NODE_SEVERITIES[bufname] = new_severity
|
||||
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
|
||||
if log.enabled "diagnostics" then
|
||||
|
||||
utils.debounce("DiagnosticChanged redraw", config.g.diagnostics.debounce_delay, function()
|
||||
local profile_redraw = log.profile_start("DiagnosticChanged redraw")
|
||||
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
end
|
||||
|
||||
log.profile_end(profile_redraw)
|
||||
end)
|
||||
end
|
||||
|
||||
log.profile_end(profile_event)
|
||||
end
|
||||
|
||||
---Fired on CocDiagnosticChanged events:
|
||||
---debounced retrieval, cache update, version increment and draw
|
||||
function M.update_coc()
|
||||
log.line("diagnostics", "CocDiagnosticChange")
|
||||
if not config.g.diagnostics.enable then
|
||||
return
|
||||
end
|
||||
utils.debounce("CocDiagnosticChanged update", config.g.diagnostics.debounce_delay, function()
|
||||
local profile = log.profile_start("CocDiagnosticChanged update")
|
||||
NODE_SEVERITIES = from_coc()
|
||||
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
|
||||
if log.enabled("diagnostics") then
|
||||
for bufname, severity in pairs(NODE_SEVERITIES) do
|
||||
log.line("diagnostics", "Indexing bufname '%s' with severity %d", bufname, severity)
|
||||
log.line("diagnostics", "COC Indexing bufname '%s' with severity %d", bufname, severity)
|
||||
end
|
||||
end
|
||||
log.profile_end(profile)
|
||||
if view.is_buf_valid(view.get_bufnr()) then
|
||||
|
||||
local bufnr = view.get_bufnr()
|
||||
local should_draw = bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_is_loaded(bufnr)
|
||||
if should_draw then
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
explorer.renderer:draw()
|
||||
@@ -179,12 +206,12 @@ end
|
||||
---@param node Node
|
||||
---@return DiagStatus|nil
|
||||
function M.get_diag_status(node)
|
||||
if not M.enable then
|
||||
if not config.g.diagnostics.enable then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- dir but we shouldn't show on dirs at all
|
||||
if node.nodes ~= nil and not M.show_on_dirs then
|
||||
if node:is(DirectoryNode) and not config.g.diagnostics.show_on_dirs then
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -195,29 +222,18 @@ function M.get_diag_status(node)
|
||||
node.diag_status = from_cache(node)
|
||||
end
|
||||
|
||||
local dir = node:as(DirectoryNode)
|
||||
|
||||
-- file
|
||||
if not node.nodes then
|
||||
if not dir then
|
||||
return node.diag_status
|
||||
end
|
||||
|
||||
-- dir is closed or we should show on open_dirs
|
||||
if not node.open or M.show_on_open_dirs then
|
||||
if not dir.open or config.g.diagnostics.show_on_open_dirs then
|
||||
return node.diag_status
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.enable = opts.diagnostics.enable
|
||||
M.debounce_delay = opts.diagnostics.debounce_delay
|
||||
M.severity = opts.diagnostics.severity
|
||||
|
||||
if M.enable then
|
||||
log.line("diagnostics", "setup")
|
||||
end
|
||||
|
||||
M.show_on_dirs = opts.diagnostics.show_on_dirs
|
||||
M.show_on_open_dirs = opts.diagnostics.show_on_open_dirs
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user