diff --git a/lua/plugins/edgy-nvim.lua b/lua/plugins/edgy-nvim.lua
new file mode 100644
index 0000000..9b39f5a
--- /dev/null
+++ b/lua/plugins/edgy-nvim.lua
@@ -0,0 +1,129 @@
+return {
+  {
+    'folke/edgy.nvim',
+    opts = function()
+      local opts = {
+        bottom = {
+          {
+            ft = 'toggleterm',
+            size = { height = 0.4 },
+            filter = function(_, win)
+              return vim.api.nvim_win_get_config(win).relative == ''
+            end,
+          },
+          {
+            ft = 'noice',
+            size = { height = 0.4 },
+            filter = function(_, win)
+              return vim.api.nvim_win_get_config(win).relative == ''
+            end,
+          },
+          'Trouble',
+          { ft = 'qf', title = 'QuickFix' },
+          { title = 'Spectre', ft = 'spectre_panel', size = { height = 0.4 } },
+          {
+            title = 'Neotest Output',
+            ft = 'neotest-output-panel',
+            size = { height = 15 },
+          },
+        },
+        left = {
+          { title = 'Neotest Summary', ft = 'neotest-summary' },
+          -- "neo-tree",
+        },
+        right = {
+          { title = 'Grug Far', ft = 'grug-far', size = { width = 0.4 } },
+          {
+            ft = 'help',
+            size = { width = 0.4 },
+            -- don't open help files in edgy that we're editing
+            filter = function(buf)
+              return vim.bo[buf].buftype == 'help'
+            end,
+          },
+        },
+        keys = {
+          -- increase width
+          ['<c-Right>'] = function(win)
+            win:resize('width', 2)
+          end,
+          -- decrease width
+          ['<c-Left>'] = function(win)
+            win:resize('width', -2)
+          end,
+          -- increase height
+          ['<c-Up>'] = function(win)
+            win:resize('height', 2)
+          end,
+          -- decrease height
+          ['<c-Down>'] = function(win)
+            win:resize('height', -2)
+          end,
+        },
+      }
+
+      if LazyVim.has('neo-tree.nvim') then
+        local pos = {
+          filesystem = 'left',
+          buffers = 'top',
+          git_status = 'right',
+          document_symbols = 'bottom',
+          diagnostics = 'bottom',
+        }
+        local sources = LazyVim.opts('neo-tree.nvim').sources or {}
+        for i, v in ipairs(sources) do
+          table.insert(opts.left, i, {
+            title = 'Neo-Tree ' .. v:gsub('_', ' '):gsub('^%l', string.upper),
+            ft = 'neo-tree',
+            filter = function(buf)
+              return vim.b[buf].neo_tree_source == v
+            end,
+            pinned = true,
+            open = function()
+              vim.cmd(
+                ('Neotree show position=%s %s dir=%s'):format(
+                  pos[v] or 'bottom',
+                  v,
+                  LazyVim.root()
+                )
+              )
+            end,
+          })
+        end
+      end
+
+      -- trouble
+      for _, pos in ipairs({ 'top', 'bottom', 'left', 'right' }) do
+        opts[pos] = opts[pos] or {}
+        table.insert(opts[pos], {
+          ft = 'trouble',
+          filter = function(_, win)
+            return vim.w[win].trouble
+              and vim.w[win].trouble.position == pos
+              and vim.w[win].trouble.type == 'split'
+              and vim.w[win].trouble.relative == 'editor'
+              and not vim.w[win].trouble_preview
+          end,
+        })
+      end
+
+      -- snacks terminal
+      for _, pos in ipairs({ 'top', 'bottom', 'left', 'right' }) do
+        opts[pos] = opts[pos] or {}
+        table.insert(opts[pos], {
+          ft = 'snacks_terminal',
+          size = { height = 0.3 },
+          title = '%{b:snacks_terminal.id}: %{b:term_title}',
+          filter = function(_, win)
+            return vim.w[win].snacks_win
+              and vim.w[win].snacks_win.position == pos
+              and vim.w[win].snacks_win.relative == 'editor'
+              and not vim.w[win].trouble_preview
+          end,
+        })
+      end
+
+      return opts
+    end,
+  },
+}
diff --git a/lua/plugins/treesj.lua b/lua/plugins/treesj.lua
index e37171f..e1b33e6 100644
--- a/lua/plugins/treesj.lua
+++ b/lua/plugins/treesj.lua
@@ -1,10 +1,34 @@
 return {
   {
     'Wansmer/treesj',
-    keys = { '<SPACE>m', '<SPACE>j', '<SPACE>s' },
+    keys = {
+      { '<SPACE>m', require('treesj').toggle, desc = 'toggle join/split' },
+      { '<SPACE>j', require('treesj').join, desc = 'join code block' },
+      { '<SPACE>p', require('treesj').split, desc = 'split code block' },
+    },
     dependencies = { 'nvim-treesitter/nvim-treesitter' },
     opts = {
+      use_default_keymaps = false,
       max_join_length = vim.o.textwidth,
     },
   },
+
+  -- Remap key so it doesn't conflict with treesj.
+  {
+    'gbprod/yanky.nvim',
+    keys = {
+      {
+        '<leader>y',
+        function()
+          if LazyVim.pick.picker.name == 'telescope' then
+            require('telescope').extensions.yank_history.yank_history({})
+          else
+            vim.cmd([[YankyRingHistory]])
+          end
+        end,
+        mode = { 'n', 'x' },
+        desc = 'Open Yank History',
+      },
+    },
+  },
 }
diff --git a/lua/plugins/which-key-nvim.lua b/lua/plugins/which-key-nvim.lua
new file mode 100644
index 0000000..d174741
--- /dev/null
+++ b/lua/plugins/which-key-nvim.lua
@@ -0,0 +1,239 @@
+return {
+  {
+    'folke/which-key.nvim',
+    opts = {
+      spec = {
+        {
+          mode = { 'n', 'v' },
+          {
+            '<LEADER>',
+            group = 'leader',
+            icon = { icon = '', color = 'green' },
+          },
+          { '<LEADER>K', desc = 'keyword program' },
+
+          { '<DEL>', desc = 'cut' },
+
+          { 'c', desc = 'change' },
+          { 'C', desc = 'change to end of line' },
+          { 'd', desc = 'delete' },
+
+          { 'D', desc = 'delete to end of line' },
+
+          { 'g', group = 'goto' },
+          { 'gd', desc = 'definition' },
+          { 'gD', desc = 'declaration' },
+          { 'gI', desc = 'implementation' },
+          { 'gy', desc = 't[y]pe definition' },
+          { 'ge', desc = 'previous end of word', icon = '' },
+          { 'gf', desc = 'file under cursor' },
+          { 'gg', desc = 'first line', icon = '󰘀' },
+          { 'gi', desc = 'last insert' },
+          { 'gO', desc = 'document symbols', icon = '󰊕' },
+          { 'gt', desc = 'next tab page' },
+          { 'gT', desc = 'previous tab page' },
+          { 'gu', desc = 'make lowercase', icon = '󰬵' },
+          { 'gU', desc = 'make uppercase', icon = '󰬶' },
+          { 'gx', desc = 'open with system app', icon = '󰏋' },
+          { 'g,', desc = 'newer position in change list' },
+          { 'g;', desc = 'older position in change list' },
+          { 'g[', desc = 'left "around"' },
+          { 'g]', desc = 'right "around"' },
+          {
+            'gs',
+            group = 'surround',
+            icon = { icon = '󰅲', color = 'purple' },
+          },
+
+          { 'K', desc = 'keyword program' },
+
+          { 'M', desc = 'middle line of window', icon = '󰘢' },
+          { 'x', desc = 'cut' },
+          { 'X', desc = 'cut to end of line' },
+          { 'Y', desc = 'yank to end of line' },
+
+          { 'z', group = 'fold/scroll/spell', icon = '' },
+          { 'zb', desc = 'bottom this line', icon = '' },
+          { 'ze', desc = 'right this line', icon = '' },
+          { 'zH', desc = 'half screen to the left', icon = '' },
+          { 'zL', desc = 'half screen to the right', icon = '' },
+          { 'zs', desc = 'left this line', icon = '' },
+          { 'zt', desc = 'top this line', icon = '' },
+          { 'zz', desc = 'center this line', icon = '󰘢' },
+          { 'z<CR>', desc = 'top this line', icon = '' },
+
+          { '[', group = 'previous', icon = '' },
+          { '[h', desc = 'hunk' },
+          { '[[', desc = 'reference' },
+          { '[b', desc = 'buffer' },
+          { '[B', desc = 'move buffer backwards' },
+          { '[d', desc = 'diagnostic' },
+          { '[D', desc = 'first diagnostic' },
+          { '[e', desc = 'error' },
+          { '[i', desc = 'top edge of scope' },
+          { '[l', desc = 'location list item' },
+          { '[L', desc = 'prev or first location list item' },
+          { '[m', desc = 'method start' },
+          { '[M', desc = 'method end' },
+          { '[p', desc = 'put & indent before' },
+          { '[P', desc = 'put & indent before' },
+          { '[q', desc = 'trouble/quickfix item' },
+          { '[Q', desc = 'prev or first trouble/quickfix item' },
+          { '[s', desc = 'misspelled word' },
+          { '[t', desc = 'todo comment' },
+          { '[T', desc = 'matching tag' },
+          { '[w', desc = 'warning' },
+          { '[%', desc = 'unmatched group' },
+          { '[(', desc = '(' },
+          { '[<', desc = '<' },
+          { '[{', desc = '{' },
+          { '[<C-l>', desc = 'location list item in prev file' },
+          { '[<C-q>', desc = 'trouble/quickfix item in prev file' },
+          { '[<C-t>', desc = 'tag in preview window' },
+          { '[<SPACE>', desc = 'add empty line above' },
+
+          { ']', group = 'next', icon = '' },
+          { ']h', desc = 'hunk' },
+          { ']]', desc = 'reference' },
+          { ']b', desc = 'buffer' },
+          { ']B', desc = 'move buffer forwards' },
+          { ']d', desc = 'diagnostic' },
+          { ']D', desc = 'last diagnostic' },
+          { ']e', desc = 'error' },
+          { ']i', desc = 'bottom edge of scope' },
+          { ']l', desc = 'location list item' },
+          { ']L', desc = 'prev or last location list item' },
+          { ']m', desc = 'method start' },
+          { ']M', desc = 'method end' },
+          { ']p', desc = 'put & indent after' },
+          { ']P', desc = 'put & indent after' },
+          { ']q', desc = 'trouble/quickfix item' },
+          { ']Q', desc = 'prev or last trouble/quickfix item' },
+          { ']s', desc = 'misspelled word' },
+          { ']t', desc = 'todo comment' },
+          { ']T', desc = 'matching tag' },
+          { ']w', desc = 'warning' },
+          { ']%', desc = 'unmatched group' },
+          { '](', desc = '(' },
+          { ']<', desc = '<' },
+          { ']{', desc = '{' },
+          { ']<C-l>', desc = 'location list item in next file' },
+          { ']<C-q>', desc = 'trouble/quickfix item in next file' },
+          { ']<C-t>', desc = 'tag in preview window' },
+          { ']<SPACE>', desc = 'add empty line below' },
+
+          { '!', desc = 'run program', icon = '' },
+          { '&', desc = 'repeat last :subsitute', icon = '󰛔' },
+          { '<', desc = 'indent decrease', icon = '󰘀' },
+          { '=', group = 'fmt with indentexpr', icon = '' },
+          { '>', desc = 'indent increase', icon = '󰘁' },
+          { '_', desc = 'first character of line', icon = '󰘀' },
+
+          { '<A-j>', desc = 'move line up', icon = '' },
+          { '<A-k>', desc = 'move line down', icon = '' },
+
+          { '<C-a>', desc = 'increment (dial)', icon = '󰆵' },
+          {
+            '<C-L>',
+            desc = 'clear & redraw',
+            icon = { icon = '', color = 'red' },
+          },
+          { '<C-x>', desc = 'decrement (dial)', icon = '󰆶' },
+
+          { '<ESC>', desc = 'clear search highlight' },
+        },
+
+        {
+          mode = { 'n', 'i', 'o' },
+          hidden = true,
+          { '<DOWN>' },
+          { '<UP>' },
+          { '<LEFT>' },
+          { '<RIGHT>' },
+          { '<SCROLLWHEELUP>' },
+          { '<SCROLLWHEELDOWN>' },
+        },
+        {
+          mode = { 'n', 'x', 'o' },
+          hidden = true,
+          { 'j' },
+          { 'k' },
+          { 'h' },
+          { 'l' },
+          { '<PLUG>' },
+          { 'xx' },
+        },
+      },
+
+      icons = {
+        rules = {
+          { pattern = 'start of line', icon = '󰘀' },
+          { pattern = 'end of line', icon = '󰘁' },
+          { pattern = 'prev[i]?[o]?[u]?[s]? word', icon = '' },
+          { pattern = 'next word', icon = '' },
+          { pattern = 'next end of word', icon = '' },
+          { pattern = 'move to next char', icon = '', color = 'green' },
+          { pattern = 'move to prev char', icon = '', color = 'green' },
+          { pattern = 'last line', icon = '󰘁' },
+          { pattern = 'move before next char', icon = '󰘀' },
+          { pattern = 'move before prev char', icon = '󰘁' },
+          { pattern = 'matching %(%){}%[%]', icon = '󰅪' },
+          { pattern = 'start of line %(non ws%)', icon = '󰘀' },
+          { pattern = 'prev empty line', icon = '' },
+          { pattern = 'next empty line', icon = '' },
+
+          { pattern = 'around', icon = '󰅪' },
+          { pattern = 'buffer', color = 'cyan' },
+          { pattern = 'change', icon = '', color = 'cyan' },
+          { pattern = 'comment', icon = '' },
+          { pattern = 'cut', icon = '', color = 'red' },
+          { pattern = 'delete', icon = '󰆴', color = 'red' },
+          { pattern = 'diagnostic', icon = '', hl = 'DiagnosticInfo' },
+          { pattern = 'error', icon = '', hl = 'DiagnosticError' },
+          { pattern = 'explorer', icon = '󰙅', color = 'yellow' },
+          { pattern = 'find', icon = '', color = 'green' },
+          { pattern = 'flash', icon = '󱐋', color = 'green' },
+          { pattern = 'fold', icon = '', color = 'purple' },
+          { pattern = 'format', icon = '󰉼', color = 'purple' },
+          { pattern = 'goto', icon = '', color = 'cyan' },
+          { pattern = 'hunk', color = 'orange' },
+          { pattern = 'inside', icon = '󰅩' },
+          { pattern = 'lazygit', icon = '', color = 'orange' },
+          { pattern = 'message', icon = '󰈸', color = 'orange' },
+          { pattern = 'notification', icon = '󰈸', color = 'orange' },
+          { pattern = 'registers', icon = '󰅍', color = 'yellow' },
+          { pattern = 'replace', icon = '', colors = 'blue' },
+          { pattern = 'session', icon = '', color = 'azure' },
+          { pattern = 'spell', icon = '', color = 'red' },
+          { pattern = 'subsitute', icon = '', color = 'green' },
+          { pattern = 'visual', icon = '', color = 'purple' },
+          { pattern = 'warning', icon = '', hl = 'DiagnosticWarn' },
+          { pattern = 'yank', icon = '', color = 'yellow' },
+          { pattern = 'prev ftFT', icon = '' },
+          { pattern = 'next ftFT', icon = '' },
+        },
+      },
+
+      replace = {
+        desc = {
+          { '%u%l', string.lower },
+          { 'prev ([wW][oO][rR][dD])', 'previous %1' },
+          { 'move to next char', 'find next character' },
+          { 'move to prev char', 'find previous character' },
+          { 'move before next char', 'move before character backwards' },
+          { 'move before prev char', 'move before character fowards' },
+          { 'prev ftFT', 'previous character match' },
+          { 'next ftFT', 'next character match' },
+          { 'start of line %(non ws%)', 'first character of line' },
+          { 'prev empty line', 'previous empty line' },
+          { 'goto %S+ start @parameter.inner', 'parameter start (inner)' },
+          { 'goto %S+ end @parameter.inner', 'parameter end (inner)' },
+          { 'goto %S+ start @class.outer', 'class start (outer)' },
+          { 'goto %S+ end @class.outer', 'class end (outer)' },
+          { 'goto %S+ start @function.outer', 'function start (outer)' },
+          { 'goto %S+ end @function.outer', 'function end (outer)' },
+        },
+      },
+    },
+  },
+}