1
Fork 0

Huge progress on korora-based tempest generation

This commit is contained in:
Matei Adriel 2023-12-25 14:14:33 +01:00
parent 63d980ddf9
commit 42cd073278
No known key found for this signature in database
8 changed files with 1678 additions and 1462 deletions

View file

@ -1,11 +1,14 @@
local M = {} local M = {}
function M.setup() function M.setup()
vim.opt.runtimepath:append(vim.g.nix_extra_runtime)
local tempest = require("my.tempest")
local nix = require("nix")
-- Import my other files -- Import my other files
require("my.options").setup() tempest.configureMany(nix.pre)
require("my.keymaps").setup() require("my.keymaps").setup()
require("my.lazy").setup() require("my.lazy").setup()
require("my.abbreviations").setup() tempest.configureMany(nix.post)
end end
return M return M

View file

@ -55,92 +55,11 @@ end
-- }}} -- }}}
function M.setup() function M.setup()
-- {{{ Free up q and Q
M.move("q", "yq", { desc = "Record macro" })
M.move("Q", "yQ")
-- }}}
-- {{{ Easier access to <C-^>
M.move("<C-^>", "<Leader>a", { desc = "[A]lternate file" })
-- }}}
-- {{{ Quit all buffers
M.nmap("Q", ":wqa<cr>", "Save all files and [q]uit")
-- }}}
-- {{{ Replace word in file
M.nmap("<leader>rw", ":%s/<C-r><C-w>/", "[R]eplace [w]ord in file")
-- }}}
-- {{{ Toggle settings
M.nmap(
"<leader>sw",
require("my.helpers.wrapMovement").toggle,
"toggle word [w]rap"
)
-- }}}
-- {{{ Text objects -- {{{ Text objects
M.delimitedTextobject("q", '"', "[q]uotes") M.delimitedTextobject("q", '"', "[q]uotes")
M.delimitedTextobject("a", "'", "[a]postrophes") M.delimitedTextobject("a", "'", "[a]postrophes")
M.delimitedTextobject("r", "[", "squa[r]e brackets") M.delimitedTextobject("r", "[", "squa[r]e brackets")
-- }}} -- }}}
-- {{{Diagnostic keymaps
M.nmap("[d", vim.diagnostic.goto_prev, "Goto previous [d]iagnostic")
M.nmap("]d", vim.diagnostic.goto_next, "Goto next [d]iagnostic")
M.move("J", "qj")
M.nmap("J", vim.diagnostic.open_float, "Open current diagnostic")
M.nmap("<leader>D", vim.diagnostic.setloclist, "[D]iagnostic loclist")
-- }}}
-- {{{ Chords (save, clipboard)
-- Different chords get mapped to f keys by a custom script of mine.
-- In the future, I might get this on my keyboard firmware.
vim.keymap.set({ "i", "v" }, "<f10>", "<Esc>", { desc = "Exit insert mode" }) -- Exit inset mode using *jk*
vim.keymap.set({ "n", "v" }, "<f11>", '"+', { desc = "Use global clipboard" }) -- Use global clipboard with *cp*
M.nmap("<f12>", "<cmd>silent write<cr>", "Save current file", true) -- Save using *ji*
-- }}}
-- {{{ Shift-Enter for not continuing the current comment
-- This does not preserve intendation. Not sure what a better solution would look like.
vim.keymap.set("i", "<S-CR>", function()
vim.paste({ "", "" }, -1)
end, { desc = "Insert newline without continuing the current comment" })
-- }}}
-- {{{ Allow quiting basic buffers with "qq"
vim.api.nvim_create_autocmd("FileType", {
pattern = { "help" },
group = vim.api.nvim_create_augroup("BasicBufferQuitting", {}),
callback = function(event)
vim.keymap.set(
"n",
"qq",
"<cmd>close<cr>",
{ buffer = event.buf, silent = true, desc = "[q]uit current buffer" }
)
end,
})
-- }}}
-- {{{ Winblend
vim.api.nvim_create_autocmd("FileType", {
pattern = { "*" },
group = vim.api.nvim_create_augroup("WinblendSettings", {}),
callback = function()
vim.opt.winblend = 0
end,
})
-- }}}
-- {{{ Manage cmdheight
vim.api.nvim_create_autocmd("CmdlineEnter", {
group = vim.api.nvim_create_augroup("SetCmdheightCmdlineEnter", {}),
callback = function()
if not vim.g.inside_venn then
vim.opt.cmdheight = 1
end
end,
})
vim.api.nvim_create_autocmd("CmdlineLeave", {
group = vim.api.nvim_create_augroup("SetCmdheightCmdlineLeave", {}),
callback = function()
if not vim.g.inside_venn then
vim.opt.cmdheight = 0
end
end,
})
-- }}}
end end
return M return M

View file

@ -7,8 +7,8 @@ end
function M.setup() function M.setup()
require("lazy").setup({ require("lazy").setup({
importFrom("my.plugins"), importFrom("my.plugins"),
importFrom("nix.plugins"),
importFrom("my.plugins.themes"), importFrom("my.plugins.themes"),
unpack(require("nix").lazy),
}, { }, {
defaults = { lazy = true }, defaults = { lazy = true },
install = { install = {

View file

@ -119,17 +119,26 @@ end
function M.configure(opts, context) function M.configure(opts, context)
if type(opts) == "function" then if type(opts) == "function" then
return M.configure(opts(context), context) opts = opts(context)
end end
if type(opts.mk_context) == "function" then if type(opts) ~= "table" then
context = opts.mk_context(context) -- TODO: throw
return
end
if type(opts.mkContext) == "function" then
context = opts.mkContext(context)
end end
if type(opts.vim) == "table" then if type(opts.vim) == "table" then
recursive_assign(opts.vim, vim) recursive_assign(opts.vim, vim)
end end
if type(opts.keys) == "function" then
opts.keys = opts.keys(context)
end
if type(opts.keys) == "table" then if type(opts.keys) == "table" then
local keys = opts.keys local keys = opts.keys
@ -143,6 +152,10 @@ function M.configure(opts, context)
end end
end end
if type(opts.autocmds) == "function" then
opts.autocmds = opts.autocmds(context)
end
if type(opts.autocmds) == "table" then if type(opts.autocmds) == "table" then
local autocmds = opts.autocmds local autocmds = opts.autocmds
@ -180,8 +193,10 @@ function M.configure(opts, context)
end end
end end
M.lazy = function(lazy, opts, spec) function M.configureMany(specs, context)
return M.configure(spec, { lazy = lazy, opts = opts }) for _, spec in ipairs(specs) do
M.configure(spec, context)
end
end end
-- }}} -- }}}
-- {{{ Neovim env handling -- {{{ Neovim env handling
@ -230,31 +245,48 @@ end
-- {{{ Fixup lazy spec generated by nix -- {{{ Fixup lazy spec generated by nix
function M.prepareLazySpec(spec) function M.prepareLazySpec(spec)
for _, module in ipairs(spec) do for _, module in ipairs(spec) do
if spec.tempest ~= nil then if module.package ~= nil then
spec.config = function(lazy, opts) module[1] = module.package
M.configure(spec.tempest, { lazy = lazy, opts = opts }) module.package = nil
end
local configType = type(module.config)
if configType == "function" or configType == "table" then
local previousConfig = module.config
module.config = function(lazy, opts)
M.configure(previousConfig, { lazy = lazy, opts = opts })
end end
end end
if spec.dependencies ~= nil then if module.keys ~= nil then
spec.dependencies = spec.dependencies.lua if type(module.keys) == "string" or module.keys.mapping ~= nil then
module.keys = { module.keys }
end end
if spec.keys ~= nil then for _, key in ipairs(module.keys) do
local keys = spec.keys if type(key) ~= "string" then
if spec.keys.mapping ~= nil then
keys = { keys }
end
for _, key in ipairs(keys) do
key[1] = key.mapping key[1] = key.mapping
key.mapping = nil
if key.mode ~= nil then if key.mode ~= nil then
key.mode = H.string_chars(key.mode) key.mode = H.string_chars(key.mode)
end end
if key.action ~= nil then
key[2] = key.action
key.action = nil
end end
end end
end end
end end
if type(module.cond) == "table" then
local final = true
for _, cond in ipairs(module.cond) do
final = final and cond
end
module.cond = final
end
end
end
-- }}} -- }}}
return M return M

File diff suppressed because it is too large Load diff

View file

@ -2,52 +2,78 @@
let let
k = korora; k = korora;
# {{{ Lua encoders
# {{{ Helpers # {{{ Helpers
helpers = rec { helpers = rec {
xor = a: b: (a || b) && (!a || !b); removeEmptyLines = str:
implies = a: b: !a || b; lib.pipe str [
hasProp = obj: p: (obj.${p} or null) != null; (lib.splitString "\n")
propXor = a: b: obj: xor (hasProp obj a) (hasProp obj b); (lib.lists.filter
(line: lib.any
(c: c != " ")
(lib.stringToCharacters line)))
(lib.concatStringsSep "\n")
];
# {{{ Verification helpers
toPretty = lib.generators.toPretty { indent = " "; };
withError = cond: err: if cond then null else err;
hasProp = obj: p: obj ? ${p};
propExists = p: obj:
helpers.withError
(helpers.hasProp obj p)
"Expected property ${p}";
propXor = a: b: obj:
helpers.withError
((hasProp obj a) != (hasProp obj b))
"Expected only one of the properties ${a} and ${b} in object ${toPretty obj}";
propOnlyOne = props: obj: propOnlyOne = props: obj:
1 == lib.count (prop: obj ? prop); helpers.withError
propImplies = a: b: obj: implies (hasProp obj a) (hasProp obj b); (1 == lib.count (hasProp obj) props)
"Expected exactly one property from the list ${toPretty props} in object ${toPretty obj}";
propImplies = a: b: obj:
helpers.withError
((hasProp obj a) -> (hasProp obj b))
"Property ${a} should imply property ${b} in object ${toPretty obj}";
mkVerify = checks: obj: mkVerify = checks: obj:
assert lib.all lib.isFunction checks;
let let
results = lib.lists.map checks obj; results = lib.lists.map (c: c obj) checks;
errors = lib.lists.filter (v: v != null) results; errors = lib.lists.filter (v: v != null) results;
in in
assert lib.all lib.isString errors;
if errors == [ ] if errors == [ ]
then null then null
else else
let prettyErrors = let prettyErrors =
lib.lists.map (s: "\n- ${s}") errors; lib.lists.map (s: "\n- ${s}") errors;
in in
"Multiple errors occured: ${prettyErrors}"; "Multiple errors occured: ${lib.concatStrings prettyErrors}";
# }}}
# {{{ Custom types
intersection = l: r: intersection = l: r:
k.typedef' k.typedef'
"${l.name} ${r.name}" "${l.name} ${r.name}"
(helpers.mkVerify [ l r ]); (helpers.mkVerify [ l r ]);
dependentAttrsOf = # dependentAttrsOf =
name: mkType: # name: mkType:
let # let
typeError = name: v: "Expected type '${name}' but value '${toPretty v}' is of type '${typeOf v}'"; # typeError = name: v: "Expected type '${name}' but value '${toPretty v}' is of type '${typeOf v}'";
addErrorContext = context: error: if error == null then null else "${context}: ${error}"; # addErrorContext = context: error: if error == null then null else "${context}: ${error}";
#
withErrorContext = addErrorContext "in ${name} value"; # withErrorContext = addErrorContext "in ${name} value";
in # in
k.typedef' name # k.typedef' name
(v: # (v:
if ! lib.isAttrs v then # if ! lib.isAttrs v then
typeError name v # typeError name v
else # else
withErrorContext # withErrorContext
(mkVerify # (mkVerify
(lib.mapAttrsToList (k: _: mkType k) v) # (lib.mapAttrsToList (k: _: mkType k) v)
v)); # v));
# }}}
# {{{ Encoding helpers
mkRawLuaObject = chunks: mkRawLuaObject = chunks:
'' ''
{ {
@ -55,238 +81,83 @@ let
} }
''; '';
encodeString = given: ''"${lib.escape ["\"" "\\"] (toString given)}"'';
mkAttrName = s: mkAttrName = s:
let let
# These list *are* incomplete # These list *are* incomplete
forbiddenChars = lib.stringToCharacters "<>[]{}()'\".,;"; forbiddenChars = lib.stringToCharacters "<>[]{}()'\".,:;";
keywords = [ "if" "then" "else" "do" "for" "local" "" ]; keywords = [ "if" "then" "else" "do" "for" "local" "" ];
in in
if lib.any (c: lib.hasInfix c s) forbiddenChars || lib.elem s keywords then if lib.any (c: lib.hasInfix c s) forbiddenChars || lib.elem s keywords then
"[${m.string s}]" "[${helpers.encodeString s}]"
else s; else s;
# }}}
}; };
# }}} # }}}
# {{{ This function takes a nix value and encodes it to a lua string.
# We provide a custom set of helpers for generating lua code for nix.enable isLuaLiteral = given: lib.isAttrs given && given.__luaEncoderTag or null == "lua";
# encodeWithDepth = depth: given:
# An encoder is a function from some nix value to a string containing lua code. let recurse = encodeWithDepth depth; in
# This object provides combinators for writing such encoders. if lib.isString given || lib.isDerivation given || lib.isPath given then
m = { helpers.encodeString given
# {{{ General helpers else if lib.isInt given || lib.isFloat given then
typed = type: toLua: type // { toString given
unsafeToLua = toLua; else if lib.isBool given then
toLua = v: toLua (type.check v); if given then "true" else "false"
override = a: m.typed (type.override a) toLua; else if given == null then
}; "nil"
withDefault = type: default: type // { else if lib.isList given then
default.value = default; helpers.mkRawLuaObject (lib.lists.map recurse given)
}; else if lib.isAttrs given && given.__luaEncoderTag or null == "foldedList" then
typedWithDefault = type: toLua: default:
m.withDefault (m.typed type toLua) default;
unsafe = type: type // { toLua = type.unsafeToLua; };
untyped = m.typed k.any;
untype = type: m.untyped type.toLua;
withName = name: type: type // { inherit name; }; # TODO: should we use override here?
# `const` is mostly useful together with `bind`. See the lua encoder for
# lazy modules for example usage.
const = code: m.untyped (_: code);
# Conceptually, this is the monadic bind operation for encoders.
# This implementation is isomoprhic to that of the reader monad in haskell.
bind = name: higherOrder:
m.typed
(k.typedef' name (v: (higherOrder v).verify v))
(given: (higherOrder given).toLua 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:
let base = m.bind
m.bind
"${caseTrue.name} ${caseFalse.name}"
(given: if predicate given then caseTrue else caseFalse);
in
if caseTrue ? default then
m.withDefault base caseTrue.default
else if caseFalse ? default then
m.withDefault base caseFalse.default
else
base;
try = caseTrue: caseFalse:
let base = m.bind
"${caseTrue.name} ${caseFalse.name}"
(given: if caseTrue.verify given == null then m.unsafe caseTrue else caseFalse);
in
if caseTrue ? default then
m.withDefault base caseTrue.default
else if caseFalse ? default then
m.withDefault base caseFalse.default
else
base;
oneOf = lib.foldr m.try
(m.bottom (v: "No variants matched for value ${builtins.toJSON v}"));
# This is simply left-composition of functions
cmap = f: t:
m.typed
(lib.typedef' t.name (v: t.verify (f v)))
(given: t.toLua (f given));
# This is simply right-composition of functions
map = f: t: m.typed t (given: f (t.toLua given));
filter = predicate: type: given:
m.conditional predicate type (m.untype m.nil);
# This is mostly useful for debugging
trace = message: m.cmap (f: lib.traceSeq message (lib.traceVal f));
bottom = mkMessage: m.typed (m.typedef "" mkMessage) lib.id;
# }}}
# {{{ Base types
string = m.typed k.string (given: ''"${lib.escape ["\"" "\\"] (toString given)}"'');
bool = m.typed k.bool (bool: if bool then "true" else "false");
integer = m.typed k.int toString;
float = m.typed k.float toString;
number = m.typed k.number toString;
ignored = type: m.typed type (_: "nil");
nil = m.typedWithDefault
(k.typedef "null" (v: v == null))
(_: "nil")
null;
stringOr = m.try m.string;
boolOr = m.try m.bool;
numberOr = m.try m.number;
nullOr = m.try m.nil;
anything = m.withName "" (m.oneOf [
m.markedLuaCode # Lua code expressions have priority over attrsets
m.string
m.number
m.bool
m.null
(m.listOf m.anything)
(m.attrsetOf m.anything)
]);
# }}}
# {{{ Lua code
identity = m.typed k.string lib.id;
markedLuaCode =
m.typed
(k.struct "marked lua code" {
value = k.string;
__luaEncoderTag = k.enum "lua encoder tag" [ "lua" ];
})
(obj: obj.value);
# This is the most rudimentary (and currently only) way of handling paths.
luaImport = tag:
m.typed (k.typedef "path" lib.isPath)
(path: "dofile(${m.string "${path}"}).${tag}");
# Accepts both tagged and untagged strings of lua code.
luaString = m.try m.markedLuaCode m.identity;
# This simply combines the above combinators into one.
luaCode = tag: m.try (m.luaImport tag) m.luaString;
# }}}
# {{{ Operators
conjunction = left: right: given:
m.typed (helpers.intersection left right) (
let let
l = left.toLua given; makeFold = name: value: ''
r = right.toLua given; -- {{{ ${name}
${recurse value},
-- }}}'';
folds = lib.mapAttrsToList makeFold given.value;
in in
if l == "nil" then r ''
else if r == "nil" then l {
else "${l} and ${r}" ${lib.concatStringsSep "\n" folds}
); }''
all = lib.foldr m.conjunction m.nil; else if isLuaLiteral given then
# Similar to `all` but takes in a list and given.value
# treats every element as a condition. else if lib.isAttrs given then
allIndices = name: type: helpers.mkRawLuaObject
m.bind name (lib.mapAttrsToList
(g: lib.pipe g [
(lib.lists.imap0
(i: _:
m.cmap
(builtins.elemAt i)
type))
m.all
]);
# }}}
# {{{ Lists
listOf = type: list:
m.typedWithDefault
(k.listOf type)
(helpers.mkRawLuaObject (lib.lists.map type.toLua list))
[ ];
listOfOr = type: m.try (m.listOf type);
# Returns nil when given empty lists
tryNonemptyList = type:
m.typedWithDefault
(k.listOf type)
(m.filter
(l: l != [ ])
(m.listOf type))
[ ];
oneOrMany = type: m.listOfOr type type;
# Can encode:
# - zero values as nil
# - one value as itself
# - multiple values as a list
zeroOrMany = type: m.nullOr (m.oneOrMany type);
# Coerces non list values to lists of one element.
oneOrManyAsList = type: m.listOfOr type (m.map (e: [ e ]) type);
# Coerces lists of one element to said element.
listAsOneOrMany = type:
m.cmap
(l: if lib.length l == 1 then lib.head l else l)
(m.oneOrMany type);
# }}}
# {{{ Attrsets
attrsetOf = type:
m.typed (k.attrsOf type)
(object:
helpers.mkRawLuaObject (lib.mapAttrsToList
(name: value: (name: value:
let result = type.toLua value; let result = recurse value;
in in
lib.optionalString (result != "nil") lib.optionalString (result != "nil")
"${helpers.mkAttrName name} = ${result}" "${helpers.mkAttrName name} = ${result}"
) )
object given)
) else if lib.isFunction given then
);
# This is the most general combinator provided in this section.
#
# We accept:
# - 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 = name: listOrder: spec: attrset:
m.cmap
(given: lib.mapAttrs
(key: type:
if given ? ${key} then
given.${key}
else
type.default or null)
spec)
(m.typed (k.struct name spec) (
let let
listChunks = lib.lists.map argNames = [ "context" "inner_context" "local_context" ];
(attr: secretArg =
let result = spec.${attr}.toLua (attrset.${attr} or null); if depth >= builtins.length argNames
then "arg_${depth}"
else builtins.elemAt argNames depth;
body = given secretArg;
encoded = encodeWithDepth (depth + 1) body;
encodedBody =
if isLuaLiteral body
then encoded
else "return ${encoded}";
in in
lib.optionalString (result != "nil") result if lib.hasInfix secretArg encoded
) then ''
listOrder; function(${secretArg})
objectChunks = lib.mapAttrsToList ${encodedBody}
(attr: type: end''
let result = type.toLua (attrset.${attr} or null); else ''
in function()
lib.optionalString (!(lib.elem attr listOrder) && result != "nil") ${encodedBody}
"${helpers.mkAttrName attr} = ${result}" end''
) else builtins.throw "Cannot encode value ${helpers.toPretty given}";
spec;
in
helpers.mkRawLuaObject (listChunks ++ objectChunks)
));
withAttrsCheck = type: verify:
type.override { inherit verify; };
# }}}
};
# }}} # }}}
encode = encodeWithDepth 0;
in in
m // { inherit helpers; } { inherit encode helpers; }

View file

@ -1,36 +1,234 @@
attrs@{ lib, ... }: attrs@{ lib, korora, ... }:
let let
e = import ./korora-lua.nix attrs; e = import ./korora-lua.nix attrs;
k = korora;
h = e.helpers; h = e.helpers;
m = { struct = name: props: verify: (k.struct name props).override {
lazyModule = e.withAttrsCheck total = false;
(e.attrset "lazy module" [ "package" ] { unknown = false;
package = e.nullOr e.string; verify = h.mkVerify verify;
dir = e.nullOr e.type; };
version = e.nullOr e.string;
tag = e.nullOr e.string; lazyType = name: mkType: k.typedef' name (v: (mkType true).verify v);
name = e.nullOr e.string;
main = e.nullOr e.string; types = {
lazy = e.nullOr e.bool; # {{{ Helper types
dependencies = e.tryNonemptyList (e.stringOr m.lazyModule); oneOrMany = type: k.union [ type (k.listOf type) ];
config = e.anything; luaValue = k.any;
cond = e.nullOr (e.bind (value: e.all [ strictLuaLiteral = (k.struct "lua literal" {
# TODO: we want a zip here value = k.string;
(e.nullOr (e.luaCode "cond")) __luaEncoderTag = k.enum "lua literal tag" [ "lua" ];
])); }).override { unknown = false; };
init = e.nullOr (e.luaCode "init"); derivation = k.typedef "derivation" lib.isDerivation;
event = e.zeroOrMany e.string; path = k.typedef "path" lib.isPath;
cmd = e.zeroOrMany e.string; functionCheckedWith = arg: type:
ft = e.zeroOrMany e.string; k.typedef'
keys = e.listOf e.anything; "${h.toPretty arg} -> ${type.name}"
passthrough = e.anything; (f:
opts = e.anything; if lib.isFunction f
}) then type.verify (f arg)
(h.mkVerify [ else "Expected function, but got ${h.toPretty f} instead");
luaEagerOrLazy = type: k.union [ type (types.functionCheckedWith "" type) ];
luaLiteral = types.luaEagerOrLazy types.strictLuaLiteral;
# }}}
# {{{ Lazy key
lazyKey = struct "lazy key"
{
mapping = k.string;
action = k.union [ types.luaLiteral k.string ];
mode = k.string;
desc = k.string;
expr = k.bool;
ft = types.oneOrMany k.string;
}
[ (h.propExists "mapping") ];
# }}}
# {{{ Lazy module
lazyModule = lazyType "actually lazy lazy module" (_: struct "lazy module"
{
package = k.string;
dir = k.union [ k.string types.derivation types.path ];
version = k.string;
tag = k.string;
name = k.string;
main = k.string;
lazy = k.bool;
dependencies = struct "lazy dependencies"
{
lua = k.listOf (k.union [ k.string types.lazyModule ]);
nix = k.listOf types.derivation;
}
[ ];
cond = types.oneOrMany types.luaLiteral;
init = types.luaLiteral;
config = k.union [ types.luaLiteral k.bool types.tempestConfig ];
event = types.oneOrMany k.string;
cmd = types.oneOrMany k.string;
ft = types.oneOrMany k.string;
keys = types.oneOrMany (k.union [ k.string types.lazyKey ]);
passthrough = types.luaValue;
opts = types.luaValue;
}
[
(h.propOnlyOne [ "dir" "package" ]) (h.propOnlyOne [ "dir" "package" ])
(h.propImplies "tag" "package") (h.propImplies "tag" "package")
(h.propImplies "version" "package") (h.propImplies "version" "package")
]); ]);
# }}}
# {{{ Tempest key
tempestKey = struct "tempest key"
{
mapping = k.string;
action = k.union [ types.luaLiteral k.string ];
mode = k.string;
desc = k.string;
expr = k.bool;
silent = k.bool;
ft = types.oneOrMany k.string;
buffer = k.union [ k.bool k.number types.luaLiteral ];
}
[
(h.propExists "mapping")
(h.propExists "action")
];
# }}}
# {{{ Tempest autocmd
tempestAutocmd = struct "tempest autocommand"
{
event = types.oneOrMany k.string;
pattern = types.oneOrMany k.string;
group = k.string;
action = k.union [ types.tempestConfig types.luaLiteral ];
}
[
(h.propExists "event")
(h.propExists "group")
(h.propExists "action")
];
# }}}
# {{{ Tempest config
tempestConfig = lazyType "lazy tempest config" (_: struct "tempest config"
{
vim = types.luaValue;
callback = k.union [ k.function types.luaLiteral ];
setup = k.attrsOf types.luaValue;
keys = types.luaEagerOrLazy (types.oneOrMany types.tempestKey);
autocmds = types.luaEagerOrLazy (types.oneOrMany types.tempestAutocmd);
mkContext = types.luaLiteral;
}
[ ]);
# }}}
# {{{ Neovim env
neovimEnv = k.enum "neovim env"
[ "neovide" "firenvim" "vscode" ];
# }}}
# {{{ Neovim config
neovimConfig = struct "neovim configuration"
{
pre = k.attrsOf types.tempestConfig;
lazy = k.attrsOf types.lazyModule;
post = k.attrsOf types.tempestConfig;
} [ ];
# }}}
};
hasType = type: value:
let err = type.verify value; in
lib.assertMsg (err == null) err;
mkLib = { tempestModule, languageServerModule }:
assert hasType k.string tempestModule;
assert hasType k.string languageServerModule;
rec {
inherit (e) encode;
# {{{ Common generation helpers
lua = value: assert hasType k.string value;
{ inherit value; __luaEncoderTag = "lua"; };
import = path: tag:
assert lib.isPath path;
assert hasType k.string tag;
lua "dofile(${encode (toString path)}).${tag}";
foldedList = value: assert hasType k.attrs value;
{ inherit value; __luaEncoderTag = "foldedList"; };
thunk = code: _: lua code;
tempest = given: context: lua ''
D.tempest.configure(
${encode given},
${context}
)
'';
customLanguageServerOnAttach = given:
assert hasType types.tempestConfig given;
lua /* lua */ ''
function(client, bufnr)
D.tempest.configure(${encode given},
{ client = client; bufnr = bufnr; })
D.language_server.on_attach(client, bufnr)
end
'';
blacklist = given:
assert hasType (types.oneOrMany types.neovimEnv) given;
lua /* lua */ ''
D.tempest.blacklist(${encode given})
'';
whitelist = given:
assert hasType (types.oneOrMany types.neovimEnv) given;
lua /* lua */ ''
D.tempest.whitelist(${encode given})
'';
# }}}
# {{{ Main config generation entrypoint
generateConfig = rawConfig:
assert hasType types.neovimConfig rawConfig;
let
config = { lazy = { }; pre = { }; post = { }; } // rawConfig;
collectNixDeps = lazyModule:
if lazyModule ? dependencies then
let
nix = lazyModule.dependencies.nix or [ ];
other = lib.pipe (lazyModule.dependencies.lua or [ ]) [
(lib.lists.map collectNixDeps)
lib.lists.flatten
];
in
nix ++ other
else
[ ];
dependencies = lib.pipe config.lazy [
(lib.mapAttrsToList (_: collectNixDeps))
lib.lists.flatten
];
processedLazyModules =
lib.mapAttrs
(name: module: { inherit name; } // module // {
dependencies = (module.dependencies or { }).lua or null;
})
config.lazy;
luaConfig = ''
local M = {}
local D = {
tempest = require(${encode tempestModule}),
langauge_server = require(${encode languageServerModule})
}
-- {{{ Pre-plugin config
M.pre = ${encode (foldedList config.pre)}
-- }}}
-- {{{ Lazy modules
M.lazy = ${encode (foldedList processedLazyModules)}
D.tempest.prepareLazySpec(M.lazy)
-- }}}
-- {{{ Post-plugin config
M.post = ${encode (foldedList config.post)}
-- }}}
return M
'';
in
{ inherit dependencies; lua = luaConfig; };
# }}}
}; };
in in
m mkLib

View file

@ -196,7 +196,7 @@ in
let let
destination = "${path}/${name}.lua"; destination = "${path}/${name}.lua";
unformatted = pkgs.writeText "raw-lua-${name}" '' unformatted = pkgs.writeText "raw-lua-${name}" ''
-- This file was generated using nix ^~^ -- I was generated using nix ^~^
${text} ${text}
''; '';
in in