neovim-flake/modules/filetree/nvimtree/nvimtree.nix
2024-04-04 18:11:29 +00:00

1114 lines
37 KiB
Nix

{
pkgs,
lib,
...
}: let
inherit (lib.options) mkEnableOption mkOption literalExpression;
inherit (lib.generators) mkLuaInline;
inherit (lib.types) nullOr str bool int submodule listOf enum oneOf attrs addCheck;
inherit (lib.nvim.types) mkPluginSetupOption;
in {
options.vim.filetree.nvimTree = {
enable = mkEnableOption "filetree via nvim-tree.lua";
mappings = {
toggle = mkOption {
type = nullOr str;
default = "<leader>t";
description = "Toggle NvimTree";
};
refresh = mkOption {
type = nullOr str;
default = "<leader>tr";
description = "Refresh NvimTree";
};
findFile = mkOption {
type = nullOr str;
default = "<leader>tg";
description = "Find file in NvimTree";
};
focus = mkOption {
type = nullOr str;
default = "<leader>tf";
description = "Focus NvimTree";
};
};
disableNetrw = mkOption {
default = false;
description = "Disables netrw and replaces it with tree";
type = bool;
};
setupOpts = mkPluginSetupOption "Nvim Tree" {
hijack_netrw = mkOption {
default = true;
description = "Prevents netrw from automatically opening when opening directories";
type = bool;
};
auto_reload_on_write = mkOption {
default = true;
description = "Auto reload tree on write";
type = bool;
};
update_focused_file = mkOption {
description = ''
Update the focused file on `BufEnter`, un-collapses the folders recursively
until it finds the file.
'';
default = {};
type = submodule {
options = {
enable = mkOption {
type = bool;
default = false;
description = "update focused file";
};
update_root = mkOption {
type = bool;
default = false;
description = ''
Update the root directory of the tree if the file is not under current
root directory. It prefers vim's cwd and `root_dirs`.
Otherwise it falls back to the folder containing the file.
Only relevant when `update_focused_file.enable` is `true`
'';
};
ignore_list = mkOption {
type = listOf str;
default = [];
description = ''
List of buffer names and filetypes that will not update the root dir
of the tree if the file isn't found under the current root directory.
Only relevant when `update_focused_file.update_root` and
`update_focused_file.enable` are `true`.
'';
};
};
};
};
sort = {
# TODO: function as a possible type
sorter = mkOption {
default = "name";
description = "How files within the same directory are sorted.";
type = enum ["name" "extension" "modification_time" "case_sensitive" "suffix" "filetype"];
};
folders_first = mkOption {
default = true;
description = "Sort folders before files. Has no effect when `sort.sorter` is a function.";
type = bool;
};
};
hijack_cursor = mkOption {
default = false;
description = "Hijack the cursor in the tree to put it at the start of the filename";
type = bool;
};
hijack_unnamed_buffer_when_opening = mkOption {
default = false;
description = "Open nvimtree in place of the unnamed buffer if it's empty.";
type = bool;
};
root_dirs = mkOption {
default = [];
description = ''
Preferred root directories. Only relevant when `updateFocusedFile.updateRoot` is `true`
'';
type = listOf str;
};
prefer_startup_root = mkOption {
default = false;
description = ''
Prefer startup root directory when updating root directory of the tree.
Only relevant when `update_focused_file.update_root` is `true`
'';
type = bool;
};
sync_root_with_cwd = mkOption {
type = bool;
default = false;
description = ''
Changes the tree root directory on `DirChanged` and refreshes the tree.
Only relevant when `updateFocusedFile.updateRoot` is `true`
(previously `update_cwd`)
'';
};
reload_on_bufenter = mkOption {
default = false;
type = bool;
description = "Automatically reloads the tree on `BufEnter` nvim-tree.";
};
respect_buf_cwd = mkOption {
default = false;
type = bool;
description = "Will change cwd of nvim-tree to that of new buffer's when opening nvim-tree.";
};
hijack_directories = {
enable = mkOption {
type = bool;
description = ''
Enable the `hijack_directories` feature. Disable this option if you use vim-dirvish or dirbuf.nvim.
If `hijack_netrw` and `disable_netrw` are `false`, this feature will be disabled.
'';
default = true;
};
auto_open = mkOption {
type = bool;
description = ''
Opens the tree if the tree was previously closed.
'';
default = false;
};
};
system_open = {
args = mkOption {
default = [];
description = "Optional argument list.";
type = listOf str;
};
cmd = mkOption {
default =
if pkgs.stdenv.isDarwin
then "open"
else if pkgs.stdenv.isLinux
then "${pkgs.xdg-utils}/bin/xdg-open"
else throw "NvimTree: No default system open command for this platform, please set `vim.filetree.nvimTree.systemOpen.cmd`";
description = "The open command itself";
type = str;
};
};
diagnostics = mkOption {
description = ''
Show LSP and COC diagnostics in the signcolumn
Note that the modified sign will take precedence over the diagnostics signs.
'';
default = {};
type = submodule {
options = {
enable = mkEnableOption "diagnostics view in the signcolumn.";
debounce_delay = mkOption {
description = "Idle milliseconds between diagnostic event and update.";
type = int;
default = 50;
};
show_on_dirs = mkOption {
description = "Show diagnostic icons on parent directories.";
default = false;
};
show_on_open_dirs = mkOption {
type = bool;
default = true;
description = ''
Show diagnostics icons on directories that are open.
Only relevant when `diagnostics.show_on_dirs` is `true`.
'';
};
icons = mkOption {
description = "Icons for diagnostic severity.";
default = {};
type = submodule {
options = {
hint = mkOption {
description = "Icon used for `hint` diagnostic.";
type = str;
default = "";
};
info = mkOption {
description = "Icon used for `info` diagnostic.";
type = str;
default = "";
};
warning = mkOption {
description = "Icon used for `warning` diagnostic.";
type = str;
default = "";
};
error = mkOption {
description = "Icon used for `error` diagnostic.";
type = str;
default = "";
};
};
};
};
severity = mkOption {
description = "Severity for which the diagnostics will be displayed. See `:help diagnostic-severity`";
default = {};
type = submodule {
options = {
min = mkOption {
description = "Minimum severity.";
type = enum ["HINT" "INFO" "WARNING" "ERROR"];
default = "HINT";
apply = x: mkLuaInline "vim.diagnostic.severity.${x}";
};
max = mkOption {
description = "Maximum severity.";
type = enum ["HINT" "INFO" "WARNING" "ERROR"];
default = "ERROR";
apply = x: mkLuaInline "vim.diagnostic.severity.${x}";
};
};
};
};
};
};
};
git = {
enable = mkEnableOption "Git integration with icons and colors.";
show_on_dirs = mkOption {
type = bool;
default = true;
description = "Show git icons on parent directories.";
};
show_on_open_dirs = mkOption {
type = bool;
default = true;
description = "Show git icons on directories that are open.";
};
disable_for_dirs = mkOption {
type = listOf str;
default = [];
description = ''
Disable git integration when git top-level matches these paths.
May be relative, evaluated via `":p"`
'';
};
timeout = mkOption {
type = int;
default = 400;
description = ''
Kills the git process after some time if it takes too long.
Git integration will be disabled after 10 git jobs exceed this timeout.
'';
};
};
modified = mkOption {
description = "Indicate which file have unsaved modification.";
default = {};
type = submodule {
options = {
enable = mkEnableOption "Modified files with icons and color highlight.";
show_on_dirs = mkOption {
type = bool;
description = "Show modified icons on parent directories.";
default = true;
};
show_on_open_dirs = mkOption {
type = bool;
description = "Show modified icons on directories that are open.";
default = true;
};
};
};
};
filesystem_watchers = mkOption {
description = ''
Will use file system watcher (libuv fs_event) to watch the filesystem for changes.
Using this will disable BufEnter / BufWritePost events in nvim-tree which
were used to update the whole tree. With this feature, the tree will be
updated only for the appropriate folder change, resulting in better
performance.
'';
default = {};
type = submodule {
options = {
enable = mkOption {
description = "Enable filesystem watchers.";
type = bool;
default = true;
};
debounce_delay = mkOption {
description = "Idle milliseconds between filesystem change and action.";
type = int;
default = 50;
};
ignore_dirs = mkOption {
type = listOf str;
default = [];
description = ''
List of vim regex for absolute directory paths that will not be watched.
Backslashes must be escaped e.g. `"my-project/\\.build$"`.
Useful when path is not in `.gitignore` or git integration is disabled.
'';
};
};
};
};
select_prompts = mkEnableOption ''
Use `vim.ui.select` style prompts. Necessary when using a UI prompt decorator such as dressing.nvim or telescope-ui-select.nvim
'';
view = mkOption {
description = "Window / buffer setup.";
default = {};
type = submodule {
options = {
centralize_selection = mkOption {
description = "If true, reposition the view so that the current node is initially centralized when entering nvim-tree.";
type = bool;
default = false;
};
cursorline = mkOption {
description = "Enable cursorline in nvim-tree window.";
type = bool;
default = true;
};
debounce_delay = mkOption {
type = int;
default = 15;
description = ''
Idle milliseconds before some reload / refresh operations.
Increase if you experience performance issues around screen refresh.
'';
};
width = mkOption {
description = ''
Width of the window: can be a `%` string, a number representing columns, a
function or a table.
A table (an attribute set in our case, see example) indicates that the view should be dynamically sized based on the
longest line.
'';
type = oneOf [int attrs];
default = 30;
example = literalExpression ''
{
min = 30;
max = -1;
padding = 1;
}
'';
};
side = mkOption {
description = "Side of the tree.";
type = enum ["left" "right"];
default = "left";
};
preserve_window_proportions = mkOption {
description = ''
Preserves window proportions when opening a file.
If `false`, the height and width of windows other than nvim-tree will be equalized.
'';
type = bool;
default = false;
};
number = mkOption {
description = "Print the line number in front of each line.";
type = bool;
default = false;
};
relativenumber = mkOption {
description = ''
Show the line number relative to the line with the cursor in front of each line.
If the option `view.number` is also `true`, the number on the cursor line
will be the line number instead of `0`.
'';
type = bool;
default = false;
};
signcolumn = mkOption {
description = ''Show diagnostic sign column. Value can be `"yes"`, `"auto"` or`"no"`.'';
type = enum ["yes" "auto" "no"];
default = "yes";
};
float = mkOption {
description = "Configuration options for floating window.";
default = {};
type = submodule {
options = {
enable = mkOption {
description = "If true, tree window will be floating.";
type = bool;
default = false;
};
quit_on_focus_loss = mkOption {
description = "Close the floating tree window when it loses focus.";
type = bool;
default = true;
};
open_win_config = mkOption {
description = "Floating window config. See `:h nvim_open_win()` for more details.";
type = attrs;
default = {
relative = "editor";
border = "rounded";
width = 30;
height = 30;
row = 1;
col = 1;
};
};
};
};
};
};
};
};
renderer = {
add_trailing = mkOption {
default = false;
description = "Appends a trailing slash to folder names.";
type = bool;
};
group_empty = mkOption {
default = false;
description = "Compact folders that only contain a single folder into one node in the file tree.";
type = bool;
};
full_name = mkOption {
default = false;
description = "Display node whose name length is wider than the width of nvim-tree window in floating window.";
type = bool;
};
highlight_git = mkOption {
type = bool;
default = false;
description = ''
Enable file highlight for git attributes using `NvimTreeGit` highlight groups.
Requires `nvimTree.git.enable`
This can be used with or without the icons.
'';
};
highlight_opened_files = mkOption {
type = enum ["none" "icon" "name" "all"];
default = "none";
description = ''
Highlight icons and/or names for bufloaded() files using the
`NvimTreeOpenedFile` highlight group.
'';
};
highlight_modified = mkOption {
type = enum ["none" "icon" "name" "all"];
default = "none";
description = ''
Highlight modified files in the tree using `NvimTreeNormal` highlight group.
Requires `nvimTree.view.highlightOpenedFiles`
'';
};
root_folder_label = mkOption {
type = oneOf [str bool];
default = false;
example = ''"":~:s?$?/..?"'';
description = ''
In what format to show root folder. See `:help filename-modifiers` for
available `string` options.
Set to `false` to hide the root folder.
Function is passed the absolute path of the root folder and should
return a string. e.g.
my_root_folder_label = function(path)
return ".../" .. vim.fn.fnamemodify(path, ":t")
end
'';
};
indent_width = mkOption {
type = addCheck int (x: x >= 1);
default = 2;
description = "Number of spaces for an each tree nesting level. Minimum 1.";
};
indent_markers = mkOption {
description = "Configuration options for tree indent markers.";
default = {};
type = submodule {
options = {
enable = mkEnableOption "Display indent markers when folders are open.";
inline_arrows = mkOption {
type = bool;
default = true;
description = "Display folder arrows in the same column as indent marker when using `renderer.icons.show.folder_arrow`";
};
icons = mkOption {
type = attrs;
description = "Individual elements of the indent markers";
default = {
corner = "";
edge = "";
item = "";
bottom = "";
none = "";
};
};
};
};
};
special_files = mkOption {
type = listOf str;
default = ["Cargo.toml" "README.md" "readme.md" "Makefile" "MAKEFILE" "flake.nix"]; # ;)
description = "A list of filenames that gets highlighted with `NvimTreeSpecialFile";
};
symlink_destination = mkOption {
type = bool;
default = true;
description = "Whether to show the destination of the symlink.";
};
icons = mkOption {
description = "Configuration options for icons.";
default = {};
type = submodule {
options = {
webdev_colors = mkOption {
type = bool;
description = " Use the webdev icon colors, otherwise `NvimTreeFileIcon`";
default = true;
};
git_placement = mkOption {
type = enum ["before" "after" "signcolumn"];
description = "Place where the git icons will be rendered. `signcolumn` requires `view.signcolumn` to be enabled.";
default = "before";
};
modified_placement = mkOption {
type = enum ["before" "after" "signcolumn"];
description = "Place where the modified icons will be rendered. `signcolumn` requires `view.signcolumn` to be enabled.";
default = "after";
};
padding = mkOption {
type = str;
description = "Inserted between icon and filename";
default = " ";
};
symlink_arrow = mkOption {
type = str;
description = "Used as a separator between symlinks' source and target.";
default = " ";
};
show = {
file = mkOption {
type = bool;
description = "Show an icon before the file name. `nvim-web-devicons` will be used if available.";
default = true;
};
folder = mkOption {
type = bool;
description = "Show an icon before the folder name.";
default = true;
};
folder_arrow = mkOption {
type = bool;
default = true;
description = ''
Show a small arrow before the folder node. Arrow will be a part of the
node when using `renderer.indent_markers`.
'';
};
git = mkOption {
type = bool;
default = false;
description = ''
Show a git status icon, see `renderer.icons.gitPlacement`
Requires `git.enable` to be true.
'';
};
modified = mkOption {
type = bool;
default = true;
description = ''
Show a modified icon, see `renderer.icons.modifiedPlacement`
Requires `modified.enable` to be true.
'';
};
};
glyphs = mkOption {
description = ''
Configuration options for icon glyphs.
NOTE: Do not set any glyphs to more than two characters if it's going
to appear in the signcolumn.
'';
default = {};
type = submodule {
options = {
default = mkOption {
type = str;
description = "Glyph for files. Will be overridden by `nvim-web-devicons` if available.";
default = "";
};
symlink = mkOption {
type = str;
description = "Glyph for symlinks.";
default = "";
};
modified = mkOption {
type = str;
description = "Icon to display for modified files.";
default = "";
};
# TODO: hardcode each attribute
folder = mkOption {
type = attrs;
description = "Glyphs for directories. Recommended to use the defaults unless you know what you are doing.";
default = {
default = "";
open = "";
arrow_open = "";
arrow_closed = "";
empty = "";
empty_open = "";
symlink = "";
symlink_open = "";
};
};
git = mkOption {
type = attrs;
description = "Glyphs for git status.";
default = {
unstaged = "";
staged = "";
unmerged = "";
renamed = "";
untracked = "";
deleted = "";
ignored = "";
};
};
};
};
};
};
};
};
};
filters = mkOption {
description = "Filtering options.";
default = {
git_ignored = false;
dotfiles = false;
git_clean = false;
no_buffer = false;
exclude = [];
};
type = submodule {
options = {
git_ignored = mkOption {
type = bool;
description = "Ignore files based on `.gitignore`. Requires git.enable` to be `true`";
default = false;
};
dotfiles = mkOption {
type = bool;
description = "Do not show dotfiles: files starting with a `.`";
default = false;
};
git_clean = mkOption {
type = bool;
default = false;
description = ''
Do not show files with no git status. This will show ignored files when
`nvimTree.filters.gitIgnored` is set, as they are effectively dirty.
'';
};
no_buffer = mkOption {
type = bool;
default = false;
description = "Do not show files that have no `buflisted()` buffer.";
};
exclude = mkOption {
type = listOf str;
default = [];
description = "List of directories or files to exclude from filtering: always show them.";
};
};
};
};
trash = mkOption {
description = "Configuration options for trashing.";
default = {
cmd = "${pkgs.glib}/bin/gio trash";
};
type = submodule {
options = {
cmd = mkOption {
type = str;
description = "The command used to trash items";
};
};
};
};
actions = mkOption {
description = "Configuration for various actions.";
default = {};
type = submodule {
options = {
use_system_clipboard = mkOption {
type = bool;
default = true;
description = ''
A boolean value that toggle the use of system clipboard when copy/paste
function are invoked. When enabled, copied text will be stored in registers
'+' (system), otherwise, it will be stored in '1' and '"'.
'';
};
# change_dir actions
change_dir = mkOption {
description = "vim `change-directory` behaviour";
default = {};
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
description = "Change the working directory when changing directories in the tree.";
};
global = mkOption {
type = bool;
default = false;
description = ''
Use `:cd` instead of `:lcd` when changing directories.
Consider that this might cause issues with the `nvimTree.syncRootWithCwd` option.
'';
};
restrict_above_cwd = mkOption {
type = bool;
default = false;
description = ''
Restrict changing to a directory above the global current working directory.
'';
};
};
};
};
# expand_all actions
expand_all = mkOption {
description = "Configuration for expand_all behaviour.";
default = {};
type = submodule {
options = {
max_folder_discovery = mkOption {
type = int;
default = 300;
description = ''
Limit the number of folders being explored when expanding every folders.
Avoids hanging neovim when running this action on very large folders.
'';
};
exclude = mkOption {
type = listOf str;
description = "A list of directories that should not be expanded automatically.";
default = [".git" "target" "build" "result"];
};
};
};
};
# file_popup actions
file_popup = mkOption {
description = "Configuration for file_popup behaviour.";
default = {};
type = submodule {
options = {
open_win_config = mkOption {
type = attrs;
default = {
col = 1;
row = 1;
relative = "cursor";
border = "rounded";
style = "minimal";
};
description = "Floating window config for file_popup. See |nvim_open_win| for more details.";
};
};
};
};
# open_file actions
open_file = mkOption {
description = "Configuration options for opening a file from nvim-tree.";
default = {};
type = submodule {
options = {
quit_on_open = mkOption {
type = bool;
description = "Closes the explorer when opening a file.";
default = false;
};
eject = mkOption {
type = bool;
description = "Prevent new opened file from opening in the same window as the tree.";
default = false;
};
resize_window = mkOption {
type = bool;
default = false;
description = "Resizes the tree when opening a file. Previously `view.auto_resize`";
};
window_picker = mkOption {
description = "window_picker";
default = {};
type = submodule {
options = {
enable = mkOption {
type = bool;
description = "Enable the window picker. If this feature is not enabled, files will open in window from which you last opened the tree.";
default = false;
};
picker = mkOption {
type = str;
default = "default";
description = ''
Change the default window picker, can be a string `"default"` or a function.
The function should return the window id that will open the node,
or `nil` if an invalid window is picked or user cancelled the action.
The picker may create a new window.
'';
example = literalExpression ''
-- with s1n7ax/nvim-window-picker plugin
require('window-picker').pick_window,
'';
};
chars = mkOption {
type = str;
description = "A string of chars used as identifiers by the window picker.";
default = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
};
exclude = {
filetype = mkOption {
type = listOf str;
description = "A list of filetypes to exclude from the window picker.";
default = ["notify" "packer" "qf" "diff" "fugitive" "fugitiveblame"];
};
buftype = mkOption {
type = listOf str;
description = "A list of buftypes to exclude from the window picker.";
default = ["nofile" "terminal" "help"];
};
};
};
};
};
};
};
};
remove_file = {
close_window = mkOption {
type = bool;
default = true;
description = "Close any window displaying a file when removing the file from the tree";
};
};
};
};
};
live_filter = mkOption {
description = ''
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.
'';
default = {};
type = submodule {
options = {
prefix = mkOption {
type = str;
description = "Prefix of the filter displayed in the buffer.";
default = "[FILTER]: ";
};
always_show_folders = mkOption {
type = bool;
description = "Whether to filter folders or not.";
default = true;
};
};
};
};
tab = mkOption {
description = "Configuration for tab behaviour.";
default = {};
type = submodule {
options = {
sync = mkOption {
description = "Configuration for syncing nvim-tree across tabs.";
default = {};
type = submodule {
options = {
open = mkOption {
type = bool;
default = false;
description = ''
Opens the tree automatically when switching tabpage or opening a new
tabpage if the tree was previously open.
'';
};
close = mkOption {
type = bool;
default = false;
description = ''
Closes the tree across all tabpages when the tree is closed.
'';
};
ignore = mkOption {
type = listOf str;
default = [];
description = ''
List of filetypes or buffer names on new tab that will prevent
`nvimTree.tab.sync.open` and `nvimTree.tab.sync.close`
'';
};
};
};
};
};
};
};
notify = mkOption {
description = "Configuration for notifications.";
default = {};
type = submodule {
options = {
threshold = mkOption {
type = enum ["ERROR" "WARNING" "INFO" "DEBUG"];
description = "Specify minimum notification level, uses the values from `vim.log.levels`";
default = "INFO";
apply = x: mkLuaInline "vim.log.levels.${x}";
};
absolute_path = mkOption {
type = bool;
description = "Whether to use absolute paths or item names in fs action notifications.";
default = true;
};
};
};
};
ui = mkOption {
description = "General UI configuration.";
default = {};
type = submodule {
options = {
confirm = {
remove = mkOption {
type = bool;
description = "Prompt before removing.";
default = true;
};
trash = mkOption {
type = bool;
description = "Prompt before trash.";
default = true;
};
};
};
};
};
};
# kept for backwards compatibility
openOnSetup = mkOption {
default = true;
description = "Open when vim is started on a directory";
type = bool;
};
};
}