Huge progress on korora-based tempest generation
This commit is contained in:
parent
63d980ddf9
commit
42cd073278
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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,29 +245,46 @@ 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
|
||||||
end
|
module.keys = { module.keys }
|
||||||
|
|
||||||
if spec.keys ~= nil then
|
|
||||||
local keys = spec.keys
|
|
||||||
if spec.keys.mapping ~= nil then
|
|
||||||
keys = { keys }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, key in ipairs(keys) do
|
for _, key in ipairs(module.keys) do
|
||||||
key[1] = key.mapping
|
if type(key) ~= "string" then
|
||||||
if key.mode ~= nil then
|
key[1] = key.mapping
|
||||||
key.mode = H.string_chars(key.mode)
|
key.mapping = nil
|
||||||
|
if key.mode ~= nil then
|
||||||
|
key.mode = H.string_chars(key.mode)
|
||||||
|
end
|
||||||
|
if key.action ~= nil then
|
||||||
|
key[2] = key.action
|
||||||
|
key.action = nil
|
||||||
|
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
|
||||||
end
|
end
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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:
|
let
|
||||||
m.withDefault (m.typed type toLua) default;
|
makeFold = name: value: ''
|
||||||
unsafe = type: type // { toLua = type.unsafeToLua; };
|
-- {{{ ${name}
|
||||||
untyped = m.typed k.any;
|
${recurse value},
|
||||||
untype = type: m.untyped type.toLua;
|
-- }}}'';
|
||||||
withName = name: type: type // { inherit name; }; # TODO: should we use override here?
|
folds = lib.mapAttrsToList makeFold given.value;
|
||||||
# `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
|
in
|
||||||
if caseTrue ? default then
|
''
|
||||||
m.withDefault base caseTrue.default
|
{
|
||||||
else if caseFalse ? default then
|
${lib.concatStringsSep "\n" folds}
|
||||||
m.withDefault base caseFalse.default
|
}''
|
||||||
else
|
else if isLuaLiteral given then
|
||||||
base;
|
given.value
|
||||||
try = caseTrue: caseFalse:
|
else if lib.isAttrs given then
|
||||||
let base = m.bind
|
helpers.mkRawLuaObject
|
||||||
"${caseTrue.name} ∨ ${caseFalse.name}"
|
(lib.mapAttrsToList
|
||||||
(given: if caseTrue.verify given == null then m.unsafe caseTrue else caseFalse);
|
(name: value:
|
||||||
in
|
let result = recurse value;
|
||||||
if caseTrue ? default then
|
in
|
||||||
m.withDefault base caseTrue.default
|
lib.optionalString (result != "nil")
|
||||||
else if caseFalse ? default then
|
"${helpers.mkAttrName name} = ${result}"
|
||||||
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
|
|
||||||
)
|
)
|
||||||
);
|
given)
|
||||||
# This is the most general combinator provided in this section.
|
else if lib.isFunction given then
|
||||||
#
|
let
|
||||||
# We accept:
|
argNames = [ "context" "inner_context" "local_context" ];
|
||||||
# - order of props that should be interpreted as list elements
|
secretArg =
|
||||||
# - spec of props that should be interpreted as list elements
|
if depth >= builtins.length argNames
|
||||||
# - record of props that should be interpreted as attribute props
|
then "arg_${depth}"
|
||||||
attrset = name: listOrder: spec: attrset:
|
else builtins.elemAt argNames depth;
|
||||||
m.cmap
|
body = given secretArg;
|
||||||
(given: lib.mapAttrs
|
encoded = encodeWithDepth (depth + 1) body;
|
||||||
(key: type:
|
encodedBody =
|
||||||
if given ? ${key} then
|
if isLuaLiteral body
|
||||||
given.${key}
|
then encoded
|
||||||
else
|
else "return ${encoded}";
|
||||||
type.default or null)
|
in
|
||||||
spec)
|
if lib.hasInfix secretArg encoded
|
||||||
(m.typed (k.struct name spec) (
|
then ''
|
||||||
let
|
function(${secretArg})
|
||||||
listChunks = lib.lists.map
|
${encodedBody}
|
||||||
(attr:
|
end''
|
||||||
let result = spec.${attr}.toLua (attrset.${attr} or null);
|
else ''
|
||||||
in
|
function()
|
||||||
lib.optionalString (result != "nil") result
|
${encodedBody}
|
||||||
)
|
end''
|
||||||
listOrder;
|
else builtins.throw "Cannot encode value ${helpers.toPretty given}";
|
||||||
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; };
|
|
||||||
# }}}
|
|
||||||
};
|
|
||||||
# }}}
|
# }}}
|
||||||
|
encode = encodeWithDepth 0;
|
||||||
in
|
in
|
||||||
m // { inherit helpers; }
|
{ inherit encode helpers; }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue