plugins/bufferline: refactor + tests (#283)

This commit is contained in:
Gaétan Lepage 2023-03-31 17:06:27 +02:00 committed by GitHub
parent e2b24e166f
commit cbf6c56385
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 430 additions and 298 deletions

View file

@ -6,249 +6,262 @@
} @ args: } @ args:
with lib; let with lib; let
cfg = config.plugins.bufferline; cfg = config.plugins.bufferline;
optionWarnings = import ../../lib/option-warnings.nix args;
helpers = import ../helpers.nix args; helpers = import ../helpers.nix args;
highlight = mkOption { basePluginPath = ["plugins" "bufferline"];
type = types.nullOr (types.submodule ({...}: {
options = { highlight = helpers.mkCompositeOption "Highlight option" {
guifg = mkOption { guifg = helpers.mkNullOrOption types.str "foreground color";
type = types.nullOr types.str;
description = "foreground color"; guibg = helpers.mkNullOrOption types.str "background color";
default = null;
};
guibg = mkOption {
type = types.nullOr types.str;
description = "background color";
default = null;
};
};
}));
default = {};
}; };
in { in {
imports = [ imports = [
(optionWarnings.mkDeprecatedOption { (
option = ["plugins" "bufferline" "indicatorIcon"]; mkRenamedOptionModule
alternative = ["plugins" "bufferline" "indicator" "icon"]; (basePluginPath ++ ["indicatorIcon"])
}) (basePluginPath ++ ["indicator" "icon"])
)
]; ];
options = { options = {
plugins.bufferline = plugins.bufferline =
helpers.extraOptionsOptions helpers.extraOptionsOptions
// { // {
enable = mkEnableOption "bufferline"; enable = mkEnableOption "bufferline";
package = helpers.mkPackageOption "bufferline" pkgs.vimPlugins.bufferline-nvim; package = helpers.mkPackageOption "bufferline" pkgs.vimPlugins.bufferline-nvim;
numbers = mkOption {
type = types.nullOr types.lines; mode = helpers.defaultNullOpts.mkEnumFirstDefault ["buffers" "tabs"] "mode";
description = "A lua function customizing the styling of numbers.";
default = null; themable =
helpers.defaultNullOpts.mkBool true
"Whether or not bufferline highlights can be overridden externally";
numbers =
helpers.defaultNullOpts.mkNullable
(
with types;
either
(enum ["none" "ordinal" "buffer_id" "both"])
helpers.rawType
)
"none"
''
Customize the styling of numbers.
Either one of "none" "ordinal" "buffer_id" "both" or a lua function:
```
function({ ordinal, id, lower, raise }): string
```
'';
bufferCloseIcon = helpers.defaultNullOpts.mkStr "" "The close icon for each buffer.";
modifiedIcon =
helpers.defaultNullOpts.mkStr ""
"The icon indicating a buffer was modified.";
closeIcon = helpers.defaultNullOpts.mkStr "" "The close icon.";
closeCommand =
helpers.defaultNullOpts.mkStr "bdelete! %d"
"Command or function run when closing a buffer.";
leftMouseCommand =
helpers.defaultNullOpts.mkStr "buffer %d"
"Command or function run when clicking on a buffer.";
rightMouseCommand =
helpers.defaultNullOpts.mkStr "bdelete! %d"
"Command or function run when right clicking on a buffer.";
middleMouseCommand =
helpers.defaultNullOpts.mkStr "null"
"Command or function run when middle clicking on a buffer.";
indicator = helpers.mkCompositeOption "Indicator" {
icon = helpers.defaultNullOpts.mkStr "" "icon";
style = helpers.defaultNullOpts.mkEnumFirstDefault ["icon" "underline"] "style";
}; };
closeCommand = mkOption {
type = types.nullOr types.lines; leftTruncMarker = helpers.defaultNullOpts.mkStr "" "left trunc marker";
description = "Command or function run when closing a buffer.";
default = null; rightTruncMarker = helpers.defaultNullOpts.mkStr "" "right trunc marker";
};
rightMouseCommand = mkOption { separatorStyle =
type = types.nullOr types.lines; helpers.defaultNullOpts.mkEnum ["slant" "thick" "thin"] "thin"
description = "Command or function run when right clicking on a buffer."; "Separator style";
default = null;
}; nameFormatter =
leftMouseCommand = mkOption { helpers.defaultNullOpts.mkStr "null"
type = types.nullOr types.lines; ''
description = "Command or function run when clicking on a buffer."; A lua function that can be used to modify the buffer's label.
default = null; The argument 'buf' containing a name, path and bufnr is supplied.
}; '';
middleMouseCommand = mkOption {
type = types.nullOr types.lines; truncateNames = helpers.defaultNullOpts.mkBool true "Whether to truncate names.";
description = "Command or function run when middle clicking on a buffer.";
default = null; tabSize = helpers.defaultNullOpts.mkInt 18 "Size of the tabs";
};
# is deprecated, but might still work maxNameLength = helpers.defaultNullOpts.mkInt 18 "Max length of a buffer name.";
indicatorIcon =
mkOption { colorIcons = helpers.defaultNullOpts.mkBool true "Enable color icons.";
type = types.nullOr types.str;
description = "The Icon shown as a indicator for buffer. Changing it is NOT recommended, showBufferIcons = helpers.defaultNullOpts.mkBool true "Show buffer icons";
this is intended to be an escape hatch for people who cannot bear it for whatever reason.";
default = null; showBufferCloseIcons = helpers.defaultNullOpts.mkBool true "Show buffer close icons";
getElementIcon =
helpers.defaultNullOpts.mkStr "null"
''
Lua function returning an element icon.
```
fun(opts: IconFetcherOpts): string?, string?
```
'';
showCloseIcon = helpers.defaultNullOpts.mkBool true "Whether to show the close icon.";
showTabIndicators =
helpers.defaultNullOpts.mkBool true
"Whether to show the tab indicators.";
showDuplicatePrefix =
helpers.defaultNullOpts.mkBool true
"Whether to show the prefix of duplicated files.";
enforceRegularTabs =
helpers.defaultNullOpts.mkBool false
"Whether to enforce regular tabs.";
alwaysShowBufferline =
helpers.defaultNullOpts.mkBool true
"Whether to always show the bufferline.";
persistBufferSort =
helpers.defaultNullOpts.mkBool true
"Whether to make the buffer sort persistent.";
maxPrefixLength = helpers.defaultNullOpts.mkInt 15 "Maximum prefix length";
sortBy = helpers.defaultNullOpts.mkStr "id" "sort by";
diagnostics =
helpers.defaultNullOpts.mkNullable
(with types; either bool (enum ["nvim_lsp" "coc"])) "false" "diagnostics";
diagnosticsIndicator =
helpers.defaultNullOpts.mkStr "null"
"Either `null` or a function that returns the diagnistics indicator.";
diagnosticsUpdateInInsert =
helpers.defaultNullOpts.mkBool true
"Whether diagnostics should update in insert mode";
offsets = helpers.defaultNullOpts.mkNullable (types.listOf types.attrs) "null" "offsets";
groups = helpers.mkCompositeOption "groups" {
items =
helpers.defaultNullOpts.mkNullable (types.listOf types.attrs) "[]"
"List of groups.";
options = helpers.mkCompositeOption "Group options" {
toggleHiddenOnEnter =
helpers.defaultNullOpts.mkBool true
"Re-open hidden groups on bufenter.";
}; };
bufferCloseIcon = mkOption {
type = types.nullOr types.str;
description = "The close icon for each buffer.";
default = null;
}; };
modifiedIcon = mkOption {
type = types.nullOr types.str;
description = "The icon indicating a buffer was modified.";
default = null;
};
closeIcon = mkOption {
type = types.nullOr types.str;
description = "The close icon.";
default = null;
};
leftTruncMarker = mkOption {
type = types.nullOr types.str;
default = null;
};
rightTruncMarker = mkOption {
type = types.nullOr types.str;
default = null;
};
nameFormatter = mkOption {
type = types.nullOr types.lines;
description = "A lua function that can be used to modify the buffer's lable. The argument 'buf' containing a name, path and bufnr is supplied.";
default = null;
};
maxNameLength = mkOption {
type = types.nullOr types.int;
description = "Max length of a buffer name.";
default = null;
};
maxPrefixLength = mkOption {
type = types.nullOr types.int;
description = "Max length of a buffer prefix (used when a buffer is de-duplicated)";
default = null;
};
tabSize = mkOption {
type = types.nullOr types.int;
description = "Size of the tabs";
default = null;
};
diagnostics = mkOption {
type = types.nullOr (types.enum [false "nvim_lsp" "coc"]);
default = null;
};
diagnosticsUpdateInInsert = mkOption {
type = types.nullOr types.bool;
default = null;
};
diagnosticsIndicator = mkOption {
type = types.nullOr helpers.rawType;
default = null;
};
customFilter = mkOption {
type = types.nullOr types.lines;
default = null;
};
showBufferIcons = mkOption {
type = types.nullOr types.bool;
default = null;
};
showBufferCloseIcons = mkOption {
type = types.nullOr types.bool;
default = null;
};
showCloseIcon = mkOption {
type = types.nullOr types.bool;
default = null;
};
showTabIndicators = mkOption {
type = types.nullOr types.bool;
default = null;
};
persistBufferSort = mkOption {
type = types.nullOr types.bool;
default = null;
};
separatorStyle = mkOption {
type = types.nullOr (types.enum ["slant" "thick" "thin"]);
default = null;
};
enforceRegularTabs = mkOption {
type = types.nullOr types.bool;
default = null;
};
alwaysShowBufferline = mkOption {
type = types.nullOr types.bool;
default = null;
};
sortBy = mkOption {
type = types.nullOr (types.enum ["id" "extension" "relative_directory" "directory" "tabs"]);
default = null;
};
indicator = mkOption {
default = {};
type = types.nullOr (types.submodule ({...}: {
options = {
icon = mkOption {
type = types.nullOr types.str;
default = null;
};
style = mkOption {
type = types.nullOr (types.enum ["icon" "underline" "none"]);
default = null;
};
};
}));
};
highlights = mkOption {
default = {};
type = types.nullOr (types.submodule ({...}: {
options = {
fill = highlight;
background = highlight;
tab = highlight; hover = helpers.mkCompositeOption "Hover" {
tabSelected = highlight; enabled = mkEnableOption "hover";
tabClose = highlight;
closeButton = highlight; reveal = helpers.defaultNullOpts.mkNullable (types.listOf types.str) "[]" "reveal";
closeButtonVisible = highlight;
closeButtonSelected = highlight;
bufferVisible = highlight; delay = helpers.defaultNullOpts.mkInt 200 "delay";
bufferSelected = highlight;
diagnostic = highlight;
diagnosticVisible = highlight;
diagnosticSelected = highlight;
info = highlight;
infoVisible = highlight;
infoSelected = highlight;
infoDiagnostic = highlight;
infoDiagnosticVisible = highlight;
infoDiagnosticSelected = highlight;
warning = highlight;
warningVisible = highlight;
warningSelected = highlight;
warningDiagnostic = highlight;
warningDiagnosticVisible = highlight;
warningDiagnosticSelected = highlight;
error = highlight;
errorVisible = highlight;
errorSelected = highlight;
errorDiagnostic = highlight;
errorDiagnosticVisible = highlight;
errorDiagnosticSelected = highlight;
modified = highlight;
modifiedVisible = highlight;
modifiedSelected = highlight;
duplicate = highlight;
duplicateVisible = highlight;
duplicateSelected = highlight;
separator = highlight;
separatorVisible = highlight;
separatorSelected = highlight;
indicatorSelected = highlight;
pick = highlight;
pickVisible = highlight;
pickSelected = highlight;
};
}));
}; };
debug = helpers.mkCompositeOption "Debug options" {
logging = helpers.defaultNullOpts.mkBool false "Whether to enable logging";
};
customFilter =
helpers.defaultNullOpts.mkStr "null"
''
```
fun(buf: number, bufnums: number[]): boolean
```
'';
highlights =
helpers.mkCompositeOption ""
(
genAttrs
[
"fill"
"background"
"tab"
"tabSelected"
"tabClose"
"closeButton"
"closeButtonVisible"
"closeButtonSelected"
"bufferVisible"
"bufferSelected"
"diagnostic"
"diagnosticVisible"
"diagnosticSelected"
"info"
"infoVisible"
"infoSelected"
"infoDiagnostic"
"infoDiagnosticVisible"
"infoDiagnosticSelected"
"warning"
"warningVisible"
"warningSelected"
"warningDiagnostic"
"warningDiagnosticVisible"
"warningDiagnosticSelected"
"error"
"errorVisible"
"errorSelected"
"errorDiagnostic"
"errorDiagnosticVisible"
"errorDiagnosticSelected"
"modified"
"modifiedVisible"
"modifiedSelected"
"duplicate"
"duplicateVisible"
"duplicateSelected"
"separator"
"separatorVisible"
"separatorSelected"
"indicatorSelected"
"pick"
"pickVisible"
"pickSelected"
]
(name: highlight)
);
}; };
}; };
@ -256,109 +269,123 @@ in {
setupOptions = { setupOptions = {
options = options =
{ {
numbers = cfg.numbers; inherit
close_command = cfg.closeCommand; (cfg)
right_mouse_command = cfg.rightMouseCommand; mode
left_mouse_command = cfg.leftMouseCommand; themable
middle_mouse_command = cfg.middleMouseCommand; numbers
# deprecated, but might still work ;
indicator_icon = cfg.indicatorIcon;
indicator =
if cfg.indicator != null
then
with cfg.indicator; {
icon = icon;
style = style;
}
else null;
buffer_close_icon = cfg.bufferCloseIcon; buffer_close_icon = cfg.bufferCloseIcon;
modified_icon = cfg.modifiedIcon; modified_icon = cfg.modifiedIcon;
close_icon = cfg.closeIcon; close_icon = cfg.closeIcon;
close_command = cfg.closeCommand;
left_mouse_command = cfg.leftMouseCommand;
right_mouse_command = cfg.rightMouseCommand;
middle_mouse_command = cfg.middleMouseCommand;
inherit (cfg) indicator;
left_trunc_marker = cfg.leftTruncMarker; left_trunc_marker = cfg.leftTruncMarker;
right_trunc_marker = cfg.rightTruncMarker; right_trunc_marker = cfg.rightTruncMarker;
name_formatter = cfg.nameFormatter; separator_style = cfg.separatorStyle;
max_name_length = cfg.maxNameLength; name_formatter =
max_prefix_length = cfg.maxPrefixLength; helpers.ifNonNull' cfg.nameFormatter
(helpers.mkRaw cfg.nameFormatter);
truncate_names = cfg.truncateNames;
tab_size = cfg.tabSize; tab_size = cfg.tabSize;
diagnostics = cfg.diagnostics; max_name_length = cfg.maxNameLength;
diagnostics_update_in_insert = cfg.diagnosticsUpdateInInsert; color_icons = cfg.colorIcons;
diagnostics_indicator = cfg.diagnosticsIndicator;
custom_filter = cfg.customFilter;
show_buffer_icons = cfg.showBufferIcons; show_buffer_icons = cfg.showBufferIcons;
show_buffer_close_icons = cfg.showBufferCloseIcons; show_buffer_close_icons = cfg.showBufferCloseIcons;
get_element_icon =
helpers.ifNonNull' cfg.getElementIcon
(helpers.mkRaw cfg.getElementIcon);
show_close_icon = cfg.showCloseIcon; show_close_icon = cfg.showCloseIcon;
show_tab_indicators = cfg.showTabIndicators; show_tab_indicators = cfg.showTabIndicators;
persist_buffer_sort = cfg.persistBufferSort; show_duplicate_prefix = cfg.showDuplicatePrefix;
separator_style = cfg.separatorStyle;
enforce_regular_tabs = cfg.enforceRegularTabs; enforce_regular_tabs = cfg.enforceRegularTabs;
always_show_bufferline = cfg.alwaysShowBufferline; always_show_bufferline = cfg.alwaysShowBufferline;
persist_buffer_sort = cfg.persistBufferSort;
max_prefix_length = cfg.maxPrefixLength;
sort_by = cfg.sortBy; sort_by = cfg.sortBy;
inherit (cfg) diagnostics;
diagnostics_indicator =
helpers.ifNonNull' cfg.diagnosticsIndicator
(helpers.mkRaw cfg.diagnosticsIndicator);
diagnostics_update_in_insert = cfg.diagnosticsUpdateInInsert;
inherit (cfg) offsets;
groups = helpers.ifNonNull' cfg.groups {
inherit (cfg.groups) items;
options = helpers.ifNonNull' (cfg.groups.options) {
toggle_hidden_on_enter = cfg.groups.options.toggleHiddenOnEnter;
};
};
inherit (cfg) hover;
inherit (cfg) debug;
custom_filter =
helpers.ifNonNull' cfg.customFilter
(helpers.mkRaw cfg.customFilter);
} }
// cfg.extraOptions; // cfg.extraOptions;
highlights =
if builtins.isNull cfg.highlights
then null
else
with cfg.highlights; {
fill = fill;
background = background;
tab = tab; highlights = with cfg.highlights;
tab_selected = tabSelected; helpers.ifNonNull' cfg.highlights {
tab_close = tabClose; inherit fill background;
close_button = closeButton;
close_button_visible = closeButtonVisible;
close_button_selected = closeButtonSelected;
buffer_visible = bufferVisible; inherit tab;
buffer_selected = bufferSelected; tab_selected = tabSelected;
tab_close = tabClose;
close_button = closeButton;
close_button_visible = closeButtonVisible;
close_button_selected = closeButtonSelected;
diagnostic = diagnostic; buffer_visible = bufferVisible;
diagnostic_visible = diagnosticVisible; buffer_selected = bufferSelected;
diagnostic_selected = diagnosticSelected;
info = info; inherit diagnostic;
info_visible = infoVisible; diagnostic_visible = diagnosticVisible;
info_selected = infoSelected; diagnostic_selected = diagnosticSelected;
info_diagnostic = infoDiagnostic; inherit info;
info_diagnostic_visible = infoDiagnosticVisible; info_visible = infoVisible;
info_diagnostic_selected = infoDiagnosticSelected; info_selected = infoSelected;
warning = warning; info_diagnostic = infoDiagnostic;
warning_visible = warningVisible; info_diagnostic_visible = infoDiagnosticVisible;
warning_selected = warningSelected; info_diagnostic_selected = infoDiagnosticSelected;
warning_diagnostic = warningDiagnostic; inherit warning;
warning_diagnostic_visible = warningDiagnosticVisible; warning_visible = warningVisible;
warning_diagnostic_selected = warningDiagnosticSelected; warning_selected = warningSelected;
error = error; warning_diagnostic = warningDiagnostic;
error_visible = errorVisible; warning_diagnostic_visible = warningDiagnosticVisible;
error_selected = errorSelected; warning_diagnostic_selected = warningDiagnosticSelected;
error_diagnostic = errorDiagnostic; inherit error;
error_diagnostic_visible = errorDiagnosticVisible; error_visible = errorVisible;
error_diagnostic_selected = errorDiagnosticSelected; error_selected = errorSelected;
modified = modified; error_diagnostic = errorDiagnostic;
modified_visible = modifiedVisible; error_diagnostic_visible = errorDiagnosticVisible;
modified_selected = modifiedSelected; error_diagnostic_selected = errorDiagnosticSelected;
duplicate = duplicate; inherit modified;
duplicate_visible = duplicateVisible; modified_visible = modifiedVisible;
duplicate_selected = duplicateSelected; modified_selected = modifiedSelected;
separator = separator; inherit duplicate;
separator_visible = separatorVisible; duplicate_visible = duplicateVisible;
separator_selected = separatorSelected; duplicate_selected = duplicateSelected;
indicator_selected = indicatorSelected; inherit separator;
separator_visible = separatorVisible;
separator_selected = separatorSelected;
pick = pick; indicator_selected = indicatorSelected;
pick_visible = pickVisible;
pick_selected = pickSelected; inherit pick;
}; pick_visible = pickVisible;
pick_selected = pickSelected;
};
}; };
in in
mkIf cfg.enable { mkIf cfg.enable {

View file

@ -0,0 +1,105 @@
{
# Empty configuration
empty = {
plugins.bufferline.enable = true;
};
# Lua functions
example = {
plugins.bufferline = {
enable = true;
customFilter = ''
function(buf_number, buf_numbers)
-- filter out filetypes you don't want to see
if vim.bo[buf_number].filetype ~= "<i-dont-want-to-see-this>" then
return true
end
-- filter out by buffer name
if vim.fn.bufname(buf_number) ~= "<buffer-name-I-dont-want>" then
return true
end
-- filter out based on arbitrary rules
-- e.g. filter out vim wiki buffer from tabline in your work repo
if vim.fn.getcwd() == "<work-repo>" and vim.bo[buf_number].filetype ~= "wiki" then
return true
end
-- filter out by it's index number in list (don't show first buffer)
if buf_numbers[1] ~= buf_number then
return true
end
end
'';
getElementIcon = ''
function(element)
-- element consists of {filetype: string, path: string, extension: string, directory: string}
-- This can be used to change how bufferline fetches the icon
-- for an element e.g. a buffer or a tab.
-- e.g.
local icon, hl = require('nvim-web-devicons').get_icon_by_filetype(opts.filetype, { default = false })
return icon, hl
end
'';
};
};
# All the upstream default options of bufferline
defaults = {
plugins.bufferline = {
enable = true;
mode = "buffers";
themable = true;
numbers = "none";
bufferCloseIcon = "";
modifiedIcon = "";
closeIcon = "";
closeCommand = "bdelete! %d";
leftMouseCommand = "buffer %d";
rightMouseCommand = "bdelete! %d";
middleMouseCommand = null;
indicator = {
icon = "";
style = "icon";
};
leftTruncMarker = "";
rightTruncMarker = "";
separatorStyle = "thin";
nameFormatter = null;
truncateNames = true;
tabSize = 18;
maxNameLength = 18;
colorIcons = true;
showBufferIcons = true;
showBufferCloseIcons = true;
getElementIcon = null;
showCloseIcon = true;
showTabIndicators = true;
showDuplicatePrefix = true;
enforceRegularTabs = false;
alwaysShowBufferline = true;
persistBufferSort = true;
maxPrefixLength = 15;
sortBy = "id";
diagnostics = false;
diagnosticsIndicator = null;
diagnosticsUpdateInInsert = true;
offsets = null;
groups = {
items = [];
options = {
toggleHiddenOnEnter = true;
};
};
hover = {
enabled = false;
reveal = [];
delay = 200;
};
debug = {
logging = false;
};
customFilter = null;
highlights = {};
};
};
}