Compare commits

...

42 Commits

Author SHA1 Message Date
Mateusz Russak
fa051cf990 refactor(#2826): multi instance nvim-tree.view 2024-08-04 13:31:11 +02:00
Mateusz Russak
0f2cda6ce0 docs: add missing live filter luadocs 2024-08-04 11:26:14 +02:00
Mateusz Russak
e6374abc7d Merge branch 'live-filter-multiinstace' of github.com:nvim-tree/nvim-tree.lua into live-filter-multiinstace 2024-08-04 11:20:04 +02:00
Mateusz Russak
32314fd3ee Update lua/nvim-tree/api.lua
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-08-04 11:19:31 +02:00
Mateusz Russak
e2853ee4fb Merge branch 'master' into live-filter-multiinstace 2024-08-04 11:19:06 +02:00
Mateusz Russak
85fba095cd Merge branch 'master' into live-filter-multiinstace 2024-07-28 11:28:26 +02:00
Mateusz Russak
d7504b3963 fix: style 2024-07-28 11:26:59 +02:00
Mateusz Russak
a634a1bb4d fix: api and filtration 2024-07-28 11:19:37 +02:00
Mateusz Russak
9deac32a40 refactor: all usages going through the explorer 2024-07-28 10:16:02 +02:00
Everton Jr.
48d0e82f94 feat(#2349): add "right_align" option for renderer.icons.*_placement (#2846)
* feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

* feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

* feat(icon_placement): consolidate doc

* fix: extra namespace added to avoid colision between right_align and full_name features

* style: rename namespace_id

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-28 13:26:22 +10:00
Mateusz Russak
c6ae2431bc Merge branch 'master' into live-filter-multiinstace 2024-07-27 13:26:26 +02:00
Mateusz Russak
82ba116bbd refactor(#2829): multi instance nvim-tree.explorer.sorters (#2835)
* refactor: multi instance nvim-tree.explorer.sorters

* fix: linter errors

* fix: style

* fix: according to code review

* chore: removed comment

* fix: missing cfg params in sorters

* tidy following rebase

* tidy following rebase

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-27 13:54:40 +10:00
Mateusz Russak
908478a0e0 refactor(#2828): multi instance nvim-tree.explorer.filters (#2841)
* refactor(#2828): multi instance nvim-tree.explorer.filters

* fix: style

* fix: apply suggestions from code review

Co-authored-by: Alexander Courtis <alex@courtis.org>

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-27 13:29:27 +10:00
Mateusz Russak
1aa9852cad docs: removed entry about macos rename (#2848) 2024-07-27 12:58:02 +10:00
Mateusz Russak
cc2d8c7475 feat(#2827): Multi Instance: Refactor: nvim-tree.live-filter 2024-07-23 18:53:16 +02:00
Alexander Courtis
4e396b2624 refactor(#2830): multi instance nvim-tree.marks (#2838)
refactor(#2380): multi instance nvim-tree.marks
2024-07-21 16:12:42 +10:00
Everton Jr.
48a9290757 feat: add renderer.highlight_hidden, renderer.icons.show.hidden and renderer.icons.hidden_placement for dotfile icons/highlights (#2840)
* feat(hidden_decorator): Allow hidden (dotfiles) to be highlighted, both icon and name (this not related to git highlights).

Better defaults

squashed

docs(hidden)

docs(hidden)

docs(hidden)

* fix(typo): small typo on hl groups

* feat(hidden_dotfile_highlight): make a file that has a dotfile parent be also a dotfile

* docs: update docs on hidden highlight

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-21 16:00:34 +10:00
Alexander Courtis
b2640685a8 Revert "feat(#2349): add "right_align" option for renderer.icons.*_placement (#2839)"
This reverts commit 1d629a5d3f.
2024-07-21 15:22:24 +10:00
Everton Jr.
1d629a5d3f feat(#2349): add "right_align" option for renderer.icons.*_placement (#2839)
* feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

* feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api

* feat(icon_placement): consolidate doc

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-21 14:49:10 +10:00
github-actions[bot]
f9ff00bc06 chore(master): release nvim-tree 1.5.0 (#2810)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-07-11 16:17:05 +10:00
Samuel Durante
abfd1d1b67 fix(#2813): macos: enable file renaming with changed capitalization (#2814)
* fix(#2813): enable file renaming in `nvim-tree` with changed capitalization

* fix(#2813): check if is macos

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-11 16:15:03 +10:00
Vladimir Levin
2ede0de67b feat(#2598): add api.tree.resize (#2811)
* feat(#2598): Implemented API `tree.resize`

* rely on  when resize

* Fix docs

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-11 15:15:40 +10:00
Epheien
12a9a995a4 fix(#2819): experimental.actions.open_file.relative_path issue following change directory (#2820)
fix issue with the description of epheien in #2819

Co-authored-by: eph <eph@MacBook-Pro.local>
2024-07-07 15:53:04 +10:00
dependabot[bot]
d1957d3472 chore(deps): bump nvim-neorocks/luarocks-tag-release from 5 to 7 (#2808)
Bumps [nvim-neorocks/luarocks-tag-release](https://github.com/nvim-neorocks/luarocks-tag-release) from 5 to 7.
- [Release notes](https://github.com/nvim-neorocks/luarocks-tag-release/releases)
- [Changelog](https://github.com/nvim-neorocks/luarocks-tag-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nvim-neorocks/luarocks-tag-release/compare/v5...v7)

---
updated-dependencies:
- dependency-name: nvim-neorocks/luarocks-tag-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-07 12:55:47 +10:00
Epheien
869c064721 feat(#2127): add experimental.actions.open_file.relative_path to open files with a relative path rather than absolute (#2805)
* temp workaround for issue #2803

* fix #2127 and #2803

* chore(#2127): read the configuration correctly

* feat(#2127): add help

* feat(#2127): normalise relative_path in config hierarchy

* feat(#2127): update help

---------

Co-authored-by: eph <eph@MacBook-Pro.local>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-07-07 12:51:43 +10:00
dependabot[bot]
74e94625b1 chore(deps): bump amannn/action-semantic-pull-request from 5.5.2 to 5.5.3 (#2812)
chore(deps): bump amannn/action-semantic-pull-request

Bumps [amannn/action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request) from 5.5.2 to 5.5.3.
- [Release notes](https://github.com/amannn/action-semantic-pull-request/releases)
- [Changelog](https://github.com/amannn/action-semantic-pull-request/blob/main/CHANGELOG.md)
- [Commits](https://github.com/amannn/action-semantic-pull-request/compare/v5.5.2...v5.5.3)

---
updated-dependencies:
- dependency-name: amannn/action-semantic-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-07 11:23:00 +10:00
Alexander Courtis
8b2c5c678b feat(#2799): filesystem_watchers.ignore_dirs and git.disable_for_dirs may be functions (#2800)
feat(#2799): filesystem_watchers.ignore_dirs and git.disable_for_dirs may be functions
2024-06-23 11:44:45 +10:00
github-actions[bot]
2086e564c4 chore(master): release nvim-tree 1.4.0 (#2785)
* chore(master): release nvim-tree 1.4.0

* add neovim minimum version 0.9 notice

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-06-09 12:43:06 +10:00
Alexander Courtis
1cac8005df chore: release 1.4.0
Release-As: 1.4.0
2024-06-09 12:30:45 +10:00
Alexander Courtis
8704b6f7fc chore(#2787): minimum nvim version 0.9, replace 0.10 deprecated, enable deprecated warnings (#2788)
* refactor(#2787): replace deprecated

* refactor(#2787): enable deprecated checks

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): use inline deprecation disabling

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): replace deprecated

* refactor(#2787): deprecated are now warnings

* refactor(#2787): 0.9 is the minimum supported version

* Revert "refactor(#2787): replace deprecated"

This reverts commit b6b4c32fcb.

* refactor(#2787): suppress deprecated until 0.11

* refactor(#2787): minimum nvim version 0.8 -> 0.9

* refactor(#2787): reset globals

* refactor(#2787): explicitly check for vim.diagnostic.is_enabled function presence
2024-06-09 12:24:35 +10:00
Alexander Courtis
26632f496e chore(#2731): neovim luadoc 0.10 compliance (#2786)
* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings, type gymnastics

* refactor(#2731): resolve warnings, type gymnastics

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): handle cwd unavailable when opening

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings, type gymnastics

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): style

* refactor(#2731): add _meta library, explicit check disables

* refactor(#2731): add lua-language-server manual install instructions

* refactor(#2731): resolve warnings

* refactor(#2731): explicitly set all diagnostics, reduce deprecated to hint

* Revert "refactor(#2731): resolve warnings"

This reverts commit 9c0526b7b0.

* Revert "refactor(#2731): resolve warnings"

This reverts commit f534fbc606.

* refactor(#2731): handle directory unavailable when deleting

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): resolve warnings

* refactor(#2731): handle directory unavailable when creating explorer

* refactor(#2731): add all nvim lua libraries

* refactor(#2731): resolve warnings

* refactor(#2731): remove vim global

* refactor(#2731): disable deprecated until we have a 0.9->0.10 story
2024-06-01 15:24:03 +10:00
Alexander Courtis
5a87ffe35c ci: release tags vMAJOR.MINOR.PATCH (#2772)
* ci: release tags vMAJOR.MINOR.PATCH

* ci: tidy luarocks release naming
2024-05-28 16:11:06 +10:00
Alexander Courtis
517e4fbb9e revert(#2781): "refactor: replace deprecated use of vim.diagnostic.is_disabled()" (#2784)
Revert "refactor: replace deprecated use of vim.diagnostic.is_disabled()  (#2781)"

This reverts commit 4215f33da5.
2024-05-26 11:34:03 +10:00
Alexander Courtis
4c8ddee453 ci: add lua-language-server 3.9.1 (#2782)
* add lua-language-server 3.9.1

* remove lua-language-server 3.7.3
2024-05-25 15:42:38 +10:00
Zachary Rizer
4215f33da5 refactor: replace deprecated use of vim.diagnostic.is_disabled() (#2781)
* Deprecation fix

* Deprecation fix

* remove unnecessary assignment

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-05-25 14:42:34 +10:00
github-actions[bot]
2bc725a3eb chore(master): release nvim-tree 1.3.3 (#2776)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-05-14 10:44:50 +10:00
Jacob Kania
340d3a9795 fix: nil access exception with git integration when changing branches (#2774)
Fix nil access exception appearing when changing branches
2024-05-14 10:31:56 +10:00
dependabot[bot]
edd4e25fd4 chore(deps): bump actions/checkout from 3 to 4 (#2773)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 12:14:07 +03:00
github-actions[bot]
78c4c083ed chore(master): release nvim-tree 1.3.2 (#2771)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-05-12 14:45:55 +10:00
Andrew Plaza
acffab931a ci: luarocks releases (#2764)
* add luarocks upload

* refactor

* restrict to full semver versions

* tweak luarocks descriptions

* remove test release following successful run

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-05-12 14:37:49 +10:00
Alexander Courtis
64f61e4c91 fix(#925): handle newlines in file names (#2754) 2024-05-04 13:51:13 +10:00
Alexander Courtis
347e1eb352 fix(#2758): use nvim-webdevicons default file icon, not renderer.icons.glyphs.default, as per :help (#2759)
fix(#2758): use nvim-webdevicons default for default files
2024-04-30 11:32:51 +10:00
66 changed files with 1658 additions and 881 deletions

View File

@@ -67,7 +67,7 @@ jobs:
strategy: strategy:
matrix: matrix:
nvim_version: [ stable, nightly ] nvim_version: [ stable, nightly ]
luals_version: [ 3.7.3 ] luals_version: [ 3.9.1 ]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

37
.github/workflows/luarocks-release.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Luarocks Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
workflow_dispatch:
jobs:
luarocks-upload:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: LuaRocks Upload
uses: nvim-neorocks/luarocks-tag-release@v7
env:
LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }}
with:
summary: A File Explorer For Neovim
detailed_description: |
Automatic updates
File type icons
Git integration
Diagnostics integration - LSP and COC
(Live) filtering
Cut, copy, paste, rename, delete, create etc.
Highly customisable
Rich API
license: "GPL-3.0"
labels: neovim
dependencies: |
nvim-web-devicons

View File

@@ -25,9 +25,13 @@ jobs:
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/google-github-actions/release-please-action.git"
git tag -d v${{ steps.release.outputs.major }} || true 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 }} || true
git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} || true
git push origin :v${{ steps.release.outputs.major }} || true git push origin :v${{ steps.release.outputs.major }} || true
git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true
git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} || true
git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}" git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}"
git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}" git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}"
git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }}"
git push origin v${{ steps.release.outputs.major }} git push origin v${{ steps.release.outputs.major }}
git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}
git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }}

View File

@@ -14,6 +14,6 @@ jobs:
semantic-pr-subject: semantic-pr-subject:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: amannn/action-semantic-pull-request@v5.5.2 - uses: amannn/action-semantic-pull-request@v5.5.3
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
/luals-out/ /luals-out/
/luals/ /luals/
# backup vim files
*~

View File

@@ -1,17 +1,15 @@
{ {
"$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" : "Lua 5.1", "runtime.version": "Lua 5.1",
"workspace": { "workspace": {
"library": [ "library": [
"$VIMRUNTIME/lua/vim/lsp", "$VIMRUNTIME/lua/vim",
"${3rd}/luv/library" "${3rd}/luv/library"
] ]
}, },
"diagnostics": { "diagnostics": {
"libraryFiles": "Disable", "libraryFiles": "Disable",
"globals": [ "globals": [],
"vim"
],
"neededFileStatus": { "neededFileStatus": {
"ambiguity-1": "Any", "ambiguity-1": "Any",
"assign-type-mismatch": "Any", "assign-type-mismatch": "Any",
@@ -33,11 +31,19 @@
"duplicate-index": "Any", "duplicate-index": "Any",
"duplicate-set-field": "Any", "duplicate-set-field": "Any",
"empty-block": "Any", "empty-block": "Any",
"global-element": "Any",
"global-in-nil-env": "Any", "global-in-nil-env": "Any",
"incomplete-signature-doc": "None",
"inject-field": "Any",
"invisible": "Any",
"lowercase-global": "Any", "lowercase-global": "Any",
"missing-fields": "Any",
"missing-global-doc": "Any",
"missing-local-export-doc": "None",
"missing-parameter": "Any", "missing-parameter": "Any",
"missing-return": "Any", "missing-return": "Any",
"missing-return-value": "Any", "missing-return-value": "Any",
"name-style-check": "None",
"need-check-nil": "Any", "need-check-nil": "Any",
"newfield-call": "Any", "newfield-call": "Any",
"newline-call": "Any", "newline-call": "Any",
@@ -70,4 +76,3 @@
} }
} }
} }

View File

@@ -1,3 +1,3 @@
{ {
".": "1.3.1" ".": "1.5.0"
} }

View File

@@ -1,5 +1,52 @@
# Changelog # Changelog
## [1.5.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.4.0...nvim-tree-v1.5.0) (2024-07-11)
### Features
* **#2127:** add experimental.actions.open_file.relative_path to open files with a relative path rather than absolute ([#2805](https://github.com/nvim-tree/nvim-tree.lua/issues/2805)) ([869c064](https://github.com/nvim-tree/nvim-tree.lua/commit/869c064721a6c2091f22c3541e8f0ff958361771))
* **#2598:** add api.tree.resize ([#2811](https://github.com/nvim-tree/nvim-tree.lua/issues/2811)) ([2ede0de](https://github.com/nvim-tree/nvim-tree.lua/commit/2ede0de67b47e89e2b4cb488ea3f58b8f5a8c90a))
* **#2799:** `filesystem_watchers.ignore_dirs` and `git.disable_for_dirs` may be functions ([#2800](https://github.com/nvim-tree/nvim-tree.lua/issues/2800)) ([8b2c5c6](https://github.com/nvim-tree/nvim-tree.lua/commit/8b2c5c678be4b49dff6a2df794877000113fd77b))
* **#2799:** filesystem_watchers.ignore_dirs and git.disable_for_dirs may be functions ([8b2c5c6](https://github.com/nvim-tree/nvim-tree.lua/commit/8b2c5c678be4b49dff6a2df794877000113fd77b))
### Bug Fixes
* **#2813:** macos: enable file renaming with changed capitalization ([#2814](https://github.com/nvim-tree/nvim-tree.lua/issues/2814)) ([abfd1d1](https://github.com/nvim-tree/nvim-tree.lua/commit/abfd1d1b6772540364743531cc0331e08a0027a9))
* **#2819:** experimental.actions.open_file.relative_path issue following change directory ([#2820](https://github.com/nvim-tree/nvim-tree.lua/issues/2820)) ([12a9a99](https://github.com/nvim-tree/nvim-tree.lua/commit/12a9a995a455d2c2466e47140663275365a5d2fc))
## [1.4.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.3.3...nvim-tree-v1.4.0) (2024-06-09)
### Notice
* Neovim 0.9 is now the minimum supported version; please upgrade to neovim release version 0.9 or 0.10.
### Reverts
* **#2781:** "refactor: replace deprecated use of vim.diagnostic.is_disabled()" ([#2784](https://github.com/nvim-tree/nvim-tree.lua/issues/2784)) ([517e4fb](https://github.com/nvim-tree/nvim-tree.lua/commit/517e4fbb9ef3c0986da7047f44b4b91a2400f93c))
### Miscellaneous Chores
* release 1.4.0 ([1cac800](https://github.com/nvim-tree/nvim-tree.lua/commit/1cac8005df6da484c97499247754afa59fef92db))
## [1.3.3](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.3.2...nvim-tree-v1.3.3) (2024-05-14)
### Bug Fixes
* nil access exception with git integration when changing branches ([#2774](https://github.com/nvim-tree/nvim-tree.lua/issues/2774)) ([340d3a9](https://github.com/nvim-tree/nvim-tree.lua/commit/340d3a9795e06bdd1814228de398cd510f9bfbb0))
## [1.3.2](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.3.1...nvim-tree-v1.3.2) (2024-05-12)
### Bug Fixes
* **#2758:** use nvim-webdevicons default file icon, not renderer.icons.glyphs.default, as per :help ([#2759](https://github.com/nvim-tree/nvim-tree.lua/issues/2759)) ([347e1eb](https://github.com/nvim-tree/nvim-tree.lua/commit/347e1eb35264677f66a79466bb5e3d111968e12c))
* **#2758:** use nvim-webdevicons default for default files ([347e1eb](https://github.com/nvim-tree/nvim-tree.lua/commit/347e1eb35264677f66a79466bb5e3d111968e12c))
* **#925:** handle newlines in file names ([#2754](https://github.com/nvim-tree/nvim-tree.lua/issues/2754)) ([64f61e4](https://github.com/nvim-tree/nvim-tree.lua/commit/64f61e4c913047a045ff90bd188dd3b54ee443cf))
## [1.3.1](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.3.0...nvim-tree-v1.3.1) (2024-04-25) ## [1.3.1](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.3.0...nvim-tree-v1.3.1) (2024-04-25)

View File

@@ -61,6 +61,15 @@ Assumes `$VIMRUNTIME` is `/usr/share/nvim/runtime`. Adjust as necessary e.g.
VIMRUNTIME="/my/path/to/runtime" make check 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.
```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
PATH="luals/bin:${PATH}" make check
```
# 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

@@ -22,7 +22,7 @@ style-doc:
scripts/doc-comments.sh scripts/doc-comments.sh
luals: luals:
scripts/luals-check.sh @scripts/luals-check.sh
# #
# fixes # fixes

View File

@@ -28,7 +28,7 @@ Questions and general support: [Discussions](https://github.com/nvim-tree/nvim-t
## Requirements ## Requirements
[neovim >=0.8.0](https://github.com/neovim/neovim/wiki/Installing-Neovim) [neovim >=0.9.0](https://github.com/neovim/neovim/wiki/Installing-Neovim)
[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" [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"

View File

@@ -103,7 +103,7 @@ Git Integration
Requirements Requirements
This file explorer requires `neovim >= 0.8.0` This file explorer requires `neovim >= 0.9.0`
============================================================================== ==============================================================================
2. QUICKSTART *nvim-tree-quickstart* 2. QUICKSTART *nvim-tree-quickstart*
@@ -428,6 +428,7 @@ Following is the default configuration. See |nvim-tree-opts| for details.
highlight_diagnostics = "none", highlight_diagnostics = "none",
highlight_opened_files = "none", highlight_opened_files = "none",
highlight_modified = "none", highlight_modified = "none",
highlight_hidden = "none",
highlight_bookmarks = "none", highlight_bookmarks = "none",
highlight_clipboard = "name", highlight_clipboard = "name",
indent_markers = { indent_markers = {
@@ -454,6 +455,7 @@ Following is the default configuration. See |nvim-tree-opts| for details.
}, },
git_placement = "before", git_placement = "before",
modified_placement = "after", modified_placement = "after",
hidden_placement = "after",
diagnostics_placement = "signcolumn", diagnostics_placement = "signcolumn",
bookmarks_placement = "signcolumn", bookmarks_placement = "signcolumn",
padding = " ", padding = " ",
@@ -464,6 +466,7 @@ Following is the default configuration. See |nvim-tree-opts| for details.
folder_arrow = true, folder_arrow = true,
git = true, git = true,
modified = true, modified = true,
hidden = false,
diagnostics = true, diagnostics = true,
bookmarks = true, bookmarks = true,
}, },
@@ -472,6 +475,7 @@ Following is the default configuration. See |nvim-tree-opts| for details.
symlink = "", symlink = "",
bookmark = "󰆤", bookmark = "󰆤",
modified = "●", modified = "●",
hidden = "󰜌",
folder = { folder = {
arrow_closed = "", arrow_closed = "",
arrow_open = "", arrow_open = "",
@@ -620,7 +624,13 @@ Following is the default configuration. See |nvim-tree-opts| for details.
default_yes = false, default_yes = false,
}, },
}, },
experimental = {}, experimental = {
actions = {
open_file = {
relative_path = false,
},
},
},
log = { log = {
enable = false, enable = false,
truncate = false, truncate = false,
@@ -832,7 +842,6 @@ Use nvim-tree in a floating window.
Highlight precedence, additive: Highlight precedence, additive:
git < opened < modified < bookmarked < diagnostics < copied < cut git < opened < modified < bookmarked < diagnostics < copied < cut
Neovim <= 0.8 will only show the highest.
*nvim-tree.renderer.add_trailing* *nvim-tree.renderer.add_trailing*
Appends a trailing slash to folder names. Appends a trailing slash to folder names.
@@ -899,6 +908,13 @@ Requires |nvim-tree.modified.enable|
Value can be `"none"`, `"icon"`, `"name"` or `"all"` Value can be `"none"`, `"icon"`, `"name"` or `"all"`
Type: `string`, Default `"none"` Type: `string`, Default `"none"`
*nvim-tree.renderer.highlight_hidden*
Highlight icons and/or names for hidden files (dotfiles) using the
`NvimTreeHiddenFileHL` highlight group.
Requires |nvim-tree.hidden.enable|
Value can be `"none"`, `"icon"`, `"name"` or `"all"`
Type: `string`, Default `"none"`
*nvim-tree.renderer.highlight_bookmarks* *nvim-tree.renderer.highlight_bookmarks*
Highlight bookmarked using the `NvimTreeBookmarkHL` group. Highlight bookmarked using the `NvimTreeBookmarkHL` group.
Value can be `"none"`, `"icon"`, `"name"` or `"all"` Value can be `"none"`, `"icon"`, `"name"` or `"all"`
@@ -937,7 +953,13 @@ Configuration options for tree indent markers.
Configuration options for icons. Configuration options for icons.
Icon order and sign column precedence: Icon order and sign column precedence:
git < modified < bookmarked < diagnostics git < hidden < modified < bookmarked < diagnostics
`renderer.icons.*_placement` options may be:
- `"before"` : before file/folder, after the file/folders icons
- `"after"` : after file/folder
- `"signcolumn"` : far left, requires |nvim-tree.view.signcolumn| enabled
- `"right_align"` : far right
*nvim-tree.renderer.icons.web_devicons* *nvim-tree.renderer.icons.web_devicons*
Configure optional plugin `"nvim-tree/nvim-web-devicons"` Configure optional plugin `"nvim-tree/nvim-web-devicons"`
@@ -967,27 +989,23 @@ Icon order and sign column precedence:
Type: `boolean`, Default: `true` Type: `boolean`, Default: `true`
*nvim-tree.renderer.icons.git_placement* *nvim-tree.renderer.icons.git_placement*
Place where the git icons will be rendered. Git icons placement.
Can be `"after"` or `"before"` filename (after the file/folders icons)
or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled).
Type: `string`, Default: `"before"` Type: `string`, Default: `"before"`
*nvim-tree.renderer.icons.diagnostics_placement* *nvim-tree.renderer.icons.diagnostics_placement*
Place where the diagnostics icon will be rendered. Diganostic icon placement.
Can be `"after"` or `"before"` filename (after the file/folders icons)
or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled).
Type: `string`, Default: `"signcolumn"` Type: `string`, Default: `"signcolumn"`
*nvim-tree.renderer.icons.modified_placement* *nvim-tree.renderer.icons.modified_placement*
Place where the modified icon will be rendered. Modified icon placement.
Can be `"after"` or `"before"` filename (after the file/folders icons) Type: `string`, Default: `"after"`
or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled).
*nvim-tree.renderer.icons.hidden_placement*
Hidden icon placement.
Type: `string`, Default: `"after"` Type: `string`, Default: `"after"`
*nvim-tree.renderer.icons.bookmarks_placement* *nvim-tree.renderer.icons.bookmarks_placement*
Place where the bookmarks icon will be rendered. Bookmark icon placement.
Can be `"after"` or `"before"` filename (after the file/folders icons)
or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled).
Type: `string`, Default: `signcolumn` Type: `string`, Default: `signcolumn`
*nvim-tree.renderer.icons.padding* *nvim-tree.renderer.icons.padding*
@@ -1000,7 +1018,7 @@ Icon order and sign column precedence:
*nvim-tree.renderer.icons.show* *nvim-tree.renderer.icons.show*
Configuration options for showing icon types. Configuration options for showing icon types.
Left to right order: file/folder, git, modified, diagnostics, bookmarked. Left to right order: file/folder, git, modified, hidden, diagnostics, bookmarked.
*nvim-tree.renderer.icons.show.file* *nvim-tree.renderer.icons.show.file*
Show an icon before the file name. Show an icon before the file name.
@@ -1025,6 +1043,11 @@ Icon order and sign column precedence:
Requires |modified.enable| `= true` Requires |modified.enable| `= true`
Type: `boolean`, Default: `true` Type: `boolean`, Default: `true`
*nvim-tree.renderer.icons.show.hidden*
Show a hidden icon, see |renderer.icons.hidden_placement|
Requires |hidden.enable| `= true`
Type: `boolean`, Default: `true`
*nvim-tree.renderer.icons.show.diagnostics* *nvim-tree.renderer.icons.show.diagnostics*
Show a diagnostics status icon, see |renderer.icons.diagnostics_placement| Show a diagnostics status icon, see |renderer.icons.diagnostics_placement|
Requires |diagnostics.enable| `= true` Requires |diagnostics.enable| `= true`
@@ -1052,6 +1075,10 @@ Icon order and sign column precedence:
Icon to display for modified files. Icon to display for modified files.
Type: `string`, Default: `"●"` Type: `string`, Default: `"●"`
*nvim-tree.renderer.icons.glyphs.hidden*
Icon to display for hidden files.
Type: `string`, Default: `"󰜌""`
*nvim-tree.renderer.icons.glyphs.folder* *nvim-tree.renderer.icons.glyphs.folder*
Glyphs for directories. Glyphs for directories.
Overridden by |nvim-tree.renderer.icons.web_devicons| if available. Overridden by |nvim-tree.renderer.icons.web_devicons| if available.
@@ -1171,8 +1198,9 @@ Only relevant when `git.show_on_dirs` is `true`.
*nvim-tree.git.disable_for_dirs* *nvim-tree.git.disable_for_dirs*
Disable git integration when git top-level matches these paths. Disable git integration when git top-level matches these paths.
May be relative, evaluated via |fnamemodify| `":p"` Strings may be relative, evaluated via |fnamemodify| `":p"`
Type: `table`, Default: `{}` Function is passed an absolute path and returns true for disable.
Type: `string[] | fun(path: string): boolean`, Default: `{}`
*nvim-tree.git.timeout* *nvim-tree.git.timeout*
Kills the git process after some time if it takes too long. Kills the git process after some time if it takes too long.
@@ -1334,10 +1362,12 @@ Idle milliseconds between filesystem change and action.
Type: `number`, Default: `50` (ms) Type: `number`, Default: `50` (ms)
*nvim-tree.filesystem_watchers.ignore_dirs* *nvim-tree.filesystem_watchers.ignore_dirs*
List of vim regex for absolute directory paths that will not be watched. List of vim regex for absolute directory paths that will not be watched or
Backslashes must be escaped e.g. `"my-project/\\.build$"`. See |string-match|. function returning whether a path should be ignored.
Strings must be backslash escaped e.g. `"my-proj/\\.build$"`. See |string-match|.
Function is passed an absolute path.
Useful when path is not in `.gitignore` or git integration is disabled. Useful when path is not in `.gitignore` or git integration is disabled.
Type: {string}, Default: `{}` Type: `string[] | fun(path: string): boolean`, Default: `{}`
============================================================================== ==============================================================================
5.13 OPTS: ACTIONS *nvim-tree-opts-actions* 5.13 OPTS: ACTIONS *nvim-tree-opts-actions*
@@ -1537,6 +1567,12 @@ Confirmation prompts.
Experimental features that may become default or optional functionality. Experimental features that may become default or optional functionality.
In the event of a problem please disable the experiment and raise an issue. In the event of a problem please disable the experiment and raise an issue.
*nvim-tree.experimental.actions.open_file.relative_path*
Buffers opened by nvim-tree will use with relative paths instead of
absolute.
Execute |:ls| to see the paths of all open buffers.
Type: `boolean`, Default: `false`
============================================================================== ==============================================================================
5.20 OPTS: LOG *nvim-tree-opts-log* 5.20 OPTS: LOG *nvim-tree-opts-log*
@@ -1656,6 +1692,22 @@ tree.focus() *nvim-tree-api.tree.focus()*
tree.reload() *nvim-tree-api.tree.reload()* tree.reload() *nvim-tree-api.tree.reload()*
Refresh the tree. Does nothing if closed. Refresh the tree. Does nothing if closed.
tree.resize({opts}) *nvim-tree-api.tree.resize()*
Resize the tree, persisting the new size.
Resets to |nvim-tree.view.width| when no {opts} provided.
See |:NvimTreeResize|
Parameters: ~
• {opts} (table) optional parameters
Options: ~
• {width} (table) new |nvim-tree.view.width| value
• {absolute} (number) set the width
• {relative} (number) increase or decrease the width
Only one option is supported, in the priority order above.
{absolute} and {relative} do nothing when {width} is a function.
tree.change_root({path}) *nvim-tree-api.tree.change_root()* tree.change_root({path}) *nvim-tree-api.tree.change_root()*
Change the tree's root to a path. Change the tree's root to a path.
@@ -2403,6 +2455,11 @@ Modified: >
NvimTreeModifiedIcon Type NvimTreeModifiedIcon Type
NvimTreeModifiedFileHL NvimTreeModifiedIcon NvimTreeModifiedFileHL NvimTreeModifiedIcon
NvimTreeModifiedFolderHL NvimTreeModifiedIcon NvimTreeModifiedFolderHL NvimTreeModifiedIcon
Hidden: >
NvimTreeModifiedIcon Conceal
NvimTreeModifiedFileHL NvimTreeHiddenIcon
NvimTreeModifiedFolderHL NvimTreeHiddenFileHL
< <
Opened: > Opened: >
NvimTreeOpenedHL Special NvimTreeOpenedHL Special
@@ -2630,10 +2687,6 @@ configurations for different types of prompts.
============================================================================== ==============================================================================
11. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific* 11. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*
macOS
- Rename to different case is not possible when using a case insensitive file
system.
Windows WSL and PowerShell Windows WSL and PowerShell
- Trash is synchronized - Trash is synchronized
- Executable file detection is disabled as this is non-performant and can - Executable file detection is disabled as this is non-performant and can
@@ -2772,6 +2825,7 @@ 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|
@@ -2822,6 +2876,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree.renderer.highlight_clipboard| |nvim-tree.renderer.highlight_clipboard|
|nvim-tree.renderer.highlight_diagnostics| |nvim-tree.renderer.highlight_diagnostics|
|nvim-tree.renderer.highlight_git| |nvim-tree.renderer.highlight_git|
|nvim-tree.renderer.highlight_hidden|
|nvim-tree.renderer.highlight_modified| |nvim-tree.renderer.highlight_modified|
|nvim-tree.renderer.highlight_opened_files| |nvim-tree.renderer.highlight_opened_files|
|nvim-tree.renderer.icons| |nvim-tree.renderer.icons|
@@ -2832,8 +2887,10 @@ highlight group is not, hard linking as follows: >
|nvim-tree.renderer.icons.glyphs.default| |nvim-tree.renderer.icons.glyphs.default|
|nvim-tree.renderer.icons.glyphs.folder| |nvim-tree.renderer.icons.glyphs.folder|
|nvim-tree.renderer.icons.glyphs.git| |nvim-tree.renderer.icons.glyphs.git|
|nvim-tree.renderer.icons.glyphs.hidden|
|nvim-tree.renderer.icons.glyphs.modified| |nvim-tree.renderer.icons.glyphs.modified|
|nvim-tree.renderer.icons.glyphs.symlink| |nvim-tree.renderer.icons.glyphs.symlink|
|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|
|nvim-tree.renderer.icons.show| |nvim-tree.renderer.icons.show|
@@ -2843,6 +2900,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree.renderer.icons.show.folder| |nvim-tree.renderer.icons.show.folder|
|nvim-tree.renderer.icons.show.folder_arrow| |nvim-tree.renderer.icons.show.folder_arrow|
|nvim-tree.renderer.icons.show.git| |nvim-tree.renderer.icons.show.git|
|nvim-tree.renderer.icons.show.hidden|
|nvim-tree.renderer.icons.show.modified| |nvim-tree.renderer.icons.show.modified|
|nvim-tree.renderer.icons.symlink_arrow| |nvim-tree.renderer.icons.symlink_arrow|
|nvim-tree.renderer.icons.web_devicons| |nvim-tree.renderer.icons.web_devicons|
@@ -2986,6 +3044,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree-api.tree.is_visible()| |nvim-tree-api.tree.is_visible()|
|nvim-tree-api.tree.open()| |nvim-tree-api.tree.open()|
|nvim-tree-api.tree.reload()| |nvim-tree-api.tree.reload()|
|nvim-tree-api.tree.resize()|
|nvim-tree-api.tree.search_node()| |nvim-tree-api.tree.search_node()|
|nvim-tree-api.tree.toggle()| |nvim-tree-api.tree.toggle()|
|nvim-tree-api.tree.toggle_custom_filter()| |nvim-tree-api.tree.toggle_custom_filter()|

View File

@@ -2,16 +2,13 @@ local lib = require "nvim-tree.lib"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local appearance = require "nvim-tree.appearance" local appearance = require "nvim-tree.appearance"
local renderer = require "nvim-tree.renderer" local renderer = require "nvim-tree.renderer"
local view = require "nvim-tree.view"
local commands = require "nvim-tree.commands" local commands = require "nvim-tree.commands"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local actions = require "nvim-tree.actions" local actions = require "nvim-tree.actions"
local legacy = require "nvim-tree.legacy" local legacy = require "nvim-tree.legacy"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local git = require "nvim-tree.git" local git = require "nvim-tree.git"
local filters = require "nvim-tree.explorer.filters"
local buffers = require "nvim-tree.buffers" local buffers = require "nvim-tree.buffers"
local events = require "nvim-tree.events"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
local _config = {} local _config = {}
@@ -26,7 +23,14 @@ local M = {
function M.change_root(path, bufnr) function M.change_root(path, bufnr)
-- skip if current file is in ignore_list -- skip if current file is in ignore_list
if type(bufnr) == "number" then if type(bufnr) == "number" then
local ft = vim.api.nvim_buf_get_option(bufnr, "filetype") or "" 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 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 if utils.str_find(path, value) or utils.str_find(ft, value) then
return return
@@ -76,21 +80,36 @@ function M.change_root(path, bufnr)
end end
function M.tab_enter() function M.tab_enter()
if view.is_visible { any_tabpage = true } then local explorer = core.get_explorer();
if not explorer then
return
end
if explorer.view:is_visible { any_tabpage = true } then
local bufname = vim.api.nvim_buf_get_name(0) local bufname = vim.api.nvim_buf_get_name(0)
local ft = vim.api.nvim_buf_get_option(0, "ft")
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 for _, filter in ipairs(M.config.tab.sync.ignore) do
if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then if bufname:match(filter) ~= nil or ft:match(filter) ~= nil then
return return
end end
end end
view.open { focus_tree = false } explorer.view:open { focus_tree = false }
renderer.draw() renderer.draw()
end end
end end
function M.open_on_directory() function M.open_on_directory()
local should_proceed = _config.hijack_directories.auto_open or view.is_visible() local explorer = core.get_explorer();
if not explorer then
return
end
local should_proceed = _config.hijack_directories.auto_open or explorer.view:is_visible()
if not should_proceed then if not should_proceed then
return return
end end
@@ -165,8 +184,12 @@ local function setup_autocommands(opts)
-- reset and draw (highlights) when colorscheme is changed -- reset and draw (highlights) when colorscheme is changed
create_nvim_tree_autocmd("ColorScheme", { create_nvim_tree_autocmd("ColorScheme", {
callback = function() callback = function()
local explorer = core.get_explorer();
if not explorer then
return
end
appearance.setup() appearance.setup()
view.reset_winhl() explorer.view:reset_winhl()
renderer.draw() renderer.draw()
end, end,
}) })
@@ -178,10 +201,14 @@ local function setup_autocommands(opts)
if not utils.is_nvim_tree_buf(0) then if not utils.is_nvim_tree_buf(0) then
return return
end end
local explorer = core.get_explorer();
if not explorer then
return
end
if opts.actions.open_file.eject then if opts.actions.open_file.eject then
view._prevent_buffer_override() explorer.view:_prevent_buffer_override()
else else
view.abandon_current_window() explorer.view:abandon_current_window()
end end
end, end,
}) })
@@ -197,7 +224,13 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("BufReadPost", { create_nvim_tree_autocmd("BufReadPost", {
callback = function(data) callback = function(data)
-- update opened file buffers -- update opened file buffers
if (filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then local explorer = core.get_explorer()
if not explorer then
return
end
if
(explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == ""
then
utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function()
actions.reloaders.reload_explorer() actions.reloaders.reload_explorer()
end) end)
@@ -208,7 +241,13 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("BufUnload", { create_nvim_tree_autocmd("BufUnload", {
callback = function(data) callback = function(data)
-- update opened file buffers -- update opened file buffers
if (filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then local explorer = core.get_explorer()
if not explorer then
return
end
if
(explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == ""
then
utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function()
actions.reloaders.reload_explorer() actions.reloaders.reload_explorer()
end) end)
@@ -307,8 +346,12 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("WinLeave", { create_nvim_tree_autocmd("WinLeave", {
pattern = "NvimTree_*", pattern = "NvimTree_*",
callback = function() callback = function()
local explorer = core.get_explorer()
if not explorer then
return
end
if utils.is_nvim_tree_buf(0) then if utils.is_nvim_tree_buf(0) then
view.close() explorer.view:close()
end end
end, end,
}) })
@@ -324,21 +367,6 @@ local function setup_autocommands(opts)
end, end,
}) })
end end
-- TODO #1545 remove similar check from view.resize
if vim.fn.has "nvim-0.9" == 1 then
create_nvim_tree_autocmd("WinResized", {
callback = function()
if vim.v.event and vim.v.event.windows then
for _, winid in ipairs(vim.v.event.windows) do
if vim.api.nvim_win_is_valid(winid) and utils.is_nvim_tree_buf(vim.api.nvim_win_get_buf(winid)) then
events._dispatch_on_tree_resize(vim.api.nvim_win_get_width(winid))
end
end
end
end,
})
end
end end
local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
@@ -394,6 +422,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
highlight_diagnostics = "none", highlight_diagnostics = "none",
highlight_opened_files = "none", highlight_opened_files = "none",
highlight_modified = "none", highlight_modified = "none",
highlight_hidden = "none",
highlight_bookmarks = "none", highlight_bookmarks = "none",
highlight_clipboard = "name", highlight_clipboard = "name",
indent_markers = { indent_markers = {
@@ -420,6 +449,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
}, },
git_placement = "before", git_placement = "before",
modified_placement = "after", modified_placement = "after",
hidden_placement = "after",
diagnostics_placement = "signcolumn", diagnostics_placement = "signcolumn",
bookmarks_placement = "signcolumn", bookmarks_placement = "signcolumn",
padding = " ", padding = " ",
@@ -430,6 +460,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
folder_arrow = true, folder_arrow = true,
git = true, git = true,
modified = true, modified = true,
hidden = false,
diagnostics = true, diagnostics = true,
bookmarks = true, bookmarks = true,
}, },
@@ -438,6 +469,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
symlink = "", symlink = "",
bookmark = "󰆤", bookmark = "󰆤",
modified = "", modified = "",
hidden = "󰜌",
folder = { folder = {
arrow_closed = "", arrow_closed = "",
arrow_open = "", arrow_open = "",
@@ -586,7 +618,13 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
default_yes = false, default_yes = false,
}, },
}, },
experimental = {}, experimental = {
actions = {
open_file = {
relative_path = false,
},
},
},
log = { log = {
enable = false, enable = false,
truncate = false, truncate = false,
@@ -634,9 +672,15 @@ local ACCEPTED_TYPES = {
update_focused_file = { update_focused_file = {
exclude = { "function" }, exclude = { "function" },
}, },
git = {
disable_for_dirs = { "function" },
},
filters = { filters = {
custom = { "function" }, custom = { "function" },
}, },
filesystem_watchers = {
ignore_dirs = { "function" },
},
actions = { actions = {
open_file = { open_file = {
window_picker = { window_picker = {
@@ -658,14 +702,16 @@ local ACCEPTED_STRINGS = {
highlight_git = { "none", "icon", "name", "all" }, highlight_git = { "none", "icon", "name", "all" },
highlight_opened_files = { "none", "icon", "name", "all" }, highlight_opened_files = { "none", "icon", "name", "all" },
highlight_modified = { "none", "icon", "name", "all" }, highlight_modified = { "none", "icon", "name", "all" },
highlight_hidden = { "none", "icon", "name", "all" },
highlight_bookmarks = { "none", "icon", "name", "all" }, highlight_bookmarks = { "none", "icon", "name", "all" },
highlight_diagnostics = { "none", "icon", "name", "all" }, highlight_diagnostics = { "none", "icon", "name", "all" },
highlight_clipboard = { "none", "icon", "name", "all" }, highlight_clipboard = { "none", "icon", "name", "all" },
icons = { icons = {
git_placement = { "before", "after", "signcolumn" }, git_placement = { "before", "after", "signcolumn", "right_align" },
modified_placement = { "before", "after", "signcolumn" }, modified_placement = { "before", "after", "signcolumn", "right_align" },
diagnostics_placement = { "before", "after", "signcolumn" }, hidden_placement = { "before", "after", "signcolumn", "right_align" },
bookmarks_placement = { "before", "after", "signcolumn" }, diagnostics_placement = { "before", "after", "signcolumn", "right_align" },
bookmarks_placement = { "before", "after", "signcolumn", "right_align" },
}, },
}, },
help = { help = {
@@ -756,8 +802,12 @@ end
function M.purge_all_state() function M.purge_all_state()
require("nvim-tree.watcher").purge_watchers() require("nvim-tree.watcher").purge_watchers()
view.close_all_tabs() local explorer = core.get_explorer()
view.abandon_all_windows() if not explorer then
return
end
explorer.view:close_all_tabs()
explorer.view:abandon_all_windows()
if core.get_explorer() ~= nil then if core.get_explorer() ~= nil then
git.purge_state() git.purge_state()
core.reset_explorer() core.reset_explorer()
@@ -766,8 +816,8 @@ end
---@param conf table|nil ---@param conf table|nil
function M.setup(conf) function M.setup(conf)
if vim.fn.has "nvim-0.8" == 0 then if vim.fn.has "nvim-0.9" == 0 then
notify.warn "nvim-tree.lua requires Neovim 0.8 or higher" notify.warn "nvim-tree.lua requires Neovim 0.9 or higher"
return return
end end
@@ -807,10 +857,8 @@ function M.setup(conf)
require("nvim-tree.explorer").setup(opts) require("nvim-tree.explorer").setup(opts)
require("nvim-tree.git").setup(opts) require("nvim-tree.git").setup(opts)
require("nvim-tree.git.utils").setup(opts) require("nvim-tree.git.utils").setup(opts)
require("nvim-tree.view").setup(opts)
require("nvim-tree.lib").setup(opts) require("nvim-tree.lib").setup(opts)
require("nvim-tree.renderer").setup(opts) require("nvim-tree.renderer").setup(opts)
require("nvim-tree.live-filter").setup(opts)
require("nvim-tree.marks").setup(opts) require("nvim-tree.marks").setup(opts)
require("nvim-tree.buffers").setup(opts) require("nvim-tree.buffers").setup(opts)
require("nvim-tree.help").setup(opts) require("nvim-tree.help").setup(opts)

View File

@@ -1,5 +1,4 @@
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local view = require "nvim-tree.view"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local renderer = require "nvim-tree.renderer" local renderer = require "nvim-tree.renderer"
local reload = require "nvim-tree.explorer.reload" local reload = require "nvim-tree.explorer.reload"
@@ -13,7 +12,8 @@ local running = {}
---Find a path in the tree, expand it and focus it ---Find a path in the tree, expand it and focus it
---@param path string relative or absolute ---@param path string relative or absolute
function M.fn(path) function M.fn(path)
if not core.get_explorer() or not view.is_visible() then local explorer = core.get_explorer()
if not explorer or not explorer.view:is_visible() then
return return
end end
@@ -75,9 +75,9 @@ function M.fn(path)
end) end)
:iterate() :iterate()
if found and view.is_visible() then if found and explorer.view:is_visible() then
renderer.draw() renderer.draw()
view.set_cursor { line, 0 } explorer.view:set_cursor { line, 0 }
end end
running[path_real] = false running[path_real] = false

View File

@@ -1,5 +1,4 @@
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local filters = require "nvim-tree.explorer.filters"
local find_file = require("nvim-tree.actions.finders.find-file").fn local find_file = require("nvim-tree.actions.finders.find-file").fn
local M = {} local M = {}
@@ -9,6 +8,11 @@ local M = {}
---@return string|nil ---@return string|nil
local function search(search_dir, input_path) local function search(search_dir, input_path)
local realpaths_searched = {} local realpaths_searched = {}
local explorer = core.get_explorer()
if not explorer then
return
end
if not search_dir then if not search_dir then
return return
@@ -19,7 +23,7 @@ local function search(search_dir, input_path)
local function iter(dir) local function iter(dir)
local realpath, path, name, stat, handle, _ local realpath, path, name, stat, handle, _
local filter_status = filters.prepare() local filter_status = explorer.filters:prepare()
handle, _ = vim.loop.fs_scandir(dir) handle, _ = vim.loop.fs_scandir(dir)
if not handle then if not handle then
@@ -42,7 +46,7 @@ local function search(search_dir, input_path)
break break
end end
if not filters.should_filter(path, stat, filter_status) then if not explorer.filters:should_filter(path, stat, filter_status) then
if string.find(path, "/" .. input_path .. "$") then if string.find(path, "/" .. input_path .. "$") then
return path return path
end end
@@ -69,8 +73,15 @@ function M.fn()
-- temporarily set &path -- temporarily set &path
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
local path_existed, path_opt = pcall(vim.api.nvim_buf_get_option, bufnr, "path")
vim.api.nvim_buf_set_option(bufnr, "path", core.get_cwd() .. "/**") 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
vim.ui.input({ prompt = "Search: ", completion = "file_in_path" }, function(input_path) vim.ui.input({ prompt = "Search: ", completion = "file_in_path" }, function(input_path)
if not input_path or input_path == "" then if not input_path or input_path == "" then
@@ -78,9 +89,17 @@ function M.fn()
end end
-- reset &path -- reset &path
if path_existed then if path_existed then
vim.api.nvim_buf_set_option(bufnr, "path", path_opt) if vim.fn.has "nvim-0.10" == 1 then
vim.api.nvim_set_option_value("path", path_opt, { buf = bufnr })
else else
vim.api.nvim_buf_set_option(bufnr, "path", nil) vim.api.nvim_buf_set_option(bufnr, "path", path_opt) ---@diagnostic disable-line: deprecated
end
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
end end
-- strip trailing slash -- strip trailing slash

View File

@@ -12,7 +12,7 @@ local M = {}
local function create_and_notify(file) local function create_and_notify(file)
events._dispatch_will_create_file(file) events._dispatch_will_create_file(file)
local ok, fd = pcall(vim.loop.fs_open, file, "w", 420) local ok, fd = pcall(vim.loop.fs_open, file, "w", 420)
if not ok then if not ok or type(fd) ~= "number" then
notify.error("Couldn't create file " .. notify.render_path(file)) notify.error("Couldn't create file " .. notify.render_path(file))
return return
end end

View File

@@ -1,6 +1,5 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local view = require "nvim-tree.view"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
@@ -10,10 +9,14 @@ local M = {
---@param windows integer[] ---@param windows integer[]
local function close_windows(windows) local function close_windows(windows)
local explorer = require "nvim-tree.core".get_explorer()
if not explorer then
return
end
-- Prevent from closing when the win count equals 1 or 2, -- Prevent from closing when the win count equals 1 or 2,
-- where the win to remove could be the last opened. -- where the win to remove could be the last opened.
-- For details see #2503. -- For details see #2503.
if view.View.float.enable and #vim.api.nvim_list_wins() < 3 then if explorer.view.View.float.enable and #vim.api.nvim_list_wins() < 3 then
return return
end end
@@ -26,16 +29,20 @@ end
---@param absolute_path string ---@param absolute_path string
local function clear_buffer(absolute_path) local function clear_buffer(absolute_path)
local explorer = require "nvim-tree.core".get_explorer()
if not explorer then
return
end
local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 } local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 }
for _, buf in pairs(bufs) do for _, buf in pairs(bufs) do
if buf.name == absolute_path then if buf.name == absolute_path then
local tree_winnr = vim.api.nvim_get_current_win() 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 explorer.view.View.float.enable) then
vim.api.nvim_set_current_win(buf.windows[1]) vim.api.nvim_set_current_win(buf.windows[1])
vim.cmd ":bn" vim.cmd ":bn"
end end
vim.api.nvim_buf_delete(buf.bufnr, { force = true }) vim.api.nvim_buf_delete(buf.bufnr, { force = true })
if not view.View.float.quit_on_focus_loss then if not explorer.view.View.float.quit_on_focus_loss then
vim.api.nvim_set_current_win(tree_winnr) vim.api.nvim_set_current_win(tree_winnr)
end end
if M.config.actions.remove_file.close_window then if M.config.actions.remove_file.close_window then
@@ -49,9 +56,9 @@ end
---@param cwd string ---@param cwd string
---@return boolean|nil ---@return boolean|nil
local function remove_dir(cwd) local function remove_dir(cwd)
local handle = vim.loop.fs_scandir(cwd) local handle, err = vim.loop.fs_scandir(cwd)
if type(handle) == "string" then if not handle then
notify.error(handle) notify.error(err)
return return
end end

View File

@@ -30,13 +30,25 @@ local function err_fmt(from, to, reason)
return string.format("Cannot rename %s -> %s: %s", from, to, reason) return string.format("Cannot rename %s -> %s: %s", from, to, reason)
end end
local function rename_file_exists(node, to)
if not utils.is_macos then
return utils.file_exists(to)
end
if string.lower(node) == string.lower(to) then
return false
end
return utils.file_exists(to)
end
---@param node Node ---@param node Node
---@param to string ---@param to string
function M.rename(node, to) function M.rename(node, to)
local notify_from = notify.render_path(node.absolute_path) local notify_from = notify.render_path(node.absolute_path)
local notify_to = notify.render_path(to) local notify_to = notify.render_path(to)
if utils.file_exists(to) then if rename_file_exists(notify_from, notify_to) then
notify.warn(err_fmt(notify_from, notify_to, "file already exists")) notify.warn(err_fmt(notify_from, notify_to, "file already exists"))
return return
end end
@@ -65,7 +77,7 @@ function M.rename(node, to)
notify.warn(err_fmt(notify_from, notify_to, err)) notify.warn(err_fmt(notify_from, notify_to, err))
return return
end end
elseif not utils.file_exists(path_to_create) then elseif not rename_file_exists(notify_from, path_to_create) then
local success = vim.loop.fs_mkdir(path_to_create, 493) local success = vim.loop.fs_mkdir(path_to_create, 493)
if not success then if not success then
notify.error("Could not create folder " .. notify.render_path(path_to_create)) notify.error("Could not create folder " .. notify.render_path(path_to_create))

View File

@@ -1,5 +1,4 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local view = require "nvim-tree.view"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
@@ -60,10 +59,14 @@ local function move(where, what, skip_gitignored)
end end
end end
local explorer = core.get_explorer()
if not explorer then
return
end
if nex then if nex then
view.set_cursor { nex, 0 } explorer.view:set_cursor { nex, 0 }
elseif vim.o.wrapscan and first then elseif vim.o.wrapscan and first then
view.set_cursor { first, 0 } explorer.view:set_cursor { first, 0 }
end end
end end
@@ -182,13 +185,19 @@ local function move_prev_recursive(what, skip_gitignored)
-- 4.3) -- 4.3)
if node_init.name == ".." then -- root node if node_init.name == ".." then -- root node
view.set_cursor { 1, 0 } -- move to root node (position 1) local explorer = core.get_explorer()
if explorer then
explorer.view:set_cursor { 1, 0 } -- move to root node (position 1)
end
else else
local node_init_line = utils.find_node_line(node_init) local node_init_line = utils.find_node_line(node_init)
if node_init_line < 0 then if node_init_line < 0 then
return return
end end
view.set_cursor { node_init_line, 0 } local explorer = core.get_explorer()
if explorer then
explorer.view:set_cursor { node_init_line, 0 } -- move to root node (position 1)
end
end end
-- 4.4) -- 4.4)

View File

@@ -1,5 +1,4 @@
local renderer = require "nvim-tree.renderer" local renderer = require "nvim-tree.renderer"
local view = require "nvim-tree.view"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
@@ -21,14 +20,20 @@ function M.fn(should_close)
local parent = utils.get_parent_of_group(node).parent local parent = utils.get_parent_of_group(node).parent
if not parent or not parent.parent then if not parent or not parent.parent then
return view.set_cursor { 1, 0 } local explorer = core.get_explorer()
if explorer then
return explorer.view:set_cursor { 1, 0 }
end
end end
local _, line = utils.find_node(core.get_explorer().nodes, function(n) local _, line = utils.find_node(core.get_explorer().nodes, function(n)
return n.absolute_path == parent.absolute_path return n.absolute_path == parent.absolute_path
end) end)
view.set_cursor { line + 1, 0 } local explorer = core.get_explorer()
if explorer then
explorer.view:set_cursor { line + 1, 0 }
end
if should_close then if should_close then
parent.open = false parent.open = false
renderer.draw() renderer.draw()

View File

@@ -56,7 +56,7 @@ end
function M.close_popup() function M.close_popup()
if current_popup ~= nil then if current_popup ~= nil then
vim.api.nvim_win_close(current_popup.winnr, { force = true }) vim.api.nvim_win_close(current_popup.winnr, true)
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,7 +2,6 @@
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 view = require "nvim-tree.view"
local M = {} local M = {}
@@ -19,21 +18,29 @@ end
---Get all windows in the current tabpage that aren't NvimTree. ---Get all windows in the current tabpage that aren't NvimTree.
---@return table with valid win_ids ---@return table with valid win_ids
local function usable_win_ids() local function usable_win_ids()
local explorer = require "nvim-tree.core".get_explorer()
local tabpage = vim.api.nvim_get_current_tabpage() local tabpage = vim.api.nvim_get_current_tabpage()
local win_ids = vim.api.nvim_tabpage_list_wins(tabpage) local win_ids = vim.api.nvim_tabpage_list_wins(tabpage)
local tree_winid = view.get_winnr(tabpage) local tree_winid = explorer and explorer.view:get_winnr(tabpage)
return vim.tbl_filter(function(id) return vim.tbl_filter(function(id)
local bufid = vim.api.nvim_win_get_buf(id) local bufid = vim.api.nvim_win_get_buf(id)
for option, v in pairs(M.window_picker.exclude) do for option, v in pairs(M.window_picker.exclude) do
local ok, option_value = pcall(vim.api.nvim_buf_get_option, bufid, option) 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
if ok and vim.tbl_contains(v, option_value) then if ok and vim.tbl_contains(v, option_value) then
return false return false
end end
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 return id ~= tree_winid and win_config.focusable and not win_config.external or false
end, win_ids) end, win_ids)
end end
@@ -83,8 +90,15 @@ local function pick_win_id()
if laststatus == 3 then if laststatus == 3 then
for _, win_id in ipairs(not_selectable) do for _, win_id in ipairs(not_selectable) do
local ok_status, statusline = pcall(vim.api.nvim_win_get_option, win_id, "statusline") local ok_status, statusline, ok_hl, winhl
local ok_hl, winhl = pcall(vim.api.nvim_win_get_option, win_id, "winhl")
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[win_id] = {
statusline = ok_status and statusline or "", statusline = ok_status and statusline or "",
@@ -92,15 +106,26 @@ local function pick_win_id()
} }
-- Clear statusline for windows not selectable -- Clear statusline for windows not selectable
vim.api.nvim_win_set_option(win_id, "statusline", " ") 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
end end
end end
-- Setup UI -- Setup UI
for _, id in ipairs(selectable) do for _, id in ipairs(selectable) do
local char = M.window_picker.chars:sub(i, i) local char = M.window_picker.chars:sub(i, i)
local ok_status, statusline = pcall(vim.api.nvim_win_get_option, id, "statusline")
local ok_hl, winhl = pcall(vim.api.nvim_win_get_option, id, "winhl") 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
win_opts[id] = { win_opts[id] = {
statusline = ok_status and statusline or "", statusline = ok_status and statusline or "",
@@ -108,8 +133,13 @@ local function pick_win_id()
} }
win_map[char] = id win_map[char] = id
vim.api.nvim_win_set_option(id, "statusline", "%=" .. char .. "%=") if vim.fn.has "nvim-0.10" == 1 then
vim.api.nvim_win_set_option(id, "winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker") 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
i = i + 1 i = i + 1
if i > #M.window_picker.chars then if i > #M.window_picker.chars then
@@ -128,14 +158,22 @@ local function pick_win_id()
-- Restore window options -- Restore window options
for _, id in ipairs(selectable) do for _, id in ipairs(selectable) do
for opt, value in pairs(win_opts[id]) do for opt, value in pairs(win_opts[id]) do
vim.api.nvim_win_set_option(id, opt, value) 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
end end
end end
if laststatus == 3 then if laststatus == 3 then
for _, id in ipairs(not_selectable) do for _, id in ipairs(not_selectable) do
for opt, value in pairs(win_opts[id]) do for opt, value in pairs(win_opts[id]) do
vim.api.nvim_win_set_option(id, opt, value) 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
end end
end end
end end
@@ -151,21 +189,39 @@ end
local function open_file_in_tab(filename) local function open_file_in_tab(filename)
if M.quit_on_open then if M.quit_on_open then
view.close() local explorer = require "nvim-tree.core".get_explorer()
if explorer then
explorer.view:close()
end
end
if M.relative_path then
filename = utils.path_relative(filename, vim.fn.getcwd())
end end
vim.cmd("tabe " .. vim.fn.fnameescape(filename)) vim.cmd("tabe " .. vim.fn.fnameescape(filename))
end end
local function drop(filename) local function drop(filename)
if M.quit_on_open then if M.quit_on_open then
view.close() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:close()
end
end
if M.relative_path then
filename = utils.path_relative(filename, vim.fn.getcwd())
end end
vim.cmd("drop " .. vim.fn.fnameescape(filename)) vim.cmd("drop " .. vim.fn.fnameescape(filename))
end end
local function tab_drop(filename) local function tab_drop(filename)
if M.quit_on_open then if M.quit_on_open then
view.close() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:close()
end
end
if M.relative_path then
filename = utils.path_relative(filename, vim.fn.getcwd())
end end
vim.cmd("tab :drop " .. vim.fn.fnameescape(filename)) vim.cmd("tab :drop " .. vim.fn.fnameescape(filename))
end end
@@ -183,7 +239,10 @@ local function on_preview(buf_loaded)
once = true, once = true,
}) })
end end
view.focus() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:focus()
end
end end
local function get_target_winid(mode) local function get_target_winid(mode)
@@ -241,7 +300,8 @@ local function open_in_new_window(filename, mode)
end, vim.api.nvim_list_wins()) 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 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 explorer = require"nvim-tree.core".get_explorer()
local new_window_side = (explorer and view.View.side == "right") and "aboveleft" or "belowright"
-- Target is invalid: create new window -- Target is invalid: create new window
if not vim.tbl_contains(win_ids, target_winid) then if not vim.tbl_contains(win_ids, target_winid) then
@@ -258,26 +318,22 @@ local function open_in_new_window(filename, mode)
-- If `hidden` is not enabled, check if buffer in target window is -- If `hidden` is not enabled, check if buffer in target window is
-- modified, and create new split if it is. -- modified, and create new split if it is.
local target_bufid = vim.api.nvim_win_get_buf(target_winid) local target_bufid = vim.api.nvim_win_get_buf(target_winid)
if vim.api.nvim_buf_get_option(target_bufid, "modified") then
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
if modified then
if not mode:match "split$" then if not mode:match "split$" then
mode = "vsplit" mode = "vsplit"
end end
end end
end end
local fname = vim.fn.fnameescape(filename) if (mode == "preview" or mode == "preview_no_picker") and explorer and explorer.view.View.float.enable then
fname = utils.escape_special_chars(fname)
local cmd
if create_new_window then
cmd = string.format("%s vsplit %s", new_window_side, fname)
elseif mode:match "split$" then
cmd = string.format("%s %s", mode, fname)
else
cmd = string.format("edit %s", fname)
end
if (mode == "preview" or mode == "preview_no_picker") and view.View.float.enable then
-- ignore "WinLeave" autocmd on preview -- ignore "WinLeave" autocmd on preview
-- because the registered "WinLeave" -- because the registered "WinLeave"
-- will kill the floating window immediately -- will kill the floating window immediately
@@ -286,7 +342,24 @@ local function open_in_new_window(filename, mode)
set_current_win_no_autocmd(target_winid, { "BufEnter" }) set_current_win_no_autocmd(target_winid, { "BufEnter" })
end end
pcall(vim.cmd, cmd) local fname
if M.relative_path then
fname = utils.escape_special_chars(vim.fn.fnameescape(utils.path_relative(filename, vim.fn.getcwd())))
else
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
command = { cmd = mode, args = { fname } }
else
command = { cmd = "edit", args = { fname } }
end
pcall(vim.api.nvim_cmd, command, { output = false })
lib.set_target_win() lib.set_target_win()
end end
@@ -300,7 +373,13 @@ local function is_already_loaded(filename)
end end
local function edit_in_current_buf(filename) local function edit_in_current_buf(filename)
require("nvim-tree.view").abandon_current_window() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:abandon_current_window()
end
if M.relative_path then
filename = utils.path_relative(filename, vim.fn.getcwd())
end
vim.cmd("keepalt keepjumps edit " .. vim.fn.fnameescape(filename)) vim.cmd("keepalt keepjumps edit " .. vim.fn.fnameescape(filename))
end end
@@ -342,7 +421,10 @@ function M.fn(mode, filename)
end end
if M.resize_window then if M.resize_window then
view.resize() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:resize()
end
end end
if mode == "preview" or mode == "preview_no_picker" then if mode == "preview" or mode == "preview_no_picker" then
@@ -350,13 +432,17 @@ function M.fn(mode, filename)
end end
if M.quit_on_open then if M.quit_on_open then
view.close() local explorer = require"nvim-tree.core".get_explorer()
if explorer then
explorer.view:close()
end
end end
end end
function M.setup(opts) function M.setup(opts)
M.quit_on_open = opts.actions.open_file.quit_on_open M.quit_on_open = opts.actions.open_file.quit_on_open
M.resize_window = opts.actions.open_file.resize_window 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 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() opts.actions.open_file.window_picker.chars = tostring(opts.actions.open_file.window_picker.chars):upper()
end end

View File

@@ -1,5 +1,4 @@
local git = require "nvim-tree.git" local git = require "nvim-tree.git"
local view = require "nvim-tree.view"
local renderer = require "nvim-tree.renderer" local renderer = require "nvim-tree.renderer"
local explorer_module = require "nvim-tree.explorer" local explorer_module = require "nvim-tree.explorer"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
@@ -43,14 +42,15 @@ end
local event_running = false local event_running = false
function M.reload_explorer() function M.reload_explorer()
if event_running or not core.get_explorer() or vim.v.exiting ~= vim.NIL then local explorer = core.get_explorer()
if event_running or not explorer or vim.v.exiting ~= vim.NIL then
return return
end end
event_running = true event_running = true
local projects = git.reload() local projects = git.reload()
refresh_nodes(core.get_explorer(), projects) refresh_nodes(core.get_explorer(), projects)
if view.is_visible() then if explorer.view:is_visible() then
renderer.draw() renderer.draw()
end end
event_running = false event_running = false

View File

@@ -1,6 +1,5 @@
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local view = require "nvim-tree.view"
local finders_find_file = require "nvim-tree.actions.finders.find-file" local finders_find_file = require "nvim-tree.actions.finders.find-file"
local M = {} local M = {}
@@ -24,27 +23,29 @@ function M.fn(opts)
local bufnr, path local bufnr, path
-- (optional) buffer number and path -- (optional) buffer number and path
if type(opts.buf) == "nil" then local opts_buf = opts.buf
if type(opts_buf) == "nil" then
bufnr = vim.api.nvim_get_current_buf() bufnr = vim.api.nvim_get_current_buf()
path = vim.api.nvim_buf_get_name(bufnr) path = vim.api.nvim_buf_get_name(bufnr)
elseif type(opts.buf) == "number" then elseif type(opts_buf) == "number" then
if not vim.api.nvim_buf_is_valid(opts.buf) then if not vim.api.nvim_buf_is_valid(opts_buf) then
return return
end end
bufnr = tonumber(opts.buf) bufnr = opts_buf
path = vim.api.nvim_buf_get_name(bufnr) path = vim.api.nvim_buf_get_name(bufnr)
elseif type(opts.buf) == "string" then elseif type(opts_buf) == "string" then
bufnr = nil bufnr = nil
path = tostring(opts.buf) path = tostring(opts_buf)
else else
return return
end end
if view.is_visible() then local explorer = core.get_explorer()
if explorer and explorer.view:is_visible() then
-- focus -- focus
if opts.focus then if opts.focus then
lib.set_target_win() lib.set_target_win()
view.focus() explorer.view:focus()
end end
elseif opts.open then elseif opts.open then
-- open -- open

View File

@@ -4,12 +4,14 @@ M.find_file = require "nvim-tree.actions.tree.find-file"
M.modifiers = require "nvim-tree.actions.tree.modifiers" M.modifiers = require "nvim-tree.actions.tree.modifiers"
M.open = require "nvim-tree.actions.tree.open" M.open = require "nvim-tree.actions.tree.open"
M.toggle = require "nvim-tree.actions.tree.toggle" M.toggle = require "nvim-tree.actions.tree.toggle"
M.resize = require "nvim-tree.actions.tree.resize"
function M.setup(opts) function M.setup(opts)
M.find_file.setup(opts) M.find_file.setup(opts)
M.modifiers.setup(opts) M.modifiers.setup(opts)
M.open.setup(opts) M.open.setup(opts)
M.toggle.setup(opts) M.toggle.setup(opts)
M.resize.setup(opts)
end end
return M return M

View File

@@ -1,8 +1,7 @@
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local filters = require "nvim-tree.explorer.filters"
local reloaders = require "nvim-tree.actions.reloaders" local reloaders = require "nvim-tree.actions.reloaders"
local core = require "nvim-tree.core"
local M = {} local M = {}
local function reload() local function reload()
@@ -11,39 +10,56 @@ local function reload()
utils.focus_node_or_parent(node) utils.focus_node_or_parent(node)
end end
function M.custom() local function wrap_explorer(fn)
filters.config.filter_custom = not filters.config.filter_custom return function(...)
local explorer = core.get_explorer()
if explorer then
return fn(explorer, ...)
end
end
end
local function custom(explorer)
explorer.filters.config.filter_custom = not explorer.filters.config.filter_custom
reload() reload()
end end
function M.git_ignored() local function git_ignored(explorer)
filters.config.filter_git_ignored = not filters.config.filter_git_ignored explorer.filters.config.filter_git_ignored = not explorer.filters.config.filter_git_ignored
reload() reload()
end end
function M.git_clean() local function git_clean(explorer)
filters.config.filter_git_clean = not filters.config.filter_git_clean explorer.filters.config.filter_git_clean = not explorer.filters.config.filter_git_clean
reload() reload()
end end
function M.no_buffer() local function no_buffer(explorer)
filters.config.filter_no_buffer = not filters.config.filter_no_buffer explorer.filters.config.filter_no_buffer = not explorer.filters.config.filter_no_buffer
reload() reload()
end end
function M.no_bookmark() local function no_bookmark(explorer)
filters.config.filter_no_bookmark = not filters.config.filter_no_bookmark explorer.filters.config.filter_no_bookmark = not explorer.filters.config.filter_no_bookmark
reload() reload()
end end
function M.dotfiles() local function dotfiles(explorer)
filters.config.filter_dotfiles = not filters.config.filter_dotfiles explorer.filters.config.filter_dotfiles = not explorer.filters.config.filter_dotfiles
reload() reload()
end end
function M.enable() local function enable(explorer)
filters.config.enable = not filters.config.enable explorer.filters.config.enable = not explorer.filters.config.enable
reload() reload()
end 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 return M

View File

@@ -1,5 +1,4 @@
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local view = require "nvim-tree.view"
local finders_find_file = require "nvim-tree.actions.finders.find-file" local finders_find_file = require "nvim-tree.actions.finders.find-file"
local M = {} local M = {}
@@ -23,10 +22,11 @@ function M.fn(opts)
opts.path = nil opts.path = nil
end end
if view.is_visible() then local explorer = require"nvim-tree.core".get_explorer()
if explorer and explorer.view:is_visible() then
-- focus -- focus
lib.set_target_win() lib.set_target_win()
view.focus() explorer.view:focus()
else else
-- open -- open
lib.open { lib.open {

View File

@@ -0,0 +1,55 @@
local M = {}
---Resize the tree, persisting the new size.
---@param opts ApiTreeResizeOpts|nil
function M.fn(opts)
local explorer = require"nvim-tree.core".get_explorer()
if not explorer then
return
end
if opts == nil then
-- reset to config values
explorer.view:configure_width()
explorer.view:resize()
return
end
local options = opts or {}
local width_cfg = options.width
if width_cfg ~= nil then
explorer.view:configure_width(width_cfg)
explorer.view:resize()
return
end
if not explorer.view:is_width_determined() then
-- {absolute} and {relative} do nothing when {width} is a function.
return
end
local absolute = options.absolute
if type(absolute) == "number" then
explorer.view:resize(absolute)
return
end
local relative = options.relative
if type(relative) == "number" then
local relative_size = tostring(relative)
if relative > 0 then
relative_size = "+" .. relative_size
end
explorer.view:resize(relative_size)
return
end
end
function M.setup(opts)
M.config = opts or {}
end
return M

View File

@@ -1,5 +1,4 @@
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local view = require "nvim-tree.view"
local finders_find_file = require "nvim-tree.actions.finders.find-file" local finders_find_file = require "nvim-tree.actions.finders.find-file"
local M = {} local M = {}
@@ -40,9 +39,14 @@ function M.fn(opts, no_focus, cwd, bang)
opts.path = nil opts.path = nil
end end
if view.is_visible() then local explorer = require"nvim-tree.core".get_explorer()
if not explorer then
return
end
if explorer.view:is_visible() then
-- close -- close
view.close() explorer.view:close()
else else
-- open -- open
lib.open { lib.open {

View File

@@ -1,12 +1,10 @@
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local view = require "nvim-tree.view" local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local actions = require "nvim-tree.actions" local actions = require "nvim-tree.actions"
local appearance_diagnostics = require "nvim-tree.appearance.diagnostics" local appearance_diagnostics = require "nvim-tree.appearance.diagnostics"
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local help = require "nvim-tree.help" local help = require "nvim-tree.help"
local live_filter = require "nvim-tree.live-filter"
local marks = require "nvim-tree.marks"
local marks_navigation = require "nvim-tree.marks.navigation" local marks_navigation = require "nvim-tree.marks.navigation"
local marks_bulk_delete = require "nvim-tree.marks.bulk-delete" local marks_bulk_delete = require "nvim-tree.marks.bulk-delete"
local marks_bulk_trash = require "nvim-tree.marks.bulk-trash" local marks_bulk_trash = require "nvim-tree.marks.bulk-trash"
@@ -43,9 +41,10 @@ local Api = {
diagnostics = {}, diagnostics = {},
} }
--- Do nothing when setup not called. --- Print error when setup not called.
--- f function to invoke --- f function to invoke
---@param f function ---@param f function
---@return fun(...) : any
local function wrap(f) local function wrap(f)
return function(...) return function(...)
if vim.g.NvimTreeSetup == 1 then if vim.g.NvimTreeSetup == 1 then
@@ -56,13 +55,13 @@ local function wrap(f)
end end
end end
---Inject the node as the first argument if absent. ---Inject the node as the first argument if present otherwise do nothing.
---@param fn function function to invoke ---@param fn function function to invoke
local function wrap_node(fn) local function wrap_node(fn)
return function(node, ...) return function(node, ...)
node = node or lib.get_node_at_cursor() node = node or lib.get_node_at_cursor()
if node then if node then
fn(node, ...) return fn(node, ...)
end end
end end
end end
@@ -72,10 +71,36 @@ end
local function wrap_node_or_nil(fn) local function wrap_node_or_nil(fn)
return function(node, ...) return function(node, ...)
node = node or lib.get_node_at_cursor() node = node or lib.get_node_at_cursor()
fn(node, ...) return fn(node, ...)
end end
end end
---Inject the explorer as the first argument if present otherwise do nothing.
---@param fn function function to invoke
---@return fun(...) : any
local function wrap_explorer(fn)
return function(...)
local explorer = core.get_explorer()
if explorer then
return fn(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 ---@class ApiTreeOpenOpts
---@field path string|nil path ---@field path string|nil path
---@field current_window boolean|nil default false ---@field current_window boolean|nil default false
@@ -95,11 +120,18 @@ Api.tree.focus = Api.tree.open
---@field focus boolean|nil default true ---@field focus boolean|nil default true
Api.tree.toggle = wrap(actions.tree.toggle.fn) Api.tree.toggle = wrap(actions.tree.toggle.fn)
Api.tree.close = wrap(view.close) Api.tree.close = wrap_explorer_member("view", "close")
Api.tree.close_in_this_tab = wrap(view.close_this_tab_only) Api.tree.close_in_this_tab = wrap_explorer_member("view", "close_this_tab_only")
Api.tree.close_in_all_tabs = wrap(view.close_all_tabs) Api.tree.close_in_all_tabs = wrap_explorer_member("view", "close_all_tabs")
Api.tree.reload = wrap(actions.reloaders.reload_explorer) Api.tree.reload = wrap(actions.reloaders.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(...) Api.tree.change_root = wrap(function(...)
require("nvim-tree").change_dir(...) require("nvim-tree").change_dir(...)
end) end)
@@ -142,12 +174,12 @@ Api.tree.is_tree_buf = wrap(utils.is_nvim_tree_buf)
---@field tabpage number|nil ---@field tabpage number|nil
---@field any_tabpage boolean|nil default false ---@field any_tabpage boolean|nil default false
Api.tree.is_visible = wrap(view.is_visible) Api.tree.is_visible = wrap_explorer_member("view", "is_visible")
---@class ApiTreeWinIdOpts ---@class ApiTreeWinIdOpts
---@field tabpage number|nil default nil ---@field tabpage number|nil default nil
Api.tree.winid = wrap(view.winid) Api.tree.winid = wrap_explorer_member("view", "winid")
Api.fs.create = wrap_node_or_nil(actions.fs.create_file.fn) Api.fs.create = wrap_node_or_nil(actions.fs.create_file.fn)
Api.fs.remove = wrap_node(actions.fs.remove_file.fn) Api.fs.remove = wrap_node(actions.fs.remove_file.fn)
@@ -231,16 +263,16 @@ Api.git.reload = wrap(actions.reloaders.reload_git)
Api.events.subscribe = events.subscribe Api.events.subscribe = events.subscribe
Api.events.Event = events.Event Api.events.Event = events.Event
Api.live_filter.start = wrap(live_filter.start_filtering) Api.live_filter.start = wrap_explorer_member("live_filter", "start_filtering")
Api.live_filter.clear = wrap(live_filter.clear_filter) Api.live_filter.clear = wrap_explorer_member("live_filter", "clear_filter")
Api.marks.get = wrap_node(marks.get_mark) Api.marks.get = wrap_node(wrap_explorer_member("marks", "get_mark"))
Api.marks.list = wrap(marks.get_marks) Api.marks.list = wrap_explorer_member("marks", "get_marks")
Api.marks.toggle = wrap_node(marks.toggle_mark) Api.marks.toggle = wrap_node(wrap_explorer_member("marks", "toggle_mark"))
Api.marks.clear = wrap(marks.clear_marks) Api.marks.clear = wrap_explorer_member("marks", "clear_marks")
Api.marks.bulk.delete = wrap(marks_bulk_delete.bulk_delete) Api.marks.bulk.delete = wrap_explorer(marks_bulk_delete.bulk_delete)
Api.marks.bulk.trash = wrap(marks_bulk_trash.bulk_trash) Api.marks.bulk.trash = wrap_explorer(marks_bulk_trash.bulk_trash)
Api.marks.bulk.move = wrap(marks_bulk_move.bulk_move) Api.marks.bulk.move = wrap_explorer(marks_bulk_move.bulk_move)
Api.marks.navigate.next = wrap(marks_navigation.next) Api.marks.navigate.next = wrap(marks_navigation.next)
Api.marks.navigate.prev = wrap(marks_navigation.prev) Api.marks.navigate.prev = wrap(marks_navigation.prev)
Api.marks.navigate.select = wrap(marks_navigation.select) Api.marks.navigate.select = wrap(marks_navigation.select)

View File

@@ -129,7 +129,12 @@ function M.hi_test()
render_displays("other, long", displays_long, bufnr, l) render_displays("other, long", displays_long, bufnr, l)
-- finalise and focus the buffer -- finalise and focus the buffer
vim.api.nvim_buf_set_option(bufnr, "modifiable", false) 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.cmd.buffer(bufnr) vim.cmd.buffer(bufnr)
end end

View File

@@ -76,6 +76,11 @@ M.HIGHLIGHT_GROUPS = {
{ group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" }, { group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" },
{ group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" }, { group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" },
-- Hidden
{ group = "NvimTreeHiddenIcon", link = "Conceal" },
{ group = "NvimTreeHiddenFileHL", link = "NvimTreeHiddenIcon" },
{ group = "NvimTreeHiddenFolderHL", link = "NvimTreeHiddenFileHL" },
-- Opened -- Opened
{ group = "NvimTreeOpenedHL", link = "Special" }, { group = "NvimTreeOpenedHL", link = "Special" },
@@ -183,15 +188,8 @@ function M.setup()
-- hard link override when legacy only is present -- hard link override when legacy only is present
for from, to in pairs(M.LEGACY_LINKS) do for from, to in pairs(M.LEGACY_LINKS) do
local hl_from local hl_from = vim.api.nvim_get_hl(0, { name = from })
local hl_to local hl_to = vim.api.nvim_get_hl(0, { name = to })
if vim.fn.has "nvim-0.9" == 1 then
hl_from = vim.api.nvim_get_hl(0, { name = from })
hl_to = vim.api.nvim_get_hl(0, { name = to })
else
hl_from = vim.api.nvim__get_hl_defs(0)[from] or {}
hl_to = vim.api.nvim__get_hl_defs(0)[to] or {}
end
if vim.tbl_isempty(hl_from) and not vim.tbl_isempty(hl_to) then if vim.tbl_isempty(hl_from) and not vim.tbl_isempty(hl_to) then
vim.api.nvim_command("hi link " .. from .. " " .. to) vim.api.nvim_command("hi link " .. from .. " " .. to)
end end

View File

@@ -6,7 +6,7 @@ M._modified = {}
---refresh M._modified ---refresh M._modified
function M.reload_modified() function M.reload_modified()
M._modified = {} M._modified = {}
local bufs = vim.fn.getbufinfo { bufmodified = true, buflisted = true } local bufs = vim.fn.getbufinfo { bufmodified = 1, buflisted = 1 }
for _, buf in pairs(bufs) do for _, buf in pairs(bufs) do
local path = buf.name local path = buf.name
if path ~= "" then -- not a [No Name] buffer if path ~= "" then -- not a [No Name] buffer

View File

@@ -1,5 +1,4 @@
local api = require "nvim-tree.api" local api = require "nvim-tree.api"
local view = require "nvim-tree.view"
local M = {} local M = {}
@@ -111,7 +110,11 @@ local CMDS = {
bar = true, bar = true,
}, },
command = function(c) command = function(c)
view.resize(c.args) local explorer = require "nvim-tree.core".get_explorer();
if not explorer then
return
end
explorer.view:resize(c.args)
end, end,
}, },
{ {

View File

@@ -1,7 +1,5 @@
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local explorer = require "nvim-tree.explorer" local explorer = require "nvim-tree.explorer"
local live_filter = require "nvim-tree.live-filter"
local view = require "nvim-tree.view"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local M = {} local M = {}
@@ -42,10 +40,10 @@ end
---@return integer ---@return integer
function M.get_nodes_starting_line() function M.get_nodes_starting_line()
local offset = 1 local offset = 1
if view.is_root_folder_visible(M.get_cwd()) then if TreeExplorer and TreeExplorer.view:is_root_folder_visible(M.get_cwd()) then
offset = offset + 1 offset = offset + 1
end end
if live_filter.filter then if TreeExplorer and TreeExplorer.live_filter.filter then
return offset + 1 return offset + 1
end end
return offset return offset

View File

@@ -1,5 +1,4 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local view = require "nvim-tree.view"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local M = {} local M = {}
@@ -39,19 +38,21 @@ end
local function from_nvim_lsp() local function from_nvim_lsp()
local buffer_severity = {} local buffer_severity = {}
local is_disabled = false -- is_enabled is not present in all 0.10 builds/releases, see #2781
if vim.fn.has "nvim-0.9" == 1 then local is_enabled = false
is_disabled = vim.diagnostic.is_disabled() 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 end
if not is_disabled then if is_enabled then
for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do
local buf = diagnostic.bufnr if diagnostic.severity and diagnostic.bufnr and vim.api.nvim_buf_is_valid(diagnostic.bufnr) then
if vim.api.nvim_buf_is_valid(buf) then local bufname = uniformize_path(vim.api.nvim_buf_get_name(diagnostic.bufnr))
local bufname = uniformize_path(vim.api.nvim_buf_get_name(buf)) if not buffer_severity[bufname] or diagnostic.severity < buffer_severity[bufname] then
local severity = diagnostic.severity buffer_severity[bufname] = diagnostic.severity
local highest_severity = buffer_severity[bufname] or severity end
buffer_severity[bufname] = math.min(highest_severity, severity)
end end
end end
end end
@@ -162,7 +163,9 @@ function M.update()
end end
end end
log.profile_end(profile) log.profile_end(profile)
if view.is_buf_valid(view.get_bufnr()) then local explorer = require "nvim-tree.core".get_explorer()
if explorer and explorer.view:is_buf_valid(explorer.view:get_bufnr()) then
require("nvim-tree.renderer").draw() require("nvim-tree.renderer").draw()
end end
end) end)

View File

@@ -16,6 +16,7 @@ M.ICON_PLACEMENT = {
signcolumn = 1, signcolumn = 1,
before = 2, before = 2,
after = 3, after = 3,
right_align = 4,
} }
return M return M

View File

@@ -2,9 +2,6 @@ local utils = require "nvim-tree.utils"
local builders = require "nvim-tree.explorer.node-builders" local builders = require "nvim-tree.explorer.node-builders"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
local git = require "nvim-tree.git" local git = require "nvim-tree.git"
local sorters = require "nvim-tree.explorer.sorters"
local filters = require "nvim-tree.explorer.filters"
local live_filter = require "nvim-tree.live-filter"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local Watcher = require "nvim-tree.watcher" local Watcher = require "nvim-tree.watcher"
@@ -15,10 +12,11 @@ local M = {}
---@param cwd string ---@param cwd string
---@param node Node ---@param node Node
---@param git_status table ---@param git_status table
local function populate_children(handle, cwd, node, git_status) ---@param parent Explorer
local function populate_children(handle, cwd, node, git_status, parent)
local node_ignored = explorer_node.is_git_ignored(node) local node_ignored = explorer_node.is_git_ignored(node)
local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") local nodes_by_path = utils.bool_record(node.nodes, "absolute_path")
local filter_status = filters.prepare(git_status) local filter_status = parent.filters:prepare(git_status)
while true do while true do
local name, t = vim.loop.fs_scandir_next(handle) local name, t = vim.loop.fs_scandir_next(handle)
if not name then if not name then
@@ -31,7 +29,7 @@ local function populate_children(handle, cwd, node, git_status)
---@type uv.fs_stat.result|nil ---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_stat(abs) local stat = vim.loop.fs_stat(abs)
if not filters.should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then if not parent.filters:should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then
local child = nil local child = nil
if t == "directory" and vim.loop.fs_access(abs, "R") then if t == "directory" and vim.loop.fs_access(abs, "R") then
child = builders.folder(node, abs, name, stat) child = builders.folder(node, abs, name, stat)
@@ -56,8 +54,9 @@ end
---@param node Node ---@param node Node
---@param status table ---@param status table
---@param parent Explorer
---@return Node[]|nil ---@return Node[]|nil
function M.explore(node, status) function M.explore(node, status, parent)
local cwd = node.link_to or node.absolute_path local cwd = node.link_to or node.absolute_path
local handle = vim.loop.fs_scandir(cwd) local handle = vim.loop.fs_scandir(cwd)
if not handle then if not handle then
@@ -66,7 +65,7 @@ function M.explore(node, status)
local profile = log.profile_start("explore init %s", node.absolute_path) local profile = log.profile_start("explore init %s", node.absolute_path)
populate_children(handle, cwd, node, status) populate_children(handle, cwd, node, status, parent)
local is_root = not node.parent local is_root = not node.parent
local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1]
@@ -74,15 +73,15 @@ function M.explore(node, status)
local child_cwd = child_folder_only.link_to or child_folder_only.absolute_path local child_cwd = child_folder_only.link_to or child_folder_only.absolute_path
local child_status = git.load_project_status(child_cwd) local child_status = git.load_project_status(child_cwd)
node.group_next = child_folder_only node.group_next = child_folder_only
local ns = M.explore(child_folder_only, child_status) local ns = M.explore(child_folder_only, child_status, parent)
node.nodes = ns or {} node.nodes = ns or {}
log.profile_end(profile) log.profile_end(profile)
return ns return ns
end end
sorters.sort(node.nodes) parent.sorters:sort(node.nodes)
live_filter.apply_filter(node) parent.live_filter:apply_filter(node)
log.profile_end(profile) log.profile_end(profile)
return node.nodes return node.nodes

View File

@@ -1,16 +1,52 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local marks = require "nvim-tree.marks"
local M = { ---@class Filters to handle all opts.filters and related API
---@field config table hydrated user opts.filters
---@field private explorer Explorer
---@field private exclude_list string[] filters.exclude
---@field private ignore_list string[] filters.custom string table
---@field private custom_function (fun(absolute_path: string): boolean)|nil filters.custom function
local Filters = {}
---@param opts table user options
---@param explorer Explorer
---@return Filters
function Filters:new(opts, explorer)
local o = {
explorer = explorer,
ignore_list = {}, ignore_list = {},
exclude_list = {}, exclude_list = opts.filters.exclude,
custom_function = nil, custom_function = nil,
} config = {
enable = opts.filters.enable,
filter_custom = true,
filter_dotfiles = opts.filters.dotfiles,
filter_git_ignored = opts.filters.git_ignored,
filter_git_clean = opts.filters.git_clean,
filter_no_buffer = opts.filters.no_buffer,
filter_no_bookmark = opts.filters.no_bookmark,
},
}
local custom_filter = opts.filters.custom
if type(custom_filter) == "function" then
o.custom_function = custom_filter
else
if custom_filter and #custom_filter > 0 then
for _, filter_name in pairs(custom_filter) do
o.ignore_list[filter_name] = true
end
end
end
setmetatable(o, self)
self.__index = self
return o
end
---@param path string ---@param path string
---@return boolean ---@return boolean
local function is_excluded(path) local function is_excluded(self, path)
for _, node in ipairs(M.exclude_list) do for _, node in ipairs(self.exclude_list) do
if path:match(node) then if path:match(node) then
return true return true
end end
@@ -22,7 +58,7 @@ end
---@param path string Absolute path ---@param path string Absolute path
---@param git_status table from prepare ---@param git_status table from prepare
---@return boolean ---@return boolean
local function git(path, git_status) local function git(self, path, git_status)
if type(git_status) ~= "table" or type(git_status.files) ~= "table" or type(git_status.dirs) ~= "table" then if type(git_status) ~= "table" or type(git_status.files) ~= "table" or type(git_status.dirs) ~= "table" then
return false return false
end end
@@ -33,12 +69,12 @@ local function git(path, git_status)
status = status or git_status.dirs.indirect[path] and git_status.dirs.indirect[path][1] status = status or git_status.dirs.indirect[path] and git_status.dirs.indirect[path][1]
-- filter ignored; overrides clean as they are effectively dirty -- filter ignored; overrides clean as they are effectively dirty
if M.config.filter_git_ignored and status == "!!" then if self.config.filter_git_ignored and status == "!!" then
return true return true
end end
-- filter clean -- filter clean
if M.config.filter_git_clean and not status then if self.config.filter_git_clean and not status then
return true return true
end end
@@ -49,8 +85,8 @@ end
---@param path string Absolute path ---@param path string Absolute path
---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 } ---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 }
---@return boolean ---@return boolean
local function buf(path, bufinfo) local function buf(self, path, bufinfo)
if not M.config.filter_no_buffer or type(bufinfo) ~= "table" then if not self.config.filter_no_buffer or type(bufinfo) ~= "table" then
return false return false
end end
@@ -66,15 +102,15 @@ end
---@param path string ---@param path string
---@return boolean ---@return boolean
local function dotfile(path) local function dotfile(self, path)
return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "." return self.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "."
end end
---@param path string ---@param path string
---@param path_type string|nil filetype of path ---@param path_type string|nil filetype of path
---@param bookmarks table<string, string|nil> path, filetype table of bookmarked files ---@param bookmarks table<string, string|nil> path, filetype table of bookmarked files
local function bookmark(path, path_type, bookmarks) local function bookmark(self, path, path_type, bookmarks)
if not M.config.filter_no_bookmark then if not self.config.filter_no_bookmark then
return false return false
end end
-- if bookmark is empty, we should see a empty filetree -- if bookmark is empty, we should see a empty filetree
@@ -108,21 +144,21 @@ end
---@param path string ---@param path string
---@return boolean ---@return boolean
local function custom(path) local function custom(self, path)
if not M.config.filter_custom then if not self.config.filter_custom then
return false return false
end end
local basename = utils.path_basename(path) local basename = utils.path_basename(path)
-- filter user's custom function -- filter user's custom function
if M.custom_function and M.custom_function(path) then if self.custom_function and self.custom_function(path) then
return true return true
end end
-- filter custom regexes -- filter custom regexes
local relpath = utils.path_relative(path, vim.loop.cwd()) local relpath = utils.path_relative(path, vim.loop.cwd())
for pat, _ in pairs(M.ignore_list) do for pat, _ in pairs(self.ignore_list) do
if vim.fn.match(relpath, pat) ~= -1 or vim.fn.match(basename, pat) ~= -1 then if vim.fn.match(relpath, pat) ~= -1 or vim.fn.match(basename, pat) ~= -1 then
return true return true
end end
@@ -130,7 +166,7 @@ local function custom(path)
local idx = path:match ".+()%.[^.]+$" local idx = path:match ".+()%.[^.]+$"
if idx then if idx then
if M.ignore_list["*" .. string.sub(path, idx)] == true then if self.ignore_list["*" .. string.sub(path, idx)] == true then
return true return true
end end
end end
@@ -144,20 +180,23 @@ end
--- git_status: reference --- git_status: reference
--- bufinfo: empty unless no_buffer set: vim.fn.getbufinfo { buflisted = 1 } --- bufinfo: empty unless no_buffer set: vim.fn.getbufinfo { buflisted = 1 }
--- bookmarks: absolute paths to boolean --- bookmarks: absolute paths to boolean
function M.prepare(git_status) function Filters:prepare(git_status)
local status = { local status = {
git_status = git_status or {}, git_status = git_status or {},
bufinfo = {}, bufinfo = {},
bookmarks = {}, bookmarks = {},
} }
if M.config.filter_no_buffer then if self.config.filter_no_buffer then
status.bufinfo = vim.fn.getbufinfo { buflisted = 1 } status.bufinfo = vim.fn.getbufinfo { buflisted = 1 }
end end
for _, node in pairs(marks.get_marks()) do local explorer = require("nvim-tree.core").get_explorer()
if explorer then
for _, node in pairs(explorer.marks:get_marks()) do
status.bookmarks[node.absolute_path] = node.type status.bookmarks[node.absolute_path] = node.type
end end
end
return status return status
end end
@@ -167,47 +206,21 @@ end
---@param fs_stat uv.fs_stat.result|nil fs_stat of file ---@param fs_stat uv.fs_stat.result|nil fs_stat of file
---@param status table from prepare ---@param status table from prepare
---@return boolean ---@return boolean
function M.should_filter(path, fs_stat, status) function Filters:should_filter(path, fs_stat, status)
if not M.config.enable then if not self.config.enable then
return false return false
end end
-- exclusions override all filters -- exclusions override all filters
if is_excluded(path) then if is_excluded(self, path) then
return false return false
end end
return git(path, status.git_status) return git(self, path, status.git_status)
or buf(path, status.bufinfo) or buf(self, path, status.bufinfo)
or dotfile(path) or dotfile(self, path)
or custom(path) or custom(self, path)
or bookmark(path, fs_stat and fs_stat.type, status.bookmarks) or bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks)
end end
function M.setup(opts) return Filters
M.config = {
enable = opts.filters.enable,
filter_custom = true,
filter_dotfiles = opts.filters.dotfiles,
filter_git_ignored = opts.filters.git_ignored,
filter_git_clean = opts.filters.git_clean,
filter_no_buffer = opts.filters.no_buffer,
filter_no_bookmark = opts.filters.no_bookmark,
}
M.ignore_list = {}
M.exclude_list = opts.filters.exclude
local custom_filter = opts.filters.custom
if type(custom_filter) == "function" then
M.custom_function = custom_filter
else
if custom_filter and #custom_filter > 0 then
for _, filter_name in pairs(custom_filter) do
M.ignore_list[filter_name] = true
end
end
end
end
return M

View File

@@ -1,6 +1,12 @@
local git = require "nvim-tree.git" local git = require "nvim-tree.git"
local notify = require "nvim-tree.notify"
local watch = require "nvim-tree.explorer.watch" local watch = require "nvim-tree.explorer.watch"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
local Filters = require "nvim-tree.explorer.filters"
local Marks = require "nvim-tree.marks"
local LiveFilter = require "nvim-tree.explorer.live-filter"
local Sorters = require "nvim-tree.explorer.sorters"
local View = require "nvim-tree.explorer.view"
local M = {} local M = {}
@@ -11,22 +17,41 @@ M.reload = require("nvim-tree.explorer.reload").reload
---@field absolute_path string ---@field absolute_path string
---@field nodes Node[] ---@field nodes Node[]
---@field open boolean ---@field open boolean
---@field filters Filters
---@field live_filter LiveFilter
---@field sorters Sorter
---@field marks Marks
local Explorer = {} local Explorer = {}
Explorer.__index = Explorer Explorer.__index = Explorer
---@param cwd string|nil ---@param path string|nil
---@return Explorer ---@return Explorer|nil
function Explorer.new(cwd) function Explorer.new(path)
cwd = vim.loop.fs_realpath(cwd or vim.loop.cwd()) local err
if path then
path, err = vim.loop.fs_realpath(path)
else
path, err = vim.loop.cwd()
end
if not path then
notify.error(err)
return
end
---@class Explorer ---@class Explorer
local explorer = setmetatable({ local explorer = setmetatable({
absolute_path = cwd, absolute_path = path,
nodes = {}, nodes = {},
open = true, open = true,
marks = Marks:new(),
sorters = Sorters:new(M.config),
view = View:new(M.config),
}, Explorer) }, Explorer)
explorer.watcher = watch.create_watcher(explorer) explorer.watcher = watch.create_watcher(explorer)
explorer.filters = Filters:new(M.config, explorer)
explorer.live_filter = LiveFilter:new(M.config, explorer)
explorer:_load(explorer) explorer:_load(explorer)
return explorer return explorer
end end
@@ -36,7 +61,7 @@ end
function Explorer:_load(node) function Explorer:_load(node)
local cwd = node.link_to or node.absolute_path local cwd = node.link_to or node.absolute_path
local git_status = git.load_project_status(cwd) local git_status = git.load_project_status(cwd)
M.explore(node, git_status) M.explore(node, git_status, self)
end end
---@param node Node ---@param node Node
@@ -57,10 +82,9 @@ function Explorer:destroy()
end end
function M.setup(opts) function M.setup(opts)
M.config = opts
require("nvim-tree.explorer.node").setup(opts) require("nvim-tree.explorer.node").setup(opts)
require("nvim-tree.explorer.explore").setup(opts) require("nvim-tree.explorer.explore").setup(opts)
require("nvim-tree.explorer.filters").setup(opts)
require("nvim-tree.explorer.sorters").setup(opts)
require("nvim-tree.explorer.reload").setup(opts) require("nvim-tree.explorer.reload").setup(opts)
require("nvim-tree.explorer.watch").setup(opts) require("nvim-tree.explorer.watch").setup(opts)
end end

View File

@@ -0,0 +1,213 @@
local utils = require "nvim-tree.utils"
local Iterator = require "nvim-tree.iterators.node-iterator"
---@class LiveFilter
---@field explorer Explorer
---@field prefix string
---@field always_show_folders boolean
---@field filter string
local LiveFilter = {}
---@param opts table
---@param explorer Explorer
function LiveFilter:new(opts, explorer)
local o = {
explorer = explorer,
prefix = opts.live_filter.prefix,
always_show_folders = opts.live_filter.always_show_folders,
filter = nil,
}
setmetatable(o, self)
self.__index = self
return o
end
local function redraw()
require("nvim-tree.renderer").draw()
end
---@param node_ Node|nil
local function reset_filter(self, node_)
node_ = node_ or self.explorer
if node_ == nil then
return
end
Iterator.builder(node_.nodes)
:hidden()
:applier(function(node)
node.hidden = false
end)
:iterate()
end
local overlay_bufnr = 0
local overlay_winnr = 0
local function remove_overlay(self)
if self.explorer.view.View.float.enable and self.explorer.view.View.float.quit_on_focus_loss then
-- return to normal nvim-tree float behaviour when filter window is closed
vim.api.nvim_create_autocmd("WinLeave", {
pattern = "NvimTree_*",
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
callback = function()
if utils.is_nvim_tree_buf(0) then
self.explorer.view:close()
end
end,
})
end
vim.api.nvim_win_close(overlay_winnr, true)
vim.api.nvim_buf_delete(overlay_bufnr, { force = true })
overlay_bufnr = 0
overlay_winnr = 0
if self.filter == "" then
self:clear_filter()
end
end
---@param node Node
---@return boolean
local function matches(self, node)
if not self.explorer.filters.config.enable then
return true
end
local path = node.absolute_path
local name = vim.fn.fnamemodify(path, ":t")
return vim.regex(self.filter):match_str(name) ~= nil
end
---@param node_ Node|nil
function LiveFilter:apply_filter(node_)
if not self.filter or self.filter == "" then
reset_filter(self, node_)
return
end
-- TODO(kiyan): this iterator cannot yet be refactored with the Iterator module
-- since the node mapper is based on its children
local function iterate(node)
local filtered_nodes = 0
local nodes = node.group_next and { node.group_next } or node.nodes
if nodes then
for _, n in pairs(nodes) do
iterate(n)
if n.hidden then
filtered_nodes = filtered_nodes + 1
end
end
end
local has_nodes = nodes and (self.always_show_folders or #nodes > filtered_nodes)
local ok, is_match = pcall(matches, self, node)
node.hidden = not (has_nodes or (ok and is_match))
end
iterate(node_ or self.explorer)
end
local function record_char(self)
vim.schedule(function()
self.filter = vim.api.nvim_buf_get_lines(overlay_bufnr, 0, -1, false)[1]
self:apply_filter()
redraw()
end)
end
local function configure_buffer_overlay(self)
overlay_bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_attach(overlay_bufnr, true, {
on_lines = function()
return record_char(self)
end,
})
vim.api.nvim_create_autocmd("InsertLeave", {
callback = function()
return remove_overlay(self)
end,
once = true,
})
vim.api.nvim_buf_set_keymap(overlay_bufnr, "i", "<CR>", "<cmd>stopinsert<CR>", {})
end
---@return integer
local function calculate_overlay_win_width(self)
local wininfo = vim.fn.getwininfo(self.explorer.view:get_winnr())[1]
if wininfo then
return wininfo.width - wininfo.textoff - #self.prefix
end
return 20
end
local function create_overlay(self)
if self.explorer.view.View.float.enable then
-- don't close nvim-tree float when focus is changed to filter window
vim.api.nvim_clear_autocmds {
event = "WinLeave",
pattern = "NvimTree_*",
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
}
end
configure_buffer_overlay(self)
overlay_winnr = vim.api.nvim_open_win(overlay_bufnr, true, {
col = 1,
row = 0,
relative = "cursor",
width = calculate_overlay_win_width(self),
height = 1,
border = "none",
style = "minimal",
})
if vim.fn.has "nvim-0.10" == 1 then
vim.api.nvim_set_option_value("modifiable", true, { buf = overlay_bufnr })
else
vim.api.nvim_buf_set_option(overlay_bufnr, "modifiable", true) ---@diagnostic disable-line: deprecated
end
vim.api.nvim_buf_set_lines(overlay_bufnr, 0, -1, false, { self.filter })
vim.cmd "startinsert"
vim.api.nvim_win_set_cursor(overlay_winnr, { 1, #self.filter + 1 })
end
function LiveFilter:start_filtering()
self.explorer.view.View.live_filter.prev_focused_node = require("nvim-tree.lib").get_node_at_cursor()
self.filter = self.filter or ""
redraw()
local row = require("nvim-tree.core").get_nodes_starting_line() - 1
local col = #self.prefix > 0 and #self.prefix - 1 or 1
self.explorer.view:set_cursor { row, col }
-- needs scheduling to let the cursor move before initializing the window
vim.schedule(function()
return create_overlay(self)
end)
end
function LiveFilter:clear_filter()
local node = require("nvim-tree.lib").get_node_at_cursor()
local last_node = self.explorer.view.View.live_filter.prev_focused_node
self.filter = nil
reset_filter(self)
redraw()
if node then
utils.focus_file(node.absolute_path)
elseif last_node then
utils.focus_file(last_node.absolute_path)
end
end
return LiveFilter

View File

@@ -77,7 +77,7 @@ function M.link(parent, absolute_path, name, fs_stat)
local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory" local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory"
if is_dir_link then if is_dir_link and link_to then
local handle = vim.loop.fs_scandir(link_to) local handle = vim.loop.fs_scandir(link_to)
has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil
open = false open = false

View File

@@ -29,7 +29,7 @@ end
---@param absolute_path string ---@param absolute_path string
---@return GitStatus ---@return GitStatus
local function get_git_status(parent_ignored, status, absolute_path) local function get_git_status(parent_ignored, status, absolute_path)
local file_status = parent_ignored and "!!" or status.files and status.files[absolute_path] local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path])
return { file = file_status } return { file = file_status }
end end
@@ -128,6 +128,19 @@ function M.is_git_ignored(node)
return node and node.git_status ~= nil and node.git_status.file == "!!" return node and node.git_status ~= nil and node.git_status.file == "!!"
end end
---@param node Node
---@return boolean
function M.is_dotfile(node)
if node == nil then
return false
end
if node.is_dot or (node.name and (node.name:sub(1, 1) == ".")) or M.is_dotfile(node.parent) then
node.is_dot = true
return true
end
return false
end
---@param node Node ---@param node Node
function M.node_destroy(node) function M.node_destroy(node)
if not node then if not node then

View File

@@ -1,9 +1,6 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local builders = require "nvim-tree.explorer.node-builders" local builders = require "nvim-tree.explorer.node-builders"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
local filters = require "nvim-tree.explorer.filters"
local sorters = require "nvim-tree.explorer.sorters"
local live_filter = require "nvim-tree.live-filter"
local git = require "nvim-tree.git" local git = require "nvim-tree.git"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
@@ -70,6 +67,10 @@ end
---@param node Node ---@param node Node
---@param git_status table ---@param git_status table
function M.reload(node, git_status) function M.reload(node, git_status)
local explorer = require("nvim-tree.core").get_explorer()
if not explorer then
return
end
local cwd = node.link_to or node.absolute_path local cwd = node.link_to or node.absolute_path
local handle = vim.loop.fs_scandir(cwd) local handle = vim.loop.fs_scandir(cwd)
if not handle then if not handle then
@@ -78,7 +79,7 @@ function M.reload(node, git_status)
local profile = log.profile_start("reload %s", node.absolute_path) local profile = log.profile_start("reload %s", node.absolute_path)
local filter_status = filters.prepare(git_status) local filter_status = explorer.filters:prepare(git_status)
if node.group_next then if node.group_next then
node.nodes = { node.group_next } node.nodes = { node.group_next }
@@ -91,7 +92,7 @@ function M.reload(node, git_status)
---@type table<string, Node> ---@type table<string, Node>
local nodes_by_path = utils.key_by(node.nodes, "absolute_path") local nodes_by_path = utils.key_by(node.nodes, "absolute_path")
while true do while true do
local name, t = vim.loop.fs_scandir_next(handle, cwd) local name, t = vim.loop.fs_scandir_next(handle)
if not name then if not name then
break break
end end
@@ -100,7 +101,7 @@ function M.reload(node, git_status)
---@type uv.fs_stat.result|nil ---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_stat(abs) local stat = vim.loop.fs_stat(abs)
if not filters.should_filter(abs, stat, filter_status) then if not explorer.filters:should_filter(abs, stat, filter_status) then
remain_childs[abs] = true remain_childs[abs] = true
-- Recreate node if type changes. -- Recreate node if type changes.
@@ -162,8 +163,8 @@ function M.reload(node, git_status)
return ns return ns
end end
sorters.sort(node.nodes) explorer.sorters:sort(node.nodes)
live_filter.apply_filter(node) explorer.live_filter:apply_filter(node)
log.profile_end(profile) log.profile_end(profile)
return node.nodes return node.nodes
end end

View File

@@ -1,12 +1,27 @@
local M = {}
local C = {} local C = {}
---@class Sorter
local Sorter = {}
function Sorter:new(opts)
local o = {}
setmetatable(o, self)
self.__index = self
o.config = vim.deepcopy(opts.sort)
if type(o.config.sorter) == "function" then
o.user = o.config.sorter
end
return o
end
--- Predefined comparator, defaulting to name --- Predefined comparator, defaulting to name
---@param sorter string as per options ---@param sorter string as per options
---@return function ---@return function
local function get_comparator(sorter) function Sorter:get_comparator(sorter)
return C[sorter] or C.name return function(a, b)
return (C[sorter] or C.name)(a, b, self.config)
end
end end
---Create a shallow copy of a portion of a list. ---Create a shallow copy of a portion of a list.
@@ -27,17 +42,17 @@ end
---@param a Node ---@param a Node
---@param b Node ---@param b Node
---@return boolean|nil ---@return boolean|nil
local function folders_or_files_first(a, b) local function folders_or_files_first(a, b, cfg)
if not (M.config.sort.folders_first or M.config.sort.files_first) then if not (cfg.folders_first or cfg.files_first) then
return return
end end
if not a.nodes and b.nodes then if not a.nodes and b.nodes then
-- file <> folder -- file <> folder
return M.config.sort.files_first return cfg.files_first
elseif a.nodes and not b.nodes then elseif a.nodes and not b.nodes then
-- folder <> file -- folder <> file
return not M.config.sort.files_first return not cfg.files_first
end end
end end
@@ -97,8 +112,8 @@ end
---Perform a merge sort using sorter option. ---Perform a merge sort using sorter option.
---@param t table nodes ---@param t table nodes
function M.sort(t) function Sorter:sort(t)
if C.user then if self.user then
local t_user = {} local t_user = {}
local origin_index = {} local origin_index = {}
@@ -115,9 +130,9 @@ function M.sort(t)
table.insert(origin_index, n) table.insert(origin_index, n)
end end
local predefined = C.user(t_user) local predefined = self.user(t_user)
if predefined then if predefined then
split_merge(t, 1, #t, get_comparator(predefined)) split_merge(t, 1, #t, self:get_comparator(predefined))
return return
end end
@@ -142,7 +157,7 @@ function M.sort(t)
split_merge(t, 1, #t, mini_comparator) -- sort by user order split_merge(t, 1, #t, mini_comparator) -- sort by user order
else else
split_merge(t, 1, #t, get_comparator(M.config.sort.sorter)) split_merge(t, 1, #t, self:get_comparator(self.config.sorter))
end end
end end
@@ -150,12 +165,12 @@ end
---@param b Node ---@param b Node
---@param ignorecase boolean|nil ---@param ignorecase boolean|nil
---@return boolean ---@return boolean
local function node_comparator_name_ignorecase_or_not(a, b, ignorecase) local function node_comparator_name_ignorecase_or_not(a, b, ignorecase, cfg)
if not (a and b) then if not (a and b) then
return true return true
end end
local early_return = folders_or_files_first(a, b) local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
end end
@@ -167,20 +182,20 @@ local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
end end
end end
function C.case_sensitive(a, b) function C.case_sensitive(a, b, cfg)
return node_comparator_name_ignorecase_or_not(a, b, false) return node_comparator_name_ignorecase_or_not(a, b, false, cfg)
end end
function C.name(a, b) function C.name(a, b, cfg)
return node_comparator_name_ignorecase_or_not(a, b, true) return node_comparator_name_ignorecase_or_not(a, b, true, cfg)
end end
function C.modification_time(a, b) function C.modification_time(a, b, cfg)
if not (a and b) then if not (a and b) then
return true return true
end end
local early_return = folders_or_files_first(a, b) local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
end end
@@ -199,17 +214,17 @@ function C.modification_time(a, b)
return last_modified_b <= last_modified_a return last_modified_b <= last_modified_a
end end
function C.suffix(a, b) function C.suffix(a, b, cfg)
if not (a and b) then if not (a and b) then
return true return true
end end
-- directories go first -- directories go first
local early_return = folders_or_files_first(a, b) local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
elseif a.nodes and b.nodes then elseif a.nodes and b.nodes then
return C.name(a, b) return C.name(a, b, cfg)
end end
-- dotfiles go second -- dotfiles go second
@@ -218,7 +233,7 @@ function C.suffix(a, b)
elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then
return false return false
elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then
return C.name(a, b) return C.name(a, b, cfg)
end end
-- unsuffixed go third -- unsuffixed go third
@@ -230,7 +245,7 @@ function C.suffix(a, b)
elseif a_suffix_ndx and not b_suffix_ndx then elseif a_suffix_ndx and not b_suffix_ndx then
return false return false
elseif not (a_suffix_ndx and b_suffix_ndx) then elseif not (a_suffix_ndx and b_suffix_ndx) then
return C.name(a, b) return C.name(a, b, cfg)
end end
-- finally, compare by suffixes -- finally, compare by suffixes
@@ -242,18 +257,18 @@ function C.suffix(a, b)
elseif not a_suffix and b_suffix then elseif not a_suffix and b_suffix then
return false return false
elseif a_suffix:lower() == b_suffix:lower() then elseif a_suffix:lower() == b_suffix:lower() then
return C.name(a, b) return C.name(a, b, cfg)
end end
return a_suffix:lower() < b_suffix:lower() return a_suffix:lower() < b_suffix:lower()
end end
function C.extension(a, b) function C.extension(a, b, cfg)
if not (a and b) then if not (a and b) then
return true return true
end end
local early_return = folders_or_files_first(a, b) local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
end end
@@ -267,18 +282,18 @@ function C.extension(a, b)
local a_ext = (a.extension or ""):lower() local a_ext = (a.extension or ""):lower()
local b_ext = (b.extension or ""):lower() local b_ext = (b.extension or ""):lower()
if a_ext == b_ext then if a_ext == b_ext then
return C.name(a, b) return C.name(a, b, cfg)
end end
return a_ext < b_ext return a_ext < b_ext
end end
function C.filetype(a, b) function C.filetype(a, b, cfg)
local a_ft = vim.filetype.match { filename = a.name } local a_ft = vim.filetype.match { filename = a.name }
local b_ft = vim.filetype.match { filename = b.name } local b_ft = vim.filetype.match { filename = b.name }
-- directories first -- directories first
local early_return = folders_or_files_first(a, b) local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
end end
@@ -292,19 +307,10 @@ function C.filetype(a, b)
-- same filetype or both nil, sort by name -- same filetype or both nil, sort by name
if a_ft == b_ft then if a_ft == b_ft then
return C.name(a, b) return C.name(a, b, cfg)
end end
return a_ft < b_ft return a_ft < b_ft
end end
function M.setup(opts) return Sorter
M.config = {}
M.config.sort = opts.sort
if type(M.config.sort.sorter) == "function" then
C.user = M.config.sort.sorter
end
end
return M

View File

@@ -2,18 +2,15 @@ local events = require "nvim-tree.events"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
---@class OpenInWinOpts local ExplorerView = {}
---@field hijack_current_buf boolean|nil default true
---@field resize boolean|nil default true
---@field winid number|nil 0 or nil for current
local M = {}
local DEFAULT_MIN_WIDTH = 30 local DEFAULT_MIN_WIDTH = 30
local DEFAULT_MAX_WIDTH = -1 local DEFAULT_MAX_WIDTH = -1
local DEFAULT_PADDING = 1 local DEFAULT_PADDING = 1
M.View = { function ExplorerView:new(opts)
local o = {
View = {
adaptive_size = false, adaptive_size = false,
centralize_selection = false, centralize_selection = false,
tabpages = {}, tabpages = {},
@@ -52,7 +49,30 @@ M.View = {
"NormalFloat:NvimTreeNormalFloat", "NormalFloat:NvimTreeNormalFloat",
}, ","), }, ","),
}, },
} }
}
local options = opts.view or {}
o.View.centralize_selection = options.centralize_selection
o.View.side = (options.side == "right") and "right" or "left"
o.View.height = options.height
o.View.hide_root_folder = opts.renderer.root_folder_label == false
o.View.tab = opts.tab
o.View.preserve_window_proportions = options.preserve_window_proportions
o.View.winopts.cursorline = options.cursorline
o.View.winopts.number = options.number
o.View.winopts.relativenumber = options.relativenumber
o.View.winopts.signcolumn = options.signcolumn
o.View.float = options.float
o.on_attach = opts.on_attach
o.config = vim.deepcopy(options)
setmetatable(o, self)
self.__index = self
o:configure_width(options.width)
o.View.initial_width = o:get_width()
end
-- The initial state of a tab -- The initial state of a tab
local tabinitial = { local tabinitial = {
@@ -92,23 +112,23 @@ local function wipe_rogue_buffer()
end end
---@param bufnr integer|boolean|nil ---@param bufnr integer|boolean|nil
local function create_buffer(bufnr) local function create_buffer(self, bufnr)
wipe_rogue_buffer() wipe_rogue_buffer()
local tab = vim.api.nvim_get_current_tabpage() local tab = vim.api.nvim_get_current_tabpage()
BUFNR_PER_TAB[tab] = bufnr or vim.api.nvim_create_buf(false, false) BUFNR_PER_TAB[tab] = bufnr or vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_set_name(M.get_bufnr(), "NvimTree_" .. tab) vim.api.nvim_buf_set_name(self:get_bufnr(), "NvimTree_" .. tab)
for option, value in pairs(BUFFER_OPTIONS) do for option, value in pairs(BUFFER_OPTIONS) do
vim.bo[M.get_bufnr()][option] = value vim.bo[self:get_bufnr()][option] = value
end end
require("nvim-tree.keymap").on_attach(M.get_bufnr()) require("nvim-tree.keymap").on_attach(self:get_bufnr())
events._dispatch_tree_attached_post(M.get_bufnr()) events._dispatch_tree_attached_post(self:get_bufnr())
end end
---@param size number|fun():number ---@param size (fun():integer)|integer|string
---@return integer ---@return integer
local function get_size(size) local function get_size(size)
if type(size) == "number" then if type(size) == "number" then
@@ -121,10 +141,13 @@ local function get_size(size)
return math.floor(vim.o.columns * percent_as_decimal) return math.floor(vim.o.columns * percent_as_decimal)
end end
---@param size number|function|nil ---@param size (fun():integer)|integer|nil
local function get_width(size) function ExplorerView:get_width(size)
size = size or M.View.width if size then
return get_size(size) return get_size(size)
else
return get_size(self.View.width)
end
end end
local move_tbl = { local move_tbl = {
@@ -134,39 +157,39 @@ local move_tbl = {
-- setup_tabpage sets up the initial state of a tab -- setup_tabpage sets up the initial state of a tab
---@param tabpage integer ---@param tabpage integer
local function setup_tabpage(tabpage) local function setup_tabpage(self, tabpage)
local winnr = vim.api.nvim_get_current_win() local winnr = vim.api.nvim_get_current_win()
M.View.tabpages[tabpage] = vim.tbl_extend("force", M.View.tabpages[tabpage] or tabinitial, { winnr = winnr }) self.View.tabpages[tabpage] = vim.tbl_extend("force", self.View.tabpages[tabpage] or tabinitial, { winnr = winnr })
end end
local function set_window_options_and_buffer() local function set_window_options_and_buffer(self)
pcall(vim.cmd, "buffer " .. M.get_bufnr()) pcall(vim.api.nvim_command, "buffer " .. self:get_bufnr())
local eventignore = vim.opt.eventignore:get() local eventignore = vim.opt.eventignore:get()
vim.opt.eventignore = "all" vim.opt.eventignore = "all"
for k, v in pairs(M.View.winopts) do for k, v in pairs(self.View.winopts) do
vim.opt_local[k] = v vim.opt_local[k] = v
end end
vim.opt.eventignore = eventignore vim.opt.eventignore = eventignore
end end
---@return table ---@return table
local function open_win_config() local function open_win_config(self)
if type(M.View.float.open_win_config) == "function" then if type(self.View.float.open_win_config) == "function" then
return M.View.float.open_win_config() return self.View.float.open_win_config(self)
else else
return M.View.float.open_win_config return self.View.float.open_win_config
end end
end end
local function open_window() local function open_window(self)
if M.View.float.enable then if self.View.float.enable then
vim.api.nvim_open_win(0, true, open_win_config()) vim.api.nvim_open_win(0, true, open_win_config(self))
else else
vim.api.nvim_command "vsp" vim.api.nvim_command "vsp"
M.reposition_window() self:reposition_window()
end end
setup_tabpage(vim.api.nvim_get_current_tabpage()) setup_tabpage(self, vim.api.nvim_get_current_tabpage())
set_window_options_and_buffer() set_window_options_and_buffer(self)
end end
---@param buf integer ---@param buf integer
@@ -202,19 +225,19 @@ end
-- save_tab_state saves any state that should be preserved across redraws. -- save_tab_state saves any state that should be preserved across redraws.
---@param tabnr integer ---@param tabnr integer
local function save_tab_state(tabnr) local function save_tab_state(self, tabnr)
local tabpage = tabnr or vim.api.nvim_get_current_tabpage() local tabpage = tabnr or vim.api.nvim_get_current_tabpage()
M.View.cursors[tabpage] = vim.api.nvim_win_get_cursor(M.get_winnr(tabpage)) self.View.cursors[tabpage] = vim.api.nvim_win_get_cursor(self:get_winnr(tabpage) or 0)
end end
---@param tabpage integer ---@param tabpage integer
local function close(tabpage) local function close(self, tabpage)
if not M.is_visible { tabpage = tabpage } then if not self:is_visible { tabpage = tabpage } then
return return
end end
save_tab_state(tabpage) save_tab_state(self, tabpage)
switch_buf_if_last_buf() switch_buf_if_last_buf()
local tree_win = M.get_winnr(tabpage) local tree_win = self:get_winnr(tabpage)
local current_win = vim.api.nvim_get_current_win() local current_win = vim.api.nvim_get_current_win()
for _, win in pairs(vim.api.nvim_tabpage_list_wins(tabpage)) do for _, win in pairs(vim.api.nvim_tabpage_list_wins(tabpage)) do
if vim.api.nvim_win_get_config(win).relative == "" then if vim.api.nvim_win_get_config(win).relative == "" then
@@ -222,8 +245,8 @@ local function close(tabpage)
if tree_win == current_win and prev_win > 0 then if tree_win == current_win and prev_win > 0 then
vim.api.nvim_set_current_win(vim.fn.win_getid(prev_win)) vim.api.nvim_set_current_win(vim.fn.win_getid(prev_win))
end end
if vim.api.nvim_win_is_valid(tree_win) then if vim.api.nvim_win_is_valid(tree_win or 0) then
vim.api.nvim_win_close(tree_win, true) vim.api.nvim_win_close(tree_win or 0, true)
end end
events._dispatch_on_tree_close() events._dispatch_on_tree_close()
return return
@@ -231,35 +254,35 @@ local function close(tabpage)
end end
end end
function M.close_this_tab_only() function ExplorerView:close_this_tab_only()
close(vim.api.nvim_get_current_tabpage()) close(self, vim.api.nvim_get_current_tabpage())
end end
function M.close_all_tabs() function ExplorerView:close_all_tabs()
for tabpage, _ in pairs(M.View.tabpages) do for tabpage, _ in pairs(self.View.tabpages) do
close(tabpage) close(self, tabpage)
end end
end end
function M.close() function ExplorerView:close()
if M.View.tab.sync.close then if self.View.tab.sync.close then
M.close_all_tabs() self:close_all_tabs()
else else
M.close_this_tab_only() self:close_this_tab_only()
end end
end end
---@param options table|nil ---@param options table|nil
function M.open(options) function ExplorerView:open(options)
if M.is_visible() then if self:is_visible() then
return return
end end
local profile = log.profile_start "view open" local profile = log.profile_start "view open"
create_buffer() create_buffer(self)
open_window() open_window(self)
M.resize() self:resize()
local opts = options or { focus_tree = true } local opts = options or { focus_tree = true }
if not opts.focus_tree then if not opts.focus_tree then
@@ -270,26 +293,26 @@ function M.open(options)
log.profile_end(profile) log.profile_end(profile)
end end
local function grow() local function grow(self)
local starts_at = M.is_root_folder_visible(require("nvim-tree.core").get_cwd()) and 1 or 0 local starts_at = self:is_root_folder_visible(require("nvim-tree.core").get_cwd()) and 1 or 0
local lines = vim.api.nvim_buf_get_lines(M.get_bufnr(), starts_at, -1, false) local lines = vim.api.nvim_buf_get_lines(self:get_bufnr(), starts_at, -1, false)
-- number of columns of right-padding to indicate end of path -- number of columns of right-padding to indicate end of path
local padding = get_size(M.View.padding) local padding = get_size(self.View.padding)
-- account for sign/number columns etc. -- account for sign/number columns etc.
local wininfo = vim.fn.getwininfo(M.get_winnr()) local wininfo = vim.fn.getwininfo(self:get_winnr())
if type(wininfo) == "table" and type(wininfo[1]) == "table" then if type(wininfo) == "table" and type(wininfo[1]) == "table" then
padding = padding + wininfo[1].textoff padding = padding + wininfo[1].textoff
end end
local resizing_width = M.View.initial_width - padding local resizing_width = self.View.initial_width - padding
local max_width local max_width
-- maybe bound max -- maybe bound max
if M.View.max_width == -1 then if self.View.max_width == -1 then
max_width = -1 max_width = -1
else else
max_width = get_width(M.View.max_width) - padding max_width = self:get_width(self.View.max_width) - padding
end end
for _, l in pairs(lines) do for _, l in pairs(lines) do
@@ -297,23 +320,23 @@ local function grow()
if resizing_width < count then if resizing_width < count then
resizing_width = count resizing_width = count
end end
if M.View.adaptive_size and max_width >= 0 and resizing_width >= max_width then if self.View.adaptive_size and max_width >= 0 and resizing_width >= max_width then
resizing_width = max_width resizing_width = max_width
break break
end end
end end
M.resize(resizing_width + padding) self:resize(resizing_width + padding)
end end
function M.grow_from_content() function ExplorerView:grow_from_content()
if M.View.adaptive_size then if self.View.adaptive_size then
grow() grow(self)
end end
end end
---@param size string|number|nil ---@param size string|number|nil
function M.resize(size) function ExplorerView:resize(size)
if M.View.float.enable and not M.View.adaptive_size then if self.View.float.enable and not self.View.adaptive_size then
-- if the floating windows's adaptive size is not desired, then the -- if the floating windows's adaptive size is not desired, then the
-- float size should be defined in view.float.open_win_config -- float size should be defined in view.float.open_win_config
return return
@@ -325,7 +348,7 @@ function M.resize(size)
size = tonumber(size) size = tonumber(size)
if first_char == "+" or first_char == "-" then if first_char == "+" or first_char == "-" then
size = M.View.width + size size = self.View.width + size
end end
end end
@@ -334,85 +357,81 @@ function M.resize(size)
end end
if size then if size then
M.View.width = size self.View.width = size
M.View.height = size self.View.height = size
end end
if not M.is_visible() then if not self:is_visible() then
return return
end end
local new_size = get_width() local new_size = self:get_width()
vim.api.nvim_win_set_width(M.get_winnr(), new_size) vim.api.nvim_win_set_width(self:get_winnr() or 0, new_size)
-- TODO #1545 remove similar check from setup_autocommands
-- We let nvim handle sending resize events after 0.9
if vim.fn.has "nvim-0.9" == 0 then
events._dispatch_on_tree_resize(new_size) events._dispatch_on_tree_resize(new_size)
end
if not M.View.preserve_window_proportions then if not self.View.preserve_window_proportions then
vim.cmd ":wincmd =" vim.cmd ":wincmd ="
end end
end end
function M.reposition_window() function ExplorerView:reposition_window()
local move_to = move_tbl[M.View.side] local move_to = move_tbl[self.View.side]
vim.api.nvim_command("wincmd " .. move_to) vim.api.nvim_command("wincmd " .. move_to)
M.resize() self:resize()
end end
local function set_current_win() local function set_current_win(self)
local current_tab = vim.api.nvim_get_current_tabpage() local current_tab = vim.api.nvim_get_current_tabpage()
M.View.tabpages[current_tab].winnr = vim.api.nvim_get_current_win() self.View.tabpages[current_tab].winnr = vim.api.nvim_get_current_win()
end end
---Open the tree in the a window ---Open the tree in the a window
---@param opts OpenInWinOpts|nil ---@param opts OpenInWinOpts|nil
function M.open_in_win(opts) function ExplorerView:open_in_win(opts)
opts = opts or { hijack_current_buf = true, resize = true } opts = opts or { hijack_current_buf = true, resize = true }
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
create_buffer(opts.hijack_current_buf and vim.api.nvim_get_current_buf()) create_buffer(self, opts.hijack_current_buf and vim.api.nvim_get_current_buf())
setup_tabpage(vim.api.nvim_get_current_tabpage()) setup_tabpage(self, vim.api.nvim_get_current_tabpage())
set_current_win() set_current_win(self)
set_window_options_and_buffer() set_window_options_and_buffer(self)
if opts.resize then if opts.resize then
M.reposition_window() self:reposition_window()
M.resize() self:resize()
end end
end end
function M.abandon_current_window() function ExplorerView:abandon_current_window()
local tab = vim.api.nvim_get_current_tabpage() local tab = vim.api.nvim_get_current_tabpage()
BUFNR_PER_TAB[tab] = nil BUFNR_PER_TAB[tab] = nil
if M.View.tabpages[tab] then if self.View.tabpages[tab] then
M.View.tabpages[tab].winnr = nil self.View.tabpages[tab].winnr = nil
end end
end end
function M.abandon_all_windows() function ExplorerView:abandon_all_windows()
for tab, _ in pairs(vim.api.nvim_list_tabpages()) do for tab, _ in pairs(vim.api.nvim_list_tabpages()) do
BUFNR_PER_TAB[tab] = nil BUFNR_PER_TAB[tab] = nil
if M.View.tabpages[tab] then if self.View.tabpages[tab] then
M.View.tabpages[tab].winnr = nil self.View.tabpages[tab].winnr = nil
end end
end end
end end
---@param opts table|nil ---@param opts table|nil
function M.is_visible(opts) function ExplorerView:is_visible(opts)
if opts and opts.tabpage then if opts and opts.tabpage then
if M.View.tabpages[opts.tabpage] == nil then if self.View.tabpages[opts.tabpage] == nil then
return false return false
end end
local winnr = M.View.tabpages[opts.tabpage].winnr local winnr = self.View.tabpages[opts.tabpage].winnr
return winnr and vim.api.nvim_win_is_valid(winnr) return winnr and vim.api.nvim_win_is_valid(winnr)
end end
if opts and opts.any_tabpage then if opts and opts.any_tabpage then
for _, v in pairs(M.View.tabpages) do for _, v in pairs(self.View.tabpages) do
if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then
return true return true
end end
@@ -420,59 +439,61 @@ function M.is_visible(opts)
return false return false
end end
return M.get_winnr() ~= nil and vim.api.nvim_win_is_valid(M.get_winnr()) return self:get_winnr() ~= nil and vim.api.nvim_win_is_valid(self:get_winnr() or 0)
end end
---@param opts table|nil ---@param opts table|nil
function M.set_cursor(opts) function ExplorerView:set_cursor(opts)
if M.is_visible() then if self:is_visible() then
pcall(vim.api.nvim_win_set_cursor, M.get_winnr(), opts) pcall(vim.api.nvim_win_set_cursor, self:get_winnr(), opts)
end end
end end
---@param winnr number|nil ---@param winnr number|nil
---@param open_if_closed boolean|nil ---@param open_if_closed boolean|nil
function M.focus(winnr, open_if_closed) function ExplorerView:focus(winnr, open_if_closed)
local wnr = winnr or M.get_winnr() local wnr = winnr or self:get_winnr()
if vim.api.nvim_win_get_tabpage(wnr or 0) ~= vim.api.nvim_win_get_tabpage(0) then if vim.api.nvim_win_get_tabpage(wnr or 0) ~= vim.api.nvim_win_get_tabpage(0) then
M.close() self:close()
M.open() self:open()
wnr = M.get_winnr() wnr = self:get_winnr()
elseif open_if_closed and not M.is_visible() then elseif open_if_closed and not self:is_visible() then
M.open() self:open()
end end
if wnr then
vim.api.nvim_set_current_win(wnr) vim.api.nvim_set_current_win(wnr)
end
end end
--- Retrieve the winid of the open tree. --- Retrieve the winid of the open tree.
---@param opts ApiTreeWinIdOpts|nil ---@param opts ApiTreeWinIdOpts|nil
---@return number|nil winid unlike get_winnr(), this returns nil if the nvim-tree window is not visible ---@return number|nil winid unlike get_winnr(), this returns nil if the nvim-tree window is not visible
function M.winid(opts) function ExplorerView:winid(opts)
local tabpage = opts and opts.tabpage local tabpage = opts and opts.tabpage
if tabpage == 0 then if tabpage == 0 then
tabpage = vim.api.nvim_get_current_tabpage() tabpage = vim.api.nvim_get_current_tabpage()
end end
if M.is_visible { tabpage = tabpage } then if self:is_visible { tabpage = tabpage } then
return M.get_winnr(tabpage) return self:get_winnr(tabpage)
else else
return nil return nil
end end
end end
--- Restores the state of a NvimTree window if it was initialized before. --- Restores the state of a NvimTree window if it was initialized before.
function M.restore_tab_state() function ExplorerView:restore_tab_state()
local tabpage = vim.api.nvim_get_current_tabpage() local tabpage = vim.api.nvim_get_current_tabpage()
M.set_cursor(M.View.cursors[tabpage]) self:set_cursor(self.View.cursors[tabpage])
end end
--- Returns the window number for nvim-tree within the tabpage specified --- Returns the window number for nvim-tree within the tabpage specified
---@param tabpage number|nil (optional) the number of the chosen tabpage. Defaults to current tabpage. ---@param tabpage number|nil (optional) the number of the chosen tabpage. Defaults to current tabpage.
---@return number|nil ---@return number|nil
function M.get_winnr(tabpage) function ExplorerView:get_winnr(tabpage)
tabpage = tabpage or vim.api.nvim_get_current_tabpage() tabpage = tabpage or vim.api.nvim_get_current_tabpage()
local tabinfo = M.View.tabpages[tabpage] local tabinfo = self.View.tabpages[tabpage]
if tabinfo and tabinfo.winnr and vim.api.nvim_win_is_valid(tabinfo.winnr) then if tabinfo and tabinfo.winnr and vim.api.nvim_win_is_valid(tabinfo.winnr) then
return tabinfo.winnr return tabinfo.winnr
end end
@@ -480,19 +501,19 @@ end
--- Returns the current nvim tree bufnr --- Returns the current nvim tree bufnr
---@return number ---@return number
function M.get_bufnr() function ExplorerView:get_bufnr()
return BUFNR_PER_TAB[vim.api.nvim_get_current_tabpage()] return BUFNR_PER_TAB[vim.api.nvim_get_current_tabpage()]
end end
---@param bufnr number ---@param bufnr number
---@return boolean ---@return boolean
function M.is_buf_valid(bufnr) function ExplorerView:is_buf_valid(bufnr)
return bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_is_loaded(bufnr) return bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_is_loaded(bufnr)
end end
function M._prevent_buffer_override() function ExplorerView:_prevent_buffer_override()
local view_winnr = M.get_winnr() local view_winnr = self:get_winnr()
local view_bufnr = M.get_bufnr() local view_bufnr = self:get_bufnr()
-- need to schedule to let the new buffer populate the window -- need to schedule to let the new buffer populate the window
-- because this event needs to be run on bufWipeout. -- because this event needs to be run on bufWipeout.
@@ -504,7 +525,7 @@ function M._prevent_buffer_override()
local bufname = vim.api.nvim_buf_get_name(curbuf) local bufname = vim.api.nvim_buf_get_name(curbuf)
if not bufname:match "NvimTree" then if not bufname:match "NvimTree" then
for i, tabpage in ipairs(M.View.tabpages) do for i, tabpage in ipairs(self.View.tabpages) do
if tabpage.winnr == view_winnr then if tabpage.winnr == view_winnr then
M.View.tabpages[i] = nil M.View.tabpages[i] = nil
break break
@@ -535,43 +556,44 @@ end
---@param cwd string|nil ---@param cwd string|nil
---@return boolean ---@return boolean
function M.is_root_folder_visible(cwd) function ExplorerView:is_root_folder_visible(cwd)
return cwd ~= "/" and not M.View.hide_root_folder return cwd ~= "/" and not self.View.hide_root_folder
end end
-- used on ColorScheme event -- used on ColorScheme event
function M.reset_winhl() function ExplorerView:reset_winhl()
if M.get_winnr() and vim.api.nvim_win_is_valid(M.get_winnr()) then local winnr = self:get_winnr()
vim.wo[M.get_winnr()].winhl = M.View.winopts.winhl if winnr and vim.api.nvim_win_is_valid(winnr) then
vim.wo[self:get_winnr()].winhl = self.View.winopts.winhl
end end
end end
function M.setup(opts) ---Check if width determined or calculated on-fly
local options = opts.view or {} ---@return boolean
M.View.centralize_selection = options.centralize_selection function ExplorerView:is_width_determined()
M.View.side = (options.side == "right") and "right" or "left" return type(self.View.width) ~= "function"
M.View.height = options.height end
M.View.hide_root_folder = opts.renderer.root_folder_label == false
M.View.tab = opts.tab
M.View.preserve_window_proportions = options.preserve_window_proportions
M.View.winopts.cursorline = options.cursorline
M.View.winopts.number = options.number
M.View.winopts.relativenumber = options.relativenumber
M.View.winopts.signcolumn = options.signcolumn
M.View.float = options.float
M.on_attach = opts.on_attach
if type(options.width) == "table" then ---Configure width-related config
M.View.adaptive_size = true ---@param width string|function|number|table|nil
M.View.width = options.width.min or DEFAULT_MIN_WIDTH function ExplorerView:configure_width(width)
M.View.max_width = options.width.max or DEFAULT_MAX_WIDTH if type(width) == "table" then
M.View.padding = options.width.padding or DEFAULT_PADDING self.View.adaptive_size = true
self.View.width = width.min or DEFAULT_MIN_WIDTH
self.View.max_width = width.max or DEFAULT_MAX_WIDTH
self.View.padding = width.padding or DEFAULT_PADDING
elseif width == nil then
if self.config.width ~= nil then
-- if we had input config - fallback to it
self.configure_width(self.config.width)
else else
M.View.adaptive_size = false -- otherwise - restore initial width
M.View.width = options.width self.View.width = self.View.initial_width
end
else
self.View.adaptive_size = false
self.View.width = width
end end
M.View.initial_width = get_width()
end end
return M return ExplorerView

View File

@@ -40,11 +40,15 @@ local function is_folder_ignored(path)
end end
end end
if type(M.config.filesystem_watchers.ignore_dirs) == "table" then
for _, ignore_dir in ipairs(M.config.filesystem_watchers.ignore_dirs) do for _, ignore_dir in ipairs(M.config.filesystem_watchers.ignore_dirs) do
if vim.fn.match(path, ignore_dir) ~= -1 then if vim.fn.match(path, ignore_dir) ~= -1 then
return true return true
end end
end end
elseif type(M.config.filesystem_watchers.ignore_dirs) == "function" then
return M.config.filesystem_watchers.ignore_dirs(path)
end
return false return false
end end

View File

@@ -170,15 +170,21 @@ function M.get_toplevel(path)
if not toplevel or not git_dir then if not toplevel or not git_dir then
return nil return nil
end end
local toplevel_norm = vim.fn.fnamemodify(toplevel, ":p")
-- ignore disabled paths -- ignore disabled paths
if type(M.config.git.disable_for_dirs) == "table" then
for _, disabled_for_dir in ipairs(M.config.git.disable_for_dirs) do for _, disabled_for_dir in ipairs(M.config.git.disable_for_dirs) do
local toplevel_norm = vim.fn.fnamemodify(toplevel, ":p")
local disabled_norm = vim.fn.fnamemodify(disabled_for_dir, ":p") local disabled_norm = vim.fn.fnamemodify(disabled_for_dir, ":p")
if toplevel_norm == disabled_norm then if toplevel_norm == disabled_norm then
return nil return nil
end end
end end
elseif type(M.config.git.disable_for_dirs) == "function" then
if M.config.git.disable_for_dirs(toplevel_norm) then
return nil
end
end
M._toplevels_by_path[path] = toplevel M._toplevels_by_path[path] = toplevel
M._git_dirs_by_toplevel[toplevel] = git_dir M._git_dirs_by_toplevel[toplevel] = git_dir

View File

@@ -173,7 +173,12 @@ local function open()
-- populate it -- populate it
vim.api.nvim_buf_set_lines(M.bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(M.bufnr, 0, -1, false, lines)
vim.api.nvim_buf_set_option(M.bufnr, "modifiable", false)
if vim.fn.has "nvim-0.10" == 1 then
vim.api.nvim_set_option_value("modifiable", false, { buf = M.bufnr })
else
vim.api.nvim_buf_set_option(M.bufnr, "modifiable", false) ---@diagnostic disable-line: deprecated
end
-- highlight it -- highlight it
for _, h in ipairs(hl) do for _, h in ipairs(hl) do

View File

@@ -1,8 +1,8 @@
local renderer = require "nvim-tree.renderer" local renderer = require "nvim-tree.renderer"
local view = require "nvim-tree.view"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local notify = require "nvim-tree.notify"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
---@class LibOpenOpts ---@class LibOpenOpts
@@ -16,11 +16,12 @@ local M = {
---@return Node|nil ---@return Node|nil
function M.get_node_at_cursor() function M.get_node_at_cursor()
if not core.get_explorer() then local explorer = core.get_explorer()
if not explorer then
return return
end end
local winnr = view.get_winnr() local winnr = explorer.view:get_winnr()
if not winnr then if not winnr then
return return
end end
@@ -28,7 +29,7 @@ function M.get_node_at_cursor()
local cursor = vim.api.nvim_win_get_cursor(winnr) local cursor = vim.api.nvim_win_get_cursor(winnr)
local line = cursor[1] local line = cursor[1]
if line == 1 and view.is_root_folder_visible(core.get_cwd()) then if line == 1 and explorer.view:is_root_folder_visible(core.get_cwd()) then
return { name = ".." } return { name = ".." }
end end
@@ -84,8 +85,7 @@ function M.get_last_group_node(node)
node = node.group_next node = node.group_next
end end
---@diagnostic disable-next-line: return-type-mismatch -- it can't be nil return node ---@diagnostic disable-line: return-type-mismatch -- it can't be nil
return node
end end
---Group empty folders ---Group empty folders
@@ -189,8 +189,12 @@ local function handle_buf_cwd(cwd)
end end
local function open_view_and_draw() local function open_view_and_draw()
local explorer = core.get_explorer()
if not explorer then
return
end
local cwd = vim.fn.getcwd() local cwd = vim.fn.getcwd()
view.open() explorer.view:open()
handle_buf_cwd(cwd) handle_buf_cwd(cwd)
renderer.draw() renderer.draw()
end end
@@ -198,8 +202,15 @@ end
local function should_hijack_current_buf() local function should_hijack_current_buf()
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
local bufname = vim.api.nvim_buf_get_name(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr)
local bufmodified = vim.api.nvim_buf_get_option(bufnr, "modified")
local ft = vim.api.nvim_buf_get_option(bufnr, "ft") local bufmodified, ft
if vim.fn.has "nvim-0.10" == 1 then
bufmodified = vim.api.nvim_get_option_value("modified", { buf = bufnr })
ft = vim.api.nvim_get_option_value("ft", { buf = bufnr })
else
bufmodified = vim.api.nvim_buf_get_option(bufnr, "modified") ---@diagnostic disable-line: deprecated
ft = vim.api.nvim_buf_get_option(bufnr, "ft") ---@diagnostic disable-line: deprecated
end
local should_hijack_unnamed = M.hijack_unnamed_buffer_when_opening and bufname == "" and not bufmodified and ft == "" local should_hijack_unnamed = M.hijack_unnamed_buffer_when_opening and bufname == "" and not bufmodified and ft == ""
local should_hijack_dir = bufname ~= "" and vim.fn.isdirectory(bufname) == 1 and M.hijack_directories.enable local should_hijack_dir = bufname ~= "" and vim.fn.isdirectory(bufname) == 1 and M.hijack_directories.enable
@@ -243,22 +254,35 @@ function M.open(opts)
M.set_target_win() M.set_target_win()
if not core.get_explorer() or opts.path then if not core.get_explorer() or opts.path then
core.init(opts.path or vim.loop.cwd()) if opts.path then
core.init(opts.path)
else
local cwd, err = vim.loop.cwd()
if not cwd then
notify.error(string.format("current working directory unavailable: %s", err))
return
end
core.init(cwd)
end
end
local explorer = core.get_explorer()
if not explorer then
return
end end
if should_hijack_current_buf() then if should_hijack_current_buf() then
view.close_this_tab_only() explorer.view:close_this_tab_only()
view.open_in_win() explorer.view:open_in_win()
renderer.draw() renderer.draw()
elseif opts.winid then elseif opts.winid then
view.open_in_win { hijack_current_buf = false, resize = false, winid = opts.winid } explorer.view:open_in_win { hijack_current_buf = false, resize = false, winid = opts.winid }
renderer.draw() renderer.draw()
elseif opts.current_window then elseif opts.current_window then
view.open_in_win { hijack_current_buf = false, resize = false } explorer.view:open_in_win { hijack_current_buf = false, resize = false }
renderer.draw() renderer.draw()
else else
open_view_and_draw() open_view_and_draw()
end end
view.restore_tab_state() explorer.view:restore_tab_state()
events._dispatch_on_tree_open() events._dispatch_on_tree_open()
end end

View File

@@ -1,191 +0,0 @@
local view = require "nvim-tree.view"
local utils = require "nvim-tree.utils"
local Iterator = require "nvim-tree.iterators.node-iterator"
local filters = require "nvim-tree.explorer.filters"
local M = {
filter = nil,
}
local function redraw()
require("nvim-tree.renderer").draw()
end
---@param node_ Node|nil
local function reset_filter(node_)
node_ = node_ or require("nvim-tree.core").get_explorer()
if node_ == nil then
return
end
Iterator.builder(node_.nodes)
:hidden()
:applier(function(node)
node.hidden = false
end)
:iterate()
end
local overlay_bufnr = nil
local overlay_winnr = nil
local function remove_overlay()
if view.View.float.enable and view.View.float.quit_on_focus_loss then
-- return to normal nvim-tree float behaviour when filter window is closed
vim.api.nvim_create_autocmd("WinLeave", {
pattern = "NvimTree_*",
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
callback = function()
if utils.is_nvim_tree_buf(0) then
view.close()
end
end,
})
end
vim.api.nvim_win_close(overlay_winnr, true)
vim.api.nvim_buf_delete(overlay_bufnr, { force = true })
overlay_bufnr = nil
overlay_winnr = nil
if M.filter == "" then
M.clear_filter()
end
end
---@param node Node
---@return boolean
local function matches(node)
if not filters.config.enable then
return true
end
local path = node.absolute_path
local name = vim.fn.fnamemodify(path, ":t")
return vim.regex(M.filter):match_str(name) ~= nil
end
---@param node_ Node|nil
function M.apply_filter(node_)
if not M.filter or M.filter == "" then
reset_filter(node_)
return
end
-- TODO(kiyan): this iterator cannot yet be refactored with the Iterator module
-- since the node mapper is based on its children
local function iterate(node)
local filtered_nodes = 0
local nodes = node.group_next and { node.group_next } or node.nodes
if nodes then
for _, n in pairs(nodes) do
iterate(n)
if n.hidden then
filtered_nodes = filtered_nodes + 1
end
end
end
local has_nodes = nodes and (M.always_show_folders or #nodes > filtered_nodes)
local ok, is_match = pcall(matches, node)
node.hidden = not (has_nodes or (ok and is_match))
end
iterate(node_ or require("nvim-tree.core").get_explorer())
end
local function record_char()
vim.schedule(function()
M.filter = vim.api.nvim_buf_get_lines(overlay_bufnr, 0, -1, false)[1]
M.apply_filter()
redraw()
end)
end
local function configure_buffer_overlay()
overlay_bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_attach(overlay_bufnr, true, {
on_lines = record_char,
})
vim.api.nvim_create_autocmd("InsertLeave", {
callback = remove_overlay,
once = true,
})
vim.api.nvim_buf_set_keymap(overlay_bufnr, "i", "<CR>", "<cmd>stopinsert<CR>", {})
end
---@return integer
local function calculate_overlay_win_width()
local wininfo = vim.fn.getwininfo(view.get_winnr())[1]
if wininfo then
return wininfo.width - wininfo.textoff - #M.prefix
end
return 20
end
local function create_overlay()
if view.View.float.enable then
-- don't close nvim-tree float when focus is changed to filter window
vim.api.nvim_clear_autocmds {
event = "WinLeave",
pattern = "NvimTree_*",
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
}
end
configure_buffer_overlay()
overlay_winnr = vim.api.nvim_open_win(overlay_bufnr, true, {
col = 1,
row = 0,
relative = "cursor",
width = calculate_overlay_win_width(),
height = 1,
border = "none",
style = "minimal",
})
vim.api.nvim_buf_set_option(overlay_bufnr, "modifiable", true)
vim.api.nvim_buf_set_lines(overlay_bufnr, 0, -1, false, { M.filter })
vim.cmd "startinsert"
vim.api.nvim_win_set_cursor(overlay_winnr, { 1, #M.filter + 1 })
end
function M.start_filtering()
view.View.live_filter.prev_focused_node = require("nvim-tree.lib").get_node_at_cursor()
M.filter = M.filter or ""
redraw()
local row = require("nvim-tree.core").get_nodes_starting_line() - 1
local col = #M.prefix > 0 and #M.prefix - 1 or 1
view.set_cursor { row, col }
-- needs scheduling to let the cursor move before initializing the window
vim.schedule(create_overlay)
end
function M.clear_filter()
local node = require("nvim-tree.lib").get_node_at_cursor()
local last_node = view.View.live_filter.prev_focused_node
M.filter = nil
reset_filter()
redraw()
if node then
utils.focus_file(node.absolute_path)
elseif last_node then
utils.focus_file(last_node.absolute_path)
end
end
function M.setup(opts)
M.prefix = opts.live_filter.prefix
M.always_show_folders = opts.live_filter.always_show_folders
end
return M

View File

@@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local remove_file = require "nvim-tree.actions.fs.remove-file" local remove_file = require "nvim-tree.actions.fs.remove-file"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
@@ -10,12 +9,13 @@ local M = {
--- Delete nodes; each removal will be optionally notified --- Delete nodes; each removal will be optionally notified
---@param nodes Node[] ---@param nodes Node[]
local function do_delete(nodes) ---@param marks Marks
local function do_delete(marks, nodes)
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
remove_file.remove(node) remove_file.remove(node)
end end
marks.clear_marks() marks:clear_marks()
if not M.config.filesystem_watchers.enable then if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer() require("nvim-tree.actions.reloaders").reload_explorer()
@@ -23,8 +23,15 @@ local function do_delete(nodes)
end end
--- Delete marked nodes, optionally prompting --- Delete marked nodes, optionally prompting
function M.bulk_delete() ---@param explorer Explorer
local nodes = marks.get_marks() function M.bulk_delete(explorer)
if not explorer then
return
end
local marks = explorer.marks
local nodes = marks:get_marks()
if not nodes or #nodes == 0 then if not nodes or #nodes == 0 then
notify.warn "No bookmarksed to delete." notify.warn "No bookmarksed to delete."
return return
@@ -36,11 +43,11 @@ function M.bulk_delete()
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short) lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short)
utils.clear_prompt() utils.clear_prompt()
if item_short == "y" then if item_short == "y" then
do_delete(nodes) do_delete(marks, nodes)
end end
end) end)
else else
do_delete(nodes) do_delete(marks, nodes)
end end
end end

View File

@@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local rename_file = require "nvim-tree.actions.fs.rename-file" local rename_file = require "nvim-tree.actions.fs.rename-file"
@@ -9,8 +8,14 @@ local M = {
config = {}, config = {},
} }
function M.bulk_move() ---@param explorer Explorer
if #marks.get_marks() == 0 then function M.bulk_move(explorer)
if not explorer then
return
end
local marks = explorer.marks
if #marks:get_marks() == 0 then
notify.warn "No bookmarks to move." notify.warn "No bookmarks to move."
return return
end end
@@ -40,14 +45,14 @@ function M.bulk_move()
return return
end end
local nodes = marks.get_marks() local nodes = marks:get_marks()
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
local head = vim.fn.fnamemodify(node.absolute_path, ":t") local head = vim.fn.fnamemodify(node.absolute_path, ":t")
local to = utils.path_join { location, head } local to = utils.path_join { location, head }
rename_file.rename(node, to) rename_file.rename(node, to)
end end
marks.clear_marks() marks:clear_marks()
if not M.config.filesystem_watchers.enable then if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer() require("nvim-tree.actions.reloaders").reload_explorer()

View File

@@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local remove_file = require "nvim-tree.actions.fs.trash" local remove_file = require "nvim-tree.actions.fs.trash"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
@@ -14,12 +13,17 @@ local function do_trash(nodes)
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
remove_file.remove(node) remove_file.remove(node)
end end
marks.clear_marks()
end end
function M.bulk_trash() ---@param explorer Explorer
local nodes = marks.get_marks() function M.bulk_trash(explorer)
if not explorer then
return
end
local marks = explorer.marks
local nodes = marks:get_marks()
if not nodes or #nodes == 0 then if not nodes or #nodes == 0 then
notify.warn "No bookmarks to trash." notify.warn "No bookmarks to trash."
return return
@@ -32,10 +36,12 @@ function M.bulk_trash()
utils.clear_prompt() utils.clear_prompt()
if item_short == "y" then if item_short == "y" then
do_trash(nodes) do_trash(nodes)
marks:clear_marks()
end end
end) end)
else else
do_trash(nodes) do_trash(nodes)
marks:clear_marks()
end end
end end

View File

@@ -1,63 +1,73 @@
local renderer = {} -- circular dependency local renderer = {} -- circular dependency
local NvimTreeMarks = {} ---@class Marks
---@field private marks Node[]
local Marks = {}
local M = {} ---@return Marks
function Marks:new()
local o = {}
setmetatable(o, self)
self.__index = self
---@class MinimalNode o.marks = {}
---@field absolute_path string
---@param node Node|MinimalNode return o
local function add_mark(node) end
NvimTreeMarks[node.absolute_path] = node
---@private
---@param node Node
function Marks:add_mark(node)
self.marks[node.absolute_path] = node
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@private
local function remove_mark(node) ---@param node Node
NvimTreeMarks[node.absolute_path] = nil function Marks:remove_mark(node)
self.marks[node.absolute_path] = nil
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@param node Node
function M.toggle_mark(node) function Marks:toggle_mark(node)
if node.absolute_path == nil then if node.absolute_path == nil then
return return
end end
if M.get_mark(node) then if self:get_mark(node) then
remove_mark(node) self:remove_mark(node)
else else
add_mark(node) self:add_mark(node)
end end
renderer.draw() renderer.draw()
end end
function M.clear_marks() function Marks:clear_marks()
NvimTreeMarks = {} self.marks = {}
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@param node Node
---@return table|nil ---@return Node|nil
function M.get_mark(node) function Marks:get_mark(node)
return node and NvimTreeMarks[node.absolute_path] return node and self.marks[node.absolute_path]
end end
---@return table ---@return Node[]
function M.get_marks() function Marks:get_marks()
local list = {} local list = {}
for _, node in pairs(NvimTreeMarks) do for _, node in pairs(self.marks) do
table.insert(list, node) table.insert(list, node)
end end
return list return list
end end
function M.setup(opts) function Marks.setup(opts)
renderer = require "nvim-tree.renderer" renderer = require "nvim-tree.renderer"
require("nvim-tree.marks.bulk-delete").setup(opts) require("nvim-tree.marks.bulk-delete").setup(opts)
@@ -65,4 +75,4 @@ function M.setup(opts)
require("nvim-tree.marks.bulk-move").setup(opts) require("nvim-tree.marks.bulk-move").setup(opts)
end end
return M return Marks

View File

@@ -1,6 +1,5 @@
local Iterator = require "nvim-tree.iterators.node-iterator" local Iterator = require "nvim-tree.iterators.node-iterator"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local Marks = require "nvim-tree.marks"
local open_file = require "nvim-tree.actions.node.open-file" local open_file = require "nvim-tree.actions.node.open-file"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
@@ -9,10 +8,15 @@ local lib = require "nvim-tree.lib"
---@param where string ---@param where string
---@return Node|nil ---@return Node|nil
local function get_nearest(node, where) local function get_nearest(node, where)
local explorer = core.get_explorer()
if not explorer then
return
end
local first, prev, next, last = nil, nil, nil, nil local first, prev, next, last = nil, nil, nil, nil
local found = false local found = false
Iterator.builder(core.get_explorer().nodes) Iterator.builder(explorer.nodes)
:recursor(function(n) :recursor(function(n)
return n.open and n.nodes return n.open and n.nodes
end) end)
@@ -22,7 +26,7 @@ local function get_nearest(node, where)
return return
end end
if not Marks.get_mark(n) then if not explorer.marks:get_mark(n) then
return return
end end
@@ -84,9 +88,14 @@ M.next = navigate_to "next"
M.prev = navigate_to "prev" M.prev = navigate_to "prev"
function M.select() function M.select()
local explorer = core.get_explorer()
if not explorer then
return
end
local list = vim.tbl_map(function(n) local list = vim.tbl_map(function(n)
return n.absolute_path return n.absolute_path
end, Marks.get_marks()) end, explorer.marks:get_marks())
vim.ui.select(list, { vim.ui.select(list, {
prompt = "Select a file to open or a folder to focus", prompt = "Select a file to open or a folder to focus",
@@ -94,7 +103,7 @@ function M.select()
if not choice or choice == "" then if not choice or choice == "" then
return return
end end
local node = Marks.get_mark { absolute_path = choice } local node = explorer.marks:get_mark { absolute_path = choice }
open_or_focus(node) open_or_focus(node)
end) end)
end end

View File

@@ -9,6 +9,7 @@
---@field fs_stat uv.fs_stat.result|nil ---@field fs_stat uv.fs_stat.result|nil
---@field git_status GitStatus|nil ---@field git_status GitStatus|nil
---@field hidden boolean ---@field hidden boolean
---@field is_dot boolean
---@field name string ---@field name string
---@field parent DirNode ---@field parent DirNode
---@field type string ---@field type string

View File

@@ -1,8 +1,6 @@
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local live_filter = require "nvim-tree.live-filter"
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 view = require "nvim-tree.view"
local DecoratorBookmarks = require "nvim-tree.renderer.decorator.bookmarks" local DecoratorBookmarks = require "nvim-tree.renderer.decorator.bookmarks"
local DecoratorCopied = require "nvim-tree.renderer.decorator.copied" local DecoratorCopied = require "nvim-tree.renderer.decorator.copied"
@@ -10,6 +8,7 @@ local DecoratorCut = require "nvim-tree.renderer.decorator.cut"
local DecoratorDiagnostics = require "nvim-tree.renderer.decorator.diagnostics" local DecoratorDiagnostics = require "nvim-tree.renderer.decorator.diagnostics"
local DecoratorGit = require "nvim-tree.renderer.decorator.git" local DecoratorGit = require "nvim-tree.renderer.decorator.git"
local DecoratorModified = require "nvim-tree.renderer.decorator.modified" local DecoratorModified = require "nvim-tree.renderer.decorator.modified"
local DecoratorHidden = require "nvim-tree.renderer.decorator.hidden"
local DecoratorOpened = require "nvim-tree.renderer.decorator.opened" local DecoratorOpened = require "nvim-tree.renderer.decorator.opened"
local pad = require "nvim-tree.renderer.components.padding" local pad = require "nvim-tree.renderer.components.padding"
@@ -60,6 +59,7 @@ function Builder:new()
lines = {}, lines = {},
markers = {}, markers = {},
signs = {}, signs = {},
extmarks = {},
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
@@ -228,6 +228,14 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
add_to_end(line, M.decorators[i]:icons_after(node)) add_to_end(line, M.decorators[i]:icons_after(node))
end end
local rights = {}
for i = #M.decorators, 1, -1 do
add_to_end(rights, M.decorators[i]:icons_right_align(node))
end
if #rights > 0 then
self.extmarks[self.index] = rights
end
return line return line
end end
@@ -295,24 +303,16 @@ function Builder:add_highlights(node)
table.insert(name_groups, name) table.insert(name_groups, name)
end end
-- one or many icon groups; <= 0.8 always uses highest due to lack of a practical nvim_get_hl equivalent -- one or many icon groups
if #icon_groups > 1 then if #icon_groups > 1 then
if vim.fn.has "nvim-0.9" == 1 then
icon_hl_group = self:create_combined_group(icon_groups) icon_hl_group = self:create_combined_group(icon_groups)
else
icon_hl_group = icon_groups[#icon_groups]
end
else else
icon_hl_group = icon_groups[1] icon_hl_group = icon_groups[1]
end end
-- one or many name groups; <= 0.8 always uses highest due to lack of a practical nvim_get_hl equivalent -- one or many name groups
if #name_groups > 1 then if #name_groups > 1 then
if vim.fn.has "nvim-0.9" == 1 then
name_hl_group = self:create_combined_group(name_groups) name_hl_group = self:create_combined_group(name_groups)
else
name_hl_group = name_groups[#name_groups]
end
else else
name_hl_group = name_groups[1] name_hl_group = name_groups[1]
end end
@@ -359,7 +359,8 @@ end
---@private ---@private
function Builder:get_nodes_number(nodes) function Builder:get_nodes_number(nodes)
if not live_filter.filter then local explorer = core.get_explorer()
if not explorer or not explorer.live_filter.filter then
return #nodes return #nodes
end end
@@ -396,24 +397,28 @@ function Builder:format_root_name(root_label)
local label = root_label(self.root_cwd) local label = root_label(self.root_cwd)
if type(label) == "string" then if type(label) == "string" then
return label return label
else
return "???"
end
end end
elseif type(root_label) == "string" then
return utils.path_remove_trailing(vim.fn.fnamemodify(self.root_cwd, root_label)) return utils.path_remove_trailing(vim.fn.fnamemodify(self.root_cwd, root_label))
end
return "???"
end end
---@private ---@private
function Builder:build_header() function Builder:build_header()
if view.is_root_folder_visible(core.get_cwd()) then local explorer = core.get_explorer()
if not explorer then
return
end
if explorer.view:is_root_folder_visible(core.get_cwd()) then
local root_name = self:format_root_name(M.opts.renderer.root_folder_label) local root_name = self:format_root_name(M.opts.renderer.root_folder_label)
table.insert(self.lines, root_name) table.insert(self.lines, root_name)
self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name)) self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name))
self.index = 1 self.index = 1
end end
if live_filter.filter then if explorer.live_filter.filter then
local filter_line = string.format("%s/%s/", M.opts.live_filter.prefix, live_filter.filter) local filter_line = string.format("%s/%s/", M.opts.live_filter.prefix, explorer.live_filter.filter)
table.insert(self.lines, filter_line) table.insert(self.lines, filter_line)
local prefix_length = string.len(M.opts.live_filter.prefix) local prefix_length = string.len(M.opts.live_filter.prefix)
self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length) self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length)
@@ -422,11 +427,21 @@ function Builder:build_header()
end end
end end
---Sanitize lines for rendering.
---Replace newlines with literal \n
---@private
function Builder:sanitize_lines()
self.lines = vim.tbl_map(function(line)
return line and line:gsub("\n", "\\n") or ""
end, self.lines)
end
---Build all lines with highlights and signs ---Build all lines with highlights and signs
---@return Builder ---@return Builder
function Builder:build() function Builder:build()
self:build_header() self:build_header()
self:build_lines() self:build_lines()
self:sanitize_lines()
return self return self
end end
@@ -440,6 +455,7 @@ function Builder.setup(opts)
DecoratorDiagnostics:new(opts), DecoratorDiagnostics:new(opts),
DecoratorBookmarks:new(opts), DecoratorBookmarks:new(opts),
DecoratorModified:new(opts), DecoratorModified:new(opts),
DecoratorHidden:new(opts),
DecoratorOpened:new(opts), DecoratorOpened:new(opts),
DecoratorGit:new(opts), DecoratorGit:new(opts),
} }

View File

@@ -67,12 +67,19 @@ local function show()
}) })
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 = 1 }) local extmarks = vim.api.nvim_buf_get_extmarks(0, ns_id, { line_nr - 1, 0 }, { line_nr - 1, -1 }, { details = true })
vim.api.nvim_win_call(M.popup_win, function() vim.api.nvim_win_call(M.popup_win, function()
vim.api.nvim_buf_set_lines(0, 0, -1, true, { line }) vim.api.nvim_buf_set_lines(0, 0, -1, true, { line })
for _, extmark in ipairs(extmarks) do for _, extmark in ipairs(extmarks) do
local hl = extmark[4] -- nvim 0.10 luadoc is incorrect: vim.api.keyset.get_extmark_item is missing the extmark_id at the start
vim.api.nvim_buf_add_highlight(0, ns_id, hl.hl_group, 0, extmark[3], hl.end_col)
---@cast extmark table
---@type integer
local col = extmark[3]
---@type vim.api.keyset.extmark_details
local details = extmark[4]
vim.api.nvim_buf_add_highlight(0, ns_id, details.hl_group, 0, col, details.end_col)
end end
vim.cmd [[ setlocal nowrap cursorline noswapfile nobuflisted buftype=nofile bufhidden=hide ]] vim.cmd [[ setlocal nowrap cursorline noswapfile nobuflisted buftype=nofile bufhidden=hide ]]
end) end)

View File

@@ -64,9 +64,14 @@ local function get_file_icon_webdev(fname, extension)
elseif string.match(extension, "%.(.*)") then elseif string.match(extension, "%.(.*)") then
-- If there are more extensions to the file, try to grab the icon for them recursively -- If there are more extensions to the file, try to grab the icon for them recursively
return get_file_icon_webdev(fname, string.match(extension, "%.(.*)")) return get_file_icon_webdev(fname, string.match(extension, "%.(.*)"))
else
local devicons_default = M.devicons.get_default_icon()
if devicons_default and type(devicons_default.icon) == "string" and type(devicons_default.name) == "string" then
return devicons_default.icon, "DevIcon" .. devicons_default.name
else else
return get_file_icon_default() return get_file_icon_default()
end end
end
end end
local function config_file_icon() local function config_file_icon()

View File

@@ -1,4 +1,4 @@
local marks = require "nvim-tree.marks" local core = require "nvim-tree.core"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
@@ -34,7 +34,7 @@ end
---@param node Node ---@param node Node
---@return HighlightedString[]|nil icons ---@return HighlightedString[]|nil icons
function DecoratorBookmarks:calculate_icons(node) function DecoratorBookmarks:calculate_icons(node)
if marks.get_mark(node) then if core.get_explorer() and core.get_explorer().marks:get_mark(node) then
return { self.icon } return { self.icon }
end end
end end
@@ -43,7 +43,7 @@ end
---@param node Node ---@param node Node
---@return string|nil group ---@return string|nil group
function DecoratorBookmarks:calculate_highlight(node) function DecoratorBookmarks:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and marks.get_mark(node) then if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().marks:get_mark(node) then
return "NvimTreeBookmarkHL" return "NvimTreeBookmarkHL"
end end
end end

View File

@@ -0,0 +1,55 @@
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local explorer_node = require "nvim-tree.explorer.node"
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorHidden: Decorator
---@field icon HighlightedString|nil
local DecoratorHidden = Decorator:new()
---@param opts table
---@return DecoratorHidden
function DecoratorHidden:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_hidden] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.hidden_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorHidden
if opts.renderer.icons.show.hidden then
o.icon = {
str = opts.renderer.icons.glyphs.hidden,
hl = { "NvimTreeHiddenIcon" },
}
o:define_sign(o.icon)
end
return o
end
---Hidden icon: hidden.enable, renderer.icons.show.hidden and node starts with `.` (dotfile).
---@param node Node
---@return HighlightedString[]|nil icons
function DecoratorHidden:calculate_icons(node)
if self.enabled and explorer_node.is_dotfile(node) then
return { self.icon }
end
end
---Hidden highlight: hidden.enable, renderer.highlight_hidden and node starts with `.` (dotfile).
---@param node Node
---@return string|nil group
function DecoratorHidden:calculate_highlight(node)
if not self.enabled or self.hl_pos == HL_POSITION.none or (not explorer_node.is_dotfile(node)) then
return nil
end
if node.nodes then
return "NvimTreeHiddenFolderHL"
else
return "NvimTreeHiddenFileHL"
end
end
return DecoratorHidden

View File

@@ -74,6 +74,17 @@ function Decorator:icons_after(node)
return self:calculate_icons(node) return self:calculate_icons(node)
end end
---Icons when ICON_PLACEMENT.right_align
---@param node Node
---@return HighlightedString[]|nil icons
function Decorator:icons_right_align(node)
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.right_align then
return
end
return self:calculate_icons(node)
end
---Maybe icons, optionally implemented ---Maybe icons, optionally implemented
---@protected ---@protected
---@param _ Node ---@param _ Node

View File

@@ -1,6 +1,5 @@
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local log = require "nvim-tree.log" local log = require "nvim-tree.log"
local view = require "nvim-tree.view"
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local _padding = require "nvim-tree.renderer.components.padding" local _padding = require "nvim-tree.renderer.components.padding"
@@ -12,61 +11,88 @@ local M = {}
local SIGN_GROUP = "NvimTreeRendererSigns" local SIGN_GROUP = "NvimTreeRendererSigns"
local namespace_id = vim.api.nvim_create_namespace "NvimTreeHighlights" local namespace_highlights_id = vim.api.nvim_create_namespace "NvimTreeHighlights"
local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks"
---@param bufnr number ---@param bufnr number
---@param lines string[] ---@param lines string[]
---@param hl_args AddHighlightArgs[] ---@param hl_args AddHighlightArgs[]
---@param signs string[] ---@param signs string[]
local function _draw(bufnr, lines, hl_args, signs) local function _draw(bufnr, lines, hl_args, signs, extmarks)
vim.api.nvim_buf_set_option(bufnr, "modifiable", true) if vim.fn.has "nvim-0.10" == 1 then
vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr })
else
vim.api.nvim_buf_set_option(bufnr, "modifiable", true) ---@diagnostic disable-line: deprecated
end
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
M.render_hl(bufnr, hl_args) M.render_hl(bufnr, hl_args)
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
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.fn.sign_unplace(SIGN_GROUP) vim.fn.sign_unplace(SIGN_GROUP)
for i, sign_name in pairs(signs) do for i, sign_name in pairs(signs) do
vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 }) vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 })
end end
vim.api.nvim_buf_clear_namespace(bufnr, namespace_extmarks_id, 0, -1)
for i, extname in pairs(extmarks) do
for _, mark in ipairs(extname) do
vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, i, -1, {
virt_text = { { mark.str, mark.hl } },
virt_text_pos = "right_align",
hl_mode = "combine",
})
end
end
end end
function M.render_hl(bufnr, hl) function M.render_hl(bufnr, hl)
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
return return
end end
vim.api.nvim_buf_clear_namespace(bufnr, namespace_id, 0, -1) vim.api.nvim_buf_clear_namespace(bufnr, namespace_highlights_id, 0, -1)
for _, data in ipairs(hl) do for _, data in ipairs(hl) do
if type(data[1]) == "table" then if type(data[1]) == "table" then
for _, group in ipairs(data[1]) do for _, group in ipairs(data[1]) do
vim.api.nvim_buf_add_highlight(bufnr, namespace_id, group, data[2], data[3], data[4]) vim.api.nvim_buf_add_highlight(bufnr, namespace_highlights_id, group, data[2], data[3], data[4])
end end
end end
end end
end end
function M.draw() function M.draw()
local bufnr = view.get_bufnr() local explorer = core.get_explorer()
if not core.get_explorer() or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then if not explorer then
return
end
local bufnr = explorer.view:get_bufnr()
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
return return
end end
local profile = log.profile_start "draw" local profile = log.profile_start "draw"
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr()) local cursor = vim.api.nvim_win_get_cursor(explorer.view:get_winnr() or 0)
icon_component.reset_config() icon_component.reset_config()
local builder = Builder:new():build() local builder = Builder:new():build()
_draw(bufnr, builder.lines, builder.hl_args, builder.signs) _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks)
if cursor and #builder.lines >= cursor[1] then if cursor and #builder.lines >= cursor[1] then
vim.api.nvim_win_set_cursor(view.get_winnr(), cursor) vim.api.nvim_win_set_cursor(explorer.view:get_winnr() or 0, cursor)
end end
view.grow_from_content() explorer.view:grow_from_content()
log.profile_end(profile) log.profile_end(profile)
events._dispatch_on_tree_rendered(bufnr, view.get_winnr()) events._dispatch_on_tree_rendered(bufnr, explorer.view:get_winnr())
end end
function M.setup(opts) function M.setup(opts)

View File

@@ -111,8 +111,11 @@ function M.find_node(nodes, fn)
return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes) return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes)
end) end)
:iterate() :iterate()
i = require("nvim-tree.view").is_root_folder_visible() and i or i - 1 local explorer = require("nvim-tree.core").get_explorer()
i = require("nvim-tree.live-filter").filter and i + 1 or i i = explorer and explorer.view:is_root_folder_visible() and i or i - 1
if explorer and explorer.live_filter.filter then
i = i + 1
end
return node, i return node, i
end end
@@ -226,7 +229,14 @@ function M.rename_loaded_buffers(old_path, new_path)
vim.api.nvim_buf_set_name(buf, new_path .. buf_name:sub(#old_path + 1)) vim.api.nvim_buf_set_name(buf, new_path .. buf_name:sub(#old_path + 1))
-- to avoid the 'overwrite existing file' error message on write for -- to avoid the 'overwrite existing file' error message on write for
-- normal files -- normal files
if vim.api.nvim_buf_get_option(buf, "buftype") == "" then local buftype
if vim.fn.has "nvim-0.10" == 1 then
buftype = vim.api.nvim_get_option_value("buftype", { buf = buf })
else
buftype = vim.api.nvim_buf_get_option(buf, "buftype") ---@diagnostic disable-line: deprecated
end
if buftype == "" then
vim.api.nvim_buf_call(buf, function() vim.api.nvim_buf_call(buf, function()
vim.cmd "silent! write!" vim.cmd "silent! write!"
vim.cmd "edit" vim.cmd "edit"
@@ -406,6 +416,9 @@ function M.debounce(context, timeout, callback)
end end
local timer = vim.loop.new_timer() local timer = vim.loop.new_timer()
if not timer then
return
end
debouncer.timer = timer debouncer.timer = timer
timer:start(timeout, 0, function() timer:start(timeout, 0, function()
timer_stop_close(timer) timer_stop_close(timer)
@@ -431,10 +444,14 @@ function M.debounce(context, timeout, callback)
end end
function M.focus_file(path) function M.focus_file(path)
local _, i = M.find_node(require("nvim-tree.core").get_explorer().nodes, function(node) local explorer = require("nvim-tree.core").get_explorer()
if not explorer then
return
end
local _, i = M.find_node(explorer.nodes, function(node)
return node.absolute_path == path return node.absolute_path == path
end) end)
require("nvim-tree.view").set_cursor { i + 1, 1 } explorer.view:set_cursor { i + 1, 1 }
end end
---Focus node passed as parameter if visible, otherwise focus first visible parent. ---Focus node passed as parameter if visible, otherwise focus first visible parent.
@@ -454,7 +471,7 @@ function M.focus_node_or_parent(node)
end) end)
if found_node or node.parent == nil then if found_node or node.parent == nil then
require("nvim-tree.view").set_cursor { i + 1, 1 } explorer.view:set_cursor { i + 1, 1 }
break break
end end

View File

@@ -29,15 +29,11 @@ fi
# any output is a fail # any output is a fail
case "${OUT}" in case "${OUT}" in
*Diagnosis\ complete*) *Diagnosis\ completed,\ no\ problems\ found*)
if [ -f "${DIR_OUT}/check.json" ]; then
cat "${DIR_OUT}/check.json"
exit 1
else
exit 0 exit 0
fi
;; ;;
*) *)
cat "${DIR_OUT}/check.json"
exit 1 exit 1
;; ;;
esac esac