From 686bdd12c4039d5fd9d6a567f652d3e9da9eb452 Mon Sep 17 00:00:00 2001
From: Matei Adriel <rafaeladriel11@gmail.com>
Date: Mon, 26 Dec 2022 20:07:10 +0100
Subject: [PATCH] Will rewrite my neovim config

---
 .lua-format                                   |   3 -
 dotfiles/neovim/.neoconf.json                 |   2 +-
 dotfiles/neovim/ftplugin/tex.lua              | 117 +++++----
 dotfiles/neovim/init.lua                      |   1 +
 dotfiles/neovim/lua/my/helpers.lua            |   2 -
 dotfiles/neovim/lua/my/keymaps.lua            |  54 ++---
 dotfiles/neovim/lua/my/options.lua            |  40 ++--
 dotfiles/neovim/lua/my/paq.lua                |  12 +
 dotfiles/neovim/lua/my/plugins/abolish.lua    | 224 +++++++++++++++++-
 dotfiles/neovim/lua/my/plugins/init.lua       |   7 +-
 dotfiles/neovim/lua/my/plugins/iron.lua       |  47 ++++
 dotfiles/neovim/lua/my/plugins/lspconfig.lua  | 123 ++++++----
 dotfiles/neovim/lua/my/plugins/moonwalk.lua   |  20 ++
 dotfiles/neovim/lua/my/plugins/neoconf.lua    |   2 +-
 dotfiles/neovim/lua/my/plugins/nerdtree.lua   |   6 +-
 dotfiles/neovim/lua/my/plugins/notify.lua     |   2 +-
 dotfiles/neovim/lua/my/plugins/null-ls.lua    |  17 +-
 dotfiles/neovim/lua/my/plugins/ufo.lua        |  18 ++
 dotfiles/neovim/tl/my/plugins/chunk.tl        |   3 +
 .../vscode-snippets/snippets/lua/core.json    |  18 ++
 modules/applications/misc.nix                 |   1 -
 modules/applications/neovim.nix               |  45 +++-
 stylua.toml                                   |   3 +
 23 files changed, 591 insertions(+), 176 deletions(-)
 create mode 100644 dotfiles/neovim/lua/my/plugins/iron.lua
 create mode 100644 dotfiles/neovim/lua/my/plugins/moonwalk.lua
 create mode 100644 dotfiles/neovim/lua/my/plugins/ufo.lua
 create mode 100644 dotfiles/neovim/tl/my/plugins/chunk.tl
 create mode 100644 stylua.toml

diff --git a/.lua-format b/.lua-format
index 53cb625..50bb10d 100644
--- a/.lua-format
+++ b/.lua-format
@@ -3,6 +3,3 @@ column_limit: 100
 keep_simple_function_one_line: false
 spaces_inside_table_braces: true
 chop_down_table: true
-# chop_down_parameter: true
-# break_after_functioncall_lp: true
-# break_before_functioncall_rp: true
diff --git a/dotfiles/neovim/.neoconf.json b/dotfiles/neovim/.neoconf.json
index 9c389ef..a0d5a68 100644
--- a/dotfiles/neovim/.neoconf.json
+++ b/dotfiles/neovim/.neoconf.json
@@ -10,7 +10,7 @@
     "library": {
       "enabled": true,
       "types": true,
-      "plugins": true,
+      "plugins": false,
       "runtime": true
     }
   }
diff --git a/dotfiles/neovim/ftplugin/tex.lua b/dotfiles/neovim/ftplugin/tex.lua
index 3698f65..5f21b10 100644
--- a/dotfiles/neovim/ftplugin/tex.lua
+++ b/dotfiles/neovim/ftplugin/tex.lua
@@ -1,5 +1,5 @@
 local A = require("my.abbreviations")
-local AB = require("my.plugins.abolish")
+local scrap = require("scrap")
 
 require("my.helpers.wrapMovement").setup()
 
