diff --git a/home/features/cli/productivity/smos/default.nix b/home/features/cli/productivity/smos/default.nix index 5082c0e..7a2dca9 100644 --- a/home/features/cli/productivity/smos/default.nix +++ b/home/features/cli/productivity/smos/default.nix @@ -1,8 +1,12 @@ -{ config, ... }: { +{ config, pkgs, ... }: +let workflowDir = "${config.home.homeDirectory}/productivity/smos"; +in +{ programs.smos = { + inherit workflowDir; + enable = true; notify.enable = true; - workflowDir = "${config.home.homeDirectory}/productivity/smos"; github = { enable = true; @@ -18,4 +22,19 @@ source = ./smos_github_oauth.age; path = "${config.xdg.dataHome}/smos/.github_token"; }; + + home.packages = + # Start smos with a custom class so our WM can move it to the correct workspace + let smosgui = pkgs.writeShellScriptBin "smosgui" '' + wezterm start --class "org.wezfurlong.wezterm.smos" --cwd ${workflowDir} smos + ''; + in + [ smosgui ]; + + xdg.desktopEntries.smosgui = { + name = "Smos GUI"; + type = "Application"; + exec = "smosgui"; + terminal = false; + }; } diff --git a/home/features/neovim/config/lua/my/tempest.lua b/home/features/neovim/config/lua/my/tempest.lua index 52536b8..0016261 100644 --- a/home/features/neovim/config/lua/my/tempest.lua +++ b/home/features/neovim/config/lua/my/tempest.lua @@ -276,6 +276,14 @@ function M.prepareLazySpec(spec) end end + local initType = type(module.init) + if initType == "function" or initType == "table" then + local previousInit = module.init + module.init = function(lazy, opts) + M.configure(previousInit, { lazy = lazy, opts = opts }) + end + end + if module.keys ~= nil then if type(module.keys) == "string" or module.keys.mapping ~= nil then module.keys = { module.keys } diff --git a/home/features/neovim/default.nix b/home/features/neovim/default.nix index a2bd2a3..4d3d21b 100644 --- a/home/features/neovim/default.nix +++ b/home/features/neovim/default.nix @@ -1274,7 +1274,7 @@ let cond = blacklist "vscode"; ft = "hypr"; - config.autocmds = { + init.autocmds = { event = "BufRead"; group = "DetectHyprlandConfig"; pattern = "hyprland.conf"; diff --git a/home/features/wayland/hyprland/hyprland.conf b/home/features/wayland/hyprland/hyprland.conf index 099b8a7..374a427 100644 --- a/home/features/wayland/hyprland/hyprland.conf +++ b/home/features/wayland/hyprland/hyprland.conf @@ -61,7 +61,7 @@ animations { } # Execute apps at launch -exec-once = wezterm & firefox & discocss & spotify & obsidian +exec-once = wezterm & firefox & discocss & spotify & obsidian & smosgui # {{{ Window rules # {{{ Automatically move stuff to workspaces @@ -69,6 +69,7 @@ windowrulev2 = workspace 2 silent, title:^(.*Firefox.*)$ windowrulev2 = workspace 3 silent, title:^(.*(Disc|WebC)ord.*)$ windowrulev2 = workspace 6 silent, title:^(.*Spotify.*)$ windowrulev2 = workspace 7 silent, title:^(.*Obsidian.*)$ +windowrulev2 = workspace 8 silent, class:^(org\.wezfurlong\.wezterm\.smos)$ # }}} # {{{ Idleinhibit rules # - while firefox is fullscreen diff --git a/modules/README.md b/modules/README.md index 3b84b41..21058d4 100644 --- a/modules/README.md +++ b/modules/README.md @@ -12,12 +12,14 @@ This directory contains custom module definitions used throughout my config. ## Common modules -| Name | Attribute | Description | Dependencies | -| ----------------------------------------------- | --------------------------- | --------------------------------------------------- | ----------------------------------------- | -| [lua-colorscheme](./common/lua-colorscheme.nix) | `satellite.colorscheme.lua` | Base16 theme to lua module generation | [stylix](https://github.com/danth/stylix) | -| [lua-encoders](./common/lua-encoders.nix) | `satellite.lib.lua` | Combinators for generating lua code from nix values | | -| [theming](./common/theming.nix) | `satellite.theming` | Base16 theming helpers and configuration | [stylix](https://github.com/danth/stylix) | -| [toggles](./common/toggles.nix) | `satellite.toggles` | Generic interface for feature flags | | +| Name | Attribute | Description | Dependencies | +| ----------------------------------------------- | --------------------------- | ---------------------------------------- | ---------------------------------------------- | +| [lua-colorscheme](./common/lua-colorscheme.nix) | `satellite.colorscheme.lua` | Base16 theme to lua module generation | [stylix](https://github.com/danth/stylix) | +| [lua-lib](./common/lua-lib.nix) | `satellite.lib.lua` | Helpers for working with lua code | | +| [korora-lua](./common/korora-lua.nix) | - | Nix -> lua encoder | [korora](https://github.com/adisbladis/korora) | +| [korora-neovim](./common/korora-neovim.nix) | - | Nix -> neovim config helpers | [korora](https://github.com/adisbladis/korora) | +| [theming](./common/theming.nix) | `satellite.theming` | Base16 theming helpers and configuration | [stylix](https://github.com/danth/stylix) | +| [toggles](./common/toggles.nix) | `satellite.toggles` | Generic interface for feature flags | | ## Nixos modules diff --git a/modules/common/default.nix b/modules/common/default.nix index 995487e..c71d6aa 100644 --- a/modules/common/default.nix +++ b/modules/common/default.nix @@ -2,9 +2,8 @@ { # example = import ./example.nix; - lua-encoders = import ./lua-encoders.nix; + lua-lib = import ./lua-lib.nix; lua-colorscheme = import ./lua-colorscheme.nix; theming = import ./theming.nix; toggles = import ./toggles.nix; - neovim = import ./neovim.nix; } diff --git a/modules/common/korora-neovim.nix b/modules/common/korora-neovim.nix index 9cc99ea..0327ed6 100644 --- a/modules/common/korora-neovim.nix +++ b/modules/common/korora-neovim.nix @@ -60,7 +60,7 @@ let } [ ]; cond = types.oneOrMany types.luaLiteral; - init = types.luaLiteral; + init = k.union [ types.luaLiteral types.tempestConfig ]; config = k.union [ types.luaLiteral k.bool types.tempestConfig ]; event = types.oneOrMany k.string; cmd = types.oneOrMany k.string; diff --git a/modules/common/lua-colorscheme.nix b/modules/common/lua-colorscheme.nix index 810fa76..ffc144e 100644 --- a/modules/common/lua-colorscheme.nix +++ b/modules/common/lua-colorscheme.nix @@ -1,6 +1,5 @@ # Lua file containing the current colorscheme. -# TODO: use the lua encoders I've written for neovim -{ lib, config, ... }: { +{ lib, config, inputs, ... }: { options.satellite.colorscheme.lua = lib.mkOption { type = lib.types.lines; description = "Lua file containing the current colorscheme"; @@ -8,6 +7,11 @@ config.satellite.colorscheme.lua = let + e = import ./korora-lua.nix { + inherit lib; + korora = inputs.korora.lib; + }; + theme = { name = config.lib.stylix.scheme.scheme; base00 = config.lib.stylix.scheme.base00; @@ -52,5 +56,5 @@ }; }; in - config.satellite.lib.lua.encoders.anything theme; + e.encode theme; } diff --git a/modules/common/lua-encoders.nix b/modules/common/lua-encoders.nix deleted file mode 100644 index e40abed..0000000 --- a/modules/common/lua-encoders.nix +++ /dev/null @@ -1,209 +0,0 @@ -{ config, lib, pkgs, ... }: -let - # {{{ Lua encoders - # We provide a custom set of helpers for generating lua code for nix.enable - # - # An encoder is a function from some nix value to a string containing lua code. - # This object provides combinators for writing such encoders. - luaEncoders = { - # {{{ "Raw" helpers - mkRawLuaObject = chunks: - '' - { - ${lib.concatStringsSep "," (lib.filter (s: s != "") chunks)} - } - ''; - # }}} - # {{{ General helpers - identity = given: given; - # `const` is mostly useful together with `bind`. See the lua encoder for - # lazy modules for example usage. - const = code: _: code; - # Conceptually, this is the monadic bind operation for encoders. - # This implementation is isomoprhic to that of the reader monad in haskell. - bind = encoder: given: encoder given given; - # This is probably the most useful combinnator defined in this entire object. - # Most of the combinators in the other categories are based on this. - conditional = predicate: caseTrue: caseFalse: - luaEncoders.bind (given: if predicate given then caseTrue else caseFalse); - # This is simply left-composition of functions - map = f: encoder: given: encoder (f given); - # This is simply right-composition of functions - postmap = f: encoder: given: f (encoder given); - filter = f: encoder: luaEncoders.conditional f encoder luaEncoders.nil; - # This is mostly useful for debugging - trace = message: luaEncoders.map (f: lib.traceSeq message (lib.traceVal f)); - fail = mkMessage: v: builtins.throw (mkMessage v); - # }}} - # {{{ Base types - string = given: ''"${lib.escape ["\"" "\\"] (toString given)}"''; - bool = bool: if bool then "true" else "false"; - number = toString; - nil = _: "nil"; - stringOr = luaEncoders.conditional lib.isString luaEncoders.string; - boolOr = luaEncoders.conditional lib.isBool luaEncoders.bool; - numberOr = luaEncoders.conditional (e: lib.isFloat e || lib.isInt e) luaEncoders.number; - nullOr = luaEncoders.conditional (e: e == null) luaEncoders.nil; - # We pipe a combinator which always fail through a bunch of - # `(thing)or : encoder -> encoder` functions, building up a combinator which - # can handle more and more kinds of values, until we eventually build up - # something that should be able to handle everything we throw at it. - anything = lib.pipe (luaEncoders.fail (v: "Cannot figure out how to encode value ${builtins.toJSON v}")) [ - (luaEncoders.attrsetOfOr luaEncoders.anything) - (luaEncoders.listOfOr luaEncoders.anything) - luaEncoders.nullOr - luaEncoders.boolOr - luaEncoders.numberOr - luaEncoders.stringOr - luaEncoders.luaCodeOr # Lua code expressions have priority over attrsets - ]; - # }}} - # {{{ Lua code - # Tagged lua code can be combined with other combinators without worrying - # about conflicts regarding how strings are interpreted. - luaCodeOr = - luaEncoders.conditional (e: lib.isAttrs e && (e.__luaEncoderTag or null) == "lua") - (obj: obj.value); - # This is the most rudimentary (and currently only) way of handling paths. - luaImportOr = tag: - luaEncoders.conditional lib.isPath - (path: "dofile(${luaEncoders.string "${path}"}).${tag}"); - # Accepts both tagged and untagged strings of lua code. - luaString = luaEncoders.luaCodeOr luaEncoders.identity; - # This simply combines the above combinators into one. - luaCode = tag: luaEncoders.luaImportOr tag luaEncoders.luaString; - # }}} - # {{{ Operators - conjunction = left: right: given: - let - l = left given; - r = right given; - in - if l == "nil" then r - else if r == "nil" then l - else "${l} and ${r}"; - all = lib.foldr luaEncoders.conjunction luaEncoders.nil; - # }}} - # {{{ Lists - listOf = encoder: list: - luaEncoders.mkRawLuaObject (lib.lists.map encoder list); - listOfOr = encoder: - luaEncoders.conditional - lib.isList - (luaEncoders.listOf encoder); - # Returns nil when given empty lists - tryNonemptyList = encoder: - luaEncoders.filter - (l: l != [ ]) - (luaEncoders.listOf encoder); - oneOrMany = encoder: luaEncoders.listOfOr encoder encoder; - # Can encode: - # - zero values as nil - # - one value as itself - # - multiple values as a list - zeroOrMany = encoder: luaEncoders.nullOr (luaEncoders.oneOrMany encoder); - # Coerces non list values to lists of one element. - oneOrManyAsList = encoder: luaEncoders.map - (given: if lib.isList given then given else [ given ]) - (luaEncoders.listOf encoder); - # Coerces lists of one element to said element. - listAsOneOrMany = encoder: - luaEncoders.map - (l: if lib.length l == 1 then lib.head l else l) - (luaEncoders.oneOrMany encoder); - # }}} - # {{{ Attrsets - attrName = s: - let - # These list *are* incomplete - forbiddenChars = lib.stringToCharacters "<>[]{}()'\".,;"; - keywords = [ "if" "then" "else" "do" "for" "local" "" ]; - in - if lib.any (c: lib.hasInfix c s) forbiddenChars || lib.elem s keywords then - "[${luaEncoders.string s}]" - else s; - - attrsetOf = encoder: object: - luaEncoders.mkRawLuaObject (lib.mapAttrsToList - (name: value: - let result = encoder value; - in - lib.optionalString (result != "nil") - "${luaEncoders.attrName name} = ${result}" - ) - object - ); - attrsetOfOr = of: luaEncoders.conditional lib.isAttrs (luaEncoders.attrsetOf of); - # This is the most general combinator provided in this section. - # - # We accept: - # - a `noNils` flag which will automatically remove any nil properties - # - order of props that should be interpreted as list elements - # - spec of props that should be interpreted as list elements - # - record of props that should be interpreted as attribute props - attrset = noNils: listOrder: spec: attrset: - let - shouldKeep = given: - if noNils then - given != "nil" - else - true; - - listChunks = lib.lists.map - (attr: - let result = spec.${attr} (attrset.${attr} or null); - in - lib.optionalString (shouldKeep result) result - ) - listOrder; - objectChunks = lib.mapAttrsToList - (attr: encoder: - let result = encoder (attrset.${attr} or null); - in - lib.optionalString (!(lib.elem attr listOrder) && shouldKeep result) - "${luaEncoders.attrName attr} = ${result}" - ) - spec; - in - luaEncoders.mkRawLuaObject (listChunks ++ objectChunks); - # }}} - }; - # }}} -in -{ - options.satellite.lib.lua = { - encoders = lib.mkOption { - # I am too lazy to make this typecheck - type = lib.types.anything; - description = "Combinators used to encode nix values as lua values"; - }; - - writeFile = lib.mkOption { - type = with lib.types; functionTo (functionTo (functionTo path)); - description = "Format and write a lua file to disk"; - }; - }; - - options.satellite.lua.styluaConfig = lib.mkOption { - type = lib.types.path; - description = "Config to use for formatting lua modules"; - }; - - config.satellite.lib.lua = { - encoders = luaEncoders; - - writeFile = path: name: text: - let - destination = "${path}/${name}.lua"; - unformatted = pkgs.writeText "raw-lua-${name}" '' - -- ❄️ I was generated using nix ^~^ - ${text} - ''; - in - pkgs.runCommand "formatted-lua-${name}" { } '' - mkdir -p $out/${path} - cp --no-preserve=mode ${unformatted} $out/${destination} - ${lib.getExe pkgs.stylua} --config-path ${config.satellite.lua.styluaConfig} $out/${destination} - ''; - }; -} diff --git a/modules/common/lua-lib.nix b/modules/common/lua-lib.nix new file mode 100644 index 0000000..47bca54 --- /dev/null +++ b/modules/common/lua-lib.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: +{ + options.satellite.lib.lua = { + writeFile = lib.mkOption { + type = with lib.types; functionTo (functionTo (functionTo path)); + description = "Format and write a lua file to disk"; + }; + }; + + options.satellite.lua.styluaConfig = lib.mkOption { + type = lib.types.path; + description = "Config to use for formatting lua modules"; + }; + + config.satellite.lib.lua = { + writeFile = path: name: text: + let + destination = "${path}/${name}.lua"; + unformatted = pkgs.writeText "raw-lua-${name}" '' + -- ❄️ I was generated using nix ^~^ + ${text} + ''; + in + pkgs.runCommand "formatted-lua-${name}" { } '' + mkdir -p $out/${path} + cp --no-preserve=mode ${unformatted} $out/${destination} + ${lib.getExe pkgs.stylua} --config-path ${config.satellite.lua.styluaConfig} $out/${destination} + ''; + }; +} diff --git a/modules/common/neovim.nix b/modules/common/neovim.nix deleted file mode 100644 index 6c7ba77..0000000 --- a/modules/common/neovim.nix +++ /dev/null @@ -1,664 +0,0 @@ -# This module provides personalised helpers for managing plugins -# using lazy.nvim and a set of custom runtime primitives. -{ pkgs, lib, config, ... }: -let - inherit (lib) types; - - e = config.satellite.lib.lua.encoders; - cfg = config.satellite.neovim; - - # {{{ Custom types - myTypes = { - oneOrMany = t: types.either t (types.listOf t); - zeroOrMore = t: types.nullOr (myTypes.oneOrMany t); - - neovimEnv = types.enum [ "firenvim" "vscode" "neovide" ]; - - # {{{ Lua code - luaCode = types.nullOr (types.oneOf [ - types.path - types.str - myTypes.luaLiteral - ]); - - luaLiteral = types.submodule { - options.__luaEncoderTag = lib.mkOption { - type = types.enum [ "lua" ]; - }; - options.value = lib.mkOption { - type = types.str; - }; - }; - - luaValue = types.nullOr (types.oneOf [ - types.str - types.number - types.bool - (types.attrsOf myTypes.luaValue) - (types.listOf myTypes.luaValue) - ]); - # }}} - # {{{ Lazy key - lazyKey = types.oneOf [ - types.str - (types.submodule - { - options = { - mapping = lib.mkOption { - type = types.str; - description = "The lhs of the neovim mapping"; - }; - - action = lib.mkOption { - default = null; - type = types.nullOr (types.oneOf [ - types.str - myTypes.luaLiteral - ]); - description = "The rhs of the neovim mapping"; - }; - - ft = lib.mkOption { - default = null; - type = myTypes.zeroOrMore types.str; - description = "Filetypes on which this keybind should take effect"; - }; - - mode = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "The vim modes the mapping should take effect in"; - }; - - desc = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "Description for the current keymapping"; - }; - - - expr = lib.mkOption { - default = null; - example = true; - type = types.nullOr types.bool; - description = "If set to `true`, the mapping is treated as an action factory"; - }; - }; - }) - ]; - # }}} - # {{{ Tempest key - tempestKey = types.submodule { - options = { - mapping = lib.mkOption { - example = "a"; - type = types.str; - description = "The lhs of the neovim mapping"; - }; - - action = lib.mkOption { - example = ""; - type = types.either types.str myTypes.luaLiteral; - description = "The rhs of the neovim mapping"; - }; - - bufnr = lib.mkOption { - default = null; - example = true; - type = types.nullOr - (types.oneOf [ - types.bool - types.integer - myTypes.luaLiteral - ]); - description = '' - The index of the buffer to apply local keymaps to. Can be set to - `true` to refer to the current buffer - ''; - }; - - mode = lib.mkOption { - default = null; - example = "nov"; - type = types.nullOr types.str; - description = "The vim modes the mapping should take effect in"; - }; - - silent = lib.mkOption { - default = null; - example = true; - type = types.nullOr types.bool; - description = "Whether the logs emitted by the keymap should be supressed"; - }; - - expr = lib.mkOption { - default = null; - example = true; - type = types.nullOr types.bool; - description = "If set to `true`, the mapping is treated as an action factory"; - }; - - desc = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "Description for the current keymapping"; - }; - }; - }; - # }}} - # {{{ Tempest autocmd - tempestAutocmd = types.submodule { - options = { - event = lib.mkOption { - example = "InsertEnter"; - type = myTypes.oneOrMany types.str; - description = "Events to bind autocmd to"; - }; - - pattern = lib.mkOption { - example = "Cargo.toml"; - type = myTypes.oneOrMany types.str; - description = "File name patterns to run autocmd on"; - }; - - group = lib.mkOption { - example = "CargoCmpSource"; - type = types.str; - description = "Name of the group to create and assign autocmd to"; - }; - - action = lib.mkOption { - example.vim.opt.cmdheight = 1; - type = types.oneOf [ - myTypes.tempestConfiguration - myTypes.luaCode - ]; - description = '' - Code to run when the respctive event occurs. Will pass the event - object as context, which might be used for things like assigning - a buffer number to local keymaps automatically. - ''; - }; - }; - }; - # }}} - # {{{ Tempest configuration - tempestConfiguration = types.submodule { - options = { - vim = lib.mkOption { - default = null; - type = myTypes.luaValue; - example.opt.cmdheight = 0; - description = "Values to assign to the `vim` lua global object"; - }; - - keys = lib.mkOption { - default = null; - type = myTypes.zeroOrMore myTypes.tempestKey; - description = '' - Arbitrary key mappings to create. The keymappings might - automatically be buffer specific depending on the context. For - instance, keymappings created inside autocmds will be local unless - otherwise specified. - ''; - }; - - autocmds = lib.mkOption { - default = null; - type = myTypes.zeroOrMore myTypes.tempestAutocmd; - description = "Arbitrary autocmds to create"; - }; - - setup = lib.mkOption { - default = null; - type = types.nullOr (types.attrsOf myTypes.luaValue); - example.lualine.opts.theme = "auto"; - description = '' - Key-pair mappings for options to pass to .setup functions imported - from different modules - ''; - }; - - callback = lib.mkOption { - default = null; - type = types.nullOr myTypes.luaCode; - description = "Arbitrary code to run after everything else has been configured"; - }; - }; - }; - # }}} - # {{{ Lazy module - lazyModule = lib.fix (lazyModule: types.submodule ({ name ? null, ... }: { - options = { - package = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "Package to configure the module around"; - example = "nvim-telescope/telescope.nvim"; - }; - - dir = lib.mkOption { - default = null; - type = types.nullOr types.path; - description = "Path to install pacakge from"; - }; - - name = lib.mkOption { - default = name; - type = types.nullOr types.str; - description = "Custom name to use for the module"; - example = "lualine"; - }; - - main = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "The name of the lua entrypoint for the plugin (usually auto-detected)"; - example = "lualine"; - }; - - version = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "Pin the package to a certain version (useful for non-nix managed packages)"; - }; - - tag = lib.mkOption { - default = null; - type = types.nullOr types.str; - description = "Pin the package to a certain git tag (useful for non-nix managed packages)"; - }; - - lazy = lib.mkOption { - default = null; - type = types.nullOr types.bool; - description = "Specifies whether this module should be lazy-loaded"; - }; - - dependencies.lua = lib.mkOption { - default = [ ]; - type = types.listOf (types.either types.str lazyModule); - description = "Lazy.nvim module dependencies"; - }; - - dependencies.nix = lib.mkOption { - default = [ ]; - type = types.listOf types.package; - description = "Nix packages to give nvim access to"; - }; - - cond = lib.mkOption { - default = null; - type = myTypes.luaCode; - description = "Condition based on which to enable/disbale loading the package"; - }; - - env.blacklist = lib.mkOption { - default = null; - type = myTypes.zeroOrMore myTypes.neovimEnv; - description = "Environments to blacklist plugin on"; - }; - - env.whitelist = lib.mkOption { - default = null; - type = myTypes.zeroOrMore myTypes.neovimEnv; - description = "Environments to whitelist plugin on"; - }; - - setup = lib.mkOption { - default = null; - type = types.nullOr (types.oneOf [ - myTypes.tempestConfiguration - myTypes.luaCode - types.bool - ]); - description = '' - Lua function (or module) to use for configuring the package. - Used instead of the canonically named `config` because said name has a special meaning in nix - ''; - }; - - event = lib.mkOption { - default = null; - type = myTypes.zeroOrMore types.str; - description = "Event on which the module should be lazy loaded"; - }; - - ft = lib.mkOption { - default = null; - type = myTypes.zeroOrMore types.str; - description = "Filetypes on which the module should be lazy loaded"; - }; - - cmd = lib.mkOption { - default = null; - type = myTypes.zeroOrMore types.str; - description = "Comands on which to load this plugin"; - }; - - init = lib.mkOption { - default = null; - type = myTypes.luaCode; - description = "Lua function (or module) to run right away (even if the package is not yet loaded)"; - }; - - passthrough = lib.mkOption { - default = null; - type = myTypes.luaCode; - description = "Attach additional things to the lazy module"; - }; - - opts = lib.mkOption { - default = null; - type = myTypes.luaValue; - description = "Custom data to pass to the plugin .setup function"; - }; - - keys = lib.mkOption { - default = null; - type = myTypes.zeroOrMore myTypes.lazyKey; - description = "Keybinds to lazy-load the module on"; - }; - }; - })); - # }}} - }; - # }}} -in -{ - # {{{ Option declaration - options.satellite.neovim = { - lazy = lib.mkOption { - default = { }; - description = "Record of plugins to install using lazy.nvim"; - type = types.attrsOf myTypes.lazyModule; - }; - - # {{{ Generated - generated = { - lazy = lib.mkOption { - type = types.attrsOf (types.submodule { - options = { - raw = lib.mkOption { - type = types.lines; - description = "The lua script generated using the other options"; - }; - - module = lib.mkOption { - type = types.package; - description = "The lua script generated using the other options"; - }; - }; - }); - description = "Attrset containing every module generated from the lazy configuration"; - }; - - all = lib.mkOption { - default = { }; - type = types.package; - description = "Derivation building all the given nix modules"; - }; - - lazySingleFile = lib.mkOption { - type = types.package; - description = "Derivation building all the given nix modules in a single file"; - }; - - dependencies = lib.mkOption { - default = [ ]; - type = types.listOf types.package; - description = "List of packages to give neovim access to"; - }; - }; - # }}} - # {{{ Lua generation lib - lib = { - # {{{ Basic lua generators - lua = lib.mkOption { - default = value: { inherit value; __luaEncoderTag = "lua"; }; - type = types.functionTo myTypes.luaLiteral; - description = "include some raw lua code inside module configuration"; - }; - - import = lib.mkOption { - default = path: tag: cfg.lib.lua (e.luaCode tag path); - type = types.functionTo (types.functionTo myTypes.luaLiteral); - description = "import some identifier from some module"; - }; - # }}} - # {{{ Encoders - encode = lib.mkOption { - default = e.anything; - type = types.functionTo types.str; - description = "Encode a nix value to a lua string"; - }; - - encodeTempestConfiguration = lib.mkOption { - default = given: - e.attrset true [ ] - { - vim = e.anything; - callback = e.nullOr e.luaString; - setup = e.nullOr (e.attrsetOf e.anything); - keys = e.zeroOrMany (e.attrset true [ ] { - mapping = e.string; - action = e.luaCodeOr e.string; - desc = e.nullOr e.string; - expr = e.nullOr e.bool; - mode = e.nullOr e.string; - silent = e.nullOr e.bool; - buffer = e.nullOr (e.luaCodeOr (e.boolOr e.number)); - }); - autocmds = e.zeroOrMany (e.attrset true [ ] { - event = e.oneOrMany e.string; - pattern = e.oneOrMany e.string; - group = e.string; - action = e.conditional lib.isAttrs - cfg.lib.encodeTempestConfiguration - e.luaString; - }); - mk_context = e.const (e.nullOr e.luaString (given.mkContext or null)); - } - given; - type = types.functionTo types.str; - description = "Generate a lua object for passing to my own lua runtime for configuration"; - }; - # }}} - # {{{ Thunks - # This version of `nlib.thunk` is required in ceratain cases because - # of issues with `types.oneOf [types.submodule ..., types.submodule]` not - # working as intended atm. - thunkString = lib.mkOption { - default = given: /* lua */ '' - function() ${e.luaString given} end - ''; - type = types.functionTo types.str; - description = "Wrap a lua expression into a lua function as a string"; - }; - - thunk = lib.mkOption { - default = given: cfg.lib.lua (cfg.lib.thunkString given); - type = types.functionTo myTypes.luaLiteral; - description = "Wrap a lua expression into a lua function"; - }; - - contextThunk = lib.mkOption { - default = given: cfg.lib.lua /* lua */ '' - function(context) ${e.luaString given} end - ''; - type = types.functionTo myTypes.luaLiteral; - description = "Wrap a lua expression into a lua function taking an argument named `context`"; - }; - - lazy = lib.mkOption { - default = given: cfg.lib.thunk "return ${e.luaCodeOr e.anything given}"; - type = types.functionTo myTypes.luaLiteral; - description = "Wrap a lua expression into a function returning said expression"; - }; - - withContext = lib.mkOption { - default = given: cfg.lib.contextThunk "return ${e.luaCodeOr e.anything given}"; - type = types.functionTo myTypes.luaLiteral; - description = "Wrap a lua expression into a lua function taking an argument named `context` and returning said expression"; - }; - - tempest = lib.mkOption { - default = given: cfg.lib.lua /* lua */ '' - function(context) - require(${e.string cfg.runtime.tempest}).configure( - ${cfg.lib.encodeTempestConfiguration given}, - context - ) - end - ''; - type = types.functionTo myTypes.luaLiteral; - description = "Wrap a lua expression into a lua function taking an argument named `context`"; - }; - # }}} - # {{{ Language server on attach - languageServerOnAttach = lib.mkOption { - default = given: cfg.lib.lua /* lua */ '' - function(client, bufnr) - require(${e.string cfg.runtime.tempest}).configure(${cfg.lib.encodeTempestConfiguration given}, - { client = client; bufnr = bufnr; }) - - require(${e.string cfg.runtime.languageServerOnAttach}).on_attach(client, bufnr) - end - ''; - type = types.functionTo myTypes.luaCode; - description = "Attach a language server and run some additional code"; - }; - # }}} - }; - # }}} - # {{{ Neovim runtime module paths - runtime = { - tempest = lib.mkOption { - type = types.str; - example = "my.runtime.tempest"; - description = "Module to import the tempest runtime from"; - }; - - languageServerOnAttach = lib.mkOption { - type = types.str; - example = "my.runtime.lspconfig"; - description = "Module to import langauge server .on_attach function from"; - }; - }; - # }}} - }; - # }}} - # {{{ Config generation - # {{{ Lazy module generation - config.satellite.neovim.generated.lazy = - let - # {{{ Lazy key encoder - lazyKeyEncoder = - e.stringOr (e.attrset true [ "mapping" "action" ] { - mapping = e.string; - action = e.nullOr (e.luaCodeOr e.string); - mode = e.nullOr - (e.map - lib.strings.stringToCharacters - (e.listAsOneOrMany e.string)); - desc = e.nullOr e.string; - expr = e.nullOr e.bool; - ft = e.zeroOrMany e.string; - }); - # }}} - # {{{ Lazy spec encoder - xor = a: b: (a || b) && (!a || !b); - implies = a: b: !a || b; - hasProp = obj: p: (obj.${p} or null) != null; - propXor = a: b: obj: xor (hasProp obj a) (hasProp obj b); - propImplies = a: b: obj: implies (hasProp obj a) (hasProp obj b); - - lazyObjectEncoder = e.bind - (opts: e.attrset true [ "package" ] - { - package = e.nullOr e.string; - dir = assert propXor "package" "dir" opts; e.nullOr e.string; - tag = assert propImplies "tag" "package" opts; e.nullOr e.string; - version = assert propImplies "version" "package" opts; e.nullOr e.string; - name = e.nullOr e.string; - main = e.nullOr e.string; - dependencies = e.map (d: d.lua) (e.tryNonemptyList (e.stringOr lazyObjectEncoder)); - lazy = e.nullOr e.bool; - cond = e.all [ - (e.nullOr (e.luaCode "cond")) - (e.filter (_: opts.env.blacklist != [ ] && opts.env.blacklist != null) - (e.const /* lua */ '' - require(${e.string cfg.runtime.tempest}).blacklist(${e.oneOrMany e.string opts.env.blacklist}) - '')) - (e.filter (_: opts.env.whitelist != [ ] && opts.env.whitelist != null) - (e.const /* lua */ '' - require(${e.string cfg.runtime.tempest}).whitelist(${e.oneOrMany e.string opts.env.blacklist}) - '')) - ]; - - config = _: - let - wrap = given: /* lua */'' - function(lazy, opts) - require(${e.string cfg.runtime.tempest}).lazy(lazy, opts, ${given}) - end - ''; - in - e.conditional lib.isAttrs - (e.postmap wrap cfg.lib.encodeTempestConfiguration) - (e.nullOr (e.boolOr (e.luaCode "config"))) - opts.setup; - init = e.nullOr (e.luaCode "init"); - event = e.zeroOrMany e.string; - cmd = e.zeroOrMany e.string; - ft = e.zeroOrMany e.string; - keys = e.nullOr (e.oneOrManyAsList lazyKeyEncoder); - passthrough = e.anything; - opts = e.anything; - }); - # }}} - in - lib.attrsets.mapAttrs - (name: opts: rec { - raw = lazyObjectEncoder opts; - module = config.satellite.lib.lua.writeFile "lua/nix/plugins" name raw; - }) - cfg.lazy; - - config.satellite.neovim.generated.lazySingleFile = - let - makeFold = name: m: '' - -- {{{ ${name} - ${m.raw}, - -- }}}''; - - mkReturnList = objects: '' - return { - ${objects} - }''; - - script = lib.pipe cfg.generated.lazy [ - (lib.attrsets.mapAttrsToList makeFold) - (lib.concatStringsSep "\n") - mkReturnList - ]; - in - config.satellite.lib.lua.writeFile - "lua/nix/plugins" "init" - script; - - config.satellite.neovim.generated.all = - pkgs.symlinkJoin { - name = "lazy-nvim-modules"; - paths = lib.attrsets.mapAttrsToList (_: m: m.module) cfg.generated.lazy; - }; - # }}} - - config.satellite.neovim.generated.dependencies = - lib.pipe cfg.lazy - [ - (lib.attrsets.mapAttrsToList (_: m: m.dependencies.nix)) - lib.lists.flatten - ]; - # }}} -}