fix up lsp stuff

This commit is contained in:
Christoph J. Scherr 2024-01-11 11:44:26 +01:00
parent 2f703ae7a5
commit 67f20cf69b
Signed by: cscherrNT
GPG Key ID: 8E2B45BC51A27EA7
76 changed files with 8070 additions and 162 deletions

View File

@ -0,0 +1,94 @@
-- This file is automatically loaded by lazyvim.config.init.
local function augroup(name)
return vim.api.nvim_create_augroup("lazyvim_" .. name, { clear = true })
end
-- Check if we need to reload the file when it changed
vim.api.nvim_create_autocmd({ "FocusGained", "TermClose", "TermLeave" }, {
group = augroup("checktime"),
command = "checktime",
})
-- Highlight on yank
vim.api.nvim_create_autocmd("TextYankPost", {
group = augroup("highlight_yank"),
callback = function()
vim.highlight.on_yank()
end,
})
-- resize splits if window got resized
vim.api.nvim_create_autocmd({ "VimResized" }, {
group = augroup("resize_splits"),
callback = function()
local current_tab = vim.fn.tabpagenr()
vim.cmd("tabdo wincmd =")
vim.cmd("tabnext " .. current_tab)
end,
})
-- go to last loc when opening a buffer
vim.api.nvim_create_autocmd("BufReadPost", {
group = augroup("last_loc"),
callback = function(event)
local exclude = { "gitcommit" }
local buf = event.buf
if vim.tbl_contains(exclude, vim.bo[buf].filetype) or vim.b[buf].lazyvim_last_loc then
return
end
vim.b[buf].lazyvim_last_loc = true
local mark = vim.api.nvim_buf_get_mark(buf, '"')
local lcount = vim.api.nvim_buf_line_count(buf)
if mark[1] > 0 and mark[1] <= lcount then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
})
-- close some filetypes with <q>
vim.api.nvim_create_autocmd("FileType", {
group = augroup("close_with_q"),
pattern = {
"PlenaryTestPopup",
"help",
"lspinfo",
"man",
"notify",
"qf",
"query",
"spectre_panel",
"startuptime",
"tsplayground",
"neotest-output",
"checkhealth",
"neotest-summary",
"neotest-output-panel",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true })
end,
})
-- wrap and check for spell in text filetypes
vim.api.nvim_create_autocmd("FileType", {
group = augroup("wrap_spell"),
pattern = { "gitcommit", "markdown" },
callback = function()
vim.opt_local.wrap = true
vim.opt_local.spell = true
end,
})
-- Auto create dir when saving a file, in case some intermediate directory does not exist
vim.api.nvim_create_autocmd({ "BufWritePre" }, {
group = augroup("auto_create_dir"),
callback = function(event)
if event.match:match("^%w%w+://") then
return
end
local file = vim.loop.fs_realpath(event.match) or event.match
vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p")
end,
})

283
lua/lazyvim/config/init.lua Normal file
View File

@ -0,0 +1,283 @@
local Util = require("lazyvim.util")
---@class LazyVimConfig: LazyVimOptions
local M = {}
M.version = "10.8.2" -- x-release-please-version
---@class LazyVimOptions
local defaults = {
-- colorscheme can be a string like `catppuccin` or a function that will load the colorscheme
---@type string|fun()
colorscheme = function()
require("tokyonight").load()
end,
-- load the default settings
defaults = {
autocmds = true, -- lazyvim.config.autocmds
keymaps = true, -- lazyvim.config.keymaps
-- lazyvim.config.options can't be configured here since that's loaded before lazyvim setup
-- if you want to disable loading options, add `package.loaded["lazyvim.config.options"] = true` to the top of your init.lua
},
news = {
-- When enabled, NEWS.md will be shown when changed.
-- This only contains big new features and breaking changes.
lazyvim = true,
-- Same but for Neovim's news.txt
neovim = false,
},
-- icons used by other plugins
-- stylua: ignore
icons = {
misc = {
dots = "󰇘",
},
dap = {
Stopped = { "󰁕 ", "DiagnosticWarn", "DapStoppedLine" },
Breakpoint = "",
BreakpointCondition = "",
BreakpointRejected = { "", "DiagnosticError" },
LogPoint = ".>",
},
diagnostics = {
Error = "",
Warn = "",
Hint = "",
Info = "",
},
git = {
added = "",
modified = "",
removed = "",
},
kinds = {
Array = "",
Boolean = "󰨙 ",
Class = "",
Codeium = "󰘦 ",
Color = "",
Control = "",
Collapsed = "",
Constant = "󰏿 ",
Constructor = "",
Copilot = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Folder = "",
Function = "󰊕 ",
Interface = "",
Key = "",
Keyword = "",
Method = "󰊕 ",
Module = "",
Namespace = "󰦮 ",
Null = "",
Number = "󰎠 ",
Object = "",
Operator = "",
Package = "",
Property = "",
Reference = "",
Snippet = "",
String = "",
Struct = "󰆼 ",
TabNine = "󰏚 ",
Text = "",
TypeParameter = "",
Unit = "",
Value = "",
Variable = "󰀫 ",
},
},
---@type table<string, string[]|boolean>?
kind_filter = {
default = {
"Class",
"Constructor",
"Enum",
"Field",
"Function",
"Interface",
"Method",
"Module",
"Namespace",
"Package",
"Property",
"Struct",
"Trait",
},
markdown = false,
help = false,
-- you can specify a different filter for each filetype
lua = {
"Class",
"Constructor",
"Enum",
"Field",
"Function",
"Interface",
"Method",
"Module",
"Namespace",
-- "Package", -- remove package since luals uses it for control flow structures
"Property",
"Struct",
"Trait",
},
},
}
M.json = {
version = 2,
data = {
version = nil, ---@type string?
news = {}, ---@type table<string, string>
extras = {}, ---@type string[]
},
}
function M.json.load()
local path = vim.fn.stdpath("config") .. "/lazyvim.json"
local f = io.open(path, "r")
if f then
local data = f:read("*a")
f:close()
local ok, json = pcall(vim.json.decode, data, { luanil = { object = true, array = true } })
if ok then
M.json.data = vim.tbl_deep_extend("force", M.json.data, json or {})
if M.json.data.version ~= M.json.version then
Util.json.migrate()
end
end
end
end
---@type LazyVimOptions
local options
---@param opts? LazyVimOptions
function M.setup(opts)
options = vim.tbl_deep_extend("force", defaults, opts or {}) or {}
-- autocmds can be loaded lazily when not opening a file
local lazy_autocmds = vim.fn.argc(-1) == 0
if not lazy_autocmds then
M.load("autocmds")
end
local group = vim.api.nvim_create_augroup("LazyVim", { clear = true })
vim.api.nvim_create_autocmd("User", {
group = group,
pattern = "VeryLazy",
callback = function()
if lazy_autocmds then
M.load("autocmds")
end
M.load("keymaps")
Util.format.setup()
Util.news.setup()
Util.root.setup()
vim.api.nvim_create_user_command("LazyExtras", function()
Util.extras.show()
end, { desc = "Manage LazyVim extras" })
end,
})
Util.track("colorscheme")
Util.try(function()
if type(M.colorscheme) == "function" then
M.colorscheme()
else
vim.cmd.colorscheme(M.colorscheme)
end
end, {
msg = "Could not load your colorscheme",
on_error = function(msg)
Util.error(msg)
vim.cmd.colorscheme("habamax")
end,
})
Util.track()
end
---@param buf? number
---@return string[]?
function M.get_kind_filter(buf)
buf = (buf == nil or buf == 0) and vim.api.nvim_get_current_buf() or buf
local ft = vim.bo[buf].filetype
if M.kind_filter == false then
return
end
if M.kind_filter[ft] == false then
return
end
---@diagnostic disable-next-line: return-type-mismatch
return type(M.kind_filter) == "table" and type(M.kind_filter.default) == "table" and M.kind_filter.default or nil
end
---@param name "autocmds" | "options" | "keymaps"
function M.load(name)
local function _load(mod)
if require("lazy.core.cache").find(mod)[1] then
Util.try(function()
require(mod)
end, { msg = "Failed loading " .. mod })
end
end
-- always load lazyvim, then user file
if M.defaults[name] or name == "options" then
_load("lazyvim.config." .. name)
end
_load("config." .. name)
if vim.bo.filetype == "lazy" then
-- HACK: LazyVim may have overwritten options of the Lazy ui, so reset this here
vim.cmd([[do VimResized]])
end
local pattern = "LazyVim" .. name:sub(1, 1):upper() .. name:sub(2)
vim.api.nvim_exec_autocmds("User", { pattern = pattern, modeline = false })
end
M.did_init = false
function M.init()
if M.did_init then
return
end
M.did_init = true
local plugin = require("lazy.core.config").spec.plugins.LazyVim
if plugin then
vim.opt.rtp:append(plugin.dir)
end
package.preload["lazyvim.plugins.lsp.format"] = function()
Util.deprecate([[require("lazyvim.plugins.lsp.format")]], [[require("lazyvim.util").format]])
return Util.format
end
-- delay notifications till vim.notify was replaced or after 500ms
require("lazyvim.util").lazy_notify()
-- load options here, before lazy init while sourcing plugin modules
-- this is needed to make sure options will be correctly applied
-- after installing missing plugins
M.load("options")
Util.plugin.setup()
M.json.load()
end
setmetatable(M, {
__index = function(_, key)
if options == nil then
return vim.deepcopy(defaults)[key]
end
---@cast options LazyVimConfig
return options[key]
end,
})
return M

View File

@ -0,0 +1,170 @@
-- This file is automatically loaded by lazyvim.config.init
local Util = require("lazyvim.util")
-- DO NOT USE THIS IN YOU OWN CONFIG!!
-- use `vim.keymap.set` instead
local map = Util.safe_keymap_set
-- better up/down
map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
map({ "n", "x" }, "<Down>", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
map({ "n", "x" }, "<Up>", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
-- Move to window using the <ctrl> hjkl keys
map("n", "<C-h>", "<C-w>h", { desc = "Go to left window", remap = true })
map("n", "<C-j>", "<C-w>j", { desc = "Go to lower window", remap = true })
map("n", "<C-k>", "<C-w>k", { desc = "Go to upper window", remap = true })
map("n", "<C-l>", "<C-w>l", { desc = "Go to right window", remap = true })
-- Resize window using <ctrl> arrow keys
map("n", "<C-Up>", "<cmd>resize +2<cr>", { desc = "Increase window height" })
map("n", "<C-Down>", "<cmd>resize -2<cr>", { desc = "Decrease window height" })
map("n", "<C-Left>", "<cmd>vertical resize -2<cr>", { desc = "Decrease window width" })
map("n", "<C-Right>", "<cmd>vertical resize +2<cr>", { desc = "Increase window width" })
-- Move Lines
map("n", "<A-j>", "<cmd>m .+1<cr>==", { desc = "Move down" })
map("n", "<A-k>", "<cmd>m .-2<cr>==", { desc = "Move up" })
map("i", "<A-j>", "<esc><cmd>m .+1<cr>==gi", { desc = "Move down" })
map("i", "<A-k>", "<esc><cmd>m .-2<cr>==gi", { desc = "Move up" })
map("v", "<A-j>", ":m '>+1<cr>gv=gv", { desc = "Move down" })
map("v", "<A-k>", ":m '<-2<cr>gv=gv", { desc = "Move up" })
-- buffers
map("n", "<S-h>", "<cmd>bprevious<cr>", { desc = "Prev buffer" })
map("n", "<S-l>", "<cmd>bnext<cr>", { desc = "Next buffer" })
map("n", "[b", "<cmd>bprevious<cr>", { desc = "Prev buffer" })
map("n", "]b", "<cmd>bnext<cr>", { desc = "Next buffer" })
map("n", "<leader>bb", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
map("n", "<leader>`", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
-- Clear search with <esc>
map({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Escape and clear hlsearch" })
-- Clear search, diff update and redraw
-- taken from runtime/lua/_editor.lua
map(
"n",
"<leader>ur",
"<Cmd>nohlsearch<Bar>diffupdate<Bar>normal! <C-L><CR>",
{ desc = "Redraw / clear hlsearch / diff update" }
)
-- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n
map("n", "n", "'Nn'[v:searchforward].'zv'", { expr = true, desc = "Next search result" })
map("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" })
map("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" })
map("n", "N", "'nN'[v:searchforward].'zv'", { expr = true, desc = "Prev search result" })
map("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" })
map("o", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" })
-- Add undo break-points
map("i", ",", ",<c-g>u")
map("i", ".", ".<c-g>u")
map("i", ";", ";<c-g>u")
-- save file
map({ "i", "x", "n", "s" }, "<C-s>", "<cmd>w<cr><esc>", { desc = "Save file" })
--keywordprg
map("n", "<leader>K", "<cmd>norm! K<cr>", { desc = "Keywordprg" })
-- better indenting
map("v", "<", "<gv")
map("v", ">", ">gv")
-- lazy
map("n", "<leader>l", "<cmd>Lazy<cr>", { desc = "Lazy" })
-- new file
map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
map("n", "<leader>xl", "<cmd>lopen<cr>", { desc = "Location List" })
map("n", "<leader>xq", "<cmd>copen<cr>", { desc = "Quickfix List" })
map("n", "[q", vim.cmd.cprev, { desc = "Previous quickfix" })
map("n", "]q", vim.cmd.cnext, { desc = "Next quickfix" })
-- formatting
map({ "n", "v" }, "<leader>cf", function()
Util.format({ force = true })
end, { desc = "Format" })
-- diagnostic
local diagnostic_goto = function(next, severity)
local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev
severity = severity and vim.diagnostic.severity[severity] or nil
return function()
go({ severity = severity })
end
end
map("n", "<leader>cd", vim.diagnostic.open_float, { desc = "Line Diagnostics" })
map("n", "]d", diagnostic_goto(true), { desc = "Next Diagnostic" })
map("n", "[d", diagnostic_goto(false), { desc = "Prev Diagnostic" })
map("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "Next Error" })
map("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "Prev Error" })
map("n", "]w", diagnostic_goto(true, "WARN"), { desc = "Next Warning" })
map("n", "[w", diagnostic_goto(false, "WARN"), { desc = "Prev Warning" })
-- stylua: ignore start
-- toggle options
map("n", "<leader>uf", function() Util.format.toggle() end, { desc = "Toggle auto format (global)" })
map("n", "<leader>uF", function() Util.format.toggle(true) end, { desc = "Toggle auto format (buffer)" })
map("n", "<leader>us", function() Util.toggle("spell") end, { desc = "Toggle Spelling" })
map("n", "<leader>uw", function() Util.toggle("wrap") end, { desc = "Toggle Word Wrap" })
map("n", "<leader>uL", function() Util.toggle("relativenumber") end, { desc = "Toggle Relative Line Numbers" })
map("n", "<leader>ul", function() Util.toggle.number() end, { desc = "Toggle Line Numbers" })
map("n", "<leader>ud", function() Util.toggle.diagnostics() end, { desc = "Toggle Diagnostics" })
local conceallevel = vim.o.conceallevel > 0 and vim.o.conceallevel or 3
map("n", "<leader>uc", function() Util.toggle("conceallevel", false, {0, conceallevel}) end, { desc = "Toggle Conceal" })
if vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint then
map( "n", "<leader>uh", function() Util.toggle.inlay_hints() end, { desc = "Toggle Inlay Hints" })
end
map("n", "<leader>uT", function() if vim.b.ts_highlight then vim.treesitter.stop() else vim.treesitter.start() end end, { desc = "Toggle Treesitter Highlight" })
-- lazygit
map("n", "<leader>gg", function() Util.terminal({ "lazygit" }, { cwd = Util.root(), esc_esc = false, ctrl_hjkl = false }) end, { desc = "Lazygit (root dir)" })
map("n", "<leader>gG", function() Util.terminal({ "lazygit" }, {esc_esc = false, ctrl_hjkl = false}) end, { desc = "Lazygit (cwd)" })
-- quit
map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit all" })
-- highlights under cursor
map("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
-- LazyVim Changelog
map("n", "<leader>L", function() Util.news.changelog() end, { desc = "LazyVim Changelog" })
-- floating terminal
local lazyterm = function() Util.terminal(nil, { cwd = Util.root() }) end
map("n", "<leader>ft", lazyterm, { desc = "Terminal (root dir)" })
map("n", "<leader>fT", function() Util.terminal() end, { desc = "Terminal (cwd)" })
map("n", "<c-/>", lazyterm, { desc = "Terminal (root dir)" })
map("n", "<c-_>", lazyterm, { desc = "which_key_ignore" })
-- Terminal Mappings
map("t", "<esc><esc>", "<c-\\><c-n>", { desc = "Enter Normal Mode" })
map("t", "<C-h>", "<cmd>wincmd h<cr>", { desc = "Go to left window" })
map("t", "<C-j>", "<cmd>wincmd j<cr>", { desc = "Go to lower window" })
map("t", "<C-k>", "<cmd>wincmd k<cr>", { desc = "Go to upper window" })
map("t", "<C-l>", "<cmd>wincmd l<cr>", { desc = "Go to right window" })
map("t", "<C-/>", "<cmd>close<cr>", { desc = "Hide Terminal" })
map("t", "<c-_>", "<cmd>close<cr>", { desc = "which_key_ignore" })
-- windows
map("n", "<leader>ww", "<C-W>p", { desc = "Other window", remap = true })
map("n", "<leader>wd", "<C-W>c", { desc = "Delete window", remap = true })
map("n", "<leader>w-", "<C-W>s", { desc = "Split window below", remap = true })
map("n", "<leader>w|", "<C-W>v", { desc = "Split window right", remap = true })
map("n", "<leader>-", "<C-W>s", { desc = "Split window below", remap = true })
map("n", "<leader>|", "<C-W>v", { desc = "Split window right", remap = true })
-- tabs
map("n", "<leader><tab>l", "<cmd>tablast<cr>", { desc = "Last Tab" })
map("n", "<leader><tab>f", "<cmd>tabfirst<cr>", { desc = "First Tab" })
map("n", "<leader><tab><tab>", "<cmd>tabnew<cr>", { desc = "New Tab" })
map("n", "<leader><tab>]", "<cmd>tabnext<cr>", { desc = "Next Tab" })
map("n", "<leader><tab>d", "<cmd>tabclose<cr>", { desc = "Close Tab" })
map("n", "<leader><tab>[", "<cmd>tabprevious<cr>", { desc = "Previous Tab" })

View File

@ -0,0 +1,93 @@
-- This file is automatically loaded by plugins.core
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
-- Enable LazyVim auto format
vim.g.autoformat = true
-- LazyVim root dir detection
-- Each entry can be:
-- * the name of a detector function like `lsp` or `cwd`
-- * a pattern or array of patterns like `.git` or `lua`.
-- * a function with signature `function(buf) -> string|string[]`
vim.g.root_spec = { "lsp", { ".git", "lua" }, "cwd" }
local opt = vim.opt
opt.autowrite = true -- Enable auto write
opt.clipboard = "unnamedplus" -- Sync with system clipboard
opt.completeopt = "menu,menuone,noselect"
opt.conceallevel = 3 -- Hide * markup for bold and italic
opt.confirm = true -- Confirm to save changes before exiting modified buffer
opt.cursorline = true -- Enable highlighting of the current line
opt.expandtab = true -- Use spaces instead of tabs
opt.formatoptions = "jcroqlnt" -- tcqj
opt.grepformat = "%f:%l:%c:%m"
opt.grepprg = "rg --vimgrep"
opt.ignorecase = true -- Ignore case
opt.inccommand = "nosplit" -- preview incremental substitute
opt.laststatus = 3 -- global statusline
opt.list = true -- Show some invisible characters (tabs...
opt.mouse = "a" -- Enable mouse mode
opt.number = true -- Print line number
opt.pumblend = 10 -- Popup blend
opt.pumheight = 10 -- Maximum number of entries in a popup
opt.relativenumber = true -- Relative line numbers
opt.scrolloff = 4 -- Lines of context
opt.sessionoptions = { "buffers", "curdir", "tabpages", "winsize", "help", "globals", "skiprtp", "folds" }
opt.shiftround = true -- Round indent
opt.shiftwidth = 2 -- Size of an indent
opt.shortmess:append({ W = true, I = true, c = true, C = true })
opt.showmode = false -- Dont show mode since we have a statusline
opt.sidescrolloff = 8 -- Columns of context
opt.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time
opt.smartcase = true -- Don't ignore case with capitals
opt.smartindent = true -- Insert indents automatically
opt.spelllang = { "en" }
opt.splitbelow = true -- Put new windows below current
opt.splitkeep = "screen"
opt.splitright = true -- Put new windows right of current
opt.tabstop = 2 -- Number of spaces tabs count for
opt.termguicolors = true -- True color support
opt.timeoutlen = 300
opt.undofile = true
opt.undolevels = 10000
opt.updatetime = 200 -- Save swap file and trigger CursorHold
opt.virtualedit = "block" -- Allow cursor to move where there is no text in visual block mode
opt.wildmode = "longest:full,full" -- Command-line completion mode
opt.winminwidth = 5 -- Minimum window width
opt.wrap = false -- Disable line wrap
opt.fillchars = {
foldopen = "",
foldclose = "",
-- fold = "⸱",
fold = " ",
foldsep = " ",
diff = "",
eob = " ",
}
if vim.fn.has("nvim-0.10") == 1 then
opt.smoothscroll = true
end
-- Folding
vim.opt.foldlevel = 99
vim.opt.foldtext = "v:lua.require'lazyvim.util'.ui.foldtext()"
if vim.fn.has("nvim-0.9.0") == 1 then
vim.opt.statuscolumn = [[%!v:lua.require'lazyvim.util'.ui.statuscolumn()]]
end
-- HACK: causes freezes on <= 0.9, so only enable on >= 0.10 for now
if vim.fn.has("nvim-0.10") == 1 then
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "v:lua.require'lazyvim.util'.ui.foldexpr()"
else
vim.opt.foldmethod = "indent"
end
vim.o.formatexpr = "v:lua.require'lazyvim.util'.format.formatexpr()"
-- Fix markdown indentation settings
vim.g.markdown_recommended_style = 0

38
lua/lazyvim/health.lua Normal file
View File

@ -0,0 +1,38 @@
local M = {}
local start = vim.health.start or vim.health.report_start
local ok = vim.health.ok or vim.health.report_ok
local warn = vim.health.warn or vim.health.report_warn
local error = vim.health.error or vim.health.report_error
function M.check()
start("LazyVim")
if vim.fn.has("nvim-0.9.0") == 1 then
ok("Using Neovim >= 0.9.0")
else
error("Neovim >= 0.9.0 is required")
end
for _, cmd in ipairs({ "git", "rg", { "fd", "fdfind" }, "lazygit" }) do
local name = type(cmd) == "string" and cmd or vim.inspect(cmd)
local commands = type(cmd) == "string" and { cmd } or cmd
---@cast commands string[]
local found = false
for _, c in ipairs(commands) do
if vim.fn.executable(c) == 1 then
name = c
found = true
end
end
if found then
ok(("`%s` is installed"):format(name))
else
warn(("`%s` is not installed"):format(name))
end
end
end
return M

8
lua/lazyvim/init.lua Normal file
View File

@ -0,0 +1,8 @@
local M = {}
---@param opts? LazyVimConfig
function M.setup(opts)
require("lazyvim.config").setup(opts)
end
return M

View File

@ -0,0 +1,256 @@
return {
-- snippets
{
"L3MON4D3/LuaSnip",
build = (not jit.os:find("Windows"))
and "echo 'NOTE: jsregexp is optional, so not a big deal if it fails to build'; make install_jsregexp"
or nil,
dependencies = {
"rafamadriz/friendly-snippets",
config = function()
require("luasnip.loaders.from_vscode").lazy_load()
end,
},
opts = {
history = true,
delete_check_events = "TextChanged",
},
-- stylua: ignore
keys = {
{
"<tab>",
function()
return require("luasnip").jumpable(1) and "<Plug>luasnip-jump-next" or "<tab>"
end,
expr = true, silent = true, mode = "i",
},
{ "<tab>", function() require("luasnip").jump(1) end, mode = "s" },
{ "<s-tab>", function() require("luasnip").jump(-1) end, mode = { "i", "s" } },
},
},
-- auto completion
{
"hrsh7th/nvim-cmp",
version = false, -- last release is way too old
event = "InsertEnter",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"saadparwaiz1/cmp_luasnip",
},
opts = function()
vim.api.nvim_set_hl(0, "CmpGhostText", { link = "Comment", default = true })
local cmp = require("cmp")
local defaults = require("cmp.config.default")()
return {
completion = {
completeopt = "menu,menuone,noinsert",
},
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<C-n>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-p>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-b>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
["<S-CR>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
["<C-CR>"] = function(fallback)
cmp.abort()
fallback()
end,
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "path" },
}, {
{ name = "buffer" },
}),
formatting = {
format = function(_, item)
local icons = require("lazyvim.config").icons.kinds
if icons[item.kind] then
item.kind = icons[item.kind] .. item.kind
end
return item
end,
},
experimental = {
ghost_text = {
hl_group = "CmpGhostText",
},
},
sorting = defaults.sorting,
}
end,
---@param opts cmp.ConfigSchema
config = function(_, opts)
for _, source in ipairs(opts.sources) do
source.group_index = source.group_index or 1
end
require("cmp").setup(opts)
end,
},
-- auto pairs
{
"echasnovski/mini.pairs",
event = "VeryLazy",
opts = {},
keys = {
{
"<leader>up",
function()
local Util = require("lazy.core.util")
vim.g.minipairs_disable = not vim.g.minipairs_disable
if vim.g.minipairs_disable then
Util.warn("Disabled auto pairs", { title = "Option" })
else
Util.info("Enabled auto pairs", { title = "Option" })
end
end,
desc = "Toggle auto pairs",
},
},
},
-- Fast and feature-rich surround actions. For text that includes
-- surrounding characters like brackets or quotes, this allows you
-- to select the text inside, change or modify the surrounding characters,
-- and more.
{
"echasnovski/mini.surround",
keys = function(_, keys)
-- Populate the keys based on the user's options
local plugin = require("lazy.core.config").spec.plugins["mini.surround"]
local opts = require("lazy.core.plugin").values(plugin, "opts", false)
local mappings = {
{ opts.mappings.add, desc = "Add surrounding", mode = { "n", "v" } },
{ opts.mappings.delete, desc = "Delete surrounding" },
{ opts.mappings.find, desc = "Find right surrounding" },
{ opts.mappings.find_left, desc = "Find left surrounding" },
{ opts.mappings.highlight, desc = "Highlight surrounding" },
{ opts.mappings.replace, desc = "Replace surrounding" },
{ opts.mappings.update_n_lines, desc = "Update `MiniSurround.config.n_lines`" },
}
mappings = vim.tbl_filter(function(m)
return m[1] and #m[1] > 0
end, mappings)
return vim.list_extend(mappings, keys)
end,
opts = {
mappings = {
add = "gsa", -- Add surrounding in Normal and Visual modes
delete = "gsd", -- Delete surrounding
find = "gsf", -- Find surrounding (to the right)
find_left = "gsF", -- Find surrounding (to the left)
highlight = "gsh", -- Highlight surrounding
replace = "gsr", -- Replace surrounding
update_n_lines = "gsn", -- Update `n_lines`
},
},
},
-- comments
{
"JoosepAlviste/nvim-ts-context-commentstring",
lazy = true,
opts = {
enable_autocmd = false,
},
},
{
"echasnovski/mini.comment",
event = "VeryLazy",
opts = {
options = {
custom_commentstring = function()
return require("ts_context_commentstring.internal").calculate_commentstring() or vim.bo.commentstring
end,
},
},
},
-- Better text-objects
{
"echasnovski/mini.ai",
-- keys = {
-- { "a", mode = { "x", "o" } },
-- { "i", mode = { "x", "o" } },
-- },
event = "VeryLazy",
opts = function()
local ai = require("mini.ai")
return {
n_lines = 500,
custom_textobjects = {
o = ai.gen_spec.treesitter({
a = { "@block.outer", "@conditional.outer", "@loop.outer" },
i = { "@block.inner", "@conditional.inner", "@loop.inner" },
}, {}),
f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}),
c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }, {}),
t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" },
},
}
end,
config = function(_, opts)
require("mini.ai").setup(opts)
-- register all text objects with which-key
require("lazyvim.util").on_load("which-key.nvim", function()
---@type table<string, string|table>
local i = {
[" "] = "Whitespace",
['"'] = 'Balanced "',
["'"] = "Balanced '",
["`"] = "Balanced `",
["("] = "Balanced (",
[")"] = "Balanced ) including white-space",
[">"] = "Balanced > including white-space",
["<lt>"] = "Balanced <",
["]"] = "Balanced ] including white-space",
["["] = "Balanced [",
["}"] = "Balanced } including white-space",
["{"] = "Balanced {",
["?"] = "User Prompt",
_ = "Underscore",
a = "Argument",
b = "Balanced ), ], }",
c = "Class",
f = "Function",
o = "Block, conditional, loop",
q = "Quote `, \", '",
t = "Tag",
}
local a = vim.deepcopy(i)
for k, v in pairs(a) do
a[k] = v:gsub(" including.*", "")
end
local ic = vim.deepcopy(i)
local ac = vim.deepcopy(a)
for key, name in pairs({ n = "Next", l = "Last" }) do
i[key] = vim.tbl_extend("force", { name = "Inside " .. name .. " textobject" }, ic)
a[key] = vim.tbl_extend("force", { name = "Around " .. name .. " textobject" }, ac)
end
require("which-key").register({
mode = { "o", "x" },
i = i,
a = a,
})
end)
end,
},
}

View File

@ -0,0 +1,53 @@
return {
-- tokyonight
{
"folke/tokyonight.nvim",
lazy = true,
opts = { style = "moon" },
},
-- catppuccin
{
"catppuccin/nvim",
lazy = true,
name = "catppuccin",
opts = {
integrations = {
aerial = true,
alpha = true,
cmp = true,
dashboard = true,
flash = true,
gitsigns = true,
headlines = true,
illuminate = true,
indent_blankline = { enabled = true },
leap = true,
lsp_trouble = true,
mason = true,
markdown = true,
mini = true,
native_lsp = {
enabled = true,
underlines = {
errors = { "undercurl" },
hints = { "undercurl" },
warnings = { "undercurl" },
information = { "undercurl" },
},
},
navic = { enabled = true, custom_bg = "lualine" },
neotest = true,
neotree = true,
noice = true,
notify = true,
semantic_tokens = true,
telescope = true,
treesitter = true,
treesitter_context = true,
which_key = true,
},
},
},
}

View File

@ -0,0 +1,496 @@
local Util = require("lazyvim.util")
return {
-- file explorer
{
"nvim-neo-tree/neo-tree.nvim",
branch = "v3.x",
cmd = "Neotree",
keys = {
{
"<leader>fe",
function()
require("neo-tree.command").execute({ toggle = true, dir = Util.root() })
end,
desc = "Explorer NeoTree (root dir)",
},
{
"<leader>fE",
function()
require("neo-tree.command").execute({ toggle = true, dir = vim.loop.cwd() })
end,
desc = "Explorer NeoTree (cwd)",
},
{ "<leader>e", "<leader>fe", desc = "Explorer NeoTree (root dir)", remap = true },
{ "<leader>E", "<leader>fE", desc = "Explorer NeoTree (cwd)", remap = true },
{
"<leader>ge",
function()
require("neo-tree.command").execute({ source = "git_status", toggle = true })
end,
desc = "Git explorer",
},
{
"<leader>be",
function()
require("neo-tree.command").execute({ source = "buffers", toggle = true })
end,
desc = "Buffer explorer",
},
},
deactivate = function()
vim.cmd([[Neotree close]])
end,
init = function()
if vim.fn.argc(-1) == 1 then
local stat = vim.loop.fs_stat(vim.fn.argv(0))
if stat and stat.type == "directory" then
require("neo-tree")
end
end
end,
opts = {
sources = { "filesystem", "buffers", "git_status", "document_symbols" },
open_files_do_not_replace_types = { "terminal", "Trouble", "trouble", "qf", "Outline" },
filesystem = {
bind_to_cwd = false,
follow_current_file = { enabled = true },
use_libuv_file_watcher = true,
},
window = {
mappings = {
["<space>"] = "none",
},
},
default_component_configs = {
indent = {
with_expanders = true, -- if nil and file nesting is enabled, will enable expanders
expander_collapsed = "",
expander_expanded = "",
expander_highlight = "NeoTreeExpander",
},
},
},
config = function(_, opts)
local function on_move(data)
Util.lsp.on_rename(data.source, data.destination)
end
local events = require("neo-tree.events")
opts.event_handlers = opts.event_handlers or {}
vim.list_extend(opts.event_handlers, {
{ event = events.FILE_MOVED, handler = on_move },
{ event = events.FILE_RENAMED, handler = on_move },
})
require("neo-tree").setup(opts)
vim.api.nvim_create_autocmd("TermClose", {
pattern = "*lazygit",
callback = function()
if package.loaded["neo-tree.sources.git_status"] then
require("neo-tree.sources.git_status").refresh()
end
end,
})
end,
},
-- search/replace in multiple files
{
"nvim-pack/nvim-spectre",
build = false,
cmd = "Spectre",
opts = { open_cmd = "noswapfile vnew" },
-- stylua: ignore
keys = {
{ "<leader>sr", function() require("spectre").open() end, desc = "Replace in files (Spectre)" },
},
},
-- Fuzzy finder.
-- The default key bindings to find files will use Telescope's
-- `find_files` or `git_files` depending on whether the
-- directory is a git repo.
{
"nvim-telescope/telescope.nvim",
cmd = "Telescope",
version = false, -- telescope did only one release, so use HEAD for now
dependencies = {
{
"nvim-telescope/telescope-fzf-native.nvim",
build = "make",
enabled = vim.fn.executable("make") == 1,
config = function()
Util.on_load("telescope.nvim", function()
require("telescope").load_extension("fzf")
end)
end,
},
},
keys = {
{
"<leader>,",
"<cmd>Telescope buffers sort_mru=true sort_lastused=true<cr>",
desc = "Switch Buffer",
},
{ "<leader>/", Util.telescope("live_grep"), desc = "Grep (root dir)" },
{ "<leader>:", "<cmd>Telescope command_history<cr>", desc = "Command History" },
{ "<leader><space>", Util.telescope("files"), desc = "Find Files (root dir)" },
-- find
{ "<leader>fb", "<cmd>Telescope buffers sort_mru=true sort_lastused=true<cr>", desc = "Buffers" },
{ "<leader>fc", Util.telescope.config_files(), desc = "Find Config File" },
{ "<leader>ff", Util.telescope("files"), desc = "Find Files (root dir)" },
{ "<leader>fF", Util.telescope("files", { cwd = false }), desc = "Find Files (cwd)" },
{ "<leader>fr", "<cmd>Telescope oldfiles<cr>", desc = "Recent" },
{ "<leader>fR", Util.telescope("oldfiles", { cwd = vim.loop.cwd() }), desc = "Recent (cwd)" },
-- git
{ "<leader>gc", "<cmd>Telescope git_commits<CR>", desc = "commits" },
{ "<leader>gs", "<cmd>Telescope git_status<CR>", desc = "status" },
-- search
{ '<leader>s"', "<cmd>Telescope registers<cr>", desc = "Registers" },
{ "<leader>sa", "<cmd>Telescope autocommands<cr>", desc = "Auto Commands" },
{ "<leader>sb", "<cmd>Telescope current_buffer_fuzzy_find<cr>", desc = "Buffer" },
{ "<leader>sc", "<cmd>Telescope command_history<cr>", desc = "Command History" },
{ "<leader>sC", "<cmd>Telescope commands<cr>", desc = "Commands" },
{ "<leader>sd", "<cmd>Telescope diagnostics bufnr=0<cr>", desc = "Document diagnostics" },
{ "<leader>sD", "<cmd>Telescope diagnostics<cr>", desc = "Workspace diagnostics" },
{ "<leader>sg", Util.telescope("live_grep"), desc = "Grep (root dir)" },
{ "<leader>sG", Util.telescope("live_grep", { cwd = false }), desc = "Grep (cwd)" },
{ "<leader>sh", "<cmd>Telescope help_tags<cr>", desc = "Help Pages" },
{ "<leader>sH", "<cmd>Telescope highlights<cr>", desc = "Search Highlight Groups" },
{ "<leader>sk", "<cmd>Telescope keymaps<cr>", desc = "Key Maps" },
{ "<leader>sM", "<cmd>Telescope man_pages<cr>", desc = "Man Pages" },
{ "<leader>sm", "<cmd>Telescope marks<cr>", desc = "Jump to Mark" },
{ "<leader>so", "<cmd>Telescope vim_options<cr>", desc = "Options" },
{ "<leader>sR", "<cmd>Telescope resume<cr>", desc = "Resume" },
{ "<leader>sw", Util.telescope("grep_string", { word_match = "-w" }), desc = "Word (root dir)" },
{ "<leader>sW", Util.telescope("grep_string", { cwd = false, word_match = "-w" }), desc = "Word (cwd)" },
{ "<leader>sw", Util.telescope("grep_string"), mode = "v", desc = "Selection (root dir)" },
{ "<leader>sW", Util.telescope("grep_string", { cwd = false }), mode = "v", desc = "Selection (cwd)" },
{ "<leader>uC", Util.telescope("colorscheme", { enable_preview = true }), desc = "Colorscheme with preview" },
{
"<leader>ss",
function()
require("telescope.builtin").lsp_document_symbols({
symbols = require("lazyvim.config").get_kind_filter(),
})
end,
desc = "Goto Symbol",
},
{
"<leader>sS",
function()
require("telescope.builtin").lsp_dynamic_workspace_symbols({
symbols = require("lazyvim.config").get_kind_filter(),
})
end,
desc = "Goto Symbol (Workspace)",
},
},
opts = function()
local actions = require("telescope.actions")
local open_with_trouble = function(...)
return require("trouble.providers.telescope").open_with_trouble(...)
end
local open_selected_with_trouble = function(...)
return require("trouble.providers.telescope").open_selected_with_trouble(...)
end
local find_files_no_ignore = function()
local action_state = require("telescope.actions.state")
local line = action_state.get_current_line()
Util.telescope("find_files", { no_ignore = true, default_text = line })()
end
local find_files_with_hidden = function()
local action_state = require("telescope.actions.state")
local line = action_state.get_current_line()
Util.telescope("find_files", { hidden = true, default_text = line })()
end
return {
defaults = {
prompt_prefix = "",
selection_caret = "",
-- open files in the first window that is an actual file.
-- use the current window if no other window is available.
get_selection_window = function()
local wins = vim.api.nvim_list_wins()
table.insert(wins, 1, vim.api.nvim_get_current_win())
for _, win in ipairs(wins) do
local buf = vim.api.nvim_win_get_buf(win)
if vim.bo[buf].buftype == "" then
return win
end
end
return 0
end,
mappings = {
i = {
["<c-t>"] = open_with_trouble,
["<a-t>"] = open_selected_with_trouble,
["<a-i>"] = find_files_no_ignore,
["<a-h>"] = find_files_with_hidden,
["<C-Down>"] = actions.cycle_history_next,
["<C-Up>"] = actions.cycle_history_prev,
["<C-f>"] = actions.preview_scrolling_down,
["<C-b>"] = actions.preview_scrolling_up,
},
n = {
["q"] = actions.close,
},
},
},
}
end,
},
-- Flash enhances the built-in search functionality by showing labels
-- at the end of each match, letting you quickly jump to a specific
-- location.
{
"folke/flash.nvim",
event = "VeryLazy",
vscode = true,
---@type Flash.Config
opts = {},
-- stylua: ignore
keys = {
{ "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" },
{ "S", mode = { "n", "o", "x" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" },
{ "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" },
{ "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" },
{ "<c-s>", mode = { "c" }, function() require("flash").toggle() end, desc = "Toggle Flash Search" },
},
},
-- Flash Telescope config
{
"nvim-telescope/telescope.nvim",
optional = true,
opts = function(_, opts)
if not Util.has("flash.nvim") then
return
end
local function flash(prompt_bufnr)
require("flash").jump({
pattern = "^",
label = { after = { 0, 0 } },
search = {
mode = "search",
exclude = {
function(win)
return vim.bo[vim.api.nvim_win_get_buf(win)].filetype ~= "TelescopeResults"
end,
},
},
action = function(match)
local picker = require("telescope.actions.state").get_current_picker(prompt_bufnr)
picker:set_selection(match.pos[1] - 1)
end,
})
end
opts.defaults = vim.tbl_deep_extend("force", opts.defaults or {}, {
mappings = { n = { s = flash }, i = { ["<c-s>"] = flash } },
})
end,
},
-- which-key helps you remember key bindings by showing a popup
-- with the active keybindings of the command you started typing.
{
"folke/which-key.nvim",
event = "VeryLazy",
opts = {
plugins = { spelling = true },
defaults = {
mode = { "n", "v" },
["g"] = { name = "+goto" },
["gs"] = { name = "+surround" },
["]"] = { name = "+next" },
["["] = { name = "+prev" },
["<leader><tab>"] = { name = "+tabs" },
["<leader>b"] = { name = "+buffer" },
["<leader>c"] = { name = "+code" },
["<leader>f"] = { name = "+file/find" },
["<leader>g"] = { name = "+git" },
["<leader>gh"] = { name = "+hunks" },
["<leader>q"] = { name = "+quit/session" },
["<leader>s"] = { name = "+search" },
["<leader>u"] = { name = "+ui" },
["<leader>w"] = { name = "+windows" },
["<leader>x"] = { name = "+diagnostics/quickfix" },
},
},
config = function(_, opts)
local wk = require("which-key")
wk.setup(opts)
wk.register(opts.defaults)
end,
},
-- git signs highlights text that has changed since the list
-- git commit, and also lets you interactively stage & unstage
-- hunks in a commit.
{
"lewis6991/gitsigns.nvim",
event = "LazyFile",
opts = {
signs = {
add = { text = "" },
change = { text = "" },
delete = { text = "" },
topdelete = { text = "" },
changedelete = { text = "" },
untracked = { text = "" },
},
on_attach = function(buffer)
local gs = package.loaded.gitsigns
local function map(mode, l, r, desc)
vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc })
end
-- stylua: ignore start
map("n", "]h", gs.next_hunk, "Next Hunk")
map("n", "[h", gs.prev_hunk, "Prev Hunk")
map({ "n", "v" }, "<leader>ghs", ":Gitsigns stage_hunk<CR>", "Stage Hunk")
map({ "n", "v" }, "<leader>ghr", ":Gitsigns reset_hunk<CR>", "Reset Hunk")
map("n", "<leader>ghS", gs.stage_buffer, "Stage Buffer")
map("n", "<leader>ghu", gs.undo_stage_hunk, "Undo Stage Hunk")
map("n", "<leader>ghR", gs.reset_buffer, "Reset Buffer")
map("n", "<leader>ghp", gs.preview_hunk, "Preview Hunk")
map("n", "<leader>ghb", function() gs.blame_line({ full = true }) end, "Blame Line")
map("n", "<leader>ghd", gs.diffthis, "Diff This")
map("n", "<leader>ghD", function() gs.diffthis("~") end, "Diff This ~")
map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns Select Hunk")
end,
},
},
-- Automatically highlights other instances of the word under your cursor.
-- This works with LSP, Treesitter, and regexp matching to find the other
-- instances.
{
"RRethy/vim-illuminate",
event = "LazyFile",
opts = {
delay = 200,
large_file_cutoff = 2000,
large_file_overrides = {
providers = { "lsp" },
},
},
config = function(_, opts)
require("illuminate").configure(opts)
local function map(key, dir, buffer)
vim.keymap.set("n", key, function()
require("illuminate")["goto_" .. dir .. "_reference"](false)
end, { desc = dir:sub(1, 1):upper() .. dir:sub(2) .. " Reference", buffer = buffer })
end
map("]]", "next")
map("[[", "prev")
-- also set it after loading ftplugins, since a lot overwrite [[ and ]]
vim.api.nvim_create_autocmd("FileType", {
callback = function()
local buffer = vim.api.nvim_get_current_buf()
map("]]", "next", buffer)
map("[[", "prev", buffer)
end,
})
end,
keys = {
{ "]]", desc = "Next Reference" },
{ "[[", desc = "Prev Reference" },
},
},
-- buffer remove
{
"echasnovski/mini.bufremove",
keys = {
{
"<leader>bd",
function()
local bd = require("mini.bufremove").delete
if vim.bo.modified then
local choice = vim.fn.confirm(("Save changes to %q?"):format(vim.fn.bufname()), "&Yes\n&No\n&Cancel")
if choice == 1 then -- Yes
vim.cmd.write()
bd(0)
elseif choice == 2 then -- No
bd(0, true)
end
else
bd(0)
end
end,
desc = "Delete Buffer",
},
-- stylua: ignore
{ "<leader>bD", function() require("mini.bufremove").delete(0, true) end, desc = "Delete Buffer (Force)" },
},
},
-- better diagnostics list and others
{
"folke/trouble.nvim",
cmd = { "TroubleToggle", "Trouble" },
opts = { use_diagnostic_signs = true },
keys = {
{ "<leader>xx", "<cmd>TroubleToggle document_diagnostics<cr>", desc = "Document Diagnostics (Trouble)" },
{ "<leader>xX", "<cmd>TroubleToggle workspace_diagnostics<cr>", desc = "Workspace Diagnostics (Trouble)" },
{ "<leader>xL", "<cmd>TroubleToggle loclist<cr>", desc = "Location List (Trouble)" },
{ "<leader>xQ", "<cmd>TroubleToggle quickfix<cr>", desc = "Quickfix List (Trouble)" },
{
"[q",
function()
if require("trouble").is_open() then
require("trouble").previous({ skip_groups = true, jump = true })
else
local ok, err = pcall(vim.cmd.cprev)
if not ok then
vim.notify(err, vim.log.levels.ERROR)
end
end
end,
desc = "Previous trouble/quickfix item",
},
{
"]q",
function()
if require("trouble").is_open() then
require("trouble").next({ skip_groups = true, jump = true })
else
local ok, err = pcall(vim.cmd.cnext)
if not ok then
vim.notify(err, vim.log.levels.ERROR)
end
end
end,
desc = "Next trouble/quickfix item",
},
},
},
-- Finds and lists all of the TODO, HACK, BUG, etc comment
-- in your project and loads them into a browsable list.
{
"folke/todo-comments.nvim",
cmd = { "TodoTrouble", "TodoTelescope" },
event = "LazyFile",
config = true,
-- stylua: ignore
keys = {
{ "]t", function() require("todo-comments").jump_next() end, desc = "Next todo comment" },
{ "[t", function() require("todo-comments").jump_prev() end, desc = "Previous todo comment" },
{ "<leader>xt", "<cmd>TodoTrouble<cr>", desc = "Todo (Trouble)" },
{ "<leader>xT", "<cmd>TodoTrouble keywords=TODO,FIX,FIXME<cr>", desc = "Todo/Fix/Fixme (Trouble)" },
{ "<leader>st", "<cmd>TodoTelescope<cr>", desc = "Todo" },
{ "<leader>sT", "<cmd>TodoTelescope keywords=TODO,FIX,FIXME<cr>", desc = "Todo/Fix/Fixme" },
},
},
}

View File

@ -0,0 +1,33 @@
return {
-- codeium cmp source
{
"nvim-cmp",
dependencies = {
-- codeium
{
"Exafunction/codeium.nvim",
cmd = "Codeium",
build = ":Codeium Auth",
opts = {},
},
},
---@param opts cmp.ConfigSchema
opts = function(_, opts)
table.insert(opts.sources, 1, {
name = "codeium",
group_index = 1,
priority = 100,
})
end,
},
{
"nvim-lualine/lualine.nvim",
optional = true,
event = "VeryLazy",
opts = function(_, opts)
table.insert(opts.sections.lualine_x, 2, require("lazyvim.util").lualine.cmp_source("codeium"))
end,
},
}

View File

@ -0,0 +1,86 @@
return {
-- copilot
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
build = ":Copilot auth",
opts = {
suggestion = { enabled = false },
panel = { enabled = false },
filetypes = {
markdown = true,
help = true,
},
},
},
{
"nvim-lualine/lualine.nvim",
optional = true,
event = "VeryLazy",
opts = function(_, opts)
local Util = require("lazyvim.util")
local colors = {
[""] = Util.ui.fg("Special"),
["Normal"] = Util.ui.fg("Special"),
["Warning"] = Util.ui.fg("DiagnosticError"),
["InProgress"] = Util.ui.fg("DiagnosticWarn"),
}
table.insert(opts.sections.lualine_x, 2, {
function()
local icon = require("lazyvim.config").icons.kinds.Copilot
local status = require("copilot.api").status.data
return icon .. (status.message or "")
end,
cond = function()
if not package.loaded["copilot"] then
return
end
local ok, clients = pcall(require("lazyvim.util").lsp.get_clients, { name = "copilot", bufnr = 0 })
if not ok then
return false
end
return ok and #clients > 0
end,
color = function()
if not package.loaded["copilot"] then
return
end
local status = require("copilot.api").status.data
return colors[status.status] or colors[""]
end,
})
end,
},
-- copilot cmp source
{
"nvim-cmp",
dependencies = {
{
"zbirenbaum/copilot-cmp",
dependencies = "copilot.lua",
opts = {},
config = function(_, opts)
local copilot_cmp = require("copilot_cmp")
copilot_cmp.setup(opts)
-- attach cmp source whenever copilot attaches
-- fixes lazy-loading issues with the copilot cmp source
require("lazyvim.util").lsp.on_attach(function(client)
if client.name == "copilot" then
copilot_cmp._on_insert_enter({})
end
end)
end,
},
},
---@param opts cmp.ConfigSchema
opts = function(_, opts)
table.insert(opts.sources, 1, {
name = "copilot",
group_index = 1,
priority = 100,
})
end,
},
}

View File

@ -0,0 +1,51 @@
local Util = require("lazyvim.util")
return {
-- Tabnine cmp source
{
"nvim-cmp",
dependencies = {
{
"tzachar/cmp-tabnine",
build = {
Util.is_win() and "pwsh -noni .\\install.ps1" or "./install.sh",
":CmpTabnineHub",
},
dependencies = "hrsh7th/nvim-cmp",
opts = {
max_lines = 1000,
max_num_results = 3,
sort = true,
},
config = function(_, opts)
require("cmp_tabnine.config"):setup(opts)
end,
},
},
---@param opts cmp.ConfigSchema
opts = function(_, opts)
table.insert(opts.sources, 1, {
name = "cmp_tabnine",
group_index = 1,
priority = 100,
})
opts.formatting.format = Util.inject.args(opts.formatting.format, function(entry, item)
-- Hide percentage in the menu
if entry.source.name == "cmp_tabnine" then
item.menu = ""
end
end)
end,
},
-- Show TabNine status in lualine
{
"nvim-lualine/lualine.nvim",
optional = true,
event = "VeryLazy",
opts = function(_, opts)
local icon = require("lazyvim.config").icons.kinds.TabNine
table.insert(opts.sections.lualine_x, 2, require("lazyvim.util").lualine.cmp_source("cmp_tabnine", icon))
end,
},
}

View File

@ -0,0 +1,32 @@
return {
-- better yank/paste
{
"gbprod/yanky.nvim",
dependencies = { { "kkharji/sqlite.lua", enabled = not jit.os:find("Windows") } },
opts = {
highlight = { timer = 250 },
ring = { storage = jit.os:find("Windows") and "shada" or "sqlite" },
},
keys = {
-- stylua: ignore
{ "<leader>p", function() require("telescope").extensions.yank_history.yank_history({ }) end, desc = "Open Yank History" },
{ "y", "<Plug>(YankyYank)", mode = { "n", "x" }, desc = "Yank text" },
{ "p", "<Plug>(YankyPutAfter)", mode = { "n", "x" }, desc = "Put yanked text after cursor" },
{ "P", "<Plug>(YankyPutBefore)", mode = { "n", "x" }, desc = "Put yanked text before cursor" },
{ "gp", "<Plug>(YankyGPutAfter)", mode = { "n", "x" }, desc = "Put yanked text after selection" },
{ "gP", "<Plug>(YankyGPutBefore)", mode = { "n", "x" }, desc = "Put yanked text before selection" },
{ "[y", "<Plug>(YankyCycleForward)", desc = "Cycle forward through yank history" },
{ "]y", "<Plug>(YankyCycleBackward)", desc = "Cycle backward through yank history" },
{ "]p", "<Plug>(YankyPutIndentAfterLinewise)", desc = "Put indented after cursor (linewise)" },
{ "[p", "<Plug>(YankyPutIndentBeforeLinewise)", desc = "Put indented before cursor (linewise)" },
{ "]P", "<Plug>(YankyPutIndentAfterLinewise)", desc = "Put indented after cursor (linewise)" },
{ "[P", "<Plug>(YankyPutIndentBeforeLinewise)", desc = "Put indented before cursor (linewise)" },
{ ">p", "<Plug>(YankyPutIndentAfterShiftRight)", desc = "Put and indent right" },
{ "<p", "<Plug>(YankyPutIndentAfterShiftLeft)", desc = "Put and indent left" },
{ ">P", "<Plug>(YankyPutIndentBeforeShiftRight)", desc = "Put before and indent right" },
{ "<P", "<Plug>(YankyPutIndentBeforeShiftLeft)", desc = "Put before and indent left" },
{ "=p", "<Plug>(YankyPutAfterFilter)", desc = "Put after applying a filter" },
{ "=P", "<Plug>(YankyPutBeforeFilter)", desc = "Put before applying a filter" },
},
},
}

View File

@ -0,0 +1,118 @@
---@param config {args?:string[]|fun():string[]?}
local function get_args(config)
local args = type(config.args) == "function" and (config.args() or {}) or config.args or {}
config = vim.deepcopy(config)
---@cast args string[]
config.args = function()
local new_args = vim.fn.input("Run with args: ", table.concat(args, " ")) --[[@as string]]
return vim.split(vim.fn.expand(new_args) --[[@as string]], " ")
end
return config
end
return {
"mfussenegger/nvim-dap",
dependencies = {
-- fancy UI for the debugger
{
"rcarriga/nvim-dap-ui",
-- stylua: ignore
keys = {
{ "<leader>du", function() require("dapui").toggle({ }) end, desc = "Dap UI" },
{ "<leader>de", function() require("dapui").eval() end, desc = "Eval", mode = {"n", "v"} },
},
opts = {},
config = function(_, opts)
-- setup dap config by VsCode launch.json file
-- require("dap.ext.vscode").load_launchjs()
local dap = require("dap")
local dapui = require("dapui")
dapui.setup(opts)
dap.listeners.after.event_initialized["dapui_config"] = function()
dapui.open({})
end
dap.listeners.before.event_terminated["dapui_config"] = function()
dapui.close({})
end
dap.listeners.before.event_exited["dapui_config"] = function()
dapui.close({})
end
end,
},
-- virtual text for the debugger
{
"theHamsta/nvim-dap-virtual-text",
opts = {},
},
-- which key integration
{
"folke/which-key.nvim",
optional = true,
opts = {
defaults = {
["<leader>d"] = { name = "+debug" },
},
},
},
-- mason.nvim integration
{
"jay-babu/mason-nvim-dap.nvim",
dependencies = "mason.nvim",
cmd = { "DapInstall", "DapUninstall" },
opts = {
-- Makes a best effort to setup the various debuggers with
-- reasonable debug configurations
automatic_installation = true,
-- You can provide additional configuration to the handlers,
-- see mason-nvim-dap README for more information
handlers = {},
-- You'll need to check that you have the required things installed
-- online, please don't ask me how to install them :)
ensure_installed = {
-- Update this to ensure that you have the debuggers for the langs you want
},
},
},
},
-- stylua: ignore
keys = {
{ "<leader>dB", function() require("dap").set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Breakpoint Condition" },
{ "<leader>db", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" },
{ "<leader>dc", function() require("dap").continue() end, desc = "Continue" },
{ "<leader>da", function() require("dap").continue({ before = get_args }) end, desc = "Run with Args" },
{ "<leader>dC", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" },
{ "<leader>dg", function() require("dap").goto_() end, desc = "Go to line (no execute)" },
{ "<leader>di", function() require("dap").step_into() end, desc = "Step Into" },
{ "<leader>dj", function() require("dap").down() end, desc = "Down" },
{ "<leader>dk", function() require("dap").up() end, desc = "Up" },
{ "<leader>dl", function() require("dap").run_last() end, desc = "Run Last" },
{ "<leader>do", function() require("dap").step_out() end, desc = "Step Out" },
{ "<leader>dO", function() require("dap").step_over() end, desc = "Step Over" },
{ "<leader>dp", function() require("dap").pause() end, desc = "Pause" },
{ "<leader>dr", function() require("dap").repl.toggle() end, desc = "Toggle REPL" },
{ "<leader>ds", function() require("dap").session() end, desc = "Session" },
{ "<leader>dt", function() require("dap").terminate() end, desc = "Terminate" },
{ "<leader>dw", function() require("dap.ui.widgets").hover() end, desc = "Widgets" },
},
config = function()
local Config = require("lazyvim.config")
vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Visual" })
for name, sign in pairs(Config.icons.dap) do
sign = type(sign) == "table" and sign or { sign }
vim.fn.sign_define(
"Dap" .. name,
{ text = sign[1], texthl = sign[2] or "DiagnosticInfo", linehl = sign[3], numhl = sign[3] }
)
end
end,
}

View File

@ -0,0 +1,43 @@
return {
"mfussenegger/nvim-dap",
dependencies = {
{
"jbyuki/one-small-step-for-vimkind",
-- stylua: ignore
config = function()
local dap = require("dap")
dap.adapters.nlua = function(callback, conf)
local adapter = {
type = "server",
host = conf.host or "127.0.0.1",
port = conf.port or 8086,
}
if conf.start_neovim then
local dap_run = dap.run
dap.run = function(c)
adapter.port = c.port
adapter.host = c.host
end
require("osv").run_this()
dap.run = dap_run
end
callback(adapter)
end
dap.configurations.lua = {
{
type = "nlua",
request = "attach",
name = "Run this file",
start_neovim = {},
},
{
type = "nlua",
request = "attach",
name = "Attach to running Neovim instance (port = 8086)",
port = 8086,
},
}
end,
},
},
}

View File

@ -0,0 +1,123 @@
local Config = require("lazyvim.config")
local Util = require("lazyvim.util")
return {
desc = "Aerial Symbol Browser",
{
"stevearc/aerial.nvim",
event = "LazyFile",
opts = function()
local icons = vim.deepcopy(Config.icons.kinds)
-- HACK: fix lua's weird choice for `Package` for control
-- structures like if/else/for/etc.
icons.lua = { Package = icons.Control }
---@type table<string, string[]>|false
local filter_kind = false
if Config.kind_filter then
filter_kind = assert(vim.deepcopy(Config.kind_filter))
filter_kind._ = filter_kind.default
filter_kind.default = nil
end
local opts = {
attach_mode = "global",
backends = { "lsp", "treesitter", "markdown", "man" },
show_guides = true,
layout = {
resize_to_content = false,
win_opts = {
winhl = "Normal:NormalFloat,FloatBorder:NormalFloat,SignColumn:SignColumnSB",
signcolumn = "yes",
statuscolumn = " ",
},
},
icons = icons,
filter_kind = filter_kind,
-- stylua: ignore
guides = {
mid_item = "├╴",
last_item = "└╴",
nested_top = "",
whitespace = " ",
},
}
return opts
end,
keys = {
{ "<leader>cs", "<cmd>AerialToggle<cr>", desc = "Aerial (Symbols)" },
},
},
-- Telescope integration
{
"nvim-telescope/telescope.nvim",
optional = true,
opts = function()
Util.on_load("telescope.nvim", function()
require("telescope").load_extension("aerial")
end)
end,
keys = {
{
"<leader>ss",
"<cmd>Telescope aerial<cr>",
desc = "Goto Symbol (Aerial)",
},
},
},
-- edgy integration
{
"folke/edgy.nvim",
optional = true,
opts = function(_, opts)
local edgy_idx = Util.plugin.extra_idx("ui.edgy")
local aerial_idx = Util.plugin.extra_idx("editor.aerial")
if edgy_idx and edgy_idx > aerial_idx then
Util.warn("The `edgy.nvim` extra must be **imported** before the `aerial.nvim` extra to work properly.", {
title = "LazyVim",
})
end
opts.right = opts.right or {}
table.insert(opts.right, {
title = "Aerial",
ft = "aerial",
pinned = true,
open = "AerialOpen",
})
end,
},
-- lualine integration
{
"nvim-lualine/lualine.nvim",
optional = true,
opts = function(_, opts)
table.insert(opts.sections.lualine_c, {
"aerial",
sep = " ", -- separator between symbols
sep_icon = "", -- separator between icon and symbol
-- The number of symbols to render top-down. In order to render only 'N' last
-- symbols, negative numbers may be supplied. For instance, 'depth = -1' can
-- be used in order to render only current symbol.
depth = 5,
-- When 'dense' mode is on, icons are not rendered near their symbols. Only
-- a single icon that represents the kind of current symbol is rendered at
-- the beginning of status line.
dense = false,
-- The separator to be used to separate symbols in dense mode.
dense_sep = ".",
-- Color the symbol icons.
colored = true,
})
end,
},
}

View File

@ -0,0 +1,56 @@
return {
-- disable flash
{ "folke/flash.nvim", enabled = false, optional = true },
-- easily jump to any location and enhanced f/t motions for Leap
{
"ggandor/flit.nvim",
enabled = true,
keys = function()
---@type LazyKeys[]
local ret = {}
for _, key in ipairs({ "f", "F", "t", "T" }) do
ret[#ret + 1] = { key, mode = { "n", "x", "o" }, desc = key }
end
return ret
end,
opts = { labeled_modes = "nx" },
},
{
"ggandor/leap.nvim",
enabled = true,
keys = {
{ "s", mode = { "n", "x", "o" }, desc = "Leap forward to" },
{ "S", mode = { "n", "x", "o" }, desc = "Leap backward to" },
{ "gs", mode = { "n", "x", "o" }, desc = "Leap from windows" },
},
config = function(_, opts)
local leap = require("leap")
for k, v in pairs(opts) do
leap.opts[k] = v
end
leap.add_default_mappings(true)
vim.keymap.del({ "x", "o" }, "x")
vim.keymap.del({ "x", "o" }, "X")
end,
},
-- rename surround mappings from gs to gz to prevent conflict with leap
{
"echasnovski/mini.surround",
opts = {
mappings = {
add = "gza", -- Add surrounding in Normal and Visual modes
delete = "gzd", -- Delete surrounding
find = "gzf", -- Find surrounding (to the right)
find_left = "gzF", -- Find surrounding (to the left)
highlight = "gzh", -- Highlight surrounding
replace = "gzr", -- Replace surrounding
update_n_lines = "gzn", -- Update `n_lines`
},
},
},
-- makes some plugins dot-repeatable like leap
{ "tpope/vim-repeat", event = "VeryLazy" },
}

View File

@ -0,0 +1,64 @@
return {
"echasnovski/mini.files",
opts = {
windows = {
preview = true,
width_focus = 30,
width_preview = 30,
},
options = {
-- Whether to use for editing directories
-- Disabled by default in LazyVim because neo-tree is used for that
use_as_default_explorer = false,
},
},
keys = {
{
"<leader>fm",
function()
require("mini.files").open(vim.api.nvim_buf_get_name(0), true)
end,
desc = "Open mini.files (directory of current file)",
},
{
"<leader>fM",
function()
require("mini.files").open(vim.loop.cwd(), true)
end,
desc = "Open mini.files (cwd)",
},
},
config = function(_, opts)
require("mini.files").setup(opts)
local show_dotfiles = true
local filter_show = function(fs_entry)
return true
end
local filter_hide = function(fs_entry)
return not vim.startswith(fs_entry.name, ".")
end
local toggle_dotfiles = function()
show_dotfiles = not show_dotfiles
local new_filter = show_dotfiles and filter_show or filter_hide
require("mini.files").refresh({ content = { filter = new_filter } })
end
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesBufferCreate",
callback = function(args)
local buf_id = args.data.buf_id
-- Tweak left-hand side of mapping to your liking
vim.keymap.set("n", "g.", toggle_dotfiles, { buffer = buf_id })
end,
})
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesActionRename",
callback = function(event)
require("lazyvim.util").lsp.on_rename(event.data.from, event.data.to)
end,
})
end,
}

View File

@ -0,0 +1,42 @@
return {
-- lsp symbol navigation for lualine. This shows where
-- in the code structure you are - within functions, classes,
-- etc - in the statusline.
{
"SmiteshP/nvim-navic",
lazy = true,
init = function()
vim.g.navic_silence = true
require("lazyvim.util").lsp.on_attach(function(client, buffer)
if client.supports_method("textDocument/documentSymbol") then
require("nvim-navic").attach(client, buffer)
end
end)
end,
opts = function()
return {
separator = " ",
highlight = true,
depth_limit = 5,
icons = require("lazyvim.config").icons.kinds,
lazy_update_context = true,
}
end,
},
-- lualine integration
{
"nvim-lualine/lualine.nvim",
optional = true,
opts = function(_, opts)
table.insert(opts.sections.lualine_c, {
function()
return require("nvim-navic").get_location()
end,
cond = function()
return package.loaded["nvim-navic"] and require("nvim-navic").is_available()
end,
})
end,
},
}

View File

@ -0,0 +1,61 @@
local Util = require("lazyvim.util")
return {
{
"simrat39/symbols-outline.nvim",
keys = { { "<leader>cs", "<cmd>SymbolsOutline<cr>", desc = "Symbols Outline" } },
cmd = "SymbolsOutline",
opts = function()
local Config = require("lazyvim.config")
local defaults = require("symbols-outline.config").defaults
local opts = {
symbols = {},
symbol_blacklist = {},
}
local filter = Config.kind_filter
if type(filter) == "table" then
filter = filter.default
if type(filter) == "table" then
for kind, symbol in pairs(defaults.symbols) do
opts.symbols[kind] = {
icon = Config.icons.kinds[kind] or symbol.icon,
hl = symbol.hl,
}
if not vim.tbl_contains(filter, kind) then
table.insert(opts.symbol_blacklist, kind)
end
end
end
end
return opts
end,
},
-- edgy integration
{
"folke/edgy.nvim",
optional = true,
opts = function(_, opts)
local edgy_idx = Util.plugin.extra_idx("ui.edgy")
local symbols_idx = Util.plugin.extra_idx("editor.symbols-outline")
if edgy_idx and edgy_idx > symbols_idx then
Util.warn(
"The `edgy.nvim` extra must be **imported** before the `symbols-outline.nvim` extra to work properly.",
{
title = "LazyVim",
}
)
end
opts.right = opts.right or {}
table.insert(opts.right, {
title = "Symbols Outline",
ft = "Outline",
pinned = true,
open = "SymbolsOutline",
})
end,
},
}

View File

@ -0,0 +1,26 @@
return {
{
"williamboman/mason.nvim",
opts = function(_, opts)
table.insert(opts.ensure_installed, "black")
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = opts.sources or {}
table.insert(opts.sources, nls.builtins.formatting.black)
end,
},
{
"stevearc/conform.nvim",
optional = true,
opts = {
formatters_by_ft = {
["python"] = { "black" },
},
},
},
}

View File

@ -0,0 +1,41 @@
return {
{
"williamboman/mason.nvim",
opts = function(_, opts)
table.insert(opts.ensure_installed, "prettier")
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = opts.sources or {}
table.insert(opts.sources, nls.builtins.formatting.prettier)
end,
},
{
"stevearc/conform.nvim",
optional = true,
opts = {
formatters_by_ft = {
["javascript"] = { "prettier" },
["javascriptreact"] = { "prettier" },
["typescript"] = { "prettier" },
["typescriptreact"] = { "prettier" },
["vue"] = { "prettier" },
["css"] = { "prettier" },
["scss"] = { "prettier" },
["less"] = { "prettier" },
["html"] = { "prettier" },
["json"] = { "prettier" },
["jsonc"] = { "prettier" },
["yaml"] = { "prettier" },
["markdown"] = { "prettier" },
["markdown.mdx"] = { "prettier" },
["graphql"] = { "prettier" },
["handlebars"] = { "prettier" },
},
},
},
}

View File

@ -0,0 +1,154 @@
return {
-- Add C/C++ to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "c", "cpp" })
end
end,
},
{
"p00f/clangd_extensions.nvim",
lazy = true,
config = function() end,
opts = {
inlay_hints = {
inline = false,
},
ast = {
--These require codicons (https://github.com/microsoft/vscode-codicons)
role_icons = {
type = "",
declaration = "",
expression = "",
specifier = "",
statement = "",
["template argument"] = "",
},
kind_icons = {
Compound = "",
Recovery = "",
TranslationUnit = "",
PackExpansion = "",
TemplateTypeParm = "",
TemplateTemplateParm = "",
TemplateParamObject = "",
},
},
},
},
-- Correctly setup lspconfig for clangd 🚀
{
"neovim/nvim-lspconfig",
opts = {
servers = {
-- Ensure mason installs the server
clangd = {
keys = {
{ "<leader>cR", "<cmd>ClangdSwitchSourceHeader<cr>", desc = "Switch Source/Header (C/C++)" },
},
root_dir = function(fname)
return require("lspconfig.util").root_pattern(
"Makefile",
"configure.ac",
"configure.in",
"config.h.in",
"meson.build",
"meson_options.txt",
"build.ninja"
)(fname) or require("lspconfig.util").root_pattern("compile_commands.json", "compile_flags.txt")(
fname
) or require("lspconfig.util").find_git_ancestor(fname)
end,
capabilities = {
offsetEncoding = { "utf-16" },
},
cmd = {
"clangd",
"--background-index",
"--clang-tidy",
"--header-insertion=iwyu",
"--completion-style=detailed",
"--function-arg-placeholders",
"--fallback-style=llvm",
},
init_options = {
usePlaceholders = true,
completeUnimported = true,
clangdFileStatus = true,
},
},
},
setup = {
clangd = function(_, opts)
local clangd_ext_opts = require("lazyvim.util").opts("clangd_extensions.nvim")
require("clangd_extensions").setup(vim.tbl_deep_extend("force", clangd_ext_opts or {}, { server = opts }))
return false
end,
},
},
},
{
"nvim-cmp",
opts = function(_, opts)
table.insert(opts.sorting.comparators, 1, require("clangd_extensions.cmp_scores"))
end,
},
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
-- Ensure C/C++ debugger is installed
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "codelldb" })
end
end,
},
opts = function()
local dap = require("dap")
if not dap.adapters["codelldb"] then
require("dap").adapters["codelldb"] = {
type = "server",
host = "localhost",
port = "${port}",
executable = {
command = "codelldb",
args = {
"--port",
"${port}",
},
},
}
end
for _, lang in ipairs({ "c", "cpp" }) do
dap.configurations[lang] = {
{
type = "codelldb",
request = "launch",
name = "Launch file",
program = function()
return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file")
end,
cwd = "${workspaceFolder}",
},
{
type = "codelldb",
request = "attach",
name = "Attach to process",
processId = require("dap.utils").pick_process,
cwd = "${workspaceFolder}",
},
}
end
end,
},
}

View File

@ -0,0 +1,49 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "cmake" })
end
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.diagnostics.cmake_lint,
})
end,
},
{
"mfussenegger/nvim-lint",
optional = true,
opts = {
linters_by_ft = {
cmake = { "cmakelint" },
},
},
},
{
"mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "cmakelang", "cmakelint" })
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
neocmake = {},
},
},
},
{
"Civitasv/cmake-tools.nvim",
opts = {},
event = "LazyFile",
},
}

View File

@ -0,0 +1,45 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "dockerfile" })
end
end,
},
{
"mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "hadolint" })
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.diagnostics.hadolint,
})
end,
},
{
"mfussenegger/nvim-lint",
optional = true,
opts = {
linters_by_ft = {
dockerfile = { "hadolint" },
},
},
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
dockerls = {},
docker_compose_language_service = {},
},
},
},
}

View File

@ -0,0 +1,57 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, {
"elixir",
"heex",
"eex",
})
end,
},
{
"williamboman/mason.nvim",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, {
"elixir-ls",
})
end,
},
{
"nvim-neotest/neotest",
optional = true,
dependencies = {
"jfpedroza/neotest-elixir",
},
opts = {
adapters = {
["neotest-elixir"] = {},
},
},
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
if vim.fn.executable("credo") == 0 then
return
end
local nls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.diagnostics.credo,
})
end,
},
{
"mfussenegger/nvim-lint",
optional = true,
opts = function(_, opts)
if vim.fn.executable("credo") == 0 then
return
end
opts.linters_by_ft = {
elixir = { "credo" },
}
end,
},
}

View File

@ -0,0 +1,155 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, {
"go",
"gomod",
"gowork",
"gosum",
})
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
gopls = {
keys = {
-- Workaround for the lack of a DAP strategy in neotest-go: https://github.com/nvim-neotest/neotest-go/issues/12
{ "<leader>td", "<cmd>lua require('dap-go').debug_test()<CR>", desc = "Debug Nearest (Go)" },
},
settings = {
gopls = {
gofumpt = true,
codelenses = {
gc_details = false,
generate = true,
regenerate_cgo = true,
run_govulncheck = true,
test = true,
tidy = true,
upgrade_dependency = true,
vendor = true,
},
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
analyses = {
fieldalignment = true,
nilness = true,
unusedparams = true,
unusedwrite = true,
useany = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" },
semanticTokens = true,
},
},
},
},
setup = {
gopls = function(_, opts)
-- workaround for gopls not supporting semanticTokensProvider
-- https://github.com/golang/go/issues/54531#issuecomment-1464982242
require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "gopls" then
if not client.server_capabilities.semanticTokensProvider then
local semantic = client.config.capabilities.textDocument.semanticTokens
client.server_capabilities.semanticTokensProvider = {
full = true,
legend = {
tokenTypes = semantic.tokenTypes,
tokenModifiers = semantic.tokenModifiers,
},
range = true,
}
end
end
end)
-- end workaround
end,
},
},
},
-- Ensure Go tools are installed
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "goimports", "gofumpt" })
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
dependencies = {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "gomodifytags", "impl" })
end,
},
},
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.code_actions.gomodifytags,
nls.builtins.code_actions.impl,
nls.builtins.formatting.goimports,
nls.builtins.formatting.gofumpt,
})
end,
},
{
"stevearc/conform.nvim",
optional = true,
opts = {
formatters_by_ft = {
go = { "goimports", "gofumpt" },
},
},
},
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "delve" })
end,
},
{
"leoluz/nvim-dap-go",
config = true,
},
},
},
{
"nvim-neotest/neotest",
optional = true,
dependencies = {
"nvim-neotest/neotest-go",
},
opts = {
adapters = {
["neotest-go"] = {
-- Here we can set options for neotest-go, e.g.
-- args = { "-tags=integration" }
},
},
},
},
}

View File

@ -0,0 +1,227 @@
local Util = require("lazyvim.util")
-- This is the same as in lspconfig.server_configurations.jdtls, but avoids
-- needing to require that when this module loads.
local java_filetypes = { "java" }
-- Utility function to extend or override a config table, similar to the way
-- that Plugin.opts works.
---@param config table
---@param custom function | table | nil
local function extend_or_override(config, custom, ...)
if type(custom) == "function" then
config = custom(config, ...) or config
elseif custom then
config = vim.tbl_deep_extend("force", config, custom) --[[@as table]]
end
return config
end
return {
-- Add java to treesitter.
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "java" })
end,
},
-- Ensure java debugger and test packages are installed.
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "java-test", "java-debug-adapter" })
end,
},
},
},
-- Configure nvim-lspconfig to install the server automatically via mason, but
-- defer actually starting it to our configuration of nvim-jtdls below.
{
"neovim/nvim-lspconfig",
opts = {
-- make sure mason installs the server
servers = {
jdtls = {},
},
setup = {
jdtls = function()
return true -- avoid duplicate servers
end,
},
},
},
-- Set up nvim-jdtls to attach to java files.
{
"mfussenegger/nvim-jdtls",
dependencies = { "folke/which-key.nvim" },
ft = java_filetypes,
opts = function()
return {
-- How to find the root dir for a given filename. The default comes from
-- lspconfig which provides a function specifically for java projects.
root_dir = require("lspconfig.server_configurations.jdtls").default_config.root_dir,
-- How to find the project name for a given root dir.
project_name = function(root_dir)
return root_dir and vim.fs.basename(root_dir)
end,
-- Where are the config and workspace dirs for a project?
jdtls_config_dir = function(project_name)
return vim.fn.stdpath("cache") .. "/jdtls/" .. project_name .. "/config"
end,
jdtls_workspace_dir = function(project_name)
return vim.fn.stdpath("cache") .. "/jdtls/" .. project_name .. "/workspace"
end,
-- How to run jdtls. This can be overridden to a full java command-line
-- if the Python wrapper script doesn't suffice.
cmd = { vim.fn.exepath("jdtls") },
full_cmd = function(opts)
local fname = vim.api.nvim_buf_get_name(0)
local root_dir = opts.root_dir(fname)
local project_name = opts.project_name(root_dir)
local cmd = vim.deepcopy(opts.cmd)
if project_name then
vim.list_extend(cmd, {
"-configuration",
opts.jdtls_config_dir(project_name),
"-data",
opts.jdtls_workspace_dir(project_name),
})
end
return cmd
end,
-- These depend on nvim-dap, but can additionally be disabled by setting false here.
dap = { hotcodereplace = "auto", config_overrides = {} },
test = true,
}
end,
config = function()
local opts = Util.opts("nvim-jdtls") or {}
-- Find the extra bundles that should be passed on the jdtls command-line
-- if nvim-dap is enabled with java debug/test.
local mason_registry = require("mason-registry")
local bundles = {} ---@type string[]
if opts.dap and Util.has("nvim-dap") and mason_registry.is_installed("java-debug-adapter") then
local java_dbg_pkg = mason_registry.get_package("java-debug-adapter")
local java_dbg_path = java_dbg_pkg:get_install_path()
local jar_patterns = {
java_dbg_path .. "/extension/server/com.microsoft.java.debug.plugin-*.jar",
}
-- java-test also depends on java-debug-adapter.
if opts.test and mason_registry.is_installed("java-test") then
local java_test_pkg = mason_registry.get_package("java-test")
local java_test_path = java_test_pkg:get_install_path()
vim.list_extend(jar_patterns, {
java_test_path .. "/extension/server/*.jar",
})
end
for _, jar_pattern in ipairs(jar_patterns) do
for _, bundle in ipairs(vim.split(vim.fn.glob(jar_pattern), "\n")) do
table.insert(bundles, bundle)
end
end
end
local function attach_jdtls()
local fname = vim.api.nvim_buf_get_name(0)
-- Configuration can be augmented and overridden by opts.jdtls
local config = extend_or_override({
cmd = opts.full_cmd(opts),
root_dir = opts.root_dir(fname),
init_options = {
bundles = bundles,
},
-- enable CMP capabilities
capabilities = require("cmp_nvim_lsp").default_capabilities(),
}, opts.jdtls)
-- Existing server will be reused if the root_dir matches.
require("jdtls").start_or_attach(config)
-- not need to require("jdtls.setup").add_commands(), start automatically adds commands
end
-- Attach the jdtls for each java buffer. HOWEVER, this plugin loads
-- depending on filetype, so this autocmd doesn't run for the first file.
-- For that, we call directly below.
vim.api.nvim_create_autocmd("FileType", {
pattern = java_filetypes,
callback = attach_jdtls,
})
-- Setup keymap and dap after the lsp is fully attached.
-- https://github.com/mfussenegger/nvim-jdtls#nvim-dap-configuration
-- https://neovim.io/doc/user/lsp.html#LspAttach
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client and client.name == "jdtls" then
local wk = require("which-key")
wk.register({
["<leader>cx"] = { name = "+extract" },
["<leader>cxv"] = { require("jdtls").extract_variable_all, "Extract Variable" },
["<leader>cxc"] = { require("jdtls").extract_constant, "Extract Constant" },
["gs"] = { require("jdtls").super_implementation, "Goto Super" },
["gS"] = { require("jdtls.tests").goto_subjects, "Goto Subjects" },
["<leader>co"] = { require("jdtls").organize_imports, "Organize Imports" },
}, { mode = "n", buffer = args.buf })
wk.register({
["<leader>c"] = { name = "+code" },
["<leader>cx"] = { name = "+extract" },
["<leader>cxm"] = {
[[<ESC><CMD>lua require('jdtls').extract_method(true)<CR>]],
"Extract Method",
},
["<leader>cxv"] = {
[[<ESC><CMD>lua require('jdtls').extract_variable_all(true)<CR>]],
"Extract Variable",
},
["<leader>cxc"] = {
[[<ESC><CMD>lua require('jdtls').extract_constant(true)<CR>]],
"Extract Constant",
},
}, { mode = "v", buffer = args.buf })
if opts.dap and Util.has("nvim-dap") and mason_registry.is_installed("java-debug-adapter") then
-- custom init for Java debugger
require("jdtls").setup_dap(opts.dap)
require("jdtls.dap").setup_dap_main_class_configs()
-- Java Test require Java debugger to work
if opts.test and mason_registry.is_installed("java-test") then
-- custom keymaps for Java test runner (not yet compatible with neotest)
wk.register({
["<leader>t"] = { name = "+test" },
["<leader>tt"] = { require("jdtls.dap").test_class, "Run All Test" },
["<leader>tr"] = { require("jdtls.dap").test_nearest_method, "Run Nearest Test" },
["<leader>tT"] = { require("jdtls.dap").pick_test, "Run Test" },
}, { mode = "n", buffer = args.buf })
end
end
-- User can set additional keymaps in opts.on_attach
if opts.on_attach then
opts.on_attach(args)
end
end
end,
})
-- Avoid race condition by calling attach the first time, since the autocmd won't fire.
attach_jdtls()
end,
},
}

View File

@ -0,0 +1,44 @@
return {
-- add json to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "json", "json5", "jsonc" })
end
end,
},
-- yaml schema support
{
"b0o/SchemaStore.nvim",
lazy = true,
version = false, -- last release is way too old
},
-- correctly setup lspconfig
{
"neovim/nvim-lspconfig",
opts = {
-- make sure mason installs the server
servers = {
jsonls = {
-- lazy-load schemastore when needed
on_new_config = function(new_config)
new_config.settings.json.schemas = new_config.settings.json.schemas or {}
vim.list_extend(new_config.settings.json.schemas, require("schemastore").json.schemas())
end,
settings = {
json = {
format = {
enable = true,
},
validate = { enable = true },
},
},
},
},
},
},
}

View File

