{ config, lib, pkgs, ... }: let inherit (lib.nix2lua) LuaNil scope lset pipe1 call call1; cfg = config.plugins.snippet.luasnip; nodes = lib.mkOption { type = with lib.types; listOf (submodule snippetNodeOpts); default = [ ]; }; unwrapNodes = map (n: n.genConfig); genConfig = lib.mkOption { type = lib.types.attrs; internal = true; }; snippetNodeOpts = { config, ... }: { options = with lib; with types; { kind = mkOption { type = enum [ "text" "insert" "choice" "snippet" ]; }; text = mkOption { type = nullOr (either str (listOf str)); default = null; }; jump = lib.mkOption { type = with lib.types; nullOr number; default = null; description = '' This determines when this node will be jumped to. `:help luasnip-insertnode` `:help luasnip-basics-jump-index` ''; }; inherit nodes; choices = nodes; # only for kind=snippet indentString = mkOption { type = types.str; default = ""; }; inherit genConfig; }; config = let inherit (config) kind text jump nodes choices; unwrapJump = index: if index == null then LuaNil else index; in { kind = lib.mkDefault ( if choices != [ ] then "choice" else if nodes != [ ] then "snippet" else if jump != null then "insert" else "text" ); genConfig = if kind == "text" then if text != null then call1 "t" text else throw "luasnip textnode require a 'text' config" else if kind == "insert" then call "i" [ (unwrapJump jump) text ] else if kind == "choice" then call "c" [ (unwrapJump jump) (unwrapNodes choices) ] else if kind == "snippet" then if config.indentString != "" then call "isn" [ (unwrapJump jump) (unwrapNodes nodes) config.indentString ] else call "sn" [ (unwrapJump jump) (unwrapNodes nodes) ] else null; }; }; snippetOpts = { name, ... } @ sub: { options = with lib; with types; { context = mkOption { type = either str attrs; description = '' `:help luasnip-snippets'; ''; }; inherit nodes; inherit genConfig; }; config = { context = lib.mkDefault name; genConfig = call "s" [ sub.config.context (unwrapNodes sub.config.nodes) ]; }; }; snippetGroupOpts = { ... } @ sub: { options = with lib; { filetype = mkOption { type = types.str; }; opts = { type = mkOption { type = types.nullOr (types.enum [ "snippets" "autosnippets" ]); default = null; }; key = mkOption { type = types.nullOr types.str; default = null; }; override_priority = mkOption { type = types.nullOr types.number; default = null; description = '' Set priority for all snippets. `:help luasnip-api` ''; }; default_priority = mkOption { type = types.nullOr types.number; default = null; description = '' Set priority only for snippets without snippet priority. `:help luasnip-api` ''; }; }; snippets = mkOption { type = types.attrsOf (types.submodule snippetOpts); default = { }; }; inherit genConfig; }; config = { genConfig = let plugin = config.plugin.luasnip; in let inherit (sub.config) filetype snippets opts; in pipe1 plugin.var (call "add_snippets" [ filetype (map (s: s.genConfig) (builtins.attrValues snippets)) opts ]); }; }; in { options.plugins.snippet.luasnip = with lib; { enable = mkEnableOption "luasnip"; package = mkPackageOption pkgs.vimPlugins "luasnip" { }; settings = mkOption { type = types.attrs; default = { }; }; snippetGroups = mkOption { type = types.listOf (types.submodule snippetGroupOpts); default = [ ]; }; }; config = lib.mkIf cfg.enable { plugin.luasnip = rec { inherit (cfg) package; varName = "luasnip"; setupSettings = cfg.settings; extraImports = lib.mkIf (cfg.snippetGroups != [ ]) { luasnip_types = "luasnip.util.types"; }; afterSetup = lib.mkIf (cfg.snippetGroups != [ ]) [ (scope (lib.flatten [ (lib.mapAttrsToList (k: v: lset k (pipe1 varName v)) { s = "snippet"; sn = "snippet_node"; isn = "indent_snippet_node"; t = "text_node"; i = "insert_node"; f = "function_node"; c = "choice_node"; d = "dynamic_node"; r = "restore_node"; }) (map (sg: sg.genConfig) cfg.snippetGroups) ])) ]; }; }; }