feat(live-filter): add ability to live filter out nodes in the tree (#1056)
This commit is contained in:
@@ -156,7 +156,7 @@ require'nvim-tree'.setup { -- BEGIN_DEFAULT_OPTS
|
|||||||
icons = {
|
icons = {
|
||||||
webdev_colors = true,
|
webdev_colors = true,
|
||||||
git_placement = "before",
|
git_placement = "before",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
hijack_directories = {
|
hijack_directories = {
|
||||||
enable = true,
|
enable = true,
|
||||||
@@ -216,6 +216,10 @@ require'nvim-tree'.setup { -- BEGIN_DEFAULT_OPTS
|
|||||||
cmd = "trash",
|
cmd = "trash",
|
||||||
require_confirm = true,
|
require_confirm = true,
|
||||||
},
|
},
|
||||||
|
live_filter = {
|
||||||
|
prefix = "[FILTER]: ",
|
||||||
|
always_show_folders = true,
|
||||||
|
},
|
||||||
log = {
|
log = {
|
||||||
enable = false,
|
enable = false,
|
||||||
truncate = false,
|
truncate = false,
|
||||||
@@ -269,6 +273,7 @@ require'nvim-tree'.setup { -- BEGIN_DEFAULT_OPTS
|
|||||||
- `S` will prompt the user to enter a path and then expands the tree to match the path
|
- `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
|
- `.` 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
|
- `C-k` will toggle a popup with file infos about the file under the cursor
|
||||||
|
- `f` will allow you to filter nodes dynamically based on regex matching.
|
||||||
|
|
||||||
### Settings
|
### Settings
|
||||||
|
|
||||||
@@ -330,6 +335,8 @@ local list = {
|
|||||||
{ key = "]c", action = "next_git_item" },
|
{ key = "]c", action = "next_git_item" },
|
||||||
{ key = "-", action = "dir_up" },
|
{ key = "-", action = "dir_up" },
|
||||||
{ key = "s", action = "system_open" },
|
{ key = "s", action = "system_open" },
|
||||||
|
{ key = "f", action = "live_filter" },
|
||||||
|
{ key = "F", action = "clear_live_filter" },
|
||||||
{ key = "q", action = "close" },
|
{ key = "q", action = "close" },
|
||||||
{ key = "g?", action = "toggle_help" },
|
{ key = "g?", action = "toggle_help" },
|
||||||
{ key = "W", action = "collapse_all" },
|
{ key = "W", action = "collapse_all" },
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ Values may be functions. Warning: this may result in unexpected behaviour.
|
|||||||
icons = {
|
icons = {
|
||||||
webdev_colors = true,
|
webdev_colors = true,
|
||||||
git_placement = "before",
|
git_placement = "before",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
hijack_directories = {
|
hijack_directories = {
|
||||||
enable = true,
|
enable = true,
|
||||||
@@ -184,6 +184,10 @@ Values may be functions. Warning: this may result in unexpected behaviour.
|
|||||||
cmd = "trash",
|
cmd = "trash",
|
||||||
require_confirm = true,
|
require_confirm = true,
|
||||||
},
|
},
|
||||||
|
live_filter = {
|
||||||
|
prefix = "[FILTER]: ",
|
||||||
|
always_show_folders = true,
|
||||||
|
},
|
||||||
log = {
|
log = {
|
||||||
enable = false,
|
enable = false,
|
||||||
truncate = false,
|
truncate = false,
|
||||||
@@ -519,6 +523,20 @@ Configuration for various actions.
|
|||||||
'+' (system), otherwise, it will be stored in '1' and '"'.
|
'+' (system), otherwise, it will be stored in '1' and '"'.
|
||||||
Type: `boolean`, Default: `true`
|
Type: `boolean`, Default: `true`
|
||||||
|
|
||||||
|
*nvim-tree.live_filter*
|
||||||
|
Configurations for the live_filtering feature.
|
||||||
|
The live filter allows you to filter the tree nodes dynamically, based on
|
||||||
|
regex matching (see |vim.regex|).
|
||||||
|
This feature is bound to the `f` key by default.
|
||||||
|
The filter can be cleared with the `F` key by default.
|
||||||
|
|
||||||
|
*nvim-tree.live_filter.prefix*
|
||||||
|
Prefix of the filter displayed in the buffer.
|
||||||
|
Type: `string`, Default: `"[FILTER]: "`
|
||||||
|
|
||||||
|
*nvim-tree.live_filter.always_show_folders*
|
||||||
|
Wether to filter folders or not.
|
||||||
|
Type: `boolean`, Default: `true`
|
||||||
|
|
||||||
*nvim-tree.log*
|
*nvim-tree.log*
|
||||||
Configuration for diagnostic logging.
|
Configuration for diagnostic logging.
|
||||||
@@ -764,6 +782,8 @@ Defaults to:
|
|||||||
{ key = "]c", action = "next_git_item" },
|
{ key = "]c", action = "next_git_item" },
|
||||||
{ key = "-", action = "dir_up" },
|
{ key = "-", action = "dir_up" },
|
||||||
{ key = "s", action = "system_open" },
|
{ key = "s", action = "system_open" },
|
||||||
|
{ key = "f", action = "live_filter" },
|
||||||
|
{ key = "F", action = "clear_live_filter" },
|
||||||
{ key = "q", action = "close" },
|
{ key = "q", action = "close" },
|
||||||
{ key = "g?", action = "toggle_help" },
|
{ key = "g?", action = "toggle_help" },
|
||||||
{ key = 'W', action = "collapse_all" },
|
{ key = 'W', action = "collapse_all" },
|
||||||
@@ -773,6 +793,7 @@ Defaults to:
|
|||||||
{ key = "U", action = "toggle_custom" },
|
{ key = "U", action = "toggle_custom" },
|
||||||
}
|
}
|
||||||
<
|
<
|
||||||
|
|
||||||
The `list` option in `view.mappings.list` is a table of
|
The `list` option in `view.mappings.list` is a table of
|
||||||
|
|
||||||
- key can be either a string or a table of string (lhs)
|
- key can be either a string or a table of string (lhs)
|
||||||
@@ -879,6 +900,11 @@ NvimTreeFileRenamed
|
|||||||
NvimTreeFileNew
|
NvimTreeFileNew
|
||||||
NvimTreeFileDeleted
|
NvimTreeFileDeleted
|
||||||
|
|
||||||
|
There are 2 highlight groups for the live filter feature
|
||||||
|
|
||||||
|
NvimTreeLiveFilterPrefix
|
||||||
|
NvimTreeLiveFilterValue
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
vinegar style *nvim-tree-vinegar*
|
vinegar style *nvim-tree-vinegar*
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,10 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
|
|||||||
cmd = "trash",
|
cmd = "trash",
|
||||||
require_confirm = true,
|
require_confirm = true,
|
||||||
},
|
},
|
||||||
|
live_filter = {
|
||||||
|
prefix = "[FILTER]: ",
|
||||||
|
always_show_folders = true,
|
||||||
|
},
|
||||||
log = {
|
log = {
|
||||||
enable = false,
|
enable = false,
|
||||||
truncate = false,
|
truncate = false,
|
||||||
@@ -538,6 +542,7 @@ function M.setup(conf)
|
|||||||
require("nvim-tree.view").setup(opts)
|
require("nvim-tree.view").setup(opts)
|
||||||
require("nvim-tree.lib").setup(opts)
|
require("nvim-tree.lib").setup(opts)
|
||||||
require("nvim-tree.renderer").setup(opts)
|
require("nvim-tree.renderer").setup(opts)
|
||||||
|
require("nvim-tree.live-filter").setup(opts)
|
||||||
|
|
||||||
setup_vim_commands()
|
setup_vim_commands()
|
||||||
setup_autocommands(opts)
|
setup_autocommands(opts)
|
||||||
|
|||||||
@@ -29,35 +29,37 @@ function M.fn(fname)
|
|||||||
|
|
||||||
local function iterate_nodes(nodes)
|
local function iterate_nodes(nodes)
|
||||||
for _, node in ipairs(nodes) do
|
for _, node in ipairs(nodes) do
|
||||||
i = i + 1
|
if not node.hidden then
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
if not node.absolute_path or not uv.fs_stat(node.absolute_path) then
|
if not node.absolute_path or not uv.fs_stat(node.absolute_path) then
|
||||||
break
|
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
|
end
|
||||||
|
|
||||||
if #node.nodes == 0 then
|
-- match against node absolute and link, as symlinks themselves will differ
|
||||||
core.get_explorer():expand(node)
|
if node.absolute_path == fname_real or node.link_to == fname_real then
|
||||||
end
|
|
||||||
|
|
||||||
if iterate_nodes(node.nodes) ~= nil then
|
|
||||||
return i
|
return i
|
||||||
end
|
end
|
||||||
-- mandatory to iterate i
|
local abs_match = vim.startswith(fname_real, node.absolute_path .. utils.path_separator)
|
||||||
elseif node.open then
|
local link_match = node.link_to and vim.startswith(fname_real, node.link_to .. utils.path_separator)
|
||||||
iterate_nodes(node.nodes)
|
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ local M = {
|
|||||||
{ key = "]c", action = "next_git_item" },
|
{ key = "]c", action = "next_git_item" },
|
||||||
{ key = "-", action = "dir_up" },
|
{ key = "-", action = "dir_up" },
|
||||||
{ key = "s", action = "system_open" },
|
{ key = "s", action = "system_open" },
|
||||||
|
{ key = "f", action = "live_filter" },
|
||||||
|
{ key = "F", action = "clear_live_filter" },
|
||||||
{ key = "q", action = "close" },
|
{ key = "q", action = "close" },
|
||||||
{ key = "g?", action = "toggle_help" },
|
{ key = "g?", action = "toggle_help" },
|
||||||
{ key = "W", action = "collapse_all" },
|
{ key = "W", action = "collapse_all" },
|
||||||
@@ -65,6 +67,8 @@ local keypress_funcs = {
|
|||||||
first_sibling = require("nvim-tree.actions.movements").sibling(-math.huge),
|
first_sibling = require("nvim-tree.actions.movements").sibling(-math.huge),
|
||||||
full_rename = require("nvim-tree.actions.rename-file").fn(true),
|
full_rename = require("nvim-tree.actions.rename-file").fn(true),
|
||||||
last_sibling = require("nvim-tree.actions.movements").sibling(math.huge),
|
last_sibling = require("nvim-tree.actions.movements").sibling(math.huge),
|
||||||
|
live_filter = require("nvim-tree.live-filter").start_filtering,
|
||||||
|
clear_live_filter = require("nvim-tree.live-filter").clear_filter,
|
||||||
next_git_item = require("nvim-tree.actions.movements").find_git_item "next",
|
next_git_item = require("nvim-tree.actions.movements").find_git_item "next",
|
||||||
next_sibling = require("nvim-tree.actions.movements").sibling(1),
|
next_sibling = require("nvim-tree.actions.movements").sibling(1),
|
||||||
parent_node = require("nvim-tree.actions.movements").parent_node(false),
|
parent_node = require("nvim-tree.actions.movements").parent_node(false),
|
||||||
@@ -92,6 +96,11 @@ function M.on_keypress(action)
|
|||||||
if view.is_help_ui() and action ~= "toggle_help" then
|
if view.is_help_ui() and action ~= "toggle_help" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if action == "live_filter" or action == "clear_live_filter" then
|
||||||
|
return keypress_funcs[action]()
|
||||||
|
end
|
||||||
|
|
||||||
local node = lib.get_node_at_cursor()
|
local node = lib.get_node_at_cursor()
|
||||||
if not node then
|
if not node then
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,34 +6,25 @@ local lib = require "nvim-tree.lib"
|
|||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local function get_line_from_node(node, find_parent)
|
local function get_index_of(node, nodes)
|
||||||
local node_path = node.absolute_path
|
local node_path = node.absolute_path
|
||||||
|
local line = 1
|
||||||
|
|
||||||
if find_parent then
|
for _, _node in ipairs(nodes) do
|
||||||
node_path = node.absolute_path:match("(.*)" .. utils.path_separator)
|
if not _node.hidden then
|
||||||
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)
|
local n = lib.get_last_group_node(_node)
|
||||||
if node_path == n.absolute_path then
|
if node_path == n.absolute_path then
|
||||||
return line, _node
|
return line
|
||||||
end
|
end
|
||||||
|
|
||||||
line = line + 1
|
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
|
||||||
end
|
end
|
||||||
return iter
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.parent_node(should_close)
|
function M.parent_node(should_close)
|
||||||
|
should_close = should_close or false
|
||||||
|
|
||||||
return function(node)
|
return function(node)
|
||||||
if should_close and node.open then
|
if should_close and node.open then
|
||||||
node.open = false
|
node.open = false
|
||||||
@@ -64,41 +55,26 @@ function M.sibling(direction)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local iter = get_line_from_node(node, true)
|
local parent = node.parent or core.get_explorer()
|
||||||
local node_path = node.absolute_path
|
local parent_nodes = vim.tbl_filter(function(n)
|
||||||
|
return not n.hidden
|
||||||
|
end, parent.nodes)
|
||||||
|
|
||||||
local line = 0
|
local node_index = get_index_of(node, parent_nodes)
|
||||||
local parent, _
|
|
||||||
|
|
||||||
-- Check if current node is already at root nodes
|
local target_idx = node_index + direction
|
||||||
for index, _node in ipairs(core.get_explorer().nodes) do
|
if target_idx < 1 then
|
||||||
if node_path == _node.absolute_path then
|
target_idx = 1
|
||||||
line = index
|
elseif target_idx > #parent_nodes then
|
||||||
end
|
target_idx = #parent_nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
if line > 0 then
|
local target_node = parent_nodes[target_idx]
|
||||||
parent = core.get_explorer()
|
local _, line = utils.find_node(core.get_explorer().nodes, function(n)
|
||||||
else
|
return n.absolute_path == target_node.absolute_path
|
||||||
_, parent = iter(core.get_explorer().nodes, true)
|
end)
|
||||||
if parent ~= nil and #parent.nodes > 1 then
|
|
||||||
line, _ = get_line_from_node(node)(parent.nodes)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ignore parent line count
|
view.set_cursor { line + 1, 0 }
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ local function get_hl_groups()
|
|||||||
GitNew = { fg = colors.yellow },
|
GitNew = { fg = colors.yellow },
|
||||||
|
|
||||||
WindowPicker = { gui = "bold", fg = "#ededed", bg = "#4493c8" },
|
WindowPicker = { gui = "bold", fg = "#ededed", bg = "#4493c8" },
|
||||||
|
LiveFilterPrefix = { gui = "bold", fg = colors.purple },
|
||||||
|
LiveFilterValue = { gui = "bold", fg = "#fff" },
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
local events = require "nvim-tree.events"
|
local events = require "nvim-tree.events"
|
||||||
local explorer = require "nvim-tree.explorer"
|
local explorer = require "nvim-tree.explorer"
|
||||||
|
local live_filter = require "nvim-tree.live-filter"
|
||||||
local view = require "nvim-tree.view"
|
local view = require "nvim-tree.view"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
@@ -28,6 +29,9 @@ function M.get_nodes_starting_line()
|
|||||||
if view.is_root_folder_visible(M.get_cwd()) then
|
if view.is_root_folder_visible(M.get_cwd()) then
|
||||||
offset = offset + 1
|
offset = offset + 1
|
||||||
end
|
end
|
||||||
|
if live_filter.filter then
|
||||||
|
return offset + 1
|
||||||
|
end
|
||||||
return offset
|
return offset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ local builders = require "nvim-tree.explorer.node-builders"
|
|||||||
local common = require "nvim-tree.explorer.common"
|
local common = require "nvim-tree.explorer.common"
|
||||||
local sorters = require "nvim-tree.explorer.sorters"
|
local sorters = require "nvim-tree.explorer.sorters"
|
||||||
local filters = require "nvim-tree.explorer.filters"
|
local filters = require "nvim-tree.explorer.filters"
|
||||||
|
local live_filter = require "nvim-tree.live-filter"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -76,6 +77,7 @@ function M.explore(node, status)
|
|||||||
end
|
end
|
||||||
|
|
||||||
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
||||||
|
live_filter.apply_filter(node)
|
||||||
return node.nodes
|
return node.nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ local builders = require "nvim-tree.explorer.node-builders"
|
|||||||
local common = require "nvim-tree.explorer.common"
|
local common = require "nvim-tree.explorer.common"
|
||||||
local filters = require "nvim-tree.explorer.filters"
|
local filters = require "nvim-tree.explorer.filters"
|
||||||
local sorters = require "nvim-tree.explorer.sorters"
|
local sorters = require "nvim-tree.explorer.sorters"
|
||||||
|
local live_filter = require "nvim-tree.live-filter"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ function M.reload(node, status)
|
|||||||
end
|
end
|
||||||
|
|
||||||
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
sorters.merge_sort(node.nodes, sorters.node_comparator)
|
||||||
|
live_filter.apply_filter(node)
|
||||||
return node.nodes
|
return node.nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,23 +13,25 @@ function M.get_node_at_cursor()
|
|||||||
if not core.get_explorer() then
|
if not core.get_explorer() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local winnr = view.get_winnr()
|
local winnr = view.get_winnr()
|
||||||
if not winnr then
|
if not winnr then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local cursor = api.nvim_win_get_cursor(view.get_winnr())
|
local cursor = api.nvim_win_get_cursor(view.get_winnr())
|
||||||
local line = cursor[1]
|
local line = cursor[1]
|
||||||
if view.is_help_ui() then
|
if view.is_help_ui() then
|
||||||
local help_lines = require("nvim-tree.renderer.help").compute_lines()
|
local help_lines = require("nvim-tree.renderer.help").compute_lines()
|
||||||
local help_text = utils.get_nodes_by_line(help_lines, 1)[line]
|
local help_text = utils.get_nodes_by_line(help_lines, 1)[line]
|
||||||
return { name = help_text }
|
return { name = help_text }
|
||||||
else
|
|
||||||
if line == 1 and core.get_explorer().cwd ~= "/" and view.is_root_folder_visible() then
|
|
||||||
return { name = ".." }
|
|
||||||
end
|
|
||||||
|
|
||||||
return utils.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())[line]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if line == 1 and view.is_root_folder_visible(core.get_cwd()) then
|
||||||
|
return { name = ".." }
|
||||||
|
end
|
||||||
|
|
||||||
|
return utils.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.
|
-- If node is grouped, return the last node in the group. Otherwise, return the given node.
|
||||||
|
|||||||
132
lua/nvim-tree/live-filter.lua
Normal file
132
lua/nvim-tree/live-filter.lua
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
local a = vim.api
|
||||||
|
|
||||||
|
local view = require "nvim-tree.view"
|
||||||
|
|
||||||
|
local M = {
|
||||||
|
filter = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function redraw()
|
||||||
|
require("nvim-tree.renderer").draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function reset_filter(node_)
|
||||||
|
local function iterate(n)
|
||||||
|
n.hidden = false
|
||||||
|
if n.nodes then
|
||||||
|
for _, node in pairs(n.nodes) do
|
||||||
|
iterate(node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
iterate(node_ or TreeExplorer)
|
||||||
|
end
|
||||||
|
|
||||||
|
local overlay_bufnr = nil
|
||||||
|
local overlay_winnr = nil
|
||||||
|
|
||||||
|
local function remove_overlay()
|
||||||
|
a.nvim_win_close(overlay_winnr, { force = true })
|
||||||
|
overlay_bufnr = nil
|
||||||
|
overlay_winnr = nil
|
||||||
|
|
||||||
|
if M.filter == "" then
|
||||||
|
M.clear_filter()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function matches(node)
|
||||||
|
local path = node.cwd or node.absolute_path
|
||||||
|
local name = vim.fn.fnamemodify(path, ":t")
|
||||||
|
return vim.regex(M.filter):match_str(name) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.apply_filter(node_)
|
||||||
|
if not M.filter or M.filter == "" then
|
||||||
|
reset_filter(node_)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function iterate(node)
|
||||||
|
local filtered_nodes = 0
|
||||||
|
local nodes = node.group_next and { node.group_next } or node.nodes
|
||||||
|
|
||||||
|
if nodes then
|
||||||
|
for _, n in pairs(nodes) do
|
||||||
|
iterate(n)
|
||||||
|
if n.hidden then
|
||||||
|
filtered_nodes = filtered_nodes + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local has_nodes = nodes and (M.always_show_folders or #nodes > filtered_nodes)
|
||||||
|
node.hidden = not (has_nodes or matches(node))
|
||||||
|
end
|
||||||
|
|
||||||
|
iterate(node_ or TreeExplorer)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function record_char()
|
||||||
|
vim.schedule(function()
|
||||||
|
M.filter = a.nvim_buf_get_lines(overlay_bufnr, 0, -1, false)[1]
|
||||||
|
M.apply_filter()
|
||||||
|
redraw()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function configure_buffer_overlay()
|
||||||
|
overlay_bufnr = a.nvim_create_buf(false, true)
|
||||||
|
|
||||||
|
a.nvim_buf_attach(overlay_bufnr, true, {
|
||||||
|
on_lines = record_char,
|
||||||
|
})
|
||||||
|
|
||||||
|
a.nvim_create_autocmd("InsertLeave", {
|
||||||
|
callback = remove_overlay,
|
||||||
|
once = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
a.nvim_buf_set_keymap(overlay_bufnr, "i", "<CR>", "<cmd>stopinsert<CR>", {})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_overlay()
|
||||||
|
configure_buffer_overlay()
|
||||||
|
overlay_winnr = a.nvim_open_win(overlay_bufnr, true, {
|
||||||
|
col = 1,
|
||||||
|
row = 0,
|
||||||
|
relative = "cursor",
|
||||||
|
width = math.max(20, a.nvim_win_get_width(view.get_winnr()) - #M.prefix - 2),
|
||||||
|
height = 1,
|
||||||
|
border = "none",
|
||||||
|
style = "minimal",
|
||||||
|
})
|
||||||
|
a.nvim_buf_set_option(overlay_bufnr, "modifiable", true)
|
||||||
|
a.nvim_buf_set_lines(overlay_bufnr, 0, -1, false, { M.filter })
|
||||||
|
vim.cmd "startinsert"
|
||||||
|
a.nvim_win_set_cursor(overlay_winnr, { 1, #M.filter + 1 })
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.start_filtering()
|
||||||
|
M.filter = M.filter or ""
|
||||||
|
|
||||||
|
redraw()
|
||||||
|
local row = require("nvim-tree.core").get_nodes_starting_line() - 1
|
||||||
|
local col = #M.prefix > 0 and #M.prefix - 1 or 1
|
||||||
|
view.set_cursor { row, col }
|
||||||
|
-- needs scheduling to let the cursor move before initializing the window
|
||||||
|
vim.schedule(create_overlay)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.clear_filter()
|
||||||
|
M.filter = nil
|
||||||
|
reset_filter()
|
||||||
|
redraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.setup(opts)
|
||||||
|
M.prefix = opts.live_filter.prefix
|
||||||
|
M.always_show_folders = opts.live_filter.always_show_folders
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -44,6 +44,12 @@ function Builder:configure_picture_map(picture_map)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Builder:configure_filter(filter, prefix)
|
||||||
|
self.filter_prefix = prefix
|
||||||
|
self.filter = filter
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
function Builder:configure_opened_file_highlighting(level)
|
function Builder:configure_opened_file_highlighting(level)
|
||||||
if level == 1 then
|
if level == 1 then
|
||||||
self.open_file_highlight = "icon"
|
self.open_file_highlight = "icon"
|
||||||
@@ -221,8 +227,8 @@ function Builder:_build_file(node, padding, git_highlight, git_icons_tbl)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Builder:_build_line(tree, node, idx)
|
function Builder:_build_line(node, idx, num_children)
|
||||||
local padding = pad.get_padding(self.depth, idx, tree, node, self.markers)
|
local padding = pad.get_padding(self.depth, idx, num_children, node, self.markers)
|
||||||
|
|
||||||
if self.depth > 0 then
|
if self.depth > 0 then
|
||||||
self:_insert_highlight("NvimTreeIndentMarker", 0, string.len(padding))
|
self:_insert_highlight("NvimTreeIndentMarker", 0, string.len(padding))
|
||||||
@@ -256,9 +262,28 @@ function Builder:_build_line(tree, node, idx)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Builder:_get_nodes_number(nodes)
|
||||||
|
if not self.filter then
|
||||||
|
return #nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
for _, n in pairs(nodes) do
|
||||||
|
if not n.hidden then
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
|
||||||
function Builder:build(tree)
|
function Builder:build(tree)
|
||||||
for idx, node in ipairs(tree.nodes) do
|
local num_children = self:_get_nodes_number(tree.nodes)
|
||||||
self:_build_line(tree, node, idx)
|
local idx = 1
|
||||||
|
for _, node in ipairs(tree.nodes) do
|
||||||
|
if not node.hidden then
|
||||||
|
self:_build_line(node, idx, num_children)
|
||||||
|
idx = idx + 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -277,6 +302,15 @@ function Builder:build_header(show_header)
|
|||||||
self.index = 1
|
self.index = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.filter then
|
||||||
|
local filter_line = self.filter_prefix .. "/" .. self.filter .. "/"
|
||||||
|
self:_insert_line(filter_line)
|
||||||
|
local prefix_length = string.len(self.filter_prefix)
|
||||||
|
self:_insert_highlight("NvimTreeLiveFilterPrefix", 0, prefix_length)
|
||||||
|
self:_insert_highlight("NvimTreeLiveFilterValue", prefix_length, string.len(filter_line))
|
||||||
|
self.index = self.index + 1
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ local function get_padding_arrows(icon_state)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_padding_indent_markers(depth, idx, tree, _, markers)
|
local function get_padding_indent_markers(depth, idx, nodes_number, _, markers)
|
||||||
local padding = ""
|
local padding = ""
|
||||||
if depth ~= 0 then
|
if depth ~= 0 then
|
||||||
local rdepth = depth / 2
|
local rdepth = depth / 2
|
||||||
markers[rdepth] = idx ~= #tree.nodes
|
markers[rdepth] = idx ~= nodes_number
|
||||||
for i = 1, rdepth do
|
for i = 1, rdepth do
|
||||||
if idx == #tree.nodes and i == rdepth then
|
if idx == nodes_number and i == rdepth then
|
||||||
padding = padding .. M.config.indent_markers.icons.corner
|
padding = padding .. M.config.indent_markers.icons.corner
|
||||||
elseif markers[i] then
|
elseif markers[i] then
|
||||||
padding = padding .. M.config.indent_markers.icons.edge
|
padding = padding .. M.config.indent_markers.icons.edge
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ local icon_component = require "nvim-tree.renderer.components.icons"
|
|||||||
local help = require "nvim-tree.renderer.help"
|
local help = require "nvim-tree.renderer.help"
|
||||||
local git = require "nvim-tree.renderer.components.git"
|
local git = require "nvim-tree.renderer.components.git"
|
||||||
local Builder = require "nvim-tree.renderer.builder"
|
local Builder = require "nvim-tree.renderer.builder"
|
||||||
|
local live_filter = require "nvim-tree.live-filter"
|
||||||
|
|
||||||
local api = vim.api
|
local api = vim.api
|
||||||
|
|
||||||
@@ -87,6 +88,7 @@ function M.draw()
|
|||||||
:configure_opened_file_highlighting(vim.g.nvim_tree_highlight_opened_files)
|
:configure_opened_file_highlighting(vim.g.nvim_tree_highlight_opened_files)
|
||||||
:configure_git_icons_padding(vim.g.nvim_tree_icon_padding)
|
:configure_git_icons_padding(vim.g.nvim_tree_icon_padding)
|
||||||
:configure_git_icons_placement(M.config.icons.git_placement)
|
:configure_git_icons_placement(M.config.icons.git_placement)
|
||||||
|
:configure_filter(live_filter.filter, live_filter.prefix)
|
||||||
:build_header(view.is_root_folder_visible(core.get_cwd()))
|
:build_header(view.is_root_folder_visible(core.get_cwd()))
|
||||||
:build(core.get_explorer())
|
:build(core.get_explorer())
|
||||||
:unwrap()
|
:unwrap()
|
||||||
|
|||||||
@@ -103,23 +103,26 @@ function M.find_node(nodes, fn)
|
|||||||
local function iter(nodes_, fn_)
|
local function iter(nodes_, fn_)
|
||||||
local i = 1
|
local i = 1
|
||||||
for _, node in ipairs(nodes_) do
|
for _, node in ipairs(nodes_) do
|
||||||
if fn_(node) then
|
if not node.hidden then
|
||||||
return node, i
|
if fn_(node) then
|
||||||
end
|
return node, i
|
||||||
if node.open and #node.nodes > 0 then
|
end
|
||||||
local n, idx = iter(node.nodes, fn_)
|
if node.open and #node.nodes > 0 then
|
||||||
i = i + idx
|
local n, idx = iter(node.nodes, fn_)
|
||||||
if n then
|
i = i + idx
|
||||||
return n, i
|
if n then
|
||||||
|
return n, i
|
||||||
|
end
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
end
|
end
|
||||||
else
|
|
||||||
i = i + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return nil, i
|
return nil, i
|
||||||
end
|
end
|
||||||
local node, i = iter(nodes, fn)
|
local node, i = iter(nodes, fn)
|
||||||
i = require("nvim-tree.view").View.hide_root_folder and i - 1 or i
|
i = require("nvim-tree.view").is_root_folder_visible() and i or i - 1
|
||||||
|
i = require("nvim-tree.live-filter").filter and i + 1 or i
|
||||||
return node, i
|
return node, i
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -132,12 +135,14 @@ function M.get_nodes_by_line(nodes_all, line_start)
|
|||||||
local line = line_start
|
local line = line_start
|
||||||
local function iter(nodes)
|
local function iter(nodes)
|
||||||
for _, node in ipairs(nodes) do
|
for _, node in ipairs(nodes) do
|
||||||
nodes_by_line[line] = node
|
if not node.hidden then
|
||||||
line = line + 1
|
nodes_by_line[line] = node
|
||||||
if node.open == true then
|
line = line + 1
|
||||||
local child = iter(node.nodes)
|
if node.open == true then
|
||||||
if child ~= nil then
|
local child = iter(node.nodes)
|
||||||
return child
|
if child ~= nil then
|
||||||
|
return child
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user