@ -0,0 +1,90 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "markdown", "markdown_inline" })
end
end,
},
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "markdownlint", "marksman" })
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.diagnostics.markdownlint,
})
end,
},
{
"mfussenegger/nvim-lint",
optional = true,
opts = {
linters_by_ft = {
markdown = { "markdownlint" },
},
},
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
marksman = {},
},
},
},
-- Markdown preview
{
"iamcco/markdown-preview.nvim",
cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
build = function()
vim.fn["mkdp#util#install"]()
end,
keys = {
{
"<leader>cp",
ft = "markdown",
"<cmd>MarkdownPreviewToggle<cr>",
desc = "Markdown Preview",
},
},
config = function()
vim.cmd([[do FileType]])
end,
},
{
"lukas-reineke/headlines.nvim",
opts = function()
local opts = {}
for _, ft in ipairs({ "markdown", "norg", "rmd", "org" }) do
opts[ft] = {
headline_highlights = {},
}
for i = 1, 6 do
local hl = "Headline" .. i
vim.api.nvim_set_hl(0, hl, { link = "Headline", default = true })
table.insert(opts[ft].headline_highlights, hl)
end
end
return opts
end,
ft = { "markdown", "norg", "rmd", "org" },
config = function(_, opts)
-- PERF: schedule to prevent headlines slowing down opening a file
vim.schedule(function()
require("headlines").setup(opts)
require("headlines").refresh()
end)
end,
},
}

View File

@ -0,0 +1,68 @@
return {
{ "Hoffs/omnisharp-extended-lsp.nvim", lazy = true },
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "c_sharp" })
end
end,
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local nls = require("null-ls")
opts.sources = opts.sources or {}
table.insert(opts.sources, nls.builtins.formatting.csharpier)
end,
},
{
"stevearc/conform.nvim",
optional = true,
opts = {
formatters_by_ft = {
cs = { "csharpier" },
},
formatters = {
csharpier = {
command = "dotnet-csharpier",
args = { "--write-stdout" },
},
},
},
},
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
table.insert(opts.ensure_installed, "csharpier")
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
omnisharp = {
handlers = {
["textDocument/definition"] = function(...)
return require("omnisharp_extended").handler(...)
end,
},
keys = {
{
"gd",
function()
require("omnisharp_extended").telescope_lsp_definitions()
end,
desc = "Goto Definition",
},
},
enable_roslyn_analyzers = true,
organize_imports_on_format = true,
enable_import_completion = true,
},
},
},
},
}

View File

@ -0,0 +1,32 @@
return {
-- "numiras/semshi",
"wookayin/semshi", -- use a maintained fork
ft = "python",
build = ":UpdateRemotePlugins",
init = function()
-- Disabled these features better provided by LSP or other more general plugins
vim.g["semshi#error_sign"] = false
vim.g["semshi#simplify_markup"] = false
vim.g["semshi#mark_selected_nodes"] = false
vim.g["semshi#update_delay_factor"] = 0.001
-- This autocmd must be defined in init to take effect
vim.api.nvim_create_autocmd({ "VimEnter", "ColorScheme" }, {
group = vim.api.nvim_create_augroup("SemanticHighlight", {}),
callback = function()
-- Only add style, inherit or link to the LSP's colors
vim.cmd([[
highlight! semshiGlobal gui=italic
highlight! link semshiImported @none
highlight! link semshiParameter @lsp.type.parameter
highlight! link semshiParameterUnused DiagnosticUnnecessary
highlight! link semshiBuiltin @function.builtin
highlight! link semshiAttribute @field
highlight! link semshiSelf @lsp.type.selfKeyword
highlight! link semshiUnresolved @lsp.type.unresolvedReference
highlight! link semshiFree @none
]])
end,
})
end,
}

View File

@ -0,0 +1,95 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "ninja", "python", "rst", "toml" })
end
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
pyright = {},
ruff_lsp = {
keys = {
{
"<leader>co",
function()
vim.lsp.buf.code_action({
apply = true,
context = {
only = { "source.organizeImports" },
diagnostics = {},
},
})
end,
desc = "Organize Imports",
},
},
},
},
setup = {
ruff_lsp = function()
require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "ruff_lsp" then
-- Disable hover in favor of Pyright
client.server_capabilities.hoverProvider = false
end
end)
end,
},
},
},
{
"nvim-neotest/neotest",
optional = true,
dependencies = {
"nvim-neotest/neotest-python",
},
opts = {
adapters = {
["neotest-python"] = {
-- Here you can specify the settings for the adapter, i.e.
-- runner = "pytest",
-- python = ".venv/bin/python",
},
},
},
},
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
"mfussenegger/nvim-dap-python",
-- stylua: ignore
keys = {
{ "<leader>dPt", function() require('dap-python').test_method() end, desc = "Debug Method", ft = "python" },
{ "<leader>dPc", function() require('dap-python').test_class() end, desc = "Debug Class", ft = "python" },
},
config = function()
local path = require("mason-registry").get_package("debugpy"):get_install_path()
require("dap-python").setup(path .. "/venv/bin/python")
end,
},
},
{
"linux-cultist/venv-selector.nvim",
cmd = "VenvSelect",
opts = function(_, opts)
if require("lazyvim.util").has("nvim-dap-python") then
opts.dap_enabled = true
end
return vim.tbl_deep_extend("force", opts, {
name = {
"venv",
".venv",
"env",
".env",
},
})
end,
keys = { { "<leader>cv", "<cmd>:VenvSelect<cr>", desc = "Select VirtualEnv" } },
},
}

View File

@ -0,0 +1,57 @@
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, {
"ruby",
})
end,
},
{
"williamboman/mason.nvim",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, {
"solargraph",
})
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
solargraph = {},
},
},
},
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
"suketa/nvim-dap-ruby",
config = function()
require("dap-ruby").setup()
end,
},
},
{
"nvim-neotest/neotest",
optional = true,
dependencies = {
"olimorris/neotest-rspec",
},
opts = {
adapters = {
["neotest-rspec"] = {
-- NOTE: By default neotest-rspec uses the system wide rspec gem instead of the one through bundler
-- rspec_cmd = function()
-- return vim.tbl_flatten({
-- "bundle",
-- "exec",
-- "rspec",
-- })
-- end,
},
},
},
},
}

View File

@ -0,0 +1,162 @@
return {
-- Extend auto completion
{
"hrsh7th/nvim-cmp",
dependencies = {
{
"Saecki/crates.nvim",
event = { "BufRead Cargo.toml" },
opts = {
src = {
cmp = { enabled = true },
},
},
},
},
---@param opts cmp.ConfigSchema
opts = function(_, opts)
local cmp = require("cmp")
opts.sources = cmp.config.sources(vim.list_extend(opts.sources, {
{ name = "crates" },
}))
end,
},
-- Add Rust & related to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "ron", "rust", "toml" })
end
end,
},
-- Ensure Rust debugger is installed
{
"williamboman/mason.nvim",
optional = true,
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "codelldb" })
end
end,
},
{
"simrat39/rust-tools.nvim",
lazy = true,
opts = function()
local ok, mason_registry = pcall(require, "mason-registry")
local adapter ---@type any
if ok then
-- rust tools configuration for debugging support
local codelldb = mason_registry.get_package("codelldb")
local extension_path = codelldb:get_install_path() .. "/extension/"
local codelldb_path = extension_path .. "adapter/codelldb"
local liblldb_path = ""
if vim.loop.os_uname().sysname:find("Windows") then
liblldb_path = extension_path .. "lldb\\bin\\liblldb.dll"
elseif vim.fn.has("mac") == 1 then
liblldb_path = extension_path .. "lldb/lib/liblldb.dylib"
else
liblldb_path = extension_path .. "lldb/lib/liblldb.so"
end
adapter = require("rust-tools.dap").get_codelldb_adapter(codelldb_path, liblldb_path)
end
return {
dap = {
adapter = adapter,
},
tools = {
on_initialized = function()
vim.cmd([[
augroup RustLSP
autocmd CursorHold *.rs silent! lua vim.lsp.buf.document_highlight()
autocmd CursorMoved,InsertEnter *.rs silent! lua vim.lsp.buf.clear_references()
autocmd BufEnter,CursorHold,InsertLeave *.rs silent! lua vim.lsp.codelens.refresh()
augroup END
]])
end,
},
}
end,
config = function() end,
},
-- Correctly setup lspconfig for Rust 🚀
{
"neovim/nvim-lspconfig",
opts = {
servers = {
-- Ensure mason installs the server
rust_analyzer = {
keys = {
{ "K", "<cmd>RustHoverActions<cr>", desc = "Hover Actions (Rust)" },
{ "<leader>cR", "<cmd>RustCodeAction<cr>", desc = "Code Action (Rust)" },
{ "<leader>dr", "<cmd>RustDebuggables<cr>", desc = "Run Debuggables (Rust)" },
},
settings = {
["rust-analyzer"] = {
cargo = {
allFeatures = true,
loadOutDirsFromCheck = true,
runBuildScripts = true,
},
-- Add clippy lints for Rust.
checkOnSave = {
allFeatures = true,
command = "clippy",
extraArgs = { "--no-deps" },
},
procMacro = {
enable = true,
ignored = {
["async-trait"] = { "async_trait" },
["napi-derive"] = { "napi" },
["async-recursion"] = { "async_recursion" },
},
},
},
},
},
taplo = {
keys = {
{
"K",
function()
if vim.fn.expand("%:t") == "Cargo.toml" and require("crates").popup_available() then
require("crates").show_popup()
else
vim.lsp.buf.hover()
end
end,
desc = "Show Crate Documentation",
},
},
},
},
setup = {
rust_analyzer = function(_, opts)
local rust_tools_opts = require("lazyvim.util").opts("rust-tools.nvim")
require("rust-tools").setup(vim.tbl_deep_extend("force", rust_tools_opts or {}, { server = opts }))
return true
end,
},
},
},
{
"nvim-neotest/neotest",
optional = true,
dependencies = {
"rouge8/neotest-rust",
},
opts = {
adapters = {
["neotest-rust"] = {},
},
},
},
}

View File

@ -0,0 +1,49 @@
return {
{
"neovim/nvim-lspconfig",
opts = {
servers = {
tailwindcss = {
-- exclude a filetype from the default_config
filetypes_exclude = { "markdown" },
-- add additional filetypes to the default_config
filetypes_include = {},
-- to fully override the default_config, change the below
-- filetypes = {}
},
},
setup = {
tailwindcss = function(_, opts)
local tw = require("lspconfig.server_configurations.tailwindcss")
opts.filetypes = opts.filetypes or {}
-- Add default filetypes
vim.list_extend(opts.filetypes, tw.default_config.filetypes)
-- Remove excluded filetypes
--- @param ft string
opts.filetypes = vim.tbl_filter(function(ft)
return not vim.tbl_contains(opts.filetypes_exclude or {}, ft)
end, opts.filetypes)
-- Add additional filetypes
vim.list_extend(opts.filetypes, opts.filetypes_include or {})
end,
},
},
},
{
"hrsh7th/nvim-cmp",
dependencies = {
{ "roobert/tailwindcss-colorizer-cmp.nvim", config = true },
},
opts = function(_, opts)
-- original LazyVim kind icon formatter
local format_kinds = opts.formatting.format
opts.formatting.format = function(entry, item)
format_kinds(entry, item) -- add icons
return require("tailwindcss-colorizer-cmp").formatter(entry, item)
end
end,
},
}

View File

@ -0,0 +1,59 @@
vim.api.nvim_create_autocmd("FileType", {
pattern = { "hcl", "terraform" },
desc = "terraform/hcl commentstring configuration",
command = "setlocal commentstring=#\\ %s",
})
return {
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, {
"terraform",
"hcl",
})
end
end,
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
terraformls = {},
},
},
},
{
"nvimtools/none-ls.nvim",
optional = true,
opts = function(_, opts)
local null_ls = require("null-ls")
opts.sources = vim.list_extend(opts.sources or {}, {
null_ls.builtins.formatting.terraform_fmt,
null_ls.builtins.diagnostics.terraform_validate,
})
end,
},
{
"mfussenegger/nvim-lint",
optional = true,
opts = {
linters_by_ft = {
terraform = { "terraform_validate" },
tf = { "terraform_validate" },
},
},
},
{
"stevearc/conform.nvim",
optional = true,
opts = {
formatters_by_ft = {
terraform = { "terraform_fmt" },
tf = { "terraform_fmt" },
["terraform-vars"] = { "terraform_fmt" },
},
},
},
}

View File

@ -0,0 +1,58 @@
return {
{
"folke/which-key.nvim",
optional = true,
opts = {
defaults = {
["<localLeader>l"] = { name = "+vimtex" },
},
},
},
-- Add BibTeX/LaTeX to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "bibtex", "latex" })
end
if type(opts.highlight.disable) == "table" then
vim.list_extend(opts.highlight.disable, { "latex" })
else
opts.highlight.disable = { "latex" }
end
end,
},
{
"lervag/vimtex",
lazy = false, -- lazy-loading will disable inverse search
config = function()
vim.api.nvim_create_autocmd({ "FileType" }, {
group = vim.api.nvim_create_augroup("lazyvim_vimtex_conceal", { clear = true }),
pattern = { "bib", "tex" },
callback = function()
vim.wo.conceallevel = 2
end,
})
vim.g.vimtex_mappings_disable = { ["n"] = { "K" } } -- disable `K` as it conflicts with LSP hover
vim.g.vimtex_quickfix_method = vim.fn.executable("pplatex") == 1 and "pplatex" or "latexlog"
end,
},
-- Correctly setup lspconfig for LaTeX 🚀
{
"neovim/nvim-lspconfig",
optional = true,
opts = {
servers = {
texlab = {
keys = {
{ "<Leader>K", "<plug>(vimtex-doc-package)", desc = "Vimtex Docs", silent = true },
},
},
},
},
},
}

View File

@ -0,0 +1,124 @@
return {
-- add typescript to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "typescript", "tsx" })
end
end,
},
-- correctly setup lspconfig
{
"neovim/nvim-lspconfig",
opts = {
-- make sure mason installs the server
servers = {
---@type lspconfig.options.tsserver
tsserver = {
keys = {
{
"<leader>co",
function()
vim.lsp.buf.code_action({
apply = true,
context = {
only = { "source.organizeImports.ts" },
diagnostics = {},
},
})
end,
desc = "Organize Imports",
},
{
"<leader>cR",
function()
vim.lsp.buf.code_action({
apply = true,
context = {
only = { "source.removeUnused.ts" },
diagnostics = {},
},
})
end,
desc = "Remove Unused Imports",
},
},
settings = {
typescript = {
format = {
indentSize = vim.o.shiftwidth,
convertTabsToSpaces = vim.o.expandtab,
tabSize = vim.o.tabstop,
},
},
javascript = {
format = {
indentSize = vim.o.shiftwidth,
convertTabsToSpaces = vim.o.expandtab,
tabSize = vim.o.tabstop,
},
},
completions = {
completeFunctionCalls = true,
},
},
},
},
},
},
{
"mfussenegger/nvim-dap",
optional = true,
dependencies = {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
table.insert(opts.ensure_installed, "js-debug-adapter")
end,
},
},
opts = function()
local dap = require("dap")
if not dap.adapters["pwa-node"] then
require("dap").adapters["pwa-node"] = {
type = "server",
host = "localhost",
port = "${port}",
executable = {
command = "node",
-- 💀 Make sure to update this path to point to your installation
args = {
require("mason-registry").get_package("js-debug-adapter"):get_install_path()
.. "/js-debug/src/dapDebugServer.js",
"${port}",
},
},
}
end
for _, language in ipairs({ "typescript", "javascript", "typescriptreact", "javascriptreact" }) do
if not dap.configurations[language] then
dap.configurations[language] = {
{
type = "pwa-node",
request = "launch",
name = "Launch file",
program = "${file}",
cwd = "${workspaceFolder}",
},
{
type = "pwa-node",
request = "attach",
name = "Attach",
processId = require("dap.utils").pick_process,
cwd = "${workspaceFolder}",
},
}
end
end
end,
},
}

View File

@ -0,0 +1,77 @@
return {
-- add yaml specific modules to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
if type(opts.ensure_installed) == "table" then
vim.list_extend(opts.ensure_installed, { "yaml" })
end
end,
},
-- yaml schema support
{
"b0o/SchemaStore.nvim",
lazy = true,
version = false, -- last release is way too old
},
-- correctly setup lspconfig
{
"neovim/nvim-lspconfig",
opts = {
-- make sure mason installs the server
servers = {
yamlls = {
-- Have to add this for yamlls to understand that we support line folding
capabilities = {
textDocument = {
foldingRange = {
dynamicRegistration = false,
lineFoldingOnly = true,
},
},
},
-- lazy-load schemastore when needed
on_new_config = function(new_config)
new_config.settings.yaml.schemas = vim.tbl_deep_extend(
"force",
new_config.settings.yaml.schemas or {},
require("schemastore").yaml.schemas()
)
end,
settings = {
redhat = { telemetry = { enabled = false } },
yaml = {
keyOrdering = false,
format = {
enable = true,
},
validate = true,
schemaStore = {
-- Must disable built-in schemaStore support to use
-- schemas from SchemaStore.nvim plugin
enable = false,
-- Avoid TypeError: Cannot read properties of undefined (reading 'length')
url = "",
},
},
},
},
},
setup = {
yamlls = function()
-- Neovim < 0.10 does not have dynamic registration for formatting
if vim.fn.has("nvim-0.10") == 0 then
require("lazyvim.util").lsp.on_attach(function(client, _)
if client.name == "yamlls" then
client.server_capabilities.documentFormattingProvider = true
end
end)
end
end,
},
},
},
}

View File

@ -0,0 +1,52 @@
return {
{
"neovim/nvim-lspconfig",
-- other settings removed for brevity
opts = {
---@type lspconfig.options
servers = {
eslint = {
settings = {
-- helps eslint find the eslintrc when it's placed in a subfolder instead of the cwd root
workingDirectory = { mode = "auto" },
},
},
},
setup = {
eslint = function()
local function get_client(buf)
return require("lazyvim.util").lsp.get_clients({ name = "eslint", bufnr = buf })[1]
end
local formatter = require("lazyvim.util").lsp.formatter({
name = "eslint: lsp",
primary = false,
priority = 200,
filter = "eslint",
})
-- Use EslintFixAll on Neovim < 0.10.0
if not pcall(require, "vim.lsp._dynamic") then
formatter.name = "eslint: EslintFixAll"
formatter.sources = function(buf)
local client = get_client(buf)
return client and { "eslint" } or {}
end
formatter.format = function(buf)
local client = get_client(buf)
if client then
local diag = vim.diagnostic.get(buf, { namespace = vim.lsp.diagnostic.get_namespace(client.id) })
if #diag > 0 then
vim.cmd("EslintFixAll")
end
end
end
end
-- register the formatter with LazyVim
require("lazyvim.util").format.register(formatter)
end,
},
},
},
}

View File

@ -0,0 +1,45 @@
local Util = require("lazyvim.util")
return {
-- none-ls
{
"nvimtools/none-ls.nvim",
event = "LazyFile",
dependencies = { "mason.nvim" },
init = function()
Util.on_very_lazy(function()
-- register the formatter with LazyVim
require("lazyvim.util").format.register({
name = "none-ls.nvim",
priority = 200, -- set higher than conform, the builtin formatter
primary = true,
format = function(buf)
return Util.lsp.format({
bufnr = buf,
filter = function(client)
return client.name == "null-ls"
end,
})
end,
sources = function(buf)
local ret = require("null-ls.sources").get_available(vim.bo[buf].filetype, "NULL_LS_FORMATTING") or {}
return vim.tbl_map(function(source)
return source.name
end, ret)
end,
})
end)
end,
opts = function(_, opts)
local nls = require("null-ls")
opts.root_dir = opts.root_dir
or require("null-ls.utils").root_pattern(".null-ls-root", ".neoconf.json", "Makefile", ".git")
opts.sources = vim.list_extend(opts.sources or {}, {
nls.builtins.formatting.fish_indent,
nls.builtins.diagnostics.fish,
nls.builtins.formatting.stylua,
nls.builtins.formatting.shfmt,
})
end,
},
}

View File

@ -0,0 +1,127 @@
return {
{
"folke/which-key.nvim",
optional = true,
opts = {
defaults = {
["<leader>t"] = { name = "+test" },
},
},
},
{
"nvim-neotest/neotest",
opts = {
-- Can be a list of adapters like what neotest expects,
-- or a list of adapter names,
-- or a table of adapter names, mapped to adapter configs.
-- The adapter will then be automatically loaded with the config.
adapters = {},
-- Example for loading neotest-go with a custom config
-- adapters = {
-- ["neotest-go"] = {
-- args = { "-tags=integration" },
-- },
-- },
status = { virtual_text = true },
output = { open_on_run = true },
quickfix = {
open = function()
if require("lazyvim.util").has("trouble.nvim") then
require("trouble").open({ mode = "quickfix", focus = false })
else
vim.cmd("copen")
end
end,
},
},
config = function(_, opts)
local neotest_ns = vim.api.nvim_create_namespace("neotest")
vim.diagnostic.config({
virtual_text = {
format = function(diagnostic)
-- Replace newline and tab characters with space for more compact diagnostics
local message = diagnostic.message:gsub("\n", " "):gsub("\t", " "):gsub("%s+", " "):gsub("^%s+", "")
return message
end,
},
}, neotest_ns)
if require("lazyvim.util").has("trouble.nvim") then
opts.consumers = opts.consumers or {}
-- Refresh and auto close trouble after running tests
---@type neotest.Consumer
opts.consumers.trouble = function(client)
client.listeners.results = function(adapter_id, results, partial)
if partial then
return
end
local tree = assert(client:get_position(nil, { adapter = adapter_id }))
local failed = 0
for pos_id, result in pairs(results) do
if result.status == "failed" and tree:get_key(pos_id) then
failed = failed + 1
end
end
vim.schedule(function()
local trouble = require("trouble")
if trouble.is_open() then
trouble.refresh()
if failed == 0 then
trouble.close()
end
end
end)
return {}
end
end
end
if opts.adapters then
local adapters = {}
for name, config in pairs(opts.adapters or {}) do
if type(name) == "number" then
if type(config) == "string" then
config = require(config)
end
adapters[#adapters + 1] = config
elseif config ~= false then
local adapter = require(name)
if type(config) == "table" and not vim.tbl_isempty(config) then
local meta = getmetatable(adapter)
if adapter.setup then
adapter.setup(config)
elseif meta and meta.__call then
adapter(config)
else
error("Adapter " .. name .. " does not support setup")
end
end
adapters[#adapters + 1] = adapter
end
end
opts.adapters = adapters
end
require("neotest").setup(opts)
end,
-- stylua: ignore
keys = {
{ "<leader>tt", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "Run File" },
{ "<leader>tT", function() require("neotest").run.run(vim.loop.cwd()) end, desc = "Run All Test Files" },
{ "<leader>tr", function() require("neotest").run.run() end, desc = "Run Nearest" },
{ "<leader>ts", function() require("neotest").summary.toggle() end, desc = "Toggle Summary" },
{ "<leader>to", function() require("neotest").output.open({ enter = true, auto_close = true }) end, desc = "Show Output" },
{ "<leader>tO", function() require("neotest").output_panel.toggle() end, desc = "Toggle Output Panel" },
{ "<leader>tS", function() require("neotest").run.stop() end, desc = "Stop" },
},
},
{
"mfussenegger/nvim-dap",
optional = true,
-- stylua: ignore
keys = {
{ "<leader>td", function() require("neotest").run.run({strategy = "dap"}) end, desc = "Debug Nearest" },
},
},
}

View File

@ -0,0 +1,79 @@
return {
{ "nvimdev/dashboard-nvim", enabled = false },
{ "echasnovski/mini.starter", enabled = false },
-- Dashboard. This runs when neovim starts, and is what displays
-- the "LAZYVIM" banner.
{
"goolord/alpha-nvim",
event = "VimEnter",
enabled = true,
init = false,
opts = function()
local dashboard = require("alpha.themes.dashboard")
local logo = [[
Z
Z
z
z
]]
dashboard.section.header.val = vim.split(logo, "\n")
-- stylua: ignore
dashboard.section.buttons.val = {
dashboard.button("f", "" .. " Find file", "<cmd> Telescope find_files <cr>"),
dashboard.button("n", "" .. " New file", "<cmd> ene <BAR> startinsert <cr>"),
dashboard.button("r", "" .. " Recent files", "<cmd> Telescope oldfiles <cr>"),
dashboard.button("g", "" .. " Find text", "<cmd> Telescope live_grep <cr>"),
dashboard.button("c", "" .. " Config", "<cmd> lua require('lazyvim.util').telescope.config_files()() <cr>"),
dashboard.button("s", "" .. " Restore Session", [[<cmd> lua require("persistence").load() <cr>]]),
dashboard.button("x", "" .. " Lazy Extras", "<cmd> LazyExtras <cr>"),
dashboard.button("l", "󰒲 " .. " Lazy", "<cmd> Lazy <cr>"),
dashboard.button("q", "" .. " Quit", "<cmd> qa <cr>"),
}
for _, button in ipairs(dashboard.section.buttons.val) do
button.opts.hl = "AlphaButtons"
button.opts.hl_shortcut = "AlphaShortcut"
end
dashboard.section.header.opts.hl = "AlphaHeader"
dashboard.section.buttons.opts.hl = "AlphaButtons"
dashboard.section.footer.opts.hl = "AlphaFooter"
dashboard.opts.layout[1].val = 8
return dashboard
end,
config = function(_, dashboard)
-- close Lazy and re-open when the dashboard is ready
if vim.o.filetype == "lazy" then
vim.cmd.close()
vim.api.nvim_create_autocmd("User", {
once = true,
pattern = "AlphaReady",
callback = function()
require("lazy").show()
end,
})
end
require("alpha").setup(dashboard.opts)
vim.api.nvim_create_autocmd("User", {
once = true,
pattern = "LazyVimStarted",
callback = function()
local stats = require("lazy").stats()
local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
dashboard.section.footer.val = "⚡ Neovim loaded "
.. stats.loaded
.. "/"
.. stats.count
.. " plugins in "
.. ms
.. "ms"
pcall(vim.cmd.AlphaRedraw)
end,
})
end,
},
}

View File

@ -0,0 +1,174 @@
return {
-- edgy
{
"folke/edgy.nvim",
event = "VeryLazy",
keys = {
{
"<leader>ue",
function()
require("edgy").toggle()
end,
desc = "Edgy Toggle",
},
-- stylua: ignore
{ "<leader>uE", function() require("edgy").select() end, desc = "Edgy Select Window" },
},
opts = function()
local opts = {
bottom = {
{
ft = "toggleterm",
size = { height = 0.4 },
filter = function(buf, win)
return vim.api.nvim_win_get_config(win).relative == ""
end,
},
{
ft = "noice",
size = { height = 0.4 },
filter = function(buf, win)
return vim.api.nvim_win_get_config(win).relative == ""
end,
},
{
ft = "lazyterm",
title = "LazyTerm",
size = { height = 0.4 },
filter = function(buf)
return not vim.b[buf].lazyterm_cmd
end,
},
"Trouble",
{
ft = "trouble",
filter = function(buf, win)
return vim.api.nvim_win_get_config(win).relative == ""
end,
},
{ ft = "qf", title = "QuickFix" },
{
ft = "help",
size = { height = 20 },
-- don't open help files in edgy that we're editing
filter = function(buf)
return vim.bo[buf].buftype == "help"
end,
},
{ title = "Spectre", ft = "spectre_panel", size = { height = 0.4 } },
{ title = "Neotest Output", ft = "neotest-output-panel", size = { height = 15 } },
},
left = {
{
title = "Neo-Tree",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "filesystem"
end,
pinned = true,
open = function()
vim.api.nvim_input("<esc><space>e")
end,
size = { height = 0.5 },
},
{ title = "Neotest Summary", ft = "neotest-summary" },
{
title = "Neo-Tree Git",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "git_status"
end,
pinned = true,
open = "Neotree position=right git_status",
},
{
title = "Neo-Tree Buffers",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "buffers"
end,
pinned = true,
open = "Neotree position=top buffers",
},
"neo-tree",
},
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,
},
}
return opts
end,
},
-- use edgy's selection window
{
"nvim-telescope/telescope.nvim",
optional = true,
opts = {
defaults = {
get_selection_window = function()
require("edgy").goto_main()
return 0
end,
},
},
},
-- prevent neo-tree from opening files in edgy windows
{
"nvim-neo-tree/neo-tree.nvim",
optional = true,
opts = function(_, opts)
opts.open_files_do_not_replace_types = opts.open_files_do_not_replace_types
or { "terminal", "Trouble", "qf", "Outline", "trouble" }
table.insert(opts.open_files_do_not_replace_types, "edgy")
end,
},
-- Fix bufferline offsets when edgy is loaded
{
"akinsho/bufferline.nvim",
optional = true,
opts = function()
local Offset = require("bufferline.offset")
if not Offset.edgy then
local get = Offset.get
Offset.get = function()
if package.loaded.edgy then
local layout = require("edgy.config").layout
local ret = { left = "", left_size = 0, right = "", right_size = 0 }
for _, pos in ipairs({ "left", "right" }) do
local sb = layout[pos]
if sb and #sb.wins > 0 then
local title = " Sidebar" .. string.rep(" ", sb.bounds.width - 8)
ret[pos] = "%#EdgyTitle#" .. title .. "%*" .. "%#WinSeparator#│%*"
ret[pos .. "_size"] = sb.bounds.width
end
end
ret.total_size = ret.left_size + ret.right_size
if ret.total_size > 0 then
return ret
end
end
return get()
end
Offset.edgy = true
end
end,
},
}

View File

@ -0,0 +1,37 @@
return {
-- animations
{
"echasnovski/mini.animate",
event = "VeryLazy",
opts = function()
-- don't use animate when scrolling with the mouse
local mouse_scrolled = false
for _, scroll in ipairs({ "Up", "Down" }) do
local key = "<ScrollWheel" .. scroll .. ">"
vim.keymap.set({ "", "i" }, key, function()
mouse_scrolled = true
return key
end, { expr = true })
end
local animate = require("mini.animate")
return {
resize = {
timing = animate.gen_timing.linear({ duration = 100, unit = "total" }),
},
scroll = {
timing = animate.gen_timing.linear({ duration = 150, unit = "total" }),
subscroll = animate.gen_subscroll.equal({
predicate = function(total_scroll)
if mouse_scrolled then
mouse_scrolled = false
return false
end
return total_scroll > 1
end,
}),
},
}
end,
},
}

View File

@ -0,0 +1,76 @@
-- start screen
return {
-- disable alpha
{ "goolord/alpha-nvim", enabled = false },
{ "nvimdev/dashboard-nvim", enabled = false },
-- enable mini.starter
{
"echasnovski/mini.starter",
version = false, -- wait till new 0.7.0 release to put it back on semver
event = "VimEnter",
opts = function()
local logo = table.concat({
" ██╗ █████╗ ███████╗██╗ ██╗██╗ ██╗██╗███╗ ███╗ Z",
" ██║ ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║ ██║██║████╗ ████║ Z ",
" ██║ ███████║ ███╔╝ ╚████╔╝ ██║ ██║██║██╔████╔██║ z ",
" ██║ ██╔══██║ ███╔╝ ╚██╔╝ ╚██╗ ██╔╝██║██║╚██╔╝██║ z ",
" ███████╗██║ ██║███████╗ ██║ ╚████╔╝ ██║██║ ╚═╝ ██║ ",
" ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ",
}, "\n")
local pad = string.rep(" ", 22)
local new_section = function(name, action, section)
return { name = name, action = action, section = pad .. section }
end
local starter = require("mini.starter")
--stylua: ignore
local config = {
evaluate_single = true,
header = logo,
items = {
new_section("Find file", "Telescope find_files", "Telescope"),
new_section("Recent files", "Telescope oldfiles", "Telescope"),
new_section("Grep text", "Telescope live_grep", "Telescope"),
new_section("Config", "lua require('lazyvim.util').telescope.config_files()()", "Config"),
new_section("Extras", "LazyExtras", "Config"),
new_section("Lazy", "Lazy", "Config"),
new_section("New file", "ene | startinsert", "Built-in"),
new_section("Quit", "qa", "Built-in"),
new_section("Session restore", [[lua require("persistence").load()]], "Session"),
},
content_hooks = {
starter.gen_hook.adding_bullet(pad .. "", false),
starter.gen_hook.aligning("center", "center"),
},
}
return config
end,
config = function(_, config)
-- close Lazy and re-open when starter is ready
if vim.o.filetype == "lazy" then
vim.cmd.close()
vim.api.nvim_create_autocmd("User", {
pattern = "MiniStarterOpened",
callback = function()
require("lazy").show()
end,
})
end
local starter = require("mini.starter")
starter.setup(config)
vim.api.nvim_create_autocmd("User", {
pattern = "LazyVimStarted",
callback = function()
local stats = require("lazy").stats()
local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
local pad_footer = string.rep(" ", 8)
starter.config.footer = pad_footer .. "⚡ Neovim loaded " .. stats.count .. " plugins in " .. ms .. "ms"
pcall(starter.refresh)
end,
})
end,
},
}

View File

@ -0,0 +1,65 @@
---@type string
local xdg_config = vim.env.XDG_CONFIG_HOME or vim.env.HOME .. "/.config"
---@param path string
local function have(path)
return vim.loop.fs_stat(xdg_config .. "/" .. path) ~= nil
end
return {
-- Add Hyprland Parser
{
"luckasRanarison/tree-sitter-hypr",
enabled = function()
return have("hypr")
end,
event = "BufRead */hypr/*.conf",
build = ":TSUpdate hypr",
config = function()
-- Fix ft detection for hyprland
vim.filetype.add({
pattern = { [".*/hypr/.*%.conf"] = "hypr" },
})
require("nvim-treesitter.parsers").get_parser_configs().hypr = {
install_info = {
url = "https://github.com/luckasRanarison/tree-sitter-hypr",
files = { "src/parser.c" },
branch = "master",
},
filetype = "hypr",
}
end,
},
-- add some stuff to treesitter
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
local function add(lang)
if type(opts.ensure_installed) == "table" then
table.insert(opts.ensure_installed, lang)
end
end
vim.filetype.add({
extension = { rasi = "rasi" },
pattern = {
[".*/waybar/config"] = "jsonc",
[".*/mako/config"] = "dosini",
[".*/kitty/*.conf"] = "bash",
},
})
add("git_config")
if have("fish") then
add("fish")
end
if have("rofi") or have("wofi") then
add("rasi")
end
end,
},
}

View File

@ -0,0 +1,387 @@
local M = {}
---@type table<string,true>
M.hl = {}
M.plugin = {
"echasnovski/mini.hipatterns",
event = "LazyFile",
opts = function()
local hi = require("mini.hipatterns")
return {
-- custom LazyVim option to enable the tailwind integration
tailwind = {
enabled = true,
ft = { "typescriptreact", "javascriptreact", "css", "javascript", "typescript", "html" },
-- full: the whole css class will be highlighted
-- compact: only the color will be highlighted
style = "full",
},
highlighters = {
hex_color = hi.gen_highlighter.hex_color({ priority = 2000 }),
},
}
end,
config = function(_, opts)
-- backward compatibility
if opts.tailwind == true then
opts.tailwind = {
enabled = true,
ft = { "typescriptreact", "javascriptreact", "css", "javascript", "typescript", "html" },
style = "full",
}
end
if type(opts.tailwind) == "table" and opts.tailwind.enabled then
-- reset hl groups when colorscheme changes
vim.api.nvim_create_autocmd("ColorScheme", {
callback = function()
M.hl = {}
end,
})
opts.highlighters.tailwind = {
pattern = function()
if not vim.tbl_contains(opts.tailwind.ft, vim.bo.filetype) then
return
end
if opts.tailwind.style == "full" then
return "%f[%w:-]()[%w:-]+%-[a-z%-]+%-%d+()%f[^%w:-]"
elseif opts.tailwind.style == "compact" then
return "%f[%w:-][%w:-]+%-()[a-z%-]+%-%d+()%f[^%w:-]"
end
end,
group = function(_, _, m)
---@type string
local match = m.full_match
---@type string, number
local color, shade = match:match("[%w-]+%-([a-z%-]+)%-(%d+)")
shade = tonumber(shade)
local bg = vim.tbl_get(M.colors, color, shade)
if bg then
local hl = "MiniHipatternsTailwind" .. color .. shade
if not M.hl[hl] then
M.hl[hl] = true
local bg_shade = shade == 500 and 950 or shade < 500 and 900 or 100
local fg = vim.tbl_get(M.colors, color, bg_shade)
vim.api.nvim_set_hl(0, hl, { bg = "#" .. bg, fg = "#" .. fg })
end
return hl
end
end,
extmark_opts = { priority = 2000 },
}
end
require("mini.hipatterns").setup(opts)
end,
}
M.colors = {
slate = {
[50] = "f8fafc",
[100] = "f1f5f9",
[200] = "e2e8f0",
[300] = "cbd5e1",
[400] = "94a3b8",
[500] = "64748b",
[600] = "475569",
[700] = "334155",
[800] = "1e293b",
[900] = "0f172a",
[950] = "020617",
},
gray = {
[50] = "f9fafb",
[100] = "f3f4f6",
[200] = "e5e7eb",
[300] = "d1d5db",
[400] = "9ca3af",
[500] = "6b7280",
[600] = "4b5563",
[700] = "374151",
[800] = "1f2937",
[900] = "111827",
[950] = "030712",
},
zinc = {
[50] = "fafafa",
[100] = "f4f4f5",
[200] = "e4e4e7",
[300] = "d4d4d8",
[400] = "a1a1aa",
[500] = "71717a",
[600] = "52525b",
[700] = "3f3f46",
[800] = "27272a",
[900] = "18181b",
[950] = "09090B",
},
neutral = {
[50] = "fafafa",
[100] = "f5f5f5",
[200] = "e5e5e5",
[300] = "d4d4d4",
[400] = "a3a3a3",
[500] = "737373",
[600] = "525252",
[700] = "404040",
[800] = "262626",
[900] = "171717",
[950] = "0a0a0a",
},
stone = {
[50] = "fafaf9",
[100] = "f5f5f4",
[200] = "e7e5e4",
[300] = "d6d3d1",
[400] = "a8a29e",
[500] = "78716c",
[600] = "57534e",
[700] = "44403c",
[800] = "292524",
[900] = "1c1917",
[950] = "0a0a0a",
},
red = {
[50] = "fef2f2",
[100] = "fee2e2",
[200] = "fecaca",
[300] = "fca5a5",
[400] = "f87171",
[500] = "ef4444",
[600] = "dc2626",
[700] = "b91c1c",
[800] = "991b1b",
[900] = "7f1d1d",
[950] = "450a0a",
},
orange = {
[50] = "fff7ed",
[100] = "ffedd5",
[200] = "fed7aa",
[300] = "fdba74",
[400] = "fb923c",
[500] = "f97316",
[600] = "ea580c",
[700] = "c2410c",
[800] = "9a3412",
[900] = "7c2d12",
[950] = "431407",
},
amber = {
[50] = "fffbeb",
[100] = "fef3c7",
[200] = "fde68a",
[300] = "fcd34d",
[400] = "fbbf24",
[500] = "f59e0b",
[600] = "d97706",
[700] = "b45309",
[800] = "92400e",
[900] = "78350f",
[950] = "451a03",
},
yellow = {
[50] = "fefce8",
[100] = "fef9c3",
[200] = "fef08a",
[300] = "fde047",
[400] = "facc15",
[500] = "eab308",
[600] = "ca8a04",
[700] = "a16207",
[800] = "854d0e",
[900] = "713f12",
[950] = "422006",
},
lime = {
[50] = "f7fee7",
[100] = "ecfccb",
[200] = "d9f99d",
[300] = "bef264",
[400] = "a3e635",
[500] = "84cc16",
[600] = "65a30d",
[700] = "4d7c0f",
[800] = "3f6212",
[900] = "365314",
[950] = "1a2e05",
},
green = {
[50] = "f0fdf4",
[100] = "dcfce7",
[200] = "bbf7d0",
[300] = "86efac",
[400] = "4ade80",
[500] = "22c55e",
[600] = "16a34a",
[700] = "15803d",
[800] = "166534",
[900] = "14532d",
[950] = "052e16",
},
emerald = {
[50] = "ecfdf5",
[100] = "d1fae5",
[200] = "a7f3d0",
[300] = "6ee7b7",
[400] = "34d399",
[500] = "10b981",
[600] = "059669",
[700] = "047857",
[800] = "065f46",
[900] = "064e3b",
[950] = "022c22",
},
teal = {
[50] = "f0fdfa",
[100] = "ccfbf1",
[200] = "99f6e4",
[300] = "5eead4",
[400] = "2dd4bf",
[500] = "14b8a6",
[600] = "0d9488",
[700] = "0f766e",
[800] = "115e59",
[900] = "134e4a",
[950] = "042f2e",
},
cyan = {
[50] = "ecfeff",
[100] = "cffafe",
[200] = "a5f3fc",
[300] = "67e8f9",
[400] = "22d3ee",
[500] = "06b6d4",
[600] = "0891b2",
[700] = "0e7490",
[800] = "155e75",
[900] = "164e63",
[950] = "083344",
},
sky = {
[50] = "f0f9ff",
[100] = "e0f2fe",
[200] = "bae6fd",
[300] = "7dd3fc",
[400] = "38bdf8",
[500] = "0ea5e9",
[600] = "0284c7",
[700] = "0369a1",
[800] = "075985",
[900] = "0c4a6e",
[950] = "082f49",
},
blue = {
[50] = "eff6ff",
[100] = "dbeafe",
[200] = "bfdbfe",
[300] = "93c5fd",
[400] = "60a5fa",
[500] = "3b82f6",
[600] = "2563eb",
[700] = "1d4ed8",
[800] = "1e40af",
[900] = "1e3a8a",
[950] = "172554",
},
indigo = {
[50] = "eef2ff",
[100] = "e0e7ff",
[200] = "c7d2fe",
[300] = "a5b4fc",
[400] = "818cf8",
[500] = "6366f1",
[600] = "4f46e5",
[700] = "4338ca",
[800] = "3730a3",
[900] = "312e81",
[950] = "1e1b4b",
},
violet = {
[50] = "f5f3ff",
[100] = "ede9fe",
[200] = "ddd6fe",
[300] = "c4b5fd",
[400] = "a78bfa",
[500] = "8b5cf6",
[600] = "7c3aed",
[700] = "6d28d9",
[800] = "5b21b6",
[900] = "4c1d95",
[950] = "2e1065",
},
purple = {
[50] = "faf5ff",
[100] = "f3e8ff",
[200] = "e9d5ff",
[300] = "d8b4fe",
[400] = "c084fc",
[500] = "a855f7",
[600] = "9333ea",
[700] = "7e22ce",
[800] = "6b21a8",
[900] = "581c87",
[950] = "3b0764",
},
fuchsia = {
[50] = "fdf4ff",
[100] = "fae8ff",
[200] = "f5d0fe",
[300] = "f0abfc",
[400] = "e879f9",
[500] = "d946ef",
[600] = "c026d3",
[700] = "a21caf",
[800] = "86198f",
[900] = "701a75",
[950] = "4a044e",
},
pink = {
[50] = "fdf2f8",
[100] = "fce7f3",
[200] = "fbcfe8",
[300] = "f9a8d4",
[400] = "f472b6",
[500] = "ec4899",
[600] = "db2777",
[700] = "be185d",
[800] = "9d174d",
[900] = "831843",
[950] = "500724",
},
rose = {
[50] = "fff1f2",
[100] = "ffe4e6",
[200] = "fecdd3",
[300] = "fda4af",
[400] = "fb7185",
[500] = "f43f5e",
[600] = "e11d48",
[700] = "be123c",
[800] = "9f1239",
[900] = "881337",
[950] = "4c0519",
},
}
return M.plugin

View File

@ -0,0 +1,66 @@
return {
{
"telescope.nvim",
dependencies = {
-- project management
{
"ahmedkhalf/project.nvim",
opts = {
manual_mode = true,
},
event = "VeryLazy",
config = function(_, opts)
require("project_nvim").setup(opts)
require("lazyvim.util").on_load("telescope.nvim", function()
require("telescope").load_extension("projects")
end)
end,
keys = {
{ "<leader>fp", "<Cmd>Telescope projects<CR>", desc = "Projects" },
},
},
},
},
{
"goolord/alpha-nvim",
optional = true,
opts = function(_, dashboard)
local button = dashboard.button("p", "" .. " Projects", ":Telescope projects <CR>")
button.opts.hl = "AlphaButtons"
button.opts.hl_shortcut = "AlphaShortcut"
table.insert(dashboard.section.buttons.val, 4, button)
end,
},
{
"echasnovski/mini.starter",
optional = true,
opts = function(_, opts)
local items = {
{
name = "Projects",
action = "Telescope projects",
section = string.rep(" ", 22) .. "Telescope",
},
}
vim.list_extend(opts.items, items)
end,
},
{
"nvimdev/dashboard-nvim",
optional = true,
opts = function(_, opts)
local projects = {
action = "Telescope projects",
desc = " Projects",
icon = "",
key = "p",
}
projects.desc = projects.desc .. string.rep(" ", 43 - #projects.desc)
projects.key_format = " %s"
table.insert(opts.config.center, 3, projects)
end,
},
}

View File

@ -0,0 +1,51 @@
if not vim.g.vscode then
return {}
end
local enabled = {
"flit.nvim",
"lazy.nvim",
"leap.nvim",
"mini.ai",
"mini.comment",
"mini.pairs",
"mini.surround",
"nvim-treesitter",
"nvim-treesitter-textobjects",
"nvim-ts-context-commentstring",
"vim-repeat",
"LazyVim",
}
local Config = require("lazy.core.config")
Config.options.checker.enabled = false
Config.options.change_detection.enabled = false
Config.options.defaults.cond = function(plugin)
return vim.tbl_contains(enabled, plugin.name) or plugin.vscode
end
-- Add some vscode specific keymaps
vim.api.nvim_create_autocmd("User", {
pattern = "LazyVimKeymaps",
callback = function()
vim.keymap.set("n", "<leader><space>", "<cmd>Find<cr>")
vim.keymap.set("n", "<leader>/", [[<cmd>call VSCodeNotify('workbench.action.findInFiles')<cr>]])
vim.keymap.set("n", "<leader>ss", [[<cmd>call VSCodeNotify('workbench.action.gotoSymbol')<cr>]])
end,
})
return {
{
"LazyVim/LazyVim",
config = function(_, opts)
opts = opts or {}
-- disable the colorscheme
opts.colorscheme = function() end
require("lazyvim").setup(opts)
end,
},
{
"nvim-treesitter/nvim-treesitter",
opts = { highlight = { enable = false } },
},
}

View File

@ -0,0 +1,116 @@
local Util = require("lazyvim.util")
local M = {}
---@param opts ConformOpts
function M.setup(_, opts)
for name, formatter in pairs(opts.formatters or {}) do
if type(formatter) == "table" then
---@diagnostic disable-next-line: undefined-field
if formatter.extra_args then
---@diagnostic disable-next-line: undefined-field
formatter.prepend_args = formatter.extra_args
Util.deprecate(("opts.formatters.%s.extra_args"):format(name), ("opts.formatters.%s.prepend_args"):format(name))
end
end
end
for _, key in ipairs({ "format_on_save", "format_after_save" }) do
if opts[key] then
Util.warn(
("Don't set `opts.%s` for `conform.nvim`.\n**LazyVim** will use the conform formatter automatically"):format(
key
)
)
---@diagnostic disable-next-line: no-unknown
opts[key] = nil
end
end
require("conform").setup(opts)
end
return {
{
"stevearc/conform.nvim",
dependencies = { "mason.nvim" },
lazy = true,
cmd = "ConformInfo",
keys = {
{
"<leader>cF",
function()
require("conform").format({ formatters = { "injected" } })
end,
mode = { "n", "v" },
desc = "Format Injected Langs",
},
},
init = function()
-- Install the conform formatter on VeryLazy
require("lazyvim.util").on_very_lazy(function()
require("lazyvim.util").format.register({
name = "conform.nvim",
priority = 100,
primary = true,
format = function(buf)
local plugin = require("lazy.core.config").plugins["conform.nvim"]
local Plugin = require("lazy.core.plugin")
local opts = Plugin.values(plugin, "opts", false)
require("conform").format(Util.merge(opts.format, { bufnr = buf }))
end,
sources = function(buf)
local ret = require("conform").list_formatters(buf)
---@param v conform.FormatterInfo
return vim.tbl_map(function(v)
return v.name
end, ret)
end,
})
end)
end,
opts = function()
local plugin = require("lazy.core.config").plugins["conform.nvim"]
if plugin.config ~= M.setup then
Util.error({
"Don't set `plugin.config` for `conform.nvim`.\n",
"This will break **LazyVim** formatting.\n",
"Please refer to the docs at https://www.lazyvim.org/plugins/formatting",
}, { title = "LazyVim" })
end
---@class ConformOpts
local opts = {
-- LazyVim will use these options when formatting with the conform.nvim formatter
format = {
timeout_ms = 3000,
async = false, -- not recommended to change
quiet = false, -- not recommended to change
},
---@type table<string, conform.FormatterUnit[]>
formatters_by_ft = {
lua = { "stylua" },
fish = { "fish_indent" },
sh = { "shfmt" },
},
-- The options you set here will be merged with the builtin formatters.
-- You can also define any custom formatters here.
---@type table<string, conform.FormatterConfigOverride|fun(bufnr: integer): nil|conform.FormatterConfigOverride>
formatters = {
injected = { options = { ignore_errors = true } },
-- # Example of using dprint only when a dprint.json file is present
-- dprint = {
-- condition = function(ctx)
-- return vim.fs.find({ "dprint.json" }, { path = ctx.filename, upward = true })[1]
-- end,
-- },
--
-- # Example of using shfmt with extra args
-- shfmt = {
-- prepend_args = { "-i", "2", "-ci" },
-- },
},
}
return opts
end,
config = M.setup,
},
}

View File

@ -0,0 +1,16 @@
if vim.fn.has("nvim-0.9.0") == 0 then
vim.api.nvim_echo({
{ "LazyVim requires Neovim >= 0.9.0\n", "ErrorMsg" },
{ "Press any key to exit", "MoreMsg" },
}, true, {})
vim.fn.getchar()
vim.cmd([[quit]])
return {}
end
require("lazyvim.config").init()
return {
{ "folke/lazy.nvim", version = "*" },
{ "LazyVim/LazyVim", priority = 10000, lazy = false, config = true, cond = true, version = "*" },
}

View File

@ -0,0 +1,93 @@
return {
{
"mfussenegger/nvim-lint",
event = "LazyFile",
opts = {
-- Event to trigger linters
events = { "BufWritePost", "BufReadPost", "InsertLeave" },
linters_by_ft = {
fish = { "fish" },
-- Use the "*" filetype to run linters on all filetypes.
-- ['*'] = { 'global linter' },
-- Use the "_" filetype to run linters on filetypes that don't have other linters configured.
-- ['_'] = { 'fallback linter' },
},
-- LazyVim extension to easily override linter options
-- or add custom linters.
---@type table<string,table>
linters = {
-- -- Example of using selene only when a selene.toml file is present
-- selene = {
-- -- `condition` is another LazyVim extension that allows you to
-- -- dynamically enable/disable linters based on the context.
-- condition = function(ctx)
-- return vim.fs.find({ "selene.toml" }, { path = ctx.filename, upward = true })[1]
-- end,
-- },
},
},
config = function(_, opts)
local Util = require("lazyvim.util")
local M = {}
local lint = require("lint")
for name, linter in pairs(opts.linters) do
if type(linter) == "table" and type(lint.linters[name]) == "table" then
lint.linters[name] = vim.tbl_deep_extend("force", lint.linters[name], linter)
else
lint.linters[name] = linter
end
end
lint.linters_by_ft = opts.linters_by_ft
function M.debounce(ms, fn)
local timer = vim.loop.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
end)
end
end
function M.lint()
-- Use nvim-lint's logic first:
-- * checks if linters exist for the full filetype first
-- * otherwise will split filetype by "." and add all those linters
-- * this differs from conform.nvim which only uses the first filetype that has a formatter
local names = lint._resolve_linter_by_ft(vim.bo.filetype)
-- Add fallback linters.
if #names == 0 then
vim.list_extend(names, lint.linters_by_ft["_"] or {})
end
-- Add global linters.
vim.list_extend(names, lint.linters_by_ft["*"] or {})
-- Filter out linters that don't exist or don't match the condition.
local ctx = { filename = vim.api.nvim_buf_get_name(0) }
ctx.dirname = vim.fn.fnamemodify(ctx.filename, ":h")
names = vim.tbl_filter(function(name)
local linter = lint.linters[name]
if not linter then
Util.warn("Linter not found: " .. name, { title = "nvim-lint" })
end
return linter and not (type(linter) == "table" and linter.condition and not linter.condition(ctx))
end, names)
-- Run linters.
if #names > 0 then
lint.try_lint(names)
end
end
vim.api.nvim_create_autocmd(opts.events, {
group = vim.api.nvim_create_augroup("nvim-lint", { clear = true }),
callback = M.debounce(100, M.lint),
})
end,
},
}

View File

