From dfb8f1cd67a0afd5af62d33997451e842c8b4e2d Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sat, 24 Aug 2024 20:50:24 -0500 Subject: [PATCH] plugins/lualine: migrate to mkNeovimPlugin --- plugins/colorschemes/base16/default.nix | 2 +- plugins/statuslines/lualine.nix | 493 +++++++++++------- .../example-configurations/issues.nix | 24 +- .../plugins/statuslines/lualine.nix | 207 ++++++-- 4 files changed, 495 insertions(+), 231 deletions(-) diff --git a/plugins/colorschemes/base16/default.nix b/plugins/colorschemes/base16/default.nix index da9b370cd9..8db6e40efc 100644 --- a/plugins/colorschemes/base16/default.nix +++ b/plugins/colorschemes/base16/default.nix @@ -173,7 +173,7 @@ lib.nixvim.neovim-plugin.mkNeovimPlugin config { extraConfig = cfg: { plugins.airline.settings.theme = lib.mkIf cfg.setUpBar (lib.mkDefault name); - plugins.lualine.theme = lib.mkIf cfg.setUpBar (lib.mkDefault name); + plugins.lualine.settings.options.theme = lib.mkIf cfg.setUpBar (lib.mkDefault name); plugins.lightline.settings.colorscheme = lib.mkDefault null; opts.termguicolors = lib.mkDefault true; diff --git a/plugins/statuslines/lualine.nix b/plugins/statuslines/lualine.nix index bddcd48f6d..5a48c091b6 100644 --- a/plugins/statuslines/lualine.nix +++ b/plugins/statuslines/lualine.nix @@ -1,149 +1,226 @@ { lib, - helpers, config, + options, pkgs, ... }: -with lib; let - cfg = config.plugins.lualine; + inherit (lib.nixvim) defaultNullOpts mkPackageOption mkSettingsRenamedOptionModules; + inherit (lib) types mkOption; + # TODO: do we really need this mkSeparatorsOption = { leftDefault ? " ", rightDefault ? " ", }: { - left = helpers.defaultNullOpts.mkStr leftDefault "Left separator"; - right = helpers.defaultNullOpts.mkStr rightDefault "Right separator"; + left = defaultNullOpts.mkStr leftDefault "Left separator"; + right = defaultNullOpts.mkStr rightDefault "Right separator"; }; mkComponentOptions = defaultName: - helpers.mkNullOrOption ( - with types; - listOf ( - either str (submodule { - options = { - name = mkOption { - type = types.either types.str helpers.nixvimTypes.rawLua; - description = "Component name or function"; - default = defaultName; - }; - - icons_enabled = helpers.defaultNullOpts.mkBool true '' - Enables the display of icons alongside the component. - ''; - - icon = helpers.mkNullOrOption ( - with types; - either str (submodule { - freeformType = attrsOf anything; - - options = { - icon = mkOption { - type = str; - description = "Icon character."; - }; - }; - }) - ) "Defines the icon to be displayed in front of the component."; - - separator = mkSeparatorsOption { }; - - color = helpers.mkNullOrOption (types.attrsOf types.str) '' - Defines a custom color for the component. - ''; - - padding = helpers.defaultNullOpts.mkNullable (types.either types.int ( - types.submodule { + lib.nixvim.mkNullOrOption' { + type = + with types; + listOf ( + either str (submodule { + freeformType = attrsOf anything; + + options = { + # TODO: deprecate + # name = mkOption { + # type = either str rawLua; + # description = "Component name or function"; + # default = defaultName; + # }; + + icons_enabled = defaultNullOpts.mkBool true '' + Enables the display of icons alongside the component. + ''; + + icon = lib.nixvim.mkNullOrOption' { + type = either str (submodule { + freeformType = attrsOf anything; + + # TODO: deprecate + # options = { + # icon = mkOption { + # type = str; + # description = "Icon character."; + # }; + # }; + }); + description = "Defines the icon to be displayed in front of the component."; + }; + + separator = mkSeparatorsOption { }; + + color = defaultNullOpts.mkNullable (either attrs str) null '' + Defines a custom color for the component. + + Default is the color defined by your theme for that section and mode. + ''; + + padding = defaultNullOpts.mkNullable (either int (submodule { options = { left = mkOption { - type = types.int; + type = int; description = "left padding"; }; right = mkOption { - type = types.int; + type = int; description = "left padding"; }; }; - } - )) 1 "Adds padding to the left and right of components."; - - fmt = helpers.mkNullOrLuaFn '' - A lua function to format the component string. - - Example: - ```lua - function(text) - return text .. "!!!" - end - ``` - ''; - - extraConfig = mkOption { - type = types.attrs; - default = { }; - description = "extra options for the component"; + })) 1 "Adds padding to the left and right of components."; + + fmt = lib.nixvim.mkNullOrLuaFn '' + A lua function to format the component string. + + Example: + ```lua + function(text) + return text .. "!!!" + end + ``` + ''; + + # TODO: deprecate + # extraConfig = mkOption { + # type = attrs; + # default = { }; + # description = "extra options for the component"; + # }; }; - }; - }) - ) - ) ""; + }) + ); + # TODO: best way to do this? + # Was setting up apply to handle the old way of transforming a config to the setup call + apply = + list: + if lib.isList list then + map ( + option: + if option != null && lib.isAttrs option then + let + # NOTE: Handle deprecated name property + # This was used to create an unkeyed attribute for a component name + optionWithNameTransformed = + if lib.hasAttr "name" option then + lib.removeAttrs (option // { "__unkeyed" = option.name; }) [ "name" ] + else + option; + + # NOTE: Handle deprecated nested icon option + # This was used to create an unkeyed attribute for an icon with options + optionWithIconTransformed = + if + lib.hasAttr "icon" optionWithNameTransformed + && lib.isAttrs optionWithNameTransformed.icon + && lib.hasAttr "icon" optionWithNameTransformed.icon + then + lib.removeAttrs ( + optionWithNameTransformed.icon // { "__unkeyed" = optionWithNameTransformed.icon.icon; } + ) [ "icon" ] + else + optionWithNameTransformed; + + # NOTE: Handles the deprecated extraConfig option + # Old freeform option was just merged into the existing config + flattenedExtraConfig = optionWithIconTransformed.extraConfig or { }; + optionWithoutExtraConfig = lib.removeAttrs optionWithIconTransformed [ "extraConfig" ]; + finalTransformedValue = optionWithoutExtraConfig // flattenedExtraConfig; + in + finalTransformedValue + else + option + ) list + else + list; + description = ""; + }; mkEmptySectionOption = name: { - lualine_a = mkComponentOptions ""; - lualine_b = mkComponentOptions ""; - lualine_c = mkComponentOptions ""; - lualine_x = mkComponentOptions ""; - lualine_y = mkComponentOptions ""; - lualine_z = mkComponentOptions ""; + lualine_a = mkComponentOptions "Left section on left side."; + lualine_b = mkComponentOptions "Middle section on left side."; + lualine_c = mkComponentOptions "Right section on left side."; + lualine_x = mkComponentOptions "Left section on right side."; + lualine_y = mkComponentOptions "Middle section on right side."; + lualine_z = mkComponentOptions "Right section on right side."; }; in -{ - options = { - plugins.lualine = { - enable = mkEnableOption "lualine"; - - package = helpers.mkPluginPackageOption "lualine" pkgs.vimPlugins.lualine-nvim; - - gitPackage = helpers.mkPackageOption { - name = "git"; - default = pkgs.git; - }; +lib.nixvim.neovim-plugin.mkNeovimPlugin config { + name = "lualine"; + originalName = "lualine-nvim"; + defaultPackage = pkgs.vimPlugins.lualine-nvim; + + maintainers = [ lib.maintainers.khaneliman ]; + + # TODO: Added 2024-08-24, remove after 24.11 + optionsRenamedToSettings = [ + "extensions" + "sections" + "inactiveSections" + "tabline" + "winbar" + "inactiveWinbar" + ]; + imports = + let + basePluginPath = [ + "plugins" + "lualine" + ]; + settingsPath = basePluginPath ++ [ "settings" ]; + optionsPath = settingsPath ++ [ "options" ]; + oldOptions = [ + "theme" + "globalstatus" + "refresh" + "iconsEnabled" + "sectionSeparators" + "componentSeparators" + "disabledFiletypes" + "ignoreFocus" + "alwaysDivideMiddle" + ]; + in + mkSettingsRenamedOptionModules basePluginPath optionsPath oldOptions; - iconsEnabled = mkOption { - type = types.bool; - description = "Whether to enable/disable icons for all components."; - default = true; - }; + settingsOptions = { + options = { + icons_enabled = defaultNullOpts.mkBool true '' + Whether to enable/disable icons for all components. + ''; - theme = helpers.defaultNullOpts.mkNullable ( + theme = defaultNullOpts.mkNullable ( with types; either str attrs ) "auto" "The theme to use for lualine-nvim."; - componentSeparators = mkSeparatorsOption { + component_separators = mkSeparatorsOption { leftDefault = ""; rightDefault = ""; }; - sectionSeparators = mkSeparatorsOption { + section_separators = mkSeparatorsOption { leftDefault = ""; rightDefault = ""; }; - disabledFiletypes = { - statusline = helpers.defaultNullOpts.mkListOf types.str [ ] '' + disabled_filetypes = { + statusline = defaultNullOpts.mkListOf types.str [ ] '' Only ignores the ft for statusline. ''; - winbar = helpers.defaultNullOpts.mkListOf types.str [ ] '' + winbar = defaultNullOpts.mkListOf types.str [ ] '' Only ignores the ft for winbar. ''; }; - ignoreFocus = helpers.defaultNullOpts.mkListOf types.str [ ] '' + ignore_focus = defaultNullOpts.mkListOf types.str [ ] '' If current filetype is in this list it'll always be drawn as inactive statusline and the last window will be drawn as active statusline. @@ -151,106 +228,174 @@ in statusline you can add their filetypes here. ''; - alwaysDivideMiddle = helpers.defaultNullOpts.mkBool true '' + always_divide_middle = defaultNullOpts.mkBool true '' When set to true, left sections i.e. 'a','b' and 'c' can't take over the entire statusline even if neither of 'x', 'y' or 'z' are present. ''; - globalstatus = helpers.defaultNullOpts.mkBool false '' + globalstatus = defaultNullOpts.mkBool false '' Enable global statusline (have a single statusline at bottom of neovim instead of one for every window). This feature is only available in neovim 0.7 and higher. ''; refresh = { - statusline = helpers.defaultNullOpts.mkInt 1000 "Refresh time for the status line (ms)"; + statusline = defaultNullOpts.mkInt 1000 "Refresh time for the status line (ms)"; - tabline = helpers.defaultNullOpts.mkInt 1000 "Refresh time for the tabline (ms)"; + tabline = defaultNullOpts.mkInt 1000 "Refresh time for the tabline (ms)"; - winbar = helpers.defaultNullOpts.mkInt 1000 "Refresh time for the winbar (ms)"; + winbar = defaultNullOpts.mkInt 1000 "Refresh time for the winbar (ms)"; }; + }; - sections = { - lualine_a = mkComponentOptions "mode"; - lualine_b = mkComponentOptions "branch"; - lualine_c = mkComponentOptions "filename"; + sections = { + lualine_a = mkComponentOptions "mode"; + lualine_b = mkComponentOptions "branch"; + lualine_c = mkComponentOptions "filename"; - lualine_x = mkComponentOptions "encoding"; - lualine_y = mkComponentOptions "progress"; - lualine_z = mkComponentOptions "location"; - }; + lualine_x = mkComponentOptions "encoding"; + lualine_y = mkComponentOptions "progress"; + lualine_z = mkComponentOptions "location"; + }; - inactiveSections = { - lualine_a = mkComponentOptions ""; - lualine_b = mkComponentOptions ""; - lualine_c = mkComponentOptions "filename"; - lualine_x = mkComponentOptions "location"; - lualine_y = mkComponentOptions ""; - lualine_z = mkComponentOptions ""; - }; + inactive_sections = { + lualine_a = mkComponentOptions ""; + lualine_b = mkComponentOptions ""; + lualine_c = mkComponentOptions "filename"; + lualine_x = mkComponentOptions "location"; + lualine_y = mkComponentOptions ""; + lualine_z = mkComponentOptions ""; + }; - tabline = mkEmptySectionOption "Tabline configuration"; + tabline = mkEmptySectionOption "Tabline configuration"; - winbar = mkEmptySectionOption "Winbar configuration"; + winbar = mkEmptySectionOption "Winbar configuration"; - inactiveWinbar = mkEmptySectionOption "Inactive Winbar configuration"; + inactive_winbar = mkEmptySectionOption "Inactive Winbar configuration"; - extensions = mkOption { - type = types.nullOr (types.listOf types.str); - default = null; - example = ''[ "fzf" ]''; - description = "list of enabled extensions"; - }; - }; + extensions = defaultNullOpts.mkListOf (with lib.types; either str (attrsOf anything)) [ ] '' + List of enabled extensions. + ''; }; - config = - let - processComponent = x: (if isAttrs x then processTableComponent else id) x; - processTableComponent = + + settingsExample = { + disabled_filetypes = { + statusline = [ + "neo-tree" + "startify" + ]; + winbar = [ + "aerial" + "dap-repl" + "neo-tree" + "neotest-summary" + "startify" + ]; + }; + globalstatus = true; + sections = { + lualine_a = [ "mode" ]; + lualine_b = [ "branch" ]; + lualine_c = [ + "filename" + "diff" + ]; + lualine_x = [ + "diagnostics" { - name, - icons_enabled, - icon, - separator, - color, - padding, - extraConfig, - fmt, - }: - mergeAttrs { - "__unkeyed" = name; - icon = if isAttrs icon then removeAttrs (icon // { "__unkeyed" = icon.icon; }) [ "icon" ] else icon; - inherit - icons_enabled - separator - color - padding - fmt - ; - } extraConfig; - processSections = mapAttrs (_: mapNullable (map processComponent)); - setupOptions = { - options = { - inherit (cfg) theme globalstatus refresh; - icons_enabled = cfg.iconsEnabled; - section_separators = cfg.sectionSeparators; - component_separators = cfg.componentSeparators; - disabled_filetypes = cfg.disabledFiletypes; - ignore_focus = cfg.ignoreFocus; - always_divide_middle = cfg.alwaysDivideMiddle; - }; - - inherit (cfg) extensions; - sections = processSections cfg.sections; - inactive_sections = processSections cfg.inactiveSections; - tabline = processSections cfg.tabline; - winbar = processSections cfg.winbar; - inactive_winbar = processSections cfg.inactiveWinbar; - }; - in - mkIf cfg.enable { - extraPlugins = [ cfg.package ] ++ (optional cfg.iconsEnabled pkgs.vimPlugins.nvim-web-devicons); - extraPackages = [ cfg.gitPackage ]; - extraConfigLua = ''require("lualine").setup(${helpers.toLuaObject setupOptions})''; + __unkeyed-1.__raw = '' + function() + local msg = "" + local buf_ft = vim.api.nvim_buf_get_option(0, 'filetype') + local clients = vim.lsp.get_active_clients() + if next(clients) == nil then + return msg + end + for _, client in ipairs(clients) do + local filetypes = client.config.filetypes + if filetypes and vim.fn.index(filetypes, buf_ft) ~= -1 then + return client.name + end + end + return msg + end + ''; + icon = ""; + color.fg = "#ffffff"; + } + "encoding" + "fileformat" + "filetype" + ]; + lualine_y = [ + { + __unkeyed-1 = "aerial"; + cond.__raw = '' + function() + local buf_size_limit = 1024 * 1024 -- 1MB size limit + if vim.api.nvim_buf_get_offset(0, vim.api.nvim_buf_line_count(0)) > buf_size_limit then + return false + end + + return true + end + ''; + sep = " ) "; + depth.__raw = "nil"; + dense = false; + dense_sep = "."; + colored = true; + } + ]; + lualine_z = [ + { + __unkeyed-1 = "location"; + } + ]; }; + tabline = { + lualine_a = [ + { + __unkeyed-1 = "buffers"; + symbols = { + alternate_file = ""; + }; + } + ]; + lualine_z = [ "tabs" ]; + }; + winbar = { + lualine_c = [ + { + __unkeyed-1 = "navic"; + } + ]; + lualine_x = [ + { + __unkeyed-1 = "filename"; + newfile_status = true; + path = 3; + shorting_target = 150; + } + ]; + }; + }; + + extraOptions = { + gitPackage = mkPackageOption { + name = "git"; + default = pkgs.git; + }; + + iconsPackage = mkPackageOption { + name = "nvim-web-devicons"; + default = pkgs.vimPlugins.nvim-web-devicons; + }; + }; + + extraConfig = cfg: { + extraPackages = [ cfg.gitPackage ]; + + extraPlugins = lib.mkIf (cfg.iconsPackage != null) [ cfg.iconsPackage ]; + }; } diff --git a/tests/test-sources/example-configurations/issues.nix b/tests/test-sources/example-configurations/issues.nix index 8b64cf5cc3..f4b7427635 100644 --- a/tests/test-sources/example-configurations/issues.nix +++ b/tests/test-sources/example-configurations/issues.nix @@ -8,17 +8,21 @@ lualine = { enable = true; - sectionSeparators = { - left = ""; - right = ""; - }; - - componentSeparators = { - left = ""; - right = ""; + settings = { + options = { + section_separators = { + left = ""; + right = ""; + }; + + component_separators = { + left = ""; + right = ""; + }; + + theme = "auto"; + }; }; - - theme = "auto"; }; goyo = { diff --git a/tests/test-sources/plugins/statuslines/lualine.nix b/tests/test-sources/plugins/statuslines/lualine.nix index 9a0a2f05d0..7344084b45 100644 --- a/tests/test-sources/plugins/statuslines/lualine.nix +++ b/tests/test-sources/plugins/statuslines/lualine.nix @@ -8,48 +8,147 @@ plugins.lualine = { enable = true; - iconsEnabled = true; - theme = "auto"; - componentSeparators = { - left = ""; - right = ""; - }; - sectionSeparators = { - left = ""; - right = ""; - }; - alwaysDivideMiddle = true; - globalstatus = false; - refresh = { - statusline = 1000; - tabline = 1000; - winbar = 1000; - }; - sections = { - lualine_a = [ "mode" ]; - lualine_b = [ - "branch" - "diff" - "diagnostics" - ]; - lualine_c = [ "filename" ]; - lualine_x = [ - "encoding" - "fileformat" - "filetype" - ]; - lualine_y = [ "progress" ]; - lualine_z = [ "location" ]; - }; - inactiveSections = { - lualine_c = [ "filename" ]; - lualine_x = [ "location" ]; + settings = { + options = { + icons_enabled = true; + theme = "auto"; + component_separators = { + left = ""; + right = ""; + }; + section_separators = { + left = ""; + right = ""; + }; + disabled_filetypes = { + statusline = [ ]; + winbar = [ ]; + }; + ignore_focus = [ ]; + always_divide_middle = true; + globalstatus.__raw = "vim.go.laststatus == 3"; + refresh = { + statusline = 1000; + tabline = 1000; + winbar = 1000; + }; + }; + sections = { + lualine_a = [ "mode" ]; + lualine_b = [ + "branch" + "diff" + "diagnostics" + ]; + lualine_c = [ "filename" ]; + lualine_x = [ + "encoding" + "fileformat" + "filetype" + ]; + lualine_y = [ "progress" ]; + lualine_z = [ "location" ]; + }; + inactive_sections = { + lualine_a = [ ]; + lualine_b = [ ]; + lualine_c = [ "filename" ]; + lualine_x = [ "location" ]; + lualine_y = [ ]; + lualine_z = [ ]; + }; + tabline = { }; + winbar = { }; + inactive_winbar = { }; + extensions = [ ]; }; }; }; example = { extraPlugins = [ pkgs.vimPlugins.gruvbox-nvim ]; + plugins.lualine = { + enable = true; + settings = { + options = { + theme.__raw = '' + (function() + local custom_gruvbox = require("lualine.themes.gruvbox") + custom_gruvbox.normal.c.bg = '#112233' + return custom_gruvbox + end)() + ''; + ignore_focus = [ + "NvimTree" + "neo-tree" + ]; + disabled_filetypes = { + winbar = [ "neo-tree" ]; + }; + }; + sections = { + lualine_c = [ + # you can specify only the sections you want to change + { + __unkeyed-1 = "filename"; + icon = "-"; + newfile_status = true; + path = 1; + shorting_target = 60; + color = { + fg = "#ffaa88"; + }; + } + ]; + lualine_z = [ + { + __unkeyed-1 = "location"; + color.__raw = '' + function(section) + return { fg = vim.bo.modified and '#aa3355' or '#33aa88' } + end + ''; + } + { + __unkeyed-1 = "%L"; + color = "WarningMsg"; + } # total lines + ]; + }; + tabline = { + lualine_a = [ + { + __unkeyed-1 = "buffers"; + icon = { + __unkeyed-1 = "X"; + align = "right"; + }; + mode = 4; + filetype_names = { + TelescopePrompt = "Telescope"; + NvimTree = "NvimTree"; + }; + fmt = '' + function(value) + return value + end + ''; + } + ]; + lualine_z = [ + { + __unkeyed-1 = "tabs"; + mode = 2; + } + ]; + }; + extensions = [ "nvim-tree" ]; + }; + }; + }; + + # TODO: remove after deprecation tested + deprecation = { plugins.lualine = { enable = true; theme.__raw = '' @@ -70,30 +169,44 @@ lualine_c = [ # you can specify only the sections you want to change { - name = "filename"; + __unkeyed-1 = "filename"; icon = "-"; - extraConfig = { - newfile_status = true; - path = 1; - shorting_target = 60; + newfile_status = true; + path = 1; + shorting_target = 60; + color = { + fg = "#ffaa88"; }; } ]; lualine_z = [ - { name = "location"; } - { name = "%L"; } # total lines + { + __unkeyed-1 = "location"; + color.__raw = '' + function(section) + return { fg = vim.bo.modified and '#aa3355' or '#33aa88' } + end + ''; + } + { + __unkeyed-1 = "%L"; + color = "WarningMsg"; + } # total lines ]; }; tabline = { lualine_a = [ { + # TODO: update after deprecation tested name = "buffers"; icon = { + # TODO: update after deprecation tested icon = "X"; align = "right"; }; + # TODO: update after deprecation tested extraConfig.mode = 4; - extraConfig.filetype_names = { + filetype_names = { TelescopePrompt = "Telescope"; NvimTree = "NvimTree"; }; @@ -106,8 +219,8 @@ ]; lualine_z = [ { - name = "tabs"; - extraConfig.mode = 2; + __unkeyed-1 = "tabs"; + mode = 2; } ]; }; @@ -118,7 +231,9 @@ no-packages = { plugins.lualine = { enable = true; + gitPackage = null; + iconsPackage = null; }; }; }