Compare commits

...

41 Commits

Author SHA1 Message Date
github-actions[bot]
321bc61580 chore(master): release nvim-tree 1.14.0 (#3146)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 10:43:00 +10:00
Alexander Courtis
442513648c perf(#3171): cache toplevel for untracked (#3185) 2025-08-12 10:34:24 +10:00
Alexander Courtis
000ca6bcdd docs: CONTRIBUTING.md: add diagnostics and backward compatibility 2025-08-11 14:22:46 +10:00
Kasper Kondzielski
1b876db049 feat(#2789): add optional function expand_until to api.tree.expand_all and api.node.expand (#3166)
* feat: Allow to expand nodes until certain condition is met

* Fix warnings

* Restore original position of edit function

* Rename field to match the api method name

* Rename ApiTreeExpandAllOpts to ApiTreeExpandOpts

* Remove toggle_descend_until

* Remove redundant empty line

* Update :help for changed methods

* Fix partial expansion of grouped nodes

* Fix lint error

* Fix linting error

* Fix incorrect open/close indicator state

* Update docs

* Rename descend_until option to expand_until

* Always check directory expansion limit

* Fix linter errors

* Ignore unused param warning

* Apply suggestions from code review

* simplify MAX_FOLDER_DISCOVERY warning

* fix bad comment whitespace

---------

Co-authored-by: ghostbuster91 <ghostbuster91@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-08-11 13:50:26 +10:00
Julien Vincent
0a52012d61 feat(#2685): highlight git new tracked with NvimTreeGitFileNewHL (#3176)
Highlight new, tracked files in working copy

Currently nvim-tree doesn't highlight new, tracked files in the working
copy/directory.

This change assigns the `NvimTreeGitFileNewHL` highlight to the `" A"`
git porcelain status marker.

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-08-10 15:00:38 +10:00
Alexander Courtis
a4699c0904 revert(#3180, #3177): resolve live filter failures (#3183)
* Revert "fix(#3172): live filter exception (#3173)"

This reverts commit 0a7fcdf3f8.

* Revert "refactor(#2826): move view to instanced window class (#3153)"

This reverts commit 0a06f65bf0.

* feat(#3157): add view.cursorlineopt
2025-08-10 14:45:25 +10:00
Alexander Courtis
9b289abd69 revert(#3180, #3177): invalid group or tabpage (#3181)
* Revert "feat(#2826): allow only one window with nvim-tree buffer per tab (#3174)"

This reverts commit dd2364d680.

* Revert "refactor(#2826): View tracks winids and bufnrs via events, unused for now (#3170)"

This reverts commit 65bae44922.

* Revert "refactor(#2826): remove view debug/cc, enable new codepaths for get_winid and get_bufnr (#3169)"

This reverts commit a9156c0139.
2025-08-10 11:18:31 +10:00
Alexander Courtis
dd2364d680 feat(#2826): allow only one window with nvim-tree buffer per tab (#3174)
* feat(#2826): allow only one window with nvim-tree buffer per tab

* feat(#2826): remove globals.BUFNR_BY_TABID

* Revert "feat(#2826): remove globals.BUFNR_BY_TABID"

This reverts commit 2651f9b34a.

* feat(#2826): remove unused View.winid_by_tabid

* feat(#2826): add feature gate experimental.close_other_windows_in_tab
2025-08-05 15:29:25 +10:00
Tomasz N
9a05b9e9f9 perf(#3171): use vim.system() instead of vim.fn.system() to execute git toplevel (#3175)
* fix(#3171): use vim.system() to determine git toplevel

* Don't use vim.trim

* Ensure sdtout is a string

* Keep Nvim 0.9 compatibility

* Use vim.system to query git config for status.showUntrackedFiles too
2025-08-05 13:23:51 +10:00
Alexander Courtis
0a7fcdf3f8 fix(#3172): live filter exception (#3173) 2025-08-04 11:51:42 +10:00
Alexander Courtis
65bae44922 refactor(#2826): View tracks winids and bufnrs via events, unused for now (#3170)
* refactor(#2826): add View.bufnr and use for all public methods

* use View.bufnr for all internal methods

* revert View.bufnr, add buffer local autocommands

* View revert to globals.BUFNR_BY_TABID until bufnr and winid are tracked for the view

* View track winids and bufnrs via events
2025-07-29 14:19:24 +10:00
Alexander Courtis
a9156c0139 refactor(#2826): remove view debug/cc, enable new codepaths for get_winid and get_bufnr (#3169)
* refactor(#2826): fuller error messages

* refactor(#2826): winnr->winid in view/globals, remove redundant get_winid and get_bufnr calls

* refactor(#2826): winnr->winid consistently

* refactor(#2826): consistent use of buffer registry, tidy, add todos

* refactor(#2826): remove unnecessary view members float, hide_root_folder; use explorer opts

* refactor(#2826): remove unused view members centralize_selection and preserve_window_proportions

* refactor(#2826): remove unused view member height

* refactor(#2826): temporarily reuse BUFNR_PER_TAB in view constructor

* refactor(#2826): get_winid returns new after consistency check

* refactor(#2826): globals.TABPAGES -> WINID_PER_TAB

* refactor(#2826): consistent naming of tabid

* refactor(#2826): more consistency checking

* refactor(#2826): more consistency checking

* refactor(#2826): move global CURSORS to view member

* Revert "refactor(#2826): move global CURSORS to view member"

This reverts commit d84dfad1c3.

* refactor(#2826): move global CURSORS to view member

* refactor(#2826): consistency check returns new

* refactor(#2826): remove consistency checks, enabling new path for view get_winid and get_bufnr

* refactor(#2826): restore CURSORS global
2025-07-28 12:44:17 +10:00
alexfinger21
10db6943cb fix(#3077): deleting a directory containing symlinked directory will delete the contents of the linked directory (#3168)
* fix(#3077) deleting a directory containing symlink file will delete all content inside the symlink

* fix(#3077): add diagnostic override TODO

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-07-28 09:42:38 +10:00
Tomasz N
543ed3cac2 fix(picker): exclude full_name window id from the choice (#3165)
Problem: `full_name` window from is considered as usable by picker
Solution: exclude its ID (also true for nil values)

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-07-21 13:22:56 +10:00
Alexander Courtis
2a386fe567 ci: luals_version 3.13.9 -> 3.15.0 (#3167) 2025-07-21 13:22:07 +10:00
Alexander Courtis
b0b49552c9 docs: polish example decorator (#3160) 2025-06-21 10:57:48 +10:00
Alexander Courtis
8eb5e0bfd1 feat(#3157): add view.cursorlineopt (#3158)
fix(#3157): add view.cursorlineopt
2025-06-20 13:46:38 +10:00
Alexander Courtis
0a06f65bf0 refactor(#2826): move view to instanced window class (#3153)
* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class, WIP

* refactor(#2826): singleton View class

* refactor(#2826): View is an Explorer member

* refactor(#2826): move autocmds to Explorer

* refactor(#2826): API uses Explorer's View

* refactor(#2826): move View into Explorer package

* refactor(#2826): retain necessary view globals

* refactor(#2826): move all winhl to appearance constants

* refactor(#2826): add lifecycle logging to all Explorer members

* refactor(#2826): fix bad cherry-pick

* refactor(#2826): better enumerate_options function

* refactor(#2826): add View.tab_line for debugging

* refactor(#2826): default lifecycle log off

* refactor(#2826): add experimental.multi_instance_debug, split globals out of view, move diagnostics to its own module

* refactor(#2826): instrument View:get_winnr

* refactor(#2826): instrument View:setup_tabpage

* refactor(#2826): instrument View:set_current_win, View:prevent_buffer_override

* refactor(#2826): instrument View:get_bufnr

* refactor(#2826): track member bufnr -> winid with global

* refactor(#2826): tidy experiment names and logs

* vim: nvim-tree: track bufnr via buffer-update channel

* vim: nvim-tree: more logging

* vim: nvim-tree: revert: track bufnr via buffer-update channel

* refactor(#2826): notify error on view winid and bufnr mismatches

* refactor(#2826): notify error on view winid and bufnr mismatches

* refactor(#2826): explorer init logging
2025-06-19 15:45:55 +10:00
Yavorski
d54a1875a9 fix: invalid window id for popup info window (#3147) 2025-06-17 16:59:28 +10:00
Garry Filakhtov
aa087788d7 docs: fix renderer.icons.bookmarks_placement parameter, misspelling (#3150)
Fix minor documentation issues

Add a missing double quotes around the default value for
`nvim-tree.renderer.icons.bookmarks_placement` config value and fix
spelling of `bookmarked`.
2025-06-17 10:23:34 +10:00
phanium
d87b41ca53 fix: window picker ignore hidden window (#3145) 2025-06-15 15:04:47 +10:00
github-actions[bot]
6b5b366596 chore(master): release nvim-tree 1.13.0 (#3120)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-14 17:30:22 +10:00
Rami Elwan
ae595611fb feat(#3132): add api.node.expand and api.node.collapse (#3133)
* feat: allow passing node to collapse all

* refactor: use snake case

* feat: handle api legacy calls and update signature

* refactor: make sure open is a boolean

* doc: collapse_all

* Revert "doc: collapse_all"

This reverts commit d243da3e14.

* add api.node.collapse

* add api.node.expand

* add api.node.expand

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-06-14 17:26:58 +10:00
Lucas Mendes
05d8172ebf fix(#3143): actions.open_file.window_picker.exclude applies when not using window picker (#3144)
* fix(#3143): ensure open.no_window_picker respects window_picker.exclude

* fix(#3143): doc

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-06-14 15:35:07 +10:00
Lorentz Lasson
1c733e8c19 chore: use portable shebangs consistently (#3141)
use portable shebangs consistently
2025-06-02 09:21:07 +10:00
Šimon Mandlík
ebcaccda1c fix(#3134): setting one glyph to "" no longer disables others (#3136)
fix: fixes #3134
2025-05-26 13:32:21 +10:00
Šimon Mandlík
cbc3165e08 fix(#2746): background and right aligned icons in floating windows (#3128)
* fix(#2746): fix cursorcolumn and right aligned icons in floating windows

* feat: remove right aligned icons from full name float, show float over right aligned icons

* refactoring: move `extmarks_length` to utils.lua

* fix: decrease `win_width` instead of increasing `text_width` when computing condition for full name float to show

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-05-24 13:19:19 +10:00
Arthur Roos
bd54d1d33c fix(#3117): windows: change file/dir case (#3135)
fix(#3117): allow changing filename's casing

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-05-24 12:52:25 +10:00
Christoph
25d16aab7d fix: "Invalid buffer id" on closing nvim-tree window (#3129)
fix: invalid buffer issue

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-05-18 04:35:59 +00:00
Ross W
e4cd856ebf fix(#3124): fix icon padding for "right_align" placements, notably for dotfiles (#3125)
fix(#3124): prevent empty icons_right_align response from breaking padding
2025-05-18 12:26:18 +10:00
Alexander Courtis
e7d1b7dadc fix(#3122): remove redundant vim.validate (#3123) 2025-05-09 10:00:28 +10:00
Spencer Chunn
ea5097a1e2 feat(#3113): add renderer.icons.folder_arrow_padding (#3114)
* Update padding.lua

* add folder_arrow_padding

* update help docs

* refactor: renderer.icons.padding

renderer.icons.padding -> renderer.icons.padding.icon
renderer.icons.folder_arrow_padding ->
renderer.icons.padding.folder_arrow

* refactor: renderer.icons.padding

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-05-05 11:51:29 +10:00
Alexander Courtis
582ae48c9e chore: fix incorrect @param (#3115) 2025-04-26 12:55:36 +10:00
github-actions[bot]
be5b788f2d chore(master): release nvim-tree 1.12.0 (#3099)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-04-21 12:04:41 +10:00
Alexander Courtis
64bb47f868 ci: simplify luarocks release tag pattern as it was not firing 2025-04-21 08:59:56 +10:00
Devansh Sharma
c24c0470d9 feat: add TreePreOpen event (#3105)
* feat: Add `TreePreOpen` and `TreePreClose` events

* docs: Update docs for `TreePreOpen` and `TreePreClose` events

* chore: remove `TreePreClose` event and update dispatch of `TreePreOpen`

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2025-04-21 08:39:48 +10:00
Devansh Sharma
3a63717d3d fix: reliably dispatch exactly one TreeOpen and TreeClose events (#3107)
* fix: correctly handle `TreeOpen` and `TreeClose` event dispatch

* fix: lint issues
2025-04-20 09:49:28 +10:00
Alexander Courtis
5bea2b3752 fix(#3101): when renderer.highlight_opened_files = "none" do not reload on BufUnload and BufReadPost (#3102)
* fix(#3101): fix bad reference to renderer.highlight_opened_files during BufUnload and BufReadPost

* fix(#3101): only redraw renderer.highlight_opened_files during BufUnload and BufReadPost

* fix(#3101): only redraw renderer.highlight_opened_files during BufUnload and BufReadPost

* fix(#3101): only redraw renderer.highlight_opened_files during BufUnload and BufReadPost
2025-04-11 12:48:34 +10:00
Šimon Mandlík
c3c1935942 fix: explicitly set border to "none" in full name float (#3094) 2025-04-04 17:29:38 +11:00
Alexander Courtis
44d9b58f11 chore: use builtin EmmyLuaCodeStyle for style checking (#3084)
* chore: sync EmmyLuaCodeStyle settings between .editorconfig and .luarc.json

* chore: lua-language-server 3.11.0 -> 3.13.9

* chore: fix incorrect definition of vim.loop.fs_lstat

* chore: add codestyle-check option to luals-check.sh

* chore: use luals for style check

* chore: use luals for style check

* Revert "chore: use luals for style check"

This reverts commit e5fde80fab.

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check

* chore: use luals for style check
2025-03-23 12:46:17 +11:00
dependabot[bot]
c09ff35de5 chore(deps): bump leafo/gh-actions-lua from 10 to 11 (#3069)
Bumps [leafo/gh-actions-lua](https://github.com/leafo/gh-actions-lua) from 10 to 11.
- [Release notes](https://github.com/leafo/gh-actions-lua/releases)
- [Commits](https://github.com/leafo/gh-actions-lua/compare/v10...v11)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-01 11:07:35 +11:00
36 changed files with 728 additions and 288 deletions

View File

@@ -7,6 +7,9 @@ end_of_line = lf
[nvim-tree-lua.txt] [nvim-tree-lua.txt]
max_line_length = 78 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] [*.lua]
indent_style = space indent_style = space
max_line_length = 140 max_line_length = 140

View File

@@ -20,45 +20,25 @@ jobs:
strategy: strategy:
matrix: matrix:
lua_version: [ 5.1 ] lua_version: [ 5.1 ]
luacheck_version: [ 1.2.0 ]
steps: steps:
- uses: actions/checkout@v4 - name: checkout
uses: actions/checkout@v4
- uses: leafo/gh-actions-lua@v10 - name: install lua ${{ matrix.lua_version }}
uses: leafo/gh-actions-lua@v11
with: with:
luaVersion: ${{ matrix.lua_version }} luaVersion: ${{ matrix.lua_version }}
- uses: leafo/gh-actions-luarocks@v4 - name: install luarocks
uses: leafo/gh-actions-luarocks@v5
- run: luarocks install luacheck 1.1.1 - name: install luacheck ${{ matrix.luacheck_version }}
run: luarocks install luacheck ${{ matrix.luacheck_version }}
- run: make lint - run: make lint
style:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ matrix.emmy_lua_code_style_version }}-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
strategy:
matrix:
emmy_lua_code_style_version: [ 1.5.6 ]
steps:
- uses: actions/checkout@v4
- name: install emmy_lua_code_style
run: |
mkdir -p CodeFormat
curl -L "https://github.com/CppCXY/EmmyLuaCodeStyle/releases/download/${{ matrix.emmy_lua_code_style_version }}/linux-x64.tar.gz" | tar zx --directory CodeFormat
- run: echo "CodeFormat/linux-x64/bin" >> "$GITHUB_PATH"
- run: make style
- run: make style-doc
check: check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -69,26 +49,31 @@ jobs:
strategy: strategy:
matrix: matrix:
nvim_version: [ stable, nightly ] nvim_version: [ stable, nightly ]
luals_version: [ 3.11.0 ] luals_version: [ 3.15.0 ]
env:
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
steps: steps:
- uses: actions/checkout@v4 - name: checkout
uses: actions/checkout@v4
- uses: rhysd/action-setup-vim@v1 - name: install nvim ${{ matrix.nvim_version }}
uses: rhysd/action-setup-vim@v1
with: with:
neovim: true neovim: true
version: ${{ matrix.nvim_version }} version: ${{ matrix.nvim_version }}
- name: install luals - name: install lua-language-server ${{ matrix.luals_version }}
run: | run: |
mkdir -p luals 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 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" - run: make check
- name: make check
env:
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
run: make check
- run: make help-check - run: make help-check
- run: make style
- run: make style-doc

View File

@@ -1,9 +1,11 @@
name: Luarocks Release name: Luarocks Release
on: on:
push: push:
tags: tags:
- 'v[0-9]+.[0-9]+.[0-9]+' - v*
workflow_dispatch: workflow_dispatch:
jobs: jobs:
luarocks-upload: luarocks-upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,3 +1,3 @@
#!/bin/sh #!/usr/bin/env sh
make make

View File

@@ -1,12 +1,23 @@
{ {
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"runtime.version.luals-check-only": "Lua 5.1",
"workspace": { "workspace": {
"library": [ "library": [
"$VIMRUNTIME/lua/vim", "$VIMRUNTIME/lua/vim",
"${3rd}/luv/library" "${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": { "diagnostics": {
"libraryFiles": "Disable", "libraryFiles": "Disable",
"globals": [], "globals": [],

View File

@@ -1,3 +1,3 @@
{ {
".": "1.11.0" ".": "1.14.0"
} }

View File

@@ -1,5 +1,74 @@
# Changelog # Changelog
## [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) ## [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)

View File

@@ -4,6 +4,30 @@ Thank you for contributing.
See [wiki: 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)
* [check](#check)
- [Diagnostics](#diagnostics)
- [Backwards Compatibility](#backwards-compatibility)
- [Adding New Actions](#adding-new-actions)
- [Documentation](#documentation)
* [Opts](#opts)
* [API](#api)
- [Windows](#windows)
- [Pull Request](#pull-request)
* [Subject](#subject)
<!-- tocstop -->
# Tools # Tools
Following are used during CI and strongly recommended during local development. Following are used during CI and strongly recommended during local development.
@@ -12,9 +36,9 @@ Language server: [luals](https://luals.github.io)
Lint: [luacheck](https://github.com/lunarmodules/luacheck/) Lint: [luacheck](https://github.com/lunarmodules/luacheck/)
Style: [EmmyLuaCodeStyle](https://github.com/CppCXY/EmmyLuaCodeStyle): `CodeCheck` Style Fixing: [EmmyLuaCodeStyle](https://github.com/CppCXY/EmmyLuaCodeStyle): `CodeCheck`
nvim-tree.lua migrated from stylua to EmmyLuaCodeStyle ~2024/10. `vim.lsp.buf.format()` may be used as it is the default formatter for luals nvim-tree.lua 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)
You can install them via you OS package manager e.g. `pacman`, `brew` or other via other package managers such as `cargo` or `luarocks` You can install them via you OS package manager e.g. `pacman`, `brew` or other via other package managers such as `cargo` or `luarocks`
@@ -36,14 +60,14 @@ make lint
## style ## style
1. Runs CodeCheck using `.editorconfig` settings 1. Runs lua language server `codestyle-check` only, using `.luarc.json` settings
1. Runs `scripts/doc-comments.sh` to validate annotated documentation 1. Runs `scripts/doc-comments.sh` to validate annotated documentation
```sh ```sh
make style make style
``` ```
You can automatically fix `CodeCheck` issues via: You can automatically fix style issues using `CodeCheck`:
```sh ```sh
make style-fix make style-fix
@@ -72,6 +96,30 @@ curl -L "https://github.com/LuaLS/lua-language-server/releases/download/3.9.1/lu
PATH="luals/bin:${PATH}" make check PATH="luals/bin:${PATH}" make check
``` ```
# Diagnostics
Diagnostics issues may not be suppressed. See [luals](https://luals.github.io) documentation for details on how to structure the code and comments.
Suppressions are permitted only in the following cases:
- Backwards compatibility shims
- neovim API metadata incorrect, awaiting upstream fix
- classic class framework
# 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.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
```
# Adding New Actions # Adding New Actions
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. 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.

View File

@@ -17,7 +17,7 @@ luacheck:
# --diagnosis-as-error does not function for workspace, hence we post-process the output # --diagnosis-as-error does not function for workspace, hence we post-process the output
style-check: style-check:
CodeFormat check --config .editorconfig --diagnosis-as-error --workspace lua @scripts/luals-check.sh codestyle-check
style-doc: style-doc:
scripts/doc-comments.sh scripts/doc-comments.sh

View File

@@ -206,7 +206,7 @@ Show the mappings: `g?`
`S` Search |nvim-tree-api.tree.search_node()| `S` Search |nvim-tree-api.tree.search_node()|
`u` Rename: Full Path |nvim-tree-api.fs.rename_full()| `u` Rename: Full Path |nvim-tree-api.fs.rename_full()|
`U` Toggle Filter: Hidden |nvim-tree-api.tree.toggle_custom_filter()| `U` Toggle Filter: Hidden |nvim-tree-api.tree.toggle_custom_filter()|
`W` Collapse |nvim-tree-api.tree.collapse_all()| `W` Collapse All |nvim-tree-api.tree.collapse_all()|
`x` Cut |nvim-tree-api.fs.cut()| `x` Cut |nvim-tree-api.fs.cut()|
`y` Copy Name |nvim-tree-api.fs.copy.filename()| `y` Copy Name |nvim-tree-api.fs.copy.filename()|
`Y` Copy Relative Path |nvim-tree-api.fs.copy.relative_path()| `Y` Copy Relative Path |nvim-tree-api.fs.copy.relative_path()|
@@ -341,7 +341,7 @@ See |nvim-tree-highlight| for details.
See |nvim-tree-api.tree.collapse_all()| See |nvim-tree-api.tree.collapse_all()|
Calls: `api.tree.collapse_all(false)` Calls: `api.tree.collapse_all({ keep_buffers = false })`
*:NvimTreeCollapseKeepBuffers* *:NvimTreeCollapseKeepBuffers*
@@ -350,7 +350,7 @@ See |nvim-tree-highlight| for details.
See |nvim-tree-api.tree.collapse_all()| See |nvim-tree-api.tree.collapse_all()|
Calls: `api.tree.collapse_all(true)` Calls: `api.tree.collapse_all({ keep_buffers = true })`
*:NvimTreeHiTest* *:NvimTreeHiTest*
@@ -398,6 +398,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
view = { view = {
centralize_selection = false, centralize_selection = false,
cursorline = true, cursorline = true,
cursorlineopt = "both",
debounce_delay = 15, debounce_delay = 15,
side = "left", side = "left",
preserve_window_proportions = false, preserve_window_proportions = false,
@@ -462,7 +463,10 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
hidden_placement = "after", hidden_placement = "after",
diagnostics_placement = "signcolumn", diagnostics_placement = "signcolumn",
bookmarks_placement = "signcolumn", bookmarks_placement = "signcolumn",
padding = " ", padding = {
icon = " ",
folder_arrow = " ",
},
symlink_arrow = " ➛ ", symlink_arrow = " ➛ ",
show = { show = {
file = true, file = true,
@@ -767,6 +771,10 @@ initially centralized, see |zz|.
Enable |cursorline| in the tree window. Enable |cursorline| in the tree window.
Type: `boolean`, Default: `true` Type: `boolean`, Default: `true`
*nvim-tree.view.cursorlineopt*
Set |cursorlineopt| in the tree window.
Type: `string`, Default: `"both"`
*nvim-tree.view.debounce_delay* *nvim-tree.view.debounce_delay*
Idle milliseconds before some reload / refresh operations. Idle milliseconds before some reload / refresh operations.
Increase if you experience performance issues around screen refresh. Increase if you experience performance issues around screen refresh.
@@ -1063,12 +1071,16 @@ Configuration options for icons.
*nvim-tree.renderer.icons.bookmarks_placement* *nvim-tree.renderer.icons.bookmarks_placement*
Bookmark icon placement. Bookmark icon placement.
Type: `string`, Default: `signcolumn` Type: `string`, Default: `"signcolumn"`
*nvim-tree.renderer.icons.padding* *nvim-tree.renderer.icons.padding.icon*
Inserted between icon and filename. Inserted between icon and filename.
Type: `string`, Default: `" "` Type: `string`, Default: `" "`
*nvim-tree.renderer.icons.padding.folder_arrow*
Inserted between folder arrow icon and file/folder icon.
Type: `string`, Default: `" "`
*nvim-tree.renderer.icons.symlink_arrow* *nvim-tree.renderer.icons.symlink_arrow*
Used as a separator between symlinks' source and target. Used as a separator between symlinks' source and target.
Type: `string`, Default: `" ➛ "` Type: `string`, Default: `" ➛ "`
@@ -1373,7 +1385,7 @@ delete/wipe. A reload or filesystem event will result in an update.
Type: `boolean`, Default: `false` Type: `boolean`, Default: `false`
*nvim-tree.filters.no_bookmark* *nvim-tree.filters.no_bookmark*
Do not show files that are not bookarked. Do not show files that are not bookmarked.
Toggle via |nvim-tree-api.tree.toggle_no_bookmark_filter()|, default `M` Toggle via |nvim-tree-api.tree.toggle_no_bookmark_filter()|, default `M`
Enabling this is not useful as there is no means yet to persist bookmarks. Enabling this is not useful as there is no means yet to persist bookmarks.
Type: `boolean`, Default: `false` Type: `boolean`, Default: `false`
@@ -1463,7 +1475,8 @@ vim |current-directory| behaviour.
Type: `boolean`, Default: `false` Type: `boolean`, Default: `false`
*nvim-tree.actions.expand_all* *nvim-tree.actions.expand_all*
Configuration for expand_all behaviour. Configuration for |nvim-tree-api.tree.expand_all()| and
|nvim-tree-api.node.expand()|
*nvim-tree.actions.expand_all.max_folder_discovery* *nvim-tree.actions.expand_all.max_folder_discovery*
Limit the number of folders being explored when expanding every folders. Limit the number of folders being explored when expanding every folders.
@@ -1506,17 +1519,13 @@ Configuration options for opening a file from nvim-tree.
Resizes the tree when opening a file. Resizes the tree when opening a file.
Type: `boolean`, Default: `true` Type: `boolean`, Default: `true`
*nvim-tree.experimental.actions.open_file.relative_path*
Buffers opened by nvim-tree will use with relative paths instead of
absolute.
Type: `boolean`, Default: `true`
*nvim-tree.actions.open_file.window_picker* *nvim-tree.actions.open_file.window_picker*
Window picker configuration. Window picker configuration.
*nvim-tree.actions.open_file.window_picker.enable* *nvim-tree.actions.open_file.window_picker.enable*
Enable the feature. If the feature is not enabled, files will open in Enable the feature. If the feature is not enabled, files will open in
window from which you last opened the tree. window from which you last opened the tree, obeying
|nvim-tree.actions.open_file.window_picker.exclude|
Type: `boolean`, Default: `true` Type: `boolean`, Default: `true`
*nvim-tree.actions.open_file.window_picker.picker* *nvim-tree.actions.open_file.window_picker.picker*
@@ -1535,9 +1544,10 @@ Configuration options for opening a file from nvim-tree.
Type: `string`, Default: `"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"` Type: `string`, Default: `"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"`
*nvim-tree.actions.open_file.window_picker.exclude* *nvim-tree.actions.open_file.window_picker.exclude*
Table of buffer option names mapped to a list of option values that Table of buffer option names mapped to a list of option values.
indicates to the picker that the buffer's window should not be Windows containing matching buffers will not be:
selectable. - available when using a window picker
- selected when not using a window picker
Type: `table`, Default: >lua Type: `table`, Default: >lua
{ {
filetype = { filetype = {
@@ -1822,17 +1832,26 @@ tree.find_file({opts}) *nvim-tree-api.tree.find_file()*
tree.search_node() *nvim-tree-api.tree.search_node()* tree.search_node() *nvim-tree-api.tree.search_node()*
Open the search dialogue as per the search_node action. Open the search dialogue as per the search_node action.
tree.collapse_all({keep_buffers}) *nvim-tree-api.tree.collapse_all()* tree.collapse_all({opts}) *nvim-tree-api.tree.collapse_all()*
Collapse the tree. Collapse the tree.
Parameters: ~ Parameters: ~
• {opts} (table) optional parameters
Options: ~
• {keep_buffers} (boolean) do not collapse nodes with open buffers. • {keep_buffers} (boolean) do not collapse nodes with open buffers.
tree.expand_all({node}) *nvim-tree-api.tree.expand_all()* tree.expand_all({node}, {opts}) *nvim-tree-api.tree.expand_all()*
Recursively expand all nodes under the tree root or specified folder. Recursively expand all nodes under the tree root or specified folder.
Parameters: ~ Parameters: ~
• {node} (Node|nil) folder • {node} (Node|nil) folder
• {opts} (ApiTreeExpandOpts) optional parameters
Options: ~
• {expand_until} ((fun(expansion_count: integer, node: Node?): boolean)?)
Return true if {node} should be expanded.
{expansion_count} is the total number of folders expanded.
*nvim-tree-api.tree.toggle_enable_filters()* *nvim-tree-api.tree.toggle_enable_filters()*
tree.toggle_enable_filters() tree.toggle_enable_filters()
@@ -2266,6 +2285,29 @@ node.buffer.wipe({node}, {opts}) *nvim-tree-api.node.buffer.wipe()*
Options: ~ Options: ~
• {force} (boolean) wipe even if buffer is modified, default false • {force} (boolean) wipe even if buffer is modified, default false
node.expand({node}, {opts}) *nvim-tree-api.node.expand()*
Recursively expand all nodes under a directory or a file's parent
directory.
Parameters: ~
• {node} (Node|nil) file or folder
• {opts} (ApiTreeExpandOpts) optional parameters
Options: ~
• {expand_until} ((fun(expansion_count: integer, node: Node?): boolean)?)
Return true if {node} should be expanded.
{expansion_count} is the total number of folders expanded.
node.collapse({node}, {opts}) *nvim-tree-api.node.collapse()*
Collapse the tree under a directory or a file's parent directory.
Parameters: ~
• {node} (Node|nil) file or folder
• {opts} (table) optional parameters
Options: ~
• {keep_buffers} (boolean) do not collapse nodes with open buffers.
============================================================================== ==============================================================================
6.4 API GIT *nvim-tree-api.git* 6.4 API GIT *nvim-tree-api.git*
@@ -2520,7 +2562,7 @@ You are encouraged to copy these to your own |nvim-tree.on_attach| function. >lu
vim.keymap.set("n", "S", api.tree.search_node, opts("Search")) vim.keymap.set("n", "S", api.tree.search_node, opts("Search"))
vim.keymap.set("n", "u", api.fs.rename_full, opts("Rename: Full Path")) vim.keymap.set("n", "u", api.fs.rename_full, opts("Rename: Full Path"))
vim.keymap.set("n", "U", api.tree.toggle_custom_filter, opts("Toggle Filter: Hidden")) vim.keymap.set("n", "U", api.tree.toggle_custom_filter, opts("Toggle Filter: Hidden"))
vim.keymap.set("n", "W", api.tree.collapse_all, opts("Collapse")) vim.keymap.set("n", "W", api.tree.collapse_all, opts("Collapse All"))
vim.keymap.set("n", "x", api.fs.cut, opts("Cut")) vim.keymap.set("n", "x", api.fs.cut, opts("Cut"))
vim.keymap.set("n", "y", api.fs.copy.filename, opts("Copy Name")) vim.keymap.set("n", "y", api.fs.copy.filename, opts("Copy Name"))
vim.keymap.set("n", "Y", api.fs.copy.relative_path, opts("Copy Relative Path")) vim.keymap.set("n", "Y", api.fs.copy.relative_path, opts("Copy Relative Path"))
@@ -2769,13 +2811,21 @@ e.g. handler for node renamed: >lua
|nvim_tree_events_kind| |nvim_tree_events_kind|
- Event.Ready - Event.Ready
When NvimTree has been initialized When NvimTree has been initialized.
• Note: Handler takes no parameter.
- Event.TreePreOpen
Invoked before the window and buffer for NvimTree are created
or opened. Before |Event.TreeOpen| event.
• Note: Handler takes no parameter. • Note: Handler takes no parameter.
- Event.TreeOpen - Event.TreeOpen
Invoked after the NvimTree is opened.
• Note: Handler takes no parameter. • Note: Handler takes no parameter.
- Event.TreeClose - Event.TreeClose
Invoked after the NvimTree is closed, but before the window is
closed. Dispatched on |WinClosed| event for NvimTree window.
• Note: Handler takes no parameter. • Note: Handler takes no parameter.
- Event.Resize - When NvimTree is resized. - Event.Resize - When NvimTree is resized.
@@ -2890,9 +2940,33 @@ Decorators may:
- Set highlight group for the name or icons - Set highlight group for the name or icons
- Override node icon - Override node icon
Specify decorators and their precedence via |nvim-tree.renderer.decorators| Create a `nvim_tree.api.decorator.UserDecorator` class and register it with
e.g. defaults with a user decorator class being overridden only by Cut: >lua precedence via |nvim-tree.renderer.decorators|
{
See |nvim-tree-decorator-example|
See `nvim-tree/_meta/api_decorator.lua` for full class documentation.
==============================================================================
11.1. DECORATOR EXAMPLE *nvim-tree-decorator-example*
A decorator class for nodes named "example", overridind 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", "Git",
"Open", "Open",
"Hidden", "Hidden",
@@ -2902,31 +2976,35 @@ e.g. defaults with a user decorator class being overridden only by Cut: >lua
"Copied", "Copied",
MyDecorator, MyDecorator,
"Cut", "Cut",
} },
},
See `nvim-tree/_meta/api_decorator.lua` for full })
`nvim_tree.api.decorator.UserDecorator` class documentation.
< <
============================================================================== Contents of `my-decorator.lua`:
11.1. DECORATOR EXAMPLE *nvim-tree-decorator-example*
>lua >lua
---Create your decorator class
---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator ---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator
---@field private my_icon nvim_tree.api.HighlightedString ---@field private my_icon1 nvim_tree.api.HighlightedString
---@field private my_icon2 nvim_tree.api.HighlightedString
---@field private my_icon_node nvim_tree.api.HighlightedString
---@field private my_highlight_group string
local MyDecorator = require("nvim-tree.api").decorator.UserDecorator:extend() local MyDecorator = require("nvim-tree.api").decorator.UserDecorator:extend()
---Mandatory constructor :new() will be called once per tree render, with no arguments. ---Mandatory constructor :new() will be called once per tree render, with no arguments.
function MyDecorator:new() function MyDecorator:new()
self.enabled = true self.enabled = true
self.highlight_range = "all" self.highlight_range = "name"
self.icon_placement = "signcolumn" self.icon_placement = "after"
-- create your icon once, for convenience -- create your icons and highlights once, applied to every node
self.my_icon = { str = "I", hl = { "MyIcon" } } 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 sign only once -- Define the icon signs only once
-- Only needed if you are using icon_placement = "signcolumn" -- Only needed if you are using icon_placement = "signcolumn"
self:define_sign(self.my_icon) -- self:define_sign(self.my_icon1)
-- self:define_sign(self.my_icon2)
end end
---Override node icon ---Override node icon
@@ -2934,33 +3012,35 @@ See `nvim-tree/_meta/api_decorator.lua` for full
---@return nvim_tree.api.HighlightedString? icon_node ---@return nvim_tree.api.HighlightedString? icon_node
function MyDecorator:icon_node(node) function MyDecorator:icon_node(node)
if node.name == "example" then if node.name == "example" then
return self.my_icon return self.my_icon_node
else else
return nil return nil
end end
end end
---Return one icon for DecoratorIconPlacement ---Return two icons for DecoratorIconPlacement "after"
---@param node nvim_tree.api.Node ---@param node nvim_tree.api.Node
---@return nvim_tree.api.HighlightedString[]? icons ---@return nvim_tree.api.HighlightedString[]? icons
function MyDecorator:icons(node) function MyDecorator:icons(node)
if node.name == "example" then if node.name == "example" then
return { self.my_icon } return { self.my_icon1, self.my_icon2, }
else else
return nil return nil
end end
end end
---Exactly one highlight group for DecoratorHighlightRange ---Exactly one highlight group for DecoratorHighlightRange "name"
---@param node nvim_tree.api.Node ---@param node nvim_tree.api.Node
---@return string? highlight_group ---@return string? highlight_group
function MyDecorator:highlight_group(node) function MyDecorator:highlight_group(node)
if node.name == "example" then if node.name == "example" then
return "MyHighlight" return self.my_highlight_group
else else
return nil return nil
end end
end end
return MyDecorator
< <
============================================================================== ==============================================================================
12. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific* 12. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*
@@ -2970,9 +3050,6 @@ Windows WSL and PowerShell
- Executable file detection is disabled as this is non-performant and can - Executable file detection is disabled as this is non-performant and can
freeze nvim freeze nvim
- Some filesystem watcher error related to permissions will not be reported - Some filesystem watcher error related to permissions will not be reported
- Some users have reported unspecified issues with
|nvim-tree.experimental.actions.open_file.relative_path|. Please report any
issues or disable this feature.
============================================================================== ==============================================================================
13. NETRW *nvim-tree-netrw* 13. NETRW *nvim-tree-netrw*
@@ -3019,6 +3096,7 @@ needed.
`sort_by` |nvim-tree.sort.sorter| `sort_by` |nvim-tree.sort.sorter|
`git.ignore` |nvim-tree.filters.git_ignored| `git.ignore` |nvim-tree.filters.git_ignored|
`renderer.icons.webdev_colors` |nvim-tree.renderer.icons.web_devicons.file.color| `renderer.icons.webdev_colors` |nvim-tree.renderer.icons.web_devicons.file.color|
`renderer.icons.padding` |nvim-tree.renderer.icons.padding.icon|
============================================================================== ==============================================================================
14.2 LEGACY: HIGHLIGHT *nvim-tree-legacy-highlight* 14.2 LEGACY: HIGHLIGHT *nvim-tree-legacy-highlight*
@@ -3106,7 +3184,6 @@ highlight group is not, hard linking as follows: >
|nvim-tree.diagnostics.show_on_open_dirs| |nvim-tree.diagnostics.show_on_open_dirs|
|nvim-tree.disable_netrw| |nvim-tree.disable_netrw|
|nvim-tree.experimental| |nvim-tree.experimental|
|nvim-tree.experimental.actions.open_file.relative_path|
|nvim-tree.filesystem_watchers.debounce_delay| |nvim-tree.filesystem_watchers.debounce_delay|
|nvim-tree.filesystem_watchers.enable| |nvim-tree.filesystem_watchers.enable|
|nvim-tree.filesystem_watchers.ignore_dirs| |nvim-tree.filesystem_watchers.ignore_dirs|
@@ -3175,7 +3252,8 @@ highlight group is not, hard linking as follows: >
|nvim-tree.renderer.icons.glyphs.symlink| |nvim-tree.renderer.icons.glyphs.symlink|
|nvim-tree.renderer.icons.hidden_placement| |nvim-tree.renderer.icons.hidden_placement|
|nvim-tree.renderer.icons.modified_placement| |nvim-tree.renderer.icons.modified_placement|
|nvim-tree.renderer.icons.padding| |nvim-tree.renderer.icons.padding.folder_arrow|
|nvim-tree.renderer.icons.padding.icon|
|nvim-tree.renderer.icons.show| |nvim-tree.renderer.icons.show|
|nvim-tree.renderer.icons.show.bookmarks| |nvim-tree.renderer.icons.show.bookmarks|
|nvim-tree.renderer.icons.show.diagnostics| |nvim-tree.renderer.icons.show.diagnostics|
@@ -3226,6 +3304,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree.update_focused_file.update_root.ignore_list| |nvim-tree.update_focused_file.update_root.ignore_list|
|nvim-tree.view.centralize_selection| |nvim-tree.view.centralize_selection|
|nvim-tree.view.cursorline| |nvim-tree.view.cursorline|
|nvim-tree.view.cursorlineopt|
|nvim-tree.view.debounce_delay| |nvim-tree.view.debounce_delay|
|nvim-tree.view.float| |nvim-tree.view.float|
|nvim-tree.view.float.enable| |nvim-tree.view.float.enable|
@@ -3282,6 +3361,8 @@ highlight group is not, hard linking as follows: >
|nvim-tree-api.marks.toggle()| |nvim-tree-api.marks.toggle()|
|nvim-tree-api.node.buffer.delete()| |nvim-tree-api.node.buffer.delete()|
|nvim-tree-api.node.buffer.wipe()| |nvim-tree-api.node.buffer.wipe()|
|nvim-tree-api.node.collapse()|
|nvim-tree-api.node.expand()|
|nvim-tree-api.node.navigate.diagnostics.next()| |nvim-tree-api.node.navigate.diagnostics.next()|
|nvim-tree-api.node.navigate.diagnostics.next_recursive()| |nvim-tree-api.node.navigate.diagnostics.next_recursive()|
|nvim-tree-api.node.navigate.diagnostics.prev()| |nvim-tree-api.node.navigate.diagnostics.prev()|

View File

@@ -236,6 +236,20 @@ local function setup_autocommands(opts)
end, end,
}) })
end end
-- Handles event dispatch when tree is closed by `:q`
create_nvim_tree_autocmd("WinClosed", {
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,
})
end end
local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
@@ -259,6 +273,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
view = { view = {
centralize_selection = false, centralize_selection = false,
cursorline = true, cursorline = true,
cursorlineopt = "both",
debounce_delay = 15, debounce_delay = 15,
side = "left", side = "left",
preserve_window_proportions = false, preserve_window_proportions = false,
@@ -323,7 +338,10 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
hidden_placement = "after", hidden_placement = "after",
diagnostics_placement = "signcolumn", diagnostics_placement = "signcolumn",
bookmarks_placement = "signcolumn", bookmarks_placement = "signcolumn",
padding = " ", padding = {
icon = " ",
folder_arrow = " ",
},
symlink_arrow = "", symlink_arrow = "",
show = { show = {
file = true, file = true,

View File

@@ -69,9 +69,16 @@ local function remove_dir(cwd)
-- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility -- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility
local stat = vim.loop.fs_stat(new_cwd) local stat = vim.loop.fs_stat(new_cwd)
local type = stat and stat.type or nil -- 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.loop.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) local success = remove_dir(new_cwd)
if not success then if not success then
return false return false

View File

@@ -57,7 +57,9 @@ end
function M.close_popup() function M.close_popup()
if current_popup ~= nil then if current_popup ~= nil then
if vim.api.nvim_win_is_valid(current_popup.winnr) then
vim.api.nvim_win_close(current_popup.winnr, true) vim.api.nvim_win_close(current_popup.winnr, true)
end
vim.cmd("augroup NvimTreeRemoveFilePopup | au! CursorMoved | augroup END") vim.cmd("augroup NvimTreeRemoveFilePopup | au! CursorMoved | augroup END")
current_popup = nil current_popup = nil

View File

@@ -2,6 +2,7 @@
local lib = require("nvim-tree.lib") local lib = require("nvim-tree.lib")
local notify = require("nvim-tree.notify") local notify = require("nvim-tree.notify")
local utils = require("nvim-tree.utils") local utils = require("nvim-tree.utils")
local full_name = require("nvim-tree.renderer.components.full-name")
local view = require("nvim-tree.view") local view = require("nvim-tree.view")
local M = {} local M = {}
@@ -39,21 +40,15 @@ local function usable_win_ids()
end end
local win_config = vim.api.nvim_win_get_config(id) 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, win_ids)
end 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. ---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 ---@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 --- invalid window was picked / user canceled, return nil. If there are
@@ -246,9 +241,14 @@ local function get_target_winid(mode)
local target_winid local target_winid
if not M.window_picker.enable or string.find(mode, "no_picker") then if not M.window_picker.enable or string.find(mode, "no_picker") then
target_winid = lib.target_winid target_winid = lib.target_winid
-- first available window local usable_wins = usable_win_ids()
if not vim.tbl_contains(vim.api.nvim_tabpage_list_wins(0), target_winid) then -- first available usable window
target_winid = first_win_id() 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 end
else else
-- pick a window -- pick a window

View File

@@ -2,6 +2,7 @@ local utils = require("nvim-tree.utils")
local core = require("nvim-tree.core") local core = require("nvim-tree.core")
local Iterator = require("nvim-tree.iterators.node-iterator") local Iterator = require("nvim-tree.iterators.node-iterator")
local FileNode = require("nvim-tree.node.file")
local DirectoryNode = require("nvim-tree.node.directory") local DirectoryNode = require("nvim-tree.node.directory")
local M = {} local M = {}
@@ -23,26 +24,30 @@ local function buf_match()
end end
end end
---@param keep_buffers boolean ---Collapse a node, root if nil
function M.fn(keep_buffers) ---@param node Node?
---@param opts ApiCollapseOpts
local function collapse(node, opts)
local explorer = core.get_explorer() local explorer = core.get_explorer()
if not explorer then if not explorer then
return return
end end
local node = explorer:get_node_at_cursor() node = node or explorer
if not node then
local node_at_cursor = explorer:get_node_at_cursor()
if not node_at_cursor then
return return
end end
local matches = buf_match() local matches = buf_match()
Iterator.builder(explorer.nodes) Iterator.builder({ node:is(FileNode) and node.parent or node:as(DirectoryNode) })
:hidden() :hidden()
:applier(function(n) :applier(function(n)
local dir = n:as(DirectoryNode) local dir = n:as(DirectoryNode)
if dir then if dir then
dir.open = keep_buffers and matches(dir.absolute_path) dir.open = opts.keep_buffers == true and matches(dir.absolute_path)
end end
end) end)
:recursor(function(n) :recursor(function(n)
@@ -51,7 +56,26 @@ function M.fn(keep_buffers)
:iterate() :iterate()
explorer.renderer:draw() explorer.renderer:draw()
utils.focus_node_or_parent(node) utils.focus_node_or_parent(node_at_cursor)
end
---@param opts ApiCollapseOpts|boolean|nil 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 ApiCollapseOpts?
function M.node(node, opts)
collapse(node, opts or {})
end end
return M return M

View File

@@ -1,95 +0,0 @@
local core = require("nvim-tree.core")
local Iterator = require("nvim-tree.iterators.node-iterator")
local notify = require("nvim-tree.notify")
local DirectoryNode = require("nvim-tree.node.directory")
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 DirectoryNode
local function expand(node)
node = node:last_group_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 dir = node:as(DirectoryNode)
if not dir then
return false
end
local should_halt = expansion_count >= M.MAX_FOLDER_DISCOVERY
local should_exclude = M.EXCLUDE[dir.name]
return not should_halt and not dir.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
node = node:as(DirectoryNode)
if node then
expand(node)
end
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
---Expand the directory node or the root
---@param node Node
function M.fn(node)
local explorer = core.get_explorer()
local parent = node:as(DirectoryNode) or explorer
if not parent then
return
end
if gen_iterator()(parent) 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

View File

@@ -0,0 +1,166 @@
local core = require("nvim-tree.core")
local Iterator = require("nvim-tree.iterators.node-iterator")
local notify = require("nvim-tree.notify")
local FileNode = require("nvim-tree.node.file")
local DirectoryNode = require("nvim-tree.node.directory")
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 DirectoryNode
local function expand(node)
node = node:last_group_node()
node.open = true
if #node.nodes == 0 then
core.get_explorer():expand(node)
end
end
---@param should_descend fun(expansion_count: integer, node: Node): boolean
---@return fun(expansion_count: integer, node: Node): boolean
local function limit_folder_discovery(should_descend)
return function(expansion_count, node)
local should_halt = expansion_count >= M.MAX_FOLDER_DISCOVERY
if should_halt then
notify.warn("expansion iteration was halted after " .. M.MAX_FOLDER_DISCOVERY .. " discovered folders")
return false
end
return should_descend(expansion_count, node)
end
end
---@param _ integer expansion_count
---@param node Node
---@return boolean
local function descend_until_empty(_, node)
local dir = node:as(DirectoryNode)
if not dir then
return false
end
local should_exclude = M.EXCLUDE[dir.name]
return not should_exclude
end
---@param expansion_count integer
---@param node Node
---@param should_descend fun(expansion_count: integer, node: Node): boolean
---@return boolean
local function should_expand(expansion_count, node, should_descend)
local dir = node:as(DirectoryNode)
if not dir then
return false
end
if not dir.open and should_descend(expansion_count, node) then
if #node.nodes == 0 then
core.get_explorer():expand(dir) -- populate node.group_next
end
if dir.group_next then
local expand_next = should_expand(expansion_count, dir.group_next, should_descend)
if expand_next then
dir.open = true
end
return expand_next
else
return true
end
end
return false
end
---@param should_descend fun(expansion_count: integer, node: Node): boolean
---@return fun(node): any
local function gen_iterator(should_descend)
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, should_descend) then
expansion_count = expansion_count + 1
node = node:as(DirectoryNode)
if node then
expand(node)
end
end
end)
:recursor(function(node)
if not should_descend(expansion_count, node) then
return nil
end
if node.group_next then
return { node.group_next }
end
if node.open and node.nodes then
return node.nodes
end
return nil
end)
:iterate()
end
end
---@param node Node?
---@param expand_opts ApiTreeExpandOpts?
local function expand_node(node, expand_opts)
if not node then
return
end
local descend_until = limit_folder_discovery((expand_opts and expand_opts.expand_until) or descend_until_empty)
gen_iterator(descend_until)(node)
local explorer = core.get_explorer()
if explorer then
explorer.renderer:draw()
end
end
---Expand the directory node or the root
---@param node Node
---@param expand_opts ApiTreeExpandOpts?
function M.all(node, expand_opts)
expand_node(node and node:as(DirectoryNode) or core.get_explorer(), expand_opts)
end
---Expand the directory node or parent node
---@param node Node
---@param expand_opts ApiTreeExpandOpts?
function M.node(node, expand_opts)
if not node then
return
end
expand_node(node:is(FileNode) and node.parent or node:as(DirectoryNode), expand_opts)
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

View File

@@ -1,10 +1,10 @@
local M = {} local M = {}
M.collapse_all = require("nvim-tree.actions.tree.modifiers.collapse-all") M.collapse = require("nvim-tree.actions.tree.modifiers.collapse")
M.expand_all = require("nvim-tree.actions.tree.modifiers.expand-all") M.expand = require("nvim-tree.actions.tree.modifiers.expand")
function M.setup(opts) function M.setup(opts)
M.expand_all.setup(opts) M.expand.setup(opts)
end end
return M return M

View File

@@ -182,8 +182,16 @@ Api.tree.get_nodes = wrap_explorer("get_nodes")
Api.tree.find_file = wrap(actions.tree.find_file.fn) Api.tree.find_file = wrap(actions.tree.find_file.fn)
Api.tree.search_node = wrap(actions.finders.search_node.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) ---@class ApiCollapseOpts
---@field keep_buffers boolean|nil default false
Api.tree.collapse_all = wrap(actions.tree.modifiers.collapse.all)
---@class ApiTreeExpandOpts
---@field expand_until (fun(expansion_count: integer, node: Node): boolean)|nil
Api.tree.expand_all = wrap_node(actions.tree.modifiers.expand.all)
Api.tree.toggle_enable_filters = wrap_explorer_member("filters", "toggle") Api.tree.toggle_enable_filters = wrap_explorer_member("filters", "toggle")
Api.tree.toggle_gitignore_filter = wrap_explorer_member_args("filters", "toggle", "git_ignored") Api.tree.toggle_gitignore_filter = wrap_explorer_member_args("filters", "toggle", "git_ignored")
Api.tree.toggle_git_clean_filter = wrap_explorer_member_args("filters", "toggle", "git_clean") Api.tree.toggle_git_clean_filter = wrap_explorer_member_args("filters", "toggle", "git_clean")
@@ -312,6 +320,9 @@ Api.node.navigate.diagnostics.prev_recursive = wrap_node(actions.moves.item.fn({
Api.node.navigate.opened.next = wrap_node(actions.moves.item.fn({ where = "next", what = "opened" })) 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.node.navigate.opened.prev = wrap_node(actions.moves.item.fn({ where = "prev", what = "opened" }))
Api.node.expand = wrap_node(actions.tree.modifiers.expand.node)
Api.node.collapse = wrap_node(actions.tree.modifiers.collapse.node)
---@class ApiNodeDeleteWipeBufferOpts ---@class ApiNodeDeleteWipeBufferOpts
---@field force boolean|nil default false ---@field force boolean|nil default false

View File

@@ -8,6 +8,7 @@ M.Event = {
Ready = "Ready", Ready = "Ready",
WillRenameNode = "WillRenameNode", WillRenameNode = "WillRenameNode",
NodeRenamed = "NodeRenamed", NodeRenamed = "NodeRenamed",
TreePreOpen = "TreePreOpen",
TreeOpen = "TreeOpen", TreeOpen = "TreeOpen",
TreeClose = "TreeClose", TreeClose = "TreeClose",
WillCreateFile = "WillCreateFile", WillCreateFile = "WillCreateFile",
@@ -91,6 +92,11 @@ function M._dispatch_folder_removed(folder_name)
dispatch(M.Event.FolderRemoved, { folder_name = folder_name }) dispatch(M.Event.FolderRemoved, { folder_name = folder_name })
end end
--@private
function M._dispatch_on_tree_pre_open()
dispatch(M.Event.TreePreOpen, nil)
end
--@private --@private
function M._dispatch_on_tree_open() function M._dispatch_on_tree_open()
dispatch(M.Event.TreeOpen, nil) dispatch(M.Event.TreeOpen, nil)

View File

@@ -101,10 +101,19 @@ function Explorer:create_autocmds()
vim.api.nvim_create_autocmd("BufReadPost", { vim.api.nvim_create_autocmd("BufReadPost", {
group = self.augroup_id, group = self.augroup_id,
callback = function(data) callback = function(data)
if (self.filters.state.no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then -- only handle normal files
if vim.bo[data.buf].buftype ~= "" then
return
end
if self.filters.state.no_buffer then
-- full reload is required to update the filter state
utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function() utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
self:reload_explorer() self:reload_explorer()
end) end)
elseif self.opts.renderer.highlight_opened_files ~= "none" then
-- draw to update opened highlight
self.renderer:draw()
end end
end, end,
}) })
@@ -113,10 +122,21 @@ function Explorer:create_autocmds()
vim.api.nvim_create_autocmd("BufUnload", { vim.api.nvim_create_autocmd("BufUnload", {
group = self.augroup_id, group = self.augroup_id,
callback = function(data) callback = function(data)
if (self.filters.state.no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then -- only handle normal files
if vim.bo[data.buf].buftype ~= "" then
return
end
if self.filters.state.no_buffer then
-- full reload is required to update the filter state
utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function() utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
self:reload_explorer() self:reload_explorer()
end) end)
elseif self.opts.renderer.highlight_opened_files ~= "none" then
-- draw to update opened highlight; must be delayed as the buffer is still loaded during BufUnload
vim.schedule(function()
self.renderer:draw()
end)
end end
end, end,
}) })
@@ -214,8 +234,9 @@ function Explorer:reload(node, project)
end end
local abs = utils.path_join({ cwd, name }) local abs = utils.path_join({ cwd, name })
---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_lstat(abs) -- path incorrectly specified as an integer
local stat = vim.loop.fs_lstat(abs) ---@diagnostic disable-line param-type-mismatch
local filter_reason = self.filters:should_filter_as_reason(abs, stat, filter_status) local filter_reason = self.filters:should_filter_as_reason(abs, stat, filter_status)
if filter_reason == FILTER_REASON.none then if filter_reason == FILTER_REASON.none then
@@ -373,8 +394,9 @@ function Explorer:populate_children(handle, cwd, node, project, parent)
if Watcher.is_fs_event_capable(abs) then if Watcher.is_fs_event_capable(abs) then
local profile = log.profile_start("populate_children %s", abs) local profile = log.profile_start("populate_children %s", abs)
---@type uv.fs_stat.result|nil -- path incorrectly specified as an integer
local stat = vim.loop.fs_lstat(abs) local stat = vim.loop.fs_lstat(abs) ---@diagnostic disable-line param-type-mismatch
local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status) local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status)
if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] then if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] then
local child = node_factory.create({ local child = node_factory.create({

View File

@@ -193,9 +193,10 @@ function M.get_toplevel(path)
end end
end end
-- attempt to fetch toplevel -- attempt to fetch toplevel, cache if untracked
local toplevel, git_dir = git_utils.get_toplevel(path) local toplevel, git_dir = git_utils.get_toplevel(path)
if not toplevel or not git_dir then if not toplevel or not git_dir then
M._toplevels_by_path[path] = false
return nil return nil
end end
local toplevel_norm = vim.fn.fnamemodify(toplevel, ":p") local toplevel_norm = vim.fn.fnamemodify(toplevel, ":p")

View File

@@ -5,6 +5,19 @@ local M = {
use_cygpath = false, use_cygpath = false,
} }
--- Execute system command
---@param cmd string[]
---@return string stdout
---@return integer exit code
local function system(cmd)
if vim.fn.has("nvim-0.10") == 1 then
local obj = vim.system(cmd):wait()
return obj.stdout or "", obj.code
else
return vim.fn.system(cmd), vim.v.shell_error
end
end
--- Retrieve the git toplevel directory --- Retrieve the git toplevel directory
---@param cwd string path ---@param cwd string path
---@return string|nil toplevel absolute path ---@return string|nil toplevel absolute path
@@ -16,12 +29,12 @@ function M.get_toplevel(cwd)
local cmd = { "git", "-C", cwd, "rev-parse", "--show-toplevel", "--absolute-git-dir" } local cmd = { "git", "-C", cwd, "rev-parse", "--show-toplevel", "--absolute-git-dir" }
log.line("git", "%s", table.concat(cmd, " ")) log.line("git", "%s", table.concat(cmd, " "))
local out = vim.fn.system(cmd) local out, exitCode = system(cmd)
log.raw("git", out) log.raw("git", out)
log.profile_end(profile) log.profile_end(profile)
if vim.v.shell_error ~= 0 or not out or #out == 0 or out:match("fatal") then if exitCode ~= 0 or not out or #out == 0 or out:match("fatal") then
return nil, nil return nil, nil
end end
@@ -73,7 +86,7 @@ function M.should_show_untracked(cwd)
local cmd = { "git", "-C", cwd, "config", "status.showUntrackedFiles" } local cmd = { "git", "-C", cwd, "config", "status.showUntrackedFiles" }
log.line("git", table.concat(cmd, " ")) log.line("git", table.concat(cmd, " "))
local has_untracked = vim.fn.system(cmd) local has_untracked = system(cmd)
log.raw("git", has_untracked) log.raw("git", has_untracked)
log.profile_end(profile) log.profile_end(profile)

View File

@@ -96,7 +96,7 @@ function M.default_on_attach(bufnr)
vim.keymap.set("n", "S", api.tree.search_node, opts("Search")) vim.keymap.set("n", "S", api.tree.search_node, opts("Search"))
vim.keymap.set("n", "u", api.fs.rename_full, opts("Rename: Full Path")) vim.keymap.set("n", "u", api.fs.rename_full, opts("Rename: Full Path"))
vim.keymap.set("n", "U", api.tree.toggle_custom_filter, opts("Toggle Filter: Hidden")) vim.keymap.set("n", "U", api.tree.toggle_custom_filter, opts("Toggle Filter: Hidden"))
vim.keymap.set("n", "W", api.tree.collapse_all, opts("Collapse")) vim.keymap.set("n", "W", api.tree.collapse_all, opts("Collapse All"))
vim.keymap.set("n", "x", api.fs.cut, opts("Cut")) vim.keymap.set("n", "x", api.fs.cut, opts("Cut"))
vim.keymap.set("n", "y", api.fs.copy.filename, opts("Copy Name")) vim.keymap.set("n", "y", api.fs.copy.filename, opts("Copy Name"))
vim.keymap.set("n", "Y", api.fs.copy.relative_path, opts("Copy Relative Path")) vim.keymap.set("n", "Y", api.fs.copy.relative_path, opts("Copy Relative Path"))

View File

@@ -60,6 +60,13 @@ local function refactored(opts)
end end
end end
utils.move_missing_val(opts, "update_focused_file", "ignore_list", opts, "update_focused_file.update_root", "ignore_list", true) utils.move_missing_val(opts, "update_focused_file", "ignore_list", opts, "update_focused_file.update_root", "ignore_list", true)
-- 2025/04/30
if opts.renderer and opts.renderer.icons and type(opts.renderer.icons.padding) == "string" then
local icons_padding = opts.renderer.icons.padding
opts.renderer.icons.padding = {}
opts.renderer.icons.padding.icon = icons_padding
end
end end
local function deprecated(opts) local function deprecated(opts)

View File

@@ -1,6 +1,5 @@
local view = require("nvim-tree.view") local view = require("nvim-tree.view")
local core = require("nvim-tree.core") local core = require("nvim-tree.core")
local events = require("nvim-tree.events")
local notify = require("nvim-tree.notify") local notify = require("nvim-tree.notify")
---@class LibOpenOpts ---@class LibOpenOpts
@@ -130,7 +129,6 @@ function M.open(opts)
open_view_and_draw() open_view_and_draw()
end end
view.restore_tab_state() view.restore_tab_state()
events._dispatch_on_tree_open()
end end
function M.setup(opts) function M.setup(opts)

View File

@@ -135,12 +135,12 @@ end
function Builder:format_line(indent_markers, arrows, icon, name, node) function Builder:format_line(indent_markers, arrows, icon, name, node)
local added_len = 0 local added_len = 0
local function add_to_end(t1, t2) local function add_to_end(t1, t2)
if not t2 then if not t2 or vim.tbl_isempty(t2) then
return return
end end
for _, v in ipairs(t2) do for _, v in ipairs(t2) do
if added_len > 0 then if added_len > 0 then
table.insert(t1, { str = self.explorer.opts.renderer.icons.padding }) table.insert(t1, { str = self.explorer.opts.renderer.icons.padding.icon })
end end
table.insert(t1, v) table.insert(t1, v)
end end

View File

@@ -1,6 +1,7 @@
local M = {} local M = {}
local utils = require("nvim-tree.utils") local utils = require("nvim-tree.utils")
local view = require("nvim-tree.view")
local function hide(win) local function hide(win)
if win then if win then
@@ -32,7 +33,7 @@ local function effective_win_width()
return win_width - win_info[1].textoff return win_width - win_info[1].textoff
end end
local function show() local function show(opts)
local line_nr = vim.api.nvim_win_get_cursor(0)[1] local line_nr = vim.api.nvim_win_get_cursor(0)[1]
if vim.wo.wrap then if vim.wo.wrap then
return return
@@ -52,6 +53,11 @@ local function show()
local text_width = vim.fn.strdisplaywidth(vim.fn.substitute(line, "[^[:print:]]*$", "", "g")) local text_width = vim.fn.strdisplaywidth(vim.fn.substitute(line, "[^[:print:]]*$", "", "g"))
local win_width = effective_win_width() local win_width = effective_win_width()
-- windows width reduced by right aligned icons
local icon_ns_id = vim.api.nvim_get_namespaces()["NvimTreeExtmarks"]
local icon_extmarks = vim.api.nvim_buf_get_extmarks(0, icon_ns_id, { line_nr - 1, 0 }, { line_nr - 1, -1 }, { details = true })
win_width = win_width - utils.extmarks_length(icon_extmarks)
if text_width < win_width then if text_width < win_width then
return return
end end
@@ -64,7 +70,9 @@ local function show()
height = 1, height = 1,
noautocmd = true, noautocmd = true,
style = "minimal", style = "minimal",
border = "none"
}) })
vim.wo[M.popup_win].winhl = view.View.winopts.winhl
local ns_id = vim.api.nvim_get_namespaces()["NvimTreeHighlights"] local ns_id = vim.api.nvim_get_namespaces()["NvimTreeHighlights"]
local extmarks = vim.api.nvim_buf_get_extmarks(0, ns_id, { line_nr - 1, 0 }, { line_nr - 1, -1 }, { details = true }) local extmarks = vim.api.nvim_buf_get_extmarks(0, ns_id, { line_nr - 1, 0 }, { line_nr - 1, -1 }, { details = true })
@@ -87,7 +95,10 @@ local function show()
end end
end end
end end
vim.cmd([[ setlocal nowrap cursorline noswapfile nobuflisted buftype=nofile bufhidden=wipe ]]) vim.cmd([[ setlocal nowrap noswapfile nobuflisted buftype=nofile bufhidden=wipe ]])
if opts.view.cursorline then
vim.cmd([[ setlocal cursorline cursorlineopt=both ]])
end
end) end)
end end
@@ -113,7 +124,7 @@ M.setup = function(opts)
pattern = { "NvimTree_*" }, pattern = { "NvimTree_*" },
callback = function() callback = function()
if utils.is_nvim_tree_buf(0) then if utils.is_nvim_tree_buf(0) then
show() show(opts)
end end
end, end,
}) })

View File

@@ -95,15 +95,15 @@ function M.get_arrows(node)
local dir = node:as(DirectoryNode) local dir = node:as(DirectoryNode)
if dir then if dir then
if dir.open then if dir.open then
str = M.config.icons.glyphs.folder["arrow_open"] .. " " str = M.config.icons.glyphs.folder["arrow_open"] .. M.config.icons.padding.folder_arrow
hl = "NvimTreeFolderArrowOpen" hl = "NvimTreeFolderArrowOpen"
else else
str = M.config.icons.glyphs.folder["arrow_closed"] .. " " str = M.config.icons.glyphs.folder["arrow_closed"] .. M.config.icons.padding.folder_arrow
end end
elseif M.config.indent_markers.enable then elseif M.config.indent_markers.enable then
str = "" str = ""
else else
str = " " str = " " .. string.rep(" ", #M.config.icons.padding.folder_arrow)
end end
return { str = str, hl = { hl } } return { str = str, hl = { hl } }

View File

@@ -62,7 +62,7 @@ function GitDecorator:build_icons_by_status(glyphs)
self.icons_by_status.ignored = { str = glyphs.ignored, hl = { "NvimTreeGitIgnoredIcon" }, ord = 7 } self.icons_by_status.ignored = { str = glyphs.ignored, hl = { "NvimTreeGitIgnoredIcon" }, ord = 7 }
end end
---@param icons GitIconsByXY ---@param icons GitIconsByStatus
function GitDecorator:build_icons_by_xy(icons) function GitDecorator:build_icons_by_xy(icons)
self.icons_by_xy = { self.icons_by_xy = {
["M "] = { icons.staged }, ["M "] = { icons.staged },
@@ -131,7 +131,7 @@ function GitDecorator:build_file_folder_hl_by_xy()
["RM"] = "NvimTreeGitFileRenamedHL", ["RM"] = "NvimTreeGitFileRenamedHL",
[" R"] = "NvimTreeGitFileRenamedHL", [" R"] = "NvimTreeGitFileRenamedHL",
["!!"] = "NvimTreeGitFileIgnoredHL", ["!!"] = "NvimTreeGitFileIgnoredHL",
[" A"] = "none", [" A"] = "NvimTreeGitFileNewHL",
} }
self.folder_hl_by_xy = {} self.folder_hl_by_xy = {}

View File

@@ -112,9 +112,8 @@ function Decorator:define_sign(icon)
vim.fn.sign_undefine(name) vim.fn.sign_undefine(name)
end end
-- don't use sign if not defined -- don't render sign if empty
if #icon.str < 1 then if #icon.str < 1 then
self.icon_placement = "none"
return return
end end

View File

@@ -1,5 +1,4 @@
local Iterator = require("nvim-tree.iterators.node-iterator") local Iterator = require("nvim-tree.iterators.node-iterator")
local notify = require("nvim-tree.notify")
local M = { local M = {
debouncers = {}, debouncers = {},
@@ -173,6 +172,21 @@ function M.find_node_line(node)
return -1 return -1
end end
---@param extmarks vim.api.keyset.get_extmark_item[] as per vim.api.nvim_buf_get_extmarks
---@return number
function M.extmarks_length(extmarks)
local length = 0
for _, extmark in ipairs(extmarks) do
local details = extmark[4]
if details and details.virt_text then
for _, text in ipairs(details.virt_text) do
length = length + vim.fn.strchars(text[1])
end
end
end
return length
end
-- get the node in the tree state depending on the absolute path of the node -- get the node in the tree state depending on the absolute path of the node
-- (grouped or hidden too) -- (grouped or hidden too)
---@param path string ---@param path string
@@ -289,13 +303,53 @@ function M.rename_loaded_buffers(old_path, new_path)
end end
end end
local is_windows_drive = function(path)
return (M.is_windows) and (path:match("^%a:\\$") ~= nil)
end
---@param path string path to file or directory ---@param path string path to file or directory
---@return boolean ---@return boolean
function M.file_exists(path) function M.file_exists(path)
if not (M.is_windows or M.is_wsl) then
local _, error = vim.loop.fs_stat(path) local _, error = vim.loop.fs_stat(path)
return error == nil return error == nil
end end
-- Windows is case-insensetive, but case-preserving
-- If a file's name is being changed into itself
-- with different casing, windows will falsely
-- report that file is already existing, so a hand-rolled
-- implementation of checking for existance is needed.
-- Same holds for WSL, since it can sometimes
-- access Windows files directly.
-- For more details see (#3117).
if is_windows_drive(path) then
return vim.fn.isdirectory(path) == 1
end
local parent = vim.fn.fnamemodify(path, ":h")
local filename = vim.fn.fnamemodify(path, ":t")
local handle = vim.loop.fs_scandir(parent)
if not handle then
-- File can not exist if its parent directory does not exist
return false
end
while true do
local name, _ = vim.loop.fs_scandir_next(handle)
if not name then
break
end
if name == filename then
return true
end
end
return false
end
---@param path string ---@param path string
---@return string ---@return string
function M.canonical_path(path) function M.canonical_path(path)
@@ -349,20 +403,6 @@ end
---@param dst_pos string value pos ---@param dst_pos string value pos
---@param remove boolean ---@param remove boolean
function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos, remove) function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos, remove)
local ok, err = pcall(vim.validate, {
src = { src, "table" },
src_path = { src_path, "string" },
src_pos = { src_pos, "string" },
dst = { dst, "table" },
dst_path = { dst_path, "string" },
dst_pos = { dst_pos, "string" },
remove = { remove, "boolean" },
})
if not ok then
notify.warn("move_missing_val: " .. (err or "invalid arguments"))
return
end
for pos in string.gmatch(src_path, "([^%.]+)%.*") do for pos in string.gmatch(src_path, "([^%.]+)%.*") do
if src[pos] and type(src[pos]) == "table" then if src[pos] and type(src[pos]) == "table" then
src = src[pos] src = src[pos]

View File

@@ -254,7 +254,6 @@ local function close(tabpage)
return return
end end
end end
events._dispatch_on_tree_close()
return return
end end
end end
@@ -289,6 +288,7 @@ function M.open(options)
local profile = log.profile_start("view open") local profile = log.profile_start("view open")
events._dispatch_on_tree_pre_open()
create_buffer() create_buffer()
open_window() open_window()
M.resize() M.resize()
@@ -329,14 +329,7 @@ local function grow()
local count = vim.fn.strchars(l) local count = vim.fn.strchars(l)
-- also add space for right-aligned icons -- also add space for right-aligned icons
local extmarks = vim.api.nvim_buf_get_extmarks(M.get_bufnr(), ns_id, { line_nr, 0 }, { line_nr, -1 }, { details = true }) local extmarks = vim.api.nvim_buf_get_extmarks(M.get_bufnr(), ns_id, { line_nr, 0 }, { line_nr, -1 }, { details = true })
for _, extmark in ipairs(extmarks) do count = count + utils.extmarks_length(extmarks)
local virt_texts = extmark[4].virt_text
if virt_texts then
for _, virt_text in ipairs(virt_texts) do
count = count + vim.fn.strchars(virt_text[1])
end
end
end
if resizing_width < count then if resizing_width < count then
resizing_width = count resizing_width = count
end end
@@ -414,6 +407,7 @@ end
---@param opts OpenInWinOpts|nil ---@param opts OpenInWinOpts|nil
function M.open_in_win(opts) function M.open_in_win(opts)
opts = opts or { hijack_current_buf = true, resize = true } opts = opts or { hijack_current_buf = true, resize = true }
events._dispatch_on_tree_pre_open()
if opts.winid and vim.api.nvim_win_is_valid(opts.winid) then if opts.winid and vim.api.nvim_win_is_valid(opts.winid) then
vim.api.nvim_set_current_win(opts.winid) vim.api.nvim_set_current_win(opts.winid)
end end
@@ -425,6 +419,7 @@ function M.open_in_win(opts)
M.reposition_window() M.reposition_window()
M.resize() M.resize()
end end
events._dispatch_on_tree_open()
end end
function M.abandon_current_window() function M.abandon_current_window()
@@ -629,6 +624,7 @@ function M.setup(opts)
M.View.tab = opts.tab M.View.tab = opts.tab
M.View.preserve_window_proportions = options.preserve_window_proportions M.View.preserve_window_proportions = options.preserve_window_proportions
M.View.winopts.cursorline = options.cursorline M.View.winopts.cursorline = options.cursorline
M.View.winopts.cursorlineopt = options.cursorlineopt
M.View.winopts.number = options.number M.View.winopts.number = options.number
M.View.winopts.relativenumber = options.relativenumber M.View.winopts.relativenumber = options.relativenumber
M.View.winopts.signcolumn = options.signcolumn M.View.winopts.signcolumn = options.signcolumn

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
out=$(grep -nr "^--- @" lua) out=$(grep -nr "^--- @" lua)

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/usr/bin/env sh
# run after changing nvim-tree.lua DEFAULT_OPTS or keymap.lua M.default_on_attach # run after changing nvim-tree.lua DEFAULT_OPTS or keymap.lua M.default_on_attach
# scrapes and updates nvim-tree-lua.txt # scrapes and updates nvim-tree-lua.txt

View File

@@ -1,9 +1,11 @@
#!/bin/sh #!/usr/bin/env sh
# Performs a lua-language-server check on all files. # Performs a lua-language-server check on all files.
# luals-out/check.json will be produced on any issues, returning 1. # luals-out/check.json will be produced on any issues, returning 1.
# Outputs only check.json to stdout, all other messages to stderr, to allow jq etc. # Outputs only check.json to stdout, all other messages to stderr, to allow jq etc.
# $VIMRUNTIME specifies neovim runtime path, defaults to "/usr/share/nvim/runtime" if unset. # $VIMRUNTIME specifies neovim runtime path, defaults to "/usr/share/nvim/runtime" if unset.
#
# Call with codestyle-check param to enable only codestyle-check
if [ -z "${VIMRUNTIME}" ]; then if [ -z "${VIMRUNTIME}" ]; then
export VIMRUNTIME="/usr/share/nvim/runtime" export VIMRUNTIME="/usr/share/nvim/runtime"
@@ -17,11 +19,24 @@ FILE_LUARC="${DIR_OUT}/luarc.json"
rm -rf "${DIR_OUT}" rm -rf "${DIR_OUT}"
mkdir "${DIR_OUT}" mkdir "${DIR_OUT}"
# Uncomment runtime.version for strict neovim baseline 5.1 case "${1}" in
# It is not set normally, to prevent luals loading 5.1 and 5.x, resulting in both versions being chosen on vim.lsp.buf.definition() "codestyle-check")
cat "${PWD}/.luarc.json" | sed -E 's/.luals-check-only//g' > "${FILE_LUARC}" jq \
'.diagnostics.neededFileStatus[] = "None" | .diagnostics.neededFileStatus."codestyle-check" = "Any"' \
"${PWD}/.luarc.json" > "${FILE_LUARC}"
# execute inside lua to prevent luals itself from being checked ;;
*)
# Add runtime.version for strict neovim baseline 5.1
# It is not set normally, to prevent luals loading 5.1 and 5.x, resulting in both versions being chosen on vim.lsp.buf.definition
jq \
'."runtime.version" = "Lua 5.1"' \
"${PWD}/.luarc.json" > "${FILE_LUARC}"
;;
esac
# execute inside lua directory to prevent luals itself from being checked
OUT=$(lua-language-server --check="${DIR_SRC}" --configpath="${FILE_LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error) OUT=$(lua-language-server --check="${DIR_SRC}" --configpath="${FILE_LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error)
RC=$? RC=$?