Compare commits

...

54 Commits

Author SHA1 Message Date
github-actions[bot]
707b24af91 chore(master): release nvim-tree 1.1.1 (#2709)
* chore(master): release nvim-tree 1.1.1

* doc: remove duplicate bug fix entry

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-03-15 12:26:28 +11:00
remvn
76b98109f6 fix: bookmark filter should include parent directory (#2704)
* fix: bookmark filter should include parent directory

* fix: dont match mark's siblings

* fix: match mark from the start

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-03-15 12:21:04 +11:00
Asman Umbetov
cfea5bd080 fix(#2395): marks.bulk.move defaults to directory at cursor (#2688)
* fix(#2395): marks.bulk.move defaults to directory at cursor

* fix(#2395): adds check if node_at_cursor.parent is nil

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-03-15 12:03:06 +11:00
Alexander Courtis
1fd9c98960 fix(#2705): change NvimTreeWindowPicker cterm background from Cyan to more visible DarkBlue (#2708)
fix(#2705): change NvimTreeWindowPicker from Cyan to the more visible DarkBlue
2024-03-15 10:58:40 +11:00
github-actions[bot]
164f11db4f chore(master): release nvim-tree 1.1.0 (#2691)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-03-14 12:10:17 +02:00
Rami Elwan
8f2a50f1cd feat: add api.fs.copy.basename, default mapping ge (#2698)
* feat: add copy basename

* fix: change keymap for copy basename

* fix: use double quotes

* fix: add missing help

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-03-14 16:57:46 +11:00
gegoune
c64becf80c ci: set concurrency and trigger ci on master (#2701) 2024-03-14 07:36:22 +02:00
Alexander Courtis
3c4267eb50 fix(#2695): git toplevel guard against missing paths (#2696) 2024-03-14 16:23:58 +11:00
DB
041dbd18f4 fix: searchcount exception on invalid search regex (#2693)
* fix: wrap searchcount in pcall to avoid error

* fix: searchcount in pcall

---------

Co-authored-by: xVermillionx <xVermillionx@notvalid>
2024-03-09 13:27:23 +11:00
Mohamed Arish
efafd73efa feat(#2630): file renames can now create directories (#2657)
* Added creating of directories when renaming files

* Style check error? fixed

* Forgot, I added back the line of code that creates a directory named as the file and forgot to remove it

* Added a check for file already exists and also switched the is_error values as they were mismatched

* I don't know how but this somehow fixed the creation of a directory?
2024-03-03 12:25:17 +11:00
Alexander Courtis
d52fdeb0a3 docs: add help indexes (#2684)
* docs: add nvim-tree-index-api

* docs: add nvim-tree-index-opts

* docs: add nvim-tree-index-api

* docs: sort indices

* docs: less verbose

* docs: use dictionary sort for indices
2024-02-24 17:53:25 +11:00
Alexander Courtis
7efaa339d3 docs: :help nvim-tree-legacy (#2679)
doc: add help nvim-tree-legacy
2024-02-24 15:50:10 +11:00
Alexander Courtis
030defdb65 docs: add highlight examples to quickstart, document pre-overhaul SpellCap groups (#2680)
* docs: add highlight examples to quickstart, document pre-overhaul SpellLocal groups

* docs: add highlight examples to quickstart

* docs: document pre-overhaul SpellCap groups

* docs: document pre-overhaul SpellCap groups
2024-02-20 13:24:37 +11:00
github-actions[bot]
d35a8d5ec6 chore(master): release nvim-tree 1.0.0 (#2670)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-18 17:28:24 +11:00
Alexander Courtis
d16246a757 chore: release 1.0.0 (#2678)
Release-As: 1.0.0
2024-02-18 17:24:05 +11:00
gegoune
863cf832ce ci: triggers, nvim stable version & env vars (#2671) 2024-02-12 09:49:39 +01:00
dependabot[bot]
c7d4650c38 chore(deps): bump JohnnyMorganz/stylua-action from 3 to 4 (#2672)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 09:48:00 +01:00
darcy
4a87b8b46b feat(#2654): filters.custom may be a function (#2655)
* feat(#2654): add `binaries` field to `filters`

* feat(#2648): allow functions in `filters.custom`

* ci: fix: stylua check

* ci: fix: add new keybind and config to docs

* fix: replace os-specific binary filter with `vim.fn.executable`

* fix: remove function and mapping for `binaries` filter

* fix: add `node` parameter to custom filter function

* fix: update doc for custom filter function signature

* fix: add custom filter to `ACCEPTED_TYPES`

* fix: accept single function for custom filter

* fix: change custom filter on `ACCEPTED_TYPES`

* fix: revert to using `path` for custom filter function

* fix: use `function` type for custom filter

* fix: type for custom filter in help

* fix: custom filter single function no longer mutates `M.config.filter_custom`

* fix: remove dead `if` statement in custom filter

* fix: separate custom filter function from `M.ignore_list`

* doc nit

---------

Co-authored-by: darcy <44690813+darccyy@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-02-11 17:18:40 +11:00
github-actions[bot]
2dbe4ea2b5 chore(master): release nvim-tree 0.100.0 (#2635)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-11 15:49:27 +11:00
Alexander Courtis
39e6fef85a fix(#2415): highlight help header and mappings (#2669) 2024-02-11 15:40:21 +11:00
Alexander Courtis
b278fc25ae feat(#2415): add :NvimTreeHiTest (#2664)
* feat(#2415): add :NvimTreeHiTest

* feat(#2415): split out appearance diagnostics
2024-02-11 14:41:40 +11:00
Zeta
8cbb1db8e9 feat: add node.open.toggle_group_empty, default mapping L (#2647)
* feat: ungrouping empty directories

* add a new api to toggle empty folders

* solve comments

* solve comments

* update help

---------

Co-authored-by: juefei yan <juefeiyan@juefeis-MacBook-Air.local>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-02-04 16:48:56 +11:00
Confidenceman02
f39f7b6fcd fix(#2415): nvim 0.8 highlight overhaul support, limited to only show highest highlight precedence (#2642)
* fix: Add support for get_hl_defs in nvim 0.8

nvim-tree is using `nvim_get_hl` which was introduced in nvim 0.9 to
replace the unstable `get_hl_defs` in the following [commit](https://github.com/neovim/neovim/pull/22693/files).

Unfortunately this raises an error in 0.8 nvim versions due to the
function not existing.

```
Failed to run `config` for nvim-tree.lua
...are/nvim/lazy/nvim-tree.lua/lua/nvim-tree/appearance.lua:199: attempt to call field 'nvim_get_hl' (a nil value)
stacktrace:
  - ~/.config/nvim/lua/confidenceman02/plugins/nvim-tree.lua:14 _in_ **config**
  - ~/.config/nvim/lua/confidenceman02/lazy.lua:14
```

- Fall back to get_hl_defs when detecting 0.8
- Set the 'link' property to nil to emulate `link = false` in
  `builder.lua`

* fix(#2415): nvim 0.8 highlight overhaul support, limited to only show highest highlight precedence

---------

Co-authored-by: Jaime Terreu <jaime@terreu.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-01-30 10:37:32 +11:00
Alexander Courtis
e9ac136a3a fix(#2415): NvimTreeIndentMarker highlight group: FileIcon->FolderIcon (#2656)
fix(#2415): fix NvimTreeIndentMarker highlight group: FileIcon->FolderIcon
2024-01-29 13:28:20 +11:00
Alexander Courtis
d9cb432d2c fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul (#2639)
* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul

* fix(#2415): disambiguate highlight groups, see :help nvim-tree-highlight-overhaul
2024-01-29 12:43:02 +11:00
Alexander Courtis
fbee8a69a4 fix(#2643): correctly apply linked highlight groups in tree window (#2653)
* fix(#2643): correctly apply linked highlight groups in tree window

* fix(#2643): recreate and apply combined highlight groups on colorscheme change
2024-01-29 12:42:19 +11:00
Alexander Courtis
7bdb220d0f fix(#2637): show buffer modified icons and highlights (#2638) 2024-01-21 17:24:43 +11:00
Danila Usachev
48b1d8638f fix(#2632): occasional error stack when locating nvim-tree window (#2633)
fix: passing nil as window handle in view.get_winnr

Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-01-21 15:54:27 +11:00
Tomasz N
75ff64e666 fix: bad column offset when using full_name (#2629)
Co-authored-by: __ <__@__>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-01-21 15:37:46 +11:00
Kevin Ko
74525ac047 fix: allow highlight overrides for DEFAULT_DEFS: NvimTreeFolderIcon, NvimTreeWindowPicker (#2636) 2024-01-21 10:32:28 +11:00
Alexander Courtis
e9c5abe073 feat(#2415): colour and highlight overhaul, see :help nvim-tree-highlight-overhaul (#2455)
* feat(#2415): granular highlight_diagnostics, normalise groups (#2454)

* chore: normalise colours and enable cterm (#2471)

* feat(#2415): granular highlight_git, normalise git groups (#2487)

* docs: update CONTRIBUTING.md (#2485)

* feat(#2415): granular highlight_git, normalise git groups

* feat(#2415): normalise and add modified groups

* feat(#2415): create Decorator class for modified and bookmarks

* feat(#2415): create DecoratorDiagnostics

* feat(#2415): create DecoratorGit

* feat(#2415): create DecoratorGit

* add DecoratorCopied DecoratorCut

* add DecoratorOpened

* remove unloaded_bufnr checks as the view debouncer takes care of it

* Add `renderer.highlight_git` to accepted strings

* fix(#2415): builder refactor (#2538)

* simplify builder signs

* decorators take care of themselves and are priority ordered

* simplify builder hl groups

* refactor builder for icon arrays

* builder use decorators generically

* fix(#2415): harden sign creation (#2539)

* fix(#2415): harden unicode signs

* Decorator tidy

* normalise git sign creation and tidy

* tidy builder

* NvimTreeBookmarkIcon

* tidy HL doc

* tidy HL doc

* tidy HL doc

* tidy builder doc

* standardise on '---@param'

* DiagnosticWarning -> DiagnosticWarn

* annotate decorators

* limit to two highlight groups for line rendering

* style

* apply #2519

* feat(#2415): combined hl groups (#2601)

* feat(#2415): create combined highlight groups

* feat(#2415): create combined highlight groups

* feat(#2415): create combined highlight groups

* ci: allow workflow_dispatch (#2620)

* one and only one hl namespace, required winhl removal

* small tidies

* colors.lua -> appearance.lua

* full-name uses one and only namespace

* don't highlight fast, just apply to namespace, safer win_set_hl

* gut builder (#2622)

collapse Builder

* fix group_empty function check

* feat(#2415): highlight-overhaul release date

---------

Co-authored-by: Akmadan23 <azadahmadi@mailo.com>
2024-01-20 16:12:13 +11:00
Alexander Courtis
f24afa2cef fix(#2624): open file from docked floating window (#2627) 2024-01-14 11:08:15 +11:00
dependabot[bot]
b8c3a23e76 chore(deps): bump actions/checkout from 3 to 4 (#2623)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 10:09:04 +01:00
Alexander Courtis
9f6d3fac82 ci: fix: run on push release-please--branches--master--components--nvim-tree (#2621) 2024-01-08 11:24:19 +11:00
Alexander Courtis
78a5836092 ci: allow workflow_dispatch (#2620) 2024-01-07 10:20:23 +11:00
Alexander Courtis
86810e5c0b ci: run on push release-please--branches--master--components--nvim-tree (#2619) 2024-01-07 09:57:13 +11:00
Antonin Godard
5d13cc8205 feat(#1389): api: recursive node navigation for git and diagnostics (#2525)
* feat(#1389): add next recursive for git and diag moves

The recurse opt can be used to directly go to the next item showing
git/diagnostic status recursively.

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* refactor: status logic in single function

Rename get_status to status_is_valid.

Use status_is_valid function in multiple place to avoid duplicating
code.

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* feat(#1389): add prev recursive for git and diag moves

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* fix(#1389): next recursive: take root node into account

The root node cannot have a status. Previously if moving from the root
node, status_is_valid was trying to fetch the status from it and errored.

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* fix(#1389): doc: remove show_on_open_dirs limitation

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* feat(#1389): move find_node_line to utils

Signed-off-by: Antonin Godard <antoningodard@pm.me>

* feat(#1389): doc: note recursive moves are to files only, tidy

---------

Signed-off-by: Antonin Godard <antoningodard@pm.me>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-01-07 09:08:58 +11:00
Alexander Courtis
6a99f5af78 ci: lua language server and Makefile (#2546)
* ci: add lls-check

* ci: add lls-check to ci.yml

* ci: download lua-language-server binary

* ci: download lua-language-server binary

* ci: dummy failure to test

* Revert "ci: dummy failure to test"

This reverts commit 2bc43bad430209e32a5049a16c56710c4f6e2f7b.

* ci: ignore lls-out

* ci: better name

* ci: shellcheck nits

* ci: add luals libs and tidy

* ci: tidy

* ci: add neovim 0.9.4

* ci: add ci neovim 0.9.4 to lib path

* ci: dummy failure to test

* Revert "ci: dummy failure to test"

This reverts commit 45987335d81ec65fecc6636b339671a9a9fcdd97.

* Revert "ci: add ci neovim 0.9.4 to lib path"

This reverts commit 4f397d6ea8bbdf6e808f9dc9db5ecbae291d8cd4.

* Revert "ci: add neovim 0.9.4"

This reverts commit 46fd1b368d27a1892b55381691723db3b30a7527.

* ci: action downloads and installs luals

* ci: remove workspaces from luals

* ci: consistent script naming

* ci: add quality to contributing

* ci: consistent script naming

* ci: add lsp to diagnostics

* ci: temporary find to enumerate home

* ci: add VIMRUNTIME for lls

* ci: temporary find to enumerate home

* ci: temporary find to enumerate home

* ci: remove temporary find to enumerate home

* ci: correct VIMRUNTIME

* ci: add ${3rd}/luv/library

* ci: note VIMRUNTIME override

* ci: add Makefile

* ci: add Makefile

* ci: add Makefile

* ci: add Makefile

* ci: document checks and fixes

* ci: add help check

* ci: add help check

* ci: dummy help failure

* Revert "ci: dummy help failure"

This reverts commit c50cceaa4a.

* ci: document checks and fixes

* ci: document checks and fixes

* ci: matrix nvim version

* ci: matrix nvim version

* Revert "ci: matrix nvim version"

This reverts commit fcef6a11e9.

* Revert "ci: matrix nvim version"

This reverts commit a8cb50d39d.

* ci: matrix nvim version from env

* ci: matrix nvim version from env

* ci: matrix nvim version from env

* ci: matrix nvim version

* ci: matrix nvim version

* ci: matrix per job

* ci: matrix per job

* ci: many lua versions

* ci: move doc to style

* ci: tidy ci and contributing
2024-01-06 13:18:52 +11:00
github-actions[bot]
f1b3e6a7eb release nvim-tree 0.99.0 (#2587)
* chore(master): release nvim-tree 0.99.0

* doc: tidy changelog

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2024-01-01 12:46:40 +11:00
Alexander Courtis
b6b86e1f3e chore: release 0.99.0
Release-As: 0.99.0
2024-01-01 12:40:29 +11:00
Alexander Courtis
fac4900bd1 fix(#2609): help toggle (#2611) 2024-01-01 12:36:57 +11:00
Azad
f779abaf2a refactor: improve API readability and tidy actions submodules (#2593)
* refactor: improve API readability, tidy actions modules

* Apply requested changes

* `actions/reloaders/reloaders.lua` -> `actions/reloaders.lua`

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2023-12-31 15:52:27 +11:00
Devansh Sharma
dc839a72a6 feat: add kind param to vim.ui.select function calls (#2602)
* feat: add kind param to vim.ui.select function calls

* feat: add kind param to prompts for bookmark actions

* docs: add section for prompts

* docs: add section for prompts

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
2023-12-31 15:37:16 +11:00
geril2207
02ae52357b fix: hijack_cursor on update focused file and vim search (#2600)
refactor: hijack_cursor search skip
2023-12-31 14:40:58 +11:00
Max
96a783fbd6 fix(#2519): Diagnostics Not Updated When Tree Not Visible (#2597)
* fix(#2519): diagnostics overhaul

Signed-off-by: iusmac <iusico.maxim@libero.it>

* fix: Properly filter diagnostics from coc

Also, while we're at it, refactor the lsp function for consistency.
There should be no functional change, just cosmetic.

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Assign diagnostic version per node to reduce overhead

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Require renderer once

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Revert "Require renderer once"

Causes circular requires after the previous commit.

This reverts commit 7413041630.

* Rename `buffer_severity_dict` to `BUFFER_SEVERITY`

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Log diagnostics update properly

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Implement error handling for coc.nvim

Signed-off-by: iusmac <iusico.maxim@libero.it>

* CI style fixes

Signed-off-by: iusmac <iusico.maxim@libero.it>

* Capture `Keyboard interrupt` when handling coc exceptions

Signed-off-by: iusmac <iusico.maxim@libero.it>

* add more doc

---------

Signed-off-by: iusmac <iusico.maxim@libero.it>
Co-authored-by: Alexander Courtis <alex@courtis.org>
2023-12-30 14:30:07 +11:00
Azad
50f30bcd8c feat: add option to skip gitignored files on git navigation (#2583)
* feat: add option to skip gitignored files on git navigation

* Add API bindings

* stylua: ignore
2023-12-19 11:29:01 +01:00
Alexander Courtis
8f92e1edd3 feat(#1850): add "no bookmark" filter (#2571)
* feat(#1850): add no bookmark filter

* feat(#1850): add no bookmark filter - style
2023-12-19 16:18:24 +11:00
gegoune
141c0f97c3 chore: first release (#2588) 2023-12-11 01:36:12 +01:00
Azad
34780aca5b refactor: take single opts param on node navigation (#2584)
* refactor: take single `opts` param on node navigation

* `MoveOpts` -> `NavigationItemOpts`
2023-12-10 23:44:36 +01:00
gegoune
4891d6cec3 ci: fix release-please manifest (#2586)
Release-As: 0.9.0
2023-12-10 11:39:39 +01:00
gegoune
90cff8e468 ci: configure release-please
Release-As: v0.9.0
2023-12-10 11:28:25 +01:00
Alexander Courtis
0a7c24b675 fix(#2568): hijack_cursor positions at top grouped node (#2569)
Co-authored-by: Azad <49314270+Akmadan23@users.noreply.github.com>
2023-12-10 00:13:22 +01:00
Alexander Courtis
27e66c2ea8 refactor(#1645): remove unused open_replacing_current_buffer (#2570) 2023-12-09 12:18:57 +11:00
Azad
2fed5e1010 ci: add style check for doc comments (#2575)
Co-authored-by: Alexander Courtis <alex@courtis.org>
2023-12-09 12:06:06 +11:00
72 changed files with 3182 additions and 1356 deletions

View File

@@ -2,11 +2,13 @@ name: CI
on:
pull_request:
branches:
- '*'
push:
branches:
- master
branches: [master]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
@@ -14,29 +16,69 @@ permissions:
jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
lua_version: [ 5.1 ]
steps:
- uses: actions/checkout@v4
- uses: leafo/gh-actions-lua@v10
with:
luaVersion: "5.1"
luaVersion: ${{ matrix.lua_version }}
- uses: leafo/gh-actions-luarocks@v4
- name: luacheck
run: |
luarocks install luacheck 1.1.1
luacheck lua
- run: luarocks install luacheck 1.1.1
- run: make lint
style:
runs-on: ubuntu-latest
strategy:
matrix:
stylua_version: [ 0.19.1 ]
steps:
- uses: actions/checkout@v4
- name: stylua
uses: JohnnyMorganz/stylua-action@v3
uses: JohnnyMorganz/stylua-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
version: "0.19"
version: ${{ matrix.stylua_version }}
args: --check lua
- run: make style-doc
check:
runs-on: ubuntu-latest
strategy:
matrix:
nvim_version: [ stable, nightly ]
luals_version: [ 3.7.3 ]
steps:
- uses: actions/checkout@v4
- uses: rhysd/action-setup-vim@v1
with:
neovim: true
version: ${{ matrix.nvim_version }}
- name: install luals
run: |
mkdir -p luals
curl -L "https://github.com/LuaLS/lua-language-server/releases/download/${{ matrix.luals_version }}/lua-language-server-${{ matrix.luals_version }}-linux-x64.tar.gz" | tar zx --directory luals
- run: echo "luals/bin" >> "$GITHUB_PATH"
- name: make check
env:
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
run: make check
- run: make help-check

View File

@@ -2,17 +2,20 @@ on:
push:
branches:
- master
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
name: release-please
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: simple
package-name: nvim-tree
command: github-release
- uses: actions/checkout@v4
- name: tag major and minor versions
if: ${{ steps.release.outputs.release_created }}

View File

@@ -6,6 +6,10 @@ on:
- reopened
- edited
- synchronize
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
semantic-pr-subject:
runs-on: ubuntu-latest

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/luals-out/
/luals/

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env bash
#!/bin/sh
stylua . --check || exit 1
luacheck . || exit 1
make

View File

@@ -1,7 +1,14 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"runtime.version" : "Lua 5.1",
"workspace": {
"library": [
"$VIMRUNTIME/lua/vim/lsp",
"${3rd}/luv/library"
]
},
"diagnostics": {
"libraryFiles": "Disable",
"globals": [
"vim"
],

View File

@@ -0,0 +1,3 @@
{
".": "1.1.1"
}

78
CHANGELOG.md Normal file
View File

@@ -0,0 +1,78 @@
# Changelog
## [1.1.1](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.1.0...nvim-tree-v1.1.1) (2024-03-15)
### Bug Fixes
* **#2395:** marks.bulk.move defaults to directory at cursor ([#2688](https://github.com/nvim-tree/nvim-tree.lua/issues/2688)) ([cfea5bd](https://github.com/nvim-tree/nvim-tree.lua/commit/cfea5bd0806aab41bef6014c6cf5a510910ddbdb))
* **#2705:** change NvimTreeWindowPicker cterm background from Cyan to more visible DarkBlue ([#2708](https://github.com/nvim-tree/nvim-tree.lua/issues/2708)) ([1fd9c98](https://github.com/nvim-tree/nvim-tree.lua/commit/1fd9c98960463d2d5d400916c0633b2df016941d))
* bookmark filter should include parent directory ([#2704](https://github.com/nvim-tree/nvim-tree.lua/issues/2704)) ([76b9810](https://github.com/nvim-tree/nvim-tree.lua/commit/76b98109f62caa12b2f1dff472060b2233ea2e90))
## [1.1.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v1.0.0...nvim-tree-v1.1.0) (2024-03-14)
### Features
* **#2630:** file renames can now create directories ([#2657](https://github.com/nvim-tree/nvim-tree.lua/issues/2657)) ([efafd73](https://github.com/nvim-tree/nvim-tree.lua/commit/efafd73efa9bc8c26282aed563ba0f01c7465b06))
* add api.fs.copy.basename, default mapping ge ([#2698](https://github.com/nvim-tree/nvim-tree.lua/issues/2698)) ([8f2a50f](https://github.com/nvim-tree/nvim-tree.lua/commit/8f2a50f1cd0c64003042364cf317c8788eaa6c8c))
### Bug Fixes
* **#2695:** git toplevel guard against missing paths ([#2696](https://github.com/nvim-tree/nvim-tree.lua/issues/2696)) ([3c4267e](https://github.com/nvim-tree/nvim-tree.lua/commit/3c4267eb5045fa86b67fe40c0c63d31efc801e77))
* searchcount exception on invalid search regex ([#2693](https://github.com/nvim-tree/nvim-tree.lua/issues/2693)) ([041dbd1](https://github.com/nvim-tree/nvim-tree.lua/commit/041dbd18f440207ad161503a384e7c82d575db66))
## [1.0.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v0.100.0...nvim-tree-v1.0.0) (2024-02-18)
### Features
* **#2654:** filters.custom may be a function ([#2655](https://github.com/nvim-tree/nvim-tree.lua/issues/2655)) ([4a87b8b](https://github.com/nvim-tree/nvim-tree.lua/commit/4a87b8b46b4a30107971871df3cb7f4c30fdd5d0))
### Miscellaneous Chores
* release 1.0.0 ([#2678](https://github.com/nvim-tree/nvim-tree.lua/issues/2678)) ([d16246a](https://github.com/nvim-tree/nvim-tree.lua/commit/d16246a7575538f77e9246520449b99333c469f7))
## [0.100.0](https://github.com/nvim-tree/nvim-tree.lua/compare/nvim-tree-v0.99.0...nvim-tree-v0.100.0) (2024-02-11)
### Features
* **#1389:** api: recursive node navigation for git and diagnostics ([#2525](https://github.com/nvim-tree/nvim-tree.lua/issues/2525)) ([5d13cc8](https://github.com/nvim-tree/nvim-tree.lua/commit/5d13cc8205bce4963866f73c50f6fdc18a515ffe))
* **#2415:** add :NvimTreeHiTest ([#2664](https://github.com/nvim-tree/nvim-tree.lua/issues/2664)) ([b278fc2](https://github.com/nvim-tree/nvim-tree.lua/commit/b278fc25ae0fc95e4808eb5618f07fc2522fd2b3))
* **#2415:** colour and highlight overhaul, see :help nvim-tree-highlight-overhaul ([#2455](https://github.com/nvim-tree/nvim-tree.lua/issues/2455)) ([e9c5abe](https://github.com/nvim-tree/nvim-tree.lua/commit/e9c5abe073a973f54d3ca10bfe30f253569f4405))
* add node.open.toggle_group_empty, default mapping L ([#2647](https://github.com/nvim-tree/nvim-tree.lua/issues/2647)) ([8cbb1db](https://github.com/nvim-tree/nvim-tree.lua/commit/8cbb1db8e90b62fc56f379992e622e9f919792ce))
### Bug Fixes
* **#2415:** disambiguate highlight groups, see :help nvim-tree-highlight-overhaul ([#2639](https://github.com/nvim-tree/nvim-tree.lua/issues/2639)) ([d9cb432](https://github.com/nvim-tree/nvim-tree.lua/commit/d9cb432d2c8d8fa9267ddbd7535d76fe4df89360))
* **#2415:** fix NvimTreeIndentMarker highlight group: FileIcon-&gt;FolderIcon ([e9ac136](https://github.com/nvim-tree/nvim-tree.lua/commit/e9ac136a3ab996aa8e4253253521dcf2cb66b81b))
* **#2415:** highlight help header and mappings ([#2669](https://github.com/nvim-tree/nvim-tree.lua/issues/2669)) ([39e6fef](https://github.com/nvim-tree/nvim-tree.lua/commit/39e6fef85ac3bb29532b877aa7c9c34911c661af))
* **#2415:** nvim 0.8 highlight overhaul support, limited to only show highest highlight precedence ([#2642](https://github.com/nvim-tree/nvim-tree.lua/issues/2642)) ([f39f7b6](https://github.com/nvim-tree/nvim-tree.lua/commit/f39f7b6fcd3865ac2146de4cb4045286308f2935))
* **#2415:** NvimTreeIndentMarker highlight group: FileIcon-&gt;FolderIcon ([#2656](https://github.com/nvim-tree/nvim-tree.lua/issues/2656)) ([e9ac136](https://github.com/nvim-tree/nvim-tree.lua/commit/e9ac136a3ab996aa8e4253253521dcf2cb66b81b))
* **#2624:** open file from docked floating window ([#2627](https://github.com/nvim-tree/nvim-tree.lua/issues/2627)) ([f24afa2](https://github.com/nvim-tree/nvim-tree.lua/commit/f24afa2cef551122b8bd53bb2e4a7df42343ce2e))
* **#2632:** occasional error stack when locating nvim-tree window ([#2633](https://github.com/nvim-tree/nvim-tree.lua/issues/2633)) ([48b1d86](https://github.com/nvim-tree/nvim-tree.lua/commit/48b1d8638fa3726236ae22e0e48a74ac8ea6592a))
* **#2637:** show buffer modified icons and highlights ([#2638](https://github.com/nvim-tree/nvim-tree.lua/issues/2638)) ([7bdb220](https://github.com/nvim-tree/nvim-tree.lua/commit/7bdb220d0fe604a77361e92cdbc7af1b8a412126))
* **#2643:** correctly apply linked highlight groups in tree window ([#2653](https://github.com/nvim-tree/nvim-tree.lua/issues/2653)) ([fbee8a6](https://github.com/nvim-tree/nvim-tree.lua/commit/fbee8a69a46f558d29ab84e96301425b0501c668))
* allow highlight overrides for DEFAULT_DEFS: NvimTreeFolderIcon, NvimTreeWindowPicker ([#2636](https://github.com/nvim-tree/nvim-tree.lua/issues/2636)) ([74525ac](https://github.com/nvim-tree/nvim-tree.lua/commit/74525ac04760bf0d9fec2bf51474d2b05f36048e))
* bad column offset when using full_name ([#2629](https://github.com/nvim-tree/nvim-tree.lua/issues/2629)) ([75ff64e](https://github.com/nvim-tree/nvim-tree.lua/commit/75ff64e6663fc3b23c72dca32b2f838acefe7c8a))
* passing nil as window handle in view.get_winnr ([48b1d86](https://github.com/nvim-tree/nvim-tree.lua/commit/48b1d8638fa3726236ae22e0e48a74ac8ea6592a))
## 0.99.0 (2024-01-01)
### Features
* **#1850:** add "no bookmark" filter ([#2571](https://github.com/nvim-tree/nvim-tree.lua/issues/2571)) ([8f92e1e](https://github.com/nvim-tree/nvim-tree.lua/commit/8f92e1edd399f839a23776dcc6eee4ba18030370))
* add kind param to vim.ui.select function calls ([#2602](https://github.com/nvim-tree/nvim-tree.lua/issues/2602)) ([dc839a7](https://github.com/nvim-tree/nvim-tree.lua/commit/dc839a72a6496ce22ebd3dd959115cf97c1b20a0))
* add option to skip gitignored files on git navigation ([#2583](https://github.com/nvim-tree/nvim-tree.lua/issues/2583)) ([50f30bc](https://github.com/nvim-tree/nvim-tree.lua/commit/50f30bcd8c62ac4a83d133d738f268279f2c2ce2))
### Bug Fixes
* **#2519:** Diagnostics Not Updated When Tree Not Visible ([#2597](https://github.com/nvim-tree/nvim-tree.lua/issues/2597)) ([96a783f](https://github.com/nvim-tree/nvim-tree.lua/commit/96a783fbd606a458bcce2ef8041240a8b94510ce))
* **#2609:** help toggle ([#2611](https://github.com/nvim-tree/nvim-tree.lua/issues/2611)) ([fac4900](https://github.com/nvim-tree/nvim-tree.lua/commit/fac4900bd18a9fa15be3d104645d9bdef7b3dcec))
* hijack_cursor on update focused file and vim search ([#2600](https://github.com/nvim-tree/nvim-tree.lua/issues/2600)) ([02ae523](https://github.com/nvim-tree/nvim-tree.lua/commit/02ae52357ba4da77a4c120390791584a81d15340))

View File

@@ -4,31 +4,82 @@ Thank you for contributing.
See [Development](https://github.com/nvim-tree/nvim-tree.lua/wiki/Development) for environment setup, tips and tools.
## Styling and formatting
# Tools
Code is formatted using luacheck, and linted using stylua.
You can install these with:
Following are used during CI and strongly recommended during local development.
```bash
luarocks install luacheck
cargo install stylua
Lint: [luacheck](https://github.com/lunarmodules/luacheck/)
Style: [StyLua](https://github.com/JohnnyMorganz/StyLua)
Language server: [luals](https://luals.github.io)
You can install them via you OS package manager e.g. `pacman`, `brew` or other via other package managers such as `cargo` or `luarocks`
# Quality
The following quality checks are mandatory and are performed during CI. They run on the entire `lua` directory and return 1 on any failure.
You can run them all via `make` or `make all`
You can setup git hooks to run all checks by running `scripts/setup-hooks.sh`
## lint
1. Runs luacheck quietly using `.luacheck` settings
```sh
make lint
```
You can setup the git hooks by running `scripts/setup-hooks.sh`.
## style
## Adding new actions
1. Runs stylua using `.stylua.toml` settings
1. Runs `scripts/doc-comments.sh` to validate annotated documentation
```sh
make style
```
You can automatically fix stylua issues via:
```sh
make style-fix
```
## check
1. Runs the checks that the LSP lua language server runs inside nvim using `.luarc.json` via `scripts/luals-check.sh`
```sh
make check
```
Assumes `$VIMRUNTIME` is `/usr/share/nvim/runtime`. Adjust as necessary e.g.
```sh
VIMRUNTIME="/my/path/to/runtime" make check
```
# 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.
Once you did, you should run the `scripts/update-help.sh`.
## Documentation
Once you did, you should run `make help-update`
# Documentation
## Opts
When adding new options, you should declare the defaults in the main `nvim-tree.lua` file.
Once you did, you should run the `scripts/update-help.sh`.
Documentation for options should also be added to `nvim-tree-opts` in `doc/nvim-tree-lua.txt`
## Pull Request
## API
When adding or changing API please update :help nvim-tree-api
# Pull Request
Please reference any issues in the description e.g. "resolves #1234".

47
Makefile Normal file
View File

@@ -0,0 +1,47 @@
all: lint style check
#
# mandatory checks
#
lint: luacheck
style: stylua style-doc
check: luals
#
# subtasks
#
luacheck:
luacheck -q lua
stylua:
stylua lua --check
style-doc:
scripts/doc-comments.sh
luals:
scripts/luals-check.sh
#
# fixes
#
style-fix:
stylua lua
#
# utility
#
help-update:
scripts/help-update.sh
#
# CI
#
help-check: help-update
git diff --exit-code doc/nvim-tree-lua.txt
.PHONY: all lint style check luacheck stylua style-doc luals style-fix help-update help-check

View File

@@ -38,6 +38,8 @@ Please install via your preferred package manager. See [Installation](https://gi
`nvim-tree/nvim-tree.lua`
Major or minor versions may be specified via tags: `v<MAJOR>` e.g. `v1` or `v<MAJOR>.<MINOR>` e.g. `v1.23`
`nvim-tree/nvim-web-devicons` optional, for file icons
Disabling [netrw](https://neovim.io/doc/user/pi_netrw.html) is strongly advised, see [:help nvim-tree-netrw](doc/nvim-tree-lua.txt)
@@ -53,7 +55,7 @@ Setup the plugin in your `init.lua`
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
-- set termguicolors to enable highlight groups
-- optionally enable 24-bit colour
vim.opt.termguicolors = true
-- empty setup using defaults
@@ -110,6 +112,23 @@ require("nvim-tree").setup {
}
```
### Highlight
Run `:NvimTreeHiTest` to show all the highlights that nvim-tree uses.
They can be customised before or after setup is called and will be immediately
applied at runtime. e.g.
```lua
vim.cmd([[
:hi NvimTreeExecFile guifg=#ffa0a0
:hi NvimTreeSpecialFile guifg=#ff80ff gui=underline
:hi NvimTreeSymlink guifg=Yellow gui=italic
:hi link NvimTreeImageFile Title
]])
```
See [:help nvim-tree-highlight](doc/nvim-tree-lua.txt) for details.
## Commands
See [:help nvim-tree-commands](doc/nvim-tree-lua.txt)

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,16 @@
local lib = require "nvim-tree.lib"
local log = require "nvim-tree.log"
local colors = require "nvim-tree.colors"
local appearance = require "nvim-tree.appearance"
local renderer = require "nvim-tree.renderer"
local view = require "nvim-tree.view"
local commands = require "nvim-tree.commands"
local utils = require "nvim-tree.utils"
local change_dir = require "nvim-tree.actions.root.change-dir"
local actions = require "nvim-tree.actions"
local legacy = require "nvim-tree.legacy"
local core = require "nvim-tree.core"
local reloaders = require "nvim-tree.actions.reloaders.reloaders"
local git = require "nvim-tree.git"
local filters = require "nvim-tree.explorer.filters"
local modified = require "nvim-tree.modified"
local find_file = require "nvim-tree.actions.tree.find-file"
local buffers = require "nvim-tree.buffers"
local events = require "nvim-tree.events"
local notify = require "nvim-tree.notify"
@@ -51,7 +49,7 @@ function M.change_root(path, bufnr)
-- test if in vim_cwd
if utils.path_relative(path, vim_cwd) ~= path then
if vim_cwd ~= cwd then
change_dir.fn(vim_cwd)
actions.root.change_dir.fn(vim_cwd)
end
return
end
@@ -62,43 +60,19 @@ function M.change_root(path, bufnr)
-- otherwise test M.init_root
if _config.prefer_startup_root and utils.path_relative(path, M.init_root) ~= path then
change_dir.fn(M.init_root)
actions.root.change_dir.fn(M.init_root)
return
end
-- otherwise root_dirs
for _, dir in pairs(_config.root_dirs) do
dir = vim.fn.fnamemodify(dir, ":p")
if utils.path_relative(path, dir) ~= path then
change_dir.fn(dir)
actions.root.change_dir.fn(dir)
return
end
end
-- finally fall back to the folder containing the file
change_dir.fn(vim.fn.fnamemodify(path, ":p:h"))
end
---@param cwd string|nil
function M.open_replacing_current_buffer(cwd)
if view.is_visible() then
return
end
local buf = vim.api.nvim_get_current_buf()
local bufname = vim.api.nvim_buf_get_name(buf)
if bufname == "" or vim.loop.fs_stat(bufname) == nil then
return
end
if cwd == "" or cwd == nil then
cwd = vim.fn.fnamemodify(bufname, ":p:h")
end
if not core.get_explorer() or cwd ~= core.get_cwd() then
core.init(cwd)
end
view.open_in_win { hijack_current_buf = false, resize = false }
require("nvim-tree.renderer").draw()
require("nvim-tree.actions.finders.find-file").fn(bufname)
actions.root.change_dir.fn(vim.fn.fnamemodify(path, ":p:h"))
end
function M.tab_enter()
@@ -111,7 +85,7 @@ function M.tab_enter()
end
end
view.open { focus_tree = false }
require("nvim-tree.renderer").draw()
renderer.draw()
end
end
@@ -127,27 +101,20 @@ function M.open_on_directory()
return
end
change_dir.force_dirchange(bufname, true)
actions.root.change_dir.force_dirchange(bufname, true)
end
function M.reset_highlight()
colors.setup()
view.reset_winhl()
renderer.render_hl(view.get_bufnr())
end
local prev_line
function M.place_cursor_on_node()
local l = vim.api.nvim_win_get_cursor(0)[1]
if l == prev_line then
local ok, search = pcall(vim.fn.searchcount)
if ok and search and search.exact_match == 1 then
return
end
prev_line = l
local node = lib.get_node_at_cursor()
if not node or node.name == ".." then
return
end
node = utils.get_parent_of_group(node)
local line = vim.api.nvim_get_current_line()
local cursor = vim.api.nvim_win_get_cursor(0)
@@ -179,11 +146,11 @@ end
---@param name string|nil
function M.change_dir(name)
if name then
change_dir.fn(name)
actions.root.change_dir.fn(name)
end
if _config.update_focused_file.enable then
find_file.fn()
actions.tree.find_file.fn()
end
end
@@ -195,8 +162,14 @@ local function setup_autocommands(opts)
vim.api.nvim_create_autocmd(name, vim.tbl_extend("force", default_opts, custom_opts))
end
-- reset highlights when colorscheme is changed
create_nvim_tree_autocmd("ColorScheme", { callback = M.reset_highlight })
-- reset and draw (highlights) when colorscheme is changed
create_nvim_tree_autocmd("ColorScheme", {
callback = function()
appearance.setup()
view.reset_winhl()
renderer.draw()
end,
})
-- prevent new opened file from opening in the same window as nvim-tree
create_nvim_tree_autocmd("BufWipeout", {
@@ -216,7 +189,7 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("BufWritePost", {
callback = function()
if opts.auto_reload_on_write and not opts.filesystem_watchers.enable then
reloaders.reload_explorer()
actions.reloaders.reload_explorer()
end
end,
})
@@ -226,7 +199,7 @@ local function setup_autocommands(opts)
-- update opened file buffers
if (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()
reloaders.reload_explorer()
actions.reloaders.reload_explorer()
end)
end
end,
@@ -237,7 +210,7 @@ local function setup_autocommands(opts)
-- update opened file buffers
if (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()
reloaders.reload_explorer(nil, data.buf)
actions.reloaders.reload_explorer()
end)
end
end,
@@ -247,7 +220,7 @@ local function setup_autocommands(opts)
pattern = { "FugitiveChanged", "NeogitStatusRefreshed" },
callback = function()
if not opts.filesystem_watchers.enable and opts.git.enable then
reloaders.reload_git()
actions.reloaders.reload_git()
end
end,
})
@@ -276,7 +249,7 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("BufEnter", {
callback = function()
utils.debounce("BufEnter:find_file", opts.view.debounce_delay, function()
find_file.fn()
actions.tree.find_file.fn()
end)
end,
})
@@ -291,7 +264,7 @@ local function setup_autocommands(opts)
callback = function()
if utils.is_nvim_tree_buf(0) then
if vim.fn.getcwd() ~= core.get_cwd() or (opts.reload_on_bufenter and not opts.filesystem_watchers.enable) then
reloaders.reload_explorer()
actions.reloaders.reload_explorer()
end
end
end,
@@ -341,8 +314,8 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd({ "BufModifiedSet", "BufWritePost" }, {
callback = function()
utils.debounce("Buf:modified", opts.view.debounce_delay, function()
modified.reload()
reloaders.reload_explorer()
buffers.reload_modified()
actions.reloaders.reload_explorer()
end)
end,
})
@@ -413,8 +386,8 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
indent_width = 2,
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
symlink_destination = true,
highlight_git = false,
highlight_diagnostics = false,
highlight_git = "none",
highlight_diagnostics = "none",
highlight_opened_files = "none",
highlight_modified = "none",
highlight_bookmarks = "none",
@@ -530,6 +503,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
dotfiles = false,
git_clean = false,
no_buffer = false,
no_bookmark = false,
custom = {},
exclude = {},
},
@@ -649,6 +623,9 @@ local ACCEPTED_TYPES = {
group_empty = { "boolean", "function" },
root_folder_label = { "function", "string", "boolean" },
},
filters = {
custom = { "function" },
},
actions = {
open_file = {
window_picker = {
@@ -667,9 +644,11 @@ local ACCEPTED_STRINGS = {
signcolumn = { "yes", "no", "auto" },
},
renderer = {
highlight_git = { "none", "icon", "name", "all" },
highlight_opened_files = { "none", "icon", "name", "all" },
highlight_modified = { "none", "icon", "name", "all" },
highlight_bookmarks = { "none", "icon", "name", "all" },
highlight_diagnostics = { "none", "icon", "name", "all" },
highlight_clipboard = { "none", "icon", "name", "all" },
icons = {
git_placement = { "before", "after", "signcolumn" },
@@ -812,7 +791,7 @@ function M.setup(conf)
require("nvim-tree.actions").setup(opts)
require("nvim-tree.keymap").setup(opts)
require("nvim-tree.colors").setup()
require("nvim-tree.appearance").setup()
require("nvim-tree.diagnostics").setup(opts)
require("nvim-tree.explorer").setup(opts)
require("nvim-tree.git").setup(opts)
@@ -822,7 +801,7 @@ function M.setup(conf)
require("nvim-tree.renderer").setup(opts)
require("nvim-tree.live-filter").setup(opts)
require("nvim-tree.marks").setup(opts)
require("nvim-tree.modified").setup(opts)
require("nvim-tree.buffers").setup(opts)
require("nvim-tree.help").setup(opts)
require("nvim-tree.watcher").setup(opts)
if M.config.renderer.icons.show.file and pcall(require, "nvim-web-devicons") then

View File

@@ -0,0 +1,6 @@
local M = {}
M.find_file = require "nvim-tree.actions.finders.find-file"
M.search_node = require "nvim-tree.actions.finders.search-node"
return M

View File

@@ -5,9 +5,7 @@ local core = require "nvim-tree.core"
local events = require "nvim-tree.events"
local notify = require "nvim-tree.notify"
local renderer = require "nvim-tree.renderer"
local reloaders = require "nvim-tree.actions.reloaders.reloaders"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local reloaders = require "nvim-tree.actions.reloaders"
local find_file = require("nvim-tree.actions.finders.find-file").fn
@@ -131,7 +129,7 @@ local function do_single_paste(source, dest, action_type, action_fn)
else
local prompt_select = "Overwrite " .. dest .. " ?"
local prompt_input = prompt_select .. " R(ename)/y/n: "
lib.prompt(prompt_input, prompt_select, { "", "y", "n" }, { "Rename", "Yes", "No" }, function(item_short)
lib.prompt(prompt_input, prompt_select, { "", "y", "n" }, { "Rename", "Yes", "No" }, "nvimtree_overwrite_rename", function(item_short)
utils.clear_prompt()
if item_short == "y" then
on_process()
@@ -297,6 +295,12 @@ function M.copy_filename(node)
copy_to_clipboard(node.name)
end
---@param node Node
function M.copy_basename(node)
local basename = vim.fn.fnamemodify(node.name, ":r")
copy_to_clipboard(basename)
end
---@param node Node
function M.copy_path(node)
local absolute_path = node.absolute_path
@@ -317,34 +321,23 @@ function M.copy_absolute_path(node)
copy_to_clipboard(content)
end
--- Clipboard text highlight group and position when highlight_clipboard.
---Node is cut. Will not be copied.
---@param node Node
---@return HL_POSITION position none when clipboard empty
---@return string|nil group only when node present in clipboard
function M.get_highlight(node)
if M.hl_pos == HL_POSITION.none then
return HL_POSITION.none, nil
end
---@return boolean
function M.is_cut(node)
return vim.tbl_contains(clipboard.cut, node)
end
for _, n in ipairs(clipboard.cut) do
if node == n then
return M.hl_pos, "NvimTreeCutHL"
end
end
for _, n in ipairs(clipboard.copy) do
if node == n then
return M.hl_pos, "NvimTreeCopiedHL"
end
end
return HL_POSITION.none, nil
---Node is copied. Will not be cut.
---@param node Node
---@return boolean
function M.is_copied(node)
return vim.tbl_contains(clipboard.copy, node)
end
function M.setup(opts)
M.config.filesystem_watchers = opts.filesystem_watchers
M.config.actions = opts.actions
M.hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none
end
return M

View File

@@ -0,0 +1,16 @@
local M = {}
M.copy_paste = require "nvim-tree.actions.fs.copy-paste"
M.create_file = require "nvim-tree.actions.fs.create-file"
M.remove_file = require "nvim-tree.actions.fs.remove-file"
M.rename_file = require "nvim-tree.actions.fs.rename-file"
M.trash = require "nvim-tree.actions.fs.trash"
function M.setup(opts)
M.copy_paste.setup(opts)
M.remove_file.setup(opts)
M.rename_file.setup(opts)
M.trash.setup(opts)
end
return M

View File

@@ -112,7 +112,7 @@ function M.fn(node)
local function do_remove()
M.remove(node)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
require("nvim-tree.actions.reloaders").reload_explorer()
end
end
@@ -130,7 +130,7 @@ function M.fn(node)
items_long = { "No", "Yes" }
end
lib.prompt(prompt_input, prompt_select, items_short, items_long, function(item_short)
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_remove", function(item_short)
utils.clear_prompt()
if item_short == "y" or item_short == (M.config.ui.confirm.default_yes and "") then
do_remove()

View File

@@ -9,6 +9,16 @@ local M = {
config = {},
}
---@param iter function iterable
---@return integer
local function get_num_nodes(iter)
local i = 0
for _ in iter do
i = i + 1
end
return i
end
local ALLOWED_MODIFIERS = {
[":p"] = true,
[":p:h"] = true,
@@ -31,15 +41,46 @@ function M.rename(node, to)
return
end
events._dispatch_will_rename_node(node.absolute_path, to)
local success, err = vim.loop.fs_rename(node.absolute_path, to)
if not success then
notify.warn(err_fmt(notify_from, notify_to, err))
return
-- create a folder for each path element if the folder does not exist
local idx = 0
local path_to_create = ""
local num_nodes = get_num_nodes(utils.path_split(utils.path_remove_trailing(to)))
local is_error = false
for path in utils.path_split(to) do
idx = idx + 1
local p = utils.path_remove_trailing(path)
if #path_to_create == 0 and vim.fn.has "win32" == 1 then
path_to_create = utils.path_join { p, path_to_create }
else
path_to_create = utils.path_join { path_to_create, p }
end
if idx == num_nodes then
events._dispatch_will_rename_node(node.absolute_path, to)
local success, err = vim.loop.fs_rename(node.absolute_path, to)
if not success then
notify.warn(err_fmt(notify_from, notify_to, err))
return
end
elseif not utils.file_exists(path_to_create) then
local success = vim.loop.fs_mkdir(path_to_create, 493)
if not success then
notify.error("Could not create folder " .. notify.render_path(path_to_create))
is_error = true
break
end
is_error = false
end
end
if not is_error then
notify.info(string.format("%s -> %s", notify_from, notify_to))
utils.rename_loaded_buffers(node.absolute_path, to)
events._dispatch_node_renamed(node.absolute_path, to)
end
notify.info(string.format("%s -> %s", notify_from, notify_to))
utils.rename_loaded_buffers(node.absolute_path, to)
events._dispatch_node_renamed(node.absolute_path, to)
end
---@param default_modifier string|nil
@@ -102,7 +143,7 @@ function M.fn(default_modifier)
M.rename(node, prepend .. new_file_path .. append)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
require("nvim-tree.actions.reloaders").reload_explorer()
end
find_file(utils.path_remove_trailing(new_file_path))

View File

@@ -1,5 +1,6 @@
local lib = require "nvim-tree.lib"
local notify = require "nvim-tree.notify"
local reloaders = require "nvim-tree.actions.reloaders"
local M = {
config = {},
@@ -59,7 +60,7 @@ function M.remove(node)
end
events._dispatch_folder_removed(node.absolute_path)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
reloaders.reload_explorer()
end
end)
else
@@ -72,7 +73,7 @@ function M.remove(node)
events._dispatch_file_removed(node.absolute_path)
clear_buffer(node.absolute_path)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
reloaders.reload_explorer()
end
end)
end
@@ -102,7 +103,7 @@ function M.fn(node)
items_long = { "No", "Yes" }
end
lib.prompt(prompt_input, prompt_select, items_short, items_long, function(item_short)
lib.prompt(prompt_input, prompt_select, items_short, items_long, "nvimtree_trash", function(item_short)
utils.clear_prompt()
if item_short == "y" or item_short == (M.config.ui.confirm.default_yes and "") then
do_trash()

View File

@@ -1,18 +1,18 @@
local M = {}
M.finders = require "nvim-tree.actions.finders"
M.fs = require "nvim-tree.actions.fs"
M.moves = require "nvim-tree.actions.moves"
M.node = require "nvim-tree.actions.node"
M.reloaders = require "nvim-tree.actions.reloaders"
M.root = require "nvim-tree.actions.root"
M.tree = require "nvim-tree.actions.tree"
function M.setup(opts)
require("nvim-tree.actions.fs.trash").setup(opts)
require("nvim-tree.actions.node.system-open").setup(opts)
require("nvim-tree.actions.node.file-popup").setup(opts)
require("nvim-tree.actions.node.open-file").setup(opts)
require("nvim-tree.actions.root.change-dir").setup(opts)
require("nvim-tree.actions.fs.rename-file").setup(opts)
require("nvim-tree.actions.fs.remove-file").setup(opts)
require("nvim-tree.actions.fs.copy-paste").setup(opts)
require("nvim-tree.actions.tree-modifiers.expand-all").setup(opts)
require("nvim-tree.actions.tree.find-file").setup(opts)
require("nvim-tree.actions.tree.open").setup(opts)
require("nvim-tree.actions.tree.toggle").setup(opts)
M.fs.setup(opts)
M.node.setup(opts)
M.root.setup(opts)
M.tree.setup(opts)
end
return M

View File

@@ -0,0 +1,7 @@
local M = {}
M.item = require "nvim-tree.actions.moves.item"
M.parent = require "nvim-tree.actions.moves.parent"
M.sibling = require "nvim-tree.actions.moves.sibling"
return M

View File

@@ -3,53 +3,234 @@ local view = require "nvim-tree.view"
local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib"
local explorer_node = require "nvim-tree.explorer.node"
local diagnostics = require "nvim-tree.diagnostics"
local M = {}
local MAX_DEPTH = 100
---@param where string
---@param what string
---Return the status of the node or nil if no status, depending on the type of
---status.
---@param node table node to inspect
---@param what string type of status
---@param skip_gitignored boolean default false
---@return boolean
local function status_is_valid(node, what, skip_gitignored)
if what == "git" then
local git_status = explorer_node.get_git_status(node)
return git_status ~= nil and (not skip_gitignored or git_status[1] ~= "!!")
elseif what == "diag" then
local diag_status = diagnostics.get_diag_status(node)
return diag_status ~= nil and diag_status.value ~= nil
elseif what == "opened" then
return vim.fn.bufloaded(node.absolute_path) ~= 0
end
return false
end
---Move to the next node that has a valid status. If none found, don't move.
---@param where string where to move (forwards or backwards)
---@param what string type of status
---@param skip_gitignored boolean default false
local function move(where, what, skip_gitignored)
local node_cur = lib.get_node_at_cursor()
local first_node_line = core.get_nodes_starting_line()
local nodes_by_line = utils.get_nodes_by_line(core.get_explorer().nodes, first_node_line)
local iter_start, iter_end, iter_step, cur, first, nex
if where == "next" then
iter_start, iter_end, iter_step = first_node_line, #nodes_by_line, 1
elseif where == "prev" then
iter_start, iter_end, iter_step = #nodes_by_line, first_node_line, -1
end
for line = iter_start, iter_end, iter_step do
local node = nodes_by_line[line]
local valid = status_is_valid(node, what, skip_gitignored)
if not first and valid then
first = line
end
if node == node_cur then
cur = line
elseif valid and cur then
nex = line
break
end
end
if nex then
view.set_cursor { nex, 0 }
elseif vim.o.wrapscan and first then
view.set_cursor { first, 0 }
end
end
local function expand_node(node)
if not node.open then
-- Expand the node.
-- Should never collapse since we checked open.
lib.expand_or_collapse(node)
end
end
--- Move to the next node recursively.
---@param what string type of status
---@param skip_gitignored boolean default false
local function move_next_recursive(what, skip_gitignored)
-- If the current node:
-- * is a directory
-- * and is not the root node
-- * and has a git/diag status
-- * and is not opened
-- expand it.
local node_init = lib.get_node_at_cursor()
if not node_init then
return
end
local valid = false
if node_init.name ~= ".." then -- root node cannot have a status
valid = status_is_valid(node_init, what, skip_gitignored)
end
if node_init.nodes ~= nil and valid and not node_init.open then
lib.expand_or_collapse(node_init)
end
move("next", what, skip_gitignored)
local node_cur = lib.get_node_at_cursor()
if not node_cur then
return
end
-- If we haven't moved at all at this point, return.
if node_init == node_cur then
return
end
-- i is used to limit iterations.
local i = 0
local is_dir = node_cur.nodes ~= nil
while is_dir and i < MAX_DEPTH do
expand_node(node_cur)
move("next", what, skip_gitignored)
-- Save current node.
node_cur = lib.get_node_at_cursor()
-- Update is_dir.
if node_cur then
is_dir = node_cur.nodes ~= nil
else
is_dir = false
end
i = i + 1
end
end
--- Move to the previous node recursively.
---
--- move_prev_recursive:
---
--- 1) Save current as node_init.
-- 2) Call a non-recursive prev.
--- 3) If current node is node_init's parent, call move_prev_recursive.
--- 4) Else:
--- 4.1) If current node is nil, is node_init (we didn't move), or is a file, return.
--- 4.2) The current file is a directory, expand it.
--- 4.3) Find node_init in current window, and move to it (if not found, return).
--- If node_init is the root node (name = ".."), directly move to position 1.
--- 4.4) Call a non-recursive prev.
--- 4.5) Save the current node and start back from 4.1.
---
---@param what string type of status
---@param skip_gitignored boolean default false
local function move_prev_recursive(what, skip_gitignored)
local node_init, node_cur
-- 1)
node_init = lib.get_node_at_cursor()
if node_init == nil then
return
end
-- 2)
move("prev", what, skip_gitignored)
node_cur = lib.get_node_at_cursor()
if node_cur == node_init.parent then
-- 3)
move_prev_recursive(what, skip_gitignored)
else
-- i is used to limit iterations.
local i = 0
while i < MAX_DEPTH do
-- 4.1)
if
node_cur == nil
or node_cur == node_init -- we didn't move
or not node_cur.nodes -- node is a file
then
return
end
-- 4.2)
local node_dir = node_cur
expand_node(node_dir)
-- 4.3)
if node_init.name == ".." then -- root node
view.set_cursor { 1, 0 } -- move to root node (position 1)
else
local node_init_line = utils.find_node_line(node_init)
if node_init_line < 0 then
return
end
view.set_cursor { node_init_line, 0 }
end
-- 4.4)
move("prev", what, skip_gitignored)
-- 4.5)
node_cur = lib.get_node_at_cursor()
i = i + 1
end
end
end
---@class NavigationItemOpts
---@field where string
---@field what string
---@param opts NavigationItemOpts
---@return fun()
function M.fn(where, what)
function M.fn(opts)
return function()
local node_cur = lib.get_node_at_cursor()
local first_node_line = core.get_nodes_starting_line()
local nodes_by_line = utils.get_nodes_by_line(core.get_explorer().nodes, first_node_line)
local iter_start, iter_end, iter_step, cur, first, nex
local recurse = false
local skip_gitignored = false
if where == "next" then
iter_start, iter_end, iter_step = first_node_line, #nodes_by_line, 1
elseif where == "prev" then
iter_start, iter_end, iter_step = #nodes_by_line, first_node_line, -1
-- recurse only valid for git and diag moves.
if (opts.what == "git" or opts.what == "diag") and opts.recurse ~= nil then
recurse = opts.recurse
end
for line = iter_start, iter_end, iter_step do
local node = nodes_by_line[line]
local valid = false
if what == "git" then
valid = explorer_node.get_git_status(node) ~= nil
elseif what == "diag" then
valid = node.diag_status ~= nil
elseif what == "opened" then
valid = vim.fn.bufloaded(node.absolute_path) ~= 0
end
if not first and valid then
first = line
end
if node == node_cur then
cur = line
elseif valid and cur then
nex = line
break
end
if opts.skip_gitignored ~= nil then
skip_gitignored = opts.skip_gitignored
end
if nex then
view.set_cursor { nex, 0 }
elseif vim.o.wrapscan and first then
view.set_cursor { first, 0 }
if not recurse then
move(opts.where, opts.what, skip_gitignored)
return
end
if opts.where == "next" then
move_next_recursive(opts.what, skip_gitignored)
elseif opts.where == "prev" then
move_prev_recursive(opts.what, skip_gitignored)
end
end
end

View File

@@ -0,0 +1,14 @@
local M = {}
M.file_popup = require "nvim-tree.actions.node.file-popup"
M.open_file = require "nvim-tree.actions.node.open-file"
M.run_command = require "nvim-tree.actions.node.run-command"
M.system_open = require "nvim-tree.actions.node.system-open"
function M.setup(opts)
require("nvim-tree.actions.node.system-open").setup(opts)
require("nvim-tree.actions.node.file-popup").setup(opts)
require("nvim-tree.actions.node.open-file").setup(opts)
end
return M

View File

@@ -10,13 +10,12 @@ local M = {}
---@param node Explorer|nil
---@param projects table
---@param unloaded_bufnr number|nil
local function refresh_nodes(node, projects, unloaded_bufnr)
local function refresh_nodes(node, projects)
Iterator.builder({ node })
:applier(function(n)
if n.nodes then
local toplevel = git.get_toplevel(n.cwd or n.link_to or n.absolute_path)
explorer_module.reload(n, projects[toplevel] or {}, unloaded_bufnr)
explorer_module.reload(n, projects[toplevel] or {})
end
end)
:recursor(function(n)
@@ -43,18 +42,16 @@ function M.reload_node_status(parent_node, projects)
end
local event_running = false
---@param _ table|nil unused node passed by action
---@param unloaded_bufnr number|nil optional bufnr recently unloaded via BufUnload event
function M.reload_explorer(_, unloaded_bufnr)
function M.reload_explorer()
if event_running or not core.get_explorer() or vim.v.exiting ~= vim.NIL then
return
end
event_running = true
local projects = git.reload()
refresh_nodes(core.get_explorer(), projects, unloaded_bufnr)
refresh_nodes(core.get_explorer(), projects)
if view.is_visible() then
renderer.draw(unloaded_bufnr)
renderer.draw()
end
event_running = false
end

View File

@@ -0,0 +1,10 @@
local M = {}
M.change_dir = require "nvim-tree.actions.root.change-dir"
M.dir_up = require "nvim-tree.actions.root.dir-up"
function M.setup(opts)
M.change_dir.setup(opts)
end
return M

View File

@@ -0,0 +1,15 @@
local M = {}
M.find_file = require "nvim-tree.actions.tree.find-file"
M.modifiers = require "nvim-tree.actions.tree.modifiers"
M.open = require "nvim-tree.actions.tree.open"
M.toggle = require "nvim-tree.actions.tree.toggle"
function M.setup(opts)
M.find_file.setup(opts)
M.modifiers.setup(opts)
M.open.setup(opts)
M.toggle.setup(opts)
end
return M

View File

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

View File

@@ -1,7 +1,7 @@
local lib = require "nvim-tree.lib"
local utils = require "nvim-tree.utils"
local filters = require "nvim-tree.explorer.filters"
local reloaders = require "nvim-tree.actions.reloaders.reloaders"
local reloaders = require "nvim-tree.actions.reloaders"
local M = {}
@@ -31,6 +31,11 @@ function M.no_buffer()
reload()
end
function M.no_bookmark()
filters.config.filter_no_bookmark = not filters.config.filter_no_bookmark
reload()
end
function M.dotfiles()
filters.config.filter_dotfiles = not filters.config.filter_dotfiles
reload()

View File

@@ -1,3 +1,17 @@
local lib = require "nvim-tree.lib"
local view = require "nvim-tree.view"
local utils = require "nvim-tree.utils"
local actions = require "nvim-tree.actions"
local appearance_diagnostics = require "nvim-tree.appearance.diagnostics"
local events = require "nvim-tree.events"
local help = require "nvim-tree.help"
local live_filter = require "nvim-tree.live-filter"
local marks = require "nvim-tree.marks"
local marks_navigation = require "nvim-tree.marks.navigation"
local marks_bulk_delete = require "nvim-tree.marks.bulk-delete"
local marks_bulk_trash = require "nvim-tree.marks.bulk-trash"
local marks_bulk_move = require "nvim-tree.marks.bulk-move"
local keymap = require "nvim-tree.keymap"
local notify = require "nvim-tree.notify"
local Api = {
@@ -26,6 +40,7 @@ local Api = {
mappings = {},
},
commands = {},
diagnostics = {},
}
--- Do nothing when setup not called.
@@ -45,7 +60,7 @@ end
---@param fn function function to invoke
local function wrap_node(fn)
return function(node, ...)
node = node or require("nvim-tree.lib").get_node_at_cursor()
node = node or lib.get_node_at_cursor()
if node then
fn(node, ...)
end
@@ -56,7 +71,7 @@ end
---@param fn function function to invoke
local function wrap_node_or_nil(fn)
return function(node, ...)
node = node or require("nvim-tree.lib").get_node_at_cursor()
node = node or lib.get_node_at_cursor()
fn(node, ...)
end
end
@@ -68,7 +83,8 @@ end
---@field find_file boolean|nil default false
---@field update_root boolean|nil default false
Api.tree.open = wrap(require("nvim-tree.actions.tree.open").fn)
Api.tree.open = wrap(actions.tree.open.fn)
Api.tree.focus = Api.tree.open
---@class ApiTreeToggleOpts
---@field path string|nil
@@ -78,19 +94,11 @@ Api.tree.open = wrap(require("nvim-tree.actions.tree.open").fn)
---@field update_root boolean|nil default false
---@field focus boolean|nil default true
Api.tree.toggle = wrap(require("nvim-tree.actions.tree.toggle").fn)
Api.tree.close = wrap(require("nvim-tree.view").close)
Api.tree.close_in_this_tab = wrap(require("nvim-tree.view").close_this_tab_only)
Api.tree.close_in_all_tabs = wrap(require("nvim-tree.view").close_all_tabs)
Api.tree.focus = wrap(function()
Api.tree.open()
end)
Api.tree.reload = wrap(require("nvim-tree.actions.reloaders.reloaders").reload_explorer)
Api.tree.toggle = wrap(actions.tree.toggle.fn)
Api.tree.close = wrap(view.close)
Api.tree.close_in_this_tab = wrap(view.close_this_tab_only)
Api.tree.close_in_all_tabs = wrap(view.close_all_tabs)
Api.tree.reload = wrap(actions.reloaders.reload_explorer)
Api.tree.change_root = wrap(function(...)
require("nvim-tree").change_dir(...)
@@ -98,17 +106,15 @@ end)
Api.tree.change_root_to_node = wrap_node(function(node)
if node.name == ".." then
require("nvim-tree.actions.root.change-dir").fn ".."
actions.root.change_dir.fn ".."
elseif node.nodes ~= nil then
require("nvim-tree.actions.root.change-dir").fn(require("nvim-tree.lib").get_last_group_node(node).absolute_path)
actions.root.change_dir.fn(lib.get_last_group_node(node).absolute_path)
end
end)
Api.tree.change_root_to_parent = wrap_node(require("nvim-tree.actions.root.dir-up").fn)
Api.tree.get_node_under_cursor = wrap(require("nvim-tree.lib").get_node_at_cursor)
Api.tree.get_nodes = wrap(require("nvim-tree.lib").get_nodes)
Api.tree.change_root_to_parent = wrap_node(actions.root.dir_up.fn)
Api.tree.get_node_under_cursor = wrap(lib.get_node_at_cursor)
Api.tree.get_nodes = wrap(lib.get_nodes)
---@class ApiTreeFindFileOpts
---@field buf string|number|nil
@@ -118,55 +124,47 @@ Api.tree.get_nodes = wrap(require("nvim-tree.lib").get_nodes)
---@field update_root boolean|nil default false
---@field focus boolean|nil default false
Api.tree.find_file = wrap(require("nvim-tree.actions.tree.find-file").fn)
Api.tree.search_node = wrap(require("nvim-tree.actions.finders.search-node").fn)
Api.tree.collapse_all = wrap(require("nvim-tree.actions.tree-modifiers.collapse-all").fn)
Api.tree.expand_all = wrap_node(require("nvim-tree.actions.tree-modifiers.expand-all").fn)
Api.tree.toggle_gitignore_filter = wrap(require("nvim-tree.actions.tree-modifiers.toggles").git_ignored)
Api.tree.toggle_git_clean_filter = wrap(require("nvim-tree.actions.tree-modifiers.toggles").git_clean)
Api.tree.toggle_no_buffer_filter = wrap(require("nvim-tree.actions.tree-modifiers.toggles").no_buffer)
Api.tree.toggle_custom_filter = wrap(require("nvim-tree.actions.tree-modifiers.toggles").custom)
Api.tree.toggle_hidden_filter = wrap(require("nvim-tree.actions.tree-modifiers.toggles").dotfiles)
Api.tree.toggle_help = wrap(require("nvim-tree.help").toggle)
Api.tree.is_tree_buf = wrap(require("nvim-tree.utils").is_nvim_tree_buf)
Api.tree.find_file = wrap(actions.tree.find_file.fn)
Api.tree.search_node = wrap(actions.finders.search_node.fn)
Api.tree.collapse_all = wrap(actions.tree.modifiers.collapse_all.fn)
Api.tree.expand_all = wrap_node(actions.tree.modifiers.expand_all.fn)
Api.tree.toggle_gitignore_filter = wrap(actions.tree.modifiers.toggles.git_ignored)
Api.tree.toggle_git_clean_filter = wrap(actions.tree.modifiers.toggles.git_clean)
Api.tree.toggle_no_buffer_filter = wrap(actions.tree.modifiers.toggles.no_buffer)
Api.tree.toggle_custom_filter = wrap(actions.tree.modifiers.toggles.custom)
Api.tree.toggle_hidden_filter = wrap(actions.tree.modifiers.toggles.dotfiles)
Api.tree.toggle_no_bookmark_filter = wrap(actions.tree.modifiers.toggles.no_bookmark)
Api.tree.toggle_help = wrap(help.toggle)
Api.tree.is_tree_buf = wrap(utils.is_nvim_tree_buf)
---@class ApiTreeIsVisibleOpts
---@field tabpage number|nil
---@field any_tabpage boolean|nil default false
Api.tree.is_visible = wrap(require("nvim-tree.view").is_visible)
Api.tree.is_visible = wrap(view.is_visible)
---@class ApiTreeWinIdOpts
---@field tabpage number|nil default nil
Api.tree.winid = wrap(require("nvim-tree.view").winid)
Api.tree.winid = wrap(view.winid)
Api.fs.create = wrap_node_or_nil(require("nvim-tree.actions.fs.create-file").fn)
Api.fs.remove = wrap_node(require("nvim-tree.actions.fs.remove-file").fn)
Api.fs.trash = wrap_node(require("nvim-tree.actions.fs.trash").fn)
Api.fs.rename_node = wrap_node(require("nvim-tree.actions.fs.rename-file").fn ":t")
Api.fs.rename = wrap_node(require("nvim-tree.actions.fs.rename-file").fn ":t")
Api.fs.rename_sub = wrap_node(require("nvim-tree.actions.fs.rename-file").fn ":p:h")
Api.fs.rename_basename = wrap_node(require("nvim-tree.actions.fs.rename-file").fn ":t:r")
Api.fs.rename_full = wrap_node(require("nvim-tree.actions.fs.rename-file").fn ":p")
Api.fs.cut = wrap_node(require("nvim-tree.actions.fs.copy-paste").cut)
Api.fs.paste = wrap_node(require("nvim-tree.actions.fs.copy-paste").paste)
Api.fs.clear_clipboard = wrap(require("nvim-tree.actions.fs.copy-paste").clear_clipboard)
Api.fs.print_clipboard = wrap(require("nvim-tree.actions.fs.copy-paste").print_clipboard)
Api.fs.copy.node = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy)
Api.fs.copy.absolute_path = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy_absolute_path)
Api.fs.copy.filename = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy_filename)
Api.fs.copy.relative_path = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy_path)
Api.fs.create = wrap_node_or_nil(actions.fs.create_file.fn)
Api.fs.remove = wrap_node(actions.fs.remove_file.fn)
Api.fs.trash = wrap_node(actions.fs.trash.fn)
Api.fs.rename_node = wrap_node(actions.fs.rename_file.fn ":t")
Api.fs.rename = wrap_node(actions.fs.rename_file.fn ":t")
Api.fs.rename_sub = wrap_node(actions.fs.rename_file.fn ":p:h")
Api.fs.rename_basename = wrap_node(actions.fs.rename_file.fn ":t:r")
Api.fs.rename_full = wrap_node(actions.fs.rename_file.fn ":p")
Api.fs.cut = wrap_node(actions.fs.copy_paste.cut)
Api.fs.paste = wrap_node(actions.fs.copy_paste.paste)
Api.fs.clear_clipboard = wrap(actions.fs.copy_paste.clear_clipboard)
Api.fs.print_clipboard = wrap(actions.fs.copy_paste.print_clipboard)
Api.fs.copy.node = wrap_node(actions.fs.copy_paste.copy)
Api.fs.copy.absolute_path = wrap_node(actions.fs.copy_paste.copy_absolute_path)
Api.fs.copy.filename = wrap_node(actions.fs.copy_paste.copy_filename)
Api.fs.copy.basename = wrap_node(actions.fs.copy_paste.copy_basename)
Api.fs.copy.relative_path = wrap_node(actions.fs.copy_paste.copy_path)
---@param mode string
---@param node table
@@ -175,18 +173,18 @@ local function edit(mode, node)
if node.link_to and not node.nodes then
path = node.link_to
end
require("nvim-tree.actions.node.open-file").fn(mode, path)
actions.node.open_file.fn(mode, path)
end
---@param mode string
---@return fun(node: table)
local function open_or_expand_or_dir_up(mode)
local function open_or_expand_or_dir_up(mode, toggle_group)
return function(node)
if node.name == ".." then
require("nvim-tree.actions.root.change-dir").fn ".."
actions.root.change_dir.fn ".."
elseif node.nodes then
require("nvim-tree.lib").expand_or_collapse(node)
else
lib.expand_or_collapse(node, toggle_group)
elseif not toggle_group then
edit(mode, node)
end
end
@@ -200,53 +198,57 @@ Api.node.open.no_window_picker = wrap_node(open_or_expand_or_dir_up "edit_no_pic
Api.node.open.vertical = wrap_node(open_or_expand_or_dir_up "vsplit")
Api.node.open.horizontal = wrap_node(open_or_expand_or_dir_up "split")
Api.node.open.tab = wrap_node(open_or_expand_or_dir_up "tabnew")
Api.node.open.toggle_group_empty = wrap_node(open_or_expand_or_dir_up("toggle_group_empty", true))
Api.node.open.preview = wrap_node(open_or_expand_or_dir_up "preview")
Api.node.open.preview_no_picker = wrap_node(open_or_expand_or_dir_up "preview_no_picker")
Api.node.show_info_popup = wrap_node(require("nvim-tree.actions.node.file-popup").toggle_file_info)
Api.node.run.cmd = wrap_node(require("nvim-tree.actions.node.run-command").run_file_command)
Api.node.run.system = wrap_node(require("nvim-tree.actions.node.system-open").fn)
Api.node.navigate.sibling.next = wrap_node(require("nvim-tree.actions.moves.sibling").fn "next")
Api.node.navigate.sibling.prev = wrap_node(require("nvim-tree.actions.moves.sibling").fn "prev")
Api.node.navigate.sibling.first = wrap_node(require("nvim-tree.actions.moves.sibling").fn "first")
Api.node.navigate.sibling.last = wrap_node(require("nvim-tree.actions.moves.sibling").fn "last")
Api.node.navigate.parent = wrap_node(require("nvim-tree.actions.moves.parent").fn(false))
Api.node.navigate.parent_close = wrap_node(require("nvim-tree.actions.moves.parent").fn(true))
Api.node.navigate.git.next = wrap_node(require("nvim-tree.actions.moves.item").fn("next", "git"))
Api.node.navigate.git.prev = wrap_node(require("nvim-tree.actions.moves.item").fn("prev", "git"))
Api.node.navigate.diagnostics.next = wrap_node(require("nvim-tree.actions.moves.item").fn("next", "diag"))
Api.node.navigate.diagnostics.prev = wrap_node(require("nvim-tree.actions.moves.item").fn("prev", "diag"))
Api.node.navigate.opened.next = wrap_node(require("nvim-tree.actions.moves.item").fn("next", "opened"))
Api.node.navigate.opened.prev = wrap_node(require("nvim-tree.actions.moves.item").fn("prev", "opened"))
Api.node.show_info_popup = wrap_node(actions.node.file_popup.toggle_file_info)
Api.node.run.cmd = wrap_node(actions.node.run_command.run_file_command)
Api.node.run.system = wrap_node(actions.node.system_open.fn)
Api.git.reload = wrap(require("nvim-tree.actions.reloaders.reloaders").reload_git)
Api.node.navigate.sibling.next = wrap_node(actions.moves.sibling.fn "next")
Api.node.navigate.sibling.prev = wrap_node(actions.moves.sibling.fn "prev")
Api.node.navigate.sibling.first = wrap_node(actions.moves.sibling.fn "first")
Api.node.navigate.sibling.last = wrap_node(actions.moves.sibling.fn "last")
Api.node.navigate.parent = wrap_node(actions.moves.parent.fn(false))
Api.node.navigate.parent_close = wrap_node(actions.moves.parent.fn(true))
Api.node.navigate.git.next = wrap_node(actions.moves.item.fn { where = "next", what = "git" })
Api.node.navigate.git.next_skip_gitignored = wrap_node(actions.moves.item.fn { where = "next", what = "git", skip_gitignored = true })
Api.node.navigate.git.next_recursive = wrap_node(actions.moves.item.fn { where = "next", what = "git", recurse = true })
Api.node.navigate.git.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "git" })
Api.node.navigate.git.prev_skip_gitignored = wrap_node(actions.moves.item.fn { where = "prev", what = "git", skip_gitignored = true })
Api.node.navigate.git.prev_recursive = wrap_node(actions.moves.item.fn { where = "prev", what = "git", recurse = true })
Api.node.navigate.diagnostics.next = wrap_node(actions.moves.item.fn { where = "next", what = "diag" })
Api.node.navigate.diagnostics.next_recursive = wrap_node(actions.moves.item.fn { where = "next", what = "diag", recurse = true })
Api.node.navigate.diagnostics.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "diag" })
Api.node.navigate.diagnostics.prev_recursive = wrap_node(actions.moves.item.fn { where = "prev", what = "diag", recurse = true })
Api.node.navigate.opened.next = wrap_node(actions.moves.item.fn { where = "next", what = "opened" })
Api.node.navigate.opened.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "opened" })
Api.events.subscribe = require("nvim-tree.events").subscribe
Api.events.Event = require("nvim-tree.events").Event
Api.git.reload = wrap(actions.reloaders.reload_git)
Api.live_filter.start = wrap(require("nvim-tree.live-filter").start_filtering)
Api.live_filter.clear = wrap(require("nvim-tree.live-filter").clear_filter)
Api.events.subscribe = events.subscribe
Api.events.Event = events.Event
Api.marks.get = wrap_node(require("nvim-tree.marks").get_mark)
Api.marks.list = wrap(require("nvim-tree.marks").get_marks)
Api.marks.toggle = wrap_node(require("nvim-tree.marks").toggle_mark)
Api.marks.clear = wrap(require("nvim-tree.marks").clear_marks)
Api.marks.bulk.delete = wrap(require("nvim-tree.marks.bulk-delete").bulk_delete)
Api.marks.bulk.trash = wrap(require("nvim-tree.marks.bulk-trash").bulk_trash)
Api.marks.bulk.move = wrap(require("nvim-tree.marks.bulk-move").bulk_move)
Api.marks.navigate.next = wrap(require("nvim-tree.marks.navigation").next)
Api.marks.navigate.prev = wrap(require("nvim-tree.marks.navigation").prev)
Api.marks.navigate.select = wrap(require("nvim-tree.marks.navigation").select)
Api.live_filter.start = wrap(live_filter.start_filtering)
Api.live_filter.clear = wrap(live_filter.clear_filter)
Api.config.mappings.default_on_attach = require("nvim-tree.keymap").default_on_attach
Api.marks.get = wrap_node(marks.get_mark)
Api.marks.list = wrap(marks.get_marks)
Api.marks.toggle = wrap_node(marks.toggle_mark)
Api.marks.clear = wrap(marks.clear_marks)
Api.marks.bulk.delete = wrap(marks_bulk_delete.bulk_delete)
Api.marks.bulk.trash = wrap(marks_bulk_trash.bulk_trash)
Api.marks.bulk.move = wrap(marks_bulk_move.bulk_move)
Api.marks.navigate.next = wrap(marks_navigation.next)
Api.marks.navigate.prev = wrap(marks_navigation.prev)
Api.marks.navigate.select = wrap(marks_navigation.select)
Api.config.mappings.get_keymap = wrap(function()
return require("nvim-tree.keymap").get_keymap()
end)
Api.config.mappings.get_keymap = wrap(keymap.get_keymap)
Api.config.mappings.get_keymap_default = wrap(keymap.get_keymap_default)
Api.config.mappings.default_on_attach = keymap.default_on_attach
Api.config.mappings.get_keymap_default = wrap(function()
return require("nvim-tree.keymap").get_keymap_default()
end)
Api.diagnostics.hi_test = wrap(appearance_diagnostics.hi_test)
Api.commands.get = wrap(function()
return require("nvim-tree.commands").get()

View File

@@ -0,0 +1,80 @@
local appearance = require "nvim-tree.appearance"
local M = {}
---@class HighlightDisplay for :NvimTreeHiTest
---@field group string nvim-tree highlight group name
---@field links string link chain to a concretely defined group
---@field def string :hi concrete definition after following any links
local HighlightDisplay = {}
---@param group string nvim-tree highlight group
---@return HighlightDisplay
function HighlightDisplay:new(group)
local o = {}
setmetatable(o, self)
self.__index = self
o.group = group
local concrete = o.group
-- maybe follow links
local links = {}
local link = vim.api.nvim_get_hl(0, { name = o.group }).link
while link do
table.insert(links, link)
concrete = link
link = vim.api.nvim_get_hl(0, { name = link }).link
end
o.links = table.concat(links, " ")
-- concrete definition
local ok, res = pcall(vim.api.nvim_cmd, { cmd = "highlight", args = { concrete } }, { output = true })
if ok and type(res) == "string" then
o.def = res:gsub(".*xxx *", "")
else
o.def = ""
end
return o
end
function HighlightDisplay:render(bufnr, fmt, l)
local text = string.format(fmt, self.group, self.links, self.def)
vim.api.nvim_buf_set_lines(bufnr, l, -1, true, { text })
vim.api.nvim_buf_add_highlight(bufnr, -1, self.group, l, 0, #self.group)
end
---Run a test similar to :so $VIMRUNTIME/syntax/hitest.vim
---Display all nvim-tree highlight groups, their link chain and actual definition
function M.hi_test()
local displays = {}
local max_group_len = 0
local max_links_len = 0
-- build all highlight groups, name only
for _, highlight_group in ipairs(appearance.HIGHLIGHT_GROUPS) do
local display = HighlightDisplay:new(highlight_group.group)
table.insert(displays, display)
max_group_len = math.max(max_group_len, #display.group)
max_links_len = math.max(max_links_len, #display.links)
end
-- create a buffer
local bufnr = vim.api.nvim_create_buf(false, true)
-- render and highlight
local l = 0
local fmt = string.format("%%-%d.%ds %%-%d.%ds %%s", max_group_len, max_group_len, max_links_len, max_links_len)
for _, display in ipairs(displays) do
display:render(bufnr, fmt, l)
l = l + 1
end
-- finalise and focus the buffer
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
vim.cmd.buffer(bufnr)
end
return M

View File

@@ -0,0 +1,202 @@
local M = {}
-- All highlight groups: linked or directly defined.
-- Please add new groups to help and preserve order.
-- Please avoid directly defined groups to preserve accessibility for TUI.
M.HIGHLIGHT_GROUPS = {
-- Standard
{ group = "NvimTreeNormal", link = "Normal" },
{ group = "NvimTreeNormalFloat", link = "NormalFloat" },
{ group = "NvimTreeNormalNC", link = "NvimTreeNormal" },
{ group = "NvimTreeLineNr", link = "LineNr" },
{ group = "NvimTreeWinSeparator", link = "WinSeparator" },
{ group = "NvimTreeEndOfBuffer", link = "EndOfBuffer" },
{ group = "NvimTreePopup", link = "Normal" },
{ group = "NvimTreeSignColumn", link = "NvimTreeNormal" },
{ group = "NvimTreeCursorColumn", link = "CursorColumn" },
{ group = "NvimTreeCursorLine", link = "CursorLine" },
{ group = "NvimTreeCursorLineNr", link = "CursorLineNr" },
{ group = "NvimTreeStatusLine", link = "StatusLine" },
{ group = "NvimTreeStatusLineNC", link = "StatusLineNC" },
-- File Text
{ group = "NvimTreeExecFile", link = "SpellCap" },
{ group = "NvimTreeImageFile", link = "SpellCap" },
{ group = "NvimTreeSpecialFile", link = "SpellCap" },
{ group = "NvimTreeSymlink", link = "SpellCap" },
-- Folder Text
{ group = "NvimTreeRootFolder", link = "Title" },
{ group = "NvimTreeFolderName", link = "Directory" },
{ group = "NvimTreeEmptyFolderName", link = "Directory" },
{ group = "NvimTreeOpenedFolderName", link = "Directory" },
{ group = "NvimTreeSymlinkFolderName", link = "Directory" },
-- File Icons
{ group = "NvimTreeFileIcon", link = "NvimTreeNormal" },
{ group = "NvimTreeSymlinkIcon", link = "NvimTreeNormal" },
-- Folder Icons
{ group = "NvimTreeFolderIcon", def = "guifg=#8094b4 ctermfg=Blue" },
{ group = "NvimTreeOpenedFolderIcon", link = "NvimTreeFolderIcon" },
{ group = "NvimTreeClosedFolderIcon", link = "NvimTreeFolderIcon" },
{ group = "NvimTreeFolderArrowClosed", link = "NvimTreeIndentMarker" },
{ group = "NvimTreeFolderArrowOpen", link = "NvimTreeIndentMarker" },
-- Indent
{ group = "NvimTreeIndentMarker", link = "NvimTreeFolderIcon" },
-- Picker
{ group = "NvimTreeWindowPicker", def = "guifg=#ededed guibg=#4493c8 gui=bold ctermfg=White ctermbg=DarkBlue" },
-- LiveFilter
{ group = "NvimTreeLiveFilterPrefix", link = "PreProc" },
{ group = "NvimTreeLiveFilterValue", link = "ModeMsg" },
-- Clipboard
{ group = "NvimTreeCutHL", link = "SpellBad" },
{ group = "NvimTreeCopiedHL", link = "SpellRare" },
-- Bookmark
{ group = "NvimTreeBookmarkIcon", link = "NvimTreeFolderIcon" },
{ group = "NvimTreeBookmarkHL", link = "SpellLocal" },
-- Modified
{ group = "NvimTreeModifiedIcon", link = "Type" },
{ group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" },
{ group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" },
-- Opened
{ group = "NvimTreeOpenedHL", link = "Special" },
-- Git Icon
{ group = "NvimTreeGitDeletedIcon", link = "Statement" },
{ group = "NvimTreeGitDirtyIcon", link = "Statement" },
{ group = "NvimTreeGitIgnoredIcon", link = "Comment" },
{ group = "NvimTreeGitMergeIcon", link = "Constant" },
{ group = "NvimTreeGitNewIcon", link = "PreProc" },
{ group = "NvimTreeGitRenamedIcon", link = "PreProc" },
{ group = "NvimTreeGitStagedIcon", link = "Constant" },
-- Git File Highlight
{ group = "NvimTreeGitFileDeletedHL", link = "NvimTreeGitDeletedIcon" },
{ group = "NvimTreeGitFileDirtyHL", link = "NvimTreeGitDirtyIcon" },
{ group = "NvimTreeGitFileIgnoredHL", link = "NvimTreeGitIgnoredIcon" },
{ group = "NvimTreeGitFileMergeHL", link = "NvimTreeGitMergeIcon" },
{ group = "NvimTreeGitFileNewHL", link = "NvimTreeGitNewIcon" },
{ group = "NvimTreeGitFileRenamedHL", link = "NvimTreeGitRenamedIcon" },
{ group = "NvimTreeGitFileStagedHL", link = "NvimTreeGitStagedIcon" },
-- Git Folder Highlight
{ group = "NvimTreeGitFolderDeletedHL", link = "NvimTreeGitFileDeletedHL" },
{ group = "NvimTreeGitFolderDirtyHL", link = "NvimTreeGitFileDirtyHL" },
{ group = "NvimTreeGitFolderIgnoredHL", link = "NvimTreeGitFileIgnoredHL" },
{ group = "NvimTreeGitFolderMergeHL", link = "NvimTreeGitFileMergeHL" },
{ group = "NvimTreeGitFolderNewHL", link = "NvimTreeGitFileNewHL" },
{ group = "NvimTreeGitFolderRenamedHL", link = "NvimTreeGitFileRenamedHL" },
{ group = "NvimTreeGitFolderStagedHL", link = "NvimTreeGitFileStagedHL" },
-- Diagnostics Icon
{ group = "NvimTreeDiagnosticErrorIcon", link = "DiagnosticError" },
{ group = "NvimTreeDiagnosticWarnIcon", link = "DiagnosticWarn" },
{ group = "NvimTreeDiagnosticInfoIcon", link = "DiagnosticInfo" },
{ group = "NvimTreeDiagnosticHintIcon", link = "DiagnosticHint" },
-- Diagnostics File Highlight
{ group = "NvimTreeDiagnosticErrorFileHL", link = "DiagnosticUnderlineError" },
{ group = "NvimTreeDiagnosticWarnFileHL", link = "DiagnosticUnderlineWarn" },
{ group = "NvimTreeDiagnosticInfoFileHL", link = "DiagnosticUnderlineInfo" },
{ group = "NvimTreeDiagnosticHintFileHL", link = "DiagnosticUnderlineHint" },
-- Diagnostics Folder Highlight
{ group = "NvimTreeDiagnosticErrorFolderHL", link = "NvimTreeDiagnosticErrorFileHL" },
{ group = "NvimTreeDiagnosticWarnFolderHL", link = "NvimTreeDiagnosticWarnFileHL" },
{ group = "NvimTreeDiagnosticInfoFolderHL", link = "NvimTreeDiagnosticInfoFileHL" },
{ group = "NvimTreeDiagnosticHintFolderHL", link = "NvimTreeDiagnosticHintFileHL" },
}
-- nvim-tree highlight groups to legacy
M.LEGACY_LINKS = {
NvimTreeModifiedIcon = "NvimTreeModifiedFile",
NvimTreeOpenedHL = "NvimTreeOpenedFile",
NvimTreeBookmarkIcon = "NvimTreeBookmark",
NvimTreeGitDeletedIcon = "NvimTreeGitDeleted",
NvimTreeGitDirtyIcon = "NvimTreeGitDirty",
NvimTreeGitIgnoredIcon = "NvimTreeGitIgnored",
NvimTreeGitMergeIcon = "NvimTreeGitMerge",
NvimTreeGitNewIcon = "NvimTreeGitNew",
NvimTreeGitRenamedIcon = "NvimTreeGitRenamed",
NvimTreeGitStagedIcon = "NvimTreeGitStaged",
NvimTreeGitFileDeletedHL = "NvimTreeFileDeleted",
NvimTreeGitFileDirtyHL = "NvimTreeFileDirty",
NvimTreeGitFileIgnoredHL = "NvimTreeFileIgnored",
NvimTreeGitFileMergeHL = "NvimTreeFileMerge",
NvimTreeGitFileNewHL = "NvimTreeFileNew",
NvimTreeGitFileRenamedHL = "NvimTreeFileRenamed",
NvimTreeGitFileStagedHL = "NvimTreeFileStaged",
NvimTreeGitFolderDeletedHL = "NvimTreeFolderDeleted",
NvimTreeGitFolderDirtyHL = "NvimTreeFolderDirty",
NvimTreeGitFolderIgnoredHL = "NvimTreeFolderIgnored",
NvimTreeGitFolderMergeHL = "NvimTreeFolderMerge",
NvimTreeGitFolderNewHL = "NvimTreeFolderNew",
NvimTreeGitFolderRenamedHL = "NvimTreeFolderRenamed",
NvimTreeGitFolderStagedHL = "NvimTreeFolderStaged",
NvimTreeDiagnosticErrorIcon = "NvimTreeLspDiagnosticsError",
NvimTreeDiagnosticWarnIcon = "NvimTreeLspDiagnosticsWarning",
NvimTreeDiagnosticInfoIcon = "NvimTreeLspDiagnosticsInformation",
NvimTreeDiagnosticHintIcon = "NvimTreeLspDiagnosticsHint",
NvimTreeDiagnosticErrorFileHL = "NvimTreeLspDiagnosticsErrorText",
NvimTreeDiagnosticWarnFileHL = "NvimTreeLspDiagnosticsWarningText",
NvimTreeDiagnosticInfoFileHL = "NvimTreeLspDiagnosticsInformationText",
NvimTreeDiagnosticHintFileHL = "NvimTreeLspDiagnosticsHintText",
NvimTreeDiagnosticErrorFolderHL = "NvimTreeLspDiagnosticsErrorFolderText",
NvimTreeDiagnosticWarnFolderHL = "NvimTreeLspDiagnosticsWarningFolderText",
NvimTreeDiagnosticInfoFolderHL = "NvimTreeLspDiagnosticsInformationFolderText",
NvimTreeDiagnosticHintFolderHL = "NvimTreeLspDiagnosticsHintFolderText",
}
function M.setup()
-- non-linked
for _, g in ipairs(M.HIGHLIGHT_GROUPS) do
if g.def then
vim.api.nvim_command("hi def " .. g.group .. " " .. g.def)
end
end
-- hard link override when legacy only is present
for from, to in pairs(M.LEGACY_LINKS) do
local hl_from
local hl_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
vim.api.nvim_command("hi link " .. from .. " " .. to)
end
end
-- default links
for _, g in ipairs(M.HIGHLIGHT_GROUPS) do
if g.link then
vim.api.nvim_command("hi def link " .. g.group .. " " .. g.link)
end
end
end
return M

View File

@@ -1,40 +1,50 @@
local M = {}
---@type table<string, boolean> record of which file is modified
M._record = {}
M._modified = {}
---refresh M.record
function M.reload()
M._record = {}
---refresh M._modified
function M.reload_modified()
M._modified = {}
local bufs = vim.fn.getbufinfo { bufmodified = true, buflisted = true }
for _, buf in pairs(bufs) do
local path = buf.name
if path ~= "" then -- not a [No Name] buffer
-- mark all the parent as modified as well
while
M._record[path] ~= true
M._modified[path] ~= true
-- no need to keep going if already recorded
-- This also prevents an infinite loop
do
M._record[path] = true
M._modified[path] = true
path = vim.fn.fnamemodify(path, ":h")
end
end
end
end
---@param node Node
---@param node table
---@return boolean
function M.is_modified(node)
return M.config.enable
and M._record[node.absolute_path]
and (not node.nodes or M.config.show_on_dirs)
and (not node.open or M.config.show_on_open_dirs)
return node
and M.config.modified.enable
and M._modified[node.absolute_path]
and (not node.nodes or M.config.modified.show_on_dirs)
and (not node.open or M.config.modified.show_on_open_dirs)
end
---A buffer exists for the node's absolute path
---@param node table
---@return boolean
function M.is_opened(node)
return node and vim.fn.bufloaded(node.absolute_path) > 0
end
---@param opts table
function M.setup(opts)
M.config = opts.modified
M.config = {
modified = opts.modified,
}
end
return M

View File

@@ -1,130 +0,0 @@
local M = {}
local function get_color_from_hl(hl_name, fallback)
local id = vim.api.nvim_get_hl_id_by_name(hl_name)
if not id then
return fallback
end
local foreground = vim.fn.synIDattr(vim.fn.synIDtrans(id), "fg")
if not foreground or foreground == "" then
return fallback
end
return foreground
end
local function get_colors()
return {
red = vim.g.terminal_color_1 or get_color_from_hl("Keyword", "Red"),
green = vim.g.terminal_color_2 or get_color_from_hl("Character", "Green"),
yellow = vim.g.terminal_color_3 or get_color_from_hl("PreProc", "Yellow"),
blue = vim.g.terminal_color_4 or get_color_from_hl("Include", "Blue"),
purple = vim.g.terminal_color_5 or get_color_from_hl("Define", "Purple"),
cyan = vim.g.terminal_color_6 or get_color_from_hl("Conditional", "Cyan"),
dark_red = vim.g.terminal_color_9 or get_color_from_hl("Keyword", "DarkRed"),
orange = vim.g.terminal_color_11 or get_color_from_hl("Number", "Orange"),
}
end
local function get_hl_groups()
local colors = get_colors()
return {
IndentMarker = { fg = "#8094b4" },
Symlink = { gui = "bold", fg = colors.cyan },
FolderIcon = { fg = "#8094b4" },
RootFolder = { fg = colors.purple },
ExecFile = { gui = "bold", fg = colors.green },
SpecialFile = { gui = "bold,underline", fg = colors.yellow },
ImageFile = { gui = "bold", fg = colors.purple },
OpenedFile = { gui = "bold", fg = colors.green },
ModifiedFile = { fg = colors.green },
GitDirty = { fg = colors.dark_red },
GitDeleted = { fg = colors.dark_red },
GitStaged = { fg = colors.green },
GitMerge = { fg = colors.orange },
GitRenamed = { fg = colors.purple },
GitNew = { fg = colors.yellow },
WindowPicker = { gui = "bold", fg = "#ededed", bg = "#4493c8" },
LiveFilterPrefix = { gui = "bold", fg = colors.purple },
LiveFilterValue = { gui = "bold", fg = "#fff" },
Bookmark = { fg = colors.green },
}
end
local function get_links()
return {
FolderName = "Directory",
EmptyFolderName = "Directory",
OpenedFolderName = "Directory",
SymlinkFolderName = "Directory",
OpenedFolderIcon = "NvimTreeFolderIcon",
ClosedFolderIcon = "NvimTreeFolderIcon",
OpenedFileIcon = "NvimTreeOpenedFile",
Normal = "Normal",
NormalFloat = "NormalFloat",
NormalNC = "NvimTreeNormal",
EndOfBuffer = "EndOfBuffer",
CursorLineNr = "CursorLineNr",
LineNr = "LineNr",
CursorLine = "CursorLine",
WinSeparator = "WinSeparator",
CursorColumn = "CursorColumn",
FileDirty = "NvimTreeGitDirty",
FileNew = "NvimTreeGitNew",
FileRenamed = "NvimTreeGitRenamed",
FileMerge = "NvimTreeGitMerge",
FileStaged = "NvimTreeGitStaged",
FileDeleted = "NvimTreeGitDeleted",
FileIgnored = "NvimTreeGitIgnored",
FolderDirty = "NvimTreeFileDirty",
FolderNew = "NvimTreeFileNew",
FolderRenamed = "NvimTreeFileRenamed",
FolderMerge = "NvimTreeFileMerge",
FolderStaged = "NvimTreeFileStaged",
FolderDeleted = "NvimTreeFileDeleted",
FolderIgnored = "NvimTreeFileIgnored",
LspDiagnosticsError = "DiagnosticError",
LspDiagnosticsWarning = "DiagnosticWarn",
LspDiagnosticsInformation = "DiagnosticInfo",
LspDiagnosticsHint = "DiagnosticHint",
LspDiagnosticsErrorText = "NvimTreeLspDiagnosticsError",
LspDiagnosticsWarningText = "NvimTreeLspDiagnosticsWarning",
LspDiagnosticsInformationText = "NvimTreeLspDiagnosticsInformation",
LspDiagnosticsHintText = "NvimTreeLspDiagnosticsHintFile",
LspDiagnosticsErrorFolderText = "NvimTreeLspDiagnosticsErrorText",
LspDiagnosticsWarningFolderText = "NvimTreeLspDiagnosticsWarningText",
LspDiagnosticsInformationFolderText = "NvimTreeLspDiagnosticsInformationText",
LspDiagnosticsHintFolderText = "NvimTreeLspDiagnosticsHintFileText",
Popup = "Normal",
GitIgnored = "Comment",
StatusLine = "StatusLine",
StatusLineNC = "StatusLineNC",
SignColumn = "NvimTreeNormal",
CutHL = "SpellBad",
CopiedHL = "SpellRare",
BookmarkHL = "SpellLocal",
}
end
function M.setup()
local highlight_groups = get_hl_groups()
for k, d in pairs(highlight_groups) do
local gui = d.gui and " gui=" .. d.gui or ""
local fg = d.fg and " guifg=" .. d.fg or ""
local bg = d.bg and " guibg=" .. d.bg or ""
vim.api.nvim_command("hi def NvimTree" .. k .. gui .. fg .. bg)
end
local links = get_links()
for k, d in pairs(links) do
vim.api.nvim_command("hi def link NvimTree" .. k .. " " .. d)
end
end
return M

View File

@@ -134,6 +134,13 @@ local CMDS = {
api.tree.collapse_all(true)
end,
},
{
name = "NvimTreeHiTest",
opts = {
desc = "nvim-tree: highlight test",
},
command = api.diagnostics.hi_test,
},
}
function M.get()

View File

@@ -1,18 +1,41 @@
local utils = require "nvim-tree.utils"
local view = require "nvim-tree.view"
local core = require "nvim-tree.core"
local log = require "nvim-tree.log"
local M = {}
local severity_levels = {
---COC severity level strings to LSP severity levels
---@enum COC_SEVERITY_LEVELS
local COC_SEVERITY_LEVELS = {
Error = 1,
Warning = 2,
Information = 3,
Hint = 4,
}
---@return table
---Absolute Node path to LSP severity level
---@alias NodeSeverities table<string, lsp.DiagnosticSeverity>
---@class DiagStatus
---@field value lsp.DiagnosticSeverity|nil
---@field cache_version integer
--- The buffer-severity mappings derived during the last diagnostic list update.
---@type NodeSeverities
local NODE_SEVERITIES = {}
---The cache version number of the buffer-severity mappings.
---@type integer
local NODE_SEVERITIES_VERSION = 0
---@param path string
---@return string
local function uniformize_path(path)
return utils.canonical_path(path:gsub("\\", "/"))
end
---Marshal severities from LSP. Does nothing when LSP disabled.
---@return NodeSeverities
local function from_nvim_lsp()
local buffer_severity = {}
@@ -25,11 +48,10 @@ local function from_nvim_lsp()
for _, diagnostic in ipairs(vim.diagnostic.get(nil, { severity = M.severity })) do
local buf = diagnostic.bufnr
if vim.api.nvim_buf_is_valid(buf) then
local bufname = vim.api.nvim_buf_get_name(buf)
local lowest_severity = buffer_severity[bufname]
if not lowest_severity or diagnostic.severity < lowest_severity then
buffer_severity[bufname] = diagnostic.severity
end
local bufname = uniformize_path(vim.api.nvim_buf_get_name(buf))
local severity = diagnostic.severity
local highest_severity = buffer_severity[bufname] or severity
buffer_severity[bufname] = math.min(highest_severity, severity)
end
end
end
@@ -37,91 +59,148 @@ local function from_nvim_lsp()
return buffer_severity
end
---@param severity integer
---Severity is within diagnostics.severity.min, diagnostics.severity.max
---@param severity lsp.DiagnosticSeverity
---@param config table
---@return boolean
local function is_severity_in_range(severity, config)
return config.max <= severity and severity <= config.min
end
---@return table
---Handle any COC exceptions, preventing any propagation
---@param err string
local function handle_coc_exception(err)
log.line("diagnostics", "handle_coc_exception: %s", vim.inspect(err))
local notify = true
-- avoid distractions on interrupts (CTRL-C)
if err:find "Vim:Interrupt" or err:find "Keyboard interrupt" then
notify = false
end
if notify then
require("nvim-tree.notify").error("Diagnostics update from coc.nvim failed. " .. vim.inspect(err))
end
end
---COC service initialized
---@return boolean
local function is_using_coc()
return vim.g.coc_service_initialized == 1
end
---Marshal severities from COC. Does nothing when COC service not started.
---@return NodeSeverities
local function from_coc()
if vim.g.coc_service_initialized ~= 1 then
if not is_using_coc() then
return {}
end
local diagnostic_list = vim.fn.CocAction "diagnosticList"
if type(diagnostic_list) ~= "table" or vim.tbl_isempty(diagnostic_list) then
local ok, diagnostic_list = xpcall(function()
return vim.fn.CocAction "diagnosticList"
end, handle_coc_exception)
if not ok or type(diagnostic_list) ~= "table" or vim.tbl_isempty(diagnostic_list) then
return {}
end
local diagnostics = {}
for _, diagnostic in ipairs(diagnostic_list) do
local bufname = diagnostic.file
local coc_severity = severity_levels[diagnostic.severity]
local serverity = diagnostics[bufname] or vim.diagnostic.severity.HINT
diagnostics[bufname] = math.min(coc_severity, serverity)
end
local buffer_severity = {}
for bufname, severity in pairs(diagnostics) do
if is_severity_in_range(severity, M.severity) then
buffer_severity[bufname] = severity
for _, diagnostic in ipairs(diagnostic_list) do
local bufname = uniformize_path(diagnostic.file)
local coc_severity = COC_SEVERITY_LEVELS[diagnostic.severity]
local highest_severity = buffer_severity[bufname] or coc_severity
if is_severity_in_range(highest_severity, M.severity) then
buffer_severity[bufname] = math.min(highest_severity, coc_severity)
end
end
return buffer_severity
end
local function is_using_coc()
return vim.g.coc_service_initialized == 1
---Maybe retrieve severity level from the cache
---@param node Node
---@return DiagStatus
local function from_cache(node)
local nodepath = uniformize_path(node.absolute_path)
local max_severity = nil
if not node.nodes then
-- direct cache hit for files
max_severity = NODE_SEVERITIES[nodepath]
else
-- dirs should be searched in the list of cached buffer names by prefix
for bufname, severity in pairs(NODE_SEVERITIES) do
local node_contains_buf = vim.startswith(bufname, nodepath .. "/")
if node_contains_buf then
if severity == M.severity.max then
max_severity = severity
break
else
max_severity = math.min(max_severity or severity, severity)
end
end
end
end
return { value = max_severity, cache_version = NODE_SEVERITIES_VERSION }
end
---Fired on DiagnosticChanged and CocDiagnosticChanged events:
---debounced retrieval, cache update, version increment and draw
function M.update()
if not M.enable or not core.get_explorer() or not view.is_buf_valid(view.get_bufnr()) then
if not M.enable then
return
end
utils.debounce("diagnostics", M.debounce_delay, function()
local profile = log.profile_start "diagnostics update"
log.line("diagnostics", "update")
local buffer_severity
if is_using_coc() then
buffer_severity = from_coc()
NODE_SEVERITIES = from_coc()
else
buffer_severity = from_nvim_lsp()
NODE_SEVERITIES = from_nvim_lsp()
end
local nodes_by_line = utils.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())
for _, node in pairs(nodes_by_line) do
node.diag_status = nil
end
for bufname, severity in pairs(buffer_severity) do
local bufpath = utils.canonical_path(bufname)
log.line("diagnostics", " bufpath '%s' severity %d", bufpath, severity)
if 0 < severity and severity < 5 then
for line, node in pairs(nodes_by_line) do
local nodepath = utils.canonical_path(node.absolute_path)
log.line("diagnostics", " %d checking nodepath '%s'", line, nodepath)
local node_contains_buf = vim.startswith(bufpath:gsub("\\", "/"), nodepath:gsub("\\", "/") .. "/")
if M.show_on_dirs and node_contains_buf and (not node.open or M.show_on_open_dirs) then
log.line("diagnostics", " matched fold node '%s'", node.absolute_path)
node.diag_status = severity
elseif nodepath == bufpath then
log.line("diagnostics", " matched file node '%s'", node.absolute_path)
node.diag_status = severity
end
end
NODE_SEVERITIES_VERSION = NODE_SEVERITIES_VERSION + 1
if log.enabled "diagnostics" then
for bufname, severity in pairs(NODE_SEVERITIES) do
log.line("diagnostics", "Indexing bufname '%s' with severity %d", bufname, severity)
end
end
log.profile_end(profile)
require("nvim-tree.renderer").draw()
if view.is_buf_valid(view.get_bufnr()) then
require("nvim-tree.renderer").draw()
end
end)
end
---Maybe retrieve diagnostic status for a node.
---Returns cached value when node's version matches.
---@param node Node
---@return DiagStatus|nil
function M.get_diag_status(node)
if not M.enable then
return nil
end
-- dir but we shouldn't show on dirs at all
if node.nodes ~= nil and not M.show_on_dirs then
return nil
end
-- here, we do a lazy update of the diagnostic status carried by the node.
-- This is by design, as diagnostics and nodes live in completely separate
-- worlds, and this module is the link between the two
if not node.diag_status or node.diag_status.cache_version < NODE_SEVERITIES_VERSION then
node.diag_status = from_cache(node)
end
-- file
if not node.nodes then
return node.diag_status
end
-- dir is closed or we should show on open_dirs
if not node.open or M.show_on_open_dirs then
return node.diag_status
end
return nil
end
function M.setup(opts)
M.enable = opts.diagnostics.enable
M.debounce_delay = opts.diagnostics.debounce_delay

View File

@@ -12,9 +12,10 @@ M.HL_POSITION = {
---Setup options for "*_placement"
---@enum ICON_PLACEMENT
M.ICON_PLACEMENT = {
signcolumn = 0,
before = 1,
after = 2,
none = 0,
signcolumn = 1,
before = 2,
after = 3,
}
return M

View File

@@ -1,8 +1,10 @@
local utils = require "nvim-tree.utils"
local marks = require "nvim-tree.marks"
local M = {
ignore_list = {},
exclude_list = {},
custom_function = nil,
}
---@param path string
@@ -46,16 +48,15 @@ end
---Check if the given path has no listed buffer
---@param path string Absolute path
---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 }
---@param unloaded_bufnr number optional bufnr recently unloaded via BufUnload event
---@return boolean
local function buf(path, bufinfo, unloaded_bufnr)
local function buf(path, bufinfo)
if not M.config.filter_no_buffer or type(bufinfo) ~= "table" then
return false
end
-- filter files with no open buffer and directories containing no open buffers
for _, b in ipairs(bufinfo) do
if b.name == path or b.name:find(path .. "/", 1, true) and b.bufnr ~= unloaded_bufnr then
if b.name == path or b.name:find(path .. "/", 1, true) then
return false
end
end
@@ -69,6 +70,25 @@ local function dotfile(path)
return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "."
end
---@param path string
---@param bookmarks table<string, boolean> absolute paths bookmarked
local function bookmark(path, bookmarks)
if not M.config.filter_no_bookmark then
return false
end
-- add trailing slash to make it match only mark's parent directory
-- not it's siblings
local parent = utils.path_add_trailing(path)
for mark, _ in pairs(bookmarks) do
if path == mark or vim.fn.stridx(mark, parent) == 0 then
return false
end
end
return true
end
---@param path string
---@return boolean
local function custom(path)
@@ -78,6 +98,11 @@ local function custom(path)
local basename = utils.path_basename(path)
-- filter user's custom function
if M.custom_function and M.custom_function(path) then
return true
end
-- filter custom regexes
local relpath = utils.path_relative(path, vim.loop.cwd())
for pat, _ in pairs(M.ignore_list) do
@@ -98,22 +123,25 @@ end
---Prepare arguments for should_filter. This is done prior to should_filter for efficiency reasons.
---@param git_status table|nil optional results of git.load_project_status(...)
---@param unloaded_bufnr number|nil optional bufnr recently unloaded via BufUnload event
---@return table
--- git_status: reference
--- unloaded_bufnr: copy
--- bufinfo: empty unless no_buffer set: vim.fn.getbufinfo { buflisted = 1 }
function M.prepare(git_status, unloaded_bufnr)
--- bookmarks: absolute paths to boolean
function M.prepare(git_status)
local status = {
git_status = git_status or {},
unloaded_bufnr = unloaded_bufnr,
bufinfo = {},
bookmarks = {},
}
if M.config.filter_no_buffer then
status.bufinfo = vim.fn.getbufinfo { buflisted = 1 }
end
for _, node in pairs(marks.get_marks()) do
status.bookmarks[node.absolute_path] = true
end
return status
end
@@ -127,7 +155,7 @@ function M.should_filter(path, status)
return false
end
return git(path, status.git_status) or buf(path, status.bufinfo, status.unloaded_bufnr) or dotfile(path) or custom(path)
return git(path, status.git_status) or buf(path, status.bufinfo) or dotfile(path) or custom(path) or bookmark(path, status.bookmarks)
end
function M.setup(opts)
@@ -137,15 +165,20 @@ function M.setup(opts)
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 custom_filter and #custom_filter > 0 then
for _, filter_name in pairs(custom_filter) do
M.ignore_list[filter_name] = true
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

View File

@@ -69,8 +69,7 @@ end
---@param node Node
---@param git_status table
---@param unloaded_bufnr number|nil
function M.reload(node, git_status, unloaded_bufnr)
function M.reload(node, git_status)
local cwd = node.link_to or node.absolute_path
local handle = vim.loop.fs_scandir(cwd)
if not handle then
@@ -79,7 +78,7 @@ function M.reload(node, git_status, unloaded_bufnr)
local profile = log.profile_start("reload %s", node.absolute_path)
local filter_status = filters.prepare(git_status, unloaded_bufnr)
local filter_status = filters.prepare(git_status)
if node.group_next then
node.nodes = { node.group_next }

View File

@@ -136,6 +136,10 @@ end
---@param path string absolute
---@return string|nil
function M.get_toplevel(path)
if not path then
return nil
end
if not M.config.git.enable then
return nil
end

View File

@@ -2,11 +2,6 @@ local log = require "nvim-tree.log"
local utils = require "nvim-tree.utils"
local notify = require "nvim-tree.notify"
-- TODO add "${3rd}/luv/library" to "workspace.library"
---@class uv.uv_handle_t: table
---@class uv.uv_stream_t: uv.uv_handle_t
---@class uv.uv_pipe_t: uv.uv_stream_t
---@class Runner
local Runner = {}
Runner.__index = Runner

View File

@@ -119,14 +119,20 @@ local function compute()
-- increase desc if lines are shorter than the header
max_desc = math.max(max_desc, #head_lhs + #head_rhs1 - max_lhs)
-- header, not padded
local hl = { { "NvimTreeRootFolder", 0, 0, #head_lhs } }
-- header text, not padded
local lines = {
head_lhs .. string.rep(" ", max_desc + max_lhs - #head_lhs - #head_rhs1 + 2) .. head_rhs1,
string.rep(" ", max_desc + max_lhs - #head_rhs2 + 2) .. head_rhs2,
}
local width = #lines[1]
-- header highlight, assume one character keys
local hl = {
{ "NvimTreeFolderName", 0, 0, #head_lhs },
{ "NvimTreeFolderName", 0, width - 1, width },
{ "NvimTreeFolderName", 1, width - 1, width },
}
-- mappings, left padded 1
local fmt = string.format(" %%-%ds %%-%ds", max_lhs, max_desc)
for i, l in ipairs(mappings) do

View File

@@ -64,14 +64,17 @@ function M.default_on_attach(bufnr)
vim.keymap.set('n', 'e', api.fs.rename_basename, opts('Rename: Basename'))
vim.keymap.set('n', ']e', api.node.navigate.diagnostics.next, opts('Next Diagnostic'))
vim.keymap.set('n', '[e', api.node.navigate.diagnostics.prev, opts('Prev Diagnostic'))
vim.keymap.set('n', 'F', api.live_filter.clear, opts('Clean Filter'))
vim.keymap.set('n', 'f', api.live_filter.start, opts('Filter'))
vim.keymap.set('n', 'F', api.live_filter.clear, opts('Live Filter: Clear'))
vim.keymap.set('n', 'f', api.live_filter.start, opts('Live Filter: Start'))
vim.keymap.set('n', 'g?', api.tree.toggle_help, opts('Help'))
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts('Copy Absolute Path'))
vim.keymap.set('n', 'ge', api.fs.copy.basename, opts('Copy Basename'))
vim.keymap.set('n', 'H', api.tree.toggle_hidden_filter, opts('Toggle Filter: Dotfiles'))
vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore'))
vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling'))
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling'))
vim.keymap.set('n', 'L', api.node.open.toggle_group_empty, opts('Toggle Group Empty'))
vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark'))
vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark'))
vim.keymap.set('n', 'o', api.node.open.edit, opts('Open'))
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts('Open: No Window Picker'))

View File

@@ -3,6 +3,7 @@ local notify = require "nvim-tree.notify"
local M = {}
-- silently move, please add to help nvim-tree-legacy-opts
local function refactored(opts)
-- 2022/06/20
utils.move_missing_val(opts, "update_focused_file", "update_cwd", opts, "update_focused_file", "update_root", true)
@@ -41,6 +42,16 @@ local function refactored(opts)
-- 2023/08/26
utils.move_missing_val(opts, "renderer.icons", "webdev_colors", opts, "renderer.icons.web_devicons.file", "color", true)
-- 2023/10/08
if type(opts.renderer) == "table" and type(opts.renderer.highlight_diagnostics) == "boolean" then
opts.renderer.highlight_diagnostics = opts.renderer.highlight_diagnostics and "name" or "none"
end
-- 2023/10/21
if type(opts.renderer) == "table" and type(opts.renderer.highlight_git) == "boolean" then
opts.renderer.highlight_git = opts.renderer.highlight_git and "name" or "none"
end
end
local function deprecated(opts)
@@ -51,12 +62,12 @@ end
local function removed(opts)
if opts.auto_close then
notify.warn "auto close feature has been removed, see note in the README (tips & reminder section)"
notify.warn "auto close feature has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Auto-Close"
opts.auto_close = nil
end
if opts.focus_empty_on_setup then
notify.warn "focus_empty_on_setup has been removed and will be replaced by a new startup configuration. Please remove this option. See https://bit.ly/3yJch2T"
notify.warn "focus_empty_on_setup has been removed: https://github.com/nvim-tree/nvim-tree.lua/wiki/Open-At-Startup"
opts.focus_empty_on_setup = nil
end

View File

@@ -3,6 +3,7 @@ local view = require "nvim-tree.view"
local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils"
local events = require "nvim-tree.events"
local explorer_node = require "nvim-tree.explorer.node"
---@class LibOpenOpts
---@field path string|nil path
@@ -24,7 +25,7 @@ function M.get_node_at_cursor()
return
end
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr())
local cursor = vim.api.nvim_win_get_cursor(winnr)
local line = cursor[1]
if line == 1 and view.is_root_folder_visible(core.get_cwd()) then
@@ -86,6 +87,34 @@ function M.get_last_group_node(node)
return node
end
---Group empty folders
-- Recursively group nodes
---@param node Node
---@return Node[]
function M.group_empty_folders(node)
local is_root = not node.parent
local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1]
if M.group_empty and not is_root and child_folder_only then
node.group_next = child_folder_only
local ns = M.group_empty_folders(child_folder_only)
node.nodes = ns or {}
return ns
end
return node.nodes
end
---Ungroup empty folders
-- If a node is grouped, ungroup it: put node.group_next to the node.nodes and set node.group_next to nil
---@param node Node
function M.ungroup_empty_folders(node)
local cur = node
while cur and cur.group_next do
cur.nodes = { cur.group_next }
cur.group_next = nil
cur = cur.nodes[1]
end
end
---@param node Node
---@return Node[]
function M.get_all_nodes_in_group(node)
@@ -98,8 +127,21 @@ function M.get_all_nodes_in_group(node)
return nodes
end
-- Toggle group empty folders
---@param head_node Node
local function toggle_group_folders(head_node)
local is_grouped = head_node.group_next ~= nil
if is_grouped then
M.ungroup_empty_folders(head_node)
else
M.group_empty_folders(head_node)
end
end
---@param node Node
function M.expand_or_collapse(node)
function M.expand_or_collapse(node, toggle_group)
toggle_group = toggle_group or false
if node.has_children then
node.has_children = false
end
@@ -108,9 +150,20 @@ function M.expand_or_collapse(node)
core.get_explorer():expand(node)
end
local open = not M.get_last_group_node(node).open
for _, n in ipairs(M.get_all_nodes_in_group(node)) do
n.open = open
local head_node = utils.get_parent_of_group(node)
if toggle_group then
toggle_group_folders(head_node)
end
local open = M.get_last_group_node(node).open
local next_open
if toggle_group then
next_open = open
else
next_open = not open
end
for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do
n.open = next_open
end
renderer.draw()
@@ -157,8 +210,9 @@ end
---@param prompt_select string
---@param items_short string[]
---@param items_long string[]
---@param kind string|nil
---@param callback fun(item_short: string)
function M.prompt(prompt_input, prompt_select, items_short, items_long, callback)
function M.prompt(prompt_input, prompt_select, items_short, items_long, kind, callback)
local function format_item(short)
for i, s in ipairs(items_short) do
if short == s then
@@ -169,7 +223,7 @@ function M.prompt(prompt_input, prompt_select, items_short, items_long, callback
end
if M.select_prompts then
vim.ui.select(items_short, { prompt = prompt_select, format_item = format_item }, function(item_short)
vim.ui.select(items_short, { prompt = prompt_select, kind = kind, format_item = format_item }, function(item_short)
callback(item_short)
end)
else
@@ -212,6 +266,7 @@ function M.setup(opts)
M.hijack_directories = opts.hijack_directories
M.respect_buf_cwd = opts.respect_buf_cwd
M.select_prompts = opts.select_prompts
M.group_empty = opts.renderer.group_empty
end
return M

View File

@@ -18,7 +18,7 @@ local function do_delete(nodes)
marks.clear_marks()
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
require("nvim-tree.actions.reloaders").reload_explorer()
end
end
@@ -33,7 +33,7 @@ function M.bulk_delete()
if M.config.ui.confirm.remove then
local prompt_select = "Remove bookmarked ?"
local prompt_input = prompt_select .. " y/N: "
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, function(item_short)
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short)
utils.clear_prompt()
if item_short == "y" then
do_delete(nodes)

View File

@@ -3,6 +3,7 @@ local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils"
local rename_file = require "nvim-tree.actions.fs.rename-file"
local notify = require "nvim-tree.notify"
local lib = require "nvim-tree.lib"
local M = {
config = {},
@@ -14,9 +15,18 @@ function M.bulk_move()
return
end
local node_at_cursor = lib.get_node_at_cursor()
local default_path = core.get_cwd()
if node_at_cursor and node_at_cursor.type == "directory" then
default_path = node_at_cursor.absolute_path
elseif node_at_cursor and node_at_cursor.parent then
default_path = node_at_cursor.parent.absolute_path
end
local input_opts = {
prompt = "Move to: ",
default = core.get_cwd(),
default = default_path,
completion = "dir",
}
@@ -40,7 +50,7 @@ function M.bulk_move()
marks.clear_marks()
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders.reloaders").reload_explorer()
require("nvim-tree.actions.reloaders").reload_explorer()
end
end)
end

View File

@@ -28,7 +28,7 @@ function M.bulk_trash()
if M.config.ui.confirm.trash then
local prompt_select = "Trash bookmarked ?"
local prompt_input = prompt_select .. " y/N: "
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, function(item_short)
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_trash", function(item_short)
utils.clear_prompt()
if item_short == "y" then
do_trash(nodes)

View File

@@ -45,7 +45,7 @@ end
---@param node Node|MinimalNode
---@return table|nil
function M.get_mark(node)
return NvimTreeMarks[node.absolute_path]
return node and NvimTreeMarks[node.absolute_path]
end
---@return table

View File

@@ -1,9 +1,5 @@
---@meta
-- TODO add "${3rd}/luv/library" to "workspace.library"
---@class uv.uv_req_t: table
---@class uv.uv_fs_t: uv.uv_req_t
---@class ParentNode
---@field name string
@@ -17,6 +13,7 @@
---@field parent DirNode
---@field type string
---@field watcher function|nil
---@field diag_status DiagStatus|nil
---@class DirNode: BaseNode
---@field has_children boolean

View File

@@ -1,136 +1,92 @@
local utils = require "nvim-tree.utils"
local core = require "nvim-tree.core"
local live_filter = require "nvim-tree.live-filter"
local notify = require "nvim-tree.notify"
local utils = require "nvim-tree.utils"
local view = require "nvim-tree.view"
local DecoratorBookmarks = require "nvim-tree.renderer.decorator.bookmarks"
local DecoratorCopied = require "nvim-tree.renderer.decorator.copied"
local DecoratorCut = require "nvim-tree.renderer.decorator.cut"
local DecoratorDiagnostics = require "nvim-tree.renderer.decorator.diagnostics"
local DecoratorGit = require "nvim-tree.renderer.decorator.git"
local DecoratorModified = require "nvim-tree.renderer.decorator.modified"
local DecoratorOpened = require "nvim-tree.renderer.decorator.opened"
local git = require "nvim-tree.renderer.components.git"
local pad = require "nvim-tree.renderer.components.padding"
local icons = require "nvim-tree.renderer.components.icons"
local modified = require "nvim-tree.renderer.components.modified"
local diagnostics = require "nvim-tree.renderer.components.diagnostics"
local bookmarks = require "nvim-tree.renderer.components.bookmarks"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local M = {
opts = {},
decorators = {},
picture_map = {
jpg = true,
jpeg = true,
png = true,
gif = true,
webp = true,
jxl = true,
},
}
---@class HighlightedString
---@field str string
---@field hl string[]
---@class AddHighlightArgs
---@field group string[]
---@field line number
---@field col_start number
---@field col_end number
---@class Builder
---@field lines string[] includes icons etc.
---@field hl_args AddHighlightArgs[] line highlights
---@field signs string[] line signs
---@field private root_cwd string absolute path
---@field private index number
---@field private depth number
---@field private combined_groups table<string, boolean> combined group names
---@field private markers boolean[] indent markers
local Builder = {}
Builder.__index = Builder
local DEFAULT_ROOT_FOLDER_LABEL = ":~:s?$?/..?"
function Builder.new(root_cwd)
return setmetatable({
---@return Builder
function Builder:new()
local o = {
root_cwd = core.get_cwd(),
index = 0,
depth = 0,
highlights = {},
hl_args = {},
combined_groups = {},
lines = {},
markers = {},
signs = {},
root_cwd = root_cwd,
}, Builder)
}
setmetatable(o, self)
self.__index = self
return o
end
function Builder:configure_root_label(root_folder_label)
self.root_folder_label = root_folder_label or DEFAULT_ROOT_FOLDER_LABEL
return self
---Insert ranged highlight groups into self.highlights
---@private
---@param groups string[]
---@param start number
---@param end_ number|nil
function Builder:insert_highlight(groups, start, end_)
table.insert(self.hl_args, { groups, self.index, start, end_ or -1 })
end
function Builder:configure_trailing_slash(with_trailing)
self.trailing_slash = with_trailing and "/" or ""
return self
end
function Builder:configure_special_files(special_files)
self.special_files = special_files
return self
end
function Builder:configure_picture_map(picture_map)
self.picture_map = picture_map
return self
end
function Builder:configure_filter(filter, prefix)
self.filter_prefix = prefix
self.filter = filter
return self
end
function Builder:configure_opened_file_highlighting(highlight_opened_files)
self.highlight_opened_files = highlight_opened_files
return self
end
function Builder:configure_modified_highlighting(highlight_modified)
self.highlight_modified = highlight_modified
return self
end
function Builder:configure_icon_padding(padding)
self.icon_padding = padding or " "
return self
end
function Builder:configure_git_icons_placement(where)
if where ~= "after" and where ~= "before" and where ~= "signcolumn" then
where = "before" -- default before
end
self.git_placement = where
return self
end
function Builder:configure_diagnostics_icon_placement(where)
if where ~= "after" and where ~= "before" and where ~= "signcolumn" then
where = "before" -- default before
end
self.diagnostics_placement = where
return self
end
function Builder:configure_bookmark_icon_placement(where)
if where ~= "after" and where ~= "before" and where ~= "signcolumn" then
where = "before" -- default before
end
self.bookmarks_placement = where
return self
end
function Builder:configure_modified_placement(where)
if where ~= "after" and where ~= "before" and where ~= "signcolumn" then
where = "after" -- default after
end
self.modified_placement = where
return self
end
function Builder:configure_symlink_destination(show)
self.symlink_destination = show
return self
end
function Builder:configure_group_name_modifier(group_name_modifier)
if type(group_name_modifier) == "function" then
self.group_name_modifier = group_name_modifier
end
return self
end
function Builder:_insert_highlight(group, start, end_)
table.insert(self.highlights, { group, self.index, start, end_ or -1 })
end
function Builder:_insert_line(line)
table.insert(self.lines, line)
end
function Builder:_get_folder_name(node)
---@private
function Builder:get_folder_name(node)
local name = node.name
local next = node.group_next
while next do
name = name .. "/" .. next.name
name = string.format("%s/%s", name, next.name)
next = next.group_next
end
if node.group_next and self.group_name_modifier then
local new_name = self.group_name_modifier(name)
if node.group_next and type(M.opts.renderer.group_empty) == "function" then
local new_name = M.opts.renderer.group_empty(name)
if type(new_name) == "string" then
name = new_name
else
@@ -138,16 +94,13 @@ function Builder:_get_folder_name(node)
end
end
return name .. self.trailing_slash
return string.format("%s%s", name, M.opts.renderer.add_trailing and "/" or "")
end
---@class HighlightedString
---@field str string
---@field hl string[]
---@private
---@param highlighted_strings HighlightedString[]
---@return string
function Builder:_unwrap_highlighted_strings(highlighted_strings)
function Builder:unwrap_highlighted_strings(highlighted_strings)
if not highlighted_strings then
return ""
end
@@ -156,21 +109,22 @@ function Builder:_unwrap_highlighted_strings(highlighted_strings)
for _, v in ipairs(highlighted_strings) do
if #v.str > 0 then
if v.hl and type(v.hl) == "table" then
self:_insert_highlight(v.hl, #string, #string + #v.str)
self:insert_highlight(v.hl, #string, #string + #v.str)
end
string = string .. v.str
string = string.format("%s%s", string, v.str)
end
end
return string
end
---@private
---@param node table
---@return HighlightedString icon
---@return HighlightedString name
function Builder:_build_folder(node)
function Builder:build_folder(node)
local has_children = #node.nodes ~= 0 or node.has_children
local icon, icon_hl = icons.get_folder_icon(node, has_children)
local foldername = self:_get_folder_name(node)
local foldername = self:get_folder_name(node)
if #icon > 0 and icon_hl == nil then
if node.open then
@@ -181,12 +135,14 @@ function Builder:_build_folder(node)
end
local foldername_hl = "NvimTreeFolderName"
if node.link_to and self.symlink_destination then
if node.link_to and M.opts.renderer.symlink_destination then
local arrow = icons.i.symlink_arrow
local link_to = utils.path_relative(node.link_to, core.get_cwd())
foldername = foldername .. arrow .. link_to
local link_to = utils.path_relative(node.link_to, self.root_cwd)
foldername = string.format("%s%s%s", foldername, arrow, link_to)
foldername_hl = "NvimTreeSymlinkFolderName"
elseif vim.tbl_contains(self.special_files, node.absolute_path) or vim.tbl_contains(self.special_files, node.name) then
elseif
vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name)
then
foldername_hl = "NvimTreeSpecialFolderName"
elseif node.open then
foldername_hl = "NvimTreeOpenedFolderName"
@@ -197,174 +153,56 @@ function Builder:_build_folder(node)
return { str = icon, hl = { icon_hl } }, { str = foldername, hl = { foldername_hl } }
end
---@private
---@param node table
---@return HighlightedString icon
---@return HighlightedString name
function Builder:_build_symlink(node)
function Builder:build_symlink(node)
local icon = icons.i.symlink
local arrow = icons.i.symlink_arrow
local symlink_formatted = node.name
if self.symlink_destination then
local link_to = utils.path_relative(node.link_to, core.get_cwd())
symlink_formatted = symlink_formatted .. arrow .. link_to
if M.opts.renderer.symlink_destination then
local link_to = utils.path_relative(node.link_to, self.root_cwd)
symlink_formatted = string.format("%s%s%s", symlink_formatted, arrow, link_to)
end
return { str = icon, hl = { "NvimTreeSymlinkIcon" } }, { str = symlink_formatted, hl = { "NvimTreeSymlink" } }
end
---@param node table
---@return HighlightedString icon
function Builder:_build_file_icon(node)
local icon, hl_group = icons.get_file_icon(node.name, node.extension)
return { str = icon, hl = { hl_group } }
end
---@private
---@param node table
---@return HighlightedString icon
---@return HighlightedString name
function Builder:_build_file(node)
local icon = self:_build_file_icon(node)
function Builder:build_file(node)
local hl
if vim.tbl_contains(self.special_files, node.absolute_path) or vim.tbl_contains(self.special_files, node.name) then
if vim.tbl_contains(M.opts.renderer.special_files, node.absolute_path) or vim.tbl_contains(M.opts.renderer.special_files, node.name) then
hl = "NvimTreeSpecialFile"
elseif node.executable then
hl = "NvimTreeExecFile"
elseif self.picture_map[node.extension] then
elseif M.picture_map[node.extension] then
hl = "NvimTreeImageFile"
end
return icon, { str = node.name, hl = { hl } }
end
---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_git_icons(node)
local git_icons = git.get_icons(node)
if git_icons and #git_icons > 0 and self.git_placement == "signcolumn" then
table.insert(self.signs, {
sign = git_icons[1].hl[1],
lnum = self.index + 1,
priority = 1,
})
git_icons = nil
end
return git_icons
end
---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_diagnostics_icon(node)
local diagnostics_icon = diagnostics.get_icon(node)
if diagnostics_icon and self.diagnostics_placement == "signcolumn" then
table.insert(self.signs, {
sign = diagnostics_icon.hl[1],
lnum = self.index + 1,
priority = 2,
})
diagnostics_icon = nil
end
return diagnostics_icon
end
---@param node table
---@return HighlightedString|nil icon
function Builder:_get_modified_icon(node)
local modified_icon = modified.get_icon(node)
if modified_icon and self.modified_placement == "signcolumn" then
table.insert(self.signs, {
sign = modified_icon.hl[1],
lnum = self.index + 1,
priority = 3,
})
modified_icon = nil
end
return modified_icon
end
---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_bookmark_icon(node)
local bookmark_icon = bookmarks.get_icon(node)
if bookmark_icon and self.bookmarks_placement == "signcolumn" then
table.insert(self.signs, {
sign = bookmark_icon.hl[1],
lnum = self.index + 1,
priority = 4,
})
bookmark_icon = nil
end
return bookmark_icon
end
---@param node table
---@return string|nil icon_hl
---@return string|nil name_hl
function Builder:_get_highlight_override(node, unloaded_bufnr)
local name_hl, icon_hl
-- git
local git_highlight = git.get_highlight(node)
if git_highlight then
name_hl = git_highlight
end
-- opened file
if self.highlight_opened_files and vim.fn.bufloaded(node.absolute_path) > 0 and vim.fn.bufnr(node.absolute_path) ~= unloaded_bufnr then
if self.highlight_opened_files == "all" or self.highlight_opened_files == "name" then
name_hl = "NvimTreeOpenedFile"
end
if self.highlight_opened_files == "all" or self.highlight_opened_files == "icon" then
icon_hl = "NvimTreeOpenedFileIcon"
end
end
-- modified file
local modified_highlight = modified.get_highlight(node)
if modified_highlight then
if self.highlight_modified == "all" or self.highlight_modified == "name" then
name_hl = modified_highlight
end
if self.highlight_modified == "all" or self.highlight_modified == "icon" then
icon_hl = modified_highlight
end
end
return icon_hl, name_hl
end
---Append optional highlighting to icon or name.
---@param node table
---@param get_hl fun(node: table): HL_POSITION, string
---@param icon_hl string[] icons to append to
---@param name_hl string[] names to append to
function Builder:_append_highlight(node, get_hl, icon_hl, name_hl)
local pos, hl = get_hl(node)
if pos ~= HL_POSITION.none and hl then
if pos == HL_POSITION.all or pos == HL_POSITION.icon then
table.insert(icon_hl, hl)
end
if pos == HL_POSITION.all or pos == HL_POSITION.name then
table.insert(name_hl, hl)
end
end
local icon, hl_group = icons.get_file_icon(node.name, node.extension)
return { str = icon, hl = { hl_group } }, { str = node.name, hl = { hl } }
end
---@private
---@param indent_markers HighlightedString[]
---@param arrows HighlightedString[]|nil
---@param icon HighlightedString
---@param name HighlightedString
---@param git_icons HighlightedString[]|nil
---@param diagnostics_icon HighlightedString|nil
---@param modified_icon HighlightedString|nil
---@param bookmark_icon HighlightedString|nil
---@param node table
---@return HighlightedString[]
function Builder:_format_line(indent_markers, arrows, icon, name, git_icons, diagnostics_icon, modified_icon, bookmark_icon)
function Builder:format_line(indent_markers, arrows, icon, name, node)
local added_len = 0
local function add_to_end(t1, t2)
if not t2 then
return
end
for _, v in ipairs(t2) do
if added_len > 0 then
table.insert(t1, { str = self.icon_padding })
table.insert(t1, { str = M.opts.renderer.icons.padding })
end
table.insert(t1, v)
end
@@ -379,78 +217,134 @@ function Builder:_format_line(indent_markers, arrows, icon, name, git_icons, dia
local line = { indent_markers, arrows }
add_to_end(line, { icon })
if git_icons and self.git_placement == "before" then
add_to_end(line, git_icons)
end
if modified_icon and self.modified_placement == "before" then
add_to_end(line, { modified_icon })
end
if diagnostics_icon and self.diagnostics_placement == "before" then
add_to_end(line, { diagnostics_icon })
end
if bookmark_icon and self.bookmarks_placement == "before" then
add_to_end(line, { bookmark_icon })
for i = #M.decorators, 1, -1 do
add_to_end(line, M.decorators[i]:icons_before(node))
end
add_to_end(line, { name })
if git_icons and self.git_placement == "after" then
add_to_end(line, git_icons)
end
if modified_icon and self.modified_placement == "after" then
add_to_end(line, { modified_icon })
end
if diagnostics_icon and self.diagnostics_placement == "after" then
add_to_end(line, { diagnostics_icon })
end
if bookmark_icon and self.bookmarks_placement == "after" then
add_to_end(line, { bookmark_icon })
for i = #M.decorators, 1, -1 do
add_to_end(line, M.decorators[i]:icons_after(node))
end
return line
end
function Builder:_build_line(node, idx, num_children, unloaded_bufnr)
local copy_paste = require "nvim-tree.actions.fs.copy-paste"
---@private
---@param node Node
function Builder:build_signs(node)
-- first in priority order
local sign_name
for _, d in ipairs(M.decorators) do
sign_name = d:sign_name(node)
if sign_name then
self.signs[self.index] = sign_name
break
end
end
end
---Create a highlight group for groups with later groups overriding previous.
---Combined group name is less than the 200 byte limit of highlight group names
---@private
---@param groups string[] highlight group names
---@return string group_name "NvimTreeCombinedHL" .. sha256
function Builder:create_combined_group(groups)
local combined_name = string.format("NvimTreeCombinedHL%s", vim.fn.sha256(table.concat(groups)))
-- only create if necessary
if not self.combined_groups[combined_name] then
self.combined_groups[combined_name] = true
local combined_hl = {}
-- build the highlight, overriding values
for _, group in ipairs(groups) do
local hl = vim.api.nvim_get_hl(0, { name = group, link = false })
combined_hl = vim.tbl_extend("force", combined_hl, hl)
end
-- add highlights to the global namespace
vim.api.nvim_set_hl(0, combined_name, combined_hl)
table.insert(self.combined_groups, combined_name)
end
return combined_name
end
---Calculate highlight group for icon and name. A combined highlight group will be created
---when there is more than one highlight.
---A highlight group is always calculated and upserted for the case of highlights changing.
---@private
---@param node Node
---@return string|nil icon_hl_group
---@return string|nil name_hl_group
function Builder:add_highlights(node)
-- result
local icon_hl_group, name_hl_group
-- calculate all groups
local icon_groups = {}
local name_groups = {}
local d, icon, name
for i = #M.decorators, 1, -1 do
d = M.decorators[i]
icon, name = d:groups_icon_name(node)
table.insert(icon_groups, icon)
table.insert(name_groups, name)
end
-- one or many icon groups; <= 0.8 always uses highest due to lack of a practical nvim_get_hl equivalent
if #icon_groups > 1 then
if vim.fn.has "nvim-0.9" == 1 then
icon_hl_group = self:create_combined_group(icon_groups)
else
icon_hl_group = icon_groups[#icon_groups]
end
else
icon_hl_group = icon_groups[1]
end
-- one or many name groups; <= 0.8 always uses highest due to lack of a practical nvim_get_hl equivalent
if #name_groups > 1 then
if vim.fn.has "nvim-0.9" == 1 then
name_hl_group = self:create_combined_group(name_groups)
else
name_hl_group = name_groups[#name_groups]
end
else
name_hl_group = name_groups[1]
end
return icon_hl_group, name_hl_group
end
---@private
function Builder:build_line(node, idx, num_children)
-- various components
local indent_markers = pad.get_indent_markers(self.depth, idx, num_children, node, self.markers)
local arrows = pad.get_arrows(node)
-- adds icons to signcolumn
local bookmark_icon = self:_get_bookmark_icon(node)
local git_icons = self:_get_git_icons(node)
local modified_icon = self:_get_modified_icon(node)
local diagnostics_icon = self:_get_diagnostics_icon(node)
-- main components
local is_folder = node.nodes ~= nil
local is_symlink = node.link_to ~= nil
local icon, name
if is_folder then
icon, name = self:_build_folder(node)
icon, name = self:build_folder(node)
elseif is_symlink then
icon, name = self:_build_symlink(node)
icon, name = self:build_symlink(node)
else
icon, name = self:_build_file(node)
icon, name = self:build_file(node)
end
-- highlight override
local icon_hl_override, name_hl_override = self:_get_highlight_override(node, unloaded_bufnr)
if icon_hl_override then
icon.hl = { icon_hl_override }
end
if name_hl_override then
name.hl = { name_hl_override }
end
-- highighting
local icon_hl_group, name_hl_group = self:add_highlights(node)
table.insert(icon.hl, icon_hl_group)
table.insert(name.hl, name_hl_group)
-- extra highighting
self:_append_highlight(node, bookmarks.get_highlight, icon.hl, name.hl)
self:_append_highlight(node, diagnostics.get_highlight, icon.hl, name.hl)
self:_append_highlight(node, copy_paste.get_highlight, icon.hl, name.hl)
local line = self:_format_line(indent_markers, arrows, icon, name, git_icons, diagnostics_icon, modified_icon, bookmark_icon)
self:_insert_line(self:_unwrap_highlighted_strings(line))
local line = self:format_line(indent_markers, arrows, icon, name, node)
table.insert(self.lines, self:unwrap_highlighted_strings(line))
self.index = self.index + 1
@@ -458,13 +352,14 @@ function Builder:_build_line(node, idx, num_children, unloaded_bufnr)
if node.open then
self.depth = self.depth + 1
self:build(node, unloaded_bufnr)
self:build_lines(node)
self.depth = self.depth - 1
end
end
function Builder:_get_nodes_number(nodes)
if not self.filter then
---@private
function Builder:get_nodes_number(nodes)
if not live_filter.filter then
return #nodes
end
@@ -477,53 +372,77 @@ function Builder:_get_nodes_number(nodes)
return i
end
function Builder:build(tree, unloaded_bufnr)
local num_children = self:_get_nodes_number(tree.nodes)
---@private
function Builder:build_lines(node)
if not node then
node = core.get_explorer()
end
local num_children = self:get_nodes_number(node.nodes)
local idx = 1
for _, node in ipairs(tree.nodes) do
if not node.hidden then
self:_build_line(node, idx, num_children, unloaded_bufnr)
for _, n in ipairs(node.nodes) do
if not n.hidden then
self:build_signs(n)
self:build_line(n, idx, num_children)
idx = idx + 1
end
end
return self
end
local function format_root_name(root_cwd, root_label)
---@private
---@param root_label function|string
---@return string
function Builder:format_root_name(root_label)
if type(root_label) == "function" then
local label = root_label(root_cwd)
local label = root_label(self.root_cwd)
if type(label) == "string" then
return label
else
root_label = DEFAULT_ROOT_FOLDER_LABEL
return "???"
end
end
return utils.path_remove_trailing(vim.fn.fnamemodify(root_cwd, root_label))
return utils.path_remove_trailing(vim.fn.fnamemodify(self.root_cwd, root_label))
end
function Builder:build_header(show_header)
if show_header then
local root_name = format_root_name(self.root_cwd, self.root_folder_label)
self:_insert_line(root_name)
self:_insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name))
---@private
function Builder:build_header()
if view.is_root_folder_visible(core.get_cwd()) then
local root_name = self:format_root_name(M.opts.renderer.root_folder_label)
table.insert(self.lines, root_name)
self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name))
self.index = 1
end
if self.filter then
local filter_line = self.filter_prefix .. "/" .. self.filter .. "/"
self:_insert_line(filter_line)
local prefix_length = string.len(self.filter_prefix)
self:_insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length)
self:_insert_highlight({ "NvimTreeLiveFilterValue" }, prefix_length, string.len(filter_line))
if live_filter.filter then
local filter_line = string.format("%s/%s/", M.opts.live_filter.prefix, live_filter.filter)
table.insert(self.lines, filter_line)
local prefix_length = string.len(M.opts.live_filter.prefix)
self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length)
self:insert_highlight({ "NvimTreeLiveFilterValue" }, prefix_length, string.len(filter_line))
self.index = self.index + 1
end
end
---Build all lines with highlights and signs
---@return Builder
function Builder:build()
self:build_header()
self:build_lines()
return self
end
function Builder:unwrap()
return self.lines, self.highlights, self.signs
function Builder.setup(opts)
M.opts = opts
-- priority order
M.decorators = {
DecoratorCut:new(opts),
DecoratorCopied:new(opts),
DecoratorDiagnostics:new(opts),
DecoratorBookmarks:new(opts),
DecoratorModified:new(opts),
DecoratorOpened:new(opts),
DecoratorGit:new(opts),
}
end
return Builder

View File

@@ -1,51 +0,0 @@
local marks = require "nvim-tree.marks"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local M = {
ICON = {},
hl_pos = HL_POSITION.none,
}
---Bookmark highlight group and position when highlight_bookmark.
---@param node table
---@return HL_POSITION position none when clipboard empty
---@return string|nil group only when node present in clipboard
function M.get_highlight(node)
if M.hl_pos == HL_POSITION.none then
return HL_POSITION.none, nil
end
local mark = marks.get_mark(node)
if mark then
return M.hl_pos, "NvimTreeBookmarkHL"
else
return HL_POSITION.none, nil
end
end
---bookmark icon if marked
---@param node table
---@return HighlightedString|nil bookmark icon
function M.get_icon(node)
if M.config.renderer.icons.show.bookmarks and marks.get_mark(node) then
return M.ICON
end
end
function M.setup(opts)
M.config = {
renderer = opts.renderer,
}
M.hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none
M.ICON = {
str = opts.renderer.icons.glyphs.bookmark,
hl = { "NvimTreeBookmark" },
}
vim.fn.sign_define(M.ICON.hl[1], { text = M.ICON.str, texthl = M.ICON.hl[1] })
end
return M

View File

@@ -1,30 +1,37 @@
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local diagnostics = require "nvim-tree.diagnostics"
local M = {
HS_FILE = {},
HS_FOLDER = {},
ICON = {},
hl_pos = HL_POSITION.none,
-- highlight strings for the icons
HS_ICON = {},
-- highlight groups for HL
HG_FILE = {},
HG_FOLDER = {},
-- position for HL
HL_POS = HL_POSITION.none,
}
---Diagnostics text highlight group when highlight_diagnostics.
---Diagnostics highlight group and position when highlight_diagnostics.
---@param node table
---@return HL_POSITION position none when no status
---@return string|nil group only when status
function M.get_highlight(node)
if not node or M.hl_pos == HL_POSITION.none then
if not node or M.HL_POS == HL_POSITION.none then
return HL_POSITION.none, nil
end
local group
local diag_status = diagnostics.get_diag_status(node)
if node.nodes then
group = M.HS_FOLDER[node.diag_status]
group = M.HS_FOLDER[diag_status and diag_status.value]
else
group = M.HS_FILE[node.diag_status]
group = M.HS_FILE[diag_status and diag_status.value]
end
if group then
return M.hl_pos, group
return M.HL_POS, group
else
return HL_POSITION.none, nil
end
@@ -35,7 +42,8 @@ end
---@return HighlightedString|nil modified icon
function M.get_icon(node)
if node and M.config.diagnostics.enable and M.config.renderer.icons.show.diagnostics then
return M.ICON[node.diag_status]
local diag_status = diagnostics.get_diag_status(node)
return M.ICON[diag_status and diag_status.value]
end
end
@@ -46,40 +54,38 @@ function M.setup(opts)
}
if opts.diagnostics.enable and opts.renderer.highlight_diagnostics then
-- TODO add a HL_POSITION
-- M.hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics]
M.hl_pos = HL_POSITION.name
M.HL_POS = HL_POSITION[opts.renderer.highlight_diagnostics]
end
M.HS_FILE[vim.diagnostic.severity.ERROR] = "NvimTreeLspDiagnosticsErrorText"
M.HS_FILE[vim.diagnostic.severity.WARN] = "NvimTreeLspDiagnosticsWarningText"
M.HS_FILE[vim.diagnostic.severity.INFO] = "NvimTreeLspDiagnosticsInfoText"
M.HS_FILE[vim.diagnostic.severity.HINT] = "NvimTreeLspDiagnosticsHintText"
M.HG_FILE[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFileHL"
M.HG_FILE[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarningFileHL"
M.HG_FILE[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFileHL"
M.HG_FILE[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFileHL"
M.HS_FOLDER[vim.diagnostic.severity.ERROR] = "NvimTreeLspDiagnosticsErrorFolderText"
M.HS_FOLDER[vim.diagnostic.severity.WARN] = "NvimTreeLspDiagnosticsWarningFolderText"
M.HS_FOLDER[vim.diagnostic.severity.INFO] = "NvimTreeLspDiagnosticsInfoFolderText"
M.HS_FOLDER[vim.diagnostic.severity.HINT] = "NvimTreeLspDiagnosticsHintFolderText"
M.HG_FOLDER[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFolderHL"
M.HG_FOLDER[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarningFolderHL"
M.HG_FOLDER[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFolderHL"
M.HG_FOLDER[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFolderHL"
M.ICON[vim.diagnostic.severity.ERROR] = {
M.HS_ICON[vim.diagnostic.severity.ERROR] = {
str = M.config.diagnostics.icons.error,
hl = { "NvimTreeLspDiagnosticsError" },
hl = { "NvimTreeDiagnosticErrorIcon" },
}
M.ICON[vim.diagnostic.severity.WARN] = {
M.HS_ICON[vim.diagnostic.severity.WARN] = {
str = M.config.diagnostics.icons.warning,
hl = { "NvimTreeLspDiagnosticsWarning" },
hl = { "NvimTreeDiagnosticWarningIcon" },
}
M.ICON[vim.diagnostic.severity.INFO] = {
M.HS_ICON[vim.diagnostic.severity.INFO] = {
str = M.config.diagnostics.icons.info,
hl = { "NvimTreeLspDiagnosticsInformation" },
hl = { "NvimTreeDiagnosticInfoIcon" },
}
M.ICON[vim.diagnostic.severity.HINT] = {
M.HS_ICON[vim.diagnostic.severity.HINT] = {
str = M.config.diagnostics.icons.hint,
hl = { "NvimTreeLspDiagnosticsHint" },
hl = { "NvimTreeDiagnosticHintIcon" },
}
for _, i in ipairs(M.ICON) do
for _, i in ipairs(M.HS_ICON) do
vim.fn.sign_define(i.hl[1], { text = i.str, texthl = i.hl[1] })
end
end

View File

@@ -57,9 +57,9 @@ local function show()
end
M.popup_win = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, false), false, {
relative = "cursor",
relative = "win",
row = 0,
col = 1 - vim.fn.getcursorcharpos()[3],
bufpos = { vim.api.nvim_win_get_cursor(0)[1] - 1, 0 },
width = math.min(text_width, vim.o.columns - 2),
height = 1,
noautocmd = true,

View File

@@ -1,191 +0,0 @@
local notify = require "nvim-tree.notify"
local explorer_node = require "nvim-tree.explorer.node"
local M = {}
local function build_icons_table(i)
local icons = {
staged = { str = i.staged, hl = { "NvimTreeGitStaged" }, ord = 1 },
unstaged = { str = i.unstaged, hl = { "NvimTreeGitDirty" }, ord = 2 },
renamed = { str = i.renamed, hl = { "NvimTreeGitRenamed" }, ord = 3 },
deleted = { str = i.deleted, hl = { "NvimTreeGitDeleted" }, ord = 4 },
unmerged = { str = i.unmerged, hl = { "NvimTreeGitMerge" }, ord = 5 },
untracked = { str = i.untracked, hl = { "NvimTreeGitNew" }, ord = 6 },
ignored = { str = i.ignored, hl = { "NvimTreeGitIgnored" }, ord = 7 },
}
return {
["M "] = { icons.staged },
[" M"] = { icons.unstaged },
["C "] = { icons.staged },
[" C"] = { icons.unstaged },
["CM"] = { icons.unstaged },
[" T"] = { icons.unstaged },
["T "] = { icons.staged },
["TM"] = { icons.staged, icons.unstaged },
["MM"] = { icons.staged, icons.unstaged },
["MD"] = { icons.staged },
["A "] = { icons.staged },
["AD"] = { icons.staged },
[" A"] = { icons.untracked },
-- not sure about this one
["AA"] = { icons.unmerged, icons.untracked },
["AU"] = { icons.unmerged, icons.untracked },
["AM"] = { icons.staged, icons.unstaged },
["??"] = { icons.untracked },
["R "] = { icons.renamed },
[" R"] = { icons.renamed },
["RM"] = { icons.unstaged, icons.renamed },
["UU"] = { icons.unmerged },
["UD"] = { icons.unmerged },
["UA"] = { icons.unmerged },
[" D"] = { icons.deleted },
["D "] = { icons.deleted },
["DA"] = { icons.unstaged },
["RD"] = { icons.deleted },
["DD"] = { icons.deleted },
["DU"] = { icons.deleted, icons.unmerged },
["!!"] = { icons.ignored },
dirty = { icons.unstaged },
}
end
local function build_hl_table()
local file = {
["M "] = "NvimTreeFileStaged",
["C "] = "NvimTreeFileStaged",
["AA"] = "NvimTreeFileStaged",
["AD"] = "NvimTreeFileStaged",
["MD"] = "NvimTreeFileStaged",
["T "] = "NvimTreeFileStaged",
["TT"] = "NvimTreeFileStaged",
[" M"] = "NvimTreeFileDirty",
["CM"] = "NvimTreeFileDirty",
[" C"] = "NvimTreeFileDirty",
[" T"] = "NvimTreeFileDirty",
["MM"] = "NvimTreeFileDirty",
["AM"] = "NvimTreeFileDirty",
dirty = "NvimTreeFileDirty",
["A "] = "NvimTreeFileStaged",
["??"] = "NvimTreeFileNew",
["AU"] = "NvimTreeFileMerge",
["UU"] = "NvimTreeFileMerge",
["UD"] = "NvimTreeFileMerge",
["DU"] = "NvimTreeFileMerge",
["UA"] = "NvimTreeFileMerge",
[" D"] = "NvimTreeFileDeleted",
["DD"] = "NvimTreeFileDeleted",
["RD"] = "NvimTreeFileDeleted",
["D "] = "NvimTreeFileDeleted",
["R "] = "NvimTreeFileRenamed",
["RM"] = "NvimTreeFileRenamed",
[" R"] = "NvimTreeFileRenamed",
["!!"] = "NvimTreeFileIgnored",
[" A"] = "none",
}
local folder = {}
for k, v in pairs(file) do
folder[k] = v:gsub("File", "Folder")
end
return file, folder
end
local function nil_() end
local function warn_status(git_status)
notify.warn(string.format("Unrecognized git state '%s'", git_status))
end
---@param node table
---@return HighlightedString[]|nil
local function get_icons_(node)
local git_status = explorer_node.get_git_status(node)
if git_status == nil then
return nil
end
local inserted = {}
local iconss = {}
for _, s in pairs(git_status) do
local icons = M.git_icons[s]
if not icons then
if not M.config.highlight_git then
warn_status(s)
end
return nil
end
for _, icon in pairs(icons) do
if #icon.str > 0 then
if not inserted[icon] then
table.insert(iconss, icon)
inserted[icon] = true
end
end
end
end
if #iconss == 0 then
return nil
end
-- sort icons so it looks slightly better
table.sort(iconss, function(a, b)
return a.ord < b.ord
end)
return iconss
end
function M.setup_signs(i)
vim.fn.sign_define("NvimTreeGitDirty", { text = i.unstaged, texthl = "NvimTreeGitDirty" })
vim.fn.sign_define("NvimTreeGitStaged", { text = i.staged, texthl = "NvimTreeGitStaged" })
vim.fn.sign_define("NvimTreeGitMerge", { text = i.unmerged, texthl = "NvimTreeGitMerge" })
vim.fn.sign_define("NvimTreeGitRenamed", { text = i.renamed, texthl = "NvimTreeGitRenamed" })
vim.fn.sign_define("NvimTreeGitNew", { text = i.untracked, texthl = "NvimTreeGitNew" })
vim.fn.sign_define("NvimTreeGitDeleted", { text = i.deleted, texthl = "NvimTreeGitDeleted" })
vim.fn.sign_define("NvimTreeGitIgnored", { text = i.ignored, texthl = "NvimTreeGitIgnored" })
end
local function get_highlight_(node)
local git_status = explorer_node.get_git_status(node)
if git_status == nil then
return
end
if node.nodes then
return M.folder_hl[git_status[1]]
else
return M.file_hl[git_status[1]]
end
end
function M.setup(opts)
M.config = opts.renderer
M.git_icons = build_icons_table(opts.renderer.icons.glyphs.git)
M.file_hl, M.folder_hl = build_hl_table()
if opts.renderer.icons.git_placement == "signcolumn" then
M.setup_signs(opts.renderer.icons.glyphs.git)
end
if opts.renderer.icons.show.git then
M.get_icons = get_icons_
else
M.get_icons = nil_
end
if opts.renderer.highlight_git then
M.get_highlight = get_highlight_
else
M.get_highlight = nil_
end
M.git_show_on_open_dirs = opts.git.show_on_open_dirs
end
return M

View File

@@ -1,41 +0,0 @@
local modified = require "nvim-tree.modified"
local M = {}
local HIGHLIGHT = "NvimTreeModifiedFile"
---return modified icon if node is modified, otherwise return empty string
---@param node table
---@return HighlightedString|nil modified icon
function M.get_icon(node)
if not modified.is_modified(node) or not M.show_icon then
return nil
end
return { str = M.icon, hl = { HIGHLIGHT } }
end
function M.setup_signs()
vim.fn.sign_define(HIGHLIGHT, { text = M.icon, texthl = HIGHLIGHT })
end
---@param node table
---@return string|nil
function M.get_highlight(node)
if not modified.is_modified(node) then
return nil
end
return HIGHLIGHT
end
function M.setup(opts)
M.icon = opts.renderer.icons.glyphs.modified
M.show_icon = opts.renderer.icons.show.modified
if opts.renderer.icons.modified_placement == "signcolumn" then
M.setup_signs()
end
end
return M

View File

@@ -0,0 +1,51 @@
local marks = require "nvim-tree.marks"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorBookmarks: Decorator
---@field icon HighlightedString
local DecoratorBookmarks = Decorator:new()
---@param opts table
---@return DecoratorBookmarks
function DecoratorBookmarks:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.bookmarks_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorBookmarks
if opts.renderer.icons.show.bookmarks then
o.icon = {
str = opts.renderer.icons.glyphs.bookmark,
hl = { "NvimTreeBookmarkIcon" },
}
o:define_sign(o.icon)
end
return o
end
---Bookmark icon: renderer.icons.show.bookmarks and node is marked
---@param node Node
---@return HighlightedString[]|nil icons
function DecoratorBookmarks:calculate_icons(node)
if marks.get_mark(node) then
return { self.icon }
end
end
---Bookmark highlight: renderer.highlight_bookmarks and node is marked
---@param node Node
---@return string|nil group
function DecoratorBookmarks:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and marks.get_mark(node) then
return "NvimTreeBookmarkHL"
end
end
return DecoratorBookmarks

View File

@@ -0,0 +1,38 @@
local copy_paste
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorCopied: Decorator
---@field enabled boolean
---@field icon HighlightedString|nil
local DecoratorCopied = Decorator:new()
---@param opts table
---@return DecoratorCopied
function DecoratorCopied:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT.none,
})
---@cast o DecoratorCopied
-- cyclic
copy_paste = copy_paste or require "nvim-tree.actions.fs.copy-paste"
return o
end
---Copied highlight: renderer.highlight_clipboard and node is copied
---@param node Node
---@return string|nil group
function DecoratorCopied:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_copied(node) then
return "NvimTreeCopiedHL"
end
end
return DecoratorCopied

View File

@@ -0,0 +1,38 @@
local copy_paste
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorCut: Decorator
---@field enabled boolean
---@field icon HighlightedString|nil
local DecoratorCut = Decorator:new()
---@param opts table
---@return DecoratorCut
function DecoratorCut:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT.none,
})
---@cast o DecoratorCut
-- cyclic
copy_paste = copy_paste or require "nvim-tree.actions.fs.copy-paste"
return o
end
---Cut highlight: renderer.highlight_clipboard and node is cut
---@param node Node
---@return string|nil group
function DecoratorCut:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_cut(node) then
return "NvimTreeCutHL"
end
end
return DecoratorCut

View File

@@ -0,0 +1,110 @@
local diagnostics = require "nvim-tree.diagnostics"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
-- highlight groups by severity
local HG_ICON = {
[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorIcon",
[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarnIcon",
[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoIcon",
[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintIcon",
}
local HG_FILE = {
[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFileHL",
[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarnFileHL",
[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFileHL",
[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFileHL",
}
local HG_FOLDER = {
[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFolderHL",
[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarnFolderHL",
[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFolderHL",
[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFolderHL",
}
-- opts.diagnostics.icons.
local ICON_KEYS = {
["error"] = vim.diagnostic.severity.ERROR,
["warning"] = vim.diagnostic.severity.WARN,
["info"] = vim.diagnostic.severity.INFO,
["hint"] = vim.diagnostic.severity.HINT,
}
---@class DecoratorDiagnostics: Decorator
---@field icons HighlightedString[]
local DecoratorDiagnostics = Decorator:new()
---@param opts table
---@return DecoratorDiagnostics
function DecoratorDiagnostics:new(opts)
local o = Decorator.new(self, {
enabled = opts.diagnostics.enable,
hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.diagnostics_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorDiagnostics
if not o.enabled then
return o
end
if opts.renderer.icons.show.diagnostics then
o.icons = {}
for name, sev in pairs(ICON_KEYS) do
o.icons[sev] = {
str = opts.diagnostics.icons[name],
hl = { HG_ICON[sev] },
}
o:define_sign(o.icons[sev])
end
end
return o
end
---Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status
---@param node Node
---@return HighlightedString[]|nil icons
function DecoratorDiagnostics:calculate_icons(node)
if node and self.enabled and self.icons then
local diag_status = diagnostics.get_diag_status(node)
local diag_value = diag_status and diag_status.value
if diag_value then
return { self.icons[diag_value] }
end
end
end
---Diagnostic highlight: diagnostics.enable, renderer.highlight_diagnostics and node has status
---@param node Node
---@return string|nil group
function DecoratorDiagnostics:calculate_highlight(node)
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
return nil
end
local diag_status = diagnostics.get_diag_status(node)
local diag_value = diag_status and diag_status.value
if not diag_value then
return nil
end
local group
if node.nodes then
group = HG_FOLDER[diag_value]
else
group = HG_FILE[diag_value]
end
if group then
return group
else
return nil
end
end
return DecoratorDiagnostics

View File

@@ -0,0 +1,221 @@
local notify = require "nvim-tree.notify"
local explorer_node = require "nvim-tree.explorer.node"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class HighlightedStringGit: HighlightedString
---@field ord number decreasing priority
---@class DecoratorGit: Decorator
---@field file_hl table<string, string> by porcelain status e.g. "AM"
---@field folder_hl table<string, string> by porcelain status
---@field icons_by_status HighlightedStringGit[] by human status
---@field icons_by_xy table<string, HighlightedStringGit[]> by porcelain status
local DecoratorGit = Decorator:new()
---@param opts table
---@return DecoratorGit
function DecoratorGit:new(opts)
local o = Decorator.new(self, {
enabled = opts.git.enable,
hl_pos = HL_POSITION[opts.renderer.highlight_git] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.git_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorGit
if not o.enabled then
return o
end
if o.hl_pos ~= HL_POSITION.none then
o:build_hl_table()
end
if opts.renderer.icons.show.git then
o:build_icons_by_status(opts.renderer.icons.glyphs.git)
o:build_icons_by_xy(o.icons_by_status)
for _, icon in pairs(o.icons_by_status) do
self:define_sign(icon)
end
end
return o
end
---@param glyphs table<string, string> user glyps
function DecoratorGit:build_icons_by_status(glyphs)
self.icons_by_status = {
staged = { str = glyphs.staged, hl = { "NvimTreeGitStagedIcon" }, ord = 1 },
unstaged = { str = glyphs.unstaged, hl = { "NvimTreeGitDirtyIcon" }, ord = 2 },
renamed = { str = glyphs.renamed, hl = { "NvimTreeGitRenamedIcon" }, ord = 3 },
deleted = { str = glyphs.deleted, hl = { "NvimTreeGitDeletedIcon" }, ord = 4 },
unmerged = { str = glyphs.unmerged, hl = { "NvimTreeGitMergeIcon" }, ord = 5 },
untracked = { str = glyphs.untracked, hl = { "NvimTreeGitNewIcon" }, ord = 6 },
ignored = { str = glyphs.ignored, hl = { "NvimTreeGitIgnoredIcon" }, ord = 7 },
}
end
---@param icons HighlightedStringGit[]
function DecoratorGit:build_icons_by_xy(icons)
self.icons_by_xy = {
["M "] = { icons.staged },
[" M"] = { icons.unstaged },
["C "] = { icons.staged },
[" C"] = { icons.unstaged },
["CM"] = { icons.unstaged },
[" T"] = { icons.unstaged },
["T "] = { icons.staged },
["TM"] = { icons.staged, icons.unstaged },
["MM"] = { icons.staged, icons.unstaged },
["MD"] = { icons.staged },
["A "] = { icons.staged },
["AD"] = { icons.staged },
[" A"] = { icons.untracked },
-- not sure about this one
["AA"] = { icons.unmerged, icons.untracked },
["AU"] = { icons.unmerged, icons.untracked },
["AM"] = { icons.staged, icons.unstaged },
["??"] = { icons.untracked },
["R "] = { icons.renamed },
[" R"] = { icons.renamed },
["RM"] = { icons.unstaged, icons.renamed },
["UU"] = { icons.unmerged },
["UD"] = { icons.unmerged },
["UA"] = { icons.unmerged },
[" D"] = { icons.deleted },
["D "] = { icons.deleted },
["DA"] = { icons.unstaged },
["RD"] = { icons.deleted },
["DD"] = { icons.deleted },
["DU"] = { icons.deleted, icons.unmerged },
["!!"] = { icons.ignored },
dirty = { icons.unstaged },
}
end
function DecoratorGit:build_hl_table()
self.file_hl = {
["M "] = "NvimTreeGitFileStagedHL",
["C "] = "NvimTreeGitFileStagedHL",
["AA"] = "NvimTreeGitFileStagedHL",
["AD"] = "NvimTreeGitFileStagedHL",
["MD"] = "NvimTreeGitFileStagedHL",
["T "] = "NvimTreeGitFileStagedHL",
["TT"] = "NvimTreeGitFileStagedHL",
[" M"] = "NvimTreeGitFileDirtyHL",
["CM"] = "NvimTreeGitFileDirtyHL",
[" C"] = "NvimTreeGitFileDirtyHL",
[" T"] = "NvimTreeGitFileDirtyHL",
["MM"] = "NvimTreeGitFileDirtyHL",
["AM"] = "NvimTreeGitFileDirtyHL",
dirty = "NvimTreeGitFileDirtyHL",
["A "] = "NvimTreeGitFileStagedHL",
["??"] = "NvimTreeGitFileNewHL",
["AU"] = "NvimTreeGitFileMergeHL",
["UU"] = "NvimTreeGitFileMergeHL",
["UD"] = "NvimTreeGitFileMergeHL",
["DU"] = "NvimTreeGitFileMergeHL",
["UA"] = "NvimTreeGitFileMergeHL",
[" D"] = "NvimTreeGitFileDeletedHL",
["DD"] = "NvimTreeGitFileDeletedHL",
["RD"] = "NvimTreeGitFileDeletedHL",
["D "] = "NvimTreeGitFileDeletedHL",
["R "] = "NvimTreeGitFileRenamedHL",
["RM"] = "NvimTreeGitFileRenamedHL",
[" R"] = "NvimTreeGitFileRenamedHL",
["!!"] = "NvimTreeGitFileIgnoredHL",
[" A"] = "none",
}
self.folder_hl = {}
for k, v in pairs(self.file_hl) do
self.folder_hl[k] = v:gsub("File", "Folder")
end
end
---Git icons: git.enable, renderer.icons.show.git and node has status
---@param node Node
---@return HighlightedString[]|nil modified icon
function DecoratorGit:calculate_icons(node)
if not node or not self.enabled or not self.icons_by_xy then
return nil
end
local git_status = explorer_node.get_git_status(node)
if git_status == nil then
return nil
end
local inserted = {}
local iconss = {}
for _, s in pairs(git_status) do
local icons = self.icons_by_xy[s]
if not icons then
if self.hl_pos == HL_POSITION.none then
notify.warn(string.format("Unrecognized git state '%s'", git_status))
end
return nil
end
for _, icon in pairs(icons) do
if #icon.str > 0 then
if not inserted[icon] then
table.insert(iconss, icon)
inserted[icon] = true
end
end
end
end
if #iconss == 0 then
return nil
end
-- sort icons so it looks slightly better
table.sort(iconss, function(a, b)
return a.ord < b.ord
end)
return iconss
end
---Get the first icon as the sign if appropriate
---@param node Node
---@return string|nil name
function DecoratorGit:sign_name(node)
if self.icon_placement ~= ICON_PLACEMENT.signcolumn then
return
end
local icons = self:calculate_icons(node)
if icons and #icons > 0 then
return icons[1].hl[1]
end
end
---Git highlight: git.enable, renderer.highlight_git and node has status
---@param node Node
---@return string|nil group
function DecoratorGit:calculate_highlight(node)
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
return nil
end
local git_status = explorer_node.get_git_status(node)
if not git_status then
return nil
end
if node.nodes then
return self.folder_hl[git_status[1]]
else
return self.file_hl[git_status[1]]
end
end
return DecoratorGit

View File

@@ -0,0 +1,122 @@
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
---@class Decorator
---@field protected enabled boolean
---@field protected hl_pos HL_POSITION
---@field protected icon_placement ICON_PLACEMENT
local Decorator = {}
---@param o Decorator|nil
---@return Decorator
function Decorator:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
---Maybe highlight groups
---@param node Node
---@return string|nil icon highlight group
---@return string|nil name highlight group
function Decorator:groups_icon_name(node)
local icon_hl, name_hl
if self.enabled and self.hl_pos ~= HL_POSITION.none then
local hl = self:calculate_highlight(node)
if self.hl_pos == HL_POSITION.all or self.hl_pos == HL_POSITION.icon then
icon_hl = hl
end
if self.hl_pos == HL_POSITION.all or self.hl_pos == HL_POSITION.name then
name_hl = hl
end
end
return icon_hl, name_hl
end
---Maybe icon sign
---@param node Node
---@return string|nil name
function Decorator:sign_name(node)
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.signcolumn then
return
end
local icons = self:calculate_icons(node)
if icons and #icons > 0 then
return icons[1].hl[1]
end
end
---Icons when ICON_PLACEMENT.before
---@param node Node
---@return HighlightedString[]|nil icons
function Decorator:icons_before(node)
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.before then
return
end
return self:calculate_icons(node)
end
---Icons when ICON_PLACEMENT.after
---@param node Node
---@return HighlightedString[]|nil icons
function Decorator:icons_after(node)
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.after then
return
end
return self:calculate_icons(node)
end
---Maybe icons, optionally implemented
---@protected
---@param _ Node
---@return HighlightedString[]|nil icons
function Decorator:calculate_icons(_)
return nil
end
---Maybe highlight group, optionally implemented
---@protected
---@param _ Node
---@return string|nil group
function Decorator:calculate_highlight(_)
return nil
end
---Define a sign
---@protected
---@param icon HighlightedString|nil
function Decorator:define_sign(icon)
if icon and #icon.hl > 0 then
local name = icon.hl[1]
if not vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
vim.fn.sign_undefine(name)
end
-- don't use sign if not defined
if #icon.str < 1 then
self.icon_placement = ICON_PLACEMENT.none
return
end
-- byte index of the next character, allowing for wide
local bi = vim.fn.byteidx(icon.str, 1)
-- first (wide) character, falls back to empty string
local text = string.sub(icon.str, 1, bi)
vim.fn.sign_define(name, {
text = text,
texthl = name,
})
end
end
return Decorator

View File

@@ -0,0 +1,61 @@
local buffers = require "nvim-tree.buffers"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorModified: Decorator
---@field icon HighlightedString|nil
local DecoratorModified = Decorator:new()
---@param opts table
---@return DecoratorModified
function DecoratorModified:new(opts)
local o = Decorator.new(self, {
enabled = opts.modified.enable,
hl_pos = HL_POSITION[opts.renderer.highlight_modified] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.modified_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorModified
if not o.enabled then
return o
end
if opts.renderer.icons.show.modified then
o.icon = {
str = opts.renderer.icons.glyphs.modified,
hl = { "NvimTreeModifiedIcon" },
}
o:define_sign(o.icon)
end
return o
end
---Modified icon: modified.enable, renderer.icons.show.modified and node is modified
---@param node Node
---@return HighlightedString[]|nil icons
function DecoratorModified:calculate_icons(node)
if self.enabled and buffers.is_modified(node) then
return { self.icon }
end
end
---Modified highlight: modified.enable, renderer.highlight_modified and node is modified
---@param node Node
---@return string|nil group
function DecoratorModified:calculate_highlight(node)
if not self.enabled or self.hl_pos == HL_POSITION.none or not buffers.is_modified(node) then
return nil
end
if node.nodes then
return "NvimTreeModifiedFolderHL"
else
return "NvimTreeModifiedFileHL"
end
end
return DecoratorModified

View File

@@ -0,0 +1,35 @@
local buffers = require "nvim-tree.buffers"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"
---@class DecoratorOpened: Decorator
---@field enabled boolean
---@field icon HighlightedString|nil
local DecoratorOpened = Decorator:new()
---@param opts table
---@return DecoratorOpened
function DecoratorOpened:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_opened_files] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT.none,
})
---@cast o DecoratorOpened
return o
end
---Opened highlight: renderer.highlight_opened_files and node has an open buffer
---@param node Node
---@return string|nil group
function DecoratorOpened:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and buffers.is_opened(node) then
return "NvimTreeOpenedHL"
end
end
return DecoratorOpened

View File

@@ -2,33 +2,30 @@ local core = require "nvim-tree.core"
local log = require "nvim-tree.log"
local view = require "nvim-tree.view"
local events = require "nvim-tree.events"
local modified = require "nvim-tree.renderer.components.modified"
local _padding = require "nvim-tree.renderer.components.padding"
local icon_component = require "nvim-tree.renderer.components.icons"
local full_name = require "nvim-tree.renderer.components.full-name"
local git = require "nvim-tree.renderer.components.git"
local diagnostics = require "nvim-tree.renderer.components.diagnostics"
local Builder = require "nvim-tree.renderer.builder"
local live_filter = require "nvim-tree.live-filter"
local bookmarks = require "nvim-tree.renderer.components.bookmarks"
local M = {
last_highlights = {},
}
local M = {}
local SIGN_GROUP = "NvimTreeRendererSigns"
local namespace_id = vim.api.nvim_create_namespace "NvimTreeHighlights"
local function _draw(bufnr, lines, hl, signs)
---@param bufnr number
---@param lines string[]
---@param hl_args AddHighlightArgs[]
---@param signs string[]
local function _draw(bufnr, lines, hl_args, signs)
vim.api.nvim_buf_set_option(bufnr, "modifiable", true)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
M.render_hl(bufnr, hl)
M.render_hl(bufnr, hl_args)
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
vim.fn.sign_unplace(SIGN_GROUP)
for _, sign in pairs(signs) do
vim.fn.sign_place(0, SIGN_GROUP, sign.sign, bufnr, { lnum = sign.lnum, priority = sign.priority })
for i, sign_name in pairs(signs) do
vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 })
end
end
@@ -37,7 +34,7 @@ function M.render_hl(bufnr, hl)
return
end
vim.api.nvim_buf_clear_namespace(bufnr, namespace_id, 0, -1)
for _, data in ipairs(hl or M.last_highlights) do
for _, data in ipairs(hl) do
if type(data[1]) == "table" then
for _, group in ipairs(data[1]) do
vim.api.nvim_buf_add_highlight(bufnr, namespace_id, group, data[2], data[3], data[4])
@@ -46,16 +43,7 @@ function M.render_hl(bufnr, hl)
end
end
local picture_map = {
jpg = true,
jpeg = true,
png = true,
gif = true,
webp = true,
jxl = true,
}
function M.draw(unloaded_bufnr)
function M.draw()
local bufnr = view.get_bufnr()
if not core.get_explorer() or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
return
@@ -66,30 +54,11 @@ function M.draw(unloaded_bufnr)
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr())
icon_component.reset_config()
local lines, hl, signs = Builder.new(core.get_cwd())
:configure_root_label(M.config.root_folder_label)
:configure_trailing_slash(M.config.add_trailing)
:configure_special_files(M.config.special_files)
:configure_picture_map(picture_map)
:configure_opened_file_highlighting(M.config.highlight_opened_files)
:configure_modified_highlighting(M.config.highlight_modified)
:configure_icon_padding(M.config.icons.padding)
:configure_git_icons_placement(M.config.icons.git_placement)
:configure_diagnostics_icon_placement(M.config.icons.diagnostics_placement)
:configure_bookmark_icon_placement(M.config.icons.bookmarks_placement)
:configure_modified_placement(M.config.icons.modified_placement)
:configure_symlink_destination(M.config.symlink_destination)
:configure_filter(live_filter.filter, live_filter.prefix)
:configure_group_name_modifier(M.config.group_empty)
:build_header(view.is_root_folder_visible(core.get_cwd()))
:build(core.get_explorer(), unloaded_bufnr)
:unwrap()
local builder = Builder:new():build()
_draw(bufnr, lines, hl, signs)
_draw(bufnr, builder.lines, builder.hl_args, builder.signs)
M.last_highlights = hl
if cursor and #lines >= cursor[1] then
if cursor and #builder.lines >= cursor[1] then
vim.api.nvim_win_set_cursor(view.get_winnr(), cursor)
end
@@ -102,15 +71,12 @@ end
function M.setup(opts)
M.config = opts.renderer
M.config.modified = opts.modified
_padding.setup(opts)
full_name.setup(opts)
git.setup(opts)
modified.setup(opts)
diagnostics.setup(opts)
bookmarks.setup(opts)
icon_component.setup(opts)
Builder.setup(opts)
end
return M

View File

@@ -116,6 +116,28 @@ function M.find_node(nodes, fn)
return node, i
end
-- Find the line number of a node.
-- Return -1 is node is nil or not found.
---@param node Node|nil
---@return integer
function M.find_node_line(node)
if not node then
return -1
end
local first_node_line = require("nvim-tree.core").get_nodes_starting_line()
local nodes_by_line = M.get_nodes_by_line(require("nvim-tree.core").get_explorer().nodes, first_node_line)
local iter_start, iter_end = first_node_line, #nodes_by_line
for line = iter_start, iter_end, 1 do
if nodes_by_line[line] == node then
return line
end
end
return -1
end
-- get the node in the tree state depending on the absolute path of the node
-- (grouped or hidden too)
---@param path string
@@ -149,12 +171,11 @@ function M.get_node_from_path(path)
:iterate()
end
--- Get the highest parent of grouped nodes
---@param node_ Node
---@return table
function M.get_parent_of_group(node_)
local node = node_
while node.parent and node.parent.group_next do
---Get the highest parent of grouped nodes
---@param node Node
---@return Node node or parent
function M.get_parent_of_group(node)
while node and node.parent and node.parent.group_next do
node = node.parent
end
return node

View File

@@ -473,7 +473,7 @@ end
function M.get_winnr(tabpage)
tabpage = tabpage or vim.api.nvim_get_current_tabpage()
local tabinfo = M.View.tabpages[tabpage]
if tabinfo ~= nil then
if tabinfo and tabinfo.winnr and vim.api.nvim_win_is_valid(tabinfo.winnr) then
return tabinfo.winnr
end
end

View File

@@ -0,0 +1,11 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"include-v-in-tag": true,
"bootstrap-sha": "34780aca5bac0a58c163ea30719a276fead1bd95",
"packages": {
".": {
"package-name": "nvim-tree",
"release-type": "simple"
}
}
}

16
scripts/doc-comments.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
out=$(grep -nr "^--- @" lua)
if [ "$out" ]; then
last_file=""
while read -r line; do
file="$(echo "$line" | cut -d: -f1)"
if [[ "$file" != "$last_file" ]]; then
echo "$file:" >&2
last_file="$file"
fi
echo "$line" | awk -F: '{ printf(" line %s: %s\n", $2, $3) }' >&2
done <<< "$out"
exit 1
fi

View File

@@ -2,7 +2,7 @@
# run after changing nvim-tree.lua DEFAULT_OPTS or keymap.lua M.default_on_attach
# scrapes and updates nvim-tree-lua.txt
# run from repository root: scripts/update-help.sh
# run from repository root: scripts/help-update.sh OR make help-update
#
@@ -21,6 +21,39 @@ sed -e "s/^ / /" /tmp/DEFAULT_OPTS.2.lua > /tmp/DEFAULT_OPTS.6.lua
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_OPTS.6.lua
}; /${end}/p; d; }" doc/nvim-tree-lua.txt
#
# opts index
#
begin="nvim-tree-index-opts\*"
end="====================="
printf '\n' > /tmp/index-opts.txt
sed -E "
/^ *\*(nvim-tree\..*)\*$/! d ;
s/^.*\*(.*)\*/|\1|/g
" doc/nvim-tree-lua.txt | sort -d >> /tmp/index-opts.txt
printf '\n' >> /tmp/index-opts.txt
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/index-opts.txt
}; /${end}/p; d; }" doc/nvim-tree-lua.txt
#
# api index
#
begin="nvim-tree-index-api\*"
end="====================="
printf '\n' > /tmp/index-api.txt
sed -E "
/\*(nvim-tree-api.*\(\))\*/! d ;
s/^.*\*(.*)\*/|\1|/g
" doc/nvim-tree-lua.txt | sort -d >> /tmp/index-api.txt
printf '\n' >> /tmp/index-api.txt
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/index-api.txt
}; /${end}/p; d; }" doc/nvim-tree-lua.txt
#
# DEFAULT_ON_ATTACH
#
@@ -38,7 +71,7 @@ sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_ON_ATTACH.lua
# help human
echo > /tmp/DEFAULT_ON_ATTACH.help
sed -E "s/^ *vim.keymap.set\('n', '(.*)',.*api(.*),.*opts\('(.*)'.*$/'\`\1\`' '\3' '|nvim-tree-api\2()|'/g
" /tmp/DEFAULT_ON_ATTACH.lua | while read line
" /tmp/DEFAULT_ON_ATTACH.lua | while read -r line
do
eval "printf '%-17.17s %-26.26s %s\n' ${line}" >> /tmp/DEFAULT_ON_ATTACH.help
done

44
scripts/luals-check.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
# Performs a lua-language-server check on all files.
# luals-out/check.json will be produced on any issues, returning 1.
# Outputs only check.json to stdout, all other messages to stderr, to allow jq etc.
# $VIMRUNTIME specifies neovim runtime path, defaults to "/usr/share/nvim/runtime" if unset.
if [ -z "${VIMRUNTIME}" ]; then
export VIMRUNTIME="/usr/share/nvim/runtime"
fi
DIR_SRC="lua"
DIR_OUT="luals-out"
# clear output
rm -rf "${DIR_OUT}"
mkdir "${DIR_OUT}"
# execute inside lua to prevent luals itself from being checked
OUT=$(lua-language-server --check="${DIR_SRC}" --configpath="${PWD}/.luarc.json" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error)
RC=$?
echo "${OUT}" >&2
if [ $RC -ne 0 ]; then
echo "failed with RC=$RC"
exit $RC
fi
# any output is a fail
case "${OUT}" in
*Diagnosis\ complete*)
if [ -f "${DIR_OUT}/check.json" ]; then
cat "${DIR_OUT}/check.json"
exit 1
else
exit 0
fi
;;
*)
exit 1
;;
esac