@ -0,0 +1,243 @@
local Util = require("lazyvim.util")
return {
-- lspconfig
{
"neovim/nvim-lspconfig",
event = "LazyFile",
dependencies = {
{ "folke/neoconf.nvim", cmd = "Neoconf", config = false, dependencies = { "nvim-lspconfig" } },
{ "folke/neodev.nvim", opts = {} },
"mason.nvim",
"williamboman/mason-lspconfig.nvim",
},
---@class PluginLspOpts
opts = {
-- options for vim.diagnostic.config()
diagnostics = {
underline = true,
update_in_insert = false,
virtual_text = {
spacing = 4,
source = "if_many",
prefix = "",
-- this will set set the prefix to a function that returns the diagnostics icon based on the severity
-- this only works on a recent 0.10.0 build. Will be set to "●" when not supported
-- prefix = "icons",
},
severity_sort = true,
},
-- Enable this to enable the builtin LSP inlay hints on Neovim >= 0.10.0
-- Be aware that you also will need to properly configure your LSP server to
-- provide the inlay hints.
inlay_hints = {
enabled = false,
},
-- add any global capabilities here
capabilities = {},
-- options for vim.lsp.buf.format
-- `bufnr` and `filter` is handled by the LazyVim formatter,
-- but can be also overridden when specified
format = {
formatting_options = nil,
timeout_ms = nil,
},
-- LSP Server Settings
---@type lspconfig.options
servers = {
lua_ls = {
-- mason = false, -- set to false if you don't want this server to be installed with mason
-- Use this to add any additional keymaps
-- for specific lsp servers
---@type LazyKeysSpec[]
-- keys = {},
settings = {
Lua = {
workspace = {
checkThirdParty = false,
},
completion = {
callSnippet = "Replace",
},
},
},
},
},
-- you can do any additional lsp server setup here
-- return true if you don't want this server to be setup with lspconfig
---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?>
setup = {
-- example to setup with typescript.nvim
-- tsserver = function(_, opts)
-- require("typescript").setup({ server = opts })
-- return true
-- end,
-- Specify * to use this function as a fallback for any server
-- ["*"] = function(server, opts) end,
},
},
---@param opts PluginLspOpts
config = function(_, opts)
if Util.has("neoconf.nvim") then
local plugin = require("lazy.core.config").spec.plugins["neoconf.nvim"]
require("neoconf").setup(require("lazy.core.plugin").values(plugin, "opts", false))
end
-- setup autoformat
Util.format.register(Util.lsp.formatter())
-- deprectaed options
if opts.autoformat ~= nil then
vim.g.autoformat = opts.autoformat
Util.deprecate("nvim-lspconfig.opts.autoformat", "vim.g.autoformat")
end
-- setup keymaps
Util.lsp.on_attach(function(client, buffer)
require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer)
end)
local register_capability = vim.lsp.handlers["client/registerCapability"]
vim.lsp.handlers["client/registerCapability"] = function(err, res, ctx)
local ret = register_capability(err, res, ctx)
local client_id = ctx.client_id
---@type lsp.Client
local client = vim.lsp.get_client_by_id(client_id)
local buffer = vim.api.nvim_get_current_buf()
require("lazyvim.plugins.lsp.keymaps").on_attach(client, buffer)
return ret
end
-- diagnostics
for name, icon in pairs(require("lazyvim.config").icons.diagnostics) do
name = "DiagnosticSign" .. name
vim.fn.sign_define(name, { text = icon, texthl = name, numhl = "" })
end
if opts.inlay_hints.enabled then
Util.lsp.on_attach(function(client, buffer)
if client.supports_method("textDocument/inlayHint") then
Util.toggle.inlay_hints(buffer, true)
end
end)
end
if type(opts.diagnostics.virtual_text) == "table" and opts.diagnostics.virtual_text.prefix == "icons" then
opts.diagnostics.virtual_text.prefix = vim.fn.has("nvim-0.10.0") == 0 and ""
or function(diagnostic)
local icons = require("lazyvim.config").icons.diagnostics
for d, icon in pairs(icons) do
if diagnostic.severity == vim.diagnostic.severity[d:upper()] then
return icon
end
end
end
end
vim.diagnostic.config(vim.deepcopy(opts.diagnostics))
local servers = opts.servers
local has_cmp, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp")
local capabilities = vim.tbl_deep_extend(
"force",
{},
vim.lsp.protocol.make_client_capabilities(),
has_cmp and cmp_nvim_lsp.default_capabilities() or {},
opts.capabilities or {}
)
local function setup(server)
local server_opts = vim.tbl_deep_extend("force", {
capabilities = vim.deepcopy(capabilities),
}, servers[server] or {})
if opts.setup[server] then
if opts.setup[server](server, server_opts) then
return
end
elseif opts.setup["*"] then
if opts.setup["*"](server, server_opts) then
return
end
end
require("lspconfig")[server].setup(server_opts)
end
-- get all the servers that are available through mason-lspconfig
local have_mason, mlsp = pcall(require, "mason-lspconfig")
local all_mslp_servers = {}
if have_mason then
all_mslp_servers = vim.tbl_keys(require("mason-lspconfig.mappings.server").lspconfig_to_package)
end
local ensure_installed = {} ---@type string[]
for server, server_opts in pairs(servers) do
if server_opts then
server_opts = server_opts == true and {} or server_opts
-- run manual setup if mason=false or if this is a server that cannot be installed with mason-lspconfig
if server_opts.mason == false or not vim.tbl_contains(all_mslp_servers, server) then
setup(server)
else
ensure_installed[#ensure_installed + 1] = server
end
end
end
if have_mason then
mlsp.setup({ ensure_installed = ensure_installed, handlers = { setup } })
end
if Util.lsp.get_config("denols") and Util.lsp.get_config("tsserver") then
local is_deno = require("lspconfig.util").root_pattern("deno.json", "deno.jsonc")
Util.lsp.disable("tsserver", is_deno)
Util.lsp.disable("denols", function(root_dir)
return not is_deno(root_dir)
end)
end
end,
},
-- cmdline tools and lsp servers
{
"williamboman/mason.nvim",
cmd = "Mason",
keys = { { "<leader>cm", "<cmd>Mason<cr>", desc = "Mason" } },
build = ":MasonUpdate",
opts = {
ensure_installed = {
"stylua",
"shfmt",
-- "flake8",
},
},
---@param opts MasonSettings | {ensure_installed: string[]}
config = function(_, opts)
require("mason").setup(opts)
local mr = require("mason-registry")
mr:on("package:install:success", function()
vim.defer_fn(function()
-- trigger FileType event to possibly load this newly installed LSP server
require("lazy.core.handler.event").trigger({
event = "FileType",
buf = vim.api.nvim_get_current_buf(),
})
end, 100)
end)
local function ensure_installed()
for _, tool in ipairs(opts.ensure_installed) do
local p = mr.get_package(tool)
if not p:is_installed() then
p:install()
end
end
end
if mr.refresh then
mr.refresh(ensure_installed)
else
ensure_installed()
end
end,
},
}

View File

@ -0,0 +1,102 @@
local M = {}
---@type LazyKeysLspSpec[]|nil
M._keys = nil
---@alias LazyKeysLspSpec LazyKeysSpec|{has?:string}
---@alias LazyKeysLsp LazyKeys|{has?:string}
---@return LazyKeysLspSpec[]
function M.get()
if M._keys then
return M._keys
end
-- stylua: ignore
M._keys = {
{ "<leader>cl", "<cmd>LspInfo<cr>", desc = "Lsp Info" },
{ "gd", function() require("telescope.builtin").lsp_definitions({ reuse_win = true }) end, desc = "Goto Definition", has = "definition" },
{ "gr", "<cmd>Telescope lsp_references<cr>", desc = "References" },
{ "gD", vim.lsp.buf.declaration, desc = "Goto Declaration" },
{ "gI", function() require("telescope.builtin").lsp_implementations({ reuse_win = true }) end, desc = "Goto Implementation" },
{ "gy", function() require("telescope.builtin").lsp_type_definitions({ reuse_win = true }) end, desc = "Goto T[y]pe Definition" },
{ "K", vim.lsp.buf.hover, desc = "Hover" },
{ "gK", vim.lsp.buf.signature_help, desc = "Signature Help", has = "signatureHelp" },
{ "<c-k>", vim.lsp.buf.signature_help, mode = "i", desc = "Signature Help", has = "signatureHelp" },
{ "<leader>ca", vim.lsp.buf.code_action, desc = "Code Action", mode = { "n", "v" }, has = "codeAction" },
{
"<leader>cA",
function()
vim.lsp.buf.code_action({
context = {
only = {
"source",
},
diagnostics = {},
},
})
end,
desc = "Source Action",
has = "codeAction",
}
}
if require("lazyvim.util").has("inc-rename.nvim") then
M._keys[#M._keys + 1] = {
"<leader>cr",
function()
local inc_rename = require("inc_rename")
return ":" .. inc_rename.config.cmd_name .. " " .. vim.fn.expand("<cword>")
end,
expr = true,
desc = "Rename",
has = "rename",
}
else
M._keys[#M._keys + 1] = { "<leader>cr", vim.lsp.buf.rename, desc = "Rename", has = "rename" }
end
return M._keys
end
---@param method string
function M.has(buffer, method)
method = method:find("/") and method or "textDocument/" .. method
local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do
if client.supports_method(method) then
return true
end
end
return false
end
---@return (LazyKeys|{has?:string})[]
function M.resolve(buffer)
local Keys = require("lazy.core.handler.keys")
if not Keys.resolve then
return {}
end
local spec = M.get()
local opts = require("lazyvim.util").opts("nvim-lspconfig")
local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do
local maps = opts.servers[client.name] and opts.servers[client.name].keys or {}
vim.list_extend(spec, maps)
end
return Keys.resolve(spec)
end
function M.on_attach(_, buffer)
local Keys = require("lazy.core.handler.keys")
local keymaps = M.resolve(buffer)
for _, keys in pairs(keymaps) do
if not keys.has or M.has(buffer, keys.has) then
local opts = Keys.opts(keys)
opts.has = nil
opts.silent = opts.silent ~= false
opts.buffer = buffer
vim.keymap.set(keys.mode or "n", keys.lhs, keys.rhs, opts)
end
end
end
return M

View File

@ -0,0 +1,146 @@
return {
-- Treesitter is a new parser generator tool that we can
-- use in Neovim to power faster and more accurate
-- syntax highlighting.
{
"nvim-treesitter/nvim-treesitter",
version = false, -- last release is way too old and doesn't work on Windows
build = ":TSUpdate",
event = { "LazyFile", "VeryLazy" },
init = function(plugin)
-- PERF: add nvim-treesitter queries to the rtp and it's custom query predicates early
-- This is needed because a bunch of plugins no longer `require("nvim-treesitter")`, which
-- no longer trigger the **nvim-treeitter** module to be loaded in time.
-- Luckily, the only thins that those plugins need are the custom queries, which we make available
-- during startup.
require("lazy.core.loader").add_to_rtp(plugin)
require("nvim-treesitter.query_predicates")
end,
dependencies = {
{
"nvim-treesitter/nvim-treesitter-textobjects",
config = function()
-- When in diff mode, we want to use the default
-- vim text objects c & C instead of the treesitter ones.
local move = require("nvim-treesitter.textobjects.move") ---@type table<string,fun(...)>
local configs = require("nvim-treesitter.configs")
for name, fn in pairs(move) do
if name:find("goto") == 1 then
move[name] = function(q, ...)
if vim.wo.diff then
local config = configs.get_module("textobjects.move")[name] ---@type table<string,string>
for key, query in pairs(config or {}) do
if q == query and key:find("[%]%[][cC]") then
vim.cmd("normal! " .. key)
return
end
end
end
return fn(q, ...)
end
end
end
end,
},
},
cmd = { "TSUpdateSync", "TSUpdate", "TSInstall" },
keys = {
{ "<c-space>", desc = "Increment selection" },
{ "<bs>", desc = "Decrement selection", mode = "x" },
},
---@type TSConfig
---@diagnostic disable-next-line: missing-fields
opts = {
highlight = { enable = true },
indent = { enable = true },
ensure_installed = {
"bash",
"c",
"diff",
"html",
"javascript",
"jsdoc",
"json",
"jsonc",
"lua",
"luadoc",
"luap",
"markdown",
"markdown_inline",
"python",
"query",
"regex",
"toml",
"tsx",
"typescript",
"vim",
"vimdoc",
"yaml",
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},
textobjects = {
move = {
enable = true,
goto_next_start = { ["]f"] = "@function.outer", ["]c"] = "@class.outer" },
goto_next_end = { ["]F"] = "@function.outer", ["]C"] = "@class.outer" },
goto_previous_start = { ["[f"] = "@function.outer", ["[c"] = "@class.outer" },
goto_previous_end = { ["[F"] = "@function.outer", ["[C"] = "@class.outer" },
},
},
},
---@param opts TSConfig
config = function(_, opts)
if type(opts.ensure_installed) == "table" then
---@type table<string, boolean>
local added = {}
opts.ensure_installed = vim.tbl_filter(function(lang)
if added[lang] then
return false
end
added[lang] = true
return true
end, opts.ensure_installed)
end
require("nvim-treesitter.configs").setup(opts)
end,
},
-- Show context of the current function
{
"nvim-treesitter/nvim-treesitter-context",
event = "LazyFile",
enabled = true,
opts = { mode = "cursor", max_lines = 3 },
keys = {
{
"<leader>ut",
function()
local Util = require("lazyvim.util")
local tsc = require("treesitter-context")
tsc.toggle()
if Util.inject.get_upvalue(tsc.toggle, "enabled") then
Util.info("Enabled Treesitter Context", { title = "Option" })
else
Util.warn("Disabled Treesitter Context", { title = "Option" })
end
end,
desc = "Toggle Treesitter Context",
},
},
},
-- Automatically add closing tags for HTML and JSX
{
"windwp/nvim-ts-autotag",
event = "LazyFile",
opts = {},
},
}

413
lua/lazyvim/plugins/ui.lua Normal file
View File

@ -0,0 +1,413 @@
local Util = require("lazyvim.util")
return {
-- Better `vim.notify()`
{
"rcarriga/nvim-notify",
keys = {
{
"<leader>un",
function()
require("notify").dismiss({ silent = true, pending = true })
end,
desc = "Dismiss all Notifications",
},
},
opts = {
timeout = 3000,
max_height = function()
return math.floor(vim.o.lines * 0.75)
end,
max_width = function()
return math.floor(vim.o.columns * 0.75)
end,
on_open = function(win)
vim.api.nvim_win_set_config(win, { zindex = 100 })
end,
},
init = function()
-- when noice is not enabled, install notify on VeryLazy
if not Util.has("noice.nvim") then
Util.on_very_lazy(function()
vim.notify = require("notify")
end)
end
end,
},
-- better vim.ui
{
"stevearc/dressing.nvim",
lazy = true,
init = function()
---@diagnostic disable-next-line: duplicate-set-field
vim.ui.select = function(...)
require("lazy").load({ plugins = { "dressing.nvim" } })
return vim.ui.select(...)
end
---@diagnostic disable-next-line: duplicate-set-field
vim.ui.input = function(...)
require("lazy").load({ plugins = { "dressing.nvim" } })
return vim.ui.input(...)
end
end,
},
-- This is what powers LazyVim's fancy-looking
-- tabs, which include filetype icons and close buttons.
{
"akinsho/bufferline.nvim",
event = "VeryLazy",
keys = {
{ "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", desc = "Toggle pin" },
{ "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", desc = "Delete non-pinned buffers" },
{ "<leader>bo", "<Cmd>BufferLineCloseOthers<CR>", desc = "Delete other buffers" },
{ "<leader>br", "<Cmd>BufferLineCloseRight<CR>", desc = "Delete buffers to the right" },
{ "<leader>bl", "<Cmd>BufferLineCloseLeft<CR>", desc = "Delete buffers to the left" },
{ "<S-h>", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev buffer" },
{ "<S-l>", "<cmd>BufferLineCycleNext<cr>", desc = "Next buffer" },
{ "[b", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev buffer" },
{ "]b", "<cmd>BufferLineCycleNext<cr>", desc = "Next buffer" },
},
opts = {
options = {
-- stylua: ignore
close_command = function(n) require("mini.bufremove").delete(n, false) end,
-- stylua: ignore
right_mouse_command = function(n) require("mini.bufremove").delete(n, false) end,
diagnostics = "nvim_lsp",
always_show_bufferline = false,
diagnostics_indicator = function(_, _, diag)
local icons = require("lazyvim.config").icons.diagnostics
local ret = (diag.error and icons.Error .. diag.error .. " " or "")
.. (diag.warning and icons.Warn .. diag.warning or "")
return vim.trim(ret)
end,
offsets = {
{
filetype = "neo-tree",
text = "Neo-tree",
highlight = "Directory",
text_align = "left",
},
},
},
},
config = function(_, opts)
require("bufferline").setup(opts)
-- Fix bufferline when restoring a session
vim.api.nvim_create_autocmd("BufAdd", {
callback = function()
vim.schedule(function()
pcall(nvim_bufferline)
end)
end,
})
end,
},
-- statusline
{
"nvim-lualine/lualine.nvim",
event = "VeryLazy",
init = function()
vim.g.lualine_laststatus = vim.o.laststatus
if vim.fn.argc(-1) > 0 then
-- set an empty statusline till lualine loads
vim.o.statusline = " "
else
-- hide the statusline on the starter page
vim.o.laststatus = 0
end
end,
opts = function()
-- PERF: we don't need this lualine require madness 🤷
local lualine_require = require("lualine_require")
lualine_require.require = require
local icons = require("lazyvim.config").icons
vim.o.laststatus = vim.g.lualine_laststatus
return {
options = {
theme = "auto",
globalstatus = true,
disabled_filetypes = { statusline = { "dashboard", "alpha", "starter" } },
},
sections = {
lualine_a = { "mode" },
lualine_b = { "branch" },
lualine_c = {
Util.lualine.root_dir(),
{
"diagnostics",
symbols = {
error = icons.diagnostics.Error,
warn = icons.diagnostics.Warn,
info = icons.diagnostics.Info,
hint = icons.diagnostics.Hint,
},
},
{ "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
{ Util.lualine.pretty_path() },
},
lualine_x = {
-- stylua: ignore
{
function() return require("noice").api.status.command.get() end,
cond = function() return package.loaded["noice"] and require("noice").api.status.command.has() end,
color = Util.ui.fg("Statement"),
},
-- stylua: ignore
{
function() return require("noice").api.status.mode.get() end,
cond = function() return package.loaded["noice"] and require("noice").api.status.mode.has() end,
color = Util.ui.fg("Constant"),
},
-- stylua: ignore
{
function() return "" .. require("dap").status() end,
cond = function () return package.loaded["dap"] and require("dap").status() ~= "" end,
color = Util.ui.fg("Debug"),
},
{
require("lazy.status").updates,
cond = require("lazy.status").has_updates,
color = Util.ui.fg("Special"),
},
{
"diff",
symbols = {
added = icons.git.added,
modified = icons.git.modified,
removed = icons.git.removed,
},
source = function()
local gitsigns = vim.b.gitsigns_status_dict
if gitsigns then
return {
added = gitsigns.added,
modified = gitsigns.changed,
removed = gitsigns.removed,
}
end
end,
},
},
lualine_y = {
{ "progress", separator = " ", padding = { left = 1, right = 0 } },
{ "location", padding = { left = 0, right = 1 } },
},
lualine_z = {
function()
return "" .. os.date("%R")
end,
},
},
extensions = { "neo-tree", "lazy" },
}
end,
},
-- indent guides for Neovim
{
"lukas-reineke/indent-blankline.nvim",
event = "LazyFile",
opts = {
indent = {
char = "",
tab_char = "",
},
scope = { enabled = false },
exclude = {
filetypes = {
"help",
"alpha",
"dashboard",
"neo-tree",
"Trouble",
"trouble",
"lazy",
"mason",
"notify",
"toggleterm",
"lazyterm",
},
},
},
main = "ibl",
},
-- Active indent guide and indent text objects. When you're browsing
-- code, this highlights the current level of indentation, and animates
-- the highlighting.
{
"echasnovski/mini.indentscope",
version = false, -- wait till new 0.7.0 release to put it back on semver
event = "LazyFile",
opts = {
-- symbol = "▏",
symbol = "",
options = { try_as_border = true },
},
init = function()
vim.api.nvim_create_autocmd("FileType", {
pattern = {
"help",
"alpha",
"dashboard",
"neo-tree",
"Trouble",
"trouble",
"lazy",
"mason",
"notify",
"toggleterm",
"lazyterm",
},
callback = function()
vim.b.miniindentscope_disable = true
end,
})
end,
},
-- Displays a popup with possible key bindings of the command you started typing
{
"folke/which-key.nvim",
opts = function(_, opts)
if require("lazyvim.util").has("noice.nvim") then
opts.defaults["<leader>sn"] = { name = "+noice" }
end
end,
},
-- Highly experimental plugin that completely replaces the UI for messages, cmdline and the popupmenu.
{
"folke/noice.nvim",
event = "VeryLazy",
opts = {
lsp = {
override = {
["vim.lsp.util.convert_input_to_markdown_lines"] = true,
["vim.lsp.util.stylize_markdown"] = true,
["cmp.entry.get_documentation"] = true,
},
},
routes = {
{
filter = {
event = "msg_show",
any = {
{ find = "%d+L, %d+B" },
{ find = "; after #%d+" },
{ find = "; before #%d+" },
},
},
view = "mini",
},
},
presets = {
bottom_search = true,
command_palette = true,
long_message_to_split = true,
inc_rename = true,
},
},
-- stylua: ignore
keys = {
{ "<S-Enter>", function() require("noice").redirect(vim.fn.getcmdline()) end, mode = "c", desc = "Redirect Cmdline" },
{ "<leader>snl", function() require("noice").cmd("last") end, desc = "Noice Last Message" },
{ "<leader>snh", function() require("noice").cmd("history") end, desc = "Noice History" },
{ "<leader>sna", function() require("noice").cmd("all") end, desc = "Noice All" },
{ "<leader>snd", function() require("noice").cmd("dismiss") end, desc = "Dismiss All" },
{ "<c-f>", function() if not require("noice.lsp").scroll(4) then return "<c-f>" end end, silent = true, expr = true, desc = "Scroll forward", mode = {"i", "n", "s"} },
{ "<c-b>", function() if not require("noice.lsp").scroll(-4) then return "<c-b>" end end, silent = true, expr = true, desc = "Scroll backward", mode = {"i", "n", "s"}},
},
},
-- icons
{ "nvim-tree/nvim-web-devicons", lazy = true },
-- ui components
{ "MunifTanjim/nui.nvim", lazy = true },
{
"goolord/alpha-nvim",
optional = true,
enabled = function()
require("lazyvim.util").warn({
"`dashboard.nvim` is now the default LazyVim starter plugin.",
"",
"To keep using `alpha.nvim`, please enable the `lazyvim.plugins.extras.ui.alpha` extra.",
"Or to hide this message, remove the alpha spec from your config.",
})
return false
end,
},
{
"nvimdev/dashboard-nvim",
event = "VimEnter",
opts = function()
local logo = [[
Z
Z
z
z
]]
logo = string.rep("\n", 8) .. logo .. "\n\n"
local opts = {
theme = "doom",
hide = {
-- this is taken care of by lualine
-- enabling this messes up the actual laststatus setting after loading a file
statusline = false,
},
config = {
header = vim.split(logo, "\n"),
-- stylua: ignore
center = {
{ action = "Telescope find_files", desc = " Find file", icon = "", key = "f" },
{ action = "ene | startinsert", desc = " New file", icon = "", key = "n" },
{ action = "Telescope oldfiles", desc = " Recent files", icon = "", key = "r" },
{ action = "Telescope live_grep", desc = " Find text", icon = "", key = "g" },
{ action = [[lua require("lazyvim.util").telescope.config_files()()]], desc = " Config", icon = "", key = "c" },
{ action = 'lua require("persistence").load()', desc = " Restore Session", icon = "", key = "s" },
{ action = "LazyExtras", desc = " Lazy Extras", icon = "", key = "x" },
{ action = "Lazy", desc = " Lazy", icon = "󰒲 ", key = "l" },
{ action = "qa", desc = " Quit", icon = "", key = "q" },
},
footer = function()
local stats = require("lazy").stats()
local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
return { "⚡ Neovim loaded " .. stats.loaded .. "/" .. stats.count .. " plugins in " .. ms .. "ms" }
end,
},
}
for _, button in ipairs(opts.config.center) do
button.desc = button.desc .. string.rep(" ", 43 - #button.desc)
button.key_format = " %s"
end
-- close Lazy and re-open when the dashboard is ready
if vim.o.filetype == "lazy" then
vim.cmd.close()
vim.api.nvim_create_autocmd("User", {
pattern = "DashboardLoaded",
callback = function()
require("lazy").show()
end,
})
end
return opts
end,
},
}

View File

@ -0,0 +1,29 @@
return {
-- measure startuptime
{
"dstein64/vim-startuptime",
cmd = "StartupTime",
config = function()
vim.g.startuptime_tries = 10
end,
},
-- Session management. This saves your session in the background,
-- keeping track of open buffers, window arrangement, and more.
-- You can restore sessions when returning through the dashboard.
{
"folke/persistence.nvim",
event = "BufReadPre",
opts = { options = vim.opt.sessionoptions:get() },
-- stylua: ignore
keys = {
{ "<leader>qs", function() require("persistence").load() end, desc = "Restore Session" },
{ "<leader>ql", function() require("persistence").load({ last = true }) end, desc = "Restore Last Session" },
{ "<leader>qd", function() require("persistence").stop() end, desc = "Don't Save Current Session" },
},
},
-- library used by other plugins
{ "nvim-lua/plenary.nvim", lazy = true },
}

View File

@ -0,0 +1,23 @@
local Config = require("lazyvim.config")
-- Some extras need to be loaded before others
local prios = {
["lazyvim.plugins.extras.editor.aerial"] = 100,
["lazyvim.plugins.extras.editor.symbols-outline"] = 100,
["lazyvim.plugins.extras.test.core"] = 1,
["lazyvim.plugins.extras.dap.core"] = 1,
}
table.sort(Config.json.data.extras, function(a, b)
local pa = prios[a] or 10
local pb = prios[b] or 10
if pa == pb then
return a < b
end
return pa < pb
end)
---@param extra string
return vim.tbl_map(function(extra)
return { import = extra }
end, Config.json.data.extras)

243
lua/lazyvim/util/extras.lua Normal file
View File

@ -0,0 +1,243 @@
local Config = require("lazyvim.config")
local Float = require("lazy.view.float")
local LazyConfig = require("lazy.core.config")
local Plugin = require("lazy.core.plugin")
local Text = require("lazy.view.text")
local Util = require("lazyvim.util")
---@class LazyExtraSource
---@field name string
---@field desc? string
---@field module string
---@class LazyExtra
---@field name string
---@field source LazyExtraSource
---@field module string
---@field desc? string
---@field enabled boolean
---@field managed boolean
---@field row? number
---@field plugins string[]
---@field optional string[]
---@class lazyvim.util.extras
local M = {}
---@type LazyExtraSource[]
M.sources = {
{ name = "LazyVim", desc = "LazyVim extras", module = "lazyvim.plugins.extras" },
{ name = "User", desc = "User extras", module = "plugins.extras" },
}
M.ns = vim.api.nvim_create_namespace("lazyvim.extras")
---@type string[]
M.state = nil
---@return LazyExtra[]
function M.get()
M.state = M.state or LazyConfig.spec.modules
local extras = {} ---@type LazyExtra[]
for _, source in ipairs(M.sources) do
local root = Util.find_root(source.module)
if root then
Util.walk(root, function(path, name, type)
if type == "file" and name:match("%.lua$") then
name = path:sub(#root + 2, -5):gsub("/", ".")
local ok, extra = pcall(M.get_extra, source, source.module .. "." .. name)
if ok then
extras[#extras + 1] = extra
end
end
end)
end
end
table.sort(extras, function(a, b)
return a.name < b.name
end)
return extras
end
---@param modname string
---@param source LazyExtraSource
function M.get_extra(source, modname)
local enabled = vim.tbl_contains(M.state, modname)
local spec = Plugin.Spec.new({ import = modname }, { optional = true })
local plugins = {} ---@type string[]
local optional = {} ---@type string[]
for _, p in pairs(spec.plugins) do
if p.optional then
optional[#optional + 1] = p.name
else
plugins[#plugins + 1] = p.name
end
end
table.sort(plugins)
table.sort(optional)
---@type LazyExtra
return {
source = source,
name = modname:sub(#source.module + 2),
module = modname,
enabled = enabled,
desc = require(modname).desc,
managed = vim.tbl_contains(Config.json.data.extras, modname) or not enabled,
plugins = plugins,
optional = optional,
}
end
---@class LazyExtraView
---@field float LazyFloat
---@field text Text
---@field extras LazyExtra[]
---@field diag LazyDiagnostic[]
local X = {}
---@return LazyExtraView
function X.new()
local self = setmetatable({}, { __index = X })
self.float = Float.new({ title = "LazyVim Extras" })
self.float:on_key("x", function()
self:toggle()
end, "Toggle extra")
self.diag = {}
self:update()
return self
end
---@param diag LazyDiagnostic
function X:diagnostic(diag)
diag.row = diag.row or self.text:row()
diag.severity = diag.severity or vim.diagnostic.severity.INFO
table.insert(self.diag, diag)
end
function X:toggle()
local pos = vim.api.nvim_win_get_cursor(self.float.win)
for _, extra in ipairs(self.extras) do
if extra.row == pos[1] then
if not extra.managed then
Util.error(
"Not managed by LazyExtras. Remove from your config to enable/disable here.",
{ title = "LazyExtras" }
)
return
end
extra.enabled = not extra.enabled
Config.json.data.extras = vim.tbl_filter(function(name)
return name ~= extra.module
end, Config.json.data.extras)
M.state = vim.tbl_filter(function(name)
return name ~= extra.module
end, M.state)
if extra.enabled then
table.insert(Config.json.data.extras, extra.module)
M.state[#M.state + 1] = extra.module
end
table.sort(Config.json.data.extras)
Util.json.save()
Util.info(
"`"
.. extra.name
.. "`"
.. " "
.. (extra.enabled and "**enabled**" or "**disabled**")
.. "\nPlease restart LazyVim to apply the changes.",
{ title = "LazyExtras" }
)
self:update()
return
end
end
end
function X:update()
self.diag = {}
self.extras = M.get()
self.text = Text.new()
self.text.padding = 2
self:render()
self.text:trim()
vim.bo[self.float.buf].modifiable = true
self.text:render(self.float.buf)
vim.bo[self.float.buf].modifiable = false
vim.diagnostic.set(
M.ns,
self.float.buf,
---@param diag LazyDiagnostic
vim.tbl_map(function(diag)
diag.col = 0
diag.lnum = diag.row - 1
return diag
end, self.diag),
{ signs = false, virtual_text = true }
)
end
function X:render()
self.text:nl():nl():append("LazyVim Extras", "LazyH1"):nl():nl()
self.text
:append("This is a list of all enabled/disabled LazyVim extras.", "LazyComment")
:nl()
:append("Each extra shows the required and optional plugins it may install.", "LazyComment")
:nl()
:append("Enable/disable extras with the ", "LazyComment")
:append("<x>", "LazySpecial")
:append(" key", "LazyComment")
:nl()
self:section({ enabled = true, title = "Enabled" })
self:section({ enabled = false, title = "Disabled" })
end
---@param extra LazyExtra
function X:extra(extra)
if not extra.managed then
self:diagnostic({
message = "Not managed by LazyExtras (config)",
severity = vim.diagnostic.severity.WARN,
})
end
extra.row = self.text:row()
local hl = extra.managed and "LazySpecial" or "LazyLocal"
if extra.enabled then
self.text:append(" " .. LazyConfig.options.ui.icons.loaded .. " ", hl)
else
self.text:append(" " .. LazyConfig.options.ui.icons.not_loaded .. " ", hl)
end
self.text:append(extra.name)
if extra.source.name ~= "LazyVim" then
self.text:append(" "):append(LazyConfig.options.ui.icons.event .. " " .. extra.source.name, "LazyReasonEvent")
end
for _, plugin in ipairs(extra.plugins) do
self.text:append(" "):append(LazyConfig.options.ui.icons.plugin .. "" .. plugin, "LazyReasonPlugin")
end
for _, plugin in ipairs(extra.optional) do
self.text:append(" "):append(LazyConfig.options.ui.icons.plugin .. "" .. plugin, "LazyReasonRequire")
end
if extra.desc then
self.text:nl():append(" " .. extra.desc, "LazyComment")
end
self.text:nl()
end
---@param opts {enabled?:boolean, title?:string}
function X:section(opts)
opts = opts or {}
---@type LazyExtra[]
local extras = vim.tbl_filter(function(extra)
return opts.enabled == nil or extra.enabled == opts.enabled
end, self.extras)
self.text:nl():append(opts.title .. ":", "LazyH2"):append(" (" .. #extras .. ")", "LazyComment"):nl()
for _, extra in ipairs(extras) do
self:extra(extra)
end
end
function M.show()
return X.new()
end
return M

173
lua/lazyvim/util/format.lua Normal file
View File

@ -0,0 +1,173 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.format
---@overload fun(opts?: {force?:boolean})
local M = setmetatable({}, {
__call = function(m, ...)
return m.format(...)
end,
})
---@class LazyFormatter
---@field name string
---@field primary? boolean
---@field format fun(bufnr:number)
---@field sources fun(bufnr:number):string[]
---@field priority number
M.formatters = {} ---@type LazyFormatter[]
---@param formatter LazyFormatter
function M.register(formatter)
M.formatters[#M.formatters + 1] = formatter
table.sort(M.formatters, function(a, b)
return a.priority > b.priority
end)
end
function M.formatexpr()
if Util.has("conform.nvim") then
return require("conform").formatexpr()
end
return vim.lsp.formatexpr({ timeout_ms = 3000 })
end
---@param buf? number
---@return (LazyFormatter|{active:boolean,resolved:string[]})[]
function M.resolve(buf)
buf = buf or vim.api.nvim_get_current_buf()
local have_primary = false
---@param formatter LazyFormatter
return vim.tbl_map(function(formatter)
local sources = formatter.sources(buf)
local active = #sources > 0 and (not formatter.primary or not have_primary)
have_primary = have_primary or (active and formatter.primary) or false
return setmetatable({
active = active,
resolved = sources,
}, { __index = formatter })
end, M.formatters)
end
---@param buf? number
function M.info(buf)
buf = buf or vim.api.nvim_get_current_buf()
local gaf = vim.g.autoformat == nil or vim.g.autoformat
local baf = vim.b[buf].autoformat
local enabled = M.enabled(buf)
local lines = {
"# Status",
("- [%s] global **%s**"):format(gaf and "x" or " ", gaf and "enabled" or "disabled"),
("- [%s] buffer **%s**"):format(
enabled and "x" or " ",
baf == nil and "inherit" or baf and "enabled" or "disabled"
),
}
local have = false
for _, formatter in ipairs(M.resolve(buf)) do
if #formatter.resolved > 0 then
have = true
lines[#lines + 1] = "\n# " .. formatter.name .. (formatter.active and " ***(active)***" or "")
for _, line in ipairs(formatter.resolved) do
lines[#lines + 1] = ("- [%s] **%s**"):format(formatter.active and "x" or " ", line)
end
end
end
if not have then
lines[#lines + 1] = "\n***No formatters available for this buffer.***"
end
Util[enabled and "info" or "warn"](
table.concat(lines, "\n"),
{ title = "LazyFormat (" .. (enabled and "enabled" or "disabled") .. ")" }
)
end
---@param buf? number
function M.enabled(buf)
buf = (buf == nil or buf == 0) and vim.api.nvim_get_current_buf() or buf
local gaf = vim.g.autoformat
local baf = vim.b[buf].autoformat
-- If the buffer has a local value, use that
if baf ~= nil then
return baf
end
-- Otherwise use the global value if set, or true by default
return gaf == nil or gaf
end
---@param buf? boolean
function M.toggle(buf)
if buf then
vim.b.autoformat = not M.enabled()
else
vim.g.autoformat = not M.enabled()
vim.b.autoformat = nil
end
M.info()
end
---@param opts? {force?:boolean, buf?:number}
function M.format(opts)
opts = opts or {}
local buf = opts.buf or vim.api.nvim_get_current_buf()
if not ((opts and opts.force) or M.enabled(buf)) then
return
end
local done = false
for _, formatter in ipairs(M.resolve(buf)) do
if formatter.active then
done = true
Util.try(function()
return formatter.format(buf)
end, { msg = "Formatter `" .. formatter.name .. "` failed" })
end
end
if not done and opts and opts.force then
Util.warn("No formatter available", { title = "LazyVim" })
end
end
function M.health()
local Config = require("lazy.core.config")
local has_plugin = Config.spec.plugins["none-ls.nvim"]
local has_extra = vim.tbl_contains(Config.spec.modules, "lazyvim.plugins.extras.lsp.none-ls")
if has_plugin and not has_extra then
Util.warn({
"`conform.nvim` and `nvim-lint` are now the default formatters and linters in LazyVim.",
"",
"You can use those plugins together with `none-ls.nvim`,",
"but you need to enable the `lazyvim.plugins.extras.lsp.none-ls` extra,",
"for formatting to work correctly.",
"",
"In case you no longer want to use `none-ls.nvim`, just remove the spec from your config.",
})
end
end
function M.setup()
M.health()
-- Autoformat autocmd
vim.api.nvim_create_autocmd("BufWritePre", {
group = vim.api.nvim_create_augroup("LazyFormat", {}),
callback = function(event)
M.format({ buf = event.buf })
end,
})
-- Manual format
vim.api.nvim_create_user_command("LazyFormat", function()
M.format({ force = true })
end, { desc = "Format selection or buffer" })
-- Format info
vim.api.nvim_create_user_command("LazyFormatInfo", function()
M.info()
end, { desc = "Show info about the formatters for the current buffer" })
end
return M

171
lua/lazyvim/util/init.lua Normal file
View File

@ -0,0 +1,171 @@
local LazyUtil = require("lazy.core.util")
---@class lazyvim.util: LazyUtilCore
---@field ui lazyvim.util.ui
---@field lsp lazyvim.util.lsp
---@field root lazyvim.util.root
---@field telescope lazyvim.util.telescope
---@field terminal lazyvim.util.terminal
---@field toggle lazyvim.util.toggle
---@field format lazyvim.util.format
---@field plugin lazyvim.util.plugin
---@field extras lazyvim.util.extras
---@field inject lazyvim.util.inject
---@field news lazyvim.util.news
---@field json lazyvim.util.json
---@field lualine lazyvim.util.lualine
local M = {}
---@type table<string, string|string[]>
local deprecated = {
get_clients = "lsp",
on_attach = "lsp",
on_rename = "lsp",
root_patterns = { "root", "patterns" },
get_root = { "root", "get" },
float_term = { "terminal", "open" },
toggle_diagnostics = { "toggle", "diagnostics" },
toggle_number = { "toggle", "number" },
fg = "ui",
}
setmetatable(M, {
__index = function(t, k)
if LazyUtil[k] then
return LazyUtil[k]
end
local dep = deprecated[k]
if dep then
local mod = type(dep) == "table" and dep[1] or dep
local key = type(dep) == "table" and dep[2] or k
M.deprecate([[require("lazyvim.util").]] .. k, [[require("lazyvim.util").]] .. mod .. "." .. key)
---@diagnostic disable-next-line: no-unknown
t[mod] = require("lazyvim.util." .. mod) -- load here to prevent loops
return t[mod][key]
end
---@diagnostic disable-next-line: no-unknown
t[k] = require("lazyvim.util." .. k)
return t[k]
end,
})
function M.is_win()
return vim.loop.os_uname().sysname:find("Windows") ~= nil
end
---@param plugin string
function M.has(plugin)
return require("lazy.core.config").spec.plugins[plugin] ~= nil
end
---@param fn fun()
function M.on_very_lazy(fn)
vim.api.nvim_create_autocmd("User", {
pattern = "VeryLazy",
callback = function()
fn()
end,
})
end
---@param name string
function M.opts(name)
local plugin = require("lazy.core.config").plugins[name]
if not plugin then
return {}
end
local Plugin = require("lazy.core.plugin")
return Plugin.values(plugin, "opts", false)
end
function M.deprecate(old, new)
M.warn(("`%s` is deprecated. Please use `%s` instead"):format(old, new), {
title = "LazyVim",
once = true,
stacktrace = true,
stacklevel = 6,
})
end
-- delay notifications till vim.notify was replaced or after 500ms
function M.lazy_notify()
local notifs = {}
local function temp(...)
table.insert(notifs, vim.F.pack_len(...))
end
local orig = vim.notify
vim.notify = temp
local timer = vim.loop.new_timer()
local check = assert(vim.loop.new_check())
local replay = function()
timer:stop()
check:stop()
if vim.notify == temp then
vim.notify = orig -- put back the original notify if needed
end
vim.schedule(function()
---@diagnostic disable-next-line: no-unknown
for _, notif in ipairs(notifs) do
vim.notify(vim.F.unpack_len(notif))
end
end)
end
-- wait till vim.notify has been replaced
check:start(function()
if vim.notify ~= temp then
replay()
end
end)
-- or if it took more than 500ms, then something went wrong
timer:start(500, 0, replay)
end
---@param name string
---@param fn fun(name:string)
function M.on_load(name, fn)
local Config = require("lazy.core.config")
if Config.plugins[name] and Config.plugins[name]._.loaded then
fn(name)
else
vim.api.nvim_create_autocmd("User", {
pattern = "LazyLoad",
callback = function(event)
if event.data == name then
fn(name)
return true
end
end,
})
end
end
-- Wrapper around vim.keymap.set that will
-- not create a keymap if a lazy key handler exists.
-- It will also set `silent` to true by default.
function M.safe_keymap_set(mode, lhs, rhs, opts)
local keys = require("lazy.core.handler").handlers.keys
---@cast keys LazyKeysHandler
local modes = type(mode) == "string" and { mode } or mode
---@param m string
modes = vim.tbl_filter(function(m)
return not (keys.have and keys:have(lhs, m))
end, modes)
-- do not create the keymap if a lazy keys handler exists
if #modes > 0 then
opts = opts or {}
opts.silent = opts.silent ~= false
if opts.remap and not vim.g.vscode then
---@diagnostic disable-next-line: no-unknown
opts.remap = nil
end
vim.keymap.set(modes, lhs, rhs, opts)
end
end
return M

View File

@ -0,0 +1,34 @@
---@class lazyvim.util.inject
local M = {}
---@generic A: any
---@generic B: any
---@generic C: any
---@generic F: function
---@param fn F|fun(a:A, b:B, c:C)
---@param wrapper fun(a:A, b:B, c:C): boolean?
---@return F
function M.args(fn, wrapper)
return function(...)
if wrapper(...) == false then
return
end
return fn(...)
end
end
function M.get_upvalue(func, name)
local i = 1
while true do
local n, v = debug.getupvalue(func, i)
if not n then
break
end
if n == name then
return v
end
i = i + 1
end
end
return M

82
lua/lazyvim/util/json.lua Normal file
View File

@ -0,0 +1,82 @@
local Config = require("lazyvim.config")
local Util = require("lazyvim.util")
---@class lazyvim.util.json
local M = {}
---@param value any
---@param indent string
local function encode(value, indent)
local t = type(value)
if t == "string" then
return string.format("%q", value)
elseif t == "number" or t == "boolean" then
return tostring(value)
elseif t == "table" then
local is_list = Util.is_list(value)
local parts = {}
local next_indent = indent .. " "
if is_list then
---@diagnostic disable-next-line: no-unknown
for _, v in ipairs(value) do
local e = encode(v, next_indent)
if e then
table.insert(parts, next_indent .. e)
end
end
return "[\n" .. table.concat(parts, ",\n") .. "\n" .. indent .. "]"
else
local keys = vim.tbl_keys(value)
table.sort(keys)
---@diagnostic disable-next-line: no-unknown
for _, k in ipairs(keys) do
local e = encode(value[k], next_indent)
if e then
table.insert(parts, next_indent .. string.format("%q", k) .. ": " .. e)
end
end
return "{\n" .. table.concat(parts, ",\n") .. "\n" .. indent .. "}"
end
end
end
function M.encode(value)
return encode(value, "")
end
function M.save()
Config.json.data.version = Config.json.version
local path = vim.fn.stdpath("config") .. "/lazyvim.json"
local f = io.open(path, "w")
if f then
f:write(Util.json.encode(Config.json.data))
f:close()
end
end
function M.migrate()
Util.info("Migrating `lazyvim.json` to version `" .. Config.json.version .. "`")
local json = Config.json
-- v0
if not json.data.version then
if json.data.hashes then
---@diagnostic disable-next-line: no-unknown
json.data.hashes = nil
end
json.data.extras = vim.tbl_map(function(extra)
return "lazyvim.plugins.extras." .. extra
end, json.data.extras or {})
elseif json.data.version == 1 then
json.data.extras = vim.tbl_map(function(extra)
-- replace double extras module name
return extra:gsub("^lazyvim%.plugins%.extras%.lazyvim%.plugins%.extras%.", "lazyvim.plugins.extras.")
end, json.data.extras or {})
end
M.save()
end
return M

125
lua/lazyvim/util/lsp.lua Normal file
View File

@ -0,0 +1,125 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.lsp
local M = {}
---@alias lsp.Client.filter {id?: number, bufnr?: number, name?: string, method?: string, filter?:fun(client: lsp.Client):boolean}
---@param opts? lsp.Client.filter
function M.get_clients(opts)
local ret = {} ---@type lsp.Client[]
if vim.lsp.get_clients then
ret = vim.lsp.get_clients(opts)
else
---@diagnostic disable-next-line: deprecated
ret = vim.lsp.get_active_clients(opts)
if opts and opts.method then
---@param client lsp.Client
ret = vim.tbl_filter(function(client)
return client.supports_method(opts.method, { bufnr = opts.bufnr })
end, ret)
end
end
return opts and opts.filter and vim.tbl_filter(opts.filter, ret) or ret
end
---@param on_attach fun(client, buffer)
function M.on_attach(on_attach)
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local buffer = args.buf ---@type number
local client = vim.lsp.get_client_by_id(args.data.client_id)
on_attach(client, buffer)
end,
})
end
---@param from string
---@param to string
function M.on_rename(from, to)
local clients = M.get_clients()
for _, client in ipairs(clients) do
if client.supports_method("workspace/willRenameFiles") then
---@diagnostic disable-next-line: invisible
local resp = client.request_sync("workspace/willRenameFiles", {
files = {
{
oldUri = vim.uri_from_fname(from),
newUri = vim.uri_from_fname(to),
},
},
}, 1000, 0)
if resp and resp.result ~= nil then
vim.lsp.util.apply_workspace_edit(resp.result, client.offset_encoding)
end
end
end
end
---@return _.lspconfig.options
function M.get_config(server)
local configs = require("lspconfig.configs")
return rawget(configs, server)
end
---@param server string
---@param cond fun( root_dir, config): boolean
function M.disable(server, cond)
local util = require("lspconfig.util")
local def = M.get_config(server)
---@diagnostic disable-next-line: undefined-field
def.document_config.on_new_config = util.add_hook_before(def.document_config.on_new_config, function(config, root_dir)
if cond(root_dir, config) then
config.enabled = false
end
end)
end
---@param opts? LazyFormatter| {filter?: (string|lsp.Client.filter)}
function M.formatter(opts)
opts = opts or {}
local filter = opts.filter or {}
filter = type(filter) == "string" and { name = filter } or filter
---@cast filter lsp.Client.filter
---@type LazyFormatter
local ret = {
name = "LSP",
primary = true,
priority = 1,
format = function(buf)
M.format(Util.merge(filter, { bufnr = buf }))
end,
sources = function(buf)
local clients = M.get_clients(Util.merge(filter, { bufnr = buf }))
---@param client lsp.Client
local ret = vim.tbl_filter(function(client)
return client.supports_method("textDocument/formatting")
or client.supports_method("textDocument/rangeFormatting")
end, clients)
---@param client lsp.Client
return vim.tbl_map(function(client)
return client.name
end, ret)
end,
}
return Util.merge(ret, opts) --[[@as LazyFormatter]]
end
---@alias lsp.Client.format {timeout_ms?: number, format_options?: table} | lsp.Client.filter
---@param opts? lsp.Client.format
function M.format(opts)
opts = vim.tbl_deep_extend("force", {}, opts or {}, require("lazyvim.util").opts("nvim-lspconfig").format or {})
local ok, conform = pcall(require, "conform")
-- use conform for formatting with LSP when available,
-- since it has better format diffing
if ok then
opts.formatters = {}
opts.lsp_fallback = true
conform.format(opts)
else
vim.lsp.buf.format(opts)
end
end
return M

View File

@ -0,0 +1,143 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.lualine
local M = {}
function M.cmp_source(name, icon)
local started = false
local function status()
if not package.loaded["cmp"] then
return
end
for _, s in ipairs(require("cmp").core.sources) do
if s.name == name then
if s.source:is_available() then
started = true
else
return started and "error" or nil
end
if s.status == s.SourceStatus.FETCHING then
return "pending"
end
return "ok"
end
end
end
local colors = {
ok = Util.ui.fg("Special"),
error = Util.ui.fg("DiagnosticError"),
pending = Util.ui.fg("DiagnosticWarn"),
}
return {
function()
return icon or require("lazyvim.config").icons.kinds[name:sub(1, 1):upper() .. name:sub(2)]
end,
cond = function()
return status() ~= nil
end,
color = function()
return colors[status()] or colors.ok
end,
}
end
---@param component any
---@param text string
---@param hl_group? string
---@return string
function M.format(component, text, hl_group)
if not hl_group then
return text
end
---@type table<string, string>
component.hl_cache = component.hl_cache or {}
local lualine_hl_group = component.hl_cache[hl_group]
if not lualine_hl_group then
local utils = require("lualine.utils.utils")
lualine_hl_group = component:create_hl({ fg = utils.extract_highlight_colors(hl_group, "fg") }, "LV_" .. hl_group)
component.hl_cache[hl_group] = lualine_hl_group
end
return component:format_hl(lualine_hl_group) .. text .. component:get_default_hl()
end
---@param opts? {relative: "cwd"|"root", modified_hl: string?}
function M.pretty_path(opts)
opts = vim.tbl_extend("force", {
relative = "cwd",
modified_hl = "Constant",
}, opts or {})
return function(self)
local path = vim.fn.expand("%:p") --[[@as string]]
if path == "" then
return ""
end
local root = Util.root.get({ normalize = true })
local cwd = Util.root.cwd()
if opts.relative == "cwd" and path:find(cwd, 1, true) == 1 then
path = path:sub(#cwd + 2)
else
path = path:sub(#root + 2)
end
local sep = package.config:sub(1, 1)
local parts = vim.split(path, "[\\/]")
if #parts > 3 then
parts = { parts[1], "", parts[#parts - 1], parts[#parts] }
end
if opts.modified_hl and vim.bo.modified then
parts[#parts] = M.format(self, parts[#parts], opts.modified_hl)
end
return table.concat(parts, sep)
end
end
---@param opts? {cwd:false, subdirectory: true, parent: true, other: true, icon?:string}
function M.root_dir(opts)
opts = vim.tbl_extend("force", {
cwd = false,
subdirectory = true,
parent = true,
other = true,
icon = "󱉭 ",
color = Util.ui.fg("Special"),
}, opts or {})
local function get()
local cwd = Util.root.cwd()
local root = Util.root.get({ normalize = true })
local name = vim.fs.basename(root)
if root == cwd then
-- root is cwd
return opts.cwd and name
elseif root:find(cwd, 1, true) == 1 then
-- root is subdirectory of cwd
return opts.subdirectory and name
elseif cwd:find(root, 1, true) == 1 then
-- root is parent directory of cwd
return opts.parent and name
else
-- root and cwd are not related
return opts.other and name
end
end
return {
function()
return (opts.icon and opts.icon .. " ") .. get()
end,
cond = function()
return type(get()) == "string"
end,
color = opts.color,
}
end
return M

90
lua/lazyvim/util/news.lua Normal file
View File

@ -0,0 +1,90 @@
local Config = require("lazyvim.config")
local Util = require("lazyvim.util")
---@class lazyvim.util.news
local M = {}
function M.hash(file)
local stat = vim.loop.fs_stat(file)
if not stat then
return
end
return stat.size .. ""
end
function M.setup()
vim.schedule(function()
if Config.news.lazyvim then
if not Config.json.data.news["NEWS.md"] then
M.welcome()
end
M.lazyvim(true)
end
if Config.news.neovim then
M.neovim(true)
end
end)
end
function M.welcome()
Util.info("Welcome to LazyVim!")
end
function M.changelog()
M.open("CHANGELOG.md", { plugin = "LazyVim" })
end
function M.lazyvim(when_changed)
M.open("NEWS.md", { plugin = "LazyVim", when_changed = when_changed })
end
function M.neovim(when_changed)
M.open("doc/news.txt", { rtp = true, when_changed = when_changed })
end
---@param file string
---@param opts? {plugin?:string, rtp?:boolean, when_changed?:boolean}
function M.open(file, opts)
local ref = file
opts = opts or {}
if opts.plugin then
local plugin = require("lazy.core.config").plugins[opts.plugin] --[[@as LazyPlugin?]]
if not plugin then
return Util.error("plugin not found: " .. opts.plugin)
end
file = plugin.dir .. "/" .. file
elseif opts.rtp then
file = vim.api.nvim_get_runtime_file(file, false)[1]
end
if not file then
return Util.error("File not found")
end
if opts.when_changed then
local is_new = not Config.json.data.news[ref]
local hash = M.hash(file)
if hash == Config.json.data.news[ref] then
return
end
Config.json.data.news[ref] = hash
Util.json.save()
-- don't open if file has never been opened
if is_new then
return
end
end
local float = require("lazy.util").float({
file = file,
size = { width = 0.6, height = 0.6 },
})
vim.opt_local.spell = false
vim.opt_local.wrap = false
vim.opt_local.signcolumn = "yes"
vim.opt_local.statuscolumn = " "
vim.opt_local.conceallevel = 3
vim.diagnostic.disable(float.buf)
end
return M

156
lua/lazyvim/util/plugin.lua Normal file
View File

@ -0,0 +1,156 @@
local Plugin = require("lazy.core.plugin")
local Util = require("lazyvim.util")
---@class lazyvim.util.plugin
local M = {}
M.use_lazy_file = true
M.lazy_file_events = { "BufReadPost", "BufNewFile", "BufWritePre" }
---@type table<string, string>
M.deprecated_extras = {
["lazyvim.plugins.extras.formatting.conform"] = "`conform.nvim` is now the default **LazyVim** formatter.",
["lazyvim.plugins.extras.linting.nvim-lint"] = "`nvim-lint` is now the default **LazyVim** linter.",
["lazyvim.plugins.extras.ui.dashboard"] = "`dashboard.nvim` is now the default **LazyVim** starter.",
}
M.deprecated_modules = {
["null-ls"] = "lsp.none-ls",
["nvim-navic.lib"] = "editor.navic",
["nvim-navic"] = "editor.navic",
}
---@type table<string, string>
M.renames = {
["windwp/nvim-spectre"] = "nvim-pack/nvim-spectre",
["jose-elias-alvarez/null-ls.nvim"] = "nvimtools/none-ls.nvim",
["null-ls.nvim"] = "none-ls.nvim",
["romgrk/nvim-treesitter-context"] = "nvim-treesitter/nvim-treesitter-context",
["glepnir/dashboard-nvim"] = "nvimdev/dashboard-nvim",
}
function M.setup()
M.fix_imports()
M.fix_renames()
M.lazy_file()
table.insert(package.loaders, function(module)
if M.deprecated_modules[module] then
Util.warn(
("`%s` is no longer included by default in **LazyVim**.\nPlease install the `%s` extra if you still want to use it."):format(
module,
M.deprecated_modules[module]
),
{ title = "LazyVim" }
)
return function() end
end
end)
end
function M.extra_idx(name)
local Config = require("lazy.core.config")
for i, extra in ipairs(Config.spec.modules) do
if extra == "lazyvim.plugins.extras." .. name then
return i
end
end
end
-- Properly load file based plugins without blocking the UI
function M.lazy_file()
M.use_lazy_file = M.use_lazy_file and vim.fn.argc(-1) > 0
-- Add support for the LazyFile event
local Event = require("lazy.core.handler.event")
if M.use_lazy_file then
-- We'll handle delayed execution of events ourselves
Event.mappings.LazyFile = { id = "LazyFile", event = "User", pattern = "LazyFile" }
Event.mappings["User LazyFile"] = Event.mappings.LazyFile
else
-- Don't delay execution of LazyFile events, but let lazy know about the mapping
Event.mappings.LazyFile = { id = "LazyFile", event = { "BufReadPost", "BufNewFile", "BufWritePre" } }
Event.mappings["User LazyFile"] = Event.mappings.LazyFile
return
end
local events = {} ---@type {event: string, buf: number, data?: any}[]
local done = false
local function load()
if #events == 0 or done then
return
end
done = true
vim.api.nvim_del_augroup_by_name("lazy_file")
---@type table<string,string[]>
local skips = {}
for _, event in ipairs(events) do
skips[event.event] = skips[event.event] or Event.get_augroups(event.event)
end
vim.api.nvim_exec_autocmds("User", { pattern = "LazyFile", modeline = false })
for _, event in ipairs(events) do
if vim.api.nvim_buf_is_valid(event.buf) then
Event.trigger({
event = event.event,
exclude = skips[event.event],
data = event.data,
buf = event.buf,
})
if vim.bo[event.buf].filetype then
Event.trigger({
event = "FileType",
buf = event.buf,
})
end
end
end
vim.api.nvim_exec_autocmds("CursorMoved", { modeline = false })
events = {}
end
-- schedule wrap so that nested autocmds are executed
-- and the UI can continue rendering without blocking
load = vim.schedule_wrap(load)
vim.api.nvim_create_autocmd(M.lazy_file_events, {
group = vim.api.nvim_create_augroup("lazy_file", { clear = true }),
callback = function(event)
table.insert(events, event)
load()
end,
})
end
function M.fix_imports()
Plugin.Spec.import = Util.inject.args(Plugin.Spec.import, function(_, spec)
local dep = M.deprecated_extras[spec and spec.import]
if dep then
dep = dep .. "\n" .. "Please remove the extra to hide this warning."
Util.warn(dep, { title = "LazyVim", once = true, stacktrace = true, stacklevel = 6 })
return false
end
end)
end
function M.fix_renames()
Plugin.Spec.add = Util.inject.args(Plugin.Spec.add, function(self, plugin)
if type(plugin) == "table" then
if M.renames[plugin[1]] then
Util.warn(
("Plugin `%s` was renamed to `%s`.\nPlease update your config for `%s`"):format(
plugin[1],
M.renames[plugin[1]],
self.importing or "LazyVim"
),
{ title = "LazyVim" }
)
plugin[1] = M.renames[plugin[1]]
end
end
end)
end
return M

181
lua/lazyvim/util/root.lua Normal file
View File

@ -0,0 +1,181 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.root
---@overload fun(): string
local M = setmetatable({}, {
__call = function(m)
return m.get()
end,
})
---@class LazyRoot
---@field paths string[]
---@field spec LazyRootSpec
---@alias LazyRootFn fun(buf: number): (string|string[])
---@alias LazyRootSpec string|string[]|LazyRootFn
---@type LazyRootSpec[]
M.spec = { "lsp", { ".git", "lua" }, "cwd" }
M.detectors = {}
function M.detectors.cwd()
return { vim.loop.cwd() }
end
function M.detectors.lsp(buf)
local bufpath = M.bufpath(buf)
if not bufpath then
return {}
end
local roots = {} ---@type string[]
for _, client in pairs(Util.lsp.get_clients({ bufnr = buf })) do
-- only check workspace folders, since we're not interested in clients
-- running in single file mode
local workspace = client.config.workspace_folders
for _, ws in pairs(workspace or {}) do
roots[#roots + 1] = vim.uri_to_fname(ws.uri)
end
end
return vim.tbl_filter(function(path)
path = Util.norm(path)
return path and bufpath:find(path, 1, true) == 1
end, roots)
end
---@param patterns string[]|string
function M.detectors.pattern(buf, patterns)
patterns = type(patterns) == "string" and { patterns } or patterns
local path = M.bufpath(buf) or vim.loop.cwd()
local pattern = vim.fs.find(patterns, { path = path, upward = true })[1]
return pattern and { vim.fs.dirname(pattern) } or {}
end
function M.bufpath(buf)
return M.realpath(vim.api.nvim_buf_get_name(assert(buf)))
end
function M.cwd()
return M.realpath(vim.loop.cwd()) or ""
end
function M.realpath(path)
if path == "" or path == nil then
return nil
end
path = vim.loop.fs_realpath(path) or path
return Util.norm(path)
end
---@param spec LazyRootSpec
---@return LazyRootFn
function M.resolve(spec)
if M.detectors[spec] then
return M.detectors[spec]
elseif type(spec) == "function" then
return spec
end
return function(buf)
return M.detectors.pattern(buf, spec)
end
end
---@param opts? { buf?: number, spec?: LazyRootSpec[], all?: boolean }
function M.detect(opts)
opts = opts or {}
opts.spec = opts.spec or type(vim.g.root_spec) == "table" and vim.g.root_spec or M.spec
opts.buf = (opts.buf == nil or opts.buf == 0) and vim.api.nvim_get_current_buf() or opts.buf
local ret = {} ---@type LazyRoot[]
for _, spec in ipairs(opts.spec) do
local paths = M.resolve(spec)(opts.buf)
paths = paths or {}
paths = type(paths) == "table" and paths or { paths }
local roots = {} ---@type string[]
for _, p in ipairs(paths) do
local pp = M.realpath(p)
if pp and not vim.tbl_contains(roots, pp) then
roots[#roots + 1] = pp
end
end
table.sort(roots, function(a, b)
return #a > #b
end)
if #roots > 0 then
ret[#ret + 1] = { spec = spec, paths = roots }
if opts.all == false then
break
end
end
end
return ret
end
function M.info()
local spec = type(vim.g.root_spec) == "table" and vim.g.root_spec or M.spec
local roots = M.detect({ all = true })
local lines = {} ---@type string[]
local first = true
for _, root in ipairs(roots) do
for _, path in ipairs(root.paths) do
lines[#lines + 1] = ("- [%s] `%s` **(%s)**"):format(
first and "x" or " ",
path,
type(root.spec) == "table" and table.concat(root.spec, ", ") or root.spec
)
first = false
end
end
lines[#lines + 1] = "```lua"
lines[#lines + 1] = "vim.g.root_spec = " .. vim.inspect(spec)
lines[#lines + 1] = "```"
require("lazyvim.util").info(lines, { title = "LazyVim Roots" })
return roots[1] and roots[1].paths[1] or vim.loop.cwd()
end
---@type table<number, string>
M.cache = {}
function M.setup()
vim.api.nvim_create_user_command("LazyRoot", function()
Util.root.info()
end, { desc = "LazyVim roots for the current buffer" })
vim.api.nvim_create_autocmd({ "LspAttach", "BufWritePost" }, {
group = vim.api.nvim_create_augroup("lazyvim_root_cache", { clear = true }),
callback = function(event)
M.cache[event.buf] = nil
end,
})
end
-- returns the root directory based on:
-- * lsp workspace folders
-- * lsp root_dir
-- * root pattern of filename of the current buffer
-- * root pattern of cwd
---@param opts? {normalize?:boolean}
---@return string
function M.get(opts)
local buf = vim.api.nvim_get_current_buf()
local ret = M.cache[buf]
if not ret then
local roots = M.detect({ all = false })
ret = roots[1] and roots[1].paths[1] or vim.loop.cwd()
M.cache[buf] = ret
end
if opts and opts.normalize then
return ret
end
return Util.is_win() and ret:gsub("/", "\\") or ret
end
---@param opts? {hl_last?: string}
function M.pretty_path(opts)
return ""
end
return M

View File

@ -0,0 +1,57 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.telescope.opts
---@field cwd? string|boolean
---@field show_untracked? boolean
---@class lazyvim.util.telescope
---@overload fun(builtin:string, opts?:lazyvim.util.telescope.opts)
local M = setmetatable({}, {
__call = function(m, ...)
return m.telescope(...)
end,
})
-- this will return a function that calls telescope.
-- cwd will default to lazyvim.util.get_root
-- for `files`, git_files or find_files will be chosen depending on .git
---@param builtin string
---@param opts? lazyvim.util.telescope.opts
function M.telescope(builtin, opts)
local params = { builtin = builtin, opts = opts }
return function()
builtin = params.builtin
opts = params.opts
opts = vim.tbl_deep_extend("force", { cwd = Util.root() }, opts or {}) --[[@as lazyvim.util.telescope.opts]]
if builtin == "files" then
if vim.loop.fs_stat((opts.cwd or vim.loop.cwd()) .. "/.git") then
opts.show_untracked = true
builtin = "git_files"
else
builtin = "find_files"
end
end
if opts.cwd and opts.cwd ~= vim.loop.cwd() then
---@diagnostic disable-next-line: inject-field
opts.attach_mappings = function(_, map)
map("i", "<a-c>", function()
local action_state = require("telescope.actions.state")
local line = action_state.get_current_line()
M.telescope(
params.builtin,
vim.tbl_deep_extend("force", {}, params.opts or {}, { cwd = false, default_text = line })
)()
end)
return true
end
end
require("telescope.builtin")[builtin](opts)
end
end
function M.config_files()
return Util.telescope("find_files", { cwd = vim.fn.stdpath("config") })
end
return M

View File

@ -0,0 +1,55 @@
---@class lazyvim.util.terminal
---@overload fun(cmd: string|string[], opts: LazyTermOpts): LazyFloat
local M = setmetatable({}, {
__call = function(m, ...)
return m.open(...)
end,
})
---@type table<string,LazyFloat>
local terminals = {}
---@class LazyTermOpts: LazyCmdOptions
---@field interactive? boolean
---@field esc_esc? boolean
---@field ctrl_hjkl? boolean
-- Opens a floating terminal (interactive by default)
---@param cmd? string[]|string
---@param opts? LazyTermOpts
function M.open(cmd, opts)
opts = vim.tbl_deep_extend("force", {
ft = "lazyterm",
size = { width = 0.9, height = 0.9 },
}, opts or {}, { persistent = true }) --[[@as LazyTermOpts]]
local termkey = vim.inspect({ cmd = cmd or "shell", cwd = opts.cwd, env = opts.env, count = vim.v.count1 })
if terminals[termkey] and terminals[termkey]:buf_valid() then
terminals[termkey]:toggle()
else
terminals[termkey] = require("lazy.util").float_term(cmd, opts)
local buf = terminals[termkey].buf
vim.b[buf].lazyterm_cmd = cmd
if opts.esc_esc == false then
vim.keymap.set("t", "<esc>", "<esc>", { buffer = buf, nowait = true })
end
if opts.ctrl_hjkl == false then
vim.keymap.set("t", "<c-h>", "<c-h>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-j>", "<c-j>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-k>", "<c-k>", { buffer = buf, nowait = true })
vim.keymap.set("t", "<c-l>", "<c-l>", { buffer = buf, nowait = true })
end
vim.api.nvim_create_autocmd("BufEnter", {
buffer = buf,
callback = function()
vim.cmd.startinsert()
end,
})
end
return terminals[termkey]
end
return M

View File

@ -0,0 +1,76 @@
local Util = require("lazyvim.util")
---@class lazyvim.util.toggle
local M = {}
---@param silent boolean?
---@param values? {[1]:any, [2]:any}
function M.option(option, silent, values)
if values then
if vim.opt_local[option]:get() == values[1] then
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = values[2]
else
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = values[1]
end
return Util.info("Set " .. option .. " to " .. vim.opt_local[option]:get(), { title = "Option" })
end
---@diagnostic disable-next-line: no-unknown
vim.opt_local[option] = not vim.opt_local[option]:get()
if not silent then
if vim.opt_local[option]:get() then
Util.info("Enabled " .. option, { title = "Option" })
else
Util.warn("Disabled " .. option, { title = "Option" })
end
end
end
local nu = { number = true, relativenumber = true }
function M.number()
if vim.opt_local.number:get() or vim.opt_local.relativenumber:get() then
nu = { number = vim.opt_local.number:get(), relativenumber = vim.opt_local.relativenumber:get() }
vim.opt_local.number = false
vim.opt_local.relativenumber = false
Util.warn("Disabled line numbers", { title = "Option" })
else
vim.opt_local.number = nu.number
vim.opt_local.relativenumber = nu.relativenumber
Util.info("Enabled line numbers", { title = "Option" })
end
end
local enabled = true
function M.diagnostics()
enabled = not enabled
if enabled then
vim.diagnostic.enable()
Util.info("Enabled diagnostics", { title = "Diagnostics" })
else
vim.diagnostic.disable()
Util.warn("Disabled diagnostics", { title = "Diagnostics" })
end
end
---@param buf? number
---@param value? boolean
function M.inlay_hints(buf, value)
local ih = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint
if type(ih) == "function" then
ih(buf, value)
elseif type(ih) == "table" and ih.enable then
if value == nil then
value = not ih.is_enabled(buf)
end
ih.enable(buf, value)
end
end
setmetatable(M, {
__call = function(m, ...)
return m.option(...)
end,
})
return M

189
lua/lazyvim/util/ui.lua Normal file
View File

@ -0,0 +1,189 @@
---@class lazyvim.util.ui
local M = {}
---@alias Sign {name:string, text:string, texthl:string, priority:number}
-- Returns a list of regular and extmark signs sorted by priority (low to high)
---@return Sign[]
---@param buf number
---@param lnum number
function M.get_signs(buf, lnum)
-- Get regular signs
---@type Sign[]
local signs = {}
if vim.fn.has("nvim-0.10") == 0 then
-- Only needed for Neovim <0.10
-- Newer versions include legacy signs in nvim_buf_get_extmarks
for _, sign in ipairs(vim.fn.sign_getplaced(buf, { group = "*", lnum = lnum })[1].signs) do
local ret = vim.fn.sign_getdefined(sign.name)[1] --[[@as Sign]]
if ret then
ret.priority = sign.priority
signs[#signs + 1] = ret
end
end
end
-- Get extmark signs
local extmarks = vim.api.nvim_buf_get_extmarks(
buf,
-1,
{ lnum - 1, 0 },
{ lnum - 1, -1 },
{ details = true, type = "sign" }
)
for _, extmark in pairs(extmarks) do
signs[#signs + 1] = {
name = extmark[4].sign_hl_group or "",
text = extmark[4].sign_text,
texthl = extmark[4].sign_hl_group,
priority = extmark[4].priority,
}
end
-- Sort by priority
table.sort(signs, function(a, b)
return (a.priority or 0) < (b.priority or 0)
end)
return signs
end
---@return Sign?
---@param buf number
---@param lnum number
function M.get_mark(buf, lnum)
local marks = vim.fn.getmarklist(buf)
vim.list_extend(marks, vim.fn.getmarklist())
for _, mark in ipairs(marks) do
if mark.pos[1] == buf and mark.pos[2] == lnum and mark.mark:match("[a-zA-Z]") then
return { text = mark.mark:sub(2), texthl = "DiagnosticHint" }
end
end
end
---@param sign? Sign
---@param len? number
function M.icon(sign, len)
sign = sign or {}
len = len or 2
local text = vim.fn.strcharpart(sign.text or "", 0, len) ---@type string
text = text .. string.rep(" ", len - vim.fn.strchars(text))
return sign.texthl and ("%#" .. sign.texthl .. "#" .. text .. "%*") or text
end
function M.foldtext()
local ok = pcall(vim.treesitter.get_parser, vim.api.nvim_get_current_buf())
local ret = ok and vim.treesitter.foldtext and vim.treesitter.foldtext()
if not ret or type(ret) == "string" then
ret = { { vim.api.nvim_buf_get_lines(0, vim.v.lnum - 1, vim.v.lnum, false)[1], {} } }
end
table.insert(ret, { " " .. require("lazyvim.config").icons.misc.dots })
if not vim.treesitter.foldtext then
return table.concat(
vim.tbl_map(function(line)
return line[1]
end, ret),
" "
)
end
return ret
end
function M.statuscolumn()
local win = vim.g.statusline_winid
local buf = vim.api.nvim_win_get_buf(win)
local is_file = vim.bo[buf].buftype == ""
local show_signs = vim.wo[win].signcolumn ~= "no"
local components = { "", "", "" } -- left, middle, right
if show_signs then
---@type Sign?,Sign?,Sign?
local left, right, fold
for _, s in ipairs(M.get_signs(buf, vim.v.lnum)) do
if s.name and s.name:find("GitSign") then
right = s
else
left = s
end
end
if vim.v.virtnum ~= 0 then
left = nil
end
vim.api.nvim_win_call(win, function()
if vim.fn.foldclosed(vim.v.lnum) >= 0 then
fold = { text = vim.opt.fillchars:get().foldclose or "", texthl = "Folded" }
end
end)
-- Left: mark or non-git sign
components[1] = M.icon(M.get_mark(buf, vim.v.lnum) or left)
-- Right: fold icon or git sign (only if file)
components[3] = is_file and M.icon(fold or right) or ""
end
-- Numbers in Neovim are weird
-- They show when either number or relativenumber is true
local is_num = vim.wo[win].number
local is_relnum = vim.wo[win].relativenumber
if (is_num or is_relnum) and vim.v.virtnum == 0 then
if vim.v.relnum == 0 then
components[2] = is_num and "%l" or "%r" -- the current line
else
components[2] = is_relnum and "%r" or "%l" -- other lines
end
components[2] = "%=" .. components[2] .. " " -- right align
end
return table.concat(components, "")
end
function M.fg(name)
---@type {foreground?:number}?
---@diagnostic disable-next-line: deprecated
local hl = vim.api.nvim_get_hl and vim.api.nvim_get_hl(0, { name = name }) or vim.api.nvim_get_hl_by_name(name, true)
---@diagnostic disable-next-line: undefined-field
local fg = hl and (hl.fg or hl.foreground)
return fg and { fg = string.format("#%06x", fg) } or nil
end
M.skip_foldexpr = {} ---@type table<number,boolean>
local skip_check = assert(vim.loop.new_check())
function M.foldexpr()
local buf = vim.api.nvim_get_current_buf()
-- still in the same tick and no parser
if M.skip_foldexpr[buf] then
return "0"
end
-- don't use treesitter folds for non-file buffers
if vim.bo[buf].buftype ~= "" then
return "0"
end
-- as long as we don't have a filetype, don't bother
-- checking if treesitter is available (it won't)
if vim.bo[buf].filetype == "" then
return "0"
end
local ok = pcall(vim.treesitter.get_parser, buf)
if ok then
return vim.treesitter.foldexpr()
end
-- no parser available, so mark it as skip
-- in the next tick, all skip marks will be reset
M.skip_foldexpr[buf] = true
skip_check:start(function()
M.skip_foldexpr = {}
skip_check:stop()
end)
return "0"
end
return M

View File

@ -60,7 +60,7 @@ return {
},
-- Enable this to show formatters used in a notification
-- Useful for debugging formatter issues
format_notify = false,
format_notify = true,
-- LSP Server Settings
---@type lspconfig.options
---@diagnostic disable: missing-fields
@ -99,6 +99,7 @@ return {
end
-- Setup autoformat
require('plex.plugins.lsp.format').setup(opts)
-- Setup formatting, keymaps and highlights.
local lsp_on_attach = require('plex.lib.utils').on_attach
---@param client lsp.Client

View File

@ -1,179 +1,102 @@
-- LSP: Key-maps
-- https://github.com/rafi/vim-config
local M = {}
---@type PluginLspKeys
---@type LazyKeysLspSpec[]|nil
M._keys = nil
---@return (LazyKeys|{has?:string})[]
---@alias LazyKeysLspSpec LazyKeysSpec|{has?:string}
---@alias LazyKeysLsp LazyKeys|{has?:string}
---@return LazyKeysLspSpec[]
function M.get()
if M._keys then
return M._keys
end
local format = function()
require('plex.plugins.lsp.format').format({ force = true })
end
---@class PluginLspKeys
-- stylua: ignore
M._keys = {
{ 'gD', vim.lsp.buf.declaration, desc = 'Goto Declaration', has = 'declaration' },
{ 'gd', vim.lsp.buf.definition, desc = 'Goto Definition', has = 'definition' },
{ 'gr', vim.lsp.buf.references, desc = 'References', has = 'references' },
{ 'gy', vim.lsp.buf.type_definition, desc = 'Goto Type Definition', has = 'typeDefinition' },
{ 'gi', vim.lsp.buf.implementation, desc = 'Goto Implementation', has = 'implementation' },
{ 'gK', vim.lsp.buf.signature_help, desc = 'Signature Help', has = 'signatureHelp' },
{ '<C-g>h', vim.lsp.buf.signature_help, mode = 'i', desc = 'Signature Help', has = 'signatureHelp' },
{ ']d', M.diagnostic_goto(true), desc = 'Next Diagnostic' },
{ '[d', M.diagnostic_goto(false), desc = 'Prev Diagnostic' },
{ ']e', M.diagnostic_goto(true, 'ERROR'), desc = 'Next Error' },
{ '[e', M.diagnostic_goto(false, 'ERROR'), desc = 'Prev Error' },
{ ',wa', vim.lsp.buf.add_workspace_folder, desc = 'Show Workspace Folders' },
{ ',wr', vim.lsp.buf.remove_workspace_folder, desc = 'Remove Workspace Folder' },
{ ',wl', '<cmd>lua =vim.lsp.buf.list_workspace_folders()<CR>', desc = 'List Workspace Folders' },
{ '<localleader>K', function()
-- Show hover documentation or folded lines.
local winid = require('plex.lib.utils').has('nvim-ufo')
and require('ufo').peekFoldedLinesUnderCursor() or nil
if not winid then
vim.lsp.buf.hover()
end
end },
{ '<Leader>ud', function() M.diagnostic_toggle(false) end, desc = 'Disable Diagnostics' },
{ '<Leader>uD', function() M.diagnostic_toggle(true) end, desc = 'Disable All Diagnostics' },
{ '<leader>cl', '<cmd>LspInfo<cr>' },
{ '<leader>cf', format, desc = 'Format Document', has = 'formatting' },
{ '<leader>cf', format, mode = 'x', desc = 'Format Range' }, -- , has = 'rangeFormatting'
{ '<Leader>cr', vim.lsp.buf.rename, desc = 'Rename', has = 'rename' },
{ '<Leader>ce', vim.diagnostic.open_float, desc = 'Open diagnostics' },
{ '<Leader>ca', vim.lsp.buf.code_action, mode = { 'n', 'x' }, has = 'codeAction', desc = 'Code Action' },
{ '<Leader>cA', function()
vim.lsp.buf.code_action({
context = {
only = { 'source' },
diagnostics = {},
},
})
end, desc = 'Source Action', has = 'codeAction' },
}
return M._keys
if M._keys then
return M._keys
end
-- stylua: ignore
M._keys = {
{ "<leader>cl", "<cmd>LspInfo<cr>", desc = "Lsp Info" },
{ "gd", function() require("telescope.builtin").lsp_definitions({ reuse_win = true }) end, desc = "Goto Definition", has = "definition" },
{ "gr", "<cmd>Telescope lsp_references<cr>", desc = "References" },
{ "gD", vim.lsp.buf.declaration, desc = "Goto Declaration" },
{ "gI", function() require("telescope.builtin").lsp_implementations({ reuse_win = true }) end, desc = "Goto Implementation" },
{ "gy", function() require("telescope.builtin").lsp_type_definitions({ reuse_win = true }) end, desc = "Goto T[y]pe Definition" },
{ "K", vim.lsp.buf.hover, desc = "Hover" },
{ "gK", vim.lsp.buf.signature_help, desc = "Signature Help", has = "signatureHelp" },
{ "<c-k>", vim.lsp.buf.signature_help, mode = "i", desc = "Signature Help", has = "signatureHelp" },
{ "<leader>ca", vim.lsp.buf.code_action, desc = "Code Action", mode = { "n", "v" }, has = "codeAction" },
{
"<leader>cA",
function()
vim.lsp.buf.code_action({
context = {
only = {
"source",
},
diagnostics = {},
},
})
end,
desc = "Source Action",
has = "codeAction",
}
}
if require("lazyvim.util").has("inc-rename.nvim") then
M._keys[#M._keys + 1] = {
"<leader>cr",
function()
local inc_rename = require("inc_rename")
return ":" .. inc_rename.config.cmd_name .. " " .. vim.fn.expand("<cword>")
end,
expr = true,
desc = "Rename",
has = "rename",
}
else
M._keys[#M._keys + 1] = { "<leader>cr", vim.lsp.buf.rename, desc = "Rename", has = "rename" }
end
return M._keys
end
---@param method string
function M.has(buffer, method)
method = method:find('/') and method or 'textDocument/' .. method
local clients
if vim.lsp.get_clients ~= nil then
clients = vim.lsp.get_clients({ bufnr = buffer })
else
---@diagnostic disable-next-line: deprecated
clients = vim.lsp.get_active_clients({ bufnr = buffer })
end
for _, client in ipairs(clients) do
if client.supports_method(method) then
return true
end
end
return false
method = method:find("/") and method or "textDocument/" .. method
local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do
if client.supports_method(method) then
return true
end
end
return false
end
---@param buffer integer
---@return (LazyKeys|{has?:string})[]
function M.resolve(buffer)
local Keys = require('lazy.core.handler.keys')
local keymaps = {} ---@type table<string,LazyKeys|{has?:string}>
local function add(keymap)
local keys = Keys.parse(keymap)
if keys[2] == false then
keymaps[keys.id] = nil
else
keymaps[keys.id] = keys
end
end
for _, keymap in ipairs(M.get()) do
add(keymap)
end
local opts = require('plex.lib.utils').opts('nvim-lspconfig')
local clients
if vim.lsp.get_clients ~= nil then
clients = vim.lsp.get_clients({ bufnr = buffer })
else
---@diagnostic disable-next-line: deprecated
clients = vim.lsp.get_active_clients({ bufnr = buffer })
end
for _, client in ipairs(clients) do
local maps = opts.servers[client.name] and opts.servers[client.name].keys
or {}
for _, keymap in ipairs(maps) do
add(keymap)
end
end
return keymaps
local Keys = require("lazy.core.handler.keys")
if not Keys.resolve then
return {}
end
local spec = M.get()
local opts = require("lazyvim.util").opts("nvim-lspconfig")
local clients = require("lazyvim.util").lsp.get_clients({ bufnr = buffer })
for _, client in ipairs(clients) do
local maps = opts.servers[client.name] and opts.servers[client.name].keys or {}
vim.list_extend(spec, maps)
end
return Keys.resolve(spec)
end
---@param client lsp.Client
---@param buffer integer
function M.on_attach(client, buffer)
local Keys = require('lazy.core.handler.keys')
local keymaps = M.resolve(buffer)
function M.on_attach(_, buffer)
local Keys = require("lazy.core.handler.keys")
local keymaps = M.resolve(buffer)
-- FIXME: This part causes weird errors and IDK what it does.
-- for _, keys in pairs(keymaps) do
-- if not keys.has or M.has(buffer, keys.has) then
-- local opts = Keys.opts(keys)
-- ---@diagnostic disable-next-line: no-unknown
-- opts.has = nil
-- opts.silent = opts.silent ~= false
-- opts.buffer = buffer
-- vim.keymap.set(keys.mode or 'n', keys[1], keys[2], opts)
-- end
-- end
end
-- Toggle diagnostics locally (false) or globally (true).
---@param global boolean
function M.diagnostic_toggle(global)
local bufnr, cmd, msg, state
if global then
bufnr = nil
state = vim.g.diagnostics_disabled
vim.g.diagnostics_disabled = not state
else
bufnr = 0
if vim.fn.has('nvim-0.9') == 1 then
state = vim.diagnostic.is_disabled(bufnr)
else
state = vim.b.diagnostics_disabled
vim.b.diagnostics_disabled = not state
end
end
cmd = state and 'enable' or 'disable'
msg = cmd:gsub('^%l', string.upper) .. 'd diagnostics'
if global then
msg = msg .. ' globally'
end
vim.notify(msg)
vim.schedule(function()
vim.diagnostic[cmd](bufnr)
end)
end
---@param next boolean
---@param severity string|nil
---@return fun()
function M.diagnostic_goto(next, severity)
local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev
local severity_int = severity and vim.diagnostic.severity[severity] or nil
return function()
go({ severity = severity_int })
end
for _, keys in pairs(keymaps) do
if not keys.has or M.has(buffer, keys.has) then
local opts = Keys.opts(keys)
opts.has = nil
opts.silent = opts.silent ~= false
opts.buffer = buffer
vim.keymap.set(keys.mode or "n", keys.lhs, keys.rhs, opts)
end
end
end
return M