diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 59275af9..a282e992 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -1,5 +1,26 @@ {lib}: let inherit (builtins) listToAttrs; in { + /** + Map over a list and convert the result to an attribute set. + + # Type + + ``` + mapListToAttrs :: (a -> { name :: String; value :: b }) -> [a] -> AttrSet + ``` + + # Arguments + + - `f`: Function mapping each list element to a `{ name; value }` pair. + - `list`: The list to map over. + + # Example + + ```nix + mapListToAttrs (x: { name = x; value = x; }) ["a" "b"] + => { a = "a"; b = "b"; } + ``` + */ mapListToAttrs = f: list: listToAttrs (map f list); } diff --git a/lib/binds.nix b/lib/binds.nix index bb40a89e..9e32be9b 100644 --- a/lib/binds.nix +++ b/lib/binds.nix @@ -5,6 +5,28 @@ inherit (lib.attrsets) isAttrs mapAttrs; binds = rec { + /** + Create a silent Lua keybinding wrapped in `mkIf` to guard against null keys. + + # Type + + ``` + mkLuaBinding :: String | Null -> String -> String -> AttrSet + ``` + + # Arguments + + - `key`: The key sequence to bind, or `null` to disable. + - `action`: Lua expression to execute on keypress. + - `desc`: Human-readable description of the binding. + + # Example + + ```nix + mkLuaBinding "f" "require('telescope').find_files" "Find files" + => { "f" = { action = "require('telescope').find_files"; desc = "Find files"; lua = true; silent = true; }; } + ``` + */ mkLuaBinding = key: action: desc: mkIf (key != null) { "${key}" = { @@ -14,6 +36,28 @@ }; }; + /** + Create a silent expression-mode Lua keybinding wrapped in `mkIf`. + + # Type + + ``` + mkExprBinding :: String | Null -> String -> String -> AttrSet + ``` + + # Arguments + + - `key`: The key sequence to bind, or `null` to disable. + - `action`: Lua expression evaluated as a Vim expression. + - `desc`: Human-readable description of the binding. + + # Example + + ```nix + mkExprBinding "" "v:count == 0 ? 'j' : 'gj'" "Smart down" + => { "" = { action = "v:count == 0 ? 'j' : 'gj'"; desc = "Smart down"; lua = true; silent = true; expr = true; }; } + ``` + */ mkExprBinding = key: action: desc: mkIf (key != null) { "${key}" = { @@ -24,6 +68,28 @@ }; }; + /** + Create a silent (non-Lua) keybinding wrapped in `mkIf` to guard against null keys. + + # Type + + ``` + mkBinding :: String | Null -> String -> String -> AttrSet + ``` + + # Arguments + + - `key`: The key sequence to bind, or `null` to disable. + - `action`: Vimscript command or mapping string to execute. + - `desc`: Human-readable description of the binding. + + # Example + + ```nix + mkBinding "w" ":w" "Save file" + => { "w" = { action = ":w"; desc = "Save file"; silent = true; }; } + ``` + */ mkBinding = key: action: desc: mkIf (key != null) { "${key}" = { @@ -32,17 +98,58 @@ }; }; + /** + Build a nullable string NixOS option suitable for storing a keybinding value. + + # Type + + ``` + mkMappingOption :: String -> String | Null -> Option + ``` + + # Arguments + + - `description`: Documentation string for the option. + - `default`: Default key value, or `null` for no binding. + + # Example + + ```nix + mkMappingOption "Toggle file tree" "e" + => mkOption { type = nullOr str; default = "e"; description = "Toggle file tree"; } + ``` + */ mkMappingOption = description: default: mkOption { type = nullOr str; inherit default description; }; - # Utility function that takes two attrsets: - # { someKey = "some_value" } and - # { someKey = { description = "Some Description"; }; } - # and merges them into - # { someKey = { value = "some_value"; description = "Some Description"; }; } + /** + Merge actual mapping values with their description metadata. + + Takes two attribute sets: one mapping keys to values and another mapping + keys to `{ description }` records. Produces an attribute set mapping + keys to `{ value; description }` records. Nesting is handled recursively. + + # Type + + ``` + addDescriptionsToMappings :: AttrSet -> AttrSet -> AttrSet + ``` + + # Arguments + + - `actualMappings`: Attribute set of key → value pairs. + - `mappingDefinitions`: Attribute set of key → `{ description }` pairs. + + # Example + + ```nix + addDescriptionsToMappings { someKey = "some_value"; } { someKey = { description = "Some Description"; }; } + => { someKey = { value = "some_value"; description = "Some Description"; }; } + ``` + */ addDescriptionsToMappings = actualMappings: mappingDefinitions: mapAttrs (name: value: let isNested = isAttrs value; @@ -57,17 +164,126 @@ returnedValue) actualMappings; + /** + Create a non-Lua keybinding from a structured binding record produced by `mkMappingOption`. + + # Type + + ``` + mkSetBinding :: { value :: String | Null; description :: String } -> String -> AttrSet + ``` + + # Arguments + + - `binding`: Binding record with `value` (key) and `description` fields. + - `action`: Vimscript command or mapping string to execute. + + # Example + + ```nix + mkSetBinding { value = "w"; description = "Save file"; } ":w" + => mkBinding "w" ":w" "Save file" + ``` + */ mkSetBinding = binding: action: mkBinding binding.value action binding.description; + /** + Create an expression-mode Lua keybinding from a structured binding record. + + # Type + + ``` + mkSetExprBinding :: { value :: String | Null; description :: String } -> String -> AttrSet + ``` + + # Arguments + + - `binding`: Binding record with `value` (key) and `description` fields. + - `action`: Lua expression evaluated as a Vim expression. + + # Example + + ```nix + mkSetExprBinding { value = ""; description = "Smart down"; } "v:count == 0 ? 'j' : 'gj'" + => mkExprBinding "" "v:count == 0 ? 'j' : 'gj'" "Smart down" + ``` + */ mkSetExprBinding = binding: action: mkExprBinding binding.value action binding.description; + /** + Create a silent Lua keybinding from a structured binding record. + + # Type + + ``` + mkSetLuaBinding :: { value :: String | Null; description :: String } -> String -> AttrSet + ``` + + # Arguments + + - `binding`: Binding record with `value` (key) and `description` fields. + - `action`: Lua expression to execute on keypress. + + # Example + + ```nix + mkSetLuaBinding { value = "f"; description = "Find files"; } "require('telescope').find_files" + => mkLuaBinding "f" "require('telescope').find_files" "Find files" + ``` + */ mkSetLuaBinding = binding: action: mkLuaBinding binding.value action binding.description; + /** + Apply `mkDefault` to every value in an attribute set. + + Useful for lowering the priority of a set of option defaults so they can + be overridden by user configuration. + + # Type + + ``` + pushDownDefault :: AttrSet -> AttrSet + ``` + + # Arguments + + - `attr`: Attribute set whose values should be wrapped with `mkDefault`. + + # Example + + ```nix + pushDownDefault { a = true; b = "hello"; } + => { a = mkDefault true; b = mkDefault "hello"; } + ``` + */ pushDownDefault = attr: mapAttrs (_: mkDefault) attr; + /** + Build a keymap record by merging extra options with mode, key, and action fields. + + # Type + + ``` + mkKeymap :: String -> String -> String -> AttrSet -> AttrSet + ``` + + # Arguments + + - `mode`: Vim mode string (e.g. `"n"`, `"v"`, `"i"`). + - `key`: Key sequence to bind. + - `action`: Action to execute on keypress. + - `opt`: Extra options merged into the resulting record. + + # Example + + ```nix + mkKeymap "n" "w" ":w" { silent = true; } + => { mode = "n"; key = "w"; action = ":w"; silent = true; } + ``` + */ mkKeymap = mode: key: action: opt: opt // {inherit mode key action;}; }; in diff --git a/lib/config.nix b/lib/config.nix index 40d81578..7ace434b 100644 --- a/lib/config.nix +++ b/lib/config.nix @@ -5,6 +5,27 @@ inherit (lib.attrsets) mapAttrsToList; inherit (lib.lists) flatten; in { + /** + Build a boolean NixOS option with the given default value and description. + + # Type + + ``` + mkBool :: Bool -> String -> Option + ``` + + # Arguments + + - `value`: Default boolean value for the option. + - `description`: Documentation string for the option. + + # Example + + ```nix + mkBool true "Enable feature X" + => mkOption { type = bool; default = true; description = "Enable feature X"; } + ``` + */ mkBool = value: description: mkOption { type = bool; diff --git a/lib/dag.nix b/lib/dag.nix index db5d53b7..bf86d7bb 100644 --- a/lib/dag.nix +++ b/lib/dag.nix @@ -19,7 +19,7 @@ in { isDag = dag: isAttrs dag && all isEntry (attrValues dag); - /* + /** Takes an attribute set containing entries built by entryAnywhere, entryAfter, and entryBefore to a topologically sorted list of entries. @@ -100,12 +100,98 @@ in { # Applies a function to each element of the given DAG. map = f: mapAttrs (n: v: v // {data = f n v.data;}); + /** + Create a DAG entry with explicit before and after dependency lists. + + # Type + + ``` + entryBetween :: [String] -> [String] -> a -> DagEntry a + ``` + + # Arguments + + - `before`: List of entry names this entry must come before. + - `after`: List of entry names this entry must come after. + - `data`: Payload for this DAG entry. + + # Example + + ```nix + entryBetween [ "c" ] [ "a" ] "payload" + => { data = "payload"; before = [ "c" ]; after = [ "a" ]; } + ``` + */ entryBetween = before: after: data: {inherit data before after;}; - # Create a DAG entry with no particular dependency information. + /** + Create a DAG entry with no ordering constraints. + + The entry may be placed anywhere in the topological sort result. + + # Type + + ``` + entryAnywhere :: a -> DagEntry a + ``` + + # Arguments + + - `data`: Payload for this DAG entry. + + # Example + + ```nix + entryAnywhere "lua code here" + => { data = "lua code here"; before = []; after = []; } + ``` + */ entryAnywhere = entryBetween [] []; + /** + Create a DAG entry that must come after the listed entries. + + # Type + + ``` + entryAfter :: [String] -> a -> DagEntry a + ``` + + # Arguments + + - `after`: List of entry names this entry must follow. + - `data`: Payload for this DAG entry. + + # Example + + ```nix + entryAfter [ "init" ] "setup code" + => { data = "setup code"; before = []; after = [ "init" ]; } + ``` + */ entryAfter = entryBetween []; + + /** + Create a DAG entry that must come before the listed entries. + + # Type + + ``` + entryBefore :: [String] -> a -> DagEntry a + ``` + + # Arguments + + - `before`: List of entry names this entry must precede. + - `data`: Payload for this DAG entry. + + # Example + + ```nix + entryBefore [ "teardown" ] "cleanup code" + => { data = "cleanup code"; before = [ "teardown" ]; after = []; } + ``` + */ entryBefore = before: entryBetween before []; # Given a list of entries, this function places them in order within the DAG. diff --git a/lib/languages.nix b/lib/languages.nix index 899d9ea8..b2371bdb 100644 --- a/lib/languages.nix +++ b/lib/languages.nix @@ -6,6 +6,32 @@ inherit (lib.nvim.types) luaInline; in { # TODO: remove + /** + Convert a list of diagnostic provider entries to a DAG-compatible attribute set. + + Accepts either plain strings (provider type names) or attrsets with `type` + and `package` fields, and produces named entries suitable for merging into + a null-ls/none-ls DAG. + + # Type + + ``` + diagnosticsToLua :: { lang :: String; config :: [String | { type :: String; package :: Derivation }]; diagnosticsProviders :: AttrSet } -> AttrSet + ``` + + # Arguments + + - `lang`: Language identifier used to prefix generated entry names. + - `config`: List of provider names (strings) or `{ type; package }` records. + - `diagnosticsProviders`: Attribute set mapping provider type names to `{ package; nullConfig }` records. + + # Example + + ```nix + diagnosticsToLua { lang = "python"; config = [ "flake8" ]; diagnosticsProviders = { flake8 = { package = pkgs.python3Packages.flake8; nullConfig = pkg: "..."; }; }; } + => { "python-diagnostics-flake8" = "..."; } + ``` + */ diagnosticsToLua = { lang, config, @@ -27,6 +53,26 @@ in { }) config; + /** + Build a boolean NixOS option that enables a language feature for all enabled languages. + + # Type + + ``` + mkEnable :: String -> Option + ``` + + # Arguments + + - `desc`: Short description of the feature being enabled (interpolated into the option description). + + # Example + + ```nix + mkEnable "LSP support" + => mkOption { default = false; type = bool; description = "Turn on LSP support for enabled languages by default"; } + ``` + */ mkEnable = desc: mkOption { default = false; @@ -34,6 +80,28 @@ in { description = "Turn on ${desc} for enabled languages by default"; }; + /** + A freeform submodule type for LSP server options. + + Provides a structured set of well-known LSP configuration fields + (`enable`, `capabilities`, `on_attach`, `filetypes`, `cmd`, `root_markers`) + while allowing arbitrary extra fields via `freeformType`. + + # Type + + ``` + lspOptions :: SubmoduleType + ``` + + # Example + + ```nix + vim.languages.rust.lsp.options = { + enable = true; + root_markers = [ "Cargo.toml" ]; + }; + ``` + */ lspOptions = submodule { freeformType = attrsOf anything; options = { diff --git a/lib/lists.nix b/lib/lists.nix index 25e85ad2..448014fb 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -1,33 +1,34 @@ {lib}: let inherit (lib.lists) elem all; in { - /* - Checks if all values are present in the list. + /** + Checks if all values are present in the list. - Type: + # Type + + ``` listContainsValues :: { list :: [a], values :: [a] } -> Bool + ``` - Arguments: - list - A list of elements. - values - A list of values to check for presence in the list. + # Arguments - Returns: - True if all values are present in the list, otherwise False. + - `list`: A list of elements. + - `values`: A list of values to check for presence in the list. + + # Example - Example: ```nix listContainsValues { list = [1 2 3]; values = [2 3]; } - => True + => true listContainsValues { list = [1 2 3]; values = [2 4]; } - => False + => false ``` */ listContainsValues = { list, values, }: let - # Check if all values are present in the list containsValue = value: elem value list; in all containsValue values; diff --git a/lib/lua.nix b/lib/lua.nix index 01c73612..547feddc 100644 --- a/lib/lua.nix +++ b/lib/lua.nix @@ -1,7 +1,57 @@ # Helpers for converting values to lua {lib}: let + /** + Test whether an object is a `luaInline` value (i.e. has `_type == "lua-inline"`). + + # Type + + ``` + isLuaInline :: Any -> Bool + ``` + + # Arguments + + - `object`: Any Nix value. + + # Example + + ```nix + isLuaInline (lib.mkLuaInline "vim.fn.getcwd()") + => true + + isLuaInline "just a string" + => false + ``` + */ isLuaInline = object: (object._type or null) == "lua-inline"; + /** + Recursively convert a Nix value to its Lua representation as a string. + + Handles all primitive Nix types as well as lists, attribute sets, + derivations (rendered as their store path string), and `luaInline` values + (rendered verbatim). Null attributes are stripped from sets. + + # Type + + ``` + toLuaObject :: Any -> String + ``` + + # Arguments + + - `args`: Any Nix value to convert. + + # Example + + ```nix + toLuaObject { a = 1; b = true; c = null; } + => ''{["a"] = 1,\n["b"] = true}'' + + toLuaObject [ "x" "y" ] + => ''{"x",\n"y"}'' + ``` + */ toLuaObject = args: { int = toString args; @@ -42,6 +92,30 @@ in { inherit isLuaInline toLuaObject; + + /** + Convert a list of Lua expression strings into a Lua table string. + + Each element is wrapped with `mkLuaInline` before conversion so that + strings are treated as raw Lua rather than quoted string literals. + + # Type + + ``` + luaTable :: [String] -> String + ``` + + # Arguments + + - `x`: List of Lua expression strings. + + # Example + + ```nix + luaTable [ "vim.fn.getcwd()" "vim.fn.expand('%')" ] + => ''{vim.fn.getcwd(),\nvim.fn.expand('%')}'' + ``` + */ luaTable = x: (toLuaObject (map lib.mkLuaInline x)); } // lib.genAttrs [