Korora progress backup
This commit is contained in:
parent
74f2ea1e2c
commit
63d980ddf9
|
@ -118,6 +118,10 @@ local function recursive_assign(source, destination)
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.configure(opts, context)
|
function M.configure(opts, context)
|
||||||
|
if type(opts) == "function" then
|
||||||
|
return M.configure(opts(context), context)
|
||||||
|
end
|
||||||
|
|
||||||
if type(opts.mk_context) == "function" then
|
if type(opts.mk_context) == "function" then
|
||||||
context = opts.mk_context(context)
|
context = opts.mk_context(context)
|
||||||
end
|
end
|
||||||
|
@ -223,5 +227,34 @@ function M.withSavedCursor(callback)
|
||||||
vim.api.nvim_win_set_cursor(0, cursor)
|
vim.api.nvim_win_set_cursor(0, cursor)
|
||||||
end
|
end
|
||||||
-- }}}
|
-- }}}
|
||||||
|
-- {{{ Fixup lazy spec generated by nix
|
||||||
|
function M.prepareLazySpec(spec)
|
||||||
|
for _, module in ipairs(spec) do
|
||||||
|
if spec.tempest ~= nil then
|
||||||
|
spec.config = function(lazy, opts)
|
||||||
|
M.configure(spec.tempest, { lazy = lazy, opts = opts })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if spec.dependencies ~= nil then
|
||||||
|
spec.dependencies = spec.dependencies.lua
|
||||||
|
end
|
||||||
|
|
||||||
|
if spec.keys ~= nil then
|
||||||
|
local keys = spec.keys
|
||||||
|
if spec.keys.mapping ~= nil then
|
||||||
|
keys = { keys }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, key in ipairs(keys) do
|
||||||
|
key[1] = key.mapping
|
||||||
|
if key.mode ~= nil then
|
||||||
|
key.mode = H.string_chars(key.mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- }}}
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
292
modules/common/korora-lua.nix
Normal file
292
modules/common/korora-lua.nix
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
{ lib, korora, ... }:
|
||||||
|
let
|
||||||
|
k = korora;
|
||||||
|
|
||||||
|
# {{{ Lua encoders
|
||||||
|
# {{{ Helpers
|
||||||
|
helpers = rec {
|
||||||
|
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);
|
||||||
|
propOnlyOne = props: obj:
|
||||||
|
1 == lib.count (prop: obj ? prop);
|
||||||
|
propImplies = a: b: obj: implies (hasProp obj a) (hasProp obj b);
|
||||||
|
mkVerify = checks: obj:
|
||||||
|
let
|
||||||
|
results = lib.lists.map checks obj;
|
||||||
|
errors = lib.lists.filter (v: v != null) results;
|
||||||
|
in
|
||||||
|
if errors == [ ]
|
||||||
|
then null
|
||||||
|
else
|
||||||
|
let prettyErrors =
|
||||||
|
lib.lists.map (s: "\n- ${s}") errors;
|
||||||
|
in
|
||||||
|
"Multiple errors occured: ${prettyErrors}";
|
||||||
|
|
||||||
|
intersection = l: r:
|
||||||
|
k.typedef'
|
||||||
|
"${l.name} ∧ ${r.name}"
|
||||||
|
(helpers.mkVerify [ l r ]);
|
||||||
|
|
||||||
|
dependentAttrsOf =
|
||||||
|
name: mkType:
|
||||||
|
let
|
||||||
|
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}";
|
||||||
|
|
||||||
|
withErrorContext = addErrorContext "in ${name} value";
|
||||||
|
in
|
||||||
|
k.typedef' name
|
||||||
|
(v:
|
||||||
|
if ! lib.isAttrs v then
|
||||||
|
typeError name v
|
||||||
|
else
|
||||||
|
withErrorContext
|
||||||
|
(mkVerify
|
||||||
|
(lib.mapAttrsToList (k: _: mkType k) v)
|
||||||
|
v));
|
||||||
|
|
||||||
|
mkRawLuaObject = chunks:
|
||||||
|
''
|
||||||
|
{
|
||||||
|
${lib.concatStringsSep "," (lib.filter (s: s != "") chunks)}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
mkAttrName = 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
|
||||||
|
"[${m.string s}]"
|
||||||
|
else s;
|
||||||
|
|
||||||
|
};
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
m = {
|
||||||
|
# {{{ General helpers
|
||||||
|
typed = type: toLua: type // {
|
||||||
|
unsafeToLua = toLua;
|
||||||
|
toLua = v: toLua (type.check v);
|
||||||
|
override = a: m.typed (type.override a) toLua;
|
||||||
|
};
|
||||||
|
withDefault = type: default: type // {
|
||||||
|
default.value = default;
|
||||||
|
};
|
||||||
|
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
|
||||||
|
l = left.toLua given;
|
||||||
|
r = right.toLua given;
|
||||||
|
in
|
||||||
|
if l == "nil" then r
|
||||||
|
else if r == "nil" then l
|
||||||
|
else "${l} and ${r}"
|
||||||
|
);
|
||||||
|
all = lib.foldr m.conjunction m.nil;
|
||||||
|
# Similar to `all` but takes in a list and
|
||||||
|
# treats every element as a condition.
|
||||||
|
allIndices = name: type:
|
||||||
|
m.bind name
|
||||||
|
(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:
|
||||||
|
let result = type.toLua value;
|
||||||
|
in
|
||||||
|
lib.optionalString (result != "nil")
|
||||||
|
"${helpers.mkAttrName name} = ${result}"
|
||||||
|
)
|
||||||
|
object
|
||||||
|
)
|
||||||
|
);
|
||||||
|
# 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
|
||||||
|
listChunks = lib.lists.map
|
||||||
|
(attr:
|
||||||
|
let result = spec.${attr}.toLua (attrset.${attr} or null);
|
||||||
|
in
|
||||||
|
lib.optionalString (result != "nil") result
|
||||||
|
)
|
||||||
|
listOrder;
|
||||||
|
objectChunks = lib.mapAttrsToList
|
||||||
|
(attr: type:
|
||||||
|
let result = type.toLua (attrset.${attr} or null);
|
||||||
|
in
|
||||||
|
lib.optionalString (!(lib.elem attr listOrder) && result != "nil")
|
||||||
|
"${helpers.mkAttrName attr} = ${result}"
|
||||||
|
)
|
||||||
|
spec;
|
||||||
|
in
|
||||||
|
helpers.mkRawLuaObject (listChunks ++ objectChunks)
|
||||||
|
));
|
||||||
|
withAttrsCheck = type: verify:
|
||||||
|
type.override { inherit verify; };
|
||||||
|
# }}}
|
||||||
|
};
|
||||||
|
# }}}
|
||||||
|
in
|
||||||
|
m // { inherit helpers; }
|
36
modules/common/korora-neovim.nix
Normal file
36
modules/common/korora-neovim.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
attrs@{ lib, ... }:
|
||||||
|
let
|
||||||
|
e = import ./korora-lua.nix attrs;
|
||||||
|
h = e.helpers;
|
||||||
|
m = {
|
||||||
|
lazyModule = e.withAttrsCheck
|
||||||
|
(e.attrset "lazy module" [ "package" ] {
|
||||||
|
package = e.nullOr e.string;
|
||||||
|
dir = e.nullOr e.type;
|
||||||
|
version = e.nullOr e.string;
|
||||||
|
tag = e.nullOr e.string;
|
||||||
|
name = e.nullOr e.string;
|
||||||
|
main = e.nullOr e.string;
|
||||||
|
lazy = e.nullOr e.bool;
|
||||||
|
dependencies = e.tryNonemptyList (e.stringOr m.lazyModule);
|
||||||
|
config = e.anything;
|
||||||
|
cond = e.nullOr (e.bind (value: e.all [
|
||||||
|
# TODO: we want a zip here
|
||||||
|
(e.nullOr (e.luaCode "cond"))
|
||||||
|
]));
|
||||||
|
init = e.nullOr (e.luaCode "init");
|
||||||
|
event = e.zeroOrMany e.string;
|
||||||
|
cmd = e.zeroOrMany e.string;
|
||||||
|
ft = e.zeroOrMany e.string;
|
||||||
|
keys = e.listOf e.anything;
|
||||||
|
passthrough = e.anything;
|
||||||
|
opts = e.anything;
|
||||||
|
})
|
||||||
|
(h.mkVerify [
|
||||||
|
(h.propOnlyOne [ "dir" "package" ])
|
||||||
|
(h.propImplies "tag" "package")
|
||||||
|
(h.propImplies "version" "package")
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
in
|
||||||
|
m
|
Loading…
Reference in a new issue