Skip to content

Instantly share code, notes, and snippets.

@henrycatalinismith
Last active November 14, 2022 19:22
Show Gist options
  • Save henrycatalinismith/987542d02f8560b412f78dcfa02ad9fb to your computer and use it in GitHub Desktop.
Save henrycatalinismith/987542d02f8560b412f78dcfa02ad9fb to your computer and use it in GitHub Desktop.
init.lua
-- 💾 cosy 1 file nvim cfg --
-- 🧙 drag+ drop install --
-- 📦 0 package management --
--------------------------------
-- plugins ---------------------
--------------------------------
local plugins = {}
local function plugin_register(name)
local dir = string.format(
"%s/site/pack/paqs/",
vim.fn.stdpath("data")
)
local url = string.format(
"https://github.com/%s",
name
)
plugins[name] = {
name = name,
dir = dir,
url = url,
}
end
local function plugin_install(name)
local plugin = plugins[name]
local args = {
"clone",
plugin.url,
"--depth=1",
"--recurse-submodules",
"--shallow-submodules",
plugin.dir,
}
end
--------------------------------
-- tables ----------------------
--------------------------------
-- Table index search
local function tbl_index(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
--------------------------------
-- editor ----------------------
--------------------------------
local function editor_keymaps()
-- Use space as the leader key
--
-- Space is the biggest key on
-- a standard keyboard and
-- doesn't do anything by
-- default in normal mode.
vim.g.mapleader = " "
end
--------------------------------
-- indentation -----------------
--------------------------------
-- Configure columns per indent
local function indent_size(s, v)
s.shiftwidth = v
s.tabstop = v
end
-- Toggle between tabs & spaces
local function indent_style(s, v)
if v == "tab" then
s.expandtab = false
elseif v == "space" then
s.expandtab = true
end
end
-- 1 space indents by default
--
-- This is intentionally small
-- in order to optimize for
-- shorter lines. Code that fits
-- in a narrow column is more
-- legible in space-constrained
-- contexts like mobile devices,
-- refreshable braille displays,
-- and split diffs.
--
-- Default to spaces, not tabs
--
-- Indentation using spaces is
-- more ubiquitous than tabs so
-- this is a better starting
-- point.
local function indent_defaults()
indent_size(vim.o, 1)
indent_style(vim.o, "space")
end
--------------------------------
-- autocommands ----------------
--------------------------------
-- Autogroup shorthand
local function augroup(name)
vim.api.nvim_create_augroup(
name,
{ clear = true }
)
end
local augroups = {
editorconfig = augroup("editorconfig"),
gist = augroup("gist"),
lsp = augroup("lsp"),
terminal = augroup("terminal"),
}
--------------------------------
-- themes ----------------------
--------------------------------
local function theme_apply(groups)
for g,c in pairs(groups) do
for n,v in pairs(c) do
local cmd = string.format(
"hi %s %s=%s gui=none",
g, n, v
)
vim.cmd(cmd)
end
end
end
local colors = {
gray = "#808080",
snow = "#FFFAFA",
crimson = "#DC143C",
darkolivegreen = "#556B2F",
darkslategray = "#2F4F4F",
deeppink = "#FF1493",
dodgerblue = "#1E90FF",
firebrick = "#B22222",
green = "#008000",
honeydew = "#F0FFF0",
lavender = "#E6E6FA",
lavenderblush = "#FFF0F5",
lightcyan = "#E0FFFF",
lightgray = "#D3D3D3",
lightskyblue = "#87CEFA",
lightyellow = "#FFFFE0",
orangered = "#FF4500",
palegreen = "#98FB98",
palevioletred = "#DB7093",
powderblue = "#B0E0E6",
royalblue = "#4169E1",
seagreen = "#2E8B57",
teal = "#008080",
thistle = "#D8BFD8",
violet = "#EE82EE",
yellow = "#FFFF00",
}
local function theme_light()
theme_apply({
Normal = {
guibg = colors.darkslategray,
guifg = colors.snow,
},
SignColumn = {
guibg = colors.darkslategray,
},
LineNr = {
guibg = colors.darkslategray,
guifg = colors.thistle,
},
CursorLine = {
guibg = "none",
},
CursorLineNR = {
guifg = colors.deeppink,
},
PMenu = {
guibg = colors.darkslategray,
guifg = colors.snow,
},
PMenuSel = {
guibg = colors.deeppink,
guifg = colors.snow,
},
IncSearch = {
guibg = colors.yellow,
},
TabLineFill = {
guifg = colors.snow,
},
TabLineBuffer = {
guibg = colors.lavender,
guifg = colors.deeppink,
},
TabLineBufferSel = {
guibg = colors.deeppink,
guifg = colors.snow,
},
TabLineNC = {
guibg = colors.lavender,
},
TabLine = {
guibg = colors.powderblue,
guifg = colors.royalblue,
},
TabLineSel = {
guibg = colors.royalblue,
guifg = colors.snow,
},
DiagnosticVirtualTextError = {
guibg = colors.lavenderblush,
guifg = colors.crimson,
},
DiagnosticVirtualTextWarn = {
guibg = colors.lightyellow,
guifg = colors.orangered,
},
DiagnosticVirtualTextInfo = {
guibg = colors.honeydew,
guifg = colors.darkolivegreen,
},
DiagnosticVirtualTextHint = {
guibg = colors.lightcyan,
guifg = colors.teal,
},
Comment = {
guifg = colors.lightgray,
},
PreProc = {
guifg = colors.violet,
},
Special = {
guifg = colors.violet,
},
String = {
guifg = colors.lightskyblue,
},
Constant = {
guifg = colors.lightskyblue,
},
Statement = {
guifg = colors.violet,
},
Identifier = {
guifg = colors.palegreen,
},
Type = {
guifg = colors.palegreen,
},
StatusLine = {
guibg = colors.snow,
guifg = colors.darkslategray,
},
})
end
--------------------------------
-- path ------------------------
--------------------------------
-- Return parent directory name
local function path_dirname(path)
return vim.fn.fnamemodify(path, ":h")
end
-- Check the file's there
local function path_exists(path)
local f = io.open(path, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
-- Remove path's trailing slash
local function path_strip(path)
local p, _ = path:gsub("/$", '')
return p
end
-- Just get the filename
local function path_basename(path)
path = path_strip(path)
local i = path:match("^.*()/")
if not i then return path end
return path:sub(i + 1, #path)
end
--------------------------------
-- buffers ---------------------
--------------------------------
-- List buffers belonging to tab
--
-- This many-to-one relationship
-- doesn't really exist in nvim
-- itself but the concept is
-- useful so this function bolts
-- it on heuristically. A buffer
-- is considered to "belong to"
-- a tab if the tab's cwd is a
-- prefix of the file's path.
-- So a buffer at
-- /var/www/index.html would be
-- considered as "belonging to"
-- a tab with cwd /var/www.
local function tab_buffers(tabnr)
local bufnrs = {}
local bufs = vim.api.nvim_list_bufs()
for _,i in pairs(bufs) do
if not vim.api.nvim_buf_is_loaded(i) then
goto continue
end
local bl = vim.api.nvim_buf_get_option(
i,
"buflisted"
)
if not bl then
goto continue
end
local path = vim.api.nvim_buf_get_name(i)
local cwd = vim.fn.getcwd(-1, tabnr)
local prefix = path:match("^"..cwd)
local inside = prefix ~= nil
if not inside then
goto continue
end
table.insert(bufnrs, i)
::continue::
end
return bufnrs
end
-- Close the current buffer
--
-- Equivalent to :tabclose
-- except it preserves the tab,
-- unloads the currently focused
-- buffer, and switches the tab
-- to point at another buffer.
local function buffer_close()
local buf = vim.api.nvim_get_current_buf()
local tab = vim.fn.tabpagenr()
local bl = vim.api.nvim_buf_get_option(
buf,
"buflisted"
)
if not bl then
vim.cmd [[ :quit! ]]
return
end
vim.cmd [[ bd ]]
local bufs = tab_buffers(tab)
if #bufs < 1 then
return
end
local cmd = string.format(
"buffer %d",
bufs[1]
)
vim.cmd(cmd)
end
local function buffer_filename()
return vim.api.nvim_buf_get_name(
vim.api.nvim_get_current_buf()
)
end
-- Open the next buffer
--
-- Equivalent to :tabnext except
-- it moves between the buffers
-- considered as "belonging to"
-- the current tab.
local function buffer_next()
local buf = vim.api.nvim_get_current_buf()
local tab = vim.fn.tabpagenr()
local bufs = tab_buffers(tab)
if #bufs < 2 then
return
end
if not vim.tbl_contains(bufs, buf) then
return
end
local cur_index = tbl_index(bufs, buf)
local nxt_index = cur_index + 1
if nxt_index > #bufs then
nxt_index = 1
end
local nxt_buf = bufs[nxt_index]
local cmd = string.format(
"buffer %d",
nxt_buf
)
vim.cmd(cmd)
end
local function buffer_write()
vim.cmd [[ write ]]
end
-- Keyboard shortcus for buffers
local function buffer_keymaps()
vim.keymap.set(
"n",
"<Tab>",
buffer_next,
{ noremap = true }
)
vim.keymap.set(
"n",
"<leader>q",
buffer_close,
{ noremap = true }
)
vim.keymap.set(
"n",
"<leader>w",
buffer_write,
{ noremap = true }
)
end
--------------------------------
-- tabs ------------------------
--------------------------------
-- Open a new tab
local function tab_new()
-- TODO: project picker?
vim.cmd [[ :tabnew ]]
end
-- Keyboard shortcuts for tabs
local function tab_keymaps()
vim.keymap.set(
"n",
"<leader>t",
tab_new,
{ noremap = true }
)
end
--------------------------------
-- lsp -------------------------
--------------------------------
-- Handle LSP attach event
local function lsp_attach()
-- TODO: Inform of this event
-- somehow. Ambiguity about
-- which buffers are attached
-- to an LSP and which aren't
-- is annoying.
vim.keymap.set(
"n",
"gd",
"<cmd>lua vim.lsp.buf.definition()<CR>",
{
noremap = true,
buffer = true,
}
)
vim.keymap.set(
"n",
"gh",
"<cmd>lua vim.lsp.buf.hover()<CR>",
{
noremap = true,
buffer = true,
}
)
vim.keymap.set(
"n",
"gr",
"<cmd>lua vim.lsp.buf.references()<CR>",
{
noremap = true,
buffer = true,
}
)
vim.keymap.set(
"n",
"<leader>[",
"<cmd>lua vim.diagnostic.goto_prev()<CR>",
{
noremap = true,
buffer = true,
}
)
vim.keymap.set(
"n",
"<leader>]",
"<cmd>lua vim.diagnostic.goto_next()<CR>",
{
noremap = true,
buffer = true,
}
)
end
-- Start Lua server
local function lsp_lua()
local cmd = {
"lua-language-server"
}
-- TODO: fix root_dir
local root_dir = vim.fs.dirname(
buffer_filename()
)
local settings = {
completion = {
enable = true,
showWord = "Disable",
},
runtime = {
version = "LuaJIT",
},
telemetry = {
enable = false,
},
}
vim.lsp.start({
name = "lua",
cmd = cmd,
root_dir = root_dir,
settings = settings,
})
end
-- Start TypeScript server
local function lsp_typescript()
local cmd = {
"typescript-language-server",
"--stdio",
}
-- TODO: fix root_dir
local root_dir = vim.fs.dirname(
buffer_filename()
)
local settings = {
completion = {
enable = true,
},
completions = {
completeFunctionCalls = true,
},
typescript = {
inlayHints = {
includeInlayParameterNameHints = "all",
includeInlayVariableTypeHints = true,
includeInlayEnumMemberValueHints = true,
},
},
javascript = {
inlayHints = {
includeInlayParameterNameHints = "all",
includeInlayVariableTypeHints = true,
includeInlayEnumMemberValueHints = true,
},
},
telemetry = {
enable = false,
},
}
-- root_dir = vim.fs.dirname(
-- vim.fs.find(
-- {
-- "package.json",
-- "tsconfig.json",
-- },
-- {
-- path = buffer_filename(),
-- upward = true,
-- }
-- )
-- ),
vim.lsp.start({
name = "tsserver",
cmd = cmd,
root_dir = root_dir,
settings = settings,
})
end
-- Hook up LSP events
local function lsp_autocommands()
vim.api.nvim_create_autocmd(
{ "FileType" },
{
pattern = "lua",
callback = lsp_lua,
group = augroups.lsp,
}
)
vim.api.nvim_create_autocmd(
{ "FileType" },
{
pattern = {
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
},
callback = lsp_typescript,
group = augroups.lsp,
}
)
vim.api.nvim_create_autocmd(
{ "LspAttach" },
{
callback = lsp_attach,
group = augroups.lsp,
}
)
end
--------------------------------
-- zsh -------------------------
--------------------------------
-- Configure zsh
--
-- Setting these options here
-- instead of in a config file
-- is limiting but also keeps
-- the entire development setup
-- within a single file.
local function zsh_args()
local args = {"zsh"}
-- Skip typing cd and go to
-- directories by typing just
-- their names.
table.insert(args, "--autocd")
-- Storing timestamps in shell
-- history is useful when
-- reconstructing incident
-- timelines.
table.insert(args, "--extendedhistory")
-- Skip loading any zsh config
-- files so that the shell's
-- environment can be fully
-- configured from nvim.
table.insert(args, "--no-rcs")
-- Write to history immediately
-- instead of waiting for exit.
table.insert(
args, "--incappendhistorytime"
)
return args
end
-- Configure zsh environment
--
-- Setting these options here
-- instead of in a config file
-- is limiting but also keeps
-- the entire development setup
-- within a single file.
local function zsh_env()
local env = {}
-- Without CLICOLOR commands
-- like ls will print output
-- in plain text.
env.CLICOLOR = "1"
-- Just have a couple of
-- directory names' worth of
-- context in the prompt.
env.PROMPT = "%2~ $ "
return env
end
-- When zsh exits the intent to
-- close the terminal is crystal
-- clear but by default nvim
-- will keep the buffer open and
-- display the exit message
-- "[Process exited 0]". So by
-- default it requires a
-- sequence of two keystrokes to
-- close a terminal and this
-- call to buf_delete automates
-- the second one.
local function zsh_on_exit(buf)
return function()
vim.api.nvim_buf_delete(
buf, { force = true }
)
end
end
--------------------------------
-- terminal --------------------
--------------------------------
-- Set up newly opened terminal
local function terminal_opened()
-- Line numbers and signs are
-- useless in terminals so turn
-- them off.
vim.opt_local.number = false
vim.opt_local.signcolumn = "no"
-- Opening a terminal already
-- took one keystroke and the
-- intent to enter a terminal
-- command next is crystal
-- clear so enter insert mode
-- automatically.
vim.cmd [[ startinsert ]]
end
-- Entering a terminal
local function terminal_entered()
-- For now most terminal
-- usage is via the <leader>`
-- shortcut so there's never
-- a circumstance where a
-- terminal is entered without
-- immediate intent to enter a
-- command.
vim.cmd [[ startinsert ]]
end
-- Leaving terminal insert mode
local function terminal_escaped()
-- For now most terminal usage
-- is in a horizontal split at
-- the bottom of the screen.
-- The next interaction after
-- leaving insert mode will
-- probably be to edit text so
-- restoring focus to the
-- editor window above removes
-- a kestroke from the journey.
vim.cmd [[ wincmd k]]
end
-- Hook up terminal events
local function terminal_autocommands()
vim.api.nvim_create_autocmd(
{ "TermOpen" },
{
callback = terminal_opened,
group = augroups.terminal,
}
)
vim.api.nvim_create_autocmd(
{ "BufEnter" },
{
pattern = "term://*",
callback = terminal_entered,
group = augroups.terminal,
}
)
vim.api.nvim_create_autocmd(
{ "ModeChanged" },
{
pattern = "t:nt",
callback = terminal_escaped,
group = augroups.terminal,
}
)
end
-- Open a zsh terminal
local function terminal_open()
local cmd = zsh_args()
local env = zsh_env()
local on_exit = zsh_on_exit(
vim.api.nvim_get_current_buf()
)
local opts = {
env = env,
on_exit = on_exit,
}
vim.fn.termopen(cmd, opts)
end
-- New splitscreen terminal
local function terminal_split()
vim.cmd [[ split terminal ]]
terminal_open()
end
-- Terminal keyboard shortcuts
local function terminal_keymaps()
vim.keymap.set(
"n",
"<leader>`",
terminal_split,
{ noremap = true }
)
vim.keymap.set(
"t",
"<Esc>",
"<C-\\><C-n>",
{ noremap = true }
)
end
--------------------------------
-- gist ------------------------
--------------------------------
-- Upload init.lua to GitHub
local function gist_update()
local command = string.format(
"gist %s -u %s",
"~/.config/nvim/init.lua",
"987542d02f8560b412f78dcfa02ad9fb"
)
if vim.fn.executable("gist") then
io.popen(command)
end
end
-- Autoupdate gist on save
--
-- These editor config files
-- are unusually prone to data
-- loss due to mistakes while
-- working on them. To avoid
-- losing an entire day's work
-- ever again, this autocmd
-- uploads the whole file to
-- GitHub after every save.
local function gist_autocommands()
vim.api.nvim_create_autocmd(
{ "BufWrite" },
{
pattern = { "init.lua" },
callback = gist_update,
group = augroups.gist,
}
)
end
--------------------------------
-- editorconfig ----------------
--------------------------------
-- List editorconfigs for path
--
-- Scans each parent directory
-- for .editorconfig files and
-- returns the final list.
local function ec_find(path)
local files = {}
local dir = path_dirname(path)
local done = false
while not done do
local filename = string.format(
"%s.editorconfig",
vim.fn.fnamemodify(dir, ":p")
)
if path_exists(filename) then
table.insert(files, filename)
end
local parent = path_dirname(dir)
if parent == dir then
done = true
end
dir = parent
end
return files
end
-- Magics a working regex
--
-- The pattern format that
-- editorconfig files use isn't
-- the same as nvim's regexes.
-- This code comes from
-- somewhere on GitHub and it
-- magics the editorconfig ones
-- into nvim ones.
local function ec_glob2regpat(glob)
local placeholder = "@@PLACEHOLDER@@"
return string.gsub(
vim.fn.glob2regpat(
vim.fn.substitute(
string.gsub(
glob,
"{(%d+)%.%.(%d+)}",
"[%1-%2]"
),
"\\*\\@<!\\*\\*\\@!",
placeholder,
"g"
)
),
placeholder,
"[^/]*"
)
end
-- Extract editorconfig line
--
-- Returns 3 pieces.
-- 1. Pattern:
-- This is the contents of
-- the square brackets on
-- lines that set a pattern.
-- 2. Key:
-- This is the bit before the
-- equals sign on lines that
-- configure a setting.
-- 3. Value:
-- This is the bit after the
-- equals sign on lines that
-- configure a setting.
local function ec_parse(line)
local pregex = "^%s*%[(.*)%]%s*$"
local kvregx = table.concat({
"^",
"([^:= ][^:=]-)",
"[:=]",
"(.-)",
"$"
}, "%s*")
local pi = (line:match("%b[]") or "")
local pattern = pi:match(pregex)
local key,value = line:match(kvregx)
if pattern ~= nil then
pattern = vim.regex(
ec_glob2regpat(pattern)
)
end
return pattern, key, value
end
-- Gets the options in the file
local function ec_read(filename, path)
local options = {}
local pattern = nil
local f = io.open(path)
for line in f:lines() do
local p, k, v = ec_parse(line)
if p then
pattern = p
end
if k ~= nil and v ~= nil then
local in_pattern = (
pattern ~= nil
and pattern:match_str(filename)
)
if k == "root" then
options["root"] = (v == "true")
elseif in_pattern then
options[k] = v
end
end
end
return options
end
-- Apply editorconfig to buffer
local function ec_apply(bufnr, options)
for k,v in pairs(options) do
if k == "indent_size" then
indent_size(vim.bo[bufnr], tonumber(v))
elseif k == "indent_style" then
indent_style(vim.bo[bufnr], v)
end
end
end
local function ec_init()
local b = vim.api.nvim_get_current_buf()
local buf = vim.bo[b]
local filename = buffer_filename()
local can_configure = (
buf.buftype == ""
and buf.modifiable
and filename ~= ""
)
if can_configure == false then
return nil
end
local options = {}
local editorconfigs = ec_find(filename)
for i,path in pairs(editorconfigs) do
options = vim.tbl_extend(
"force",
options,
ec_read(path_basename(filename), path)
)
end
ec_apply(b, options)
end
-- Hook up editorconfig events
local function ec_autocommands()
vim.api.nvim_create_autocmd(
{ "BufEnter" },
{
callback = ec_init,
group = augroups.editorconfig,
}
)
end
--------------------------------
-- public functions ------------
--------------------------------
-- Identify groups under cursor
--
-- It can be really helpful to
-- inspect the highlight groups
-- applied to the code under the
-- cursor but nvim doesn't
-- surface this information by
-- default. This function
-- generates a string for use
-- in the status line that lists
-- the groups.
function HighlightGroup()
local pos = vim.api.nvim_win_get_cursor(0)
local line = pos[1]
local col = pos[2] + 1
local synID = vim.fn.synID
local synIDattr = vim.fn.synIDattr
local synIDtrans = vim.fn.synIDtrans
local hi = synIDattr(
synID(line, col, true),
"name"
)
local trans = synIDattr(
synID(line, col, false),
"name"
)
local lo = synIDattr(
synIDtrans(synID(line, col, true)),
"name"
)
local groups = {}
local show_hi = hi and hi ~= ""
local show_trans = (
trans
and trans ~= ""
and trans ~= hi
)
local show_lo = (
lo
and lo ~= ""
and lo ~= trans
and lo ~= hi
)
if show_hi then
table.insert(
groups,
string.format("[%s]", hi)
)
end
if show_trans then
table.insert(
groups,
string.format("[%s]", trans)
)
end
if show_lo then
table.insert(
groups,
string.format("[%s]", lo)
)
end
return table.concat(groups, "")
end
-- Shorthand mode string
--
-- Instead of long form stuff
-- like "NORMAL" or "INSERT"
-- this returns the real short
-- ones that nvim provides like
-- "n" and "i".
function Mode()
return vim.api.nvim_get_mode().mode
end
-- Custom statusline string
function StatusLine()
local parts = {}
-- Apply the correct highlight
-- group to the line.
table.insert(
parts,
"%#StatusLine#"
)
-- Nothing in the left hand
-- side. It's nice if that
-- whole side of the screen is
-- just for code.
table.insert(
parts,
"%="
)
-- Nothing in the center.
-- Center-aligned stuff moves
-- around too much.
table.insert(
parts,
"%="
)
-- Show the highlight group
-- under the cursor. This
-- changes size very
-- dramatically as the cursor
-- moves. So positioning it
-- furthest to the left stops
-- it from shifting the layout
-- of the rest of the line.
table.insert(
parts,
"%{%v:lua.HighlightGroup()%}"
)
-- File status flags. These
-- change a lot so they can't
-- go on the right, but they
-- don't change as much as the
-- highlight group so they can
-- go right of that.
table.insert(
parts,
"%y%h%w%m%r"
)
-- Cursor position. This
-- changes almost continually
-- so to avoid thrashing the
-- layout it has enough padding
-- for three digits on both
-- axes.
table.insert(
parts,
"[%-3l,%-03c]"
)
-- Add the mode last. This
-- changes least often of
-- everything so putting it
-- next to the right-hand edge
-- won't shift the layout too
-- much.
table.insert(
parts,
"[%{%v:lua.Mode()%}] "
)
local line = table.concat(
parts,
""
)
return line
end
-- Custom TabLine string
function TabLine()
local bufn = vim.api.nvim_get_current_buf()
local tabnr = vim.fn.tabpagenr()
local tabmax = vim.fn.tabpagenr("$")
local bufnrs = tab_buffers(tabnr)
local parts = {}
-- Left-hand side
for _,b in pairs(bufnrs) do
local bpath = vim.api.nvim_buf_get_name(b)
local bname = path_basename(bpath)
local bgroup = "%#TabLineBuffer#"
if b == bufn then
bgroup = "%#TabLineBufferSel#"
end
table.insert(parts, bgroup)
table.insert(parts, " ")
table.insert(parts, bname)
table.insert(parts, " ")
end
table.insert(parts, "%#TabLineNC#")
table.insert(parts, " ")
table.insert(parts, "%=")
-- Right-hand side
if tabmax > 1 then
for t = 1,tabmax do
local tcwd = vim.fn.getcwd(-1, t)
local tname = path_basename(tcwd)
local tgroup = "%#TabLine#"
if t == tabnr then
tgroup = "%#TabLineSel#"
end
table.insert(parts, tgroup)
table.insert(parts, " ")
table.insert(parts, tname)
table.insert(parts, " ")
end
end
return table.concat(parts, "")
end
--------------------------------
-- ui --------------------------
--------------------------------
-- Terminal colors on
--
-- Without this none of the
-- colors work properly in the
-- terminal.
local function ui_enable_guicolors()
vim.o.termguicolors = true
end
-- Open new splits below
--
-- Most split usage involves
-- terminals and those benefit
-- from having the full screen
-- width.
local function ui_enable_splitbelow()
vim.o.splitbelow = true
end
-- No signcolumn LSP diagnostics
--
-- The inline ones are plenty
-- prominent on their own.
local function ui_hide_diagnostic_signs()
vim.lsp.handlers[
"textDocument/publishDiagnostics"
] = vim.lsp.with(
vim.lsp.diagnostic.on_publish_diagnostics,
{
signs = false,
}
)
end
-- Hide the startup tildes
local function ui_hide_tildes()
vim.opt.fillchars:append {
eob = " ",
}
end
-- Highlight the cursor line
--
-- Even if the whole line
-- isn't being highlighted it's
-- useful to at least highlight
-- the current line number.
local function ui_show_cursorline()
vim.o.cursorline = true
end
-- Line numbers up to 9999
--
-- Setting a wide column for the
-- line numbers minimizes UI
-- movement when file lengths
-- change.
local function ui_show_numbers()
vim.o.number = true
vim.o.numberwidth = 4
end
-- Max out the signcolumn
--
-- Using both available columns
-- for this allows for a little
-- bit of whitespace between an
-- icon and the left of the
-- window.
local function ui_show_signcolumn()
vim.o.signcolumn = "yes:2"
end
local function ui_show_statusline()
vim.o.statusline = "%{%v:lua.StatusLine()%}"
end
-- Always show the tabline
--
-- There's always exactly one
-- tab open on startup and then
-- 99% of use cases involve
-- opening more. Hiding the
-- tabline therefore causes a
-- layout shift almost every
-- time so just always show it
-- so the layout is stable.
local function ui_show_tabline()
vim.o.showtabline = 2
vim.o.tabline = "%!v:lua.TabLine()"
end
--------------------------------
-- neovide ---------------------
--------------------------------
-- Use Iosevka
local function neovide_font()
vim.o.guifont = "Iosevka Term:h22"
end
-- Tweak animation timing
--
-- The defaults are a bit slow
-- in order to make the
-- animations prominent and
-- noticeable. These tweaked
-- numbers reduce the
-- distraction a little.
local function neovide_cursor()
vim.g.neovide_cursor_animation_length = 0.07
vim.g.neovide_cursor_trail_size = 0.7
end
-- Fix copypaste
--
-- See issue 113 on neovide's
-- GitHub repo for more context.
local function neovide_keymaps()
vim.api.nvim_set_keymap(
"",
"<D-v>",
"+p<CR>",
{
noremap = true,
silent = true,
}
)
vim.api.nvim_set_keymap(
"!",
"<D-v>",
"<C-R>+",
{
noremap = true,
silent = true,
}
)
vim.api.nvim_set_keymap(
"t",
"<D-v>",
"<C-R>+",
{
noremap = true,
silent = true,
}
)
vim.api.nvim_set_keymap(
"v",
"<D-v>",
"<C-R>+",
{
noremap = true,
silent = true,
}
)
end
local function init()
theme_light()
indent_defaults()
editor_keymaps()
buffer_keymaps()
tab_keymaps()
terminal_keymaps()
ui_enable_guicolors()
ui_enable_splitbelow()
ui_hide_diagnostic_signs()
ui_hide_tildes()
ui_show_cursorline()
ui_show_numbers()
ui_show_signcolumn()
ui_show_statusline()
ui_show_tabline()
ec_autocommands()
gist_autocommands()
lsp_autocommands()
terminal_autocommands()
if vim.g.neovide then
neovide_font()
neovide_cursor()
neovide_keymaps()
end
plugin_register("nvim-tree/nvim-tree.lua")
end
init()
--------------------------------
-- experimental ----------------
--------------------------------
local function xy(x, y)
local p = {
x = x or 0,
y = y or 0,
}
setmetatable(p, {
__add = function(p1, p2)
return xy(
p1.x + p2.x,
p1.y + p2.y
)
end,
__sub = function(p1, p2)
return xy(
p1.x - p2.x,
p1.y - p2.y
)
end,
__mul = function(p1, v)
return xy(
p1.x * v,
p1.y * v
)
end,
__div = function(p1, v)
return xy(
p1.x / v,
p1.y / v
)
end,
__lt = function(p1, p2)
return (
p1.x < p2.x and
p1.y < p2.y
)
end,
__gt = function(p1, p2)
return (
p1.x > p2.x and
p1.y > p2.y
)
end,
})
return p
end
local function center(p, c)
return (p - c) / 2
end
local function editor_size()
return xy(
vim.o.columns,
vim.o.lines
)
end
local function window_size()
return xy(
vim.api.nvim_win_get_width(0),
vim.api.nvim_win_get_height(0)
)
end
winid = nil
function popup_show()
local size = xy(80, 20)
local pos = xy(0,0)
local bufn = vim.api.nvim_get_current_buf()
winid = vim.api.nvim_open_win(
bufn,
false,
{
relative = "win",
width = size.x,
height = size.y,
row = pos.x,
col = pos.y,
}
)
end
function popup_hide()
if vim.api.nvim_win_is_valid(winid) then
vim.api.nvim_win_close(winid, true)
end
end
vim.keymap.set(
"n",
"<Space>w",
popup_hide
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment