Skip to content

Instantly share code, notes, and snippets.

@mvllow
Created October 6, 2022 22:09
Show Gist options
  • Save mvllow/e423a9be50d43a784d99626222d21b75 to your computer and use it in GitHub Desktop.
Save mvllow/e423a9be50d43a784d99626222d21b75 to your computer and use it in GitHub Desktop.
Custom statusline/winbar
local install_path = vim.fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim"
if vim.fn.empty(vim.fn.glob(install_path)) > 0 then
vim.fn.execute("!git clone --depth 1 https://github.com/wbthomason/packer.nvim " .. install_path)
end
require("packer").startup(function(use)
use("wbthomason/packer.nvim")
use({
"rose-pine/neovim",
as = "rose-pine",
config = function()
require("rose-pine").setup({ disable_italics = true })
vim.cmd("colorscheme rose-pine")
end,
})
use("editorconfig/editorconfig-vim")
use({
"nvim-treesitter/nvim-treesitter",
run = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = "all",
ignore_install = { "phpdoc" },
highlight = { enable = true },
})
end,
})
use({
"numToStr/Comment.nvim",
requires = "JoosepAlviste/nvim-ts-context-commentstring",
config = function()
require("nvim-treesitter.configs").setup({
context_commentstring = {
enable = true,
enable_autocmd = false,
},
})
require("Comment").setup({
pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(),
})
end,
})
use({
"nvim-telescope/telescope.nvim",
requires = "nvim-lua/plenary.nvim",
config = function()
require("telescope").setup({})
end,
})
use({
"neovim/nvim-lspconfig",
requires = {
"folke/lua-dev.nvim",
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
"WhoIsSethDaniel/mason-tool-installer.nvim",
},
config = function()
require("mason").setup()
require("mason-tool-installer").setup({})
local function on_attach(_, bufnr)
local opts = { buffer = bufnr, silent = true }
vim.keymap.set("i", "<c-k>", vim.lsp.buf.signature_help, opts)
vim.keymap.set("n", "<leader>a", vim.lsp.buf.code_action, opts)
vim.keymap.set("n", "<leader>r", vim.lsp.buf.rename, opts)
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
end
local capabilities = vim.lsp.protocol.make_client_capabilities()
-- Improve compatibility with nvim-cmp completions
local has_cmp_nvim_lsp, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp")
if has_cmp_nvim_lsp then
capabilities = cmp_nvim_lsp.update_capabilities(capabilities)
end
-- Automatically setup servers installed via `:MasonInstall`
require("mason-lspconfig").setup_handlers({
function(server_name)
if server_name == "sumneko_lua" then
require("lspconfig")[server_name].setup(require("lua-dev").setup({
on_attach = on_attach,
capabilities = capabilities,
}))
else
require("lspconfig")[server_name].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end
end,
})
end,
})
use({
"jose-elias-alvarez/null-ls.nvim",
requires = "nvim-lua/plenary.nvim",
config = function()
local null_ls = require("null-ls")
local sources = {
null_ls.builtins.formatting.stylua,
}
null_ls.setup({
sources = sources,
on_attach = function(client, bufnr)
if client.supports_method("textDocument/formatting") then
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
vim.lsp.buf.format({
bufnr = bufnr,
filter = function(lsp_client)
return lsp_client.name == "null-ls"
end,
})
end,
})
end
end,
})
end,
})
end)
-- Set diagnostic sign column symbols
local signs = { "Error", "Warn", "Hint", "Info" }
for _, type in pairs(signs) do
local hl = string.format("DiagnosticSign%s", type)
vim.fn.sign_define(hl, { text = "●", texthl = hl, numhl = hl })
end
M = {}
--- Re-evaluate function each time the statusline is redrawn.
--- @param fn string
function M.watch_fn(fn)
-- TODO: This seems unnecessarily hacky. Without it, however, messages
-- will not be updated.
--
-- `%{luaeval(...)}` re-evaluates each time the statusline is redrawn.
--
-- Ideally this wouldn't require a string version of our function, as
-- that makes typos more likely to go unnoticed and cause issues. Also,
-- using default variables within the passed function such as "%f" or
-- "%#SomeHighlightGroup#" no longer work with this method.
return '%<%{luaeval("' .. fn .. '")}'
end
--- LSP loading status
function M.lsp_status()
local messages = vim.lsp.util.get_progress_messages()
local mode = vim.api.nvim_get_mode().mode
-- If neovim is not in normal mode, or if there are no messages.
if mode ~= "n" or vim.tbl_isempty(messages) then
return ""
end
local percentage
local result = {}
for _, msg in pairs(messages) do
if msg.message then
table.insert(result, msg.title .. ": " .. msg.message)
else
table.insert(result, msg.title)
end
if msg.percentage then
percentage = math.max(percentage or 0, msg.percentage)
end
end
if percentage then
return string.format("%03d: %s", percentage, table.concat(result, ", "))
else
return table.concat(result, ", ")
end
end
--- Get first diagnostic message for the current line.
function M.diagnostic_message()
local severities = { "Error", "Warning" }
local diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
if not next(diagnostics) then
return ""
end
if not severities[diagnostics[1].severity] then
return " " .. diagnostics[1].message .. " "
else
return " " .. severities[diagnostics[1].severity] .. ": " .. diagnostics[1].message .. " "
end
end
--- Get number of errors for the current buffer.
function M.diagnostic_error_status()
local num_errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR })
if num_errors > 0 then
return "● " .. num_errors
end
return ""
end
--- Get number of warnings for the current buffer.
function M.diagnostic_warn_status()
local num_warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN })
if num_warnings > 0 then
return "● " .. num_warnings
end
return ""
end
--- Configure statusline sections.
function M.statusline()
local lsp_error_count = "%#DiagnosticError#" .. M.watch_fn("M.diagnostic_error_status()") .. "%*"
local lsp_warning_count = "%#DiagnosticWarn#" .. M.watch_fn("M.diagnostic_warn_status()") .. "%*"
local sections = {
-- TODO: `%M` causes a layout shift between saved and unsaved buffer states
-- "%f %M",
"%f",
-- TODO: Highlight groups can cause mismatching backgrounds
-- against the statusline.
lsp_error_count,
lsp_warning_count,
M.watch_fn("M.lsp_status()"),
"%=",
"%l:%c",
}
--- Combine all sections with padding between each section.
--- TODO: Empty sections, e.g. when there are 0 errors, create an extra space.
return " " .. table.concat(sections, " ") .. " "
end
--- Configure winbar sections
function M.winbar()
local sections = {
"%=",
"%#PMenu#" .. M.watch_fn("M.diagnostic_message()") .. "%*",
}
--- Combine all sections with padding between each section
--- TODO: Empty sections, e.g. when there are 0 errors, create an extra space
return " " .. table.concat(sections, " ") .. " "
end
vim.diagnostic.config({ virtual_text = false })
vim.opt.signcolumn = "yes"
vim.opt.statusline = M.statusline()
vim.opt.winbar = M.winbar()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment