From f35b13d669867209427449840ff0930a732591dc Mon Sep 17 00:00:00 2001
From: Squibid <me@zacharyscheiman.com>
Date: Fri, 24 Nov 2023 21:38:31 -0500
Subject: more stuff too lazy to seperate

---
 lua/core/auto.lua                 |  30 ----
 lua/core/binds.lua                | 162 --------------------
 lua/core/cmds.lua                 |   8 -
 lua/core/conf.lua                 |  81 ++++++++++
 lua/core/handler.lua              |   5 -
 lua/core/misc.lua                 |  30 ++++
 lua/core/opts.lua                 |  65 --------
 lua/core/plugins.lua              | 134 ----------------
 lua/core/statusbar/components.lua | 315 ++++++++++++++++++++++++++++++++++++++
 lua/core/theme.lua                |  76 +++++++++
 10 files changed, 502 insertions(+), 404 deletions(-)
 delete mode 100644 lua/core/auto.lua
 delete mode 100644 lua/core/binds.lua
 delete mode 100644 lua/core/cmds.lua
 create mode 100644 lua/core/conf.lua
 delete mode 100644 lua/core/handler.lua
 create mode 100644 lua/core/misc.lua
 delete mode 100644 lua/core/opts.lua
 delete mode 100644 lua/core/plugins.lua
 create mode 100644 lua/core/statusbar/components.lua
 create mode 100644 lua/core/theme.lua

(limited to 'lua/core')

diff --git a/lua/core/auto.lua b/lua/core/auto.lua
deleted file mode 100644
index 170f2d7..0000000
--- a/lua/core/auto.lua
+++ /dev/null
@@ -1,30 +0,0 @@
-local function auto(event, opts)
-  a.nvim_create_autocmd(event, opts)
-end
-
-a.nvim_create_augroup('bufcheck', { clear = true })
-
-auto('TextYankPost', { -- highlight yanks
-  group = 'bufcheck',
-  pattern = '*',
-  desc = 'Highlight on yank.',
-  callback = function()
-    vim.highlight.on_yank{ timeout = 250 }
-  end
-})
-
-auto('BufRead', { -- return to last place
-  pattern = '*',
-  command = [[call setpos(".", getpos("'\""))]],
-  desc = 'Return to the last place the buffer was closed in.',
-})
-
-auto('BufWritePre', { -- make dirs when they don't exist
-  pattern = '*',
-  group = vim.api.nvim_create_augroup('auto_create_dir', { clear = true }),
-  desc = 'Basically mkdir -p.',
-  callback = function(ctx)
-    local dir = vim.fn.fnamemodify(ctx.file, ':p:h')
-    vim.fn.mkdir(dir, 'p')
-  end
-})
diff --git a/lua/core/binds.lua b/lua/core/binds.lua
deleted file mode 100644
index b1e98be..0000000
--- a/lua/core/binds.lua
+++ /dev/null
@@ -1,162 +0,0 @@
-local function map(mode, bind, cmd, opts)
-  opts = opts or {}
-  opts['noremap'] = true
-  opts['silent'] = true
-
-  if type(bind) == 'table' then
-    for i in pairs(bind) do
-      vim.keymap.set(mode, bind[i], cmd, opts)
-    end
-  elseif type(bind) == 'string' then
-    vim.keymap.set(mode, bind, cmd, opts)
-  end
-end
-
--- vim binds ------------------------------------------------------------------
-g.mapleader = ' ' -- set leader key
-
-map('x', '<leader>p', [["_dP]], { desc = 'Greatest remap of all time.' })
-map('n', '<esc>', ':nohlsearch<Bar>:echo<CR>', { desc = 'Clear search.' })
-map('t', '<esc>', '<C-\\><C-n>', { desc = 'make <esc> work in terminals.' })
--- move selected text up/down
-map('v', '<S-k>', ":m '<-2<CR>gv=gv", { desc = 'Move selected text up.' })
-map('v', '<S-j>', ":m '>+1<CR>gv=gv", { desc = 'Move selected text down.' })
-
--- the cursor STAYS IN THE MIDDLE
-map('n', '<S-j>', 'mzJ`z<cmd>delm z<CR>') -- when combining lines
-map('n', 'n', 'nzzzv') -- when searching
-map('n', 'N', 'Nzzzv')
-map('n', '<C-d>', '<C-d>zz') -- half page jumping
-map('n', '<C-u>', '<C-u>zz')
-
-map('n', '<leader>x', '<cmd>!chmod +x "%"<CR>') -- execute order 111
-
--- add some keybinds to the file view (netrw)
-a.nvim_create_autocmd('FileType', {
-  pattern = 'netrw',
-  callback = function()
-    local bind = function(lhs, rhs)
-      vim.keymap.set('n', lhs, rhs, { remap = true, buffer = true })
-    end
-    bind('h', '-^') -- Go up a directory
-    bind('l', '<CR>') -- Go down a directory / open a file
-    bind('.', 'gh') -- Toggle hidden files
-    bind('P', '<C-w>z') -- Close preview window
-    bind('<esc>', '<cmd>q<CR>') -- Close netrw
-  end
-})
-
--- tabs
-map('n', '[]', '<cmd>tabnew<CR>')
-map('n', '][', '<cmd>tabc<CR>')
-map('n', '[[', '<cmd>tabp<CR>')
-map('n', ']]', '<cmd>tabN<CR>')
-
--- plugin binds ---------------------------------------------------------------
-
--- pretty lsp view
-map('n', 'gd', '<CMD>Glance definitions<CR>')
-map('n', 'gr', '<CMD>Glance references<CR>')
-map('n', 'gy', '<CMD>Glance type_definitions<CR>')
-map('n', 'gi', '<CMD>Glance implementations<CR>')
-
-if pcall(require, "treesj") then
-  local treesj = require('treesj') -- treesj
-  map('n', '<leader>j', treesj.toggle)
-end
-
-if pcall(require, "telescope") then
-  local telebuilt = require('telescope.builtin') -- telescope
-  -- local telexten = require('telescope').extensions
-  map('n', '<leader>sf', telebuilt.find_files, { desc = 'Find files.' })
-  map('n', '<leader>so', telebuilt.oldfiles, { desc = 'Find old files.' })
-  map('n', '<leader>sg', telebuilt.git_files, { desc = 'Find git files.' })
-  -- search urls in buffer
-  map('n', '<leader>su', '<Cmd>UrlView<CR>', { desc = 'Find urls in buffer.' })
-  -- search lsp symbols
-  map('n', '<leader>ss', telebuilt.lsp_document_symbols,
-      { desc = 'Find LSP Symbols.' })
-  -- search for keybinds
-  map('n', '<leader>sk', telebuilt.keymaps,
-      { desc = 'Find nvim Highlights.' })
-  -- search for highlights
-  map('n', '<leader>sh', telebuilt.highlights,
-      { desc = 'Find nvim Highlights.' })
-  -- search for autocommands
-  map('n', '<leader>sa', telebuilt.autocommands,
-      { desc = 'Find nvim Autocommands.' })
-  -- search for vim options
-  map('n', '<leader>sv', telebuilt.vim_options, { desc = 'Find vim options.' })
-  -- search for string in project
-  map('n', '<leader>sp', function()
-    telebuilt.grep_string({ search = vim.fn.input('Find string in project > ')})
-  end, { desc = 'Find string in project.' })
-  -- Code Actions (requires telescope)
-  if pcall(require, "actions-preview") then
-    map({ "n", "v" }, "<leader>ca", require("actions-preview").code_actions, {
-      desc = 'preview code actions'
-    })
-  end
-end
-
-map('n', '<leader>u', '<cmd>UndotreeToggle<CR>', { desc = 'Open undo tree.' })
-map('n', '<leader>f', '<cmd>SFMToggle<CR>', { desc = 'Open file tree view.' })
-map('n', '<leader>b', '<cmd>JABSOpen<CR>', { desc = 'Switch between buffers.' })
-
-if pcall(require, "smart-splits") then
-  local smartsplits = require('smart-splits') -- resizing buffers (toggleable)
-  map('n', '<leader>r', smartsplits.start_resize_mode)
-end
-
--- toggle term (don't use leader key in these binds)
-map({'n', 't'}, '<C-\\>', '<cmd>ToggleTerm direction=float<CR>')
-map({'n', 't'}, '<C-g>', '<cmd>lua _glow()<CR>')
-
--- true zen
-if pcall(require, "true-zen") then
-  map('n', '<leader>zf', require("true-zen.focus").toggle, {
-    desc = 'fullscreen',
-  })
-  map('n', '<leader>zm', require("true-zen.minimalist").toggle, {
-    desc = 'minimal',
-  })
-  map('n', '<leader>za', require("true-zen.ataraxis").toggle, {
-    desc = 'zen',
-  })
-end
-
--- git
-map('n', '<leader>gp', '<cmd>Gitsigns preview_hunk_inline<CR>')
-map('n', '<leader>gs', '<cmd>Gitsigns stage_hunk<CR>')
-map('n', '<leader>gb', '<cmd>Gitsigns blame_line<CR>')
-map('n', '<leader>g]', '<cmd>Gitsigns next_hunk<CR>')
-map('n', '<leader>g[', '<cmd>Gitsigns prev_hunk<CR>')
-
--- neogen
-if pcall(require, "neogen") then
-  map('n', '<leader>df', require("neogen").generate, {
-    desc = 'Generate anotations',
-  })
-end
-
--- venn
-function _G.Toggle_venn()
-  local venn_enabled = vim.inspect(vim.b.venn_enabled)
-  if venn_enabled == "nil" then
-    vim.b.venn_enabled = true
-    vim.cmd([[setlocal ve=all]])
-    -- draw a line on HJKL keystokes
-    vim.api.nvim_buf_set_keymap(0, "n", "J", "<C-v>j:VBox<CR>", {noremap = true})
-    vim.api.nvim_buf_set_keymap(0, "n", "K", "<C-v>k:VBox<CR>", {noremap = true})
-    vim.api.nvim_buf_set_keymap(0, "n", "L", "<C-v>l:VBox<CR>", {noremap = true})
-    vim.api.nvim_buf_set_keymap(0, "n", "H", "<C-v>h:VBox<CR>", {noremap = true})
-    -- draw a box by pressing "f" with visual selection
-    vim.api.nvim_buf_set_keymap(0, "v", "f", ":VBox<CR>", {noremap = true})
-  else
-    vim.cmd[[setlocal ve=]]
-    vim.cmd[[mapclear <buffer>]]
-    vim.b.venn_enabled = nil
-  end
-end
--- toggle keymappings for venn using <leader>v
-vim.api.nvim_set_keymap('n', '<leader>v', ":lua Toggle_venn()<CR>", { noremap = true})
diff --git a/lua/core/cmds.lua b/lua/core/cmds.lua
deleted file mode 100644
index 3cc78e1..0000000
--- a/lua/core/cmds.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-local function cmd(name, exec, opts)
-  opts = opts or {}
-  vim.api.nvim_create_user_command(name, exec, opts)
-end
-
-cmd('Colorscheme', function()
-  require('telescope.builtin').colorscheme()
-end)
diff --git a/lua/core/conf.lua b/lua/core/conf.lua
new file mode 100644
index 0000000..72dd9bf
--- /dev/null
+++ b/lua/core/conf.lua
@@ -0,0 +1,81 @@
+local pickers = require("telescope.pickers")
+local finders = require("telescope.finders")
+local previewers = require("telescope.previewers")
+local conf = require("telescope.config").values
+local actions = require("telescope.actions")
+local action_state = require("telescope.actions.state")
+
+local M = {}
+
+local function genmenu()
+  local list = {}
+  local function add(name, plug)
+    if not plug then
+      table.insert(list, name)
+    elseif package.loaded[plug] then
+      table.insert(list, name)
+    end
+  end
+
+  add('Edit Config', nil)
+  add('Update Plugins', 'dep')
+  add('Keybinds', 'telescope')
+  add('Colorscheme', 'telescope')
+
+  return list
+end
+
+function M.configmenu()
+  pickers.new({
+    prompt_title = "Nvim Config Menu",
+    finder = finders.new_table { results = genmenu() },
+    sorter = conf.generic_sorter(),
+    previewer = previewers.new_buffer_previewer {
+      define_preview = function(self, entry)
+        local lines = {
+          'a'
+        }
+        if entry.value == "Edit Config" then
+          lines = misc.readf(os.getenv('XDG_CONFIG_HOME')..'/nvim/init.lua')
+          local ft = vim.filetype.match({
+            filename = os.getenv('XDG_CONFIG_HOME')..'/nvim/init.lua' })
+          require("telescope.previewers.utils").highlighter(self.state.bufnr, ft)
+        elseif entry.value == "Colorscheme" then
+          lines = vim.fn.getcompletion('', 'color')
+          for k, v in pairs(lines) do
+            if v.find(v, '.ext') then
+              table.remove(lines, k)
+              break
+            end
+          end
+        end
+        vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)
+      end
+    },
+
+    attach_mappings = function(bufnr, map)
+      actions.select_default:replace(function()
+        actions.close(bufnr)
+        local selection = action_state.get_selected_entry()
+        if selection[1] == 'Edit Config' then
+          vim.cmd('e $XDG_CONFIG_HOME/nvim/init.lua')
+        elseif selection[1] == 'Update Plugins' then
+          require('dep').sync()
+          if package.loaded['nvim-treesitter'] then
+            vim.cmd('TSUpdate')
+          end
+          if package.loaded['mason'] then
+            require('mason.api.command').MasonUpdate()
+          end
+        elseif selection[1] == 'Keybinds' then
+          require('telescope.builtin').keymaps()
+        elseif selection[1] == 'Colorscheme' then
+          require('core.theme').switcher()
+        end
+      end)
+      return true
+    end,
+  }):find()
+end
+
+return M
diff --git a/lua/core/handler.lua b/lua/core/handler.lua
deleted file mode 100644
index 0038146..0000000
--- a/lua/core/handler.lua
+++ /dev/null
@@ -1,5 +0,0 @@
-require('core.plugins') -- load plugins first to allow colorscheme to be set in opts
-require('core.opts')
-require('core.binds')
-require('core.auto')
-require('core.cmds')
diff --git a/lua/core/misc.lua b/lua/core/misc.lua
new file mode 100644
index 0000000..41cbf93
--- /dev/null
+++ b/lua/core/misc.lua
@@ -0,0 +1,30 @@
+local M = {}
+
+M.appid = "Nvim Config"
+
+function M.colorscheme(name)
+  vim.cmd('colorscheme '..name)
+  for k, v in pairs(vim.fn.getcompletion('', 'color')) do
+    if v == name..'.ext' then
+      vim.cmd('colorscheme '..name..'.ext')
+    end
+  end
+end
+
+function M.include(fn)
+  if not pcall(require, fn) then
+    vim.notify('Could not find '..fn, vim.log.levels.WARN, { title = M.appid })
+  end
+end
+
+function M.readf(fn)
+  local f = io.open(fn, "r")
+  if not f then return nil end
+  local tab = {}
+  for l in f:lines() do
+    table.insert(tab, l)
+  end
+  return tab
+end
+
+return M
diff --git a/lua/core/opts.lua b/lua/core/opts.lua
deleted file mode 100644
index 82d88bd..0000000
--- a/lua/core/opts.lua
+++ /dev/null
@@ -1,65 +0,0 @@
--- better ui ------------------------------------------------------------------
-if pcall(require, "notify") then vim.notify = require("notify") end
-o.colorcolumn = { 80 }
-
--- buffer
-o.scrolloff = 5
-o.wrap = true -- wraping lines
-o.linebreak = true -- fix where line is wraped
-o.cursorline = true
-
--- statusbar
-o.laststatus = 3
-o.cmdheight = 1
-o.showmode = false -- stop vim from showing mode (we have a statusbar)
-
--- tabline
-o.showtabline = 2
-
--- status column
-o.signcolumn = 'yes:1' -- show gutter
-
--- indents + tabs
-local tabwidth = 2
-o.expandtab = true
-o.smarttab = true
-o.cindent = true
-o.autoindent = true
-o.tabstop = tabwidth
-o.shiftwidth = tabwidth
-o.softtabstop = tabwidth
-
--- colorscheme
-o.termguicolors = true
-vim.cmd('colorscheme mellow') -- mellow
-vim.cmd('colorscheme mellow+') -- some changes
-
--- better editing -------------------------------------------------------------
-o.clipboard = 'unnamedplus' -- system clipboard
-
--- file saving ----------------------------------------------------------------
-o.swapfile = false
-o.undofile = true
-o.confirm = true
-
--- searching ------------------------------------------------------------------
-o.ignorecase = true
-o.smartcase = true
-o.wrapscan = true
-o.showmatch = true
-o.incsearch = true
-
--- wild menus -----------------------------------------------------------------
-o.wildoptions = 'pum'
-o.pumblend = 3
-o.pumheight = 20
-
-o.wildignorecase = true
-o.wildignore = '*.o'
-
--- netrw ----------------------------------------------------------------------
-g.netrw_banner = 1
-g.netrw_localcopydircmd = 'cp -r'
-g.netrw_winsize = 30
-g.netrw_liststyle = 1
-g.netrw_preview = 1
diff --git a/lua/core/plugins.lua b/lua/core/plugins.lua
deleted file mode 100644
index db20075..0000000
--- a/lua/core/plugins.lua
+++ /dev/null
@@ -1,134 +0,0 @@
-require 'dep' {
-  sync = "always",
-  -- dep manages dep ----------------------------------------------------------
-  { 'squibid/dep',
-    url = 'https://git.squi.bid/dep',
-    -- branch = 'dev'
-  },
-
-  { 'squibid/git-yodel',
-    url = 'https://git.squi.bid/git-yodel'
-  },
-
-  -- colorschemes -------------------------------------------------------------
-  { 'kvrohit/mellow.nvim',
-    requires = 'nvim-treesitter/nvim-treesitter'
-  },
-
-  -- ui -----------------------------------------------------------------------
-  { 'lukas-reineke/indent-blankline.nvim' }, -- indentation indicators
-  { 'folke/which-key.nvim' }, -- key map help
-  { 'rcarriga/nvim-notify' }, -- notifications
-  { 'tjdevries/express_line.nvim', -- status bar
-    requires = 'nvim-lua/plenary.nvim',
-  },
-  { 'goolord/alpha-nvim' }, -- start page
-  { 'dinhhuy258/sfm.nvim', -- tree view
-    deps = 'dinhhuy258/sfm-git.nvim',
-  },
-  { 'matbme/JABS.nvim' }, -- buffer switcher
-  { 'tomiis4/Hypersonic.nvim' }, -- regex helper/displayer
-
-  -- functional plugins -------------------------------------------------------
-  { 'lewis6991/gitsigns.nvim' }, -- very helpful git things
-  { 'squibid/git-yodel', -- git cache diff preview when in commit buffer
-    url = 'https://git.squi.bid/git-yodel'
-  },
-  { 'chentoast/marks.nvim' }, -- marks in gutter
-  { 'vidocqh/auto-indent.nvim' }, -- better tabbing into indents
-  { 'mbbill/undotree' }, -- careful this one is written in vimscript
-  { 'dhruvasagar/vim-table-mode' }, -- same with this one
-  { 'windwp/nvim-autopairs' },
-  { 'numToStr/Comment.nvim' },
-  { 'ahmedkhalf/project.nvim' }, -- cd into root of project
-  { 'akinsho/toggleterm.nvim' }, -- TODO: switch to tmux based popup terminal
-  { 'mrjones2014/smart-splits.nvim'}, -- buffer resizing
-
-  -- note taking --------------------------------------------------------------
-  { 'nvim-neorg/neorg',
-    config = function()
-      if package.loaded['nvim-treesitter'] then
-        vim.cmd(':Neorg sync-parsers<CR>')
-      end
-    end,
-    requires = {
-      'nvim-lua/plenary.nvim',
-      'nvim-treesitter/nvim-treesitter'
-    },
-    deps = 'nvim-neorg/neorg-telescope'
-  },
-
-  { 'jbyuki/venn.nvim' },
-
-  -- fzf ----------------------------------------------------------------------
-  { 'nvim-telescope/telescope.nvim',
-    requires = 'nvim-lua/plenary.nvim',
-    deps = {
-      'nvim-telescope/telescope-file-browser.nvim',
-      'nvim-telescope/telescope-ui-select.nvim',
-      'nvim-telescope/telescope-symbols.nvim',
-      'axieax/urlview.nvim',
-    }
-  },
-
-  -- treesitter + colorizing --------------------------------------------------
-  { 'nvim-treesitter/nvim-treesitter',
-    deps = {
-      'm-demare/hlargs.nvim',
-      'Wansmer/treesj',
-      'nvim-treesitter/nvim-treesitter-context',
-    }
-  },
-  { 'NvChad/nvim-colorizer.lua' },
-  { 'folke/todo-comments.nvim',
-    requires = 'nvim-lua/plenary.nvim',
-  },
-
-  -- cmp ----------------------------------------------------------------------
-  { 'hrsh7th/nvim-cmp',
-    deps = {
-      'lukas-reineke/cmp-under-comparator', -- better results
-      'hrsh7th/cmp-buffer', -- buffers
-      'FelipeLema/cmp-async-path', -- path
-      'hrsh7th/cmp-calc', -- calculator
-      'saadparwaiz1/cmp_luasnip', -- snippets
-      'hrsh7th/cmp-nvim-lsp', -- lsp
-      'uga-rosa/cmp-dictionary', -- dictionary
-      'hrsh7th/cmp-nvim-lua', -- nvim lua api
-    },
-  },
-
-  -- snippets -----------------------------------------------------------------
-  { 'L3MON4D3/LuaSnip',
-    deps = 'rafamadriz/friendly-snippets',
-  },
-  { 'doxnit/cmp-luasnip-choice' },
-
-  -- lsp ----------------------------------------------------------------------
-  { 'neovim/nvim-lspconfig' }, -- setup lsp
-  { 'j-hui/fidget.nvim', -- shows lsp progress
-    branch = 'legacy',
-  },
-
-  { 'ray-x/lsp_signature.nvim' }, -- see information about the current function
-  { 'dnlhc/glance.nvim' }, -- diagnostic info at a glance
-  { 'aznhe21/actions-preview.nvim', -- codeactions
-    requires = 'nvim-telescope/telescope.nvim'
-  },
-
-  { 'danymat/neogen', -- generate lsp annotations
-    requires = 'nvim-treesitter/nvim-treesitter'
-  },
-
-  { 'whynothugo/lsp_lines.nvim',
-    url = 'https://git.sr.ht/~whynothugo/lsp_lines.nvim',
-  },
-
-  -- mason --------------------------------------------------------------------
-  { 'williamboman/mason.nvim',
-    deps = {
-      'WhoIsSethDaniel/mason-tool-installer.nvim',
-      'williamboman/mason-lspconfig.nvim',
-    }
-  }
-}
diff --git a/lua/core/statusbar/components.lua b/lua/core/statusbar/components.lua
new file mode 100644
index 0000000..cce3127
--- /dev/null
+++ b/lua/core/statusbar/components.lua
@@ -0,0 +1,315 @@
+if not pcall(require, "el") then return end
+
+local job = require "plenary.job"
+local el_sub = require "el.subscribe"
+
+local M = {}
+
+function M.extract_hl(spec)
+  if not spec or vim.tbl_isempty(spec) then return end
+  local hl_name, hl_opts = { "El" }, {}
+  for attr, val in pairs(spec) do
+    if type(val) == "table" then
+      table.insert(hl_name, attr)
+      assert(vim.tbl_count(val) == 1)
+      local hl, what = next(val)
+      local hlID = vim.fn.hlID(hl)
+      if hlID > 0 then
+        table.insert(hl_name, hl)
+        local col = vim.fn.synIDattr(hlID, what)
+        if col and #col > 0 then
+          table.insert(hl_name, what)
+          hl_opts[attr] = col
+        end
+      end
+    else
+      -- bold, underline, etc
+      hl_opts[attr] = val
+    end
+  end
+  hl_name = table.concat(hl_name, "_")
+  -- if highlight exists, verify it has
+  -- the correct colorscheme highlights
+  local newID = vim.fn.hlID(hl_name)
+  if newID > 0 then
+    for what, expected in pairs(hl_opts) do
+      local res = vim.fn.synIDattr(newID, what)
+      if type(expected) == "boolean" then
+        -- synIDattr returns '1' for boolean
+        res = res and res == "1" and true
+      end
+      if res ~= expected then
+        -- need to regen the highlight
+        -- print("color mismatch", hl_name, what, "e:", expected, "c:", res)
+        newID = 0
+      end
+    end
+  end
+  if newID == 0 then
+    vim.api.nvim_set_hl(0, hl_name, hl_opts)
+  end
+  return hl_name
+end
+
+local function set_hl(hls, s)
+  if not hls or not s then return s end
+  hls = type(hls) == "string" and { hls } or hls
+  for _, hl in ipairs(hls) do
+    if vim.fn.hlID(hl) > 0 then
+      return ("%%#%s#%s%%0*"):format(hl, s)
+    end
+  end
+  return s
+end
+
+local function wrap_fnc(opts, fn)
+  return function(window, buffer)
+    -- buf_autocmd doesn't send win
+    if not window and buffer then
+      window = { win_id = vim.fn.bufwinid(buffer.bufnr) }
+    end
+    if opts.hide_inactive and window and
+      window.win_id ~= vim.api.nvim_get_current_win() then
+      return ""
+    end
+    return fn(window, buffer)
+  end
+end
+
+function M.mode(opts)
+  opts = opts or {}
+  return wrap_fnc(opts, function(_, _)
+    local fmt = opts.fmt or "%s%s"
+    local mode = vim.api.nvim_get_mode().mode
+    local mode_data = opts.modes and opts.modes[mode]
+    local hls = mode_data and mode_data[3]
+    local icon = opts.hl_icon_only and set_hl(hls, opts.icon) or opts.icon
+    mode = mode_data and mode_data[1]:upper() or mode
+    mode = (fmt):format(icon or "", mode)
+    return not opts.hl_icon_only and set_hl(hls, mode) or mode
+  end)
+end
+
+function M.git_branch(opts)
+  opts = opts or {}
+  return el_sub.buf_autocmd("el_git_branch", "BufEnter",
+  wrap_fnc(opts, function(_, buffer)
+    -- Try fugitive first as it's most reliable
+    local branch = vim.g.loaded_fugitive == 1 and
+    vim.fn.FugitiveHead() or nil
+    -- buffer can be null and code will crash with:
+    -- E5108: Error executing lua ... 'attempt to index a nil value'
+    if not buffer or not (buffer.bufnr > 0) then
+      return
+    end
+    -- fugitive is empty or not loaded, try gitsigns
+    if not branch or #branch == 0 then
+      local ok, res = pcall(vim.api.nvim_buf_get_var,
+      buffer.bufnr, "gitsigns_head")
+      if ok then branch = res end
+    end
+    -- last resort run git command
+    if not branch then
+      local j = job:new {
+        command = "git",
+        args = { "branch", "--show-current" },
+        cwd = vim.fn.fnamemodify(buffer.name, ":h"),
+      }
+
+      local ok, result = pcall(function()
+        return vim.trim(j:sync()[1])
+      end)
+      if ok then
+        branch = result
+      end
+    end
+
+    if branch and #branch > 0 then
+      local fmt = opts.fmt or "%s %s"
+      local icon = opts.icon or ""
+      return set_hl(opts.hl, (fmt):format(icon, branch))
+    end
+  end))
+end
+
+local function git_changes_formatter(opts)
+  local specs = {
+    insert = {
+      regex = "(%d+) insertions?",
+      icon  = opts.icon_insert or "+",
+      hl    = opts.hl_insert,
+    },
+    change = {
+      regex = "(%d+) files? changed",
+      icon  = opts.icon_change or "~",
+      hl    = opts.hl_change,
+    },
+    delete = {
+      regex = "(%d+) deletions?",
+      icon  = opts.icon_delete or "-",
+      hl    = opts.hl_delete,
+    },
+  }
+  return function(_, _, s)
+    local result = {}
+    for k, v in pairs(specs) do
+      local count = nil
+      if type(s) == "string" then
+        -- 'git diff --shortstat' output
+        -- from 'git_changes_all'
+        count = tonumber(string.match(s, v.regex))
+      else
+        -- map from 'git_changes_buf'
+        count = s[k]
+      end
+      if count and count > 0 then
+        table.insert(result, set_hl(v.hl, ("%s%d"):format(v.icon, count)))
+      end
+    end
+    return table.concat(result, " ")
+  end
+end
+
+-- requires gitsigns
+function M.git_changes_buf(opts)
+  opts = opts or {}
+  local formatter = opts.formatter or git_changes_formatter(opts)
+  return wrap_fnc(opts, function(window, buffer)
+    local stats = {}
+    if buffer and buffer.bufnr > 0 then
+      local ok, res = pcall(vim.api.nvim_buf_get_var,
+      buffer.bufnr, "vgit_status")
+      if ok then stats = res end
+    end
+    if buffer and buffer.bufnr > 0 then
+      local ok, res = pcall(vim.api.nvim_buf_get_var,
+      buffer.bufnr, "gitsigns_status_dict")
+      if ok then stats = res end
+    end
+    local counts = {
+      insert = stats.added > 0 and stats.added or nil,
+      change = stats.changed > 0 and stats.changed or nil,
+      delete = stats.removed > 0 and stats.removed or nil,
+    }
+    if not vim.tbl_isempty(counts) then
+      local fmt = opts.fmt or "%s"
+      local out = formatter(window, buffer, counts)
+      return out and fmt:format(out) or nil
+    else
+      -- el functions that return a
+      -- string must not return nil
+      return ""
+    end
+  end)
+end
+
+function M.git_changes_all(opts)
+  opts = opts or {}
+  local formatter = opts.formatter or git_changes_formatter(opts)
+  return el_sub.buf_autocmd("el_git_changes", "BufWritePost",
+  wrap_fnc(opts, function(window, buffer)
+    if not buffer or
+      not (buffer.bufnr > 0) or
+      vim.bo[buffer.bufnr].bufhidden ~= "" or
+      vim.bo[buffer.bufnr].buftype == "nofile" or
+      vim.fn.filereadable(buffer.name) ~= 1 then
+      return
+    end
+
+    local j = job:new {
+      command = "git",
+      args = { "diff", "--shortstat" },
+      -- makes no sense to run for one file as
+      -- 'file(s) changed' will always be 1
+      -- args = { "diff", "--shortstat", buffer.name },
+      cwd = vim.fn.fnamemodify(buffer.name, ":h"),
+    }
+
+    local ok, git_changes = pcall(function()
+      return formatter(window, buffer, vim.trim(j:sync()[1]))
+    end)
+
+    if ok then
+      local fmt = opts.fmt or "%s"
+      return git_changes and fmt:format(git_changes) or nil
+    end
+  end))
+end
+
+function M.lsp_srvname(opts)
+  local fmt = opts.fmt or "%s"
+  local icon = opts.icon or ""
+  local buf_clients = vim.lsp.buf_get_clients(0)
+  if not buf_clients or #buf_clients == 0 then
+    return ""
+  end
+  local names = ""
+  for i, c in ipairs(buf_clients) do
+    if i > 1 then names = names .. ", " end
+    names = names .. c.name
+  end
+  return icon..fmt:format(names)
+end
+
+local function diag_formatter(opts)
+  return function(_, buffer, counts)
+    local items = {}
+    local icons = {
+      ["errors"]   = { opts.icon_err or "x", opts.hl_err or "DiagnosticError"},
+      ["warnings"] = { opts.icon_warn or "!", opts.hl_warn or "DiagnosticWarn"},
+      ["infos"]    = { opts.icon_info or "i", opts.hl_info or "DiagnosticInfo"},
+      ["hints"]    = { opts.icon_hint or "h", opts.hl_hint or "DiagnosticHint"},
+    }
+    for _, k in ipairs({ "errors", "warnings", "infos", "hints" }) do
+      if counts[k] > 0 then
+        table.insert(items,
+        set_hl(icons[k][2], ("%s:%s"):format(icons[k][1], counts[k])))
+      end
+    end
+    local fmt = opts.fmt or "%s"
+    if vim.tbl_isempty(items) then
+      return ""
+    else
+      return fmt:format(table.concat(items, " "))
+    end
+  end
+end
+
+local function get_buffer_counts(diagnostic, _, buffer)
+  local counts = { 0, 0, 0, 0 }
+  local diags = diagnostic.get(buffer.bufnr)
+  if diags and not vim.tbl_isempty(diags) then
+    for _, d in ipairs(diags) do
+      if tonumber(d.severity) then
+        counts[d.severity] = counts[d.severity] + 1
+      end
+    end
+  end
+  return {
+    errors   = counts[1],
+    warnings = counts[2],
+    infos    = counts[3],
+    hints    = counts[4],
+  }
+end
+
+function M.diagnostics(opts)
+  opts = opts or {}
+  local formatter = opts.formatter or diag_formatter(opts)
+  return el_sub.buf_autocmd("el_buf_diagnostic", "LspAttach,DiagnosticChanged",
+  wrap_fnc(opts, function(window, buffer)
+    return formatter(window, buffer, get_buffer_counts(vim.diagnostic, window, buffer))
+  end))
+end
+
+function M.line(opts)
+  opts = opts or {}
+  local fmt = opts.fmt or "%s"
+  return wrap_fnc(opts, function(_, _)
+    local al = vim.api.nvim_buf_line_count(0)
+    local cl = vim.api.nvim_win_get_cursor(0)[1]
+    return (fmt):format(cl.."/"..al.." "..math.floor((cl / al) * 100).."%%")
+  end)
+end
+
+return M
diff --git a/lua/core/theme.lua b/lua/core/theme.lua
new file mode 100644
index 0000000..9d508f2
--- /dev/null
+++ b/lua/core/theme.lua
@@ -0,0 +1,76 @@
+local pickers = require("telescope.pickers")
+local finders = require("telescope.finders")
+local previewers = require("telescope.previewers")
+local conf = require("telescope.config").values
+local actions = require("telescope.actions")
+local action_set = require("telescope.actions.set")
+local action_state = require("telescope.actions.state")
+local misc = require('core.misc')
+
+local M = {}
+
+function M.switcher()
+  local bufnr = vim.api.nvim_get_current_buf()
+
+  -- show current buffer content in previewer
+  local colors = vim.fn.getcompletion('', 'color')
+  for k, v in pairs(colors) do
+    if v.find(v, '.ext') then
+      table.remove(colors, k)
+      break
+    end
+  end
+
+  -- our picker function: colors
+  pickers.new({
+    prompt_title = "Set Nvim Colorscheme",
+    finder = finders.new_table { results = colors },
+    sorter = conf.generic_sorter(),
+    previewer = previewers.new_buffer_previewer {
+      define_preview = function(self, entry)
+        -- add content
+        local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
+        vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines)
+
+        -- add syntax highlighting in previewer
+        local ft = (vim.filetype.match { buf = bufnr } or "diff"):match "%w+"
+        require("telescope.previewers.utils").highlighter(self.state.bufnr, ft)
+      end
+    },
+
+    attach_mappings = function(prompt_bufnr, map)
+      -- reload theme while typing
+      vim.schedule(function()
+        vim.api.nvim_create_autocmd("TextChangedI", {
+          buffer = prompt_bufnr,
+          callback = function()
+            if action_state.get_selected_entry() then
+              misc.colorscheme(action_state.get_selected_entry()[1])
+            end
+          end,
+        })
+      end)
+
+      -- reload theme on cycling
+      actions.move_selection_previous:replace(function()
+        action_set.shift_selection(prompt_bufnr, -1)
+        misc.colorscheme(action_state.get_selected_entry()[1])
+      end)
+      actions.move_selection_next:replace(function()
+        action_set.shift_selection(prompt_bufnr, 1)
+        misc.colorscheme(action_state.get_selected_entry()[1])
+      end)
+
+      -- reload theme on selection
+      actions.select_default:replace(function()
+        if action_state.get_selected_entry() then
+          actions.close(prompt_bufnr)
+          misc.colorscheme(action_state.get_selected_entry()[1])
+        end
+      end)
+      return true
+    end,
+  }):find()
+end
+
+return M
-- 
cgit v1.2.1