@@ -42,44 +42,13 @@ local abbreviations = {
   { "gamma", "\\gamma" },
   { "lam", "\\lambda" },
   { "nuls", "\\varnothing" }, -- Other fancy symvols
-  { "ints", "\\mathbb{Z}" },
-  { "nats", "\\mathbb{N}" },
-  { "rats", "\\mathbb{Q}" },
-  { "irats", "\\mathbb{I}" },
-  { "rrea", "\\mathbb{R}" },
-  { "ppri", "\\mathbb{P}" },
-  { "ffie", "\\mathbb{F}" },
-  { "ccom", "\\mathbb{C}" }, -- Exponents
-  { "ei", "^{-1}" },
-  { "e0", "^{0}" },
-  { "e1", "^{1}" },
-  { "e2", "^{2}" },
-  { "e3", "^{3}" },
-  { "e4", "^{4}" },
-  { "en", "^{n}" },
-  { "etn", "^{-}" },
-  { "ett", "^{t}" },
-  { "tmat", "^{T}" }, -- Tranpose of a matrix
-  { "cmat", "^{*}" }, -- Conjugate of a matrix
+
+  { "tmat", "^T" }, -- Tranpose of a matrix
+  { "cmat", "^*" }, -- Conjugate of a matrix
   { "ortco", "^{\\bot}" }, -- Orthogonal complement
-  { "etp", "^{+}" }, -- Subscripts
-  { "s0", "_{0}" },
-  { "s1", "_{1}" },
-  { "s2", "_{2}" },
-  { "s3", "_{3}" },
-  { "s4", "_{4}" },
-  { "sn", "_{n}" }, -- Function calls
-  { "fx", "f(x)" },
-  { "gx", "g(x)" },
-  { "hx", "h(x)" },
-  { "Px", "P(x)" },
-  { "Pn", "P(n)" },
-  { "foa", "f(a)" },
-  { "goa", "g(a)" },
-  { "hoa", "h(a)" },
-  { "dfx", "f'(x)" },
-  { "dgx", "g'(x)" },
-  { "dhx", "h'(x)" }, -- Basic commands
+  { "sinter", "^{\\circ}" }, -- Interior of a set
+
+  -- Basic commands
   { "mangle", "\\measuredangle" },
   { "aangle", "\\angle" },
 
@@ -111,7 +80,6 @@ local abbreviations = {
   { "comp", "\\circ" },
   { "mul", "\\cdot" },
   { "smul", "\\times" },
-  { "texpl", "&& \\text{}" },
   { "card", "\\#" },
   { "div", "\\|" },
   { "ndiv", "\\not\\|\\:" },
@@ -120,29 +88,86 @@ local abbreviations = {
   { "rref", "reduced row echalon form" }
 }
 
+---@type ExpansionOptions
+local no_capitalization = { capitalized = false }
+
 -- Todo: convert exponents and subscripts
 -- to use this more concise notation.
+---@type ExpansionInput[]
 local abolishAbbreviations = {
-  { "eg{va,ve,p}{,s}", "eigen{value,vector,pair}{}" },
-  { "ib{p,s}", "integration by {parts,substitution}" },
-  { "mx{,s}", "matri{x,ces}" },
+  -- General phrases
   { "thrf", "therefore" },
-  { "dete{,s}", "determinant{}" },
   { "bcla", "by contradiction let's assume" },
+  { "wlg", "without loss of generality" },
+
+  -- Calculus
+  { "ib{p,s}", "integration by {parts,substitution}" },
+
+  -- Linear algebra
+  { "eg{va,ve,p}{,s}", "eigen{value,vector,pair}{}" },
+  { "mx{,s}", "matri{x,ces}" },
+  { "dete{,s}", "determinant{}" },
   { "ort{n,g}", "orto{normal,gonal}" },
   { "l{in,de}", "linearly {independent,dependent}" },
-  { "wlg", "without loss of generality" },
 
   -- My own operator syntax:
   --   - Any operator can be prefixed with "a" to
   --     align in aligned mode
   --   - Any operator can be prefixed with cr to
   --     start a new line and align in aligned mode
-  { "{cr,a,}{eq,neq,leq,geq,lt,gt}", "{\\\\\\&,&,}{=,\\neq,\\leq,\\geq,<,>}" }
+  {
+    "{cr,a,}{eq,neq,leq,geq,lt,gt}",
+    "{\\\\\\&,&,}{=,\\neq,\\leq,\\geq,<,>}",
+    options = no_capitalization
+  },
+
+  -- Exponents and subscripts:
+  --   {operation}{argument}
+  --   - operation = e (exponent) | s (subscript)
+  --   - argument = t{special} | {basic}
+  --   - basic = 0-9|n|i|t|k
+  --   - special =
+  --     - "p" => +
+  --     - "m" => -
+  --     - "i" => -1
+  {
+    "{e,s}{{0,1,2,3,4,5,6,7,8,9,n,i,t,k},t{i,m,p}}",
+    "{^,_}{{},{\\{-1\\},-,+}}",
+    options = no_capitalization
+  },
+
+  -- Set symbols
+  --   - nats => naturals
+  --   - ints => integers
+  --   - rats => rationals
+  --   - irats => irationals
+  --   - rrea => reals
+  --   - comp => complex
+  --   - ppri => primes
+  --   - ffie => fields
+  {
+    "{nats,ints,rats,irats,rrea,comp,ppri,ffie}",
+    "\\mathbb\\{{N,Z,Q,I,R,C,P,F}\\}",
+    options = no_capitalization
+  },
+
+  -- Function calls:
+  --   {function-name}{modifier?}{argument}
+  --
+  --   - function-name = f/g/h/P
+  --   - modifier:
+  --     - d => derivative
+  --     - 2 => squared
+  --     - 3 => cubed
+  --     - i => inverse
+  --   - argument = x/a/t/i/n/k
+  { "{f,g,h,P}{d,2,3,i,}{x,a,t,i,n,k}", "{}{',^2,^3,^\\{-1\\},}({})" }
 }
 
+local expanded = scrap.expand_many(abolishAbbreviations)
+
 A.manyLocalAbbr(abbreviations)
-AB.abolishMany(abolishAbbreviations)
+A.manyLocalAbbr(expanded)
 
 vim.keymap.set("n", "<leader>lc", "<cmd>VimtexCompile<cr>",
                { desc = "Compile current buffer using vimtex", buffer = true })
diff --git a/dotfiles/neovim/init.lua b/dotfiles/neovim/init.lua
index f5afbeb..c9874d5 100644
--- a/dotfiles/neovim/init.lua
+++ b/dotfiles/neovim/init.lua
@@ -1 +1,2 @@
+-- vim.opt.runtimepath:prepend(os.getenv("LAZY_NVIM_PATH"))
 require("my.init").setup()
diff --git a/dotfiles/neovim/lua/my/helpers.lua b/dotfiles/neovim/lua/my/helpers.lua
index 7c0b26f..e9158b5 100644
--- a/dotfiles/neovim/lua/my/helpers.lua
+++ b/dotfiles/neovim/lua/my/helpers.lua
@@ -1,7 +1,5 @@
 local M = {}
 
-function M.global(name, value) vim.g[name] = value end
-
 function M.mergeTables(t1, t2)
     local t3 = {}
 
diff --git a/dotfiles/neovim/lua/my/keymaps.lua b/dotfiles/neovim/lua/my/keymaps.lua
index 3d4926a..87c11ac 100644
--- a/dotfiles/neovim/lua/my/keymaps.lua
+++ b/dotfiles/neovim/lua/my/keymaps.lua
@@ -3,23 +3,7 @@ local arpeggio = require("my.plugins.arpeggio")
 
 local M = {}
 
-local function map(mode, lhs, rhs, opts)
-  if string.len(mode) > 1 then
-    for i = 1, #mode do
-      local c = mode:sub(i, i)
-      map(c, lhs, rhs, opts)
-    end
-  else
-    local options = helpers.mergeTables(opts, { noremap = true })
-    vim.api.nvim_set_keymap(mode, lhs, rhs, options)
-  end
-end
-
-function M.mapSilent(mode, lhs, rhs, opts)
-  local options = helpers.mergeTables(opts, { silent = true })
-  map(mode, lhs, rhs, options)
-end
-
+-- {{{ Helpers
 -- Performs a basic move operation
 function M.move(from, to, opts)
   vim.keymap.set("n", to, from, opts)
@@ -32,18 +16,17 @@ function M.delimitedTextobject(from, to, name, perhapsOpts)
   vim.keymap.set({ "v", "o" }, "i" .. from, "i" .. to, opts)
   vim.keymap.set({ "v", "o" }, "a" .. from, "a" .. to, opts)
 end
+-- }}}
 
 function M.setup()
-  -- I rarely use macro stuff
+  -- {{{ Free up q and Q
   M.move("q", "yq", { desc = "Record macro" })
   M.move("Q", "yQ")
-
-  -- Free these up for easymotion-style plugins
-  -- vim.keymap.set("n", "s", "<Nop>")
-  -- vim.keymap.set("n", "S", "<Nop>")
-
+  -- }}}
+  -- {{{ Easier access to C^
   M.move("<C-^>", "<Leader>a", { desc = "Go to previous file" })
-
+  -- }}}
+  -- {{{ Quit current buffer / all buffers
   vim.keymap.set({ "n", "v" }, "<leader>q", function()
     local buf = vim.api.nvim_win_get_buf(0)
 
@@ -54,19 +37,35 @@ function M.setup()
   end, { desc = "Quit current buffer" })
 
   vim.keymap.set("n", "Q", ":wqa<cr>", { desc = "Save all files and quit" })
+  -- }}}
+  -- {{{ Replace word in file
   vim.keymap.set("n", "<leader>rw", ":%s/<C-r><C-w>/", { desc = "Replace word in file" })
-
+  -- }}}
+  -- {{{ Text objects
   M.delimitedTextobject("q", '"', "quotes")
   M.delimitedTextobject("a", "'", "'")
   M.delimitedTextobject("r", "[", "square brackets")
+  -- }}}
+  -- {{{Diagnostic keymaps
+  do
+    local opts = function(desc)
+      return { noremap = true, silent = true, desc = desc }
+    end
 
-  -- Create chords
+    vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts("Goto previous diagnostic"))
+    vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts("Goto next diagnostic"))
+    vim.keymap.set('n', 'J', vim.diagnostic.open_float, opts("Open current diagnostic"))
+    vim.keymap.set('n', '<leader>J', vim.diagnostic.setloclist, opts("Set diagnostics loclist"))
+  end
+  -- }}}
+  -- {{{ Chords
   if arpeggio ~= nil then
     arpeggio.chordSilent("n", "ji", ":silent :write<cr>") -- Saving
     arpeggio.chord("i", "jk", "<Esc>") -- Remap Esc to jk
     arpeggio.chord("nv", "cp", "\"+") -- Press cp to use the global clipboard
   end
-
+  -- }}}
+  -- {{{ Set up which-key structure
   local status, wk = pcall(require, "which-key")
 
   if status then
@@ -80,6 +79,7 @@ function M.setup()
       }
     })
   end
