neo-tree The Best Solution For Filetree
Filetree とは、フォルダとファイルを木構造にして表示してくれるもので、VSCode などにも同じ機能があります。 Vim ではこの Filetree もキーバインドで操作できるようになっており、様々な種類があります。
ここでは私のお気に入り、neo-tree.nvim を紹介します。 ちなみに私も少しコントリビュートしています。

neo-tree の強みは、ファイルのステータスを右側に表示して、更に色もそれに応じてつけてくれることです。 また、フォルダはその子や孫の状態を反映した色になります。
対抗馬に nvim-tree があり、これもとても使いやすく、またこっちのほうが有名です。 しかし、私の環境ではとても動作が不安定だったため断念しました。
Setup
私は何がどう動いているのかこのプラグインは理解しているので設定ファイルがとてつもなく長いですが、公式ではもっと小さいセットアップを推奨しています。neo-tree.nvim - Minimal Quickstart
require("window-picker").setup({
autoselect_one = true,
include_current = false,
filter_rules = {
bo = {
filetype = { "neo-tree", "neo-tree-popup", "notify", "quickfix" },
buftype = { "terminal" },
},
},
other_win_hl_color = "#e35e4f",
})
vim.g.neo_tree_remove_legacy_commands = 1
local neotree = require("neo-tree")
neotree.setup({
close_if_last_window = true,
enable_diagnostics = true,
enable_git_status = true,
enable_modified_markers = true,
enable_refresh_on_write = true,
git_status_async = true,
git_status_async_options = {
batch_size = 1000,
batch_delay = 10,
max_lines = 10000,
},
hide_root_node = true,
retain_hidden_root_indent = false,
resize_timer_interval = -1, -- in ms, needed for containers to redraw right aligned and faded content
sort_case_insensitive = true,
source_selector = {
winbar = true,
},
default_component_configs = {
container = {
enable_character_fade = true,
},
indent = {
indent_size = 2,
padding = 0,
},
icon = {
folder_empty = "",
default = "",
highlight = "None",
},
modified = {
symbol = "[+]",
highlight = "NeoTreeModified",
},
name = {
trailing_slash = false,
use_git_status_colors = true,
highlight = "NeoTreeFileName",
},
git_status = {
symbols = {
added = "",
modified = "",
deleted = "",
renamed = "凜",
untracked = "✚",
ignored = "",
unstaged = "",
staged = "",
conflict = "",
},
align = "right",
},
},
renderers = {
directory = {
{ "indent" },
{ "icon" },
{ "current_filter" },
{
"container",
width = "100%",
right_padding = 1,
content = {
{ "name", zindex = 10 },
{
"symlink_target",
zindex = 10,
highlight = "NeoTreeSymbolicLinkTarget",
},
{ "clipboard", zindex = 10 },
{ "diagnostics", errors_only = true, zindex = 20, align = "right" },
},
},
},
file = {
{ "indent" },
{ "icon" },
{
"container",
width = "100%",
right_padding = 1,
content = {
{ "name", use_git_status_colors = true, zindex = 10 },
{
"symlink_target",
zindex = 10,
highlight = "NeoTreeSymbolicLinkTarget",
},
{ "clipboard", zindex = 10 },
{ "bufnr", zindex = 10 },
{ "modified", zindex = 20, align = "right" },
{ "diagnostics", zindex = 20, align = "right" },
{ "git_status", zindex = 20, align = "right" },
},
},
},
message = {
{ "indent", with_markers = false },
{ "name", highlight = "NeoTreeMessage" },
},
terminal = {
{ "indent" },
{ "icon" },
{ "name" },
{ "bufnr" },
},
},
nesting_rules = {},
window = { -- see https://github.com/MunifTanjim/nui.nvim/tree/main/lua/nui/popup for
position = "left",
width = 40,
mapping_options = {
noremap = true,
nowait = true,
},
mappings = {
["<space>"] = { "toggle_node", nowait = false },
["<2-LeftMouse>"] = "open",
["<cr>"] = "open",
-- ["<cr>"] = "open_with_window_picker",
["l"] = "open_with_window_picker",
["s"] = "split_with_window_picker",
["v"] = "vsplit_with_window_picker",
["t"] = "open_tabnew",
["C"] = "close_node",
["h"] = "close_node",
["z"] = "close_all_nodes",
["R"] = "refresh",
["a"] = { "add", config = { show_path = "relative" } },
["A"] = "add_directory",
["d"] = "delete",
["r"] = "rename",
["y"] = "copy_to_clipboard",
["x"] = "cut_to_clipboard",
["p"] = "paste_from_clipboard",
["c"] = "copy",
["m"] = "move",
["q"] = "close_window",
["?"] = "show_help",
},
},
filesystem = {
window = {
mappings = {
["H"] = "toggle_hidden",
["/"] = "fuzzy_finder",
["D"] = "fuzzy_finder_directory",
["f"] = "filter_on_submit",
["<C-x>"] = "clear_filter",
["<bs>"] = "navigate_up",
["."] = "set_root",
["[g"] = "prev_git_modified",
["]g"] = "next_git_modified",
["o"] = "system_open",
},
},
commands = {
system_open = function(state)
vim.api.nvim_command(string.format("silent !xdg-open '%s'", state.tree:get_node():get_id()))
end,
},
bind_to_cwd = false, -- true creates a 2-way binding between vim's cwd and neo-tree's root
filtered_items = {
visible = false, -- when true, they will just be displayed differently than normal items
force_visible_in_empty_folder = false,
show_hidden_count = true,
hide_dotfiles = false,
hide_gitignored = false,
hide_by_name = {
".DS_Store",
"thumbs.db",
},
hide_by_pattern = {
"*.meta",
"*:Zone.Identifier",
},
never_show = {
".DS_Store",
"thumbs.db",
},
},
find_by_full_path_words = true,
group_empty_dirs = true,
follow_current_file = true,
hijack_netrw_behavior = "open_default",
-- use_libuv_file_watcher = true,
},
git_status = {
window = {
mappings = {
["A"] = "git_add_all",
["gu"] = "git_unstage_file",
["ga"] = "git_add_file",
["gr"] = "git_revert_file",
["gc"] = "git_commit",
["gp"] = "git_push",
["gg"] = "git_commit_and_push",
},
},
},
event_handlers = {
{
event = "file_opened",
handler = function(_)
neotree.close_all()
end,
},
},
})Create Keybind to Open
nvim では基本的に木は閉じた状態で編集し、他のファイルを開きたいときだけ Filetree を開くと言った操作をしている人が多いです。 neo-tree を開くキーバインドを上のファイルに追記する形で追加しましょう。トグルなので、すでに開いている状態では閉じるキーバインドになります。
vim.keymap.set("n", "<leader>e", "<Cmd>Neotree toggle<CR>", { remap = false, silent = true })また、ファイルを名前検索する場合(VSCode でのCtrl + p)は別のプラグインを使用するのでそちらをご覧ください。
また、neo-tree にフォーカスしている間は特殊なキーバインドに切り替わります。
それらのキーバインドを知るには neo-tree を開いた状態で、?を押すとヘルプ画面が出てきます。
Issues and Pull Requests
このプラグインの作者の方はとても優しい人で、プラグインも開発も活発なので、問題があれば気兼ねなく Issue を立てるといいと思います。