diff --git a/plugins/default.nix b/plugins/default.nix index 3c561985..caf6d37f 100644 --- a/plugins/default.nix +++ b/plugins/default.nix @@ -147,6 +147,7 @@ ./utils/specs.nix ./utils/spider.nix ./utils/startify.nix + ./utils/startup.nix ./utils/surround.nix ./utils/tmux-navigator.nix ./utils/todo-comments.nix diff --git a/plugins/utils/startup.nix b/plugins/utils/startup.nix new file mode 100644 index 00000000..f778a359 --- /dev/null +++ b/plugins/utils/startup.nix @@ -0,0 +1,350 @@ +{ + lib, + helpers, + config, + pkgs, + ... +}: +with lib; let + cfg = config.plugins.startup; +in { + meta.maintainers = [maintainers.GaetanLepage]; + + options.plugins.startup = + helpers.extraOptionsOptions + // { + enable = mkEnableOption "startup.nvim"; + + package = helpers.mkPackageOption "startup.nvim" pkgs.vimPlugins.startup-nvim; + + theme = helpers.defaultNullOpts.mkStr "dashboard" '' + Use a pre-defined theme. + ''; + + sections = let + sectionType = with types; + submodule { + options = { + type = helpers.defaultNullOpts.mkEnumFirstDefault ["text" "mapping" "oldfiles"] '' + - "text" -> text that will be displayed + - "mapping" -> create mappings for commands that can be used. + use `mappings.executeCommand` on the commands to execute. + - "oldfiles" -> display oldfiles (can be opened with `mappings.openFile`/`openFileSplit`) + ''; + + oldfilesDirectory = helpers.defaultNullOpts.mkBool false '' + if the oldfiles of the current directory should be displayed. + ''; + + align = helpers.defaultNullOpts.mkEnumFirstDefault ["center" "left" "right"] '' + How to align the section. + ''; + + foldSection = helpers.defaultNullOpts.mkBool false '' + Whether to fold or not. + ''; + + title = helpers.defaultNullOpts.mkStr "title" '' + Title for the folded section. + ''; + + margin = + helpers.defaultNullOpts.mkNullable + ( + with types; + either + (numbers.between 0.0 1.0) + ints.positive + ) + "5" + '' + The margin for left or right alignment. + - if < 1 fraction of screen width + - if > 1 numbers of column + ''; + + content = + helpers.mkNullOrOption + ( + with types; + oneOf [ + # for "text" "mapping" + ( + listOf + ( + either + str + (listOf str) + ) + ) + helpers.rawType + # for "oldfiles" sections + (enum [""]) + ] + ) + '' + The type of `content` depends on the secton `type`: + - "text" -> a list of strings or a function (`rawType`) that requires a function that returns a table of strings + - "mapping" -> a list of list of strings in the format: + ```nix + [ + [ ] + [ ] + ] + ``` + Example: `[" Find File" "Telescope find_files" "ff"]` + - "oldfiles" -> `""` + ''; + + highlight = helpers.mkNullOrOption types.str '' + Highlight group in which the section text should be highlighted. + ''; + + defaultColor = helpers.defaultNullOpts.mkStr "#FF0000" '' + A hex color that gets used if you don't specify `highlight`. + ''; + + oldfilesAmount = helpers.defaultNullOpts.mkUnsignedInt 5 '' + The amount of oldfiles to be displayed. + ''; + }; + }; + in + mkOption { + type = with types; attrsOf sectionType; + default = {}; + description = '' + ''; + example = { + header = { + type = "text"; + align = "center"; + foldSection = false; + title = "Header"; + margin = 5; + content.__raw = "require('startup.headers').hydra_header"; + highlight = "Statement"; + defaultColor = ""; + oldfilesAmount = 0; + }; + body = { + type = "mapping"; + align = "center"; + foldSection = true; + title = "Basic Commands"; + margin = 5; + content = [ + [ + " Find File" + "Telescope find_files" + "ff" + ] + [ + "󰍉 Find Word" + "Telescope live_grep" + "lg" + ] + [ + " Recent Files" + "Telescope oldfiles" + "of" + ] + [ + " File Browser" + "Telescope file_browser" + "fb" + ] + [ + " Colorschemes" + "Telescope colorscheme" + "cs" + ] + [ + " New File" + "lua require'startup'.new_file()" + "nf" + ] + ]; + highlight = "String"; + defaultColor = ""; + oldfilesAmount = 0; + }; + }; + }; + + options = { + mappingKeys = helpers.defaultNullOpts.mkBool true '' + Display mapping (e.g. `ff`). + ''; + + cursorColumn = + helpers.defaultNullOpts.mkNullable + ( + with types; + either + (numbers.between 0.0 1.0) + ints.positive + ) + "0.5" + '' + - if < 1, fraction of screen width + - if > 1 numbers of column + ''; + + after = helpers.mkNullOrOption types.str '' + A function that gets executed at the end. + ''; + + emptyLinesBetweenMappings = helpers.defaultNullOpts.mkBool true '' + Add an empty line between mapping/commands. + ''; + + disableStatuslines = helpers.defaultNullOpts.mkBool true '' + Disable status-, buffer- and tablines. + ''; + + paddings = helpers.defaultNullOpts.mkNullable (with types; listOf ints.unsigned) "[]" '' + Amount of empty lines before each section (must be equal to amount of sections). + ''; + }; + + mappings = { + executeCommand = helpers.defaultNullOpts.mkStr "" '' + Keymapping to execute a command. + ''; + + openFile = helpers.defaultNullOpts.mkStr "o" '' + Keymapping to open a file. + ''; + + openFileSplit = helpers.defaultNullOpts.mkStr "" '' + Keymapping to open a file in a split. + ''; + + openSection = helpers.defaultNullOpts.mkStr "" '' + Keymapping to open a section. + ''; + + openHelp = helpers.defaultNullOpts.mkStr "?" '' + Keymapping to open help. + ''; + }; + + colors = { + background = helpers.defaultNullOpts.mkStr "#1f2227" '' + The background color. + ''; + + foldedSection = helpers.defaultNullOpts.mkStr "#56b6c2" '' + The color of folded sections. + This can also be changed with the `StartupFoldedSection` highlight group. + ''; + }; + + parts = mkOption { + type = with types; listOf str; + default = []; + description = "List all sections in order."; + example = ["section_1" "section_2"]; + }; + + userMappings = mkOption { + type = with types; attrsOf str; + description = "Add your own mappings as key-command pairs."; + default = {}; + example = { + "ff" = "Telescope find_files"; + "lg" = "Telescope live_grep"; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = let + sectionNames = attrNames cfg.sections; + numSections = length sectionNames; + in [ + { + assertion = (cfg.options.paddings == null) || (length cfg.options.paddings) == numSections; + message = '' + Nixvim (plugins.startup): Make sure that `plugins.startup.options.paddings` has the same + number of elements as there are sections. + ''; + } + { + assertion = + ((length cfg.parts) <= numSections) + && ( + all + (part: hasAttr part cfg.sections) + cfg.parts + ); + message = '' + Nixvim (plugins.startup): You should not have more section names in `plugins.startup.parts` than you have sections defined. + ''; + } + ]; + extraPlugins = [cfg.package]; + + extraConfigLua = let + sections = + mapAttrs + ( + name: sectionAttrs: + with sectionAttrs; { + inherit type; + oldfiles_directory = oldfilesDirectory; + inherit align; + fold_section = foldSection; + inherit + title + margin + content + highlight + ; + default_color = defaultColor; + oldfiles_amount = oldfilesAmount; + } + ) + cfg.sections; + + options = with cfg.options; + { + mapping_keys = mappingKeys; + cursor_column = cursorColumn; + after = helpers.mkRaw after; + empty_lines_between_mappings = emptyLinesBetweenMappings; + disable_statuslines = disableStatuslines; + inherit paddings; + } + // cfg.extraOptions; + + setupOptions = + { + inherit (cfg) theme; + inherit options; + mappings = with cfg.mappings; { + execute_command = executeCommand; + open_file = openFile; + open_file_split = openFileSplit; + open_section = openSection; + open_help = openHelp; + }; + colors = with cfg.colors; { + inherit background; + folded_section = foldedSection; + }; + inherit (cfg) parts; + } + // sections; + in + '' + require('startup').setup(${helpers.toLuaObject setupOptions}) + '' + + ( + optionalString + (cfg.userMappings != {}) + "require('startup').create_mappings(${helpers.toLuaObject cfg.userMappings})" + ); + }; +} diff --git a/tests/test-sources/plugins/utils/startup.nix b/tests/test-sources/plugins/utils/startup.nix new file mode 100644 index 00000000..f9f90ccb --- /dev/null +++ b/tests/test-sources/plugins/utils/startup.nix @@ -0,0 +1,167 @@ +{ + empty = { + plugins.startup.enable = true; + }; + + builtin-theme = { + plugins.startup = { + enable = true; + theme = "dashboard"; + + # Default options + options = { + mappingKeys = true; + cursorColumn = 0.5; + after = null; + emptyLinesBetweenMappings = true; + disableStatuslines = true; + paddings = []; + }; + mappings = { + executeCommand = ""; + openFile = "o"; + openFileSplit = ""; + openSection = ""; + openHelp = "?"; + }; + colors = { + background = "#1f2227"; + foldedSection = "#56b6c2"; + }; + userMappings = { + "ff" = "Telescope find_files"; + "lg" = "Telescope live_grep"; + }; + }; + }; + + # Replicate the settings of the 'evil' theme + custom-section-evil = { + plugins.startup = { + enable = true; + + sections = { + header = { + type = "text"; + align = "center"; + foldSection = false; + title = "Header"; + margin = 5; + content.__raw = "require('startup.headers').hydra_header"; + highlight = "Statement"; + defaultColor = ""; + oldfilesAmount = 0; + }; + header_2 = { + type = "text"; + oldfilesDirectory = false; + align = "center"; + foldSection = false; + title = "Quote"; + margin = 5; + content.__raw = "require('startup.functions').quote()"; + highlight = "Constant"; + defaultColor = ""; + oldfilesAmount = 0; + }; + body = { + type = "mapping"; + align = "center"; + foldSection = true; + title = "Basic Commands"; + margin = 5; + content = [ + [" Find File" "Telescope find_files" "ff"] + ["󰍉 Find Word" "Telescope live_grep" "lg"] + [" Recent Files" "Telescope oldfiles" "of"] + [" File Browser" "Telescope file_browser" "fb"] + [" Colorschemes" "Telescope colorscheme" "cs"] + [" New File" "lua require'startup'.new_file()" "nf"] + ]; + highlight = "String"; + defaultColor = ""; + oldfilesAmount = 0; + }; + body_2 = { + type = "oldfiles"; + oldfilesDirectory = true; + align = "center"; + foldSection = true; + title = "Oldfiles of Directory"; + margin = 5; + content = []; + highlight = "String"; + defaultColor = "#FFFFFF"; + oldfilesAmount = 5; + }; + footer = { + type = "oldfiles"; + oldfilesDirectory = false; + align = "center"; + foldSection = true; + title = "Oldfiles"; + margin = 5; + content = ["startup.nvim"]; + highlight = "TSString"; + defaultColor = "#FFFFFF"; + oldfilesAmount = 5; + }; + clock = { + type = "text"; + content.__raw = '' + function() + local clock = " " .. os.date("%H:%M") + local date = " " .. os.date("%d-%m-%y") + return { clock, date } + end + ''; + oldfilesDirectory = false; + align = "center"; + foldSection = false; + title = ""; + margin = 5; + highlight = "TSString"; + defaultColor = "#FFFFFF"; + oldfilesAmount = 10; + }; + footer_2 = { + type = "text"; + content.__raw = "require('startup.functions').packer_plugins()"; + oldfilesDirectory = false; + align = "center"; + foldSection = false; + title = ""; + margin = 5; + highlight = "TSString"; + defaultColor = "#FFFFFF"; + oldfilesAmount = 10; + }; + }; + options = { + after = '' + function() + require("startup.utils").oldfiles_mappings() + end + ''; + mappingKeys = true; + cursorColumn = 0.5; + emptyLinesBetweenMappings = true; + disableStatuslines = true; + paddings = [2 2 2 2 2 2 2]; + }; + colors = { + background = "#1f2227"; + foldedSection = "#56b6c2"; + }; + parts = [ + "header" + "header_2" + "body" + "body_2" + "footer" + "clock" + "footer_2" + ]; + }; + }; +}