+  -- }}}
 
   return M
 end
diff --git a/dotfiles/neovim/lua/my/options.lua b/dotfiles/neovim/lua/my/options.lua
index 5002b34..d01756e 100644
--- a/dotfiles/neovim/lua/my/options.lua
+++ b/dotfiles/neovim/lua/my/options.lua
@@ -3,43 +3,41 @@ local helpers = require("my.helpers")
 local M = {}
 
 function M.setup()
-  local opt = vim.opt -- to set options
-
   -- Disable filetype.vim
   vim.g.do_filetype_lua = true
   vim.g.did_load_filetypes = false
 
   -- Basic options
-  opt.joinspaces = false -- No double spaces with join
-  opt.list = true -- Show some invisible characters
-  opt.cmdheight = 0 -- Hide command line when it's not getting used
+  vim.opt.joinspaces = false -- No double spaces with join
+  vim.opt.list = true -- Show some invisible characters
+  vim.opt.cmdheight = 0 -- Hide command line when it's not getting used
 
   -- Line numbers
-  opt.number = true -- Show line numbers
-  opt.relativenumber = true -- Relative line numbers
+  vim.opt.number = true -- Show line numbers
+  vim.opt.relativenumber = true -- Relative line numbers
 
   -- TODO: only do this for specific filestypes
-  opt.expandtab = true -- Use spaces for the tab char
+  vim.opt.expandtab = true -- Use spaces for the tab char
 
-  opt.scrolloff = 4 -- Lines of context
-  opt.shiftround = true -- Round indent
-  opt.shiftwidth = 2 -- Size of an indent
-  opt.termguicolors = true -- True color support
+  vim.opt.scrolloff = 4 -- Lines of context
+  vim.opt.shiftround = true -- Round indent
+  vim.opt.shiftwidth = 2 -- Size of an indent
+  vim.opt.termguicolors = true -- True color support
 
-  opt.ignorecase = true -- Ignore case
-  opt.smartcase = true -- Do not ignore case with capitals
+  vim.opt.ignorecase = true -- Ignore case
+  vim.opt.smartcase = true -- Do not ignore case with capitals
 
-  opt.smartindent = true -- Insert indents automatically
+  vim.opt.smartindent = true -- Insert indents automatically
 
-  opt.splitbelow = true -- Put new windows below current
-  opt.splitright = true -- Put new windows right of current
+  vim.opt.splitbelow = true -- Put new windows below current
+  vim.opt.splitright = true -- Put new windows right of current
 
-  opt.wrap = false -- Disable line wrap (by default)
-  opt.wildmode = { 'list', 'longest' } -- Command-line completion mode
-  opt.completeopt = { "menu", "menuone", "noselect" }
+  vim.opt.wrap = false -- Disable line wrap (by default)
+  vim.opt.wildmode = { 'list', 'longest' } -- Command-line completion mode
+  vim.opt.completeopt = { "menu", "menuone", "noselect" }
 
   -- Set leader
-  helpers.global("mapleader", " ")
+  vim.g.mapleader = " "
 
   -- Import other options
   require("my.options.folding").setup()
diff --git a/dotfiles/neovim/lua/my/paq.lua b/dotfiles/neovim/lua/my/paq.lua
index 61995a3..37e4258 100644
--- a/dotfiles/neovim/lua/my/paq.lua
+++ b/dotfiles/neovim/lua/my/paq.lua
@@ -66,6 +66,18 @@ function M.setup()
     "akinsho/toggleterm.nvim", -- cool terminal thingy
     "folke/noice.nvim", -- better ui for cmd line and other stuff
     "rcarriga/nvim-notify", -- better notifiaction ui
+    "hkupty/iron.nvim", -- repl support
+    "0styx0/abbremand.nvim", -- dependency for the next thing
+    "0styx0/abbreinder.nvim", -- reminds you of abbreviations
+    "ellisonleao/glow.nvim", -- md preview (in terminal)
+    "frabjous/knap", -- md preview
+    "tpope/vim-sleuth", -- automatically set options based on current file
+    "mateiadrielrafael/scrap.nvim", -- vim-abolish rewrite
+    "kevinhwang91/promise-async", -- required by nvim-ufo
+    "kevinhwang91/nvim-ufo", -- better folds and stuff
+    "ThePrimeagen/refactoring.nvim", -- refactoring
+    "gpanders/nvim-moonwalk", -- configure nvim in any language which compiles to lua
+    "teal-language/vim-teal", -- teal language support
 
     -- Git stuff
     "ruifm/gitlinker.nvim", -- generate permalinks for code
diff --git a/dotfiles/neovim/lua/my/plugins/abolish.lua b/dotfiles/neovim/lua/my/plugins/abolish.lua
index 0e34836..bb1ffbb 100644
--- a/dotfiles/neovim/lua/my/plugins/abolish.lua
+++ b/dotfiles/neovim/lua/my/plugins/abolish.lua
@@ -1,13 +1,227 @@
+local A = require("my.abbreviations")
+
 local M = {}
 
-function M.abolish(from, to)
-  vim.cmd(":Abolish " .. from .. " " .. to)
+-- function M.abolish(from, to)
+--   vim.cmd(":Abolish -buffer " .. from .. " " .. to)
+-- end
+--
+-- function M.abolishMany(many)
+--   for _, entry in pairs(many) do M.abolish(entry[1], entry[2]) end
+-- end
+
+local function concatTables(t1, t2)
+  assert(type(t1) == "table")
+  assert(type(t2) == "table")
+
+  local t3 = {}
+  for i = 1, #t1 do t3[#t3 + 1] = t1[i] end
+  for i = 1, #t2 do t3[#t3 + 1] = t2[i] end
+  return t3
 end
 
-function M.abolishMany(many)
-  for _, entry in pairs(many) do
-    M.abolish(entry[1], entry[2])
+local function betterAbolish(unprocessed, context, out)
+  local from = unprocessed[1] or {}
+  local to = unprocessed[2] or {}
+
+  assert(type(from) == "table" and type(to) == "table",
+         "Both arguments should be tables. Found " .. vim.inspect(from) .. " and " ..
+             vim.inspect(to) .. " instead.")
+
+  -- print(vim.inspect({ context = context, unprocessed = unprocessed }))
+
+  if #from == 0 and #to == 0 then
+    table.insert(out, context)
+    return
+  end
+
+  for i = 1, 2, 1 do
+    local head = unprocessed[i][1]
+    if type(head) == "string" then
+      local context_clone = { context[1], context[2] }
+
+      context_clone[i] = context_clone[i] .. head
+
+      local unprocessed_clone = { unprocessed[1], unprocessed[2] }
+      unprocessed_clone[i] = { unpack(unprocessed[i], 2) }
+
+      return betterAbolish(unprocessed_clone, context_clone, out)
+    end
+  end
+
+  -- print(vim.inspect({ from, to, context }))
+
+  assert(type(from[1]) == "table", vim.inspect(from) .. " starts with neither a table nor a string")
+  assert(type(to[1]) == "table", vim.inspect(to) .. " does not start with a table")
+
+  for i = 1, #from[1], 1 do
+    local when = from[1][i]
+    local replacement = when
+
+    if #to[1] > 0 then replacement = to[1][((i - 1) % #to[1]) + 1] end
+
+    assert(type(when) == "table")
+    assert(type(replacement) == "table")
+
+    local unprocessed_clone = {
+      concatTables(when, { unpack(from, 2) }),
+      concatTables(replacement, { unpack(to, 2) })
+    }
+
+    -- print(vim.inspect({
+    --   unprocessed_clone = unprocessed_clone,
+    --   when = when,
+    --   replacement = replacement,
+    --   from = from,
+    --   to = to,
+    --   i = i
+    -- }))
+
+    betterAbolish(unprocessed_clone, context, out)
   end
 end
 
+function M.betterAbolish(from, to)
+  local result = {}
+  betterAbolish({ from, to }, { "", "" }, result)
+
+  return result
+end
+
+local function withCasing(input)
+  local out = {}
+
+  for i = 1, #input, 1 do
+    local from = input[i][1]
+    local to = input[i][2]
+
+    table.insert(out, { from, to })
+    table.insert(out, { string.upper(from), string.upper(to) })
+
+    if #from and #to then
+      table.insert(out, {
+        string.upper(string.sub(from, 1, 1)) .. string.sub(from, 2),
+        string.upper(string.sub(to, 1, 1)) .. string.sub(to, 2)
+      })
+    end
+  end
+
+  return out
+end
+
+---Parses the input for this plugin
+---@param input string
+---@param context {delimiters:{left:string,right:string},separator:string}
+---@return nil|{positio:number,message:string}
+---@return (string|table)[]|nil
+local function parse(input, context)
+  local position = 1
+  ---@type { start:number, contents:(string|table)[] }[]
+  local stack = { { start = position, contents = {} } }
+
+  local function error(message, pos)
+    return { position = pos or position, message = message }
+  end
+
+  local escaped = false
+  local escapedChars = {
+    ["\\"] = true,
+    [context.delimiters.left] = true,
+    [context.delimiters.right] = true
+  }
+
+  -- When encountering {}, instead of treating it like a single
+  -- choice containing an empty string, we must treat it as an empty choice
+  --
+  -- The specialEmpty arg tells us whether to consider such cases.
+  local function saveUp(specialEmpty)
+    local prev = stack[#stack - 1].contents
+    local current = stack[#stack]
+
+    assert(type(prev[#prev]) == "table")
+    ---@cast prev table
+
+    -- If specialEmpty is true (so we are processing a '}'),
+    -- we only want to keep empty strings (so those where #current.contents == 0)
+    -- if we've had a , before (so #prev[#prev] > 0)
+    if not specialEmpty or #current.contents > 0 or #prev[#prev] > 0 then
+      table.insert(prev[#prev], current.contents)
+    end
+  end
+
+  while position <= string.len(input) do
+    local first = string.sub(input, position, position)
+    local next = string.sub(input, position + 1, position + 1)
+    local current = stack[#stack]
+
+    if not escaped and first == "\\" and escapedChars[next] then
+      escaped = true
+
+    elseif not escaped and first == context.delimiters.left then
+      table.insert(current.contents, {})
+      stack[#stack + 1] = { start = position, contents = {} }
+    elseif not escaped and first == context.delimiters.right then
+      if #stack == 1 then
+        return nil, error("Delimiter " .. context.delimiters.right .. " never opened")
+      end
+
+      -- we want special treatment for {}
+      saveUp(true)
+
+      stack[#stack] = nil
+    elseif not escaped and first == context.separator and #stack > 1 then
+      -- we want to treat empty strings before , as empty strings
+      saveUp(false)
+
+      current.contents = {}
+    else
+      local last = current.contents[#current.contents]
+
+      if type(last) == "string" then
+        current.contents[#current.contents] = last .. first
+      else
+        table.insert(current.contents, first)
+      end
+
+      escaped = false
+    end
+
+    position = position + 1
+  end
+
+  if #stack > 1 then
+    return nil, error("Delimiter " .. context.delimiters.left .. " never closed", stack[2].start)
+  end
+
+  return stack[1].contents, nil
+end
+
+local context = { delimiters = { left = "{", right = "}" }, separator = "," }
+
+function M.abolishMany(many)
+  local total = 0
+
+  for _, entry in pairs(many) do
+    local left = parse(entry[1], context)
+    local right = parse(entry[2], context)
+
+    local abbreviations = withCasing(M.betterAbolish(left, right))
+    total = total + #abbreviations
+
+    A.manyLocalAbbr(abbreviations)
+  end
+
+  print("Added " .. total .. " abbreviations")
+end
+
+-- function M.setup()
+--   local context = { delimiters = { left = "{", right = "}" }, separator = "," }
+--   print(vim.inspect({ parse("abc\\d{a, d,e}dsdf\\{sdf\\}", context) }))
+--   local parsed, _ = parse("ab{e,{f0,1e,d2},f,{3,4,5},\\{{000,111}\\}}cd", context)
+--   -- local parsed, _ = parse("abc", context)
+--   print(vim.inspect(parsed))
+--   local processed = M.betterAbolish(parsed, parsed)
+--   print(vim.inspect(processed))
+-- end
+
 return M
diff --git a/dotfiles/neovim/lua/my/plugins/init.lua b/dotfiles/neovim/lua/my/plugins/init.lua
index cdd7a6b..54c6797 100644
--- a/dotfiles/neovim/lua/my/plugins/init.lua
+++ b/dotfiles/neovim/lua/my/plugins/init.lua
@@ -2,9 +2,12 @@ local env = require("my.helpers.env")
 local M = {}
 
 function M.setup()
+  require("my.plugins.moonwalk").setup()
+  require("my.plugins.chunk")
   require('nvim_comment').setup()
   require('fidget').setup()
   require('dressing').setup()
+  require('abbreinder').setup()
 
   require("my.plugins.autopairs").setup()
   require("my.plugins.telescope").setup()
@@ -34,7 +37,8 @@ function M.setup()
     require("my.plugins.null-ls").setup()
     require("my.plugins.vimtex").setup()
     -- require("my.plugins.lean").setup()
-    -- require("my.plugins.notify").setup()
+    require("my.plugins.notify").setup()
+    require("my.plugins.iron").setup()
   end)
 
   if env.neovide.active() then
@@ -55,6 +59,7 @@ function M.setup()
   require("my.plugins.hydra").setup()
   require("my.plugins.clipboard-image").setup()
   require("my.plugins.mind").setup()
+  require("my.plugins.ufo").setup()
 
   -- require("my.plugins.slam").setup()
 end
diff --git a/dotfiles/neovim/lua/my/plugins/iron.lua b/dotfiles/neovim/lua/my/plugins/iron.lua
new file mode 100644
index 0000000..0692811
--- /dev/null
+++ b/dotfiles/neovim/lua/my/plugins/iron.lua
@@ -0,0 +1,47 @@
+local M = {}
+
+function M.setup()
+  local iron = require("iron.core")
+
+  iron.setup {
+    config = {
+      -- Your repl definitions come here
+      repl_definition = {},
+      -- How the repl window will be displayed
+      -- See below for more information
+      repl_open_cmd = require('iron.view').right(40)
+    },
+    -- Iron doesn't set keymaps by default anymore.
+    -- You can set them here or manually add keymaps to the functions in iron.core
+    keymaps = {
+      send_motion = "<space>isc",
+      visual_send = "<space>is",
+      send_file = "<space>isf",
+      send_line = "<space>isl",
+      send_mark = "<space>ism",
+      mark_motion = "<space>imc",
+      mark_visual = "<space>imc",
+      remove_mark = "<space>imd",
+      cr = "<space>is<cr>",
+      interrupt = "<space>is<space>",
+      exit = "<space>isq",
+      clear = "<space>isr"
+    },
+    -- If the highlight is on, you can change how it looks
+    -- For the available options, check nvim_set_hl
+    highlight = { italic = true },
+    ignore_blank_lines = true -- ignore blank lines when sending visual select lines
+  }
+
+  -- iron also has a list of commands, see :h iron-commands for all available commands
+  vim.keymap.set('n', '<space>iss', '<cmd>IronRepl<cr>')
+  vim.keymap.set('n', '<space>ir', '<cmd>IronRestart<cr>')
+  vim.keymap.set('n', '<space>if', '<cmd>IronFocus<cr>')
+  vim.keymap.set('n', '<space>ih', '<cmd>IronHide<cr>')
+
+  local status, wk = pcall(require, "which-key")
+
+  if status then wk.register({ ["<leader>i"] = { name = "Iron repl commands" } }) end
+end
+
+return M
diff --git a/dotfiles/neovim/lua/my/plugins/lspconfig.lua b/dotfiles/neovim/lua/my/plugins/lspconfig.lua
index ad1fa8c..f799ad0 100644
--- a/dotfiles/neovim/lua/my/plugins/lspconfig.lua
+++ b/dotfiles/neovim/lua/my/plugins/lspconfig.lua
@@ -1,41 +1,68 @@
 local M = {}
 
 function M.on_attach(client, bufnr)
-  -- Enable completion triggered by <c-x><c-o>
-  vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
-
-  if client.server_capabilities.documentFormattingProvider then
-    vim.api.nvim_create_autocmd("BufWritePre", {
-      group = vim.api.nvim_create_augroup("LspFormatting", {}),
-      buffer = bufnr,
-      callback = function()
-        vim.lsp.buf.format({ async = false })
-      end
-    })
+  -- {{{ Auto format
+  local function format()
+    vim.lsp.buf.format({ async = false, bufnr = bufnr })
   end
 
+  if false and client.supports_method("textDocument/formatting") then
+    vim.api.nvim_create_autocmd("BufWritePre", {
+      group = vim.api.nvim_create_augroup("LspFormatting", { clear = false }),
+      buffer = bufnr,
+      callback = format,
+    })
+  end
+  -- }}}
+  -- {{{ Keymap helpers
   local opts = function(desc)
     return { noremap = true, silent = true, desc = desc }
   end
 
-  -- Go to declaration / definition / implementation
-  vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts("Go to declaration"))
-  vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts("Go to definition"))
-  vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts("Go to implementation"))
-  vim.keymap.set("n", "gr", vim.lsp.buf.references, opts("Go to references"))
+  local nmap = function(from, to, desc)
+    vim.keymap.set("n", from, to, opts(desc))
+  end
+  -- }}}
+  -- {{{ Go to declaration / definition / implementation
+  nmap("gd", vim.lsp.buf.definition, "[G]o to [d]efinition")
+  nmap("gi", vim.lsp.buf.implementation, "[G]o to [i]mplementation")
+  nmap("gr", vim.lsp.buf.references, "[G]o to [r]eferences")
+  -- }}}
+  -- {{{ Hover
+  -- Note: diagnostics are already covered in keymaps.lua
+  nmap("K", vim.lsp.buf.hover, "Hover")
+  nmap("L", vim.lsp.buf.signature_help, "Signature help")
+  -- }}}
+  -- {{{ Code actions
+  nmap("<leader>rn", vim.lsp.buf.rename, "[R]e[n]ame")
+  nmap("<leader>f", format, "[F]ormat")
+  nmap("<leader>c", vim.lsp.buf.code_action, "[C]ode actions")
 
-  -- Hover
-  vim.keymap.set("n", "J", vim.diagnostic.open_float, opts("Show diagnostic"))
-  vim.keymap.set("n", "K", vim.lsp.buf.hover, opts("Hover"))
-  vim.keymap.set("n", "L", vim.lsp.buf.signature_help, opts("Signature help"))
-
-  -- Code actions
-  vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts("Rename"))
-  vim.keymap.set("n", "<leader>c", vim.lsp.buf.code_action, opts("Code actions"))
-  vim.keymap.set("n", "<leader>f", vim.lsp.buf.format, opts("Format"))
+  vim.keymap.set(
+    "v",
+    "<leader>c",
+    ":'<,'> lua vim.lsp.buf.range_code_action()",
+    opts("[C]ode actions")
+  )
+  -- }}}
+  -- {{{ Workspace stuff
+  nmap(
+    "<leader>wa",
+    vim.lsp.buf.add_workspace_folder,
+    "[W]orkspace [A]dd Folder"
+  )
+  nmap(
+    "<leader>wr",
+    vim.lsp.buf.remove_workspace_folder,
+    "[W]orkspace [R]emove Folder"
+  )
+  nmap("<leader>wl", function()
+    print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
+  end, "[W]orkspace [L]ist Folders")
+  -- }}}
 end
 
--- General server config
+-- {{{ General server config
 ---@type lspconfig.options
 local servers = {
   tsserver = {
@@ -43,39 +70,51 @@ local servers = {
       -- We handle formatting using null-ls and prettierd
       client.server_capabilities.documentFormattingProvider = false
       M.on_attach(client, bufnr)
-    end
+    end,
   },
   dhall_lsp_server = {},
   purescriptls = {
     settings = {
       purescript = {
         censorWarnings = { "UnusedName", "ShadowedName", "UserDefinedWarning" },
-        formatter = "purs-tidy"
-      }
-    }
+        formatter = "purs-tidy",
+      },
+    },
   },
   hls = {
     haskell = {
       -- set formatter
-      formattingProvider = "ormolu"
-    }
+      formattingProvider = "ormolu",
+    },
   },
   rnix = {},
   cssls = {},
   jsonls = {},
   rust_analyzer = {},
+  -- teal_ls = {},
   sumneko_lua = {
-    cmd = { "lua-language-server", "--logpath=/home/adrielus/.local/share/lua-language-server/log" }
-  }
+    cmd = {
+      "lua-language-server",
+      "--logpath=/home/adrielus/.local/share/lua-language-server/log",
+    },
+  },
 }
+-- }}}
 
-M.capabilities = require('cmp_nvim_lsp').default_capabilities()
+-- {{{ Capabilities
+M.capabilities = require("cmp_nvim_lsp").default_capabilities()
+-- Add folding capabilities
+M.capabilities.textDocument.foldingRange =
+  { dynamicRegistration = false, lineFoldingOnly = true }
+-- }}}
 
 function M.setup()
-  vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover,
-                                                        { border = "single" })
+  -- {{{ Change on-hover borders
+  vim.lsp.handlers["textDocument/hover"] =
+    vim.lsp.with(vim.lsp.handlers.hover, { border = "single" })
   vim.lsp.handlers["textDocument/signatureHelp"] =
-      vim.lsp.with(vim.lsp.handlers.signature_help, { border = "single" })
+    vim.lsp.with(vim.lsp.handlers.signature_help, { border = "single" })
+  -- }}}
 
   -- Setup basic language servers
   for lsp, details in pairs(servers) do
@@ -84,15 +123,15 @@ function M.setup()
       details.on_attach = M.on_attach
     end
 
-    require('lspconfig')[lsp].setup {
+    require("lspconfig")[lsp].setup({
       on_attach = details.on_attach,
       settings = details.settings, -- Specific per-language settings
       flags = {
-        debounce_text_changes = 150 -- This will be the default in neovim 0.7+
+        debounce_text_changes = 150, -- This will be the default in neovim 0.7+
       },
       cmd = details.cmd,
-      capabilities = M.capabilities
-    }
+      capabilities = M.capabilities,
+    })
   end
 end
 
diff --git a/dotfiles/neovim/lua/my/plugins/moonwalk.lua b/dotfiles/neovim/lua/my/plugins/moonwalk.lua
new file mode 100644
index 0000000..fb7bfae
--- /dev/null
+++ b/dotfiles/neovim/lua/my/plugins/moonwalk.lua
@@ -0,0 +1,20 @@
+local M = {}
+
+function M.setup()
+  require("moonwalk").add_loader("tl", function(src, path)
+    local tl = require("tl")
+    local errs = {}
+    local _, program = tl.parse_program(tl.lex(src), errs)
+
+    if #errs > 0 then
+      error(
+        path .. ":" .. errs[1].y .. ":" .. errs[1].x .. ": " .. errs[1].msg,
+        0
+      )
+    end
+
+    return tl.pretty_print_ast(program)
+  end)
+end
+
+return M
diff --git a/dotfiles/neovim/lua/my/plugins/neoconf.lua b/dotfiles/neovim/lua/my/plugins/neoconf.lua
index 5e32a04..d60e604 100644
--- a/dotfiles/neovim/lua/my/plugins/neoconf.lua
+++ b/dotfiles/neovim/lua/my/plugins/neoconf.lua
@@ -2,7 +2,7 @@ local M = {}
 
 function M.setup()
   require("neoconf").setup({
-    -- import existing settinsg from other plugins
+    -- import existing settings from other plugins
     import = {
       vscode = true, -- local .vscode/settings.json
       coc = false, -- global/local coc-settings.json
diff --git a/dotfiles/neovim/lua/my/plugins/nerdtree.lua b/dotfiles/neovim/lua/my/plugins/nerdtree.lua
index 5bcd3f2..5181b76 100644
--- a/dotfiles/neovim/lua/my/plugins/nerdtree.lua
+++ b/dotfiles/neovim/lua/my/plugins/nerdtree.lua
@@ -1,10 +1,8 @@
-local mapSilent = require("my.keymaps").mapSilent
-
 local M = {}
 
 function M.setup()
-    -- Toggle nerdtree with Control-t
-    mapSilent("n", "<C-t>", ":NERDTreeToggle<CR>")
+  -- Toggle nerdtree with Control-t
+  vim.keymaps.set("n", "<C-t>", ":NERDTreeToggle<CR>", { silent = true })
 end
 
 return M
diff --git a/dotfiles/neovim/lua/my/plugins/notify.lua b/dotfiles/neovim/lua/my/plugins/notify.lua
index 292485c..d5c84e0 100644
--- a/dotfiles/neovim/lua/my/plugins/notify.lua
+++ b/dotfiles/neovim/lua/my/plugins/notify.lua
@@ -1,7 +1,7 @@
 local M = {}
 
 function M.setup()
-  vim.notify = require("notify")
+  -- vim.notify = require("notify")
 end
 
 return M
diff --git a/dotfiles/neovim/lua/my/plugins/null-ls.lua b/dotfiles/neovim/lua/my/plugins/null-ls.lua
index b63f7c4..19ebd4d 100644
--- a/dotfiles/neovim/lua/my/plugins/null-ls.lua
+++ b/dotfiles/neovim/lua/my/plugins/null-ls.lua
@@ -4,23 +4,20 @@ local M = {}
 
 function M.setup()
   local null_ls = require("null-ls")
+  -- require("refactoring").setup({})
 
   local sources = {
-    -- null_ls.builtins.formatting.prettierd.with({extra_filetypes = {}}), -- format ts files
-
-    null_ls.builtins.formatting.prettier.with({ extra_filetypes = {} }), -- format ts files
-    null_ls.builtins.formatting.lua_format.with({
-      -- extra_args = function(params)
-      --   return params.options and params.options.tabSize and
-      --              { "--indent-width=" .. params.options.tabSize }
-      -- end
-    }) -- format lua code
+    -- null_ls.builtins.formatting.prettier.with({ extra_filetypes = {} }), -- format ts files
+    null_ls.builtins.formatting.prettierd.with({ extra_filetypes = {} }), -- format ts files
+    -- null_ls.builtins.formatting.lua_format.with({}), -- format lua code
+    null_ls.builtins.formatting.stylua.with({}), -- format lua code
+    -- null_ls.builtins.code_actions.refactoring.with({}), -- refactor stuff
   }
 
   null_ls.setup({
     sources = sources,
     on_attach = lspconfig.on_attach,
-    debug = true
+    debug = true,
   })
 end
 
diff --git a/dotfiles/neovim/lua/my/plugins/ufo.lua b/dotfiles/neovim/lua/my/plugins/ufo.lua
new file mode 100644
index 0000000..d067bd5
--- /dev/null
+++ b/dotfiles/neovim/lua/my/plugins/ufo.lua
@@ -0,0 +1,18 @@
+local M = {}
+
+function M.setup()
+  vim.o.foldcolumn = '0'
+  vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value
+  vim.o.foldlevelstart = 99
+  vim.o.foldenable = true
+
+  -- Using ufo provider need remap `zR` and `zM`.
+  -- vim.keymap.set('n', 'zR', require('ufo').openAllFolds)
+  -- vim.keymap.set('n', 'zM', require('ufo').closeAllFolds)
+
+  -- Tell the server the capability of foldingRange,
+  -- Neovim hasn't added foldingRange to default capabilities, users must add it manually
+  -- require('ufo').setup()
+end
+
+return M
diff --git a/dotfiles/neovim/tl/my/plugins/chunk.tl b/dotfiles/neovim/tl/my/plugins/chunk.tl
new file mode 100644
index 0000000..20b638e
--- /dev/null
+++ b/dotfiles/neovim/tl/my/plugins/chunk.tl
@@ -0,0 +1,3 @@
+function hi()
+  print("Hello world!")
+end
diff --git a/dotfiles/vscode-snippets/snippets/lua/core.json b/dotfiles/vscode-snippets/snippets/lua/core.json
index b14c2f6..ab3c56f 100644
--- a/dotfiles/vscode-snippets/snippets/lua/core.json
+++ b/dotfiles/vscode-snippets/snippets/lua/core.json
@@ -11,5 +11,23 @@
       "",
       "return M"
     ]
+  },
+  "Busted describe": {
+    "prefix": "describe",
+    "description": "Create a describe call for a busted test",
+    "body": [
+      "describe(\"$1\", function ()",
+      "\t$0",
+      "end)"
+    ]
+  },
+  "Busted it": {
+    "prefix": "it",
+    "description": "Create an it call for a busted test",
+    "body": [
+      "it(\"$1\", function ()",
+      "\t$0",
+      "end)"
+    ]
   }
 }
diff --git a/modules/applications/misc.nix b/modules/applications/misc.nix
index 6e9758d..0003002 100644
--- a/modules/applications/misc.nix
+++ b/modules/applications/misc.nix
@@ -40,7 +40,6 @@
     # vim
     # emacs
     vimclip # use neovim anywhere
-    neovide # neovim ui!
 
     # chat apps
     # slack
diff --git a/modules/applications/neovim.nix b/modules/applications/neovim.nix
index c9d35a8..5b2e60c 100644
--- a/modules/applications/neovim.nix
+++ b/modules/applications/neovim.nix
@@ -3,8 +3,22 @@ let
   paq = pkgs.fetchFromGitHub {
     owner = "savq";
     repo = "paq-nvim";
-    rev = "bc5950b990729464f2493b1eaab5a7721bd40bf5";
-    sha256 = "0rsv3j5rxfv7ys9zvq775f63vy6w880b0xhyr164y8fcadhpypb3";
+    rev = "0ed94d59e315e066ced3f453ff00c0ae94938f1e";
+    sha256 = "0dsq6cjm7jm7jh9dfxym4ipkp46fvw1lr9z98zd80im18rg4fg63";
+  };
+
+  teal = pkgs.fetchFromGitHub {
+    owner = "teal-language";
+    repo = "tl";
+    rev = "526fe3640fe6265706541c251e984c033a1a5ec9";
+    sha256 = "0l31qj492iaiadpp4s0wflfb7vn6zzxwhbiyczisdgpd9ydj20gf";
+  };
+
+  lazy-nvim = pkgs.fetchFromGitHub {
+    owner = "folke";
+    repo = "lazy.nvim";
+    rev = "511524ebff27ed8dea9e8d2eadb26ef19fb322c7";
+    sha256 = "0c8hfhrj2rfkpff0kwiv5g5bpvdq36b4xzsi8199jrpfvvp79302";
   };
 
   theme = pkgs.myThemes.current;
@@ -18,13 +32,14 @@ let
     haskell-language-server # haskell
     tectonic # also latex something?
     texlab # latex
-    # vscode-langservers-extracted # css and shit
+    nodePackages_latest.vscode-langservers-extracted
 
     # Formatters
     luaformatter # lua
+    stylua # lua
     ormolu # haskell
     easy-purescript-nix.purs-tidy
-    # prettierd # prettier but faster
+    nodePackages_latest.prettier_d_slim
 
     # Others
     nodePackages.typescript # typescript
@@ -36,34 +51,41 @@ let
     libstdcxx5 # required by treesitter aparently
     zathura # pdf reader
     xdotool # for zathura reverse search or whatever it's called
+    lua # for repls and whatnot
+    glow # md preview in terminal
+    pandoc # md processing
+    libsForQt5.falkon # aparently needed for md preview
+    luajitPackages.luarocks # lua package manager
 
     texlive.combined.scheme-full # latex stuff
     python38Packages.pygments # required for latex syntax highlighting
   ];
 
 
-  base = pkgs.neovim-nightly;
-  # base = pkgs.neovim;
-
-  neovim =
+  wrapClient = { base, name }:
     pkgs.symlinkJoin {
       inherit (base) name meta;
       paths = [ base ];
       nativeBuildInputs = [ pkgs.makeWrapper ];
       postBuild = ''
-        wrapProgram $out/bin/nvim \
-          --prefix PATH : ${lib.makeBinPath extraPackages}
+        wrapProgram $out/bin/${name} \
+          --prefix PATH : ${lib.makeBinPath extraPackages} \
+          --set LAZY_NVIM_PATH ${lazy-nvim} 
       '';
     };
 
+  neovim = wrapClient { base = pkgs.neovim-nightly; name = "nvim"; };
+  neovide = wrapClient { base = pkgs.neovide; name = "neovide"; };
+
   nixPlugins = ".local/share/nvim/site/pack/nix";
 in
 {
   home-manager.users.adrielus = { config, ... }:
     let simlink = config.lib.file.mkOutOfStoreSymlink; in
     {
-      home.file.".local/share/nvim/site/pack/paqs/start/paq-nvim".source = paq;
+      home.file."${nixPlugins}/start/paq-nvim".source = paq;
       home.file."${nixPlugins}/start/theming/lua/my/theme.lua".source = theme.neovim.theme;
+      home.file."${nixPlugins}/start/teal/lua".source = teal; # teal (typed lua)
       home.file."${nixPlugins}/start/snippets".source = simlink "${paths.dotfiles}/vscode-snippets";
       home.file.".config/nvim".source = simlink "${paths.dotfiles}/neovim";
 
@@ -71,6 +93,7 @@ in
 
       home.packages = [
         neovim
+        neovide
       ];
     };
 }
diff --git a/stylua.toml b/stylua.toml
new file mode 100644
index 0000000..03d2f90
--- /dev/null
+++ b/stylua.toml
@@ -0,0 +1,3 @@
+column_width = 80
+indent_width = 2
+indent_type = "Spaces"