mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-04-13 12:30:40 +08:00
feat(filetree): add nvim-tree.lua
This commit is contained in:
parent
fba36bf5a0
commit
62a15d02a4
@ -1307,6 +1307,7 @@ let g:spacevim_smartcloseignoreft = [
|
||||
\ 'tagbar',
|
||||
\ 'vimfiler',
|
||||
\ 'defx',
|
||||
\ 'NvimTree',
|
||||
\ 'SpaceVimRunner',
|
||||
\ 'SpaceVimREPL',
|
||||
\ 'SpaceVimQuickFix',
|
||||
@ -1732,6 +1733,12 @@ function! SpaceVim#welcome() abort
|
||||
elseif exists(':NERDTree') == 2
|
||||
NERDTree
|
||||
wincmd p
|
||||
elseif exists(':NvimTreeOpen') == 2
|
||||
NvimTreeOpen
|
||||
" the statusline of nvimtree is not udpated when open nvim tree in
|
||||
" welcome function
|
||||
doautocmd WinEnter
|
||||
wincmd p
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
@ -84,6 +84,8 @@ function! SpaceVim#layers#core#plugins() abort
|
||||
call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-git',{'merged' : 0, 'loadconf' : 1}])
|
||||
call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-icons',{'merged' : 0}])
|
||||
call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-sftp',{'merged' : 0}])
|
||||
elseif g:spacevim_filemanager ==# 'nvim-tree'
|
||||
call add(plugins, [g:_spacevim_root_dir . 'bundle/nvim-tree.lua',{'merged' : 0, 'loadconf' : 1}])
|
||||
endif
|
||||
|
||||
if !g:spacevim_vimcompatible
|
||||
@ -313,6 +315,11 @@ function! SpaceVim#layers#core#config() abort
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 'T'], 'Defx -no-toggle', 'show-file-tree', 1)
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 'o'], "Defx -no-toggle -search=`expand('%:p')` `stridx(expand('%:p'), getcwd()) < 0? expand('%:p:h'): getcwd()`", 'open-file-tree', 1)
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['b', 't'], 'exe "Defx -no-toggle " . fnameescape(expand("%:p:h"))', 'show-file-tree-at-buffer-dir', 1)
|
||||
elseif g:spacevim_filemanager ==# 'nvim-tree'
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 't'], 'NvimTreeToggle', 'toggle-file-tree', 1)
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 'T'], 'NvimTree', 'show-file-tree', 1)
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 'o'], "NvimTreeFindFile", 'open-file-tree', 1)
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['b', 't'], 'exe "NvimTreeOpen " . fnameescape(expand("%:p:h"))', 'show-file-tree-at-buffer-dir', 1)
|
||||
endif
|
||||
call SpaceVim#mapping#space#def('nnoremap', ['f', 'y'], 'call SpaceVim#util#CopyToClipboard()', 'show-and-copy-buffer-filename', 1)
|
||||
nnoremap <silent> <Plug>YankGitRemoteURL :call SpaceVim#util#CopyToClipboard(2)<Cr>
|
||||
|
@ -425,6 +425,13 @@ function! SpaceVim#layers#core#statusline#get(...) abort
|
||||
\ . ' defx '
|
||||
\ . '%#SpaceVim_statusline_b_SpaceVim_statusline_c#'
|
||||
\ . s:lsep . ' '
|
||||
elseif &filetype ==# 'NvimTree'
|
||||
return '%#SpaceVim_statusline_ia#' . s:winnr(1)
|
||||
\ . '%#SpaceVim_statusline_ia_SpaceVim_statusline_b#' . s:lsep
|
||||
\ . '%#SpaceVim_statusline_b#'
|
||||
\ . ' NvimTree '
|
||||
\ . '%#SpaceVim_statusline_b_SpaceVim_statusline_c#'
|
||||
\ . s:lsep . ' '
|
||||
elseif &filetype ==# 'Fuzzy'
|
||||
return '%#SpaceVim_statusline_a_bold# Fuzzy %#SpaceVim_statusline_a_SpaceVim_statusline_b#' . s:lsep
|
||||
\ . '%#SpaceVim_statusline_b# %{fuzzy#statusline()} %#SpaceVim_statusline_b_SpaceVim_statusline_c#' . s:lsep
|
||||
|
@ -24,7 +24,7 @@ let s:default = {
|
||||
\ 'min_size' : 3,
|
||||
\ 'width' : 1,
|
||||
\ 'right_offset' : 1,
|
||||
\ 'excluded_filetypes' : ['startify', 'leaderf'],
|
||||
\ 'excluded_filetypes' : ['startify', 'leaderf', 'NvimTree'],
|
||||
\ 'shape' : {
|
||||
\ 'head' : '▲',
|
||||
\ 'body' : '█',
|
||||
|
@ -25,5 +25,6 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
|
||||
- [deoplete](https://github.com/Shougo/deoplete.nvim/tree/1c40f648d2b00e70beb4c473b7c0e32b633bd9ae)
|
||||
- [vim-scala@7657218](https://github.com/derekwyatt/vim-scala/tree/7657218f14837395a4e6759f15289bad6febd1b4)
|
||||
- [neosnippet.vim@5973e80](https://github.com/Shougo/neosnippet.vim/tree/5973e801e7ad38a01e888cb794d74e076a35ea9b)
|
||||
- [nvim-tree.lua](https://github.com/kyazdani42/nvim-tree.lua/tree/9049f364cc3ceaff07ab130e1d35aec9e4124563)
|
||||
- [telescope.nvim@39b12d8](https://github.com/nvim-telescope/telescope.nvim/tree/39b12d84e86f5054e2ed98829b367598ae53ab41)
|
||||
- [telescope-ctags-outline.nvim](https://github.com/fcying/telescope-ctags-outline.nvim)
|
||||
|
9
bundle/nvim-tree.lua/.editorconfig
Normal file
9
bundle/nvim-tree.lua/.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
indent_size = 2
|
3
bundle/nvim-tree.lua/.github/FUNDING.yml
vendored
Normal file
3
bundle/nvim-tree.lua/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: kyazdani42
|
71
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
71
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
name: Bug report
|
||||
description: Report a problem with nvim-tree
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting: search [existing issues](https://github.com/kyazdani42/nvim-tree.lua/issues) and make sure that nvim-tree is updated to the latest version. If you are experiencing performance issues, please [enable profiling](https://github.com/kyazdani42/nvim-tree.lua#performance-issues) and attach the logs.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "A short description of the problem you are reporting."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Neovim version"
|
||||
description: "Output of `nvim --version`. Please see nvim-tree.lua [minimum required version](https://github.com/kyazdani42/nvim-tree.lua#notice)."
|
||||
placeholder: |
|
||||
NVIM v0.6.1
|
||||
Build type: Release
|
||||
LuaJIT 2.1.0-beta3
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: "Operating system and version"
|
||||
placeholder: "Linux 5.16.11-arch1-1, macOS 11.5, Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: "nvim-tree version"
|
||||
description: "`cd <your-package-directory>/nvim-tree.lua ; git log --format='%h' -n 1`"
|
||||
placeholder: |
|
||||
nvim-tree branch, commit or tag number
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Minimal config"
|
||||
description: "Minimal(!) configuration necessary to reproduce the issue.
|
||||
|
||||
(Right click) save [nvt-min.lua](https://raw.githubusercontent.com/kyazdani42/nvim-tree.lua/master/.github/ISSUE_TEMPLATE/nvt-min.lua) to `/tmp` and run using `nvim -nu /tmp/nvt-min.lua`
|
||||
|
||||
If _absolutely_ necessary, add plugins and modify the nvim-tree setup at the indicated lines.
|
||||
|
||||
Paste the contents of your `/tmp/nvt-min.lua` here."
|
||||
render: lua
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Steps to reproduce"
|
||||
description: "Steps to reproduce using the minimal config provided below."
|
||||
placeholder: |
|
||||
1. nvim -nu /tmp/nvt-min.lua
|
||||
2. :NvimTreeOpen
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: "A description of the behavior you expected:"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Actual behavior"
|
||||
description: "Observed behavior (may optionally include images, videos or a screencast)."
|
||||
|
20
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
34
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/nvt-min.lua
vendored
Normal file
34
bundle/nvim-tree.lua/.github/ISSUE_TEMPLATE/nvt-min.lua
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
vim.cmd [[set runtimepath=$VIMRUNTIME]]
|
||||
vim.cmd [[set packpath=/tmp/nvt-min/site]]
|
||||
local package_root = "/tmp/nvt-min/site/pack"
|
||||
local install_path = package_root .. "/packer/start/packer.nvim"
|
||||
local function load_plugins()
|
||||
require("packer").startup {
|
||||
{
|
||||
"wbthomason/packer.nvim",
|
||||
"kyazdani42/nvim-tree.lua",
|
||||
"kyazdani42/nvim-web-devicons",
|
||||
-- ADD PLUGINS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
|
||||
},
|
||||
config = {
|
||||
package_root = package_root,
|
||||
compile_path = install_path .. "/plugin/packer_compiled.lua",
|
||||
display = { non_interactive = true },
|
||||
},
|
||||
}
|
||||
end
|
||||
if vim.fn.isdirectory(install_path) == 0 then
|
||||
print "Installing nvim-tree and dependencies."
|
||||
vim.fn.system { "git", "clone", "--depth=1", "https://github.com/wbthomason/packer.nvim", install_path }
|
||||
end
|
||||
load_plugins()
|
||||
require("packer").sync()
|
||||
vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua setup()]]
|
||||
vim.opt.termguicolors = true
|
||||
vim.opt.cursorline = true
|
||||
|
||||
-- MODIFY NVIM-TREE SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
|
||||
_G.setup = function()
|
||||
require("nvim-tree").setup {}
|
||||
end
|
||||
|
BIN
bundle/nvim-tree.lua/.github/screenshot.png
vendored
Normal file
BIN
bundle/nvim-tree.lua/.github/screenshot.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 242 KiB |
BIN
bundle/nvim-tree.lua/.github/screenshot2.png
vendored
Normal file
BIN
bundle/nvim-tree.lua/.github/screenshot2.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 615 KiB |
BIN
bundle/nvim-tree.lua/.github/screenshot3.png
vendored
Normal file
BIN
bundle/nvim-tree.lua/.github/screenshot3.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
BIN
bundle/nvim-tree.lua/.github/screenshot4.png
vendored
Normal file
BIN
bundle/nvim-tree.lua/.github/screenshot4.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 565 KiB |
34
bundle/nvim-tree.lua/.github/workflows/ci.yml
vendored
Normal file
34
bundle/nvim-tree.lua/.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
luacheck:
|
||||
name: luacheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo add-apt-repository universe
|
||||
sudo apt install luarocks -y
|
||||
sudo luarocks install luacheck
|
||||
- name: Run luacheck
|
||||
run: luacheck .
|
||||
stylua:
|
||||
name: stylua
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: JohnnyMorganz/stylua-action@1.0.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --color always --check lua/
|
4
bundle/nvim-tree.lua/.hooks/pre-commit.sh
Normal file
4
bundle/nvim-tree.lua/.hooks/pre-commit.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
stylua . --check || exit 1
|
||||
luacheck . || exit 1
|
14
bundle/nvim-tree.lua/.luacheckrc
Normal file
14
bundle/nvim-tree.lua/.luacheckrc
Normal file
@ -0,0 +1,14 @@
|
||||
-- vim: ft=lua tw=80
|
||||
|
||||
-- Don't report unused self arguments of methods.
|
||||
self = false
|
||||
|
||||
ignore = {
|
||||
"631", -- max_line_length
|
||||
}
|
||||
|
||||
-- Global objects defined by the C code
|
||||
globals = {
|
||||
"vim",
|
||||
"TreeExplorer"
|
||||
}
|
6
bundle/nvim-tree.lua/.stylua.toml
Normal file
6
bundle/nvim-tree.lua/.stylua.toml
Normal file
@ -0,0 +1,6 @@
|
||||
column_width = 120
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferDouble"
|
||||
call_parentheses = "None"
|
24
bundle/nvim-tree.lua/CONTRIBUTING.md
Normal file
24
bundle/nvim-tree.lua/CONTRIBUTING.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Contributing to `nvim-tree.lua`
|
||||
|
||||
Thank you for contributing.
|
||||
|
||||
## Styling and formatting
|
||||
|
||||
Code is formatted using luacheck, and linted using stylua.
|
||||
You can install these with:
|
||||
|
||||
```bash
|
||||
luarocks install luacheck
|
||||
cargo install stylua
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
## Documentation
|
||||
|
||||
When adding new options, you should declare the defaults in the main `nvim-tree.lua` file.
|
||||
Once you did, you should run the `update-default-opts.sh` script which will update the default documentation in the README and the help file.
|
||||
|
||||
Documentation for options should also be added, see how this is done after `nvim-tree.disable_netrw` in the `nvim-tree-lua.txt` file.
|
15
bundle/nvim-tree.lua/LICENSE
Normal file
15
bundle/nvim-tree.lua/LICENSE
Normal file
@ -0,0 +1,15 @@
|
||||
nvim-tree.lua is a file explorer / filesystem tree view plugin for neovim
|
||||
Copyright © 2019 Yazdani Kiyan
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
391
bundle/nvim-tree.lua/README.md
Normal file
391
bundle/nvim-tree.lua/README.md
Normal file
@ -0,0 +1,391 @@
|
||||
# A File Explorer For Neovim Written In Lua
|
||||
|
||||
[](https://github.com/kyazdani42/nvim-tree.lua/actions/workflows/ci.yml)
|
||||
|
||||
## Notice
|
||||
|
||||
This plugin requires [neovim >=0.6.0](https://github.com/neovim/neovim/wiki/Installing-Neovim).
|
||||
|
||||
If you have issues since the recent setup migration, check out [this guide](https://github.com/kyazdani42/nvim-tree.lua/issues/674)
|
||||
|
||||
## Install
|
||||
|
||||
Install with [vim-plug](https://github.com/junegunn/vim-plug):
|
||||
|
||||
```vim
|
||||
" requires
|
||||
Plug 'kyazdani42/nvim-web-devicons' " for file icons
|
||||
Plug 'kyazdani42/nvim-tree.lua'
|
||||
```
|
||||
|
||||
Install with [packer](https://github.com/wbthomason/packer.nvim):
|
||||
|
||||
```lua
|
||||
use {
|
||||
'kyazdani42/nvim-tree.lua',
|
||||
requires = {
|
||||
'kyazdani42/nvim-web-devicons', -- optional, for file icon
|
||||
},
|
||||
tag = 'nightly' -- optional, updated every week. (see issue #1193)
|
||||
}
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Options are currently being migrated into the setup function, you need to run `require'nvim-tree'.setup()` in your personal configurations.
|
||||
Setup should be run in a lua file or in a lua heredoc (`:help lua-heredoc`) if using in a vim file.
|
||||
Note that options under the `g:` command should be set **BEFORE** running the setup function.
|
||||
These are being migrated to the setup function incrementally, check [this issue](https://github.com/kyazdani42/nvim-tree.lua/issues/674) if you encounter any problems related to configs not working after update.
|
||||
```vim
|
||||
" vimrc
|
||||
let g:nvim_tree_git_hl = 1 "0 by default, will enable file highlight for git attributes (can be used without the icons).
|
||||
let g:nvim_tree_highlight_opened_files = 1 "0 by default, will enable folder and file icon highlight for opened files/directories.
|
||||
let g:nvim_tree_root_folder_modifier = ':~' "This is the default. See :help filename-modifiers for more options
|
||||
let g:nvim_tree_add_trailing = 1 "0 by default, append a trailing slash to folder names
|
||||
let g:nvim_tree_group_empty = 1 " 0 by default, compact folders that only contain a single folder into one node in the file tree
|
||||
let g:nvim_tree_icon_padding = ' ' "one space by default, used for rendering the space between the icon and the filename. Use with caution, it could break rendering if you set an empty string depending on your font.
|
||||
let g:nvim_tree_symlink_arrow = ' >> ' " defaults to ' ➛ '. used as a separator between symlinks' source and target.
|
||||
let g:nvim_tree_respect_buf_cwd = 1 "0 by default, will change cwd of nvim-tree to that of new buffer's when opening nvim-tree.
|
||||
let g:nvim_tree_create_in_closed_folder = 1 "0 by default, When creating files, sets the path of a file when cursor is on a closed folder to the parent folder when 0, and inside the folder when 1.
|
||||
let g:nvim_tree_special_files = { 'README.md': 1, 'Makefile': 1, 'MAKEFILE': 1 } " List of filenames that gets highlighted with NvimTreeSpecialFile
|
||||
let g:nvim_tree_show_icons = {
|
||||
\ 'git': 1,
|
||||
\ 'folders': 0,
|
||||
\ 'files': 0,
|
||||
\ 'folder_arrows': 0,
|
||||
\ }
|
||||
"If 0, do not show the icons for one of 'git' 'folder' and 'files'
|
||||
"1 by default, notice that if 'files' is 1, it will only display
|
||||
"if nvim-web-devicons is installed and on your runtimepath.
|
||||
"if folder is 1, you can also tell folder_arrows 1 to show small arrows next to the folder icons.
|
||||
"but this will not work when you set renderer.indent_markers.enable (because of UI conflict)
|
||||
|
||||
" default will show icon by default if no icon is provided
|
||||
" default shows no icon by default
|
||||
let g:nvim_tree_icons = {
|
||||
\ 'default': "",
|
||||
\ 'symlink': "",
|
||||
\ 'git': {
|
||||
\ 'unstaged': "✗",
|
||||
\ 'staged': "✓",
|
||||
\ 'unmerged': "",
|
||||
\ 'renamed': "➜",
|
||||
\ 'untracked': "★",
|
||||
\ 'deleted': "",
|
||||
\ 'ignored': "◌"
|
||||
\ },
|
||||
\ 'folder': {
|
||||
\ 'arrow_open': "",
|
||||
\ 'arrow_closed': "",
|
||||
\ 'default': "",
|
||||
\ 'open': "",
|
||||
\ 'empty': "",
|
||||
\ 'empty_open': "",
|
||||
\ 'symlink': "",
|
||||
\ 'symlink_open': "",
|
||||
\ }
|
||||
\ }
|
||||
|
||||
nnoremap <C-n> :NvimTreeToggle<CR>
|
||||
nnoremap <leader>r :NvimTreeRefresh<CR>
|
||||
nnoremap <leader>n :NvimTreeFindFile<CR>
|
||||
" More available functions:
|
||||
" NvimTreeOpen
|
||||
" NvimTreeClose
|
||||
" NvimTreeFocus
|
||||
" NvimTreeFindFileToggle
|
||||
" NvimTreeResize
|
||||
" NvimTreeCollapse
|
||||
" NvimTreeCollapseKeepBuffers
|
||||
|
||||
set termguicolors " this variable must be enabled for colors to be applied properly
|
||||
|
||||
" a list of groups can be found at `:help nvim_tree_highlight`
|
||||
highlight NvimTreeFolderIcon guibg=blue
|
||||
```
|
||||
|
||||
```lua
|
||||
-- init.lua
|
||||
|
||||
-- empty setup using defaults: add your own options
|
||||
require'nvim-tree'.setup {
|
||||
}
|
||||
|
||||
-- OR
|
||||
|
||||
-- setup with all defaults
|
||||
-- each of these are documented in `:help nvim-tree.OPTION_NAME`
|
||||
require'nvim-tree'.setup { -- BEGIN_DEFAULT_OPTS
|
||||
auto_reload_on_write = true,
|
||||
disable_netrw = false,
|
||||
hijack_cursor = false,
|
||||
hijack_netrw = true,
|
||||
hijack_unnamed_buffer_when_opening = false,
|
||||
ignore_buffer_on_setup = false,
|
||||
open_on_setup = false,
|
||||
open_on_setup_file = false,
|
||||
open_on_tab = false,
|
||||
sort_by = "name",
|
||||
update_cwd = false,
|
||||
view = {
|
||||
width = 30,
|
||||
height = 30,
|
||||
hide_root_folder = false,
|
||||
side = "left",
|
||||
preserve_window_proportions = false,
|
||||
number = false,
|
||||
relativenumber = false,
|
||||
signcolumn = "yes",
|
||||
mappings = {
|
||||
custom_only = false,
|
||||
list = {
|
||||
-- user mappings go here
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
indent_markers = {
|
||||
enable = false,
|
||||
icons = {
|
||||
corner = "└ ",
|
||||
edge = "│ ",
|
||||
none = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
webdev_colors = true,
|
||||
git_placement = "before",
|
||||
}
|
||||
},
|
||||
hijack_directories = {
|
||||
enable = true,
|
||||
auto_open = true,
|
||||
},
|
||||
update_focused_file = {
|
||||
enable = false,
|
||||
update_cwd = false,
|
||||
ignore_list = {},
|
||||
},
|
||||
ignore_ft_on_setup = {},
|
||||
system_open = {
|
||||
cmd = "",
|
||||
args = {},
|
||||
},
|
||||
diagnostics = {
|
||||
enable = false,
|
||||
show_on_dirs = false,
|
||||
icons = {
|
||||
hint = "",
|
||||
info = "",
|
||||
warning = "",
|
||||
error = "",
|
||||
},
|
||||
},
|
||||
filters = {
|
||||
dotfiles = false,
|
||||
custom = {},
|
||||
exclude = {},
|
||||
},
|
||||
git = {
|
||||
enable = true,
|
||||
ignore = true,
|
||||
timeout = 400,
|
||||
},
|
||||
actions = {
|
||||
use_system_clipboard = true,
|
||||
change_dir = {
|
||||
enable = true,
|
||||
global = false,
|
||||
restrict_above_cwd = false,
|
||||
},
|
||||
open_file = {
|
||||
quit_on_open = false,
|
||||
resize_window = false,
|
||||
window_picker = {
|
||||
enable = true,
|
||||
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
|
||||
exclude = {
|
||||
filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" },
|
||||
buftype = { "nofile", "terminal", "help" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
trash = {
|
||||
cmd = "trash",
|
||||
require_confirm = true,
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
truncate = false,
|
||||
types = {
|
||||
all = false,
|
||||
config = false,
|
||||
copy_paste = false,
|
||||
diagnostics = false,
|
||||
git = false,
|
||||
profile = false,
|
||||
},
|
||||
},
|
||||
} -- END_DEFAULT_OPTS
|
||||
```
|
||||
|
||||
## Key Bindings
|
||||
|
||||
### Default actions
|
||||
|
||||
- `<CR>` or `o` on the root folder will cd in the above directory
|
||||
- `<C-]>` will cd in the directory under the cursor
|
||||
- `<BS>` will close current opened directory or parent
|
||||
- type `a` to add a file. Adding a directory requires leaving a leading `/` at the end of the path.
|
||||
> you can add multiple directories by doing foo/bar/baz/f and it will add foo bar and baz directories and f as a file
|
||||
- type `r` to rename a file
|
||||
- type `<C-r>` to rename a file and omit the filename on input
|
||||
- type `x` to add/remove file/directory to cut clipboard
|
||||
- type `c` to add/remove file/directory to copy clipboard
|
||||
- type `y` will copy name to system clipboard
|
||||
- type `Y` will copy relative path to system clipboard
|
||||
- type `gy` will copy absolute path to system clipboard
|
||||
- type `p` to paste from clipboard. Cut clipboard has precedence over copy (will prompt for confirmation)
|
||||
- type `d` to delete a file (will prompt for confirmation)
|
||||
- type `D` to trash a file (configured in setup())
|
||||
- type `]c` to go to next git item
|
||||
- type `[c` to go to prev git item
|
||||
- type `-` to navigate up to the parent directory of the current file/directory
|
||||
- type `s` to open a file with default system application or a folder with default file manager (if you want to change the command used to do it see `:h nvim-tree.setup` under `system_open`)
|
||||
- if the file is a directory, `<CR>` will open the directory otherwise it will open the file in the buffer near the tree
|
||||
- if the file is a symlink, `<CR>` will follow the symlink (if the target is a file)
|
||||
- `<C-v>` will open the file in a vertical split
|
||||
- `<C-x>` will open the file in a horizontal split
|
||||
- `<C-t>` will open the file in a new tab
|
||||
- `<Tab>` will open the file as a preview (keeps the cursor in the tree)
|
||||
- `I` will toggle visibility of hidden folders / files
|
||||
- `H` will toggle visibility of dotfiles (files/folders starting with a `.`)
|
||||
- `R` will refresh the tree
|
||||
- Double left click acts like `<CR>`
|
||||
- Double right click acts like `<C-]>`
|
||||
- `W` will collapse the whole tree
|
||||
- `S` will prompt the user to enter a path and then expands the tree to match the path
|
||||
- `.` will enter vim command mode with the file the cursor is on
|
||||
- `C-k` will toggle a popup with file infos about the file under the cursor
|
||||
|
||||
### Settings
|
||||
|
||||
The `list` option in `view.mappings.list` is a table of
|
||||
```lua
|
||||
-- key can be either a string or a table of string (lhs)
|
||||
-- action is the name of the action, set to `""` to remove default action
|
||||
-- action_cb is the function that will be called, it receives the node as a parameter. Optional for default actions
|
||||
-- mode is normal by default
|
||||
|
||||
local tree_cb = require'nvim-tree.config'.nvim_tree_callback
|
||||
|
||||
local function print_node_path(node) {
|
||||
print(node.absolute_path)
|
||||
}
|
||||
|
||||
local list = {
|
||||
{ key = {"<CR>", "o" }, action = "edit", mode = "n"},
|
||||
{ key = "p", action = "print_path", action_cb = print_node_path },
|
||||
{ key = "s", cb = tree_cb("vsplit") }, --tree_cb and the cb property are deprecated
|
||||
{ key = "<2-RightMouse>", action = "" }, -- will remove default cd action
|
||||
}
|
||||
```
|
||||
|
||||
These are the default bindings:
|
||||
```lua
|
||||
|
||||
-- default mappings
|
||||
local list = {
|
||||
{ key = {"<CR>", "o", "<2-LeftMouse>"}, action = "edit" },
|
||||
{ key = "<C-e>", action = "edit_in_place" },
|
||||
{ key = {"O"}, action = "edit_no_picker" },
|
||||
{ key = {"<2-RightMouse>", "<C-]>"}, action = "cd" },
|
||||
{ key = "<C-v>", action = "vsplit" },
|
||||
{ key = "<C-x>", action = "split" },
|
||||
{ key = "<C-t>", action = "tabnew" },
|
||||
{ key = "<", action = "prev_sibling" },
|
||||
{ key = ">", action = "next_sibling" },
|
||||
{ key = "P", action = "parent_node" },
|
||||
{ key = "<BS>", action = "close_node" },
|
||||
{ key = "<Tab>", action = "preview" },
|
||||
{ key = "K", action = "first_sibling" },
|
||||
{ key = "J", action = "last_sibling" },
|
||||
{ key = "I", action = "toggle_git_ignored" },
|
||||
{ key = "H", action = "toggle_dotfiles" },
|
||||
{ key = "R", action = "refresh" },
|
||||
{ key = "a", action = "create" },
|
||||
{ key = "d", action = "remove" },
|
||||
{ key = "D", action = "trash" },
|
||||
{ key = "r", action = "rename" },
|
||||
{ key = "<C-r>", action = "full_rename" },
|
||||
{ key = "x", action = "cut" },
|
||||
{ key = "c", action = "copy" },
|
||||
{ key = "p", action = "paste" },
|
||||
{ key = "y", action = "copy_name" },
|
||||
{ key = "Y", action = "copy_path" },
|
||||
{ key = "gy", action = "copy_absolute_path" },
|
||||
{ key = "[c", action = "prev_git_item" },
|
||||
{ key = "]c", action = "next_git_item" },
|
||||
{ key = "-", action = "dir_up" },
|
||||
{ key = "s", action = "system_open" },
|
||||
{ key = "q", action = "close" },
|
||||
{ key = "g?", action = "toggle_help" },
|
||||
{ key = "W", action = "collapse_all" },
|
||||
{ key = "S", action = "search_node" },
|
||||
{ key = "<C-k>", action = "toggle_file_info" },
|
||||
{ key = ".", action = "run_file_command" }
|
||||
}
|
||||
```
|
||||
|
||||
You can toggle the help UI by pressing `g?`.
|
||||
|
||||
## Tips & reminders
|
||||
|
||||
1. You can add a directory by adding a `/` at the end of the paths, entering multiple directories `BASE/foo/bar/baz` will add directory foo, then bar and add a file baz to it.
|
||||
2. You can update window options for the tree by setting `require"nvim-tree.view".View.winopts.MY_OPTION = MY_OPTION_VALUE`
|
||||
3. `toggle` has a second parameter which allows to toggle without focusing the explorer (`require"nvim-tree".toggle(false, true)`).
|
||||
4. You can allow nvim-tree to behave like vinegar (see `:help nvim-tree-vinegar`).
|
||||
5. If you `:set nosplitright`, the files will open on the left side of the tree, placing the tree window in the right side of the file you opened.
|
||||
6. You can automatically close the tab/vim when nvim-tree is the last window in the tab. WARNING: other plugins or automation may interfere with this:
|
||||
```vim
|
||||
autocmd BufEnter * ++nested if winnr('$') == 1 && bufname() == 'NvimTree_' . tabpagenr() | quit | endif
|
||||
```
|
||||
|
||||
## Diagnostic Logging
|
||||
|
||||
You may enable diagnostic logging to `$XDG_CACHE_HOME/nvim/nvim-tree.log`. See `:help nvim-tree.log`.
|
||||
|
||||
## Performance Issues
|
||||
|
||||
If you are experiencing performance issues with nvim-tree.lua, you can enable profiling in the logs. It is advisable to enable git logging at the same time, as that can be a source of performance problems.
|
||||
|
||||
```lua
|
||||
log = {
|
||||
enable = true,
|
||||
truncate = true,
|
||||
types = {
|
||||
git = true,
|
||||
profile = true,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
Please attach `$XDG_CACHE_HOME/nvim/nvim-tree.log` if you raise an issue.
|
||||
|
||||
*Performance Tips:*
|
||||
|
||||
* If you are using fish as an editor shell (which might be fixed in the future), try set `shell=/bin/bash` in your vim config.
|
||||
|
||||
* Try manually running the git command (see the logs) in your shell e.g. `git --no-optional-locks status --porcelain=v1 --ignored=matching -u`.
|
||||
|
||||
* Huge git repositories may timeout after the default `git.timeout` of 400ms. Try increasing that in your setup if you see `[git] job timed out` in the logs.
|
||||
|
||||
* Try temporarily disabling git integration by setting `git.enable = false` in your setup.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
1
bundle/nvim-tree.lua/doc/.gitignore
vendored
Normal file
1
bundle/nvim-tree.lua/doc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
tags
|
1045
bundle/nvim-tree.lua/doc/nvim-tree-lua.txt
Normal file
1045
bundle/nvim-tree.lua/doc/nvim-tree-lua.txt
Normal file
File diff suppressed because it is too large
Load Diff
519
bundle/nvim-tree.lua/lua/nvim-tree.lua
Normal file
519
bundle/nvim-tree.lua/lua/nvim-tree.lua
Normal file
@ -0,0 +1,519 @@
|
||||
local luv = vim.loop
|
||||
local api = vim.api
|
||||
|
||||
local lib = require "nvim-tree.lib"
|
||||
local log = require "nvim-tree.log"
|
||||
local colors = require "nvim-tree.colors"
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local change_dir = require "nvim-tree.actions.change-dir"
|
||||
local legacy = require "nvim-tree.legacy"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local _config = {}
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.focus()
|
||||
M.open()
|
||||
view.focus()
|
||||
end
|
||||
|
||||
---@deprecated
|
||||
M.on_keypress = require("nvim-tree.actions").on_keypress
|
||||
|
||||
function M.toggle(find_file, no_focus)
|
||||
if view.is_visible() then
|
||||
view.close()
|
||||
else
|
||||
local previous_buf = api.nvim_get_current_buf()
|
||||
M.open()
|
||||
if _config.update_focused_file.enable or find_file then
|
||||
M.find_file(false, previous_buf)
|
||||
end
|
||||
if no_focus then
|
||||
vim.cmd "noautocmd wincmd p"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.open(cwd)
|
||||
cwd = cwd ~= "" and cwd or nil
|
||||
if view.is_visible() then
|
||||
lib.set_target_win()
|
||||
view.focus()
|
||||
else
|
||||
lib.open(cwd)
|
||||
end
|
||||
end
|
||||
|
||||
function M.open_replacing_current_buffer()
|
||||
if view.is_visible() then
|
||||
return
|
||||
end
|
||||
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(buf)
|
||||
if bufname == "" or vim.loop.fs_stat(bufname) == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local cwd = vim.fn.fnamemodify(bufname, ":p:h")
|
||||
if not core.get_explorer() or cwd ~= core.get_cwd() then
|
||||
core.init(cwd)
|
||||
end
|
||||
view.open_in_current_win { hijack_current_buf = false, resize = false }
|
||||
require("nvim-tree.renderer").draw()
|
||||
require("nvim-tree.actions.find-file").fn(bufname)
|
||||
end
|
||||
|
||||
function M.tab_change()
|
||||
if view.is_visible { any_tabpage = true } then
|
||||
local bufname = vim.api.nvim_buf_get_name(0)
|
||||
if bufname:match "Neogit" ~= nil or bufname:match "--graph" ~= nil then
|
||||
return
|
||||
end
|
||||
view.open { focus_tree = false }
|
||||
require("nvim-tree.renderer").draw()
|
||||
end
|
||||
end
|
||||
|
||||
local function find_existing_windows()
|
||||
return vim.tbl_filter(function(win)
|
||||
local buf = api.nvim_win_get_buf(win)
|
||||
return api.nvim_buf_get_name(buf):match "NvimTree" ~= nil
|
||||
end, api.nvim_list_wins())
|
||||
end
|
||||
|
||||
local function is_file_readable(fname)
|
||||
local stat = luv.fs_stat(fname)
|
||||
return stat and stat.type == "file" and luv.fs_access(fname, "R")
|
||||
end
|
||||
|
||||
local function update_base_dir_with_filepath(filepath, bufnr)
|
||||
local ft = api.nvim_buf_get_option(bufnr, "filetype") or ""
|
||||
for _, value in pairs(_config.update_focused_file.ignore_list) do
|
||||
if utils.str_find(filepath, value) or utils.str_find(ft, value) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not vim.startswith(filepath, core.get_explorer().cwd) then
|
||||
change_dir.fn(vim.fn.fnamemodify(filepath, ":p:h"))
|
||||
end
|
||||
end
|
||||
|
||||
function M.find_file(with_open, bufnr)
|
||||
if not with_open and not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
local filepath = utils.canonical_path(vim.fn.fnamemodify(bufname, ":p"))
|
||||
if not is_file_readable(filepath) then
|
||||
return
|
||||
end
|
||||
|
||||
if with_open then
|
||||
M.open()
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
-- if we don't schedule, it will search for NvimTree
|
||||
if _config.update_focused_file.update_cwd then
|
||||
update_base_dir_with_filepath(filepath, bufnr)
|
||||
end
|
||||
require("nvim-tree.actions.find-file").fn(filepath)
|
||||
end)
|
||||
end
|
||||
|
||||
M.resize = view.resize
|
||||
|
||||
function M.open_on_directory()
|
||||
local should_proceed = M.initialized and (_config.hijack_directories.auto_open or view.is_visible())
|
||||
if not should_proceed then
|
||||
return
|
||||
end
|
||||
|
||||
local buf = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(buf)
|
||||
if vim.fn.isdirectory(bufname) ~= 1 then
|
||||
return
|
||||
end
|
||||
|
||||
change_dir.force_dirchange(bufname, true)
|
||||
end
|
||||
|
||||
function M.reset_highlight()
|
||||
colors.setup()
|
||||
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
|
||||
return
|
||||
end
|
||||
prev_line = l
|
||||
|
||||
local node = lib.get_node_at_cursor()
|
||||
if not node or node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
local line = api.nvim_get_current_line()
|
||||
local cursor = api.nvim_win_get_cursor(0)
|
||||
local idx = vim.fn.stridx(line, node.name)
|
||||
|
||||
if idx >= 0 then
|
||||
api.nvim_win_set_cursor(0, { cursor[1], idx })
|
||||
end
|
||||
end
|
||||
|
||||
function M.on_enter(netrw_disabled)
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
local buftype = api.nvim_buf_get_option(bufnr, "filetype")
|
||||
local ft_ignore = _config.ignore_ft_on_setup
|
||||
|
||||
local stats = luv.fs_stat(bufname)
|
||||
local is_dir = stats and stats.type == "directory"
|
||||
local is_file = stats and stats.type == "file"
|
||||
local cwd
|
||||
if is_dir then
|
||||
cwd = vim.fn.expand(bufname)
|
||||
-- INFO: could potentially conflict with rooter plugins
|
||||
vim.cmd("noautocmd cd " .. cwd)
|
||||
end
|
||||
|
||||
local lines = not is_dir and api.nvim_buf_get_lines(bufnr, 0, -1, false) or {}
|
||||
local buf_has_content = #lines > 1 or (#lines == 1 and lines[1] ~= "")
|
||||
|
||||
local buf_is_dir = is_dir and netrw_disabled
|
||||
local buf_is_empty = bufname == "" and not buf_has_content
|
||||
local should_be_preserved = vim.tbl_contains(ft_ignore, buftype)
|
||||
|
||||
local should_open = false
|
||||
local should_focus_other_window = false
|
||||
local should_find = false
|
||||
if (_config.open_on_setup or _config.open_on_setup_file) and not should_be_preserved then
|
||||
if buf_is_dir or buf_is_empty then
|
||||
should_open = true
|
||||
elseif is_file and _config.open_on_setup_file then
|
||||
should_open = true
|
||||
should_focus_other_window = true
|
||||
should_find = _config.update_focused_file.enable
|
||||
elseif _config.ignore_buffer_on_setup then
|
||||
should_open = true
|
||||
should_focus_other_window = true
|
||||
end
|
||||
end
|
||||
|
||||
local should_hijack = _config.hijack_directories.enable
|
||||
and _config.hijack_directories.auto_open
|
||||
and is_dir
|
||||
and not should_be_preserved
|
||||
|
||||
-- Session that left a NvimTree Buffer opened, reopen with it
|
||||
local existing_tree_wins = find_existing_windows()
|
||||
if existing_tree_wins[1] then
|
||||
api.nvim_set_current_win(existing_tree_wins[1])
|
||||
end
|
||||
|
||||
if should_open or should_hijack or existing_tree_wins[1] ~= nil then
|
||||
lib.open(cwd)
|
||||
|
||||
if should_focus_other_window then
|
||||
vim.cmd "noautocmd wincmd p"
|
||||
if should_find then
|
||||
M.find_file(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
M.initialized = true
|
||||
end
|
||||
|
||||
function M.get_config()
|
||||
return M.config
|
||||
end
|
||||
|
||||
local function manage_netrw(disable_netrw, hijack_netrw)
|
||||
if hijack_netrw then
|
||||
vim.cmd "silent! autocmd! FileExplorer *"
|
||||
vim.cmd "autocmd VimEnter * ++once silent! autocmd! FileExplorer *"
|
||||
end
|
||||
if disable_netrw then
|
||||
vim.g.loaded_netrw = 1
|
||||
vim.g.loaded_netrwPlugin = 1
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_vim_commands()
|
||||
vim.cmd [[
|
||||
command! -nargs=? -complete=dir NvimTreeOpen lua require'nvim-tree'.open("<args>")
|
||||
command! NvimTreeClose lua require'nvim-tree.view'.close()
|
||||
command! NvimTreeToggle lua require'nvim-tree'.toggle(false)
|
||||
command! NvimTreeFocus lua require'nvim-tree'.focus()
|
||||
command! NvimTreeRefresh lua require'nvim-tree.actions.reloaders'.reload_explorer()
|
||||
command! NvimTreeClipboard lua require'nvim-tree.actions.copy-paste'.print_clipboard()
|
||||
command! NvimTreeFindFile lua require'nvim-tree'.find_file(true)
|
||||
command! NvimTreeFindFileToggle lua require'nvim-tree'.toggle(true)
|
||||
command! -nargs=1 NvimTreeResize lua require'nvim-tree'.resize("<args>")
|
||||
command! NvimTreeCollapse lua require'nvim-tree.actions.collapse-all'.fn()
|
||||
command! NvimTreeCollapseKeepBuffers lua require'nvim-tree.actions.collapse-all'.fn(true)
|
||||
]]
|
||||
end
|
||||
|
||||
function M.change_dir(name)
|
||||
change_dir.fn(name)
|
||||
|
||||
if _config.update_focused_file.enable then
|
||||
M.find_file(false)
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_autocommands(opts)
|
||||
vim.cmd "augroup NvimTree"
|
||||
vim.cmd "autocmd!"
|
||||
|
||||
-- reset highlights when colorscheme is changed
|
||||
vim.cmd "au ColorScheme * lua require'nvim-tree'.reset_highlight()"
|
||||
if opts.auto_reload_on_write then
|
||||
vim.cmd "au BufWritePost * lua require'nvim-tree.actions.reloaders'.reload_explorer()"
|
||||
end
|
||||
vim.cmd "au User FugitiveChanged,NeogitStatusRefreshed lua require'nvim-tree.actions.reloaders'.reload_git()"
|
||||
|
||||
if opts.open_on_tab then
|
||||
vim.cmd "au TabEnter * lua require'nvim-tree'.tab_change()"
|
||||
end
|
||||
if opts.hijack_cursor then
|
||||
vim.cmd "au CursorMoved NvimTree_* lua require'nvim-tree'.place_cursor_on_node()"
|
||||
end
|
||||
if opts.update_cwd then
|
||||
vim.cmd "au DirChanged * lua require'nvim-tree'.change_dir(vim.loop.cwd())"
|
||||
end
|
||||
if opts.update_focused_file.enable then
|
||||
vim.cmd "au BufEnter * lua require'nvim-tree'.find_file(false)"
|
||||
end
|
||||
|
||||
if not opts.actions.open_file.quit_on_open then
|
||||
vim.cmd "au BufWipeout NvimTree_* lua require'nvim-tree.view'._prevent_buffer_override()"
|
||||
else
|
||||
vim.cmd "au BufWipeout NvimTree_* lua require'nvim-tree.view'.abandon_current_window()"
|
||||
end
|
||||
|
||||
if opts.hijack_directories.enable then
|
||||
vim.cmd "au BufEnter,BufNewFile * lua require'nvim-tree'.open_on_directory()"
|
||||
end
|
||||
|
||||
vim.cmd "augroup end"
|
||||
end
|
||||
|
||||
local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
|
||||
auto_reload_on_write = true,
|
||||
disable_netrw = false,
|
||||
hijack_cursor = false,
|
||||
hijack_netrw = true,
|
||||
hijack_unnamed_buffer_when_opening = false,
|
||||
ignore_buffer_on_setup = false,
|
||||
open_on_setup = false,
|
||||
open_on_setup_file = false,
|
||||
open_on_tab = false,
|
||||
sort_by = "name",
|
||||
update_cwd = false,
|
||||
view = {
|
||||
width = 30,
|
||||
height = 30,
|
||||
hide_root_folder = false,
|
||||
side = "left",
|
||||
preserve_window_proportions = false,
|
||||
number = false,
|
||||
relativenumber = false,
|
||||
signcolumn = "yes",
|
||||
mappings = {
|
||||
custom_only = false,
|
||||
list = {
|
||||
-- user mappings go here
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer = {
|
||||
indent_markers = {
|
||||
enable = false,
|
||||
icons = {
|
||||
corner = "└ ",
|
||||
edge = "│ ",
|
||||
none = " ",
|
||||
},
|
||||
},
|
||||
icons = {
|
||||
webdev_colors = true,
|
||||
git_placement = "before",
|
||||
},
|
||||
},
|
||||
hijack_directories = {
|
||||
enable = true,
|
||||
auto_open = true,
|
||||
},
|
||||
update_focused_file = {
|
||||
enable = false,
|
||||
update_cwd = false,
|
||||
ignore_list = {},
|
||||
},
|
||||
ignore_ft_on_setup = {},
|
||||
system_open = {
|
||||
cmd = "",
|
||||
args = {},
|
||||
},
|
||||
diagnostics = {
|
||||
enable = false,
|
||||
show_on_dirs = false,
|
||||
icons = {
|
||||
hint = "",
|
||||
info = "",
|
||||
warning = "",
|
||||
error = "",
|
||||
},
|
||||
},
|
||||
filters = {
|
||||
dotfiles = false,
|
||||
custom = {},
|
||||
exclude = {},
|
||||
},
|
||||
git = {
|
||||
enable = true,
|
||||
ignore = true,
|
||||
timeout = 400,
|
||||
},
|
||||
actions = {
|
||||
use_system_clipboard = true,
|
||||
change_dir = {
|
||||
enable = true,
|
||||
global = false,
|
||||
restrict_above_cwd = false,
|
||||
},
|
||||
open_file = {
|
||||
quit_on_open = false,
|
||||
resize_window = false,
|
||||
window_picker = {
|
||||
enable = true,
|
||||
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
|
||||
exclude = {
|
||||
filetype = { "notify", "packer", "qf", "diff", "fugitive", "fugitiveblame" },
|
||||
buftype = { "nofile", "terminal", "help" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
trash = {
|
||||
cmd = "trash",
|
||||
require_confirm = true,
|
||||
},
|
||||
log = {
|
||||
enable = false,
|
||||
truncate = false,
|
||||
types = {
|
||||
all = false,
|
||||
config = false,
|
||||
copy_paste = false,
|
||||
diagnostics = false,
|
||||
git = false,
|
||||
profile = false,
|
||||
},
|
||||
},
|
||||
} -- END_DEFAULT_OPTS
|
||||
|
||||
local function merge_options(conf)
|
||||
return vim.tbl_deep_extend("force", DEFAULT_OPTS, conf or {})
|
||||
end
|
||||
|
||||
local FIELD_OVERRIDE_TYPECHECK = {
|
||||
width = { string = true, ["function"] = true, number = true },
|
||||
height = { string = true, ["function"] = true, number = true },
|
||||
}
|
||||
|
||||
local function validate_options(conf)
|
||||
local msg
|
||||
|
||||
local function validate(user, def, prefix)
|
||||
-- only compare tables with contents that are not integer indexed
|
||||
if type(user) ~= "table" or type(def) ~= "table" or not next(def) or type(next(def)) == "number" then
|
||||
return
|
||||
end
|
||||
|
||||
for k, v in pairs(user) do
|
||||
local invalid
|
||||
local override_typecheck = FIELD_OVERRIDE_TYPECHECK[k] or {}
|
||||
if def[k] == nil then
|
||||
-- option does not exist
|
||||
invalid = string.format("unknown option: %s%s", prefix, k)
|
||||
elseif type(v) ~= type(def[k]) and not override_typecheck[type(v)] then
|
||||
-- option is of the wrong type and is not a function
|
||||
invalid = string.format("invalid option: %s%s expected: %s actual: %s", prefix, k, type(def[k]), type(v))
|
||||
end
|
||||
|
||||
if invalid then
|
||||
if msg then
|
||||
msg = string.format("%s | %s", msg, invalid)
|
||||
else
|
||||
msg = string.format("%s", invalid)
|
||||
end
|
||||
user[k] = nil
|
||||
else
|
||||
validate(v, def[k], prefix .. k .. ".")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
validate(conf, DEFAULT_OPTS, "")
|
||||
|
||||
if msg then
|
||||
utils.warn(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(conf)
|
||||
legacy.migrate_legacy_options(conf or {})
|
||||
|
||||
validate_options(conf)
|
||||
|
||||
local opts = merge_options(conf)
|
||||
local netrw_disabled = opts.disable_netrw or opts.hijack_netrw
|
||||
|
||||
_config.update_focused_file = opts.update_focused_file
|
||||
_config.open_on_setup = opts.open_on_setup
|
||||
_config.open_on_setup_file = opts.open_on_setup_file
|
||||
_config.ignore_buffer_on_setup = opts.ignore_buffer_on_setup
|
||||
_config.ignore_ft_on_setup = opts.ignore_ft_on_setup
|
||||
_config.hijack_directories = opts.hijack_directories
|
||||
_config.hijack_directories.enable = _config.hijack_directories.enable and netrw_disabled
|
||||
|
||||
manage_netrw(opts.disable_netrw, opts.hijack_netrw)
|
||||
|
||||
M.config = opts
|
||||
require("nvim-tree.log").setup(opts)
|
||||
|
||||
log.line("config", "default config + user")
|
||||
log.raw("config", "%s\n", vim.inspect(opts))
|
||||
|
||||
require("nvim-tree.actions").setup(opts)
|
||||
require("nvim-tree.colors").setup()
|
||||
require("nvim-tree.diagnostics").setup(opts)
|
||||
require("nvim-tree.explorer").setup(opts)
|
||||
require("nvim-tree.git").setup(opts)
|
||||
require("nvim-tree.view").setup(opts)
|
||||
require("nvim-tree.lib").setup(opts)
|
||||
require("nvim-tree.renderer").setup(opts)
|
||||
|
||||
setup_vim_commands()
|
||||
setup_autocommands(opts)
|
||||
|
||||
vim.schedule(function()
|
||||
M.on_enter(netrw_disabled)
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
52
bundle/nvim-tree.lua/lua/nvim-tree/actions/change-dir.lua
Normal file
52
bundle/nvim-tree.lua/lua/nvim-tree/actions/change-dir.lua
Normal file
@ -0,0 +1,52 @@
|
||||
local a = vim.api
|
||||
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {
|
||||
current_tab = a.nvim_get_current_tabpage(),
|
||||
}
|
||||
|
||||
function M.fn(name, with_open)
|
||||
if not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
|
||||
local foldername = name == ".." and vim.fn.fnamemodify(utils.path_remove_trailing(core.get_cwd()), ":h") or name
|
||||
local no_cwd_change = vim.fn.expand(foldername) == core.get_cwd()
|
||||
or M.options.restrict_above_cwd and foldername < vim.fn.getcwd(-1, -1)
|
||||
local new_tab = a.nvim_get_current_tabpage()
|
||||
local is_window = (vim.v.event.scope == "window" or vim.v.event.changed_window) and new_tab == M.current_tab
|
||||
if no_cwd_change or is_window then
|
||||
return
|
||||
end
|
||||
M.current_tab = new_tab
|
||||
M.force_dirchange(foldername, with_open)
|
||||
end
|
||||
|
||||
function M.force_dirchange(foldername, with_open)
|
||||
local ps = log.profile_start("change dir %s", foldername)
|
||||
|
||||
if M.options.enable and vim.tbl_isempty(vim.v.event) then
|
||||
if M.options.global then
|
||||
vim.cmd("cd " .. vim.fn.fnameescape(foldername))
|
||||
else
|
||||
vim.cmd("lcd " .. vim.fn.fnameescape(foldername))
|
||||
end
|
||||
end
|
||||
core.init(foldername)
|
||||
if with_open then
|
||||
require("nvim-tree.lib").open()
|
||||
else
|
||||
require("nvim-tree.renderer").draw()
|
||||
end
|
||||
|
||||
log.profile_end(ps, "change dir %s", foldername)
|
||||
end
|
||||
|
||||
function M.setup(options)
|
||||
M.options = options.actions.change_dir
|
||||
end
|
||||
|
||||
return M
|
43
bundle/nvim-tree.lua/lua/nvim-tree/actions/collapse-all.lua
Normal file
43
bundle/nvim-tree.lua/lua/nvim-tree/actions/collapse-all.lua
Normal file
@ -0,0 +1,43 @@
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.fn(keep_buffers)
|
||||
if not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
|
||||
local buffer_paths = {}
|
||||
for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
|
||||
table.insert(buffer_paths, vim.api.nvim_buf_get_name(buffer))
|
||||
end
|
||||
|
||||
local function iter(nodes)
|
||||
for _, node in pairs(nodes) do
|
||||
if node.open then
|
||||
local new_open = false
|
||||
|
||||
if keep_buffers == true then
|
||||
for _, buffer_path in ipairs(buffer_paths) do
|
||||
local matches = utils.str_find(buffer_path, node.absolute_path)
|
||||
if matches then
|
||||
new_open = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
node.open = new_open
|
||||
end
|
||||
if node.nodes then
|
||||
iter(node.nodes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
iter(core.get_explorer().nodes)
|
||||
renderer.draw()
|
||||
end
|
||||
|
||||
return M
|
247
bundle/nvim-tree.lua/lua/nvim-tree/actions/copy-paste.lua
Normal file
247
bundle/nvim-tree.lua/lua/nvim-tree/actions/copy-paste.lua
Normal file
@ -0,0 +1,247 @@
|
||||
local a = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local lib = require "nvim-tree.lib"
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
local clipboard = {
|
||||
move = {},
|
||||
copy = {},
|
||||
}
|
||||
|
||||
local function do_copy(source, destination)
|
||||
local source_stats, handle
|
||||
local success, errmsg
|
||||
|
||||
source_stats, errmsg = uv.fs_stat(source)
|
||||
if not source_stats then
|
||||
log.line("copy_paste", "do_copy fs_stat '%s' failed '%s'", source, errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
log.line("copy_paste", "do_copy %s '%s' -> '%s'", source_stats.type, source, destination)
|
||||
|
||||
if source == destination then
|
||||
log.line("copy_paste", "do_copy source and destination are the same, exiting early")
|
||||
return true
|
||||
end
|
||||
|
||||
if source_stats.type == "file" then
|
||||
success, errmsg = uv.fs_copyfile(source, destination)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_copy fs_copyfile failed '%s'", errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
return true
|
||||
elseif source_stats.type == "directory" then
|
||||
handle, errmsg = uv.fs_scandir(source)
|
||||
if type(handle) == "string" then
|
||||
return false, handle
|
||||
elseif not handle then
|
||||
log.line("copy_paste", "do_copy fs_scandir '%s' failed '%s'", source, errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
success, errmsg = uv.fs_mkdir(destination, source_stats.mode)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_copy fs_mkdir '%s' failed '%s'", destination, errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
while true do
|
||||
local name, _ = uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local new_name = utils.path_join { source, name }
|
||||
local new_destination = utils.path_join { destination, name }
|
||||
success, errmsg = do_copy(new_name, new_destination)
|
||||
if not success then
|
||||
return false, errmsg
|
||||
end
|
||||
end
|
||||
else
|
||||
errmsg = string.format("'%s' illegal file type '%s'", source, source_stats.type)
|
||||
log.line("copy_paste", "do_copy %s", errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function do_single_paste(source, dest, action_type, action_fn)
|
||||
local dest_stats
|
||||
local success, errmsg, errcode
|
||||
|
||||
log.line("copy_paste", "do_single_paste '%s' -> '%s'", source, dest)
|
||||
|
||||
dest_stats, errmsg, errcode = uv.fs_stat(dest)
|
||||
if not dest_stats and errcode ~= "ENOENT" then
|
||||
a.nvim_err_writeln("Could not " .. action_type .. " " .. source .. " - " .. (errmsg or "???"))
|
||||
return false, errmsg
|
||||
end
|
||||
|
||||
local should_process = true
|
||||
local should_rename = false
|
||||
|
||||
if dest_stats then
|
||||
print(dest .. " already exists. Overwrite? y/n/r(ename)")
|
||||
local ans = utils.get_user_input_char()
|
||||
utils.clear_prompt()
|
||||
should_process = ans:match "^y"
|
||||
should_rename = ans:match "^r"
|
||||
end
|
||||
|
||||
if should_rename then
|
||||
local new_dest = vim.fn.input("New name: ", dest)
|
||||
return do_single_paste(source, new_dest, action_type, action_fn)
|
||||
end
|
||||
|
||||
if should_process then
|
||||
success, errmsg = action_fn(source, dest)
|
||||
if not success then
|
||||
a.nvim_err_writeln("Could not " .. action_type .. " " .. source .. " - " .. (errmsg or "???"))
|
||||
return false, errmsg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function add_to_clipboard(node, clip)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
for idx, _node in ipairs(clip) do
|
||||
if _node.absolute_path == node.absolute_path then
|
||||
table.remove(clip, idx)
|
||||
return a.nvim_out_write(node.absolute_path .. " removed to clipboard.\n")
|
||||
end
|
||||
end
|
||||
table.insert(clip, node)
|
||||
a.nvim_out_write(node.absolute_path .. " added to clipboard.\n")
|
||||
end
|
||||
|
||||
function M.copy(node)
|
||||
add_to_clipboard(node, clipboard.copy)
|
||||
end
|
||||
|
||||
function M.cut(node)
|
||||
add_to_clipboard(node, clipboard.move)
|
||||
end
|
||||
|
||||
local function do_paste(node, action_type, action_fn)
|
||||
node = lib.get_last_group_node(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
local clip = clipboard[action_type]
|
||||
if #clip == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local destination = node.absolute_path
|
||||
local stats, errmsg, errcode = uv.fs_stat(destination)
|
||||
if not stats and errcode ~= "ENOENT" then
|
||||
log.line("copy_paste", "do_paste fs_stat '%s' failed '%s'", destination, errmsg)
|
||||
a.nvim_err_writeln("Could not " .. action_type .. " " .. destination .. " - " .. (errmsg or "???"))
|
||||
return
|
||||
end
|
||||
local is_dir = stats and stats.type == "directory"
|
||||
|
||||
if not is_dir then
|
||||
destination = vim.fn.fnamemodify(destination, ":p:h")
|
||||
elseif not node.open then
|
||||
destination = vim.fn.fnamemodify(destination, ":p:h:h")
|
||||
end
|
||||
|
||||
for _, _node in ipairs(clip) do
|
||||
local dest = utils.path_join { destination, _node.name }
|
||||
do_single_paste(_node.absolute_path, dest, action_type, action_fn)
|
||||
end
|
||||
|
||||
clipboard[action_type] = {}
|
||||
return require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
end
|
||||
|
||||
local function do_cut(source, destination)
|
||||
log.line("copy_paste", "do_cut '%s' -> '%s'", source, destination)
|
||||
|
||||
if source == destination then
|
||||
log.line("copy_paste", "do_cut source and destination are the same, exiting early")
|
||||
return true
|
||||
end
|
||||
|
||||
local success, errmsg = uv.fs_rename(source, destination)
|
||||
if not success then
|
||||
log.line("copy_paste", "do_cut fs_rename failed '%s'", errmsg)
|
||||
return false, errmsg
|
||||
end
|
||||
utils.rename_loaded_buffers(source, destination)
|
||||
return true
|
||||
end
|
||||
|
||||
function M.paste(node)
|
||||
if clipboard.move[1] ~= nil then
|
||||
return do_paste(node, "move", do_cut)
|
||||
end
|
||||
|
||||
return do_paste(node, "copy", do_copy)
|
||||
end
|
||||
|
||||
function M.print_clipboard()
|
||||
local content = {}
|
||||
if #clipboard.move > 0 then
|
||||
table.insert(content, "Cut")
|
||||
for _, item in pairs(clipboard.move) do
|
||||
table.insert(content, " * " .. item.absolute_path)
|
||||
end
|
||||
end
|
||||
if #clipboard.copy > 0 then
|
||||
table.insert(content, "Copy")
|
||||
for _, item in pairs(clipboard.copy) do
|
||||
table.insert(content, " * " .. item.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
return a.nvim_out_write(table.concat(content, "\n") .. "\n")
|
||||
end
|
||||
|
||||
local function copy_to_clipboard(content)
|
||||
if M.use_system_clipboard == true then
|
||||
vim.fn.setreg("+", content)
|
||||
vim.fn.setreg('"', content)
|
||||
return a.nvim_out_write(string.format("Copied %s to system clipboard! \n", content))
|
||||
else
|
||||
vim.fn.setreg('"', content)
|
||||
vim.fn.setreg("1", content)
|
||||
return a.nvim_out_write(string.format("Copied %s to neovim clipboard \n", content))
|
||||
end
|
||||
end
|
||||
|
||||
function M.copy_filename(node)
|
||||
return copy_to_clipboard(node.name)
|
||||
end
|
||||
|
||||
function M.copy_path(node)
|
||||
local absolute_path = node.absolute_path
|
||||
local relative_path = utils.path_relative(absolute_path, core.get_cwd())
|
||||
local content = node.nodes ~= nil and utils.path_add_trailing(relative_path) or relative_path
|
||||
return copy_to_clipboard(content)
|
||||
end
|
||||
|
||||
function M.copy_absolute_path(node)
|
||||
local absolute_path = node.absolute_path
|
||||
local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path
|
||||
return copy_to_clipboard(content)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.use_system_clipboard = opts.actions.use_system_clipboard
|
||||
end
|
||||
|
||||
return M
|
115
bundle/nvim-tree.lua/lua/nvim-tree/actions/create-file.lua
Normal file
115
bundle/nvim-tree.lua/lua/nvim-tree/actions/create-file.lua
Normal file
@ -0,0 +1,115 @@
|
||||
local a = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
local lib = require "nvim-tree.lib"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function focus_file(file)
|
||||
local _, i = utils.find_node(core.get_explorer().nodes, function(node)
|
||||
return node.absolute_path == file
|
||||
end)
|
||||
require("nvim-tree.view").set_cursor { i + 1, 1 }
|
||||
end
|
||||
|
||||
local function create_file(file)
|
||||
if utils.file_exists(file) then
|
||||
print(file .. " already exists. Overwrite? y/n")
|
||||
local ans = utils.get_user_input_char()
|
||||
utils.clear_prompt()
|
||||
if ans ~= "y" then
|
||||
return
|
||||
end
|
||||
end
|
||||
local ok, fd = pcall(uv.fs_open, file, "w", 420)
|
||||
if not ok then
|
||||
a.nvim_err_writeln("Couldn't create file " .. file)
|
||||
return
|
||||
end
|
||||
uv.fs_close(fd)
|
||||
events._dispatch_file_created(file)
|
||||
end
|
||||
|
||||
local function get_num_nodes(iter)
|
||||
local i = 0
|
||||
for _ in iter do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
local function get_containing_folder(node)
|
||||
local is_open = vim.g.nvim_tree_create_in_closed_folder == 1 or node.open
|
||||
if node.nodes ~= nil and is_open then
|
||||
return utils.path_add_trailing(node.absolute_path)
|
||||
end
|
||||
local node_name_size = #(node.name or "")
|
||||
return node.absolute_path:sub(0, -node_name_size - 1)
|
||||
end
|
||||
|
||||
function M.fn(node)
|
||||
node = lib.get_last_group_node(node)
|
||||
if node.name == ".." then
|
||||
node = {
|
||||
absolute_path = core.get_cwd(),
|
||||
nodes = core.get_explorer().nodes,
|
||||
open = true,
|
||||
}
|
||||
end
|
||||
|
||||
local containing_folder = get_containing_folder(node)
|
||||
|
||||
local input_opts = { prompt = "Create file ", default = containing_folder, completion = "file" }
|
||||
|
||||
vim.ui.input(input_opts, function(new_file_path)
|
||||
if not new_file_path or new_file_path == containing_folder then
|
||||
return
|
||||
end
|
||||
|
||||
utils.clear_prompt()
|
||||
|
||||
if utils.file_exists(new_file_path) then
|
||||
utils.warn "Cannot create: file already exists"
|
||||
return
|
||||
end
|
||||
|
||||
-- create a folder for each path element if the folder does not exist
|
||||
-- if the answer ends with a /, create a file for the last path element
|
||||
local is_last_path_file = not new_file_path:match(utils.path_separator .. "$")
|
||||
local path_to_create = ""
|
||||
local idx = 0
|
||||
|
||||
local num_nodes = get_num_nodes(utils.path_split(utils.path_remove_trailing(new_file_path)))
|
||||
local is_error = false
|
||||
for path in utils.path_split(new_file_path) do
|
||||
idx = idx + 1
|
||||
local p = utils.path_remove_trailing(path)
|
||||
if #path_to_create == 0 and vim.fn.has "win32" == 1 then
|
||||
path_to_create = utils.path_join { p, path_to_create }
|
||||
else
|
||||
path_to_create = utils.path_join { path_to_create, p }
|
||||
end
|
||||
if is_last_path_file and idx == num_nodes then
|
||||
create_file(path_to_create)
|
||||
elseif not utils.file_exists(path_to_create) then
|
||||
local success = uv.fs_mkdir(path_to_create, 493)
|
||||
if not success then
|
||||
a.nvim_err_writeln("Could not create folder " .. path_to_create)
|
||||
is_error = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not is_error then
|
||||
a.nvim_out_write(new_file_path .. " was properly created\n")
|
||||
end
|
||||
events._dispatch_folder_created(new_file_path)
|
||||
require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
focus_file(new_file_path)
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
16
bundle/nvim-tree.lua/lua/nvim-tree/actions/dir-up.lua
Normal file
16
bundle/nvim-tree.lua/lua/nvim-tree/actions/dir-up.lua
Normal file
@ -0,0 +1,16 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.fn(node)
|
||||
if not node or node.name == ".." then
|
||||
return require("nvim-tree.actions.change-dir").fn ".."
|
||||
else
|
||||
local newdir = vim.fn.fnamemodify(utils.path_remove_trailing(core.get_cwd()), ":h")
|
||||
require("nvim-tree.actions.change-dir").fn(newdir)
|
||||
return require("nvim-tree.actions.find-file").fn(node.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
82
bundle/nvim-tree.lua/lua/nvim-tree/actions/file-popup.lua
Normal file
82
bundle/nvim-tree.lua/lua/nvim-tree/actions/file-popup.lua
Normal file
@ -0,0 +1,82 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local a = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
local function get_formatted_lines(node)
|
||||
local stats = node.fs_stat
|
||||
local fpath = " fullpath: " .. node.absolute_path
|
||||
local created_at = " created: " .. os.date("%x %X", stats.birthtime.sec)
|
||||
local modified_at = " modified: " .. os.date("%x %X", stats.mtime.sec)
|
||||
local accessed_at = " accessed: " .. os.date("%x %X", stats.atime.sec)
|
||||
local size = " size: " .. utils.format_bytes(stats.size)
|
||||
|
||||
return {
|
||||
fpath,
|
||||
size,
|
||||
accessed_at,
|
||||
modified_at,
|
||||
created_at,
|
||||
}
|
||||
end
|
||||
|
||||
local current_popup = nil
|
||||
|
||||
local function setup_window(node)
|
||||
local lines = get_formatted_lines(node)
|
||||
|
||||
local max_width = vim.fn.max(vim.tbl_map(function(n)
|
||||
return #n
|
||||
end, lines))
|
||||
local winnr = a.nvim_open_win(0, false, {
|
||||
col = 1,
|
||||
row = 1,
|
||||
relative = "cursor",
|
||||
width = max_width + 1,
|
||||
height = #lines,
|
||||
border = "shadow",
|
||||
noautocmd = true,
|
||||
style = "minimal",
|
||||
})
|
||||
current_popup = {
|
||||
winnr = winnr,
|
||||
file_path = node.absolute_path,
|
||||
}
|
||||
local bufnr = a.nvim_create_buf(false, true)
|
||||
a.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
a.nvim_win_set_buf(winnr, bufnr)
|
||||
end
|
||||
|
||||
function M.close_popup()
|
||||
if current_popup ~= nil then
|
||||
a.nvim_win_close(current_popup.winnr, { force = true })
|
||||
vim.cmd "augroup NvimTreeRemoveFilePopup | au! CursorMoved | augroup END"
|
||||
|
||||
current_popup = nil
|
||||
end
|
||||
end
|
||||
|
||||
function M.toggle_file_info(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
if current_popup ~= nil then
|
||||
local is_same_node = current_popup.file_path == node.absolute_path
|
||||
|
||||
M.close_popup()
|
||||
|
||||
if is_same_node then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
setup_window(node)
|
||||
|
||||
vim.cmd [[
|
||||
augroup NvimTreeRemoveFilePopup
|
||||
au CursorMoved * lua require'nvim-tree.actions.file-popup'.close_popup()
|
||||
augroup END
|
||||
]]
|
||||
end
|
||||
|
||||
return M
|
77
bundle/nvim-tree.lua/lua/nvim-tree/actions/find-file.lua
Normal file
77
bundle/nvim-tree.lua/lua/nvim-tree/actions/find-file.lua
Normal file
@ -0,0 +1,77 @@
|
||||
local log = require "nvim-tree.log"
|
||||
local uv = vim.loop
|
||||
local view = require "nvim-tree.view"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
local running = {}
|
||||
|
||||
---Find a path in the tree, expand it and focus it
|
||||
---@param fname string full path
|
||||
function M.fn(fname)
|
||||
if running[fname] or not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
running[fname] = true
|
||||
|
||||
local ps = log.profile_start("find file %s", fname)
|
||||
-- always match against the real path
|
||||
local fname_real = uv.fs_realpath(fname)
|
||||
if not fname_real then
|
||||
return
|
||||
end
|
||||
|
||||
local i = core.get_nodes_starting_line() - 1
|
||||
local tree_altered = false
|
||||
|
||||
local function iterate_nodes(nodes)
|
||||
for _, node in ipairs(nodes) do
|
||||
i = i + 1
|
||||
|
||||
if not node.absolute_path or not uv.fs_stat(node.absolute_path) then
|
||||
break
|
||||
end
|
||||
|
||||
-- match against node absolute and link, as symlinks themselves will differ
|
||||
if node.absolute_path == fname_real or node.link_to == fname_real then
|
||||
return i
|
||||
end
|
||||
local abs_match = vim.startswith(fname_real, node.absolute_path .. utils.path_separator)
|
||||
local link_match = node.link_to and vim.startswith(fname_real, node.link_to .. utils.path_separator)
|
||||
local path_matches = node.nodes and (abs_match or link_match)
|
||||
if path_matches then
|
||||
if not node.open then
|
||||
node.open = true
|
||||
tree_altered = true
|
||||
end
|
||||
|
||||
if #node.nodes == 0 then
|
||||
core.get_explorer():expand(node)
|
||||
end
|
||||
|
||||
if iterate_nodes(node.nodes) ~= nil then
|
||||
return i
|
||||
end
|
||||
-- mandatory to iterate i
|
||||
elseif node.open then
|
||||
iterate_nodes(node.nodes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local index = iterate_nodes(core.get_explorer().nodes)
|
||||
if tree_altered then
|
||||
renderer.draw()
|
||||
end
|
||||
if index and view.is_visible() then
|
||||
view.set_cursor { index, 0 }
|
||||
end
|
||||
running[fname] = false
|
||||
|
||||
log.profile_end(ps, "find file %s", fname)
|
||||
end
|
||||
|
||||
return M
|
243
bundle/nvim-tree.lua/lua/nvim-tree/actions/init.lua
Normal file
243
bundle/nvim-tree.lua/lua/nvim-tree/actions/init.lua
Normal file
@ -0,0 +1,243 @@
|
||||
local a = vim.api
|
||||
|
||||
local lib = require "nvim-tree.lib"
|
||||
local log = require "nvim-tree.log"
|
||||
local view = require "nvim-tree.view"
|
||||
local util = require "nvim-tree.utils"
|
||||
local nvim_tree_callback = require("nvim-tree.config").nvim_tree_callback
|
||||
|
||||
local M = {
|
||||
mappings = {
|
||||
{ key = { "<CR>", "o", "<2-LeftMouse>" }, action = "edit" },
|
||||
{ key = "<C-e>", action = "edit_in_place" },
|
||||
{ key = "O", action = "edit_no_picker" },
|
||||
{ key = { "<2-RightMouse>", "<C-]>" }, action = "cd" },
|
||||
{ key = "<C-v>", action = "vsplit" },
|
||||
{ key = "<C-x>", action = "split" },
|
||||
{ key = "<C-t>", action = "tabnew" },
|
||||
{ key = "<", action = "prev_sibling" },
|
||||
{ key = ">", action = "next_sibling" },
|
||||
{ key = "P", action = "parent_node" },
|
||||
{ key = "<BS>", action = "close_node" },
|
||||
{ key = "<Tab>", action = "preview" },
|
||||
{ key = "K", action = "first_sibling" },
|
||||
{ key = "J", action = "last_sibling" },
|
||||
{ key = "I", action = "toggle_git_ignored" },
|
||||
{ key = "H", action = "toggle_dotfiles" },
|
||||
{ key = "R", action = "refresh" },
|
||||
{ key = "a", action = "create" },
|
||||
{ key = "d", action = "remove" },
|
||||
{ key = "D", action = "trash" },
|
||||
{ key = "r", action = "rename" },
|
||||
{ key = "<C-r>", action = "full_rename" },
|
||||
{ key = "x", action = "cut" },
|
||||
{ key = "c", action = "copy" },
|
||||
{ key = "p", action = "paste" },
|
||||
{ key = "y", action = "copy_name" },
|
||||
{ key = "Y", action = "copy_path" },
|
||||
{ key = "gy", action = "copy_absolute_path" },
|
||||
{ key = "[c", action = "prev_git_item" },
|
||||
{ key = "]c", action = "next_git_item" },
|
||||
{ key = "-", action = "dir_up" },
|
||||
{ key = "s", action = "system_open" },
|
||||
{ key = "q", action = "close" },
|
||||
{ key = "g?", action = "toggle_help" },
|
||||
{ key = "W", action = "collapse_all" },
|
||||
{ key = "S", action = "search_node" },
|
||||
{ key = ".", action = "run_file_command" },
|
||||
{ key = "<C-k>", action = "toggle_file_info" },
|
||||
{ key = "U", action = "toggle_custom" },
|
||||
},
|
||||
custom_keypress_funcs = {},
|
||||
}
|
||||
|
||||
local keypress_funcs = {
|
||||
close = view.close,
|
||||
close_node = require("nvim-tree.actions.movements").parent_node(true),
|
||||
collapse_all = require("nvim-tree.actions.collapse-all").fn,
|
||||
copy_absolute_path = require("nvim-tree.actions.copy-paste").copy_absolute_path,
|
||||
copy_name = require("nvim-tree.actions.copy-paste").copy_filename,
|
||||
copy_path = require("nvim-tree.actions.copy-paste").copy_path,
|
||||
copy = require("nvim-tree.actions.copy-paste").copy,
|
||||
create = require("nvim-tree.actions.create-file").fn,
|
||||
cut = require("nvim-tree.actions.copy-paste").cut,
|
||||
dir_up = require("nvim-tree.actions.dir-up").fn,
|
||||
first_sibling = require("nvim-tree.actions.movements").sibling(-math.huge),
|
||||
full_rename = require("nvim-tree.actions.rename-file").fn(true),
|
||||
last_sibling = require("nvim-tree.actions.movements").sibling(math.huge),
|
||||
next_git_item = require("nvim-tree.actions.movements").find_git_item "next",
|
||||
next_sibling = require("nvim-tree.actions.movements").sibling(1),
|
||||
parent_node = require("nvim-tree.actions.movements").parent_node(false),
|
||||
paste = require("nvim-tree.actions.copy-paste").paste,
|
||||
prev_git_item = require("nvim-tree.actions.movements").find_git_item "prev",
|
||||
prev_sibling = require("nvim-tree.actions.movements").sibling(-1),
|
||||
refresh = require("nvim-tree.actions.reloaders").reload_explorer,
|
||||
remove = require("nvim-tree.actions.remove-file").fn,
|
||||
rename = require("nvim-tree.actions.rename-file").fn(false),
|
||||
run_file_command = require("nvim-tree.actions.run-command").run_file_command,
|
||||
search_node = require("nvim-tree.actions.search-node").fn,
|
||||
toggle_file_info = require("nvim-tree.actions.file-popup").toggle_file_info,
|
||||
system_open = require("nvim-tree.actions.system-open").fn,
|
||||
toggle_dotfiles = require("nvim-tree.actions.toggles").dotfiles,
|
||||
toggle_help = require("nvim-tree.actions.toggles").help,
|
||||
toggle_custom = require("nvim-tree.actions.toggles").custom,
|
||||
toggle_git_ignored = require("nvim-tree.actions.toggles").git_ignored,
|
||||
trash = require("nvim-tree.actions.trash").fn,
|
||||
}
|
||||
|
||||
function M.on_keypress(action)
|
||||
if view.is_help_ui() and action == "close" then
|
||||
action = "toggle_help"
|
||||
end
|
||||
if view.is_help_ui() and action ~= "toggle_help" then
|
||||
return
|
||||
end
|
||||
local node = lib.get_node_at_cursor()
|
||||
if not node then
|
||||
return
|
||||
end
|
||||
|
||||
local custom_function = M.custom_keypress_funcs[action]
|
||||
local default_function = keypress_funcs[action]
|
||||
|
||||
if type(custom_function) == "function" then
|
||||
return custom_function(node)
|
||||
elseif default_function then
|
||||
return default_function(node)
|
||||
end
|
||||
|
||||
if action == "preview" then
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
if not node.nodes then
|
||||
return require("nvim-tree.actions.open-file").fn("preview", node.absolute_path)
|
||||
end
|
||||
elseif node.name == ".." then
|
||||
return require("nvim-tree.actions.change-dir").fn ".."
|
||||
elseif action == "cd" then
|
||||
if node.nodes ~= nil then
|
||||
require("nvim-tree.actions.change-dir").fn(lib.get_last_group_node(node).absolute_path)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if node.link_to and not node.nodes then
|
||||
require("nvim-tree.actions.open-file").fn(action, node.link_to)
|
||||
elseif node.nodes ~= nil then
|
||||
lib.expand_or_collapse(node)
|
||||
else
|
||||
require("nvim-tree.actions.open-file").fn(action, node.absolute_path)
|
||||
end
|
||||
end
|
||||
|
||||
function M.apply_mappings(bufnr)
|
||||
for _, b in pairs(M.mappings) do
|
||||
local mapping_rhs = b.cb or nvim_tree_callback(b.action)
|
||||
if type(b.key) == "table" then
|
||||
for _, key in pairs(b.key) do
|
||||
a.nvim_buf_set_keymap(bufnr, b.mode or "n", key, mapping_rhs, { noremap = true, silent = true, nowait = true })
|
||||
end
|
||||
elseif mapping_rhs then
|
||||
a.nvim_buf_set_keymap(bufnr, b.mode or "n", b.key, mapping_rhs, { noremap = true, silent = true, nowait = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function merge_mappings(user_mappings)
|
||||
if #user_mappings == 0 then
|
||||
return M.mappings
|
||||
end
|
||||
|
||||
local function is_empty(s)
|
||||
return s == ""
|
||||
end
|
||||
|
||||
local user_keys = {}
|
||||
local removed_keys = {}
|
||||
-- remove default mappings if action is a empty string
|
||||
for _, map in pairs(user_mappings) do
|
||||
if type(map.key) == "table" then
|
||||
for _, key in pairs(map.key) do
|
||||
table.insert(user_keys, key)
|
||||
if is_empty(map.action) then
|
||||
table.insert(removed_keys, key)
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(user_keys, map.key)
|
||||
if is_empty(map.action) then
|
||||
table.insert(removed_keys, map.key)
|
||||
end
|
||||
end
|
||||
|
||||
if map.action and type(map.action_cb) == "function" then
|
||||
if not is_empty(map.action) then
|
||||
M.custom_keypress_funcs[map.action] = map.action_cb
|
||||
else
|
||||
util.warn "action can't be empty if action_cb provided"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local default_map = vim.tbl_filter(function(map)
|
||||
if type(map.key) == "table" then
|
||||
local filtered_keys = {}
|
||||
for _, key in pairs(map.key) do
|
||||
if not vim.tbl_contains(user_keys, key) and not vim.tbl_contains(removed_keys, key) then
|
||||
table.insert(filtered_keys, key)
|
||||
end
|
||||
end
|
||||
map.key = filtered_keys
|
||||
return not vim.tbl_isempty(map.key)
|
||||
else
|
||||
return not vim.tbl_contains(user_keys, map.key) and not vim.tbl_contains(removed_keys, map.key)
|
||||
end
|
||||
end, M.mappings)
|
||||
|
||||
local user_map = vim.tbl_filter(function(map)
|
||||
return not is_empty(map.action)
|
||||
end, user_mappings)
|
||||
|
||||
return vim.fn.extend(default_map, user_map)
|
||||
end
|
||||
|
||||
local function copy_mappings(user_mappings)
|
||||
if #user_mappings == 0 then
|
||||
return M.mappings
|
||||
end
|
||||
|
||||
for _, map in pairs(user_mappings) do
|
||||
if map.action and type(map.action_cb) == "function" then
|
||||
M.custom_keypress_funcs[map.action] = map.action_cb
|
||||
end
|
||||
end
|
||||
|
||||
return user_mappings
|
||||
end
|
||||
|
||||
local DEFAULT_MAPPING_CONFIG = {
|
||||
custom_only = false,
|
||||
list = {},
|
||||
}
|
||||
|
||||
function M.setup(opts)
|
||||
require("nvim-tree.actions.system-open").setup(opts.system_open)
|
||||
require("nvim-tree.actions.trash").setup(opts.trash)
|
||||
require("nvim-tree.actions.open-file").setup(opts)
|
||||
require("nvim-tree.actions.change-dir").setup(opts)
|
||||
require("nvim-tree.actions.copy-paste").setup(opts)
|
||||
|
||||
local user_map_config = (opts.view or {}).mappings or {}
|
||||
local options = vim.tbl_deep_extend("force", DEFAULT_MAPPING_CONFIG, user_map_config)
|
||||
if options.custom_only then
|
||||
M.mappings = copy_mappings(options.list)
|
||||
else
|
||||
M.mappings = merge_mappings(options.list)
|
||||
end
|
||||
|
||||
log.line("config", "active mappings")
|
||||
log.raw("config", "%s\n", vim.inspect(M.mappings))
|
||||
end
|
||||
|
||||
return M
|
145
bundle/nvim-tree.lua/lua/nvim-tree/actions/movements.lua
Normal file
145
bundle/nvim-tree.lua/lua/nvim-tree/actions/movements.lua
Normal file
@ -0,0 +1,145 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local view = require "nvim-tree.view"
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local core = require "nvim-tree.core"
|
||||
local lib = require "nvim-tree.lib"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function get_line_from_node(node, find_parent)
|
||||
local node_path = node.absolute_path
|
||||
|
||||
if find_parent then
|
||||
node_path = node.absolute_path:match("(.*)" .. utils.path_separator)
|
||||
end
|
||||
|
||||
local line = core.get_nodes_starting_line()
|
||||
local function iter(nodes, recursive)
|
||||
for _, _node in ipairs(nodes) do
|
||||
local n = lib.get_last_group_node(_node)
|
||||
if node_path == n.absolute_path then
|
||||
return line, _node
|
||||
end
|
||||
|
||||
line = line + 1
|
||||
if _node.open == true and recursive then
|
||||
local _, child = iter(_node.nodes, recursive)
|
||||
if child ~= nil then
|
||||
return line, child
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return iter
|
||||
end
|
||||
|
||||
function M.parent_node(should_close)
|
||||
return function(node)
|
||||
if should_close and node.open then
|
||||
node.open = false
|
||||
return renderer.draw()
|
||||
end
|
||||
|
||||
local parent = node.parent
|
||||
|
||||
if not parent or parent.cwd then
|
||||
return view.set_cursor { 1, 0 }
|
||||
end
|
||||
|
||||
local _, line = utils.find_node(core.get_explorer().nodes, function(n)
|
||||
return n.absolute_path == parent.absolute_path
|
||||
end)
|
||||
|
||||
view.set_cursor { line + 1, 0 }
|
||||
if should_close then
|
||||
parent.open = false
|
||||
renderer.draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.sibling(direction)
|
||||
return function(node)
|
||||
if node.name == ".." or not direction then
|
||||
return
|
||||
end
|
||||
|
||||
local iter = get_line_from_node(node, true)
|
||||
local node_path = node.absolute_path
|
||||
|
||||
local line = 0
|
||||
local parent, _
|
||||
|
||||
-- Check if current node is already at root nodes
|
||||
for index, _node in ipairs(core.get_explorer().nodes) do
|
||||
if node_path == _node.absolute_path then
|
||||
line = index
|
||||
end
|
||||
end
|
||||
|
||||
if line > 0 then
|
||||
parent = core.get_explorer()
|
||||
else
|
||||
_, parent = iter(core.get_explorer().nodes, true)
|
||||
if parent ~= nil and #parent.nodes > 1 then
|
||||
line, _ = get_line_from_node(node)(parent.nodes)
|
||||
end
|
||||
|
||||
-- Ignore parent line count
|
||||
line = line - 1
|
||||
end
|
||||
|
||||
local index = line + direction
|
||||
if index < 1 then
|
||||
index = 1
|
||||
elseif index > #parent.nodes then
|
||||
index = #parent.nodes
|
||||
end
|
||||
local target_node = parent.nodes[index]
|
||||
|
||||
line, _ = get_line_from_node(target_node)(core.get_explorer().nodes, true)
|
||||
view.set_cursor { line, 0 }
|
||||
end
|
||||
end
|
||||
|
||||
function M.find_git_item(where)
|
||||
return function()
|
||||
local node_cur = lib.get_node_at_cursor()
|
||||
local nodes_by_line = lib.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())
|
||||
|
||||
local cur, first, prev, nex = nil, nil, nil, nil
|
||||
for line, node in pairs(nodes_by_line) do
|
||||
if not first and node.git_status then
|
||||
first = line
|
||||
end
|
||||
|
||||
if node == node_cur then
|
||||
cur = line
|
||||
elseif node.git_status then
|
||||
if not cur then
|
||||
prev = line
|
||||
end
|
||||
if cur and not nex then
|
||||
nex = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if where == "prev" then
|
||||
if prev then
|
||||
view.set_cursor { prev, 0 }
|
||||
end
|
||||
else
|
||||
if cur then
|
||||
if nex then
|
||||
view.set_cursor { nex, 0 }
|
||||
end
|
||||
elseif first then
|
||||
view.set_cursor { first, 0 }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
286
bundle/nvim-tree.lua/lua/nvim-tree/actions/open-file.lua
Normal file
286
bundle/nvim-tree.lua/lua/nvim-tree/actions/open-file.lua
Normal file
@ -0,0 +1,286 @@
|
||||
-- Copyright 2019 Yazdani Kiyan under MIT License
|
||||
local api = vim.api
|
||||
|
||||
local lib = require "nvim-tree.lib"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local view = require "nvim-tree.view"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function get_split_cmd()
|
||||
local side = view.View.side
|
||||
if side == "right" then
|
||||
return "aboveleft"
|
||||
end
|
||||
if side == "left" then
|
||||
return "belowright"
|
||||
end
|
||||
if side == "top" then
|
||||
return "bot"
|
||||
end
|
||||
return "top"
|
||||
end
|
||||
|
||||
---Get user to pick a window. Selectable windows are all windows in the current
|
||||
---tabpage that aren't NvimTree.
|
||||
---@return integer|nil -- If a valid window was picked, return its id. If an
|
||||
--- invalid window was picked / user canceled, return nil. If there are
|
||||
--- no selectable windows, return -1.
|
||||
local function pick_window()
|
||||
local tabpage = api.nvim_get_current_tabpage()
|
||||
local win_ids = api.nvim_tabpage_list_wins(tabpage)
|
||||
local tree_winid = view.get_winnr(tabpage)
|
||||
|
||||
local selectable = vim.tbl_filter(function(id)
|
||||
local bufid = api.nvim_win_get_buf(id)
|
||||
for option, v in pairs(M.window_picker.exclude) do
|
||||
local ok, option_value = pcall(api.nvim_buf_get_option, bufid, option)
|
||||
if ok and vim.tbl_contains(v, option_value) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local win_config = api.nvim_win_get_config(id)
|
||||
return id ~= tree_winid and win_config.focusable and not win_config.external
|
||||
end, win_ids)
|
||||
|
||||
-- If there are no selectable windows: return. If there's only 1, return it without picking.
|
||||
if #selectable == 0 then
|
||||
return -1
|
||||
end
|
||||
if #selectable == 1 then
|
||||
return selectable[1]
|
||||
end
|
||||
|
||||
local i = 1
|
||||
local win_opts = {}
|
||||
local win_map = {}
|
||||
local laststatus = vim.o.laststatus
|
||||
vim.o.laststatus = 2
|
||||
|
||||
local not_selectable = vim.tbl_filter(function(id)
|
||||
return not vim.tbl_contains(selectable, id)
|
||||
end, win_ids)
|
||||
|
||||
if laststatus == 3 then
|
||||
for _, win_id in ipairs(not_selectable) do
|
||||
local ok_status, statusline = pcall(api.nvim_win_get_option, win_id, "statusline")
|
||||
local ok_hl, winhl = pcall(api.nvim_win_get_option, win_id, "winhl")
|
||||
|
||||
win_opts[win_id] = {
|
||||
statusline = ok_status and statusline or "",
|
||||
winhl = ok_hl and winhl or "",
|
||||
}
|
||||
|
||||
-- Clear statusline for windows not selectable
|
||||
api.nvim_win_set_option(win_id, "statusline", " ")
|
||||
end
|
||||
end
|
||||
|
||||
-- Setup UI
|
||||
for _, id in ipairs(selectable) do
|
||||
local char = M.window_picker.chars:sub(i, i)
|
||||
local ok_status, statusline = pcall(api.nvim_win_get_option, id, "statusline")
|
||||
local ok_hl, winhl = pcall(api.nvim_win_get_option, id, "winhl")
|
||||
|
||||
win_opts[id] = {
|
||||
statusline = ok_status and statusline or "",
|
||||
winhl = ok_hl and winhl or "",
|
||||
}
|
||||
win_map[char] = id
|
||||
|
||||
api.nvim_win_set_option(id, "statusline", "%=" .. char .. "%=")
|
||||
api.nvim_win_set_option(id, "winhl", "StatusLine:NvimTreeWindowPicker,StatusLineNC:NvimTreeWindowPicker")
|
||||
|
||||
i = i + 1
|
||||
if i > #M.window_picker.chars then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
vim.cmd "redraw"
|
||||
print "Pick window: "
|
||||
local _, resp = pcall(utils.get_user_input_char)
|
||||
resp = (resp or ""):upper()
|
||||
utils.clear_prompt()
|
||||
|
||||
-- Restore window options
|
||||
for _, id in ipairs(selectable) do
|
||||
for opt, value in pairs(win_opts[id]) do
|
||||
api.nvim_win_set_option(id, opt, value)
|
||||
end
|
||||
end
|
||||
|
||||
if laststatus == 3 then
|
||||
for _, id in ipairs(not_selectable) do
|
||||
for opt, value in pairs(win_opts[id]) do
|
||||
api.nvim_win_set_option(id, opt, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.o.laststatus = laststatus
|
||||
|
||||
if not vim.tbl_contains(vim.split(M.window_picker.chars, ""), resp) then
|
||||
return
|
||||
end
|
||||
|
||||
return win_map[resp]
|
||||
end
|
||||
|
||||
local function open_file_in_tab(filename)
|
||||
if M.quit_on_open then
|
||||
view.close()
|
||||
else
|
||||
-- Switch window first to ensure new window doesn't inherit settings from
|
||||
-- NvimTree
|
||||
if lib.target_winid > 0 and api.nvim_win_is_valid(lib.target_winid) then
|
||||
api.nvim_set_current_win(lib.target_winid)
|
||||
else
|
||||
vim.cmd "wincmd p"
|
||||
end
|
||||
end
|
||||
|
||||
-- This sequence of commands are here to ensure a number of things: the new
|
||||
-- buffer must be opened in the current tabpage first so that focus can be
|
||||
-- brought back to the tree if it wasn't quit_on_open. It also ensures that
|
||||
-- when we open the new tabpage with the file, its window doesn't inherit
|
||||
-- settings from NvimTree, as it was already loaded.
|
||||
|
||||
vim.cmd("edit " .. vim.fn.fnameescape(filename))
|
||||
|
||||
local alt_bufid = vim.fn.bufnr "#"
|
||||
if alt_bufid ~= -1 then
|
||||
api.nvim_set_current_buf(alt_bufid)
|
||||
end
|
||||
|
||||
if not M.quit_on_open then
|
||||
vim.cmd "wincmd p"
|
||||
end
|
||||
|
||||
vim.cmd("tabe " .. vim.fn.fnameescape(filename))
|
||||
end
|
||||
|
||||
function M.fn(mode, filename)
|
||||
if mode == "tabnew" then
|
||||
open_file_in_tab(filename)
|
||||
return
|
||||
end
|
||||
|
||||
if mode == "edit_in_place" then
|
||||
require("nvim-tree.view").abandon_current_window()
|
||||
vim.cmd("edit " .. vim.fn.fnameescape(filename))
|
||||
return
|
||||
end
|
||||
|
||||
local tabpage = api.nvim_get_current_tabpage()
|
||||
local win_ids = api.nvim_tabpage_list_wins(tabpage)
|
||||
|
||||
local target_winid
|
||||
if not M.window_picker.enable or mode == "edit_no_picker" then
|
||||
target_winid = lib.target_winid
|
||||
else
|
||||
local pick_window_id = pick_window()
|
||||
if pick_window_id == nil then
|
||||
return
|
||||
end
|
||||
target_winid = pick_window_id
|
||||
end
|
||||
|
||||
if target_winid == -1 then
|
||||
target_winid = lib.target_winid
|
||||
end
|
||||
|
||||
local do_split = mode == "split" or mode == "vsplit"
|
||||
local vertical = mode ~= "split"
|
||||
|
||||
-- Check if file is already loaded in a buffer
|
||||
local buf_loaded = false
|
||||
for _, buf_id in ipairs(api.nvim_list_bufs()) do
|
||||
if api.nvim_buf_is_loaded(buf_id) and filename == api.nvim_buf_get_name(buf_id) then
|
||||
buf_loaded = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if filename is already open in a window
|
||||
local found = false
|
||||
for _, id in ipairs(win_ids) do
|
||||
if filename == api.nvim_buf_get_name(api.nvim_win_get_buf(id)) then
|
||||
if mode == "preview" then
|
||||
return
|
||||
end
|
||||
found = true
|
||||
api.nvim_set_current_win(id)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
if not target_winid or not vim.tbl_contains(win_ids, target_winid) then
|
||||
-- Target is invalid, or window does not exist in current tabpage: create
|
||||
-- new window
|
||||
local split_cmd = get_split_cmd()
|
||||
local splitside = view.is_vertical() and "vsp" or "sp"
|
||||
vim.cmd(split_cmd .. " " .. splitside)
|
||||
target_winid = api.nvim_get_current_win()
|
||||
lib.target_winid = target_winid
|
||||
|
||||
-- No need to split, as we created a new window.
|
||||
do_split = false
|
||||
elseif not vim.o.hidden then
|
||||
-- If `hidden` is not enabled, check if buffer in target window is
|
||||
-- modified, and create new split if it is.
|
||||
local target_bufid = api.nvim_win_get_buf(target_winid)
|
||||
if api.nvim_buf_get_option(target_bufid, "modified") then
|
||||
do_split = true
|
||||
end
|
||||
end
|
||||
|
||||
local cmd
|
||||
if do_split or #api.nvim_list_wins() == 1 then
|
||||
cmd = string.format("%ssplit ", vertical and "vertical " or "")
|
||||
else
|
||||
cmd = "edit "
|
||||
end
|
||||
|
||||
cmd = cmd .. vim.fn.fnameescape(filename)
|
||||
api.nvim_set_current_win(target_winid)
|
||||
pcall(vim.cmd, cmd)
|
||||
lib.set_target_win()
|
||||
end
|
||||
|
||||
if M.resize_window then
|
||||
view.resize()
|
||||
end
|
||||
|
||||
if mode == "preview" then
|
||||
if not buf_loaded then
|
||||
vim.bo.bufhidden = "delete"
|
||||
vim.cmd [[
|
||||
augroup RemoveBufHidden
|
||||
autocmd!
|
||||
autocmd TextChanged <buffer> setlocal bufhidden= | autocmd! RemoveBufHidden
|
||||
autocmd TextChangedI <buffer> setlocal bufhidden= | autocmd! RemoveBufHidden
|
||||
augroup end
|
||||
]]
|
||||
end
|
||||
view.focus()
|
||||
return
|
||||
end
|
||||
|
||||
if M.quit_on_open then
|
||||
view.close()
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.quit_on_open = opts.actions.open_file.quit_on_open
|
||||
M.resize_window = opts.actions.open_file.resize_window
|
||||
if opts.actions.open_file.window_picker.chars then
|
||||
opts.actions.open_file.window_picker.chars = tostring(opts.actions.open_file.window_picker.chars):upper()
|
||||
end
|
||||
M.window_picker = opts.actions.open_file.window_picker
|
||||
end
|
||||
|
||||
return M
|
62
bundle/nvim-tree.lua/lua/nvim-tree/actions/reloaders.lua
Normal file
62
bundle/nvim-tree.lua/lua/nvim-tree/actions/reloaders.lua
Normal file
@ -0,0 +1,62 @@
|
||||
local git = require "nvim-tree.git"
|
||||
local view = require "nvim-tree.view"
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local explorer_module = require "nvim-tree.explorer"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function refresh_nodes(node, projects)
|
||||
local cwd = node.cwd or node.link_to or node.absolute_path
|
||||
local project_root = git.get_project_root(cwd)
|
||||
explorer_module.reload(node, projects[project_root] or {})
|
||||
for _, _node in ipairs(node.nodes) do
|
||||
if _node.nodes and _node.open then
|
||||
refresh_nodes(_node, projects)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.reload_node_status(parent_node, projects)
|
||||
local project_root = git.get_project_root(parent_node.absolute_path or parent_node.cwd)
|
||||
local status = projects[project_root] or {}
|
||||
for _, node in ipairs(parent_node.nodes) do
|
||||
if node.nodes then
|
||||
node.git_status = status.dirs and status.dirs[node.absolute_path]
|
||||
else
|
||||
node.git_status = status.files and status.files[node.absolute_path]
|
||||
end
|
||||
if node.nodes and #node.nodes > 0 then
|
||||
M.reload_node_status(node, projects)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local event_running = false
|
||||
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)
|
||||
if view.is_visible() then
|
||||
renderer.draw()
|
||||
end
|
||||
event_running = false
|
||||
end
|
||||
|
||||
function M.reload_git()
|
||||
if not core.get_explorer() or not git.config.enable or event_running then
|
||||
return
|
||||
end
|
||||
event_running = true
|
||||
|
||||
local projects = git.reload()
|
||||
M.reload_node_status(core.get_explorer(), projects)
|
||||
renderer.draw()
|
||||
event_running = false
|
||||
end
|
||||
|
||||
return M
|
91
bundle/nvim-tree.lua/lua/nvim-tree/actions/remove-file.lua
Normal file
91
bundle/nvim-tree.lua/lua/nvim-tree/actions/remove-file.lua
Normal file
@ -0,0 +1,91 @@
|
||||
local a = vim.api
|
||||
local luv = vim.loop
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function close_windows(windows)
|
||||
for _, window in ipairs(windows) do
|
||||
if a.nvim_win_is_valid(window) then
|
||||
a.nvim_win_close(window, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clear_buffer(absolute_path)
|
||||
local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 }
|
||||
for _, buf in pairs(bufs) do
|
||||
if buf.name == absolute_path then
|
||||
if buf.hidden == 0 and #bufs > 1 then
|
||||
local winnr = a.nvim_get_current_win()
|
||||
a.nvim_set_current_win(buf.windows[1])
|
||||
vim.cmd ":bn"
|
||||
a.nvim_set_current_win(winnr)
|
||||
end
|
||||
a.nvim_buf_delete(buf.bufnr, { force = true })
|
||||
close_windows(buf.windows)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_dir(cwd)
|
||||
local handle = luv.fs_scandir(cwd)
|
||||
if type(handle) == "string" then
|
||||
return a.nvim_err_writeln(handle)
|
||||
end
|
||||
|
||||
while true do
|
||||
local name, t = luv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local new_cwd = utils.path_join { cwd, name }
|
||||
if t == "directory" then
|
||||
local success = remove_dir(new_cwd)
|
||||
if not success then
|
||||
return false
|
||||
end
|
||||
else
|
||||
local success = luv.fs_unlink(new_cwd)
|
||||
if not success then
|
||||
return false
|
||||
end
|
||||
clear_buffer(new_cwd)
|
||||
end
|
||||
end
|
||||
|
||||
return luv.fs_rmdir(cwd)
|
||||
end
|
||||
|
||||
function M.fn(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
print("Remove " .. node.name .. " ? y/n")
|
||||
local ans = utils.get_user_input_char()
|
||||
utils.clear_prompt()
|
||||
if ans:match "^y" then
|
||||
if node.nodes ~= nil and not node.link_to then
|
||||
local success = remove_dir(node.absolute_path)
|
||||
if not success then
|
||||
return a.nvim_err_writeln("Could not remove " .. node.name)
|
||||
end
|
||||
events._dispatch_folder_removed(node.absolute_path)
|
||||
else
|
||||
local success = luv.fs_unlink(node.absolute_path)
|
||||
if not success then
|
||||
return a.nvim_err_writeln("Could not remove " .. node.name)
|
||||
end
|
||||
events._dispatch_file_removed(node.absolute_path)
|
||||
clear_buffer(node.absolute_path)
|
||||
end
|
||||
require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
45
bundle/nvim-tree.lua/lua/nvim-tree/actions/rename-file.lua
Normal file
45
bundle/nvim-tree.lua/lua/nvim-tree/actions/rename-file.lua
Normal file
@ -0,0 +1,45 @@
|
||||
local a = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local lib = require "nvim-tree.lib"
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.fn(with_sub)
|
||||
return function(node)
|
||||
node = lib.get_last_group_node(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
local namelen = node.name:len()
|
||||
local abs_path = with_sub and node.absolute_path:sub(0, namelen * -1 - 1) or node.absolute_path
|
||||
|
||||
local input_opts = { prompt = "Rename to ", default = abs_path, completion = "file" }
|
||||
|
||||
vim.ui.input(input_opts, function(new_file_path)
|
||||
if not new_file_path then
|
||||
return
|
||||
end
|
||||
|
||||
if utils.file_exists(new_file_path) then
|
||||
utils.warn "Cannot rename: file already exists"
|
||||
return
|
||||
end
|
||||
|
||||
local success = uv.fs_rename(node.absolute_path, new_file_path)
|
||||
if not success then
|
||||
return a.nvim_err_writeln("Could not rename " .. node.absolute_path .. " to " .. new_file_path)
|
||||
end
|
||||
utils.clear_prompt()
|
||||
a.nvim_out_write(node.absolute_path .. " ➜ " .. new_file_path .. "\n")
|
||||
utils.rename_loaded_buffers(node.absolute_path, new_file_path)
|
||||
events._dispatch_node_renamed(abs_path, new_file_path)
|
||||
require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
22
bundle/nvim-tree.lua/lua/nvim-tree/actions/run-command.lua
Normal file
22
bundle/nvim-tree.lua/lua/nvim-tree/actions/run-command.lua
Normal file
@ -0,0 +1,22 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {}
|
||||
|
||||
---Retrieves the absolute path to the node.
|
||||
---Safely handles the node representing the current directory
|
||||
---(the topmost node in the nvim-tree window)
|
||||
local function get_node_path(node)
|
||||
if node.name == ".." then
|
||||
return utils.path_remove_trailing(core.get_cwd())
|
||||
else
|
||||
return node.absolute_path
|
||||
end
|
||||
end
|
||||
|
||||
function M.run_file_command(node)
|
||||
local node_path = get_node_path(node)
|
||||
vim.api.nvim_input(": " .. node_path .. "<Home>")
|
||||
end
|
||||
|
||||
return M
|
79
bundle/nvim-tree.lua/lua/nvim-tree/actions/search-node.lua
Normal file
79
bundle/nvim-tree.lua/lua/nvim-tree/actions/search-node.lua
Normal file
@ -0,0 +1,79 @@
|
||||
local api = vim.api
|
||||
local uv = vim.loop
|
||||
local utils = require "nvim-tree.utils"
|
||||
local core = require "nvim-tree.core"
|
||||
local filters = require "nvim-tree.explorer.filters"
|
||||
local find_file = require("nvim-tree.actions.find-file").fn
|
||||
|
||||
local M = {}
|
||||
|
||||
local function search(dir, input_path)
|
||||
local path, name, stat, handle, _
|
||||
|
||||
if not dir then
|
||||
return
|
||||
end
|
||||
|
||||
handle, _ = uv.fs_scandir(dir)
|
||||
if not handle then
|
||||
return
|
||||
end
|
||||
|
||||
name, _ = uv.fs_scandir_next(handle)
|
||||
while name do
|
||||
path = dir .. "/" .. name
|
||||
|
||||
stat, _ = uv.fs_stat(path)
|
||||
if not stat then
|
||||
break
|
||||
end
|
||||
|
||||
if not filters.should_ignore(path) then
|
||||
if string.find(path, "/" .. input_path .. "$") then
|
||||
return path
|
||||
end
|
||||
|
||||
if stat.type == "directory" then
|
||||
path = search(path, input_path)
|
||||
if path then
|
||||
return path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
name, _ = uv.fs_scandir_next(handle)
|
||||
end
|
||||
end
|
||||
|
||||
function M.fn()
|
||||
if not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
|
||||
-- temporarily set &path
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local path_existed, path_opt = pcall(api.nvim_buf_get_option, bufnr, "path")
|
||||
api.nvim_buf_set_option(bufnr, "path", core.get_cwd() .. "/**")
|
||||
|
||||
-- completes files/dirs under cwd
|
||||
local input_path = vim.fn.input("Search: ", "", "file_in_path")
|
||||
utils.clear_prompt()
|
||||
|
||||
-- reset &path
|
||||
if path_existed then
|
||||
api.nvim_buf_set_option(bufnr, "path", path_opt)
|
||||
else
|
||||
api.nvim_buf_set_option(bufnr, "path", nil)
|
||||
end
|
||||
|
||||
-- strip trailing slash
|
||||
input_path = string.gsub(input_path, "/$", "")
|
||||
|
||||
-- search under cwd
|
||||
local found = search(core.get_cwd(), input_path)
|
||||
if found then
|
||||
find_file(found)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
70
bundle/nvim-tree.lua/lua/nvim-tree/actions/system-open.lua
Normal file
70
bundle/nvim-tree.lua/lua/nvim-tree/actions/system-open.lua
Normal file
@ -0,0 +1,70 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local M = {
|
||||
config = {
|
||||
is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1,
|
||||
is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1,
|
||||
is_unix = vim.fn.has "unix" == 1,
|
||||
},
|
||||
}
|
||||
|
||||
function M.fn(node)
|
||||
if #M.config.system_open.cmd == 0 then
|
||||
require("nvim-tree.utils").warn "Cannot open file with system application. Unrecognized platform."
|
||||
return
|
||||
end
|
||||
|
||||
local process = {
|
||||
cmd = M.config.system_open.cmd,
|
||||
args = M.config.system_open.args,
|
||||
errors = "\n",
|
||||
stderr = uv.new_pipe(false),
|
||||
}
|
||||
table.insert(process.args, node.link_to or node.absolute_path)
|
||||
process.handle, process.pid = uv.spawn(
|
||||
process.cmd,
|
||||
{ args = process.args, stdio = { nil, nil, process.stderr }, detached = true },
|
||||
function(code)
|
||||
process.stderr:read_stop()
|
||||
process.stderr:close()
|
||||
process.handle:close()
|
||||
if code ~= 0 then
|
||||
process.errors = process.errors .. string.format("NvimTree system_open: return code %d.", code)
|
||||
error(process.errors)
|
||||
end
|
||||
end
|
||||
)
|
||||
table.remove(process.args)
|
||||
if not process.handle then
|
||||
error("\n" .. process.pid .. "\nNvimTree system_open: failed to spawn process using '" .. process.cmd .. "'.")
|
||||
return
|
||||
end
|
||||
uv.read_start(process.stderr, function(err, data)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
if data then
|
||||
process.errors = process.errors .. data
|
||||
end
|
||||
end)
|
||||
uv.unref(process.handle)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config.system_open = opts or {}
|
||||
|
||||
if #M.config.system_open.cmd == 0 then
|
||||
if M.config.is_windows then
|
||||
M.config.system_open = {
|
||||
cmd = "cmd",
|
||||
args = { "/c", "start", '""' },
|
||||
}
|
||||
elseif M.config.is_macos then
|
||||
M.config.system_open.cmd = "open"
|
||||
elseif M.config.is_unix then
|
||||
M.config.system_open.cmd = "xdg-open"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
28
bundle/nvim-tree.lua/lua/nvim-tree/actions/toggles.lua
Normal file
28
bundle/nvim-tree.lua/lua/nvim-tree/actions/toggles.lua
Normal file
@ -0,0 +1,28 @@
|
||||
local view = require "nvim-tree.view"
|
||||
local filters = require "nvim-tree.explorer.filters"
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local reloaders = require "nvim-tree.actions.reloaders"
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.custom()
|
||||
filters.config.filter_custom = not filters.config.filter_custom
|
||||
return reloaders.reload_explorer()
|
||||
end
|
||||
|
||||
function M.git_ignored()
|
||||
filters.config.filter_git_ignored = not filters.config.filter_git_ignored
|
||||
return reloaders.reload_explorer()
|
||||
end
|
||||
|
||||
function M.dotfiles()
|
||||
filters.config.filter_dotfiles = not filters.config.filter_dotfiles
|
||||
return reloaders.reload_explorer()
|
||||
end
|
||||
|
||||
function M.help()
|
||||
view.toggle_help()
|
||||
renderer.draw()
|
||||
end
|
||||
|
||||
return M
|
90
bundle/nvim-tree.lua/lua/nvim-tree/actions/trash.lua
Normal file
90
bundle/nvim-tree.lua/lua/nvim-tree/actions/trash.lua
Normal file
@ -0,0 +1,90 @@
|
||||
local a = vim.api
|
||||
|
||||
local M = {
|
||||
config = {
|
||||
is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1,
|
||||
is_macos = vim.fn.has "mac" == 1 or vim.fn.has "macunix" == 1,
|
||||
is_unix = vim.fn.has "unix" == 1,
|
||||
},
|
||||
}
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local events = require "nvim-tree.events"
|
||||
|
||||
local function clear_buffer(absolute_path)
|
||||
local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 }
|
||||
for _, buf in pairs(bufs) do
|
||||
if buf.name == absolute_path then
|
||||
if buf.hidden == 0 and #bufs > 1 then
|
||||
local winnr = a.nvim_get_current_win()
|
||||
a.nvim_set_current_win(buf.windows[1])
|
||||
vim.cmd ":bn"
|
||||
a.nvim_set_current_win(winnr)
|
||||
end
|
||||
vim.api.nvim_buf_delete(buf.bufnr, {})
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.fn(node)
|
||||
if node.name == ".." then
|
||||
return
|
||||
end
|
||||
|
||||
-- configs
|
||||
if M.config.is_unix then
|
||||
if M.config.trash.cmd == nil then
|
||||
M.config.trash.cmd = "trash"
|
||||
end
|
||||
if M.config.trash.require_confirm == nil then
|
||||
M.config.trash.require_confirm = true
|
||||
end
|
||||
else
|
||||
utils.warn "Trash is currently a UNIX only feature!"
|
||||
return
|
||||
end
|
||||
|
||||
-- trashes a path (file or folder)
|
||||
local function trash_path(on_exit)
|
||||
vim.fn.jobstart(M.config.trash.cmd .. ' "' .. node.absolute_path .. '"', {
|
||||
detach = true,
|
||||
on_exit = on_exit,
|
||||
})
|
||||
end
|
||||
|
||||
local is_confirmed = true
|
||||
|
||||
-- confirmation prompt
|
||||
if M.config.trash.require_confirm then
|
||||
is_confirmed = false
|
||||
print("Trash " .. node.name .. " ? y/n")
|
||||
local ans = utils.get_user_input_char()
|
||||
if ans:match "^y" then
|
||||
is_confirmed = true
|
||||
end
|
||||
utils.clear_prompt()
|
||||
end
|
||||
|
||||
-- trashing
|
||||
if is_confirmed then
|
||||
if node.nodes ~= nil and not node.link_to then
|
||||
trash_path(function()
|
||||
events._dispatch_folder_removed(node.absolute_path)
|
||||
require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
end)
|
||||
else
|
||||
trash_path(function()
|
||||
events._dispatch_file_removed(node.absolute_path)
|
||||
clear_buffer(node.absolute_path)
|
||||
require("nvim-tree.actions.reloaders").reload_explorer()
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config.trash = opts or {}
|
||||
end
|
||||
|
||||
return M
|
102
bundle/nvim-tree.lua/lua/nvim-tree/colors.lua
Normal file
102
bundle/nvim-tree.lua/lua/nvim-tree/colors.lua
Normal file
@ -0,0 +1,102 @@
|
||||
local api = vim.api
|
||||
local icons = require "nvim-tree.renderer.icon-config"
|
||||
|
||||
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 },
|
||||
|
||||
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" },
|
||||
}
|
||||
end
|
||||
|
||||
local function get_links()
|
||||
return {
|
||||
FolderName = "Directory",
|
||||
EmptyFolderName = "Directory",
|
||||
OpenedFolderName = "Directory",
|
||||
Normal = "Normal",
|
||||
NormalNC = "NvimTreeNormal",
|
||||
EndOfBuffer = "EndOfBuffer",
|
||||
CursorLine = "CursorLine",
|
||||
VertSplit = "VertSplit",
|
||||
WinSeparator = "NvimTreeVertSplit",
|
||||
CursorColumn = "CursorColumn",
|
||||
FileDirty = "NvimTreeGitDirty",
|
||||
FileNew = "NvimTreeGitNew",
|
||||
FileRenamed = "NvimTreeGitRenamed",
|
||||
FileMerge = "NvimTreeGitMerge",
|
||||
FileStaged = "NvimTreeGitStaged",
|
||||
FileDeleted = "NvimTreeGitDeleted",
|
||||
Popup = "Normal",
|
||||
GitIgnored = "Comment",
|
||||
StatusLine = "StatusLine",
|
||||
StatusLineNC = "StatusLineNC",
|
||||
SignColumn = "NvimTreeNormal",
|
||||
}
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
if icons.get_config().show_file_icon and icons.get_config().has_devicons then
|
||||
require("nvim-web-devicons").setup()
|
||||
end
|
||||
local higlight_groups = get_hl_groups()
|
||||
for k, d in pairs(higlight_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 ""
|
||||
api.nvim_command("hi def NvimTree" .. k .. gui .. fg .. bg)
|
||||
end
|
||||
|
||||
local links = get_links()
|
||||
for k, d in pairs(links) do
|
||||
api.nvim_command("hi def link NvimTree" .. k .. " " .. d)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
10
bundle/nvim-tree.lua/lua/nvim-tree/config.lua
Normal file
10
bundle/nvim-tree.lua/lua/nvim-tree/config.lua
Normal file
@ -0,0 +1,10 @@
|
||||
-- INFO: DEPRECATED FILE, DO NOT ADD ANYTHING IN THERE
|
||||
-- keeping to avoid breaking user configs. Will remove during a weekend.
|
||||
local M = {}
|
||||
|
||||
-- TODO: remove this once the cb property is not supported in mappings
|
||||
function M.nvim_tree_callback(callback_name)
|
||||
return string.format(":lua require'nvim-tree.actions'.on_keypress('%s')<CR>", callback_name)
|
||||
end
|
||||
|
||||
return M
|
34
bundle/nvim-tree.lua/lua/nvim-tree/core.lua
Normal file
34
bundle/nvim-tree.lua/lua/nvim-tree/core.lua
Normal file
@ -0,0 +1,34 @@
|
||||
local events = require "nvim-tree.events"
|
||||
local explorer = require "nvim-tree.explorer"
|
||||
local view = require "nvim-tree.view"
|
||||
|
||||
local M = {}
|
||||
|
||||
TreeExplorer = nil
|
||||
local first_init_done = false
|
||||
|
||||
function M.init(foldername)
|
||||
TreeExplorer = explorer.Explorer.new(foldername)
|
||||
if not first_init_done then
|
||||
events._dispatch_ready()
|
||||
first_init_done = true
|
||||
end
|
||||
end
|
||||
|
||||
function M.get_explorer()
|
||||
return TreeExplorer
|
||||
end
|
||||
|
||||
function M.get_cwd()
|
||||
return TreeExplorer.cwd
|
||||
end
|
||||
|
||||
function M.get_nodes_starting_line()
|
||||
local offset = 1
|
||||
if view.is_root_folder_visible(M.get_cwd()) then
|
||||
offset = offset + 1
|
||||
end
|
||||
return offset
|
||||
end
|
||||
|
||||
return M
|
178
bundle/nvim-tree.lua/lua/nvim-tree/diagnostics.lua
Normal file
178
bundle/nvim-tree.lua/lua/nvim-tree/diagnostics.lua
Normal file
@ -0,0 +1,178 @@
|
||||
local a = vim.api
|
||||
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 GROUP = "NvimTreeDiagnosticSigns"
|
||||
|
||||
local function get_lowest_severity(diagnostics)
|
||||
local severity = math.huge
|
||||
for _, v in ipairs(diagnostics) do
|
||||
if v.severity < severity then
|
||||
severity = v.severity
|
||||
end
|
||||
end
|
||||
return severity
|
||||
end
|
||||
|
||||
local severity_levels = { Error = 1, Warning = 2, Information = 3, Hint = 4 }
|
||||
local sign_names = {
|
||||
{ "NvimTreeSignError", "NvimTreeLspDiagnosticsError" },
|
||||
{ "NvimTreeSignWarning", "NvimTreeLspDiagnosticsWarning" },
|
||||
{ "NvimTreeSignInformation", "NvimTreeLspDiagnosticsInformation" },
|
||||
{ "NvimTreeSignHint", "NvimTreeLspDiagnosticsHint" },
|
||||
}
|
||||
|
||||
local function add_sign(linenr, severity)
|
||||
local buf = view.get_bufnr()
|
||||
if not a.nvim_buf_is_valid(buf) or not a.nvim_buf_is_loaded(buf) then
|
||||
return
|
||||
end
|
||||
local sign_name = sign_names[severity][1]
|
||||
vim.fn.sign_place(1, GROUP, sign_name, buf, { lnum = linenr + 1 })
|
||||
end
|
||||
|
||||
local function from_nvim_lsp()
|
||||
local buffer_severity = {}
|
||||
|
||||
-- vim.lsp.diagnostic.get_all was deprecated in nvim 0.7 and replaced with vim.diagnostic.get
|
||||
-- This conditional can be removed when the minimum required version of nvim is changed to 0.7.
|
||||
if vim.diagnostic then
|
||||
-- nvim version >= 0.7
|
||||
for _, diagnostic in ipairs(vim.diagnostic.get()) do
|
||||
local buf = diagnostic.bufnr
|
||||
if a.nvim_buf_is_valid(buf) then
|
||||
local bufname = a.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
|
||||
end
|
||||
end
|
||||
else
|
||||
-- nvim version < 0.7
|
||||
for buf, diagnostics in pairs(vim.lsp.diagnostic.get_all()) do
|
||||
if a.nvim_buf_is_valid(buf) then
|
||||
local bufname = a.nvim_buf_get_name(buf)
|
||||
if not buffer_severity[bufname] then
|
||||
local severity = get_lowest_severity(diagnostics)
|
||||
buffer_severity[bufname] = severity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return buffer_severity
|
||||
end
|
||||
|
||||
local function from_coc()
|
||||
if vim.g.coc_service_initialized ~= 1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local diagnostic_list = vim.fn.CocAction "diagnosticList"
|
||||
if type(diagnostic_list) ~= "table" or vim.tbl_isempty(diagnostic_list) then
|
||||
return {}
|
||||
end
|
||||
|
||||
local buffer_severity = {}
|
||||
local diagnostics = {}
|
||||
|
||||
for _, diagnostic in ipairs(diagnostic_list) do
|
||||
local bufname = diagnostic.file
|
||||
local severity = severity_levels[diagnostic.severity]
|
||||
|
||||
local severity_list = diagnostics[bufname] or {}
|
||||
table.insert(severity_list, severity)
|
||||
diagnostics[bufname] = severity_list
|
||||
end
|
||||
|
||||
for bufname, severity_list in pairs(diagnostics) do
|
||||
if not buffer_severity[bufname] then
|
||||
local severity = math.min(unpack(severity_list))
|
||||
buffer_severity[bufname] = severity
|
||||
end
|
||||
end
|
||||
|
||||
return buffer_severity
|
||||
end
|
||||
|
||||
local function is_using_coc()
|
||||
return vim.g.coc_service_initialized == 1
|
||||
end
|
||||
|
||||
function M.clear()
|
||||
if not M.enable or not view.is_buf_valid(view.get_bufnr()) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.fn.sign_unplace(GROUP)
|
||||
end
|
||||
|
||||
function M.update()
|
||||
if not M.enable or not core.get_explorer() or not view.is_buf_valid(view.get_bufnr()) then
|
||||
return
|
||||
end
|
||||
local ps = log.profile_start "diagnostics update"
|
||||
log.line("diagnostics", "update")
|
||||
|
||||
local buffer_severity
|
||||
if is_using_coc() then
|
||||
buffer_severity = from_coc()
|
||||
else
|
||||
buffer_severity = from_nvim_lsp()
|
||||
end
|
||||
|
||||
M.clear()
|
||||
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
|
||||
local node, line = utils.find_node(core.get_explorer().nodes, function(node)
|
||||
local nodepath = utils.canonical_path(node.absolute_path)
|
||||
log.line("diagnostics", " checking nodepath '%s'", nodepath)
|
||||
if M.show_on_dirs and not node.open then
|
||||
return vim.startswith(bufpath, nodepath)
|
||||
else
|
||||
return nodepath == bufpath
|
||||
end
|
||||
end)
|
||||
if node then
|
||||
log.line("diagnostics", " matched node '%s'", node.absolute_path)
|
||||
add_sign(line, severity)
|
||||
end
|
||||
end
|
||||
end
|
||||
log.profile_end(ps, "diagnostics update")
|
||||
end
|
||||
|
||||
local links = {
|
||||
NvimTreeLspDiagnosticsError = "DiagnosticError",
|
||||
NvimTreeLspDiagnosticsWarning = "DiagnosticWarn",
|
||||
NvimTreeLspDiagnosticsInformation = "DiagnosticInfo",
|
||||
NvimTreeLspDiagnosticsHint = "DiagnosticHint",
|
||||
}
|
||||
|
||||
function M.setup(opts)
|
||||
M.enable = opts.diagnostics.enable
|
||||
M.show_on_dirs = opts.diagnostics.show_on_dirs
|
||||
vim.fn.sign_define(sign_names[1][1], { text = opts.diagnostics.icons.error, texthl = sign_names[1][2] })
|
||||
vim.fn.sign_define(sign_names[2][1], { text = opts.diagnostics.icons.warning, texthl = sign_names[2][2] })
|
||||
vim.fn.sign_define(sign_names[3][1], { text = opts.diagnostics.icons.info, texthl = sign_names[3][2] })
|
||||
vim.fn.sign_define(sign_names[4][1], { text = opts.diagnostics.icons.hint, texthl = sign_names[4][2] })
|
||||
|
||||
for lhs, rhs in pairs(links) do
|
||||
vim.cmd("hi def link " .. lhs .. " " .. rhs)
|
||||
end
|
||||
|
||||
if M.enable then
|
||||
log.line("diagnostics", "setup")
|
||||
vim.cmd "au DiagnosticChanged * lua require'nvim-tree.diagnostics'.update()"
|
||||
vim.cmd "au User CocDiagnosticChange lua require'nvim-tree.diagnostics'.update()"
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
129
bundle/nvim-tree.lua/lua/nvim-tree/events.lua
Normal file
129
bundle/nvim-tree.lua/lua/nvim-tree/events.lua
Normal file
@ -0,0 +1,129 @@
|
||||
local M = {}
|
||||
|
||||
local global_handlers = {}
|
||||
|
||||
local Event = {
|
||||
Ready = "Ready",
|
||||
NodeRenamed = "NodeRenamed",
|
||||
TreeOpen = "TreeOpen",
|
||||
TreeClose = "TreeClose",
|
||||
FileCreated = "FileCreated",
|
||||
FileRemoved = "FileRemoved",
|
||||
FolderCreated = "FolderCreated",
|
||||
FolderRemoved = "FolderRemoved",
|
||||
}
|
||||
|
||||
local function get_handlers(event_name)
|
||||
return global_handlers[event_name] or {}
|
||||
end
|
||||
|
||||
local function register_handler(event_name, handler)
|
||||
local handlers = get_handlers(event_name)
|
||||
table.insert(handlers, handler)
|
||||
global_handlers[event_name] = handlers
|
||||
end
|
||||
|
||||
local function dispatch(event_name, payload)
|
||||
for _, handler in pairs(get_handlers(event_name)) do
|
||||
local success, error = pcall(handler, payload)
|
||||
if not success then
|
||||
vim.api.nvim_err_writeln("Handler for event " .. event_name .. " errored. " .. vim.inspect(error))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_ready()
|
||||
dispatch(Event.Ready)
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_node_renamed(old_name, new_name)
|
||||
dispatch(Event.NodeRenamed, { old_name = old_name, new_name = new_name })
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_file_removed(fname)
|
||||
dispatch(Event.FileRemoved, { fname = fname })
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_file_created(fname)
|
||||
dispatch(Event.FileCreated, { fname = fname })
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_folder_created(folder_name)
|
||||
dispatch(Event.FolderCreated, { folder_name = folder_name })
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_folder_removed(folder_name)
|
||||
dispatch(Event.FolderRemoved, { folder_name = folder_name })
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_on_tree_open()
|
||||
dispatch(Event.TreeOpen, nil)
|
||||
end
|
||||
|
||||
--@private
|
||||
function M._dispatch_on_tree_close()
|
||||
dispatch(Event.TreeClose, nil)
|
||||
end
|
||||
|
||||
--Registers a handler for the Ready event.
|
||||
--@param handler (function) Handler with the signature `function()`
|
||||
function M.on_nvim_tree_ready(handler)
|
||||
register_handler(Event.Ready, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the NodeRenamed event.
|
||||
--@param handler (function) Handler with the signature function(payload), where payload is a table containing:
|
||||
-- - old_name (string) Absolute path to the old node location.
|
||||
-- - new_name (string) Absolute path to the new node location.
|
||||
function M.on_node_renamed(handler)
|
||||
register_handler(Event.NodeRenamed, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the FileCreated event.
|
||||
--@param handler (function) Handler with the signature function(payload), where payload is a table containing:
|
||||
-- - fname (string) Absolute path to the created file.
|
||||
function M.on_file_created(handler)
|
||||
register_handler(Event.FileCreated, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the FileRemoved event.
|
||||
--@param handler (function) Handler with the signature function(payload), where payload is a table containing:
|
||||
-- - fname (string) Absolute path to the removed file.
|
||||
function M.on_file_removed(handler)
|
||||
register_handler(Event.FileRemoved, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the FolderCreated event.
|
||||
--@param handler (function) Handler with the signature function(payload), where payload is a table containing:
|
||||
-- - folder_name (string) Absolute path to the created folder.
|
||||
function M.on_folder_created(handler)
|
||||
register_handler(Event.FolderCreated, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the FolderRemoved event.
|
||||
--@param handler (function) Handler with the signature function(payload), where payload is a table containing:
|
||||
-- - folder_name (string) Absolute path to the removed folder.
|
||||
function M.on_folder_removed(handler)
|
||||
register_handler(Event.FolderRemoved, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the TreeOpen event.
|
||||
--@param handler (function) Handler with the signature function(payload)
|
||||
function M.on_tree_open(handler)
|
||||
register_handler(Event.TreeOpen, handler)
|
||||
end
|
||||
|
||||
--Registers a handler for the TreeClose event.
|
||||
--@param handler (function) Handler with the signature function(payload)
|
||||
function M.on_tree_close(handler)
|
||||
register_handler(Event.TreeClose, handler)
|
||||
end
|
||||
|
||||
return M
|
9
bundle/nvim-tree.lua/lua/nvim-tree/explorer/common.lua
Normal file
9
bundle/nvim-tree.lua/lua/nvim-tree/explorer/common.lua
Normal file
@ -0,0 +1,9 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.has_one_child_folder(node)
|
||||
return #node.nodes == 1 and node.nodes[1].nodes and uv.fs_access(node.nodes[1].absolute_path, "R")
|
||||
end
|
||||
|
||||
return M
|
77
bundle/nvim-tree.lua/lua/nvim-tree/explorer/explore.lua
Normal file
77
bundle/nvim-tree.lua/lua/nvim-tree/explorer/explore.lua
Normal file
@ -0,0 +1,77 @@
|
||||
local api = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local builders = require "nvim-tree.explorer.node-builders"
|
||||
local common = require "nvim-tree.explorer.common"
|
||||
local sorters = require "nvim-tree.explorer.sorters"
|
||||
local filters = require "nvim-tree.explorer.filters"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function get_type_from(type_, cwd)
|
||||
return type_ or (uv.fs_stat(cwd) or {}).type
|
||||
end
|
||||
|
||||
local function populate_children(handle, cwd, node, status)
|
||||
local node_ignored = node.git_status == "!!"
|
||||
while true do
|
||||
local name, t = uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local nodes_by_path = utils.key_by(node.nodes, "absolute_path")
|
||||
local abs = utils.path_join { cwd, name }
|
||||
t = get_type_from(t, abs)
|
||||
if
|
||||
not filters.should_ignore(abs)
|
||||
and not filters.should_ignore_git(abs, status.files)
|
||||
and not nodes_by_path[abs]
|
||||
then
|
||||
if t == "directory" and uv.fs_access(abs, "R") then
|
||||
table.insert(node.nodes, builders.folder(node, abs, name, status, node_ignored))
|
||||
elseif t == "file" then
|
||||
table.insert(node.nodes, builders.file(node, abs, name, status, node_ignored))
|
||||
elseif t == "link" then
|
||||
local link = builders.link(node, abs, name, status, node_ignored)
|
||||
if link.link_to ~= nil then
|
||||
table.insert(node.nodes, link)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_dir_handle(cwd)
|
||||
local handle = uv.fs_scandir(cwd)
|
||||
if type(handle) == "string" then
|
||||
api.nvim_err_writeln(handle)
|
||||
return
|
||||
end
|
||||
return handle
|
||||
end
|
||||
|
||||
function M.explore(node, status)
|
||||
local cwd = node.cwd or node.link_to or node.absolute_path
|
||||
local handle = get_dir_handle(cwd)
|
||||
if not handle then
|
||||
return
|
||||
end
|
||||
|
||||
populate_children(handle, cwd, node, status)
|
||||
|
||||
local is_root = node.cwd ~= nil
|
||||
local child_folder_only = common.has_one_child_folder(node) and node.nodes[1]
|
||||
if vim.g.nvim_tree_group_empty == 1 and not is_root and child_folder_only then
|
||||
node.group_next = child_folder_only
|
||||
local ns = M.explore(child_folder_only, status)
|
||||
node.nodes = ns or {}
|
||||
return ns
|
||||
end
|
||||
|
||||
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
||||
return node.nodes
|
||||
end
|
||||
|
||||
return M
|
77
bundle/nvim-tree.lua/lua/nvim-tree/explorer/filters.lua
Normal file
77
bundle/nvim-tree.lua/lua/nvim-tree/explorer/filters.lua
Normal file
@ -0,0 +1,77 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local M = {
|
||||
ignore_list = {},
|
||||
exclude_list = {},
|
||||
}
|
||||
|
||||
local function is_excluded(path)
|
||||
for _, node in ipairs(M.exclude_list) do
|
||||
if path:match(node) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Check if the given path should be ignored.
|
||||
---@param path string Absolute path
|
||||
---@return boolean
|
||||
function M.should_ignore(path)
|
||||
local basename = utils.path_basename(path)
|
||||
|
||||
if is_excluded(path) then
|
||||
return false
|
||||
end
|
||||
|
||||
if M.config.filter_dotfiles then
|
||||
if basename:sub(1, 1) == "." then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if not M.config.filter_custom then
|
||||
return false
|
||||
end
|
||||
|
||||
local relpath = utils.path_relative(path, vim.loop.cwd())
|
||||
for pat, _ in pairs(M.ignore_list) do
|
||||
if vim.fn.match(relpath, pat) ~= -1 or vim.fn.match(basename, pat) ~= -1 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local idx = path:match ".+()%.[^.]+$"
|
||||
if idx then
|
||||
if M.ignore_list["*" .. string.sub(path, idx)] == true then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function M.should_ignore_git(path, status)
|
||||
return M.config.filter_git_ignored
|
||||
and (M.config.filter_git_ignored and status and status[path] == "!!")
|
||||
and not is_excluded(path)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = {
|
||||
filter_custom = true,
|
||||
filter_dotfiles = opts.filters.dotfiles,
|
||||
filter_git_ignored = opts.git.ignore,
|
||||
}
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
40
bundle/nvim-tree.lua/lua/nvim-tree/explorer/init.lua
Normal file
40
bundle/nvim-tree.lua/lua/nvim-tree/explorer/init.lua
Normal file
@ -0,0 +1,40 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local git = require "nvim-tree.git"
|
||||
|
||||
local M = {}
|
||||
|
||||
M.explore = require("nvim-tree.explorer.explore").explore
|
||||
M.reload = require("nvim-tree.explorer.reload").reload
|
||||
|
||||
local Explorer = {}
|
||||
Explorer.__index = Explorer
|
||||
|
||||
function Explorer.new(cwd)
|
||||
cwd = uv.fs_realpath(cwd or uv.cwd())
|
||||
local explorer = setmetatable({
|
||||
cwd = cwd,
|
||||
nodes = {},
|
||||
}, Explorer)
|
||||
explorer:_load(explorer)
|
||||
return explorer
|
||||
end
|
||||
|
||||
function Explorer:_load(node)
|
||||
local cwd = node.cwd or node.link_to or node.absolute_path
|
||||
local git_statuses = git.load_project_status(cwd)
|
||||
M.explore(node, git_statuses)
|
||||
end
|
||||
|
||||
function Explorer:expand(node)
|
||||
self:_load(node)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
require("nvim-tree.explorer.filters").setup(opts)
|
||||
require("nvim-tree.explorer.sorters").setup(opts)
|
||||
end
|
||||
|
||||
M.Explorer = Explorer
|
||||
|
||||
return M
|
@ -0,0 +1,89 @@
|
||||
local uv = vim.loop
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local M = {
|
||||
is_windows = vim.fn.has "win32" == 1,
|
||||
}
|
||||
|
||||
function M.get_dir_git_status(parent_ignored, status, absolute_path)
|
||||
if parent_ignored then
|
||||
return "!!"
|
||||
end
|
||||
local dir_status = status.dirs and status.dirs[absolute_path]
|
||||
local file_status = status.files and status.files[absolute_path]
|
||||
return dir_status or file_status
|
||||
end
|
||||
|
||||
function M.get_git_status(parent_ignored, status, absolute_path)
|
||||
return parent_ignored and "!!" or status.files and status.files[absolute_path]
|
||||
end
|
||||
|
||||
function M.folder(parent, absolute_path, name, status, parent_ignored)
|
||||
local handle = uv.fs_scandir(absolute_path)
|
||||
local has_children = handle and uv.fs_scandir_next(handle) ~= nil
|
||||
|
||||
return {
|
||||
absolute_path = absolute_path,
|
||||
fs_stat = uv.fs_stat(absolute_path),
|
||||
git_status = M.get_dir_git_status(parent_ignored, status, absolute_path),
|
||||
group_next = nil, -- If node is grouped, this points to the next child dir/link node
|
||||
has_children = has_children,
|
||||
name = name,
|
||||
nodes = {},
|
||||
open = false,
|
||||
parent = parent,
|
||||
}
|
||||
end
|
||||
|
||||
local function is_executable(absolute_path, ext)
|
||||
if M.is_windows then
|
||||
return utils.is_windows_exe(ext)
|
||||
end
|
||||
return uv.fs_access(absolute_path, "X")
|
||||
end
|
||||
|
||||
function M.file(parent, absolute_path, name, status, parent_ignored)
|
||||
local ext = string.match(name, ".?[^.]+%.(.*)") or ""
|
||||
|
||||
return {
|
||||
absolute_path = absolute_path,
|
||||
executable = is_executable(absolute_path, ext),
|
||||
extension = ext,
|
||||
fs_stat = uv.fs_stat(absolute_path),
|
||||
git_status = M.get_git_status(parent_ignored, status, absolute_path),
|
||||
name = name,
|
||||
parent = parent,
|
||||
}
|
||||
end
|
||||
|
||||
-- TODO-INFO: sometimes fs_realpath returns nil
|
||||
-- I expect this be a bug in glibc, because it fails to retrieve the path for some
|
||||
-- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails
|
||||
-- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong.
|
||||
-- So we need to check for link_to ~= nil when adding new links to the main tree
|
||||
function M.link(parent, absolute_path, name, status, parent_ignored)
|
||||
--- I dont know if this is needed, because in my understanding, there isnt hard links in windows, but just to be sure i changed it.
|
||||
local link_to = uv.fs_realpath(absolute_path)
|
||||
local open, nodes, has_children
|
||||
if (link_to ~= nil) and uv.fs_stat(link_to).type == "directory" then
|
||||
local handle = uv.fs_scandir(link_to)
|
||||
has_children = handle and uv.fs_scandir_next(handle) ~= nil
|
||||
open = false
|
||||
nodes = {}
|
||||
end
|
||||
|
||||
return {
|
||||
absolute_path = absolute_path,
|
||||
fs_stat = uv.fs_stat(absolute_path),
|
||||
git_status = M.get_git_status(parent_ignored, status, absolute_path),
|
||||
group_next = nil, -- If node is grouped, this points to the next child dir/link node
|
||||
has_children = has_children,
|
||||
link_to = link_to,
|
||||
name = name,
|
||||
nodes = nodes,
|
||||
open = open,
|
||||
parent = parent,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
87
bundle/nvim-tree.lua/lua/nvim-tree/explorer/reload.lua
Normal file
87
bundle/nvim-tree.lua/lua/nvim-tree/explorer/reload.lua
Normal file
@ -0,0 +1,87 @@
|
||||
local api = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local utils = require "nvim-tree.utils"
|
||||
local builders = require "nvim-tree.explorer.node-builders"
|
||||
local common = require "nvim-tree.explorer.common"
|
||||
local filters = require "nvim-tree.explorer.filters"
|
||||
local sorters = require "nvim-tree.explorer.sorters"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function update_status(nodes_by_path, node_ignored, status)
|
||||
return function(node)
|
||||
if nodes_by_path[node.absolute_path] then
|
||||
if node.nodes then
|
||||
node.git_status = builders.get_dir_git_status(node_ignored, status, node.absolute_path)
|
||||
else
|
||||
node.git_status = builders.get_git_status(node_ignored, status, node.absolute_path)
|
||||
end
|
||||
end
|
||||
return node
|
||||
end
|
||||
end
|
||||
|
||||
function M.reload(node, status)
|
||||
local cwd = node.cwd or node.link_to or node.absolute_path
|
||||
local handle = uv.fs_scandir(cwd)
|
||||
if type(handle) == "string" then
|
||||
api.nvim_err_writeln(handle)
|
||||
return
|
||||
end
|
||||
|
||||
if node.group_next then
|
||||
node.nodes = { node.group_next }
|
||||
node.group_next = nil
|
||||
end
|
||||
|
||||
local child_names = {}
|
||||
|
||||
local node_ignored = node.git_status == "!!"
|
||||
local nodes_by_path = utils.key_by(node.nodes, "absolute_path")
|
||||
while true do
|
||||
local name, t = uv.fs_scandir_next(handle)
|
||||
if not name then
|
||||
break
|
||||
end
|
||||
|
||||
local abs = utils.path_join { cwd, name }
|
||||
t = t or (uv.fs_stat(abs) or {}).type
|
||||
if not filters.should_ignore(abs) and not filters.should_ignore_git(abs, status.files) then
|
||||
child_names[abs] = true
|
||||
if not nodes_by_path[abs] then
|
||||
if t == "directory" and uv.fs_access(abs, "R") then
|
||||
table.insert(node.nodes, builders.folder(node, abs, name, status, node_ignored))
|
||||
elseif t == "file" then
|
||||
table.insert(node.nodes, builders.file(node, abs, name, status, node_ignored))
|
||||
elseif t == "link" then
|
||||
local link = builders.link(node, abs, name, status, node_ignored)
|
||||
if link.link_to ~= nil then
|
||||
table.insert(node.nodes, link)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
node.nodes = vim.tbl_map(
|
||||
update_status(nodes_by_path, node_ignored, status),
|
||||
vim.tbl_filter(function(n)
|
||||
return child_names[n.absolute_path]
|
||||
end, node.nodes)
|
||||
)
|
||||
|
||||
local is_root = node.cwd ~= nil
|
||||
local child_folder_only = common.has_one_child_folder(node) and node.nodes[1]
|
||||
if vim.g.nvim_tree_group_empty == 1 and not is_root and child_folder_only then
|
||||
node.group_next = child_folder_only
|
||||
local ns = M.reload(child_folder_only, status)
|
||||
node.nodes = ns or {}
|
||||
return ns
|
||||
end
|
||||
|
||||
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
||||
return node.nodes
|
||||
end
|
||||
|
||||
return M
|
138
bundle/nvim-tree.lua/lua/nvim-tree/explorer/sorters.lua
Normal file
138
bundle/nvim-tree.lua/lua/nvim-tree/explorer/sorters.lua
Normal file
@ -0,0 +1,138 @@
|
||||
local M = {
|
||||
sort_by = nil,
|
||||
node_comparator = nil,
|
||||
}
|
||||
|
||||
---Create a shallow copy of a portion of a list.
|
||||
---@param t table
|
||||
---@param first integer First index, inclusive
|
||||
---@param last integer Last index, inclusive
|
||||
---@return table
|
||||
local function tbl_slice(t, first, last)
|
||||
local slice = {}
|
||||
for i = first, last or #t, 1 do
|
||||
table.insert(slice, t[i])
|
||||
end
|
||||
|
||||
return slice
|
||||
end
|
||||
|
||||
local function merge(t, first, mid, last, comparator)
|
||||
local n1 = mid - first + 1
|
||||
local n2 = last - mid
|
||||
local ls = tbl_slice(t, first, mid)
|
||||
local rs = tbl_slice(t, mid + 1, last)
|
||||
local i = 1
|
||||
local j = 1
|
||||
local k = first
|
||||
|
||||
while i <= n1 and j <= n2 do
|
||||
if comparator(ls[i], rs[j]) then
|
||||
t[k] = ls[i]
|
||||
i = i + 1
|
||||
else
|
||||
t[k] = rs[j]
|
||||
j = j + 1
|
||||
end
|
||||
k = k + 1
|
||||
end
|
||||
|
||||
while i <= n1 do
|
||||
t[k] = ls[i]
|
||||
i = i + 1
|
||||
k = k + 1
|
||||
end
|
||||
|
||||
while j <= n2 do
|
||||
t[k] = rs[j]
|
||||
j = j + 1
|
||||
k = k + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function split_merge(t, first, last, comparator)
|
||||
if (last - first) < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local mid = math.floor((first + last) / 2)
|
||||
|
||||
split_merge(t, first, mid, comparator)
|
||||
split_merge(t, mid + 1, last, comparator)
|
||||
merge(t, first, mid, last, comparator)
|
||||
end
|
||||
|
||||
---Perform a merge sort on a given list.
|
||||
---@param t any[]
|
||||
---@param comparator function|nil
|
||||
function M.merge_sort(t, comparator)
|
||||
if not comparator then
|
||||
comparator = function(left, right)
|
||||
return left < right
|
||||
end
|
||||
end
|
||||
|
||||
split_merge(t, 1, #t, comparator)
|
||||
end
|
||||
|
||||
local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
if a.nodes and not b.nodes then
|
||||
return true
|
||||
elseif not a.nodes and b.nodes then
|
||||
return false
|
||||
end
|
||||
|
||||
if ignorecase then
|
||||
return a.name:lower() <= b.name:lower()
|
||||
else
|
||||
return a.name <= b.name
|
||||
end
|
||||
end
|
||||
|
||||
function M.node_comparator_name_case_sensisive(a, b)
|
||||
return node_comparator_name_ignorecase_or_not(a, b, false)
|
||||
end
|
||||
|
||||
function M.node_comparator_name_ignorecase(a, b)
|
||||
return node_comparator_name_ignorecase_or_not(a, b, true)
|
||||
end
|
||||
|
||||
function M.node_comparator_modification_time(a, b)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
if a.nodes and not b.nodes then
|
||||
return true
|
||||
elseif not a.nodes and b.nodes then
|
||||
return false
|
||||
end
|
||||
|
||||
local last_modified_a = 0
|
||||
local last_modified_b = 0
|
||||
|
||||
if a.fs_stat ~= nil then
|
||||
last_modified_a = a.fs_stat.mtime.sec
|
||||
end
|
||||
|
||||
if b.fs_stat ~= nil then
|
||||
last_modified_b = b.fs_stat.mtime.sec
|
||||
end
|
||||
|
||||
return last_modified_b <= last_modified_a
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.sort_by = opts.sort_by
|
||||
if M.sort_by == "modification_time" then
|
||||
M.node_comparator = M.node_comparator_modification_time
|
||||
elseif M.sort_by == "case_sensitive" then
|
||||
M.node_comparator = M.node_comparator_name_case_sensisive
|
||||
else
|
||||
M.node_comparator = M.node_comparator_name_ignorecase
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
78
bundle/nvim-tree.lua/lua/nvim-tree/git/init.lua
Normal file
78
bundle/nvim-tree.lua/lua/nvim-tree/git/init.lua
Normal file
@ -0,0 +1,78 @@
|
||||
local git_utils = require "nvim-tree.git.utils"
|
||||
local Runner = require "nvim-tree.git.runner"
|
||||
|
||||
local M = {
|
||||
config = nil,
|
||||
projects = {},
|
||||
cwd_to_project_root = {},
|
||||
}
|
||||
|
||||
function M.reload()
|
||||
if not M.config.enable then
|
||||
return {}
|
||||
end
|
||||
|
||||
for project_root in pairs(M.projects) do
|
||||
M.projects[project_root] = {}
|
||||
local git_status = Runner.run {
|
||||
project_root = project_root,
|
||||
list_untracked = git_utils.should_show_untracked(project_root),
|
||||
list_ignored = true,
|
||||
timeout = M.config.timeout,
|
||||
}
|
||||
M.projects[project_root] = {
|
||||
files = git_status,
|
||||
dirs = git_utils.file_status_to_dir_status(git_status, project_root),
|
||||
}
|
||||
end
|
||||
|
||||
return M.projects
|
||||
end
|
||||
|
||||
function M.get_project_root(cwd)
|
||||
if M.cwd_to_project_root[cwd] then
|
||||
return M.cwd_to_project_root[cwd]
|
||||
end
|
||||
|
||||
if M.cwd_to_project_root[cwd] == false then
|
||||
return nil
|
||||
end
|
||||
|
||||
local project_root = git_utils.get_toplevel(cwd)
|
||||
return project_root
|
||||
end
|
||||
|
||||
function M.load_project_status(cwd)
|
||||
if not M.config.enable then
|
||||
return {}
|
||||
end
|
||||
|
||||
local project_root = M.get_project_root(cwd)
|
||||
if not project_root then
|
||||
M.cwd_to_project_root[cwd] = false
|
||||
return {}
|
||||
end
|
||||
|
||||
local status = M.projects[project_root]
|
||||
if status then
|
||||
return status
|
||||
end
|
||||
|
||||
local git_status = Runner.run {
|
||||
project_root = project_root,
|
||||
list_untracked = git_utils.should_show_untracked(project_root),
|
||||
list_ignored = true,
|
||||
timeout = M.config.timeout,
|
||||
}
|
||||
M.projects[project_root] = {
|
||||
files = git_status,
|
||||
dirs = git_utils.file_status_to_dir_status(git_status, project_root),
|
||||
}
|
||||
return M.projects[project_root]
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts.git
|
||||
end
|
||||
|
||||
return M
|
158
bundle/nvim-tree.lua/lua/nvim-tree/git/runner.lua
Normal file
158
bundle/nvim-tree.lua/lua/nvim-tree/git/runner.lua
Normal file
@ -0,0 +1,158 @@
|
||||
local uv = vim.loop
|
||||
local log = require "nvim-tree.log"
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local Runner = {}
|
||||
Runner.__index = Runner
|
||||
|
||||
function Runner:_parse_status_output(line)
|
||||
local status = line:sub(1, 2)
|
||||
-- removing `"` when git is returning special file status containing spaces
|
||||
local path = line:sub(4, -2):gsub('^"', ""):gsub('"$', "")
|
||||
-- replacing slashes if on windows
|
||||
if vim.fn.has "win32" == 1 then
|
||||
path = path:gsub("/", "\\")
|
||||
end
|
||||
if #status > 0 and #path > 0 then
|
||||
self.output[utils.path_remove_trailing(utils.path_join { self.project_root, path })] = status
|
||||
end
|
||||
return #line
|
||||
end
|
||||
|
||||
function Runner:_handle_incoming_data(prev_output, incoming)
|
||||
if incoming and utils.str_find(incoming, "\n") then
|
||||
local prev = prev_output .. incoming
|
||||
local i = 1
|
||||
for line in prev:gmatch "[^\n]*\n" do
|
||||
i = i + self:_parse_status_output(line)
|
||||
end
|
||||
|
||||
return prev:sub(i, -1)
|
||||
end
|
||||
|
||||
if incoming then
|
||||
return prev_output .. incoming
|
||||
end
|
||||
|
||||
for line in prev_output:gmatch "[^\n]*\n" do
|
||||
self._parse_status_output(line)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function Runner:_getopts(stdout_handle, stderr_handle)
|
||||
local untracked = self.list_untracked and "-u" or nil
|
||||
local ignored = (self.list_untracked and self.list_ignored) and "--ignored=matching" or "--ignored=no"
|
||||
return {
|
||||
args = { "--no-optional-locks", "status", "--porcelain=v1", ignored, untracked },
|
||||
cwd = self.project_root,
|
||||
stdio = { nil, stdout_handle, stderr_handle },
|
||||
}
|
||||
end
|
||||
|
||||
function Runner:_log_raw_output(output)
|
||||
if output and type(output) == "string" then
|
||||
log.raw("git", "%s", output)
|
||||
end
|
||||
end
|
||||
|
||||
function Runner:_run_git_job()
|
||||
local handle, pid
|
||||
local stdout = uv.new_pipe(false)
|
||||
local stderr = uv.new_pipe(false)
|
||||
local timer = uv.new_timer()
|
||||
|
||||
local function on_finish(rc)
|
||||
self.rc = rc or 0
|
||||
if timer:is_closing() or stdout:is_closing() or stderr:is_closing() or (handle and handle:is_closing()) then
|
||||
return
|
||||
end
|
||||
timer:stop()
|
||||
timer:close()
|
||||
stdout:read_stop()
|
||||
stderr:read_stop()
|
||||
stdout:close()
|
||||
stderr:close()
|
||||
if handle then
|
||||
handle:close()
|
||||
end
|
||||
|
||||
pcall(uv.kill, pid)
|
||||
end
|
||||
|
||||
local opts = self:_getopts(stdout, stderr)
|
||||
log.line("git", "running job with timeout %dms", self.timeout)
|
||||
log.line("git", "git %s", table.concat(opts.args, " "))
|
||||
|
||||
handle, pid = uv.spawn(
|
||||
"git",
|
||||
opts,
|
||||
vim.schedule_wrap(function(rc)
|
||||
on_finish(rc)
|
||||
end)
|
||||
)
|
||||
|
||||
timer:start(
|
||||
self.timeout,
|
||||
0,
|
||||
vim.schedule_wrap(function()
|
||||
on_finish(-1)
|
||||
end)
|
||||
)
|
||||
|
||||
local output_leftover = ""
|
||||
local function manage_stdout(err, data)
|
||||
if err then
|
||||
return
|
||||
end
|
||||
self:_log_raw_output(data)
|
||||
output_leftover = self:_handle_incoming_data(output_leftover, data)
|
||||
end
|
||||
|
||||
local function manage_stderr(_, data)
|
||||
self:_log_raw_output(data)
|
||||
end
|
||||
|
||||
uv.read_start(stdout, vim.schedule_wrap(manage_stdout))
|
||||
uv.read_start(stderr, vim.schedule_wrap(manage_stderr))
|
||||
end
|
||||
|
||||
function Runner:_wait()
|
||||
local function is_done()
|
||||
return self.rc ~= nil
|
||||
end
|
||||
while not vim.wait(30, is_done) do
|
||||
end
|
||||
end
|
||||
|
||||
-- This module runs a git process, which will be killed if it takes more than timeout which defaults to 400ms
|
||||
function Runner.run(opts)
|
||||
local ps = log.profile_start("git job %s", opts.project_root)
|
||||
|
||||
local self = setmetatable({
|
||||
project_root = opts.project_root,
|
||||
list_untracked = opts.list_untracked,
|
||||
list_ignored = opts.list_ignored,
|
||||
timeout = opts.timeout or 400,
|
||||
output = {},
|
||||
rc = nil, -- -1 indicates timeout
|
||||
}, Runner)
|
||||
|
||||
self:_run_git_job()
|
||||
self:_wait()
|
||||
|
||||
log.profile_end(ps, "git job %s", opts.project_root)
|
||||
|
||||
if self.rc == -1 then
|
||||
log.line("git", "job timed out")
|
||||
elseif self.rc ~= 0 then
|
||||
log.line("git", "job failed with return code %d", self.rc)
|
||||
else
|
||||
log.line("git", "job success")
|
||||
end
|
||||
|
||||
return self.output
|
||||
end
|
||||
|
||||
return Runner
|
53
bundle/nvim-tree.lua/lua/nvim-tree/git/utils.lua
Normal file
53
bundle/nvim-tree.lua/lua/nvim-tree/git/utils.lua
Normal file
@ -0,0 +1,53 @@
|
||||
local M = {}
|
||||
|
||||
function M.get_toplevel(cwd)
|
||||
local cmd = "git -C " .. vim.fn.shellescape(cwd) .. " rev-parse --show-toplevel"
|
||||
local toplevel = vim.fn.system(cmd)
|
||||
|
||||
if not toplevel or #toplevel == 0 or toplevel:match "fatal" then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- git always returns path with forward slashes
|
||||
if vim.fn.has "win32" == 1 then
|
||||
toplevel = toplevel:gsub("/", "\\")
|
||||
end
|
||||
|
||||
-- remove newline
|
||||
return toplevel:sub(0, -2)
|
||||
end
|
||||
|
||||
local untracked = {}
|
||||
|
||||
function M.should_show_untracked(cwd)
|
||||
if untracked[cwd] ~= nil then
|
||||
return untracked[cwd]
|
||||
end
|
||||
|
||||
local cmd = "git -C " .. cwd .. " config --type=bool status.showUntrackedFiles"
|
||||
local has_untracked = vim.fn.system(cmd)
|
||||
untracked[cwd] = vim.trim(has_untracked) ~= "false"
|
||||
return untracked[cwd]
|
||||
end
|
||||
|
||||
function M.file_status_to_dir_status(status, cwd)
|
||||
local dirs = {}
|
||||
for p, s in pairs(status) do
|
||||
if s ~= "!!" then
|
||||
local modified = vim.fn.fnamemodify(p, ":h")
|
||||
dirs[modified] = s
|
||||
end
|
||||
end
|
||||
|
||||
for dirname, s in pairs(dirs) do
|
||||
local modified = dirname
|
||||
while modified ~= cwd and modified ~= "/" do
|
||||
modified = vim.fn.fnamemodify(modified, ":h")
|
||||
dirs[modified] = s
|
||||
end
|
||||
end
|
||||
|
||||
return dirs
|
||||
end
|
||||
|
||||
return M
|
240
bundle/nvim-tree.lua/lua/nvim-tree/legacy.lua
Normal file
240
bundle/nvim-tree.lua/lua/nvim-tree/legacy.lua
Normal file
@ -0,0 +1,240 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local M = {}
|
||||
|
||||
-- TODO update bit.ly/3vIpEOJ when adding a migration
|
||||
|
||||
-- migrate the g: to o if the user has not specified that when calling setup
|
||||
local g_migrations = {
|
||||
nvim_tree_disable_netrw = function(o)
|
||||
if o.disable_netrw == nil then
|
||||
o.disable_netrw = vim.g.nvim_tree_disable_netrw ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_hijack_netrw = function(o)
|
||||
if o.hijack_netrw == nil then
|
||||
o.hijack_netrw = vim.g.nvim_tree_hijack_netrw ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_auto_open = function(o)
|
||||
if o.open_on_setup == nil then
|
||||
o.open_on_setup = vim.g.nvim_tree_auto_open ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_tab_open = function(o)
|
||||
if o.open_on_tab == nil then
|
||||
o.open_on_tab = vim.g.nvim_tree_tab_open ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_update_cwd = function(o)
|
||||
if o.update_cwd == nil then
|
||||
o.update_cwd = vim.g.nvim_tree_update_cwd ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_hijack_cursor = function(o)
|
||||
if o.hijack_cursor == nil then
|
||||
o.hijack_cursor = vim.g.nvim_tree_hijack_cursor ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_system_open_command = function(o)
|
||||
utils.table_create_missing(o, "system_open")
|
||||
if o.system_open.cmd == nil then
|
||||
o.system_open.cmd = vim.g.nvim_tree_system_open_command
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_system_open_command_args = function(o)
|
||||
utils.table_create_missing(o, "system_open")
|
||||
if o.system_open.args == nil then
|
||||
o.system_open.args = vim.g.nvim_tree_system_open_command_args
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_follow = function(o)
|
||||
utils.table_create_missing(o, "update_focused_file")
|
||||
if o.update_focused_file.enable == nil then
|
||||
o.update_focused_file.enable = vim.g.nvim_tree_follow ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_follow_update_path = function(o)
|
||||
utils.table_create_missing(o, "update_focused_file")
|
||||
if o.update_focused_file.update_cwd == nil then
|
||||
o.update_focused_file.update_cwd = vim.g.nvim_tree_follow_update_path ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_lsp_diagnostics = function(o)
|
||||
utils.table_create_missing(o, "diagnostics")
|
||||
if o.diagnostics.enable == nil then
|
||||
o.diagnostics.enable = vim.g.nvim_tree_lsp_diagnostics ~= 0
|
||||
if o.diagnostics.show_on_dirs == nil then
|
||||
o.diagnostics.show_on_dirs = vim.g.nvim_tree_lsp_diagnostics ~= 0
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_auto_resize = function(o)
|
||||
utils.table_create_missing(o, "actions.open_file")
|
||||
if o.actions.open_file.resize_window == nil then
|
||||
o.actions.open_file.resize_window = vim.g.nvim_tree_auto_resize ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_bindings = function(o)
|
||||
utils.table_create_missing(o, "view.mappings")
|
||||
if o.view.mappings.list == nil then
|
||||
o.view.mappings.list = vim.g.nvim_tree_bindings
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_disable_keybindings = function(o)
|
||||
utils.table_create_missing(o, "view.mappings")
|
||||
if o.view.mappings.custom_only == nil then
|
||||
if vim.g.nvim_tree_disable_keybindings ~= 0 then
|
||||
o.view.mappings.custom_only = true
|
||||
-- specify one mapping so that defaults do not apply
|
||||
o.view.mappings.list = {
|
||||
{ key = "g?", action = "" },
|
||||
}
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_disable_default_keybindings = function(o)
|
||||
utils.table_create_missing(o, "view.mappings")
|
||||
if o.view.mappings.custom_only == nil then
|
||||
o.view.mappings.custom_only = vim.g.nvim_tree_disable_default_keybindings ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_hide_dotfiles = function(o)
|
||||
utils.table_create_missing(o, "filters")
|
||||
if o.filters.dotfiles == nil then
|
||||
o.filters.dotfiles = vim.g.nvim_tree_hide_dotfiles ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_ignore = function(o)
|
||||
utils.table_create_missing(o, "filters")
|
||||
if o.filters.custom == nil then
|
||||
o.filters.custom = vim.g.nvim_tree_ignore
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_gitignore = function(o)
|
||||
utils.table_create_missing(o, "git")
|
||||
if o.git.ignore == nil then
|
||||
o.git.ignore = vim.g.nvim_tree_gitignore ~= 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_disable_window_picker = function(o)
|
||||
utils.table_create_missing(o, "actions.open_file.window_picker")
|
||||
if o.actions.open_file.window_picker.enable == nil then
|
||||
o.actions.open_file.window_picker.enable = vim.g.nvim_tree_disable_window_picker == 0
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_window_picker_chars = function(o)
|
||||
utils.table_create_missing(o, "actions.open_file.window_picker")
|
||||
if o.actions.open_file.window_picker.chars == nil then
|
||||
o.actions.open_file.window_picker.chars = vim.g.nvim_tree_window_picker_chars
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_window_picker_exclude = function(o)
|
||||
utils.table_create_missing(o, "actions.open_file.window_picker")
|
||||
if o.actions.open_file.window_picker.exclude == nil then
|
||||
o.actions.open_file.window_picker.exclude = vim.g.nvim_tree_window_picker_exclude
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_quit_on_open = function(o)
|
||||
utils.table_create_missing(o, "actions.open_file")
|
||||
if o.actions.open_file.quit_on_open == nil then
|
||||
o.actions.open_file.quit_on_open = vim.g.nvim_tree_quit_on_open == 1
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_change_dir_global = function(o)
|
||||
utils.table_create_missing(o, "actions.change_dir")
|
||||
if o.actions.change_dir.global == nil then
|
||||
o.actions.change_dir.global = vim.g.nvim_tree_change_dir_global == 1
|
||||
end
|
||||
end,
|
||||
|
||||
nvim_tree_indent_markers = function(o)
|
||||
utils.table_create_missing(o, "renderer.indent_markers")
|
||||
if o.renderer.indent_markers.enable == nil then
|
||||
o.renderer.indent_markers.enable = vim.g.nvim_tree_indent_markers == 1
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
local function refactored(opts)
|
||||
-- mapping actions
|
||||
if opts.view and opts.view.mappings and opts.view.mappings.list then
|
||||
for _, m in pairs(opts.view.mappings.list) do
|
||||
if m.action == "toggle_ignored" then
|
||||
m.action = "toggle_git_ignored"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- update_to_buf_dir -> hijack_directories
|
||||
if opts.update_to_buf_dir ~= nil then
|
||||
utils.table_create_missing(opts, "hijack_directories")
|
||||
if opts.hijack_directories.enable == nil then
|
||||
opts.hijack_directories.enable = opts.update_to_buf_dir.enable
|
||||
end
|
||||
if opts.hijack_directories.auto_open == nil then
|
||||
opts.hijack_directories.auto_open = opts.update_to_buf_dir.auto_open
|
||||
end
|
||||
opts.update_to_buf_dir = nil
|
||||
end
|
||||
|
||||
-- view.auto_resize -> actions.open_file.resize_window
|
||||
if opts.view and opts.view.auto_resize ~= nil then
|
||||
utils.table_create_missing(opts, "actions.open_file")
|
||||
if opts.actions.open_file.resize_window == nil then
|
||||
opts.actions.open_file.resize_window = opts.view.auto_resize
|
||||
end
|
||||
opts.view.auto_resize = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function removed(opts)
|
||||
if opts.auto_close then
|
||||
utils.warn "auto close feature has been removed, see note in the README (tips & reminder section)"
|
||||
opts.auto_close = nil
|
||||
end
|
||||
end
|
||||
|
||||
function M.migrate_legacy_options(opts)
|
||||
-- g: options
|
||||
local msg
|
||||
for g, m in pairs(g_migrations) do
|
||||
if vim.fn.exists("g:" .. g) ~= 0 then
|
||||
m(opts)
|
||||
msg = (msg and msg .. ", " or "Following options were moved to setup, see bit.ly/3vIpEOJ: ") .. g
|
||||
end
|
||||
end
|
||||
if msg then
|
||||
utils.warn(msg)
|
||||
end
|
||||
|
||||
-- silently move
|
||||
refactored(opts)
|
||||
|
||||
-- warn and delete
|
||||
removed(opts)
|
||||
end
|
||||
|
||||
return M
|
144
bundle/nvim-tree.lua/lua/nvim-tree/lib.lua
Normal file
144
bundle/nvim-tree.lua/lua/nvim-tree/lib.lua
Normal file
@ -0,0 +1,144 @@
|
||||
local api = vim.api
|
||||
|
||||
local renderer = require "nvim-tree.renderer"
|
||||
local view = require "nvim-tree.view"
|
||||
local core = require "nvim-tree.core"
|
||||
|
||||
local M = {
|
||||
target_winid = nil,
|
||||
}
|
||||
|
||||
function M.get_nodes_by_line(nodes_all, line_start)
|
||||
local nodes_by_line = {}
|
||||
local line = line_start
|
||||
local function iter(nodes)
|
||||
for _, node in ipairs(nodes) do
|
||||
nodes_by_line[line] = node
|
||||
line = line + 1
|
||||
if node.open == true then
|
||||
local child = iter(node.nodes)
|
||||
if child ~= nil then
|
||||
return child
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
iter(nodes_all)
|
||||
return nodes_by_line
|
||||
end
|
||||
|
||||
function M.get_node_at_cursor()
|
||||
if not core.get_explorer() then
|
||||
return
|
||||
end
|
||||
local winnr = view.get_winnr()
|
||||
if not winnr then
|
||||
return
|
||||
end
|
||||
local cursor = api.nvim_win_get_cursor(view.get_winnr())
|
||||
local line = cursor[1]
|
||||
if view.is_help_ui() then
|
||||
local help_lines = require("nvim-tree.renderer.help").compute_lines()
|
||||
local help_text = M.get_nodes_by_line(help_lines, 1)[line]
|
||||
return { name = help_text }
|
||||
else
|
||||
if line == 1 and core.get_explorer().cwd ~= "/" and view.is_root_folder_visible() then
|
||||
return { name = ".." }
|
||||
end
|
||||
|
||||
return M.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())[line]
|
||||
end
|
||||
end
|
||||
|
||||
-- If node is grouped, return the last node in the group. Otherwise, return the given node.
|
||||
function M.get_last_group_node(node)
|
||||
local next = node
|
||||
while next.group_next do
|
||||
next = next.group_next
|
||||
end
|
||||
return next
|
||||
end
|
||||
|
||||
function M.expand_or_collapse(node)
|
||||
node.open = not node.open
|
||||
if node.has_children then
|
||||
node.has_children = false
|
||||
end
|
||||
|
||||
if #node.nodes == 0 then
|
||||
core.get_explorer():expand(node)
|
||||
end
|
||||
|
||||
renderer.draw()
|
||||
end
|
||||
|
||||
function M.set_target_win()
|
||||
local id = api.nvim_get_current_win()
|
||||
local tree_id = view.get_winnr()
|
||||
if tree_id and id == tree_id then
|
||||
M.target_winid = 0
|
||||
return
|
||||
end
|
||||
|
||||
M.target_winid = id
|
||||
end
|
||||
|
||||
local function handle_buf_cwd(cwd)
|
||||
local respect_buf_cwd = vim.g.nvim_tree_respect_buf_cwd or 0
|
||||
if respect_buf_cwd == 1 and cwd ~= core.get_explorer().cwd then
|
||||
require("nvim-tree.actions.change-dir").fn(cwd)
|
||||
end
|
||||
end
|
||||
|
||||
local function open_view_and_draw()
|
||||
local cwd = vim.fn.getcwd()
|
||||
view.open()
|
||||
handle_buf_cwd(cwd)
|
||||
renderer.draw()
|
||||
end
|
||||
|
||||
local function should_hijack_current_buf()
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local bufname = api.nvim_buf_get_name(bufnr)
|
||||
local bufmodified = api.nvim_buf_get_option(bufnr, "modified")
|
||||
local ft = api.nvim_buf_get_option(bufnr, "ft")
|
||||
|
||||
local should_hijack_unnamed = M.hijack_unnamed_buffer_when_opening and bufname == "" and not bufmodified and ft == ""
|
||||
local should_hijack_dir = bufname ~= "" and vim.fn.isdirectory(bufname) == 1 and M.hijack_directories.enable
|
||||
|
||||
return should_hijack_dir or should_hijack_unnamed
|
||||
end
|
||||
|
||||
function M.open(cwd)
|
||||
M.set_target_win()
|
||||
if not core.get_explorer() or cwd then
|
||||
core.init(cwd or vim.loop.cwd())
|
||||
end
|
||||
if should_hijack_current_buf() then
|
||||
view.open_in_current_win()
|
||||
renderer.draw()
|
||||
else
|
||||
open_view_and_draw()
|
||||
end
|
||||
view.restore_tab_state()
|
||||
end
|
||||
|
||||
-- @deprecated: use nvim-tree.actions.collapse-all.fn
|
||||
M.collapse_all = require("nvim-tree.actions.collapse-all").fn
|
||||
-- @deprecated: use nvim-tree.actions.dir-up.fn
|
||||
M.dir_up = require("nvim-tree.actions.dir-up").fn
|
||||
-- @deprecated: use nvim-tree.actions.change-dir.fn
|
||||
M.change_dir = require("nvim-tree.actions.change-dir").fn
|
||||
-- @deprecated: use nvim-tree.actions.reloaders.reload_explorer
|
||||
M.refresh_tree = require("nvim-tree.actions.reloaders").reload_explorer
|
||||
-- @deprecated: use nvim-tree.actions.reloaders.reload_git
|
||||
M.reload_git = require("nvim-tree.actions.reloaders").reload_git
|
||||
-- @deprecated: use nvim-tree.actions.find-file.fn
|
||||
M.set_index_and_redraw = require("nvim-tree.actions.find-file").fn
|
||||
|
||||
function M.setup(opts)
|
||||
M.hijack_unnamed_buffer_when_opening = opts.hijack_unnamed_buffer_when_opening
|
||||
M.hijack_directories = opts.hijack_directories
|
||||
end
|
||||
|
||||
return M
|
63
bundle/nvim-tree.lua/lua/nvim-tree/log.lua
Normal file
63
bundle/nvim-tree.lua/lua/nvim-tree/log.lua
Normal file
@ -0,0 +1,63 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local M = {
|
||||
config = nil,
|
||||
path = nil,
|
||||
}
|
||||
|
||||
--- Write to log file
|
||||
--- @param typ string as per log.types config
|
||||
--- @param fmt string for string.format
|
||||
--- @vararg any arguments for string.format
|
||||
function M.raw(typ, fmt, ...)
|
||||
if not M.path or not M.config.types[typ] and not M.config.types.all then
|
||||
return
|
||||
end
|
||||
|
||||
local line = string.format(fmt, ...)
|
||||
local file = io.open(M.path, "a")
|
||||
io.output(file)
|
||||
io.write(line)
|
||||
io.close(file)
|
||||
end
|
||||
|
||||
--- Write to log file via M.line
|
||||
--- START is prefixed
|
||||
--- @return number nanos to pass to profile_end
|
||||
function M.profile_start(fmt, ...)
|
||||
if not M.path or not M.config.types.profile and not M.config.types.all then
|
||||
return
|
||||
end
|
||||
M.line("profile", "START " .. (fmt or "???"), ...)
|
||||
return uv.hrtime()
|
||||
end
|
||||
|
||||
--- Write to log file via M.line
|
||||
--- END is prefixed and duration in seconds is suffixed
|
||||
--- @param start number nanos returned from profile_start
|
||||
function M.profile_end(start, fmt, ...)
|
||||
if not M.path or not M.config.types.profile and not M.config.types.all then
|
||||
return
|
||||
end
|
||||
local millis = start and math.modf((uv.hrtime() - start) / 1000000) or -1
|
||||
M.line("profile", "END " .. (fmt or "???") .. " " .. millis .. "ms", ...)
|
||||
end
|
||||
|
||||
-- Write to log file via M.raw
|
||||
-- time and typ are prefixed and a trailing newline is added
|
||||
function M.line(typ, fmt, ...)
|
||||
M.raw(typ, string.format("[%s] [%s] %s\n", os.date "%Y-%m-%d %H:%M:%S", typ, fmt), ...)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = opts.log
|
||||
if M.config and M.config.enable and M.config.types then
|
||||
M.path = string.format("%s/nvim-tree.log", vim.fn.stdpath "cache", os.date "%H:%M:%S", vim.env.USER)
|
||||
if M.config.truncate then
|
||||
os.remove(M.path)
|
||||
end
|
||||
print("nvim-tree.lua logging to " .. M.path)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
276
bundle/nvim-tree.lua/lua/nvim-tree/renderer/builder.lua
Normal file
276
bundle/nvim-tree.lua/lua/nvim-tree/renderer/builder.lua
Normal file
@ -0,0 +1,276 @@
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
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 Builder = {}
|
||||
Builder.__index = Builder
|
||||
|
||||
function Builder.new(root_cwd)
|
||||
return setmetatable({
|
||||
index = 0,
|
||||
depth = nil,
|
||||
highlights = {},
|
||||
lines = {},
|
||||
markers = {},
|
||||
root_cwd = root_cwd,
|
||||
}, Builder)
|
||||
end
|
||||
|
||||
function Builder:configure_initial_depth(show_arrows)
|
||||
self.depth = show_arrows and 2 or 0
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_root_modifier(root_folder_modifier)
|
||||
self.root_folder_modifier = root_folder_modifier or ":~"
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_trailing_slash(with_trailing)
|
||||
self.trailing_slash = with_trailing and "/" or ""
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_special_map(special_map)
|
||||
self.special_map = special_map
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_picture_map(picture_map)
|
||||
self.picture_map = picture_map
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_opened_file_highlighting(level)
|
||||
if level == 1 then
|
||||
self.open_file_highlight = "icon"
|
||||
elseif level == 2 then
|
||||
self.open_file_highlight = "name"
|
||||
elseif level == 3 then
|
||||
self.open_file_highlight = "all"
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_git_icons_padding(padding)
|
||||
self.git_icon_padding = padding or " "
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:configure_git_icons_placement(where)
|
||||
where = where or "before"
|
||||
self.is_git_before = where == "before"
|
||||
self.is_git_after = not self.is_git_before
|
||||
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
|
||||
|
||||
local function get_folder_name(node)
|
||||
local name = node.name
|
||||
local next = node.group_next
|
||||
while next do
|
||||
name = name .. "/" .. next.name
|
||||
next = next.group_next
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
function Builder:_unwrap_git_data(git_icons_and_hl_groups, offset)
|
||||
if not git_icons_and_hl_groups then
|
||||
return ""
|
||||
end
|
||||
|
||||
local icon = ""
|
||||
for _, v in ipairs(git_icons_and_hl_groups) do
|
||||
if #v.icon > 0 then
|
||||
self:_insert_highlight(v.hl, offset + #icon, offset + #icon + #v.icon)
|
||||
icon = icon .. v.icon .. self.git_icon_padding
|
||||
end
|
||||
end
|
||||
return icon
|
||||
end
|
||||
|
||||
function Builder:_build_folder(node, padding, git_hl, git_icons_tbl)
|
||||
local offset = string.len(padding)
|
||||
|
||||
local name = get_folder_name(node)
|
||||
local has_children = #node.nodes ~= 0 or node.has_children
|
||||
local icon = icons.get_folder_icon(node.open, node.link_to ~= nil, has_children)
|
||||
|
||||
local foldername = name .. self.trailing_slash
|
||||
local git_icons = self:_unwrap_git_data(git_icons_tbl, offset + #icon + (self.is_git_after and #foldername + 1 or 0))
|
||||
local fname_starts_at = offset + #icon + (self.is_git_before and #git_icons or 0)
|
||||
local line = self:_format_line(padding .. icon, foldername, git_icons)
|
||||
self:_insert_line(line)
|
||||
|
||||
if #icon > 0 then
|
||||
self:_insert_highlight("NvimTreeFolderIcon", offset, offset + #icon)
|
||||
end
|
||||
|
||||
local foldername_hl = "NvimTreeFolderName"
|
||||
if self.special_map[node.absolute_path] then
|
||||
foldername_hl = "NvimTreeSpecialFolderName"
|
||||
elseif node.open then
|
||||
foldername_hl = "NvimTreeOpenedFolderName"
|
||||
elseif not has_children then
|
||||
foldername_hl = "NvimTreeEmptyFolderName"
|
||||
end
|
||||
|
||||
self:_insert_highlight(foldername_hl, fname_starts_at, fname_starts_at + #foldername)
|
||||
|
||||
if git_hl then
|
||||
self:_insert_highlight(git_hl, fname_starts_at, fname_starts_at + #foldername)
|
||||
end
|
||||
end
|
||||
|
||||
function Builder:_format_line(before, after, git_icons)
|
||||
return string.format(
|
||||
"%s%s%s %s",
|
||||
before,
|
||||
self.is_git_after and "" or git_icons,
|
||||
after,
|
||||
self.is_git_after and git_icons or ""
|
||||
)
|
||||
end
|
||||
|
||||
function Builder:_build_symlink(node, padding, git_highlight, git_icons_tbl)
|
||||
local offset = string.len(padding)
|
||||
|
||||
local icon = icons.i.symlink
|
||||
local arrow = icons.i.symlink_arrow
|
||||
local symlink_formatted = node.name .. arrow .. node.link_to
|
||||
|
||||
local link_highlight = git_highlight or "NvimTreeSymlink"
|
||||
|
||||
local git_icons_starts_at = offset + #icon + (self.is_git_after and #symlink_formatted + 1 or 0)
|
||||
local git_icons = self:_unwrap_git_data(git_icons_tbl, git_icons_starts_at)
|
||||
local line = self:_format_line(padding .. icon, symlink_formatted, git_icons)
|
||||
|
||||
self:_insert_highlight(link_highlight, offset + (self.is_git_after and 0 or #git_icons), string.len(line))
|
||||
self:_insert_line(line)
|
||||
end
|
||||
|
||||
function Builder:_build_file_icon(node, offset)
|
||||
local icon, hl_group = icons.get_file_icon(node.name, node.extension)
|
||||
if hl_group then
|
||||
self:_insert_highlight(hl_group, offset, offset + #icon)
|
||||
end
|
||||
return icon, false
|
||||
end
|
||||
|
||||
function Builder:_highlight_opened_files(node, offset, icon_length, git_icons_length)
|
||||
local from = offset
|
||||
local to = offset
|
||||
|
||||
if self.open_file_highlight == "icon" then
|
||||
to = from + icon_length
|
||||
elseif self.open_file_highlight == "name" then
|
||||
from = offset + icon_length + git_icons_length
|
||||
to = from + #node.name
|
||||
elseif self.open_file_highlight == "all" then
|
||||
to = from + icon_length + git_icons_length + #node.name
|
||||
end
|
||||
|
||||
self:_insert_highlight("NvimTreeOpenedFile", from, to)
|
||||
end
|
||||
|
||||
function Builder:_build_file(node, padding, git_highlight, git_icons_tbl)
|
||||
local offset = string.len(padding)
|
||||
|
||||
local icon = self:_build_file_icon(node, offset)
|
||||
|
||||
local git_icons_starts_at = offset + #icon + (self.is_git_after and #node.name + 1 or 0)
|
||||
local git_icons = self:_unwrap_git_data(git_icons_tbl, git_icons_starts_at)
|
||||
|
||||
self:_insert_line(self:_format_line(padding .. icon, node.name, git_icons))
|
||||
|
||||
local git_icons_length = self.is_git_after and 0 or #git_icons
|
||||
local col_start = offset + #icon + git_icons_length
|
||||
local col_end = col_start + #node.name
|
||||
|
||||
if self.special_map[node.absolute_path] or self.special_map[node.name] then
|
||||
self:_insert_highlight("NvimTreeSpecialFile", col_start, col_end)
|
||||
elseif node.executable then
|
||||
self:_insert_highlight("NvimTreeExecFile", col_start, col_end)
|
||||
elseif self.picture_map[node.extension] then
|
||||
self:_insert_highlight("NvimTreeImageFile", col_start, col_end)
|
||||
end
|
||||
|
||||
local should_highlight_opened_files = self.open_file_highlight and vim.fn.bufloaded(node.absolute_path) > 0
|
||||
if should_highlight_opened_files then
|
||||
self:_highlight_opened_files(node, offset, #icon, git_icons_length)
|
||||
end
|
||||
|
||||
if git_highlight then
|
||||
self:_insert_highlight(git_highlight, col_start, col_end)
|
||||
end
|
||||
end
|
||||
|
||||
function Builder:_build_line(tree, node, idx)
|
||||
local padding = pad.get_padding(self.depth, idx, tree, node, self.markers)
|
||||
|
||||
if self.depth > 0 then
|
||||
self:_insert_highlight("NvimTreeIndentMarker", 0, string.len(padding))
|
||||
end
|
||||
|
||||
local git_highlight = git.get_highlight(node)
|
||||
local git_icons_tbl = git.get_icons(node)
|
||||
|
||||
local is_folder = node.nodes ~= nil
|
||||
local is_symlink = node.link_to ~= nil
|
||||
|
||||
if is_folder then
|
||||
self:_build_folder(node, padding, git_highlight, git_icons_tbl)
|
||||
elseif is_symlink then
|
||||
self:_build_symlink(node, padding, git_highlight, git_icons_tbl)
|
||||
else
|
||||
self:_build_file(node, padding, git_highlight, git_icons_tbl)
|
||||
end
|
||||
self.index = self.index + 1
|
||||
|
||||
if node.open then
|
||||
self.depth = self.depth + 2
|
||||
self:build(node)
|
||||
self.depth = self.depth - 2
|
||||
end
|
||||
end
|
||||
|
||||
function Builder:build(tree)
|
||||
for idx, node in ipairs(tree.nodes) do
|
||||
self:_build_line(tree, node, idx)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
local function format_root_name(root_cwd, modifier)
|
||||
local base_root = utils.path_remove_trailing(vim.fn.fnamemodify(root_cwd, modifier))
|
||||
return utils.path_join { base_root, ".." }
|
||||
end
|
||||
|
||||
function Builder:build_header(show_header)
|
||||
if show_header then
|
||||
local root_name = format_root_name(self.root_cwd, self.root_folder_modifier)
|
||||
self:_insert_line(root_name)
|
||||
self:_insert_highlight("NvimTreeRootFolder", 0, string.len(root_name))
|
||||
self.index = 1
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function Builder:unwrap()
|
||||
return self.lines, self.highlights
|
||||
end
|
||||
|
||||
return Builder
|
158
bundle/nvim-tree.lua/lua/nvim-tree/renderer/components/git.lua
Normal file
158
bundle/nvim-tree.lua/lua/nvim-tree/renderer/components/git.lua
Normal file
@ -0,0 +1,158 @@
|
||||
local _icons = require "nvim-tree.renderer.icon-config"
|
||||
local utils = require "nvim-tree.utils"
|
||||
|
||||
local M = {}
|
||||
|
||||
local function build_icons_table()
|
||||
local i = M.icon_state.icons.git_icons
|
||||
return {
|
||||
["M "] = { { icon = i.staged, hl = "NvimTreeGitStaged" } },
|
||||
[" M"] = { { icon = i.unstaged, hl = "NvimTreeGitDirty" } },
|
||||
["C "] = { { icon = i.staged, hl = "NvimTreeGitStaged" } },
|
||||
[" C"] = { { icon = i.unstaged, hl = "NvimTreeGitDirty" } },
|
||||
["CM"] = { { icon = i.unstaged, hl = "NvimTreeGitDirty" } },
|
||||
[" T"] = { { icon = i.unstaged, hl = "NvimTreeGitDirty" } },
|
||||
["T "] = { { icon = i.staged, hl = "NvimTreeGitStaged" } },
|
||||
["MM"] = {
|
||||
{ icon = i.staged, hl = "NvimTreeGitStaged" },
|
||||
{ icon = i.unstaged, hl = "NvimTreeGitDirty" },
|
||||
},
|
||||
["MD"] = {
|
||||
{ icon = i.staged, hl = "NvimTreeGitStaged" },
|
||||
},
|
||||
["A "] = {
|
||||
{ icon = i.staged, hl = "NvimTreeGitStaged" },
|
||||
},
|
||||
["AD"] = {
|
||||
{ icon = i.staged, hl = "NvimTreeGitStaged" },
|
||||
},
|
||||
[" A"] = {
|
||||
{ icon = i.untracked, hl = "NvimTreeGitNew" },
|
||||
},
|
||||
-- not sure about this one
|
||||
["AA"] = {
|
||||
{ icon = i.unmerged, hl = "NvimTreeGitMerge" },
|
||||
{ icon = i.untracked, hl = "NvimTreeGitNew" },
|
||||
},
|
||||
["AU"] = {
|
||||
{ icon = i.unmerged, hl = "NvimTreeGitMerge" },
|
||||
{ icon = i.untracked, hl = "NvimTreeGitNew" },
|
||||
},
|
||||
["AM"] = {
|
||||
{ icon = i.staged, hl = "NvimTreeGitStaged" },
|
||||
{ icon = i.unstaged, hl = "NvimTreeGitDirty" },
|
||||
},
|
||||
["??"] = { { icon = i.untracked, hl = "NvimTreeGitNew" } },
|
||||
["R "] = { { icon = i.renamed, hl = "NvimTreeGitRenamed" } },
|
||||
[" R"] = { { icon = i.renamed, hl = "NvimTreeGitRenamed" } },
|
||||
["RM"] = {
|
||||
{ icon = i.unstaged, hl = "NvimTreeGitDirty" },
|
||||
{ icon = i.renamed, hl = "NvimTreeGitRenamed" },
|
||||
},
|
||||
["UU"] = { { icon = i.unmerged, hl = "NvimTreeGitMerge" } },
|
||||
["UD"] = { { icon = i.unmerged, hl = "NvimTreeGitMerge" } },
|
||||
["UA"] = { { icon = i.unmerged, hl = "NvimTreeGitMerge" } },
|
||||
[" D"] = { { icon = i.deleted, hl = "NvimTreeGitDeleted" } },
|
||||
["D "] = { { icon = i.deleted, hl = "NvimTreeGitDeleted" } },
|
||||
["RD"] = { { icon = i.deleted, hl = "NvimTreeGitDeleted" } },
|
||||
["DD"] = { { icon = i.deleted, hl = "NvimTreeGitDeleted" } },
|
||||
["DU"] = {
|
||||
{ icon = i.deleted, hl = "NvimTreeGitDeleted" },
|
||||
{ icon = i.unmerged, hl = "NvimTreeGitMerge" },
|
||||
},
|
||||
["!!"] = { { icon = i.ignored, hl = "NvimTreeGitIgnored" } },
|
||||
dirty = { { icon = i.unstaged, hl = "NvimTreeGitDirty" } },
|
||||
}
|
||||
end
|
||||
|
||||
local function nil_() end
|
||||
|
||||
local function warn_status(git_status)
|
||||
utils.warn(
|
||||
'Unrecognized git state "'
|
||||
.. git_status
|
||||
.. '". Please open up an issue on https://github.com/kyazdani42/nvim-tree.lua/issues with this message.'
|
||||
)
|
||||
end
|
||||
|
||||
local function get_icons_(node)
|
||||
local git_status = node.git_status
|
||||
if not git_status then
|
||||
return nil
|
||||
end
|
||||
|
||||
local icons = M.git_icons[git_status]
|
||||
if not icons then
|
||||
if vim.g.nvim_tree_git_hl ~= 1 then
|
||||
warn_status(git_status)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return icons
|
||||
end
|
||||
|
||||
local git_hl = {
|
||||
["M "] = "NvimTreeFileStaged",
|
||||
["C "] = "NvimTreeFileStaged",
|
||||
["AA"] = "NvimTreeFileStaged",
|
||||
["AD"] = "NvimTreeFileStaged",
|
||||
["MD"] = "NvimTreeFileStaged",
|
||||
["T "] = "NvimTreeFileStaged",
|
||||
[" M"] = "NvimTreeFileDirty",
|
||||
["CM"] = "NvimTreeFileDirty",
|
||||
[" C"] = "NvimTreeFileDirty",
|
||||
[" T"] = "NvimTreeFileDirty",
|
||||
["MM"] = "NvimTreeFileDirty",
|
||||
["AM"] = "NvimTreeFileDirty",
|
||||
dirty = "NvimTreeFileDirty",
|
||||
["A "] = "NvimTreeFileNew",
|
||||
["??"] = "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",
|
||||
["!!"] = "NvimTreeGitIgnored",
|
||||
[" A"] = "none",
|
||||
}
|
||||
|
||||
local function get_highlight_(node)
|
||||
local git_status = node.git_status
|
||||
if not git_status then
|
||||
return
|
||||
end
|
||||
|
||||
return git_hl[git_status]
|
||||
end
|
||||
|
||||
M.get_icons = nil_
|
||||
M.get_highlight = nil_
|
||||
|
||||
M.icon_state = _icons.get_config()
|
||||
M.git_icons = build_icons_table()
|
||||
|
||||
function M.reload()
|
||||
M.icon_state = _icons.get_config()
|
||||
M.git_icons = build_icons_table()
|
||||
|
||||
if M.icon_state.show_git_icon then
|
||||
M.get_icons = get_icons_
|
||||
else
|
||||
M.get_icons = nil_
|
||||
end
|
||||
if vim.g.nvim_tree_git_hl == 1 then
|
||||
M.get_highlight = get_highlight_
|
||||
else
|
||||
M.get_highlight = nil_
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,93 @@
|
||||
local icon_config = require "nvim-tree.renderer.icon-config"
|
||||
|
||||
local M = { i = {} }
|
||||
|
||||
local function config_symlinks()
|
||||
M.i.symlink = #M.icons.symlink > 0 and M.icons.symlink .. M.padding or ""
|
||||
M.i.symlink_arrow = vim.g.nvim_tree_symlink_arrow or " ➛ "
|
||||
end
|
||||
|
||||
local function empty()
|
||||
return ""
|
||||
end
|
||||
|
||||
local function get_folder_icon(open, is_symlink, has_children)
|
||||
local n
|
||||
if is_symlink and open then
|
||||
n = M.icons.folder_icons.symlink_open
|
||||
elseif is_symlink then
|
||||
n = M.icons.folder_icons.symlink
|
||||
elseif open then
|
||||
if has_children then
|
||||
n = M.icons.folder_icons.open
|
||||
else
|
||||
n = M.icons.folder_icons.empty_open
|
||||
end
|
||||
else
|
||||
if has_children then
|
||||
n = M.icons.folder_icons.default
|
||||
else
|
||||
n = M.icons.folder_icons.empty
|
||||
end
|
||||
end
|
||||
return n .. M.padding
|
||||
end
|
||||
|
||||
local function get_file_icon_default()
|
||||
local hl_group = "NvimTreeFileIcon"
|
||||
local icon = M.icons.default
|
||||
if #icon > 0 then
|
||||
return icon .. M.padding, hl_group
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
local function get_file_icon_webdev(fname, extension)
|
||||
local icon, hl_group = M.devicons.get_icon(fname, extension)
|
||||
if not M.webdev_colors then
|
||||
hl_group = "NvimTreeFileIcon"
|
||||
end
|
||||
if icon and hl_group ~= "DevIconDefault" then
|
||||
return icon .. M.padding, hl_group
|
||||
elseif string.match(extension, "%.(.*)") then
|
||||
-- If there are more extensions to the file, try to grab the icon for them recursively
|
||||
return get_file_icon_webdev(fname, string.match(extension, "%.(.*)"))
|
||||
else
|
||||
return get_file_icon_default()
|
||||
end
|
||||
end
|
||||
|
||||
local function config_file_icon()
|
||||
if M.configs.show_file_icon then
|
||||
if M.devicons then
|
||||
M.get_file_icon = get_file_icon_webdev
|
||||
else
|
||||
M.get_file_icon = get_file_icon_default
|
||||
end
|
||||
else
|
||||
M.get_file_icon = empty
|
||||
end
|
||||
end
|
||||
|
||||
local function config_folder_icon()
|
||||
if M.configs.show_folder_icon then
|
||||
M.get_folder_icon = get_folder_icon
|
||||
else
|
||||
M.get_folder_icon = empty
|
||||
end
|
||||
end
|
||||
|
||||
function M.reset_config(webdev_colors)
|
||||
M.configs = icon_config.get_config()
|
||||
M.icons = M.configs.icons
|
||||
M.padding = vim.g.nvim_tree_icon_padding or " "
|
||||
M.devicons = M.configs.has_devicons and require "nvim-web-devicons" or nil
|
||||
M.webdev_colors = webdev_colors
|
||||
|
||||
config_symlinks()
|
||||
config_file_icon()
|
||||
config_folder_icon()
|
||||
end
|
||||
|
||||
return M
|
@ -0,0 +1,53 @@
|
||||
local M = {}
|
||||
|
||||
function M.get_padding(depth)
|
||||
return string.rep(" ", depth)
|
||||
end
|
||||
|
||||
local function get_padding_arrows(icon_state)
|
||||
return function(depth, _, _, node)
|
||||
if node.nodes then
|
||||
local icon = icon_state.icons.folder_icons[node.open and "arrow_open" or "arrow_closed"]
|
||||
return string.rep(" ", depth - 2) .. icon .. " "
|
||||
end
|
||||
return string.rep(" ", depth)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_padding_indent_markers(depth, idx, tree, _, markers)
|
||||
local padding = ""
|
||||
if depth ~= 0 then
|
||||
local rdepth = depth / 2
|
||||
markers[rdepth] = idx ~= #tree.nodes
|
||||
for i = 1, rdepth do
|
||||
if idx == #tree.nodes and i == rdepth then
|
||||
padding = padding .. M.config.indent_markers.icons.corner
|
||||
elseif markers[i] then
|
||||
padding = padding .. M.config.indent_markers.icons.edge
|
||||
else
|
||||
padding = padding .. M.config.indent_markers.icons.none
|
||||
end
|
||||
end
|
||||
end
|
||||
return padding
|
||||
end
|
||||
|
||||
function M.reload_padding_function()
|
||||
local icon_state = require("nvim-tree.renderer.icon-config").get_config()
|
||||
|
||||
if icon_state.show_folder_icon and icon_state.show_folder_arrows then
|
||||
M.get_padding = get_padding_arrows(icon_state)
|
||||
end
|
||||
|
||||
if M.config.indent_markers.enable then
|
||||
M.get_padding = get_padding_indent_markers
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = {
|
||||
indent_markers = opts.renderer.indent_markers,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
50
bundle/nvim-tree.lua/lua/nvim-tree/renderer/help.lua
Normal file
50
bundle/nvim-tree.lua/lua/nvim-tree/renderer/help.lua
Normal file
@ -0,0 +1,50 @@
|
||||
local M = {}
|
||||
|
||||
function M.compute_lines()
|
||||
local help_lines = { "HELP" }
|
||||
local help_hl = { { "NvimTreeRootFolder", 0, 0, #help_lines[1] } }
|
||||
local mappings = vim.tbl_filter(function(v)
|
||||
return (v.cb ~= nil and v.cb ~= "") or (v.action ~= nil and v.action ~= "")
|
||||
end, require("nvim-tree.actions").mappings)
|
||||
local processed = {}
|
||||
for _, b in pairs(mappings) do
|
||||
local cb = b.cb
|
||||
local key = b.key
|
||||
local name
|
||||
if cb and cb:sub(1, 35) == require("nvim-tree.config").nvim_tree_callback("test"):sub(1, 35) then
|
||||
name = cb:match "'[^']+'[^']*$"
|
||||
name = name:match "'[^']+'"
|
||||
elseif b.action then
|
||||
name = b.action
|
||||
else
|
||||
name = (b.name ~= nil) and b.name or cb
|
||||
name = '"' .. name .. '"'
|
||||
end
|
||||
table.insert(processed, { key, name, true })
|
||||
end
|
||||
table.sort(processed, function(a, b)
|
||||
return (a[3] == b[3] and (a[2] < b[2] or (a[2] == b[2] and #a[1] < #b[1]))) or (a[3] and not b[3])
|
||||
end)
|
||||
|
||||
local num = 0
|
||||
for _, val in pairs(processed) do
|
||||
local keys = type(val[1]) == "string" and { val[1] } or val[1]
|
||||
local map_name = val[2]
|
||||
local builtin = val[3]
|
||||
for _, key in pairs(keys) do
|
||||
num = num + 1
|
||||
local bind_string = string.format("%6s : %s", key, map_name)
|
||||
table.insert(help_lines, bind_string)
|
||||
|
||||
local hl_len = math.max(6, string.len(key)) + 2
|
||||
table.insert(help_hl, { "NvimTreeFolderName", num, 0, hl_len })
|
||||
|
||||
if not builtin then
|
||||
table.insert(help_hl, { "NvimTreeFileRenamed", num, hl_len, -1 })
|
||||
end
|
||||
end
|
||||
end
|
||||
return help_lines, help_hl
|
||||
end
|
||||
|
||||
return M
|
61
bundle/nvim-tree.lua/lua/nvim-tree/renderer/icon-config.lua
Normal file
61
bundle/nvim-tree.lua/lua/nvim-tree/renderer/icon-config.lua
Normal file
@ -0,0 +1,61 @@
|
||||
local M = {}
|
||||
|
||||
function M.get_config()
|
||||
local show_icons = vim.g.nvim_tree_show_icons or { git = 1, folders = 1, files = 1, folder_arrows = 1 }
|
||||
local icons = {
|
||||
default = "",
|
||||
symlink = "",
|
||||
git_icons = {
|
||||
unstaged = "✗",
|
||||
staged = "✓",
|
||||
unmerged = "",
|
||||
renamed = "➜",
|
||||
untracked = "★",
|
||||
deleted = "",
|
||||
ignored = "◌",
|
||||
},
|
||||
folder_icons = {
|
||||
arrow_closed = "",
|
||||
arrow_open = "",
|
||||
default = "",
|
||||
open = "",
|
||||
empty = "",
|
||||
empty_open = "",
|
||||
symlink = "",
|
||||
symlink_open = "",
|
||||
},
|
||||
}
|
||||
|
||||
local user_icons = vim.g.nvim_tree_icons
|
||||
if user_icons then
|
||||
if user_icons.default then
|
||||
icons.default = user_icons.default
|
||||
icons.symlink = user_icons.default
|
||||
end
|
||||
if user_icons.symlink then
|
||||
icons.symlink = user_icons.symlink
|
||||
end
|
||||
for key, val in pairs(user_icons.git or {}) do
|
||||
if icons.git_icons[key] then
|
||||
icons.git_icons[key] = val
|
||||
end
|
||||
end
|
||||
for key, val in pairs(user_icons.folder or {}) do
|
||||
if icons.folder_icons[key] then
|
||||
icons.folder_icons[key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local has_devicons = pcall(require, "nvim-web-devicons")
|
||||
return {
|
||||
show_file_icon = show_icons.files == 1,
|
||||
show_folder_icon = show_icons.folders == 1,
|
||||
show_git_icon = show_icons.git == 1,
|
||||
show_folder_arrows = show_icons.folder_arrows == 1,
|
||||
has_devicons = has_devicons,
|
||||
icons = icons,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
116
bundle/nvim-tree.lua/lua/nvim-tree/renderer/init.lua
Normal file
116
bundle/nvim-tree.lua/lua/nvim-tree/renderer/init.lua
Normal file
@ -0,0 +1,116 @@
|
||||
local core = require "nvim-tree.core"
|
||||
local diagnostics = require "nvim-tree.diagnostics"
|
||||
local log = require "nvim-tree.log"
|
||||
local view = require "nvim-tree.view"
|
||||
|
||||
local _padding = require "nvim-tree.renderer.components.padding"
|
||||
local icon_component = require "nvim-tree.renderer.components.icons"
|
||||
local help = require "nvim-tree.renderer.help"
|
||||
local git = require "nvim-tree.renderer.components.git"
|
||||
local Builder = require "nvim-tree.renderer.builder"
|
||||
|
||||
local api = vim.api
|
||||
|
||||
local M = {
|
||||
last_highlights = {},
|
||||
}
|
||||
|
||||
local namespace_id = api.nvim_create_namespace "NvimTreeHighlights"
|
||||
|
||||
local function _draw(bufnr, lines, hl)
|
||||
api.nvim_buf_set_option(bufnr, "modifiable", true)
|
||||
api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
||||
M.render_hl(bufnr, hl)
|
||||
api.nvim_buf_set_option(bufnr, "modifiable", false)
|
||||
end
|
||||
|
||||
function M.render_hl(bufnr, hl)
|
||||
if not bufnr or not api.nvim_buf_is_loaded(bufnr) then
|
||||
return
|
||||
end
|
||||
api.nvim_buf_clear_namespace(bufnr, namespace_id, 0, -1)
|
||||
for _, data in ipairs(hl or M.last_highlights) do
|
||||
api.nvim_buf_add_highlight(bufnr, namespace_id, data[1], data[2], data[3], data[4])
|
||||
end
|
||||
end
|
||||
|
||||
local function should_show_arrows()
|
||||
return not M.config.indent_markers.enable
|
||||
and icon_component.configs.show_folder_icon
|
||||
and icon_component.configs.show_folder_arrows
|
||||
end
|
||||
|
||||
local picture_map = {
|
||||
jpg = true,
|
||||
jpeg = true,
|
||||
png = true,
|
||||
gif = true,
|
||||
}
|
||||
|
||||
local function get_special_files_map()
|
||||
return vim.g.nvim_tree_special_files
|
||||
or {
|
||||
["Cargo.toml"] = true,
|
||||
Makefile = true,
|
||||
["README.md"] = true,
|
||||
["readme.md"] = true,
|
||||
}
|
||||
end
|
||||
|
||||
function M.draw()
|
||||
local bufnr = view.get_bufnr()
|
||||
if not core.get_explorer() or not bufnr or not api.nvim_buf_is_loaded(bufnr) then
|
||||
return
|
||||
end
|
||||
|
||||
local ps = log.profile_start "draw"
|
||||
|
||||
local cursor = api.nvim_win_get_cursor(view.get_winnr())
|
||||
_padding.reload_padding_function()
|
||||
icon_component.reset_config(M.config.icons.webdev_colors)
|
||||
git.reload()
|
||||
|
||||
local lines, hl
|
||||
if view.is_help_ui() then
|
||||
lines, hl = help.compute_lines()
|
||||
else
|
||||
lines, hl = Builder.new(core.get_cwd())
|
||||
:configure_initial_depth(should_show_arrows())
|
||||
:configure_root_modifier(vim.g.nvim_tree_root_folder_modifier)
|
||||
:configure_trailing_slash(vim.g.nvim_tree_add_trailing == 1)
|
||||
:configure_special_map(get_special_files_map())
|
||||
:configure_picture_map(picture_map)
|
||||
:configure_opened_file_highlighting(vim.g.nvim_tree_highlight_opened_files)
|
||||
:configure_git_icons_padding(vim.g.nvim_tree_icon_padding)
|
||||
:configure_git_icons_placement(M.config.icons.git_placement)
|
||||
:build_header(view.is_root_folder_visible(core.get_cwd()))
|
||||
:build(core.get_explorer())
|
||||
:unwrap()
|
||||
end
|
||||
|
||||
_draw(bufnr, lines, hl)
|
||||
M.last_highlights = hl
|
||||
|
||||
if cursor and #lines >= cursor[1] then
|
||||
api.nvim_win_set_cursor(view.get_winnr(), cursor)
|
||||
end
|
||||
|
||||
if view.is_help_ui() then
|
||||
diagnostics.clear()
|
||||
else
|
||||
diagnostics.update()
|
||||
end
|
||||
|
||||
log.profile_end(ps, "draw")
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = {
|
||||
indent_markers = opts.renderer.indent_markers,
|
||||
icons = opts.renderer.icons,
|
||||
}
|
||||
|
||||
_padding.setup(opts)
|
||||
end
|
||||
|
||||
return M
|
221
bundle/nvim-tree.lua/lua/nvim-tree/utils.lua
Normal file
221
bundle/nvim-tree.lua/lua/nvim-tree/utils.lua
Normal file
@ -0,0 +1,221 @@
|
||||
local has_notify, notify = pcall(require, "notify")
|
||||
|
||||
local a = vim.api
|
||||
local uv = vim.loop
|
||||
|
||||
local M = {}
|
||||
|
||||
M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1
|
||||
|
||||
function M.path_to_matching_str(path)
|
||||
return path:gsub("(%-)", "(%%-)"):gsub("(%.)", "(%%.)"):gsub("(%_)", "(%%_)")
|
||||
end
|
||||
|
||||
function M.warn(msg)
|
||||
vim.schedule(function()
|
||||
if has_notify then
|
||||
notify(msg, vim.log.levels.WARN, { title = "NvimTree" })
|
||||
else
|
||||
vim.notify("[NvimTree] " .. msg, vim.log.levels.WARN)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function M.str_find(haystack, needle)
|
||||
return vim.fn.stridx(haystack, needle) ~= -1
|
||||
end
|
||||
|
||||
function M.read_file(path)
|
||||
local fd = uv.fs_open(path, "r", 438)
|
||||
if not fd then
|
||||
return ""
|
||||
end
|
||||
local stat = uv.fs_fstat(fd)
|
||||
if not stat then
|
||||
return ""
|
||||
end
|
||||
local data = uv.fs_read(fd, stat.size, 0)
|
||||
uv.fs_close(fd)
|
||||
return data or ""
|
||||
end
|
||||
|
||||
local path_separator = package.config:sub(1, 1)
|
||||
function M.path_join(paths)
|
||||
return table.concat(vim.tbl_map(M.path_remove_trailing, paths), path_separator)
|
||||
end
|
||||
|
||||
function M.path_split(path)
|
||||
return path:gmatch("[^" .. path_separator .. "]+" .. path_separator .. "?")
|
||||
end
|
||||
|
||||
---Get the basename of the given path.
|
||||
---@param path string
|
||||
---@return string
|
||||
function M.path_basename(path)
|
||||
path = M.path_remove_trailing(path)
|
||||
local i = path:match("^.*()" .. path_separator)
|
||||
if not i then
|
||||
return path
|
||||
end
|
||||
return path:sub(i + 1, #path)
|
||||
end
|
||||
|
||||
---Get a path relative to another path.
|
||||
---@param path string
|
||||
---@param relative_to string
|
||||
---@return string
|
||||
function M.path_relative(path, relative_to)
|
||||
local p, _ = path:gsub("^" .. M.path_to_matching_str(M.path_add_trailing(relative_to)), "")
|
||||
return p
|
||||
end
|
||||
|
||||
function M.path_add_trailing(path)
|
||||
if path:sub(-1) == path_separator then
|
||||
return path
|
||||
end
|
||||
|
||||
return path .. path_separator
|
||||
end
|
||||
|
||||
function M.path_remove_trailing(path)
|
||||
local p, _ = path:gsub(path_separator .. "$", "")
|
||||
return p
|
||||
end
|
||||
|
||||
M.path_separator = path_separator
|
||||
|
||||
function M.clear_prompt()
|
||||
vim.api.nvim_command "normal! :"
|
||||
end
|
||||
|
||||
function M.get_user_input_char()
|
||||
local c = vim.fn.getchar()
|
||||
while type(c) ~= "number" do
|
||||
c = vim.fn.getchar()
|
||||
end
|
||||
return vim.fn.nr2char(c)
|
||||
end
|
||||
|
||||
-- get the node from the tree that matches the predicate
|
||||
-- @param nodes list of node
|
||||
-- @param fn function(node): boolean
|
||||
function M.find_node(nodes, fn)
|
||||
local function iter(nodes_, fn_)
|
||||
local i = 1
|
||||
for _, node in ipairs(nodes_) do
|
||||
if fn_(node) then
|
||||
return node, i
|
||||
end
|
||||
if node.open and #node.nodes > 0 then
|
||||
local n, idx = iter(node.nodes, fn_)
|
||||
i = i + idx
|
||||
if n then
|
||||
return n, i
|
||||
end
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
return nil, i
|
||||
end
|
||||
local node, i = iter(nodes, fn)
|
||||
i = require("nvim-tree.view").View.hide_root_folder and i - 1 or i
|
||||
return node, i
|
||||
end
|
||||
|
||||
---Matching executable files in Windows.
|
||||
---@param ext string
|
||||
---@return boolean
|
||||
local PATHEXT = vim.env.PATHEXT or ""
|
||||
local wexe = vim.split(PATHEXT:gsub("%.", ""), ";")
|
||||
local pathexts = {}
|
||||
for _, v in pairs(wexe) do
|
||||
pathexts[v] = true
|
||||
end
|
||||
|
||||
function M.is_windows_exe(ext)
|
||||
return pathexts[ext:upper()]
|
||||
end
|
||||
|
||||
function M.rename_loaded_buffers(old_path, new_path)
|
||||
for _, buf in pairs(a.nvim_list_bufs()) do
|
||||
if a.nvim_buf_is_loaded(buf) then
|
||||
local buf_name = a.nvim_buf_get_name(buf)
|
||||
local exact_match = buf_name == old_path
|
||||
local child_match = (
|
||||
buf_name:sub(1, #old_path) == old_path and buf_name:sub(#old_path + 1, #old_path + 1) == path_separator
|
||||
)
|
||||
if exact_match or child_match then
|
||||
a.nvim_buf_set_name(buf, new_path .. buf_name:sub(#old_path + 1))
|
||||
-- to avoid the 'overwrite existing file' error message on write for
|
||||
-- normal files
|
||||
if a.nvim_buf_get_option(buf, "buftype") == "" then
|
||||
a.nvim_buf_call(buf, function()
|
||||
vim.cmd "silent! write!"
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param path string path to file or directory
|
||||
--- @return boolean
|
||||
function M.file_exists(path)
|
||||
local _, error = vim.loop.fs_stat(path)
|
||||
return error == nil
|
||||
end
|
||||
|
||||
--- @param path string
|
||||
--- @return string
|
||||
function M.canonical_path(path)
|
||||
if M.is_windows and path:match "^%a:" then
|
||||
return path:sub(1, 1):upper() .. path:sub(2)
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
-- Create empty sub-tables if not present
|
||||
-- @param tbl to create empty inside of
|
||||
-- @param sub dot separated string of sub-tables
|
||||
-- @return deepest sub-table
|
||||
function M.table_create_missing(tbl, sub)
|
||||
if tbl == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local t = tbl
|
||||
for s in string.gmatch(sub, "([^%.]+)%.*") do
|
||||
if t[s] == nil then
|
||||
t[s] = {}
|
||||
end
|
||||
t = t[s]
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
function M.format_bytes(bytes)
|
||||
local units = { "B", "K", "M", "G", "T" }
|
||||
|
||||
bytes = math.max(bytes, 0)
|
||||
local pow = math.floor((bytes and math.log(bytes) or 0) / math.log(1024))
|
||||
pow = math.min(pow, #units)
|
||||
|
||||
local value = bytes / (1024 ^ pow)
|
||||
value = math.floor((value * 10) + 0.5) / 10
|
||||
|
||||
pow = pow + 1
|
||||
|
||||
return (units[pow] == nil) and (bytes .. "B") or (value .. units[pow])
|
||||
end
|
||||
|
||||
function M.key_by(tbl, key)
|
||||
local keyed = {}
|
||||
for _, val in ipairs(tbl) do
|
||||
keyed[val[key]] = val
|
||||
end
|
||||
return keyed
|
||||
end
|
||||
|
||||
return M
|
399
bundle/nvim-tree.lua/lua/nvim-tree/view.lua
Normal file
399
bundle/nvim-tree.lua/lua/nvim-tree/view.lua
Normal file
@ -0,0 +1,399 @@
|
||||
local a = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
local events = require "nvim-tree.events"
|
||||
|
||||
M.View = {
|
||||
tabpages = {},
|
||||
cursors = {},
|
||||
hide_root_folder = false,
|
||||
winopts = {
|
||||
relativenumber = false,
|
||||
number = false,
|
||||
list = false,
|
||||
foldenable = false,
|
||||
winfixwidth = true,
|
||||
winfixheight = true,
|
||||
spell = false,
|
||||
signcolumn = "yes",
|
||||
foldmethod = "manual",
|
||||
foldcolumn = "0",
|
||||
cursorcolumn = false,
|
||||
cursorlineopt = "line",
|
||||
colorcolumn = "0",
|
||||
wrap = false,
|
||||
winhl = table.concat({
|
||||
"EndOfBuffer:NvimTreeEndOfBuffer",
|
||||
"Normal:NvimTreeNormal",
|
||||
"CursorLine:NvimTreeCursorLine",
|
||||
-- #1221 WinSeparator not present in nvim 0.6.1 and some builds of 0.7.0
|
||||
pcall(vim.cmd, "silent hi WinSeparator") and "WinSeparator:NvimTreeWinSeparator" or "VertSplit:NvimTreeWinSeparator",
|
||||
"StatusLine:NvimTreeStatusLine",
|
||||
"StatusLineNC:NvimTreeStatuslineNC",
|
||||
"SignColumn:NvimTreeSignColumn",
|
||||
"NormalNC:NvimTreeNormalNC",
|
||||
}, ","),
|
||||
},
|
||||
}
|
||||
|
||||
-- The initial state of a tab
|
||||
local tabinitial = {
|
||||
-- True if help is displayed
|
||||
help = false,
|
||||
-- The position of the cursor { line, column }
|
||||
cursor = { 0, 0 },
|
||||
-- The NvimTree window number
|
||||
winnr = nil,
|
||||
}
|
||||
|
||||
local BUFNR_PER_TAB = {}
|
||||
local BUFFER_OPTIONS = {
|
||||
swapfile = false,
|
||||
buftype = "nofile",
|
||||
modifiable = false,
|
||||
filetype = "NvimTree",
|
||||
bufhidden = "wipe",
|
||||
buflisted = false,
|
||||
}
|
||||
|
||||
local function matches_bufnr(bufnr)
|
||||
for _, b in pairs(BUFNR_PER_TAB) do
|
||||
if b == bufnr then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function wipe_rogue_buffer()
|
||||
for _, bufnr in ipairs(a.nvim_list_bufs()) do
|
||||
if not matches_bufnr(bufnr) and a.nvim_buf_get_name(bufnr):match "NvimTree" ~= nil then
|
||||
return pcall(a.nvim_buf_delete, bufnr, { force = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function create_buffer(bufnr)
|
||||
wipe_rogue_buffer()
|
||||
|
||||
local tab = a.nvim_get_current_tabpage()
|
||||
BUFNR_PER_TAB[tab] = bufnr or a.nvim_create_buf(false, false)
|
||||
a.nvim_buf_set_name(M.get_bufnr(), "NvimTree_" .. tab)
|
||||
|
||||
for option, value in pairs(BUFFER_OPTIONS) do
|
||||
vim.bo[M.get_bufnr()][option] = value
|
||||
end
|
||||
|
||||
require("nvim-tree.actions").apply_mappings(M.get_bufnr())
|
||||
end
|
||||
|
||||
local function get_size()
|
||||
local width_or_height = M.is_vertical() and "width" or "height"
|
||||
local size = M.View[width_or_height]
|
||||
if type(size) == "number" then
|
||||
return size
|
||||
elseif type(size) == "function" then
|
||||
return size()
|
||||
end
|
||||
local size_as_number = tonumber(size:sub(0, -2))
|
||||
local percent_as_decimal = size_as_number / 100
|
||||
return math.floor(vim.o.columns * percent_as_decimal)
|
||||
end
|
||||
|
||||
local move_tbl = {
|
||||
left = "H",
|
||||
right = "L",
|
||||
bottom = "J",
|
||||
top = "K",
|
||||
}
|
||||
|
||||
-- TODO: remove this once they fix https://github.com/neovim/neovim/issues/14670
|
||||
local function set_local(opt, value)
|
||||
local cmd
|
||||
if value == true then
|
||||
cmd = string.format("setlocal %s", opt)
|
||||
elseif value == false then
|
||||
cmd = string.format("setlocal no%s", opt)
|
||||
else
|
||||
cmd = string.format("setlocal %s=%s", opt, value)
|
||||
end
|
||||
vim.cmd(cmd)
|
||||
end
|
||||
|
||||
-- setup_tabpage sets up the initial state of a tab
|
||||
local function setup_tabpage(tabpage)
|
||||
local winnr = a.nvim_get_current_win()
|
||||
M.View.tabpages[tabpage] = vim.tbl_extend("force", M.View.tabpages[tabpage] or tabinitial, { winnr = winnr })
|
||||
end
|
||||
|
||||
local function open_window()
|
||||
a.nvim_command "vsp"
|
||||
M.reposition_window()
|
||||
setup_tabpage(a.nvim_get_current_tabpage())
|
||||
end
|
||||
|
||||
local function set_window_options_and_buffer()
|
||||
pcall(vim.cmd, "buffer " .. M.get_bufnr())
|
||||
for k, v in pairs(M.View.winopts) do
|
||||
set_local(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_existing_buffers()
|
||||
return vim.tbl_filter(function(buf)
|
||||
return a.nvim_buf_is_valid(buf) and vim.fn.buflisted(buf) == 1
|
||||
end, a.nvim_list_bufs())
|
||||
end
|
||||
|
||||
local function switch_buf_if_last_buf()
|
||||
if #a.nvim_list_wins() == 1 then
|
||||
if #get_existing_buffers() > 0 then
|
||||
vim.cmd "sbnext"
|
||||
else
|
||||
vim.cmd "new"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- save_tab_state saves any state that should be preserved across redraws.
|
||||
local function save_tab_state()
|
||||
local tabpage = a.nvim_get_current_tabpage()
|
||||
M.View.cursors[tabpage] = a.nvim_win_get_cursor(M.get_winnr())
|
||||
end
|
||||
|
||||
function M.close()
|
||||
if not M.is_visible() then
|
||||
return
|
||||
end
|
||||
save_tab_state()
|
||||
switch_buf_if_last_buf()
|
||||
local tree_win = M.get_winnr()
|
||||
local current_win = a.nvim_get_current_win()
|
||||
for _, win in pairs(a.nvim_list_wins()) do
|
||||
if tree_win ~= win and a.nvim_win_get_config(win).relative == "" then
|
||||
a.nvim_win_close(tree_win, true)
|
||||
local prev_win = vim.fn.winnr "#" -- this tab only
|
||||
if tree_win == current_win and prev_win > 0 then
|
||||
a.nvim_set_current_win(vim.fn.win_getid(prev_win))
|
||||
end
|
||||
events._dispatch_on_tree_close()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.open(options)
|
||||
if M.is_visible() then
|
||||
return
|
||||
end
|
||||
|
||||
create_buffer()
|
||||
open_window()
|
||||
set_window_options_and_buffer()
|
||||
M.resize()
|
||||
|
||||
local opts = options or { focus_tree = true }
|
||||
if not opts.focus_tree then
|
||||
vim.cmd "wincmd p"
|
||||
end
|
||||
events._dispatch_on_tree_open()
|
||||
end
|
||||
|
||||
function M.resize(size)
|
||||
if type(size) == "string" then
|
||||
size = vim.trim(size)
|
||||
local first_char = size:sub(1, 1)
|
||||
size = tonumber(size)
|
||||
|
||||
if first_char == "+" or first_char == "-" then
|
||||
size = M.View.width + size
|
||||
end
|
||||
end
|
||||
|
||||
if type(size) == "number" and size <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if size then
|
||||
M.View.width = size
|
||||
M.View.height = size
|
||||
end
|
||||
|
||||
if not M.is_visible() then
|
||||
return
|
||||
end
|
||||
|
||||
if M.is_vertical() then
|
||||
a.nvim_win_set_width(M.get_winnr(), get_size())
|
||||
else
|
||||
a.nvim_win_set_height(M.get_winnr(), get_size())
|
||||
end
|
||||
|
||||
if not M.View.preserve_window_proportions then
|
||||
vim.cmd ":wincmd ="
|
||||
end
|
||||
end
|
||||
|
||||
function M.reposition_window()
|
||||
local move_to = move_tbl[M.View.side]
|
||||
a.nvim_command("wincmd " .. move_to)
|
||||
M.resize()
|
||||
end
|
||||
|
||||
local function set_current_win()
|
||||
local current_tab = a.nvim_get_current_tabpage()
|
||||
M.View.tabpages[current_tab].winnr = a.nvim_get_current_win()
|
||||
end
|
||||
|
||||
function M.open_in_current_win(opts)
|
||||
opts = opts or { hijack_current_buf = true, resize = true }
|
||||
create_buffer(opts.hijack_current_buf and a.nvim_get_current_buf())
|
||||
setup_tabpage(a.nvim_get_current_tabpage())
|
||||
set_current_win()
|
||||
set_window_options_and_buffer()
|
||||
if opts.resize then
|
||||
M.reposition_window()
|
||||
M.resize()
|
||||
end
|
||||
end
|
||||
|
||||
function M.abandon_current_window()
|
||||
local tab = a.nvim_get_current_tabpage()
|
||||
BUFNR_PER_TAB[tab] = nil
|
||||
M.View.tabpages[tab].winnr = nil
|
||||
end
|
||||
|
||||
function M.is_visible(opts)
|
||||
if opts and opts.any_tabpage then
|
||||
for _, v in pairs(M.View.tabpages) do
|
||||
if a.nvim_win_is_valid(v.winnr) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return M.get_winnr() ~= nil and a.nvim_win_is_valid(M.get_winnr())
|
||||
end
|
||||
|
||||
function M.set_cursor(opts)
|
||||
if M.is_visible() then
|
||||
pcall(a.nvim_win_set_cursor, M.get_winnr(), opts)
|
||||
-- patch until https://github.com/neovim/neovim/issues/17395 is fixed
|
||||
require("nvim-tree.renderer").draw()
|
||||
end
|
||||
end
|
||||
|
||||
function M.focus(winnr, open_if_closed)
|
||||
local wnr = winnr or M.get_winnr()
|
||||
|
||||
if a.nvim_win_get_tabpage(wnr or 0) ~= a.nvim_win_get_tabpage(0) then
|
||||
M.close()
|
||||
M.open()
|
||||
wnr = M.get_winnr()
|
||||
elseif open_if_closed and not M.is_visible() then
|
||||
M.open()
|
||||
end
|
||||
|
||||
a.nvim_set_current_win(wnr)
|
||||
end
|
||||
|
||||
function M.is_vertical()
|
||||
return M.View.side == "left" or M.View.side == "right"
|
||||
end
|
||||
|
||||
--- Restores the state of a NvimTree window if it was initialized before.
|
||||
function M.restore_tab_state()
|
||||
local tabpage = a.nvim_get_current_tabpage()
|
||||
M.set_cursor(M.View.cursors[tabpage])
|
||||
end
|
||||
|
||||
--- Returns the window number for nvim-tree within the tabpage specified
|
||||
---@param tabpage number: (optional) the number of the chosen tabpage. Defaults to current tabpage.
|
||||
---@return number
|
||||
function M.get_winnr(tabpage)
|
||||
tabpage = tabpage or a.nvim_get_current_tabpage()
|
||||
local tabinfo = M.View.tabpages[tabpage]
|
||||
if tabinfo ~= nil then
|
||||
return tabinfo.winnr
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the current nvim tree bufnr
|
||||
---@return number
|
||||
function M.get_bufnr()
|
||||
return BUFNR_PER_TAB[a.nvim_get_current_tabpage()]
|
||||
end
|
||||
|
||||
--- Checks if nvim-tree is displaying the help ui within the tabpage specified
|
||||
---@param tabpage number: (optional) the number of the chosen tabpage. Defaults to current tabpage.
|
||||
---@return number
|
||||
function M.is_help_ui(tabpage)
|
||||
tabpage = tabpage or a.nvim_get_current_tabpage()
|
||||
local tabinfo = M.View.tabpages[tabpage]
|
||||
if tabinfo ~= nil then
|
||||
return tabinfo.help
|
||||
end
|
||||
end
|
||||
|
||||
function M.toggle_help(tabpage)
|
||||
tabpage = tabpage or a.nvim_get_current_tabpage()
|
||||
M.View.tabpages[tabpage].help = not M.View.tabpages[tabpage].help
|
||||
end
|
||||
|
||||
function M.is_buf_valid(bufnr)
|
||||
return bufnr and a.nvim_buf_is_valid(bufnr) and a.nvim_buf_is_loaded(bufnr)
|
||||
end
|
||||
|
||||
function M._prevent_buffer_override()
|
||||
local view_winnr = M.get_winnr()
|
||||
local view_bufnr = M.get_bufnr()
|
||||
|
||||
-- need to schedule to let the new buffer populate the window
|
||||
-- because this event needs to be run on bufWipeout.
|
||||
-- Otherwise the curwin/curbuf would match the view buffer and the view window.
|
||||
vim.schedule(function()
|
||||
local curwin = a.nvim_get_current_win()
|
||||
local curbuf = a.nvim_win_get_buf(curwin)
|
||||
local bufname = a.nvim_buf_get_name(curbuf)
|
||||
if not bufname:match "NvimTree" then
|
||||
for i, tabpage in ipairs(M.View.tabpages) do
|
||||
if tabpage.winnr == view_winnr then
|
||||
M.View.tabpages[i] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if curwin ~= view_winnr or bufname == "" or curbuf == view_bufnr then
|
||||
return
|
||||
end
|
||||
|
||||
-- patch to avoid the overriding window to be fixed in size
|
||||
-- might need a better patch
|
||||
vim.cmd "setlocal nowinfixwidth"
|
||||
vim.cmd "setlocal nowinfixheight"
|
||||
M.open { focus_tree = false }
|
||||
require("nvim-tree.renderer").draw()
|
||||
a.nvim_win_close(curwin, { force = true })
|
||||
require("nvim-tree.actions.open-file").fn("edit", bufname)
|
||||
end)
|
||||
end
|
||||
|
||||
function M.is_root_folder_visible(cwd)
|
||||
return cwd ~= "/" and not M.View.hide_root_folder
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
local options = opts.view or {}
|
||||
M.View.side = options.side
|
||||
M.View.width = options.width
|
||||
M.View.height = options.height
|
||||
M.View.hide_root_folder = options.hide_root_folder
|
||||
M.View.preserve_window_proportions = options.preserve_window_proportions
|
||||
M.View.winopts.number = options.number
|
||||
M.View.winopts.relativenumber = options.relativenumber
|
||||
M.View.winopts.signcolumn = options.signcolumn
|
||||
end
|
||||
|
||||
return M
|
3
bundle/nvim-tree.lua/scripts/setup-hooks.sh
Normal file
3
bundle/nvim-tree.lua/scripts/setup-hooks.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ln -sf ../../.hooks/pre-commit.sh .git/hooks/pre-commit
|
21
bundle/nvim-tree.lua/update-default-opts.sh
Normal file
21
bundle/nvim-tree.lua/update-default-opts.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
# run after changing nvim-tree.lua DEFAULT_OPTS: scrapes and updates README.md, nvim-tree-lua.txt
|
||||
|
||||
begin="BEGIN_DEFAULT_OPTS"
|
||||
end="END_DEFAULT_OPTS"
|
||||
|
||||
# scrape, indented at 2
|
||||
sed -n -e "/${begin}/,/${end}/{ /${begin}/d; /${end}/d; p; }" lua/nvim-tree.lua > /tmp/DEFAULT_OPTS.2.lua
|
||||
|
||||
# indent some more
|
||||
sed -e "s/^ / /" /tmp/DEFAULT_OPTS.2.lua > /tmp/DEFAULT_OPTS.6.lua
|
||||
|
||||
# README.md indented at 2
|
||||
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_OPTS.2.lua
|
||||
}; /${end}/p; d }" README.md
|
||||
|
||||
# help, indented at 6
|
||||
sed -i -e "/${begin}/,/${end}/{ /${begin}/{p; r /tmp/DEFAULT_OPTS.6.lua
|
||||
}; /${end}/p; d }" doc/nvim-tree-lua.txt
|
||||
|
42
config/plugins/nvim-tree.vim
Normal file
42
config/plugins/nvim-tree.vim
Normal file
@ -0,0 +1,42 @@
|
||||
let s:WIN = SpaceVim#api#import('vim#window')
|
||||
nnoremap <silent> <F3> <cmd>NvimTreeToggle<CR>
|
||||
" we can not use this option to disable default key bindings
|
||||
" let g:nvim_tree_disable_default_keybindings = 1
|
||||
augroup vfinit
|
||||
au!
|
||||
autocmd FileType NvimTree call s:nvim_tree_init()
|
||||
autocmd BufEnter * nested if
|
||||
\ (!has('vim_starting') && s:WIN.win_count() == 1 && g:_spacevim_autoclose_filetree
|
||||
\ && &filetype ==# 'NvimTree') |
|
||||
\ call s:close_last_filetree() | endif
|
||||
augroup END
|
||||
function! s:close_last_filetree() abort
|
||||
call SpaceVim#layers#shell#close_terminal()
|
||||
q
|
||||
endfunction
|
||||
function! s:nvim_tree_init() abort
|
||||
nnoremap <silent><buffer> . :<C-u>lua require'nvim-tree.actions'.on_keypress('toggle_dotfiles')<Cr>
|
||||
endfunction
|
||||
lua <<EOF
|
||||
-- init.lua
|
||||
|
||||
-- empty setup using defaults: add your own options
|
||||
require'nvim-tree'.setup {
|
||||
view = {
|
||||
width = vim.api.nvim_eval('g:spacevim_sidebar_width'),
|
||||
height = 30,
|
||||
hide_root_folder = false,
|
||||
side = "right",
|
||||
preserve_window_proportions = false,
|
||||
number = false,
|
||||
relativenumber = false,
|
||||
signcolumn = "yes",
|
||||
mappings = {
|
||||
custom_only = true,
|
||||
list = {
|
||||
-- user mappings go here
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
EOF
|
Loading…
x
Reference in New Issue
Block a user