Share your setups #36
Replies: 41 comments 121 replies
-
|
Hi, my config https://github.com/axpira/dotfiles/blob/main/nvim/init.lua |
Beta Was this translation helpful? Give feedback.
-
require("mini.base16").setup {
palette = {
base00 = "#000000",
base01 = "#111111",
base02 = "#333333",
base03 = "#bbbbbb",
base04 = "#dddddd",
base05 = "#ffffff",
base06 = "#ffffff",
base07 = "#ffffff",
base09 = "#ff2222",
base08 = "#ff9922",
base0A = "#ff22ff",
base0B = "#22ff22",
base0C = "#4444ff",
base0D = "#22ffff",
base0E = "#ffff22",
base0F = "#999999",
},
use_cterm = false,
}
require("mini.comment").setup {}
require("mini.completion").setup {}
require("mini.jump").setup {
mappings = {
repeat_jump = "",
},
highlight_delay = 0,
}
require("mini.pairs").setup {}
require("mini.sessions").setup {
directory = vim.fn.stdpath "config" .. "/sessions",
}
require("mini.starter").setup {
evaluate_single = true,
}
require("mini.statusline").setup {}
require("mini.surround").setup {
n_lines = 100,
mappings = {
add = "S",
delete = "ds",
find_left = "[s",
find = "]s",
highlight = "",
replace = "cs",
update_n_lines = "",
},
}
require("mini.tabline").setup {} |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
I had a go at getting mini.ai to work with treesitter text objects. It seems to work alright with the little testing I've done, but I'm sure there are some edge cases that will break this. Credit for most of the work goes to the nvim-treesitter-textobjects plugin, the One other thing I added is the ability to use a table of queries instead of just one. Most of the logic was already there, it should just find the best match of any of the given queries. I'm 99% sure this is more complicated than it needs to be, as I've just kinda smooshed the two things together. UpdateThanks to the amazing update to the api (seriously, thanks so much @echasnovski), I have massively simplified this to the below function. My approach does come with the dependency on the nvim-treesitter plugin, but it supports multiple queries in one object and should have full support for all queries defined by nvim-treesitter-textobjects. local queries = require "nvim-treesitter.query"
local miniAiTreesitter = function(ai_type, _, _, query_list)
ai_type = ai_type == "a" and ".outer" or ".inner"
query_list = vim.tbl_map(function(query) return query .. ai_type end, query_list)
local matches = {}
for _, query in pairs(query_list) do
vim.list_extend(matches, queries.get_capture_matches_recursively(0, query, "textobjects"))
end
matches = vim.tbl_map(function(match)
local from_line, from_col, to_line, to_col = match.node:range()
return {
from = { line = from_line + 1, col = from_col + 1 },
to = { line = to_line + 1, col = to_col + 1 }
}
end, matches)
return matches
end
local miniAiTreeWrapper = function(query_list)
if type(query_list) ~= "table" then
query_list = { query_list }
end
return function(ai_type, _, opts)
return miniAiTreesitter(ai_type, _, opts, query_list)
end
end
require("mini.ai").setup({
custom_textobjects = {
o = miniAiTreeWrapper({"@block", "@conditional", "@loop"}),
s = miniAiTreeWrapper({"@function", "@class"}),
c = miniAiTreeWrapper("@comment"),
},
})If I make any further changes to this you should be able to find them here |
Beta Was this translation helpful? Give feedback.
-
|
mini.nvim is beautifull one set plugin, here is my setup |
Beta Was this translation helpful? Give feedback.
-
|
This is my config It's still a work in progress (I started a couple of days ago, switching from vscode after I decided, finally, to go 100% neovim). So mini is currently 90% of my plugins, if not more. 🤣 This is amazing, I said in reddit and I need to say that again: thank you for this impressive work. |
Beta Was this translation helpful? Give feedback.
-
|
An idea that maybe could be of interest of more people: https://www.reddit.com/r/neovim/comments/x0hf25/nicer_jupyter_notebook_workflow_with_neovim/ |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
|
Very nice. (Minimap scrolls to the sides - not necessary.) |
Beta Was this translation helpful? Give feedback.
-
|
Mini is my favourite plugin. My neovim setup is minimal, so I really enjoy that I can setup all my mini modules of choice without setting any preferences, because the defaults are just so solid for me. The proof is that I can just loop an array to initialise them. |
Beta Was this translation helpful? Give feedback.
-
|
You can look at mine in here |
Beta Was this translation helpful? Give feedback.
-
|
Here is my setup: The border colors for the notify window seem to be both fore- and background to be the same: |
Beta Was this translation helpful? Give feedback.
-
|
Here is how { -- Split parameters, simpler version of treesj.lua
url = 'https://github.com/echasnovski/mini.splitjoin',
version = '*',
opts = {
mappings = {}, -- Configured in treesj => treesitter.lua
detect = {
separator = '[,;]'
}
}
},
{ -- Split/Join, integrated with mini.splitjoin
url = 'https://github.com/Wansmer/treesj',
dependencies = { 'https://github.com/nvim-treesitter/nvim-treesitter/' },
keys = {
{ '<leader>m', mode = { 'n', 'v' }, desc = 'Toggle split' }
},
config = function()
local tsj = require('treesj')
tsj.setup({
use_default_keymaps = false,
max_join_length = 512,
})
local function get_pos_lang(node)
local c = vim.api.nvim_win_get_cursor(0)
local range = { c[1] - 1, c[2], c[1] - 1, c[2] }
local buf = vim.api.nvim_get_current_buf()
local ok, parser = pcall(
vim.treesitter.get_parser,
buf,
vim.treesitter.language.get_lang(vim.bo[buf].ft)
)
if not ok then
return ""
end
local current_tree = parser:language_for_range(range)
return current_tree:lang()
end
vim.keymap.set({ 'n', 'v' }, "<leader>m", function()
local tsj_langs = require("treesj.langs")["presets"]
local lang = get_pos_lang()
if lang ~= "" and tsj_langs[lang] then
require("treesj").toggle()
else
require("mini.splitjoin").toggle()
end
end)
end
} |
Beta Was this translation helpful? Give feedback.
-
|
I spent this morning tweaking the look of my mini.statusline: My changes from the default:
I spent a couple hours (yes, sadly), experimenting with lots of other variations:
I love I love I also enabled The only packages I've tried thus far that I did not care for were With regards to Overall, love all the hard work you've put into the mini packages. Simply amazing! |
Beta Was this translation helpful? Give feedback.
-
|
Recently migrated to Highlights: Lazy stats (startup time). Currently updated via auto command due to stats not being available when `mini.starter` starts. -- Set starter footer and refresh after `startuptime` is available
vim.api.nvim_create_autocmd("User", {
pattern = "MiniStarterOpened",
callback = function()
vim.api.nvim_create_autocmd("User", {
pattern = "LazyVimStarted",
callback = function()
local starter = require "mini.starter"
local stats = require("lazy").stats()
local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
starter.config.footer = function()
return "⚡ Loaded plugins: "
.. stats.loaded
.. "/"
.. stats.count
.. "\n⚡ Startup time: "
.. ms
.. " ms"
end
starter.refresh()
end,
})
end,
})A dedicated section for workspaces from `workspaces.nvim`. local workspace_items = function()
local workspaces = require "workspaces"
local items = {}
for _, w in pairs(workspaces.get()) do
table.insert(items, {
name = w.name .. " " .. vim.fn.fnamemodify(w.path, ":~:."),
action = "WorkspacesOpen " .. w.name,
section = "Workspaces",
})
end
return items
endA workaround for centralizing header and justifying select sections. -- A workaround to centralize everything.
-- `aligning("center", "center")` will centralize the longest line in
-- `content`, then left align other items to its beginning.
-- It causes the header to not be truly centralized and have a variable
-- shift to the left.
-- This function will use `aligning` and pad the header accordingly.
-- It also goes over `justified_sections`, goes over all their items names
-- and justifies them by padding existing space in them.
-- Since `item_bullet` are separated from the items themselves, their
-- width is measured separately and deducted from the padding.
local centralize = function(justified_sections, centralize_header)
return function(content, buf_id)
-- Get max line width, same as in `aligning`
local max_line_width = math.max(unpack(vim.tbl_map(function(l)
return vim.fn.strdisplaywidth(l)
end, starter.content_to_lines(content))))
-- Align
content = starter.gen_hook.aligning("center", "center")(content, buf_id)
-- Iterate over header items and pad with relative missing spaces
if centralize_header == true then
local coords = starter.content_coords(content, "header")
for _, c in ipairs(coords) do
local unit = content[c.line][c.unit]
local pad = (max_line_width - vim.fn.strdisplaywidth(unit.string))
/ 2
if unit.string ~= "" then
unit.string = string.rep(" ", pad) .. unit.string
end
end
end
-- Justify recent files and workspaces
if justified_sections ~= nil and #justified_sections > 0 then
-- Check if `adding_bullet` has mutated the `content`
local coords = starter.content_coords(content, "item_bullet")
local bullet_len = 0
if coords ~= nil then
-- Bullet items are defined, compensate for bullet prefix width
bullet_len = vim.fn.strdisplaywidth(
content[coords[1].line][coords[1].unit].string
)
end
coords = starter.content_coords(content, "item")
for _, c in ipairs(coords) do
local unit = content[c.line][c.unit]
if vim.tbl_contains(justified_sections, unit.item.section) then
local one, two = unpack(vim.split(unit.string, " "))
unit.string = one
.. string.rep(
" ",
max_line_width
- vim.fn.strdisplaywidth(unit.string)
- bullet_len
+ 1
)
.. two
end
end
end
return content
end
endHow it is used in `MiniStarter.setup`. starter.setup {
-- evaluate_single = true,
header = "███████████████████████████\n"
.. "███████▀▀▀░░░░░░░▀▀▀███████\n"
.. "████▀░░░░░░░░░░░░░░░░░▀████\n"
.. "███│░░░░░░░░░░░░░░░░░░░│███\n"
.. "██▌│░░░░░░░░░░░░░░░░░░░│▐██\n"
.. "██░└┐░░░░░░░░░░░░░░░░░┌┘░██\n"
.. "██░░└┐░░░░░░░░░░░░░░░┌┘░░██\n"
.. "██░░┌┘▄▄▄▄▄░░░░░▄▄▄▄▄└┐░░██\n"
.. "██▌░│██████▌░░░▐██████│░▐██\n"
.. "███░│▐███▀▀░░▄░░▀▀███▌│░███\n"
.. "██▀─┘░░░░░░░▐█▌░░░░░░░└─▀██\n"
.. "██▄░░░▄▄▄▓░░▀█▀░░▓▄▄▄░░░▄██\n"
.. "████▄─┘██▌░░░░░░░▐██└─▄████\n"
.. "█████░░▐█─┬┬┬┬┬┬┬─█▌░░█████\n"
.. "████▌░░░▀┬┼┼┼┼┼┼┼┬▀░░░▐████\n"
.. "█████▄░░░└┴┴┴┴┴┴┴┘░░░▄█████\n"
.. "███████▄░░░░░░░░░░░▄███████\n"
.. "██████████▄▄▄▄▄▄▄██████████\n"
.. "pwd: "
.. vim.fn.fnamemodify(vim.fn.getcwd(), ":~:."),
items = {
workspace_items,
starter.sections.recent_files(10, false, function(path)
-- Bring back trailing slash after `dirname`
return " " .. vim.fn.fnamemodify(path, ":~:.:h") .. "/"
end),
{ section = "Tools", name = "Lazy", action = "Lazy" },
{ section = "Tools", name = "Telescope", action = "Telescope" },
starter.sections.builtin_actions(),
},
content_hooks = {
-- starter.gen_hook.adding_bullet(),
centralize({ "Recent files", "Workspaces" }, true),
},
}
workspaces.nvim |
Beta Was this translation helpful? Give feedback.
-
|
This is what I've got so far, still WIP: https://gist.github.com/luisdavim/b985e141310567969d90114d9cbd15b8 |
Beta Was this translation helpful? Give feedback.
-
|
Hi I just found this discussion and here is my swahpy/mvim. Looking forward to your feedback! |
Beta Was this translation helpful? Give feedback.
-
|
Hello, I would also like to share and get feedback from my configuration: |
Beta Was this translation helpful? Give feedback.
-
|
My entire nvim dots are in one file and is great for java development right now. I had a version with lazy a while back with 30 plugins and now I have around 10 and some can be removed. Mini.nvim made life so much easier here is the repo: https://github.com/DarthMooMancer/MacOS-Dots |
Beta Was this translation helpful? Give feedback.
-
|
Here is my config: https://github.com/aorith/dotfiles/tree/master/topics/neovim/nvim I really like the consistency of |
Beta Was this translation helpful? Give feedback.
-
|
Hope I'm not late to the party. I read through mini files and IN LOVE with the bookmarks function. Perf for navigation in large projects. However, I'd prefer to have that in per project approach rather than in-memory solution where the bookmarks is lost when closing neovim. So I took the liberty to fork and modify it a little bit to store the data to 'mini.files' setupreturn {
"liketoeatcheese/mini.files",
branch = "main",
dependencies = {},
config = function()
require("mini.files").setup( -- No need to copy this inside `setup()`. Will be used automatically.
{
-- Customization of shown content
content = {
-- Predicate for which file system entries to show
filter = nil,
-- What prefix to show to the left of file system entry
prefix = nil,
-- In which order to show file system entries
sort = nil,
},
-- Module mappings created only inside explorer.
-- Use `''` (empty string) to not create one.
mappings = {
close = "<space>q",
go_in_plus = "L",
--[[ go_in_plus = "L", ]]
go_in = "",
go_out = "H",
mark_goto = "'",
mark_set = "m",
reset = "<BS>",
reveal_cwd = "@",
show_help = "g?",
synchronize = "=",
trim_left = "<",
trim_right = ">",
},
-- General options
options = {
-- Whether to delete permanently or move into module-specific trash
permanent_delete = true,
-- Whether to use for editing directories
use_as_default_explorer = true,
},
-- Customization of explorer windows
windows = {
-- Maximum number of windows to show side by side
max_number = math.huge,
-- Whether to show preview of file/directory under cursor
preview = true,
-- Width of focused window
width_focus = 30,
-- Width of non-focused window
width_nofocus = 35,
-- Width of preview window
width_preview = 55,
},
}
)
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesWindowUpdate",
callback = function(args)
vim.cmd([[
setlocal relativenumber
]])
local config = vim.api.nvim_win_get_config(args.data.win_id)
-- Ensure fixed height
config.height = vim.o.lines - 2
--[[ config.height = 10 ]]
-- Ensure title padding
if config.title[#config.title][1] ~= " " then
table.insert(config.title, { " ", "NormalFloat" })
end
if config.title[1][1] ~= " " then
table.insert(config.title, 1, { " ", "NormalFloat" })
end
vim.api.nvim_win_set_config(args.data.win_id, config)
end,
})
local mini_utils = {}
-- Copy just the filename
function mini_utils.copy_filename()
local entry = MiniFiles.get_fs_entry()
if not entry then
return
end
local filename = vim.fs.basename(entry.path)
if vim.fn.has("wsl") == 1 then
vim.fn.setreg("+", filename)
vim.fn.system("wslcopy", vim.fn.getreg("+"))
else
vim.fn.setreg("+", filename)
end
vim.notify("Copied: " .. filename)
end
-- Copy the full path in Windows format (for WSL)
function mini_utils.copy_windows_path()
local entry = MiniFiles.get_fs_entry()
if not entry then
return
end
local filepath = entry.path
-- Convert WSL path to Windows drive letter format
local win_path = filepath:gsub("^/mnt/(%w)", function(drive)
return string.upper(drive) .. ":/"
end)
win_path = win_path:gsub("/", "\\")
if vim.fn.has("wsl") == 1 then
vim.fn.setreg("+", win_path)
vim.fn.system("wslcopy", vim.fn.getreg("+"))
else
vim.fn.setreg("+", win_path)
end
vim.notify("Copied: " .. win_path)
end
-- Copy the full path
function mini_utils.copy_filepath()
local entry = MiniFiles.get_fs_entry()
if not entry then
return
end
local filepath = entry.path
--[[ filepath = filepath:gsub("/", "\\") ]]
if vim.fn.has("wsl") == 1 then
vim.fn.setreg("+", filepath)
vim.fn.system("wslcopy", vim.fn.getreg("+"))
else
vim.fn.setreg("+", filepath)
end
vim.notify("Copied: " .. filepath)
end
-- Copy relative path from current working directory
function mini_utils.copy_relative_path_forward_slash()
local entry = MiniFiles.get_fs_entry()
if not entry then
return
end
local filepath = entry.path
-- Get the current working directory
local cwd = vim.fn.getcwd()
-- Convert both paths to absolute paths
local abs_filepath = vim.fn.fnamemodify(filepath, ":p")
local abs_cwd = vim.fn.fnamemodify(cwd, ":p")
-- Get the relative path
local relative_path = vim.fn.fnamemodify(abs_filepath, ":." .. abs_cwd .. ":~")
-- Remove leading './' if present
relative_path = relative_path:gsub("^%./", "")
relative_path = relative_path:gsub("\\", "/")
if vim.fn.has("wsl") == 1 then
vim.fn.setreg("+", relative_path)
vim.fn.system("wslcopy", vim.fn.getreg("+"))
else
vim.fn.setreg("+", relative_path)
end
vim.notify("Copied: " .. relative_path)
end
-- Copy relative path from current working directory
function mini_utils.copy_relative_path()
local entry = MiniFiles.get_fs_entry()
if not entry then
return
end
local filepath = entry.path
-- Get the current working directory
local cwd = vim.fn.getcwd()
-- Convert both paths to absolute paths
local abs_filepath = vim.fn.fnamemodify(filepath, ":p")
local abs_cwd = vim.fn.fnamemodify(cwd, ":p")
-- Get the relative path
local relative_path = vim.fn.fnamemodify(abs_filepath, ":." .. abs_cwd .. ":~")
-- Remove leading './' if present
relative_path = relative_path:gsub("^%./", "")
if vim.fn.has("wsl") == 1 then
vim.fn.setreg("+", relative_path)
vim.fn.system("wslcopy", vim.fn.getreg("+"))
else
vim.fn.setreg("+", relative_path)
end
vim.notify("Copied: " .. relative_path)
end
-- Set root directory to current directory (equivalent to Neotree's set_root)
function mini_utils.set_root()
-- Works only if cursor is on the valid file system entry
local cur_entry_path = MiniFiles.get_fs_entry().path
local cur_directory = vim.fs.dirname(cur_entry_path)
vim.fn.chdir(cur_directory)
vim.api.nvim_set_current_dir(cur_directory)
MiniFiles.trim_left()
end
local go_in_plus = function()
for _ = 1, vim.v.count1 do
MiniFiles.go_in({ close_on_file = true })
end
end
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesBufferCreate",
callback = function(args)
local map_buf = function(lhs, rhs)
vim.keymap.set("n", lhs, rhs, { buffer = args.data.buf_id })
end
map_buf("<Esc>", MiniFiles.close)
map_buf("q", MiniFiles.close)
map_buf("<c-h>", MiniFiles.go_out)
map_buf("<c-l>", go_in_plus)
vim.keymap.set("n", ".", mini_utils.set_root, { buffer = args.data.buf_id })
vim.keymap.set("n", "a", "o", { buffer = args.data.buf_id })
--[[ vim.keymap.set("n", "y", mini_utils.copy_filename, { buffer = args.data.buf_id }) ]]
vim.keymap.set("n", "gm", mini_utils.copy_relative_path_forward_slash, { buffer = args.data.buf_id })
vim.keymap.set("n", "gy", mini_utils.copy_filepath, { buffer = args.data.buf_id })
vim.keymap.set("n", "<s-y>", mini_utils.copy_relative_path, { buffer = args.data.buf_id })
end,
})
local go_in_plus = function()
for _ = 1, vim.v.count1 do
MiniFiles.go_in({ close_on_file = true })
end
end
local map_split = function(buf_id, lhs, direction)
local rhs = function()
-- Make new window and set it as target
local cur_target = MiniFiles.get_explorer_state().target_window
local new_target = vim.api.nvim_win_call(cur_target, function()
vim.cmd(direction .. " split")
return vim.api.nvim_get_current_win()
end)
MiniFiles.set_target_window(new_target)
go_in_plus()
-- This intentionally doesn't act on file under cursor in favor of
-- explicit "go in" action (`l` / `L`). To immediately open file,
-- add appropriate `MiniFiles.go_in()` call instead of this comment.
end
-- Adding `desc` will result into `show_help` entries
local desc = "Split " .. direction
vim.keymap.set("n", lhs, rhs, { buffer = buf_id, desc = desc })
end
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesBufferCreate",
callback = function(args)
local buf_id = args.data.buf_id
-- Tweak keys to your liking
vim.keymap.set("n", "<C-A-v>", "<C-v>", { noremap = true, desc = "Enter visual block mode" })
map_split(buf_id, "<C-v>", "vertical")
end,
})
end,
}For the bonus. This is not really related to mini at all. I wrote this since I use search and replace a lot and there's no plugin out there that do this (Not that I know off at least). This basically allows you to visually select the text you one and escape all special characters that sed needs snap it into :%s/ or do the same for the word that you are on, and some other nuggets of searching within buffer, within the project, etc...: search_and_replace.lualocal M = {}
-- Escape special characters in the string
local function escape(str)
return str:gsub("([~\\^$.*\\/%[%]])", "\\%1"):gsub("\n", "\\n")
end
-- Escape special characters in the string
local function escapeFzf(str)
--[[ return str:gsub('([~\\^$*\\/%[%]\'\\])"', "\\%1") ]]
return str:gsub("([\\'])", "\\%1"):gsub("\n", "\\n")
end
local function get_visual_selection()
local start_pos = vim.fn.getpos("'<")
local end_pos = vim.fn.getpos("'>")
-- Adjust for Lua's 1-indexing
local start_col = start_pos[3]
local end_col = end_pos[3]
-- If selection is within a single line
if start_pos[2] == end_pos[2] then
return vim.fn.getline(start_pos[2]):sub(start_col, end_col)
end
local lines = vim.fn.getline(start_pos[2], end_pos[2])
if #lines == 0 then
return ""
end
-- Adjust first and last line of the selection
lines[1] = lines[1]:sub(start_col)
lines[#lines] = lines[#lines]:sub(1, end_col)
return table.concat(lines, "\n")
end
-- Function to be called from Neovim command
function M.SaveWithHighlight()
-- Get the current visual selection
local text = get_visual_selection()
text = escape(text) -- Escape the text for regex
-- Put the text into the command line
vim.fn.setreg("h", text)
end
-- Function to be called from Neovim command
function M.SubstituteWithPreviousHightlightHighlightMakeGroup()
-- Get the current visual selection
local content = vim.fn.getreg("h")
-- Put the text into the command line
local cmd = ":'<,'>s/\\(" .. content .. "\\)/"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, false))
end
-- Function to be called from Neovim command
function M.SubstituteWithHighlightMakeGroup()
-- Get the current visual selection
local text = get_visual_selection()
text = escape(text) -- Escape the text for regex
-- Put the text into the command line
local cmd = ":%s/\\(" .. text .. "\\)/"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, false))
end
-- Function to substitute with the word under the cursor
function M.SubstituteWithWord()
local word = vim.fn.expand("<cword>")
word = escape(word)
local cmd = ":%s/\\(" .. word .. "\\)/"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, true))
end
-- Function to substitute with the word under the cursor
function M.SearchWithWord()
local word = vim.fn.expand("<cword>")
word = escape(word)
local cmd = "/" .. word .. "<cr>"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, true))
end
-- Function to substitute with the word under the cursor
function M.SearchWithWORD()
local word = vim.fn.expand("<cWORD>")
word = escape(word)
local cmd = "/" .. word .. "<cr>"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, true))
end
-- Function to be called from Neovim command
function M.SearchWithHighlight()
-- Get the current visual selection
local text = get_visual_selection()
text = escape(text) -- Escape the text for regex
-- Put the text into the command line
local cmd = "/" .. text
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, false))
end
-- Function to be called from Neovim command
function M.SearchWorkSpaceWithHighlight()
-- Get the current visual selection
local text = get_visual_selection()
text = escapeFzf(text) -- Escape the text for regex
-- Put the text into the command line
local cmd = ":lua require('fzf-lua').live_grep_native({multiprocess=true,search = '" .. text .. "'})<CR>"
vim.fn.feedkeys(vim.api.nvim_replace_termcodes(cmd, true, false, true))
end
return MMappingskeymap("v", "<Leader>rp", ':lua require"utils.search_and_replace".SubstituteWithHighlightMakeGroup()<CR>', opts)
keymap("v", "<Leader>rs", ':lua require"utils.search_and_replace".SaveWithHighlight()<CR>', opts)
keymap(
"v",
"<Leader>rh",
':lua require"utils.search_and_replace".SubstituteWithPreviousHightlightHighlightMakeGroup()<CR>',
opts
)
keymap("n", "<Leader>rp", ':lua require"utils.search_and_replace".SubstituteWithWord()<CR>', opts)
keymap("v", "<Leader>lh", ':lua require"utils.search_and_replace".SearchWithHighlight()<CR>', opts)
keymap("v", "<Leader>lf", ':lua require"utils.search_and_replace".SearchWithHighlight()<CR>', opts)
keymap("n", "<Leader>lw", ':lua require"utils.search_and_replace".SearchWithWord()<CR>', opts)
keymap("n", "<Leader>lW", ':lua require"utils.search_and_replace".SearchWithWORD()<CR>', opts)
keymap("v", "<Leader>lw", ':lua require"utils.search_and_replace".SearchWorkSpaceWithHighlight()<CR>', opts) |
Beta Was this translation helpful? Give feedback.
-
|
Loving mini so far, honestly no complaints :) |
Beta Was this translation helpful? Give feedback.
-
|
Hey! I wanted to share a small experience I had while configuring MiniStarter in Neovim. I customized the header colors and tweaked every detail to better match the overall colorscheme. MiniStarter:local header = require("config/header")
MiniStarter.setup({
evaluate_single = true,
header = table.concat(header.header.val, "\n"),
footer = function()
local stats = require("lazy").stats()
local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
return "⚡ Neovim loaded " .. stats.count .. " plugins in " .. ms .. "ms"
end,
items = {
MiniStarter.sections.pick(),
},
content_hooks = {
-- MiniStarter.gen_hook.adding_bullet(""),
},
})
vim.api.nvim_create_autocmd("User", {
pattern = "MiniStarterOpened",
callback = function(ev)
local ns = vim.api.nvim_create_namespace("MiniStarterOpenedHeader")
if vim.bo.filetype == "ministarter" then
for i, x in ipairs(header.header.opts.hl) do
for _, z in ipairs(x) do
vim.api.nvim_buf_set_extmark(ev.buf, ns, i - 1, z[2], { end_col = z[3] - 1, hl_group = z[1] })
end
end
return
end
vim.api.nvim_buf_clear_namespace(ev.buf, ns, 0, -1)
end,
})
|
Beta Was this translation helpful? Give feedback.
-
|
Heya, it's actually my first time switching from vscode to neovim and i were told to use some IDE distro such as NvimChad and lazynvim but i stumbled on this godsend while browsing through lazy's plugin dependencies. And i'm loving it so far 💕 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
I have tried to make it as minimal as possible Nvim |
Beta Was this translation helpful? Give feedback.
-
|
My config is here. After trying multiple distros and rebuilding my configuration from scratch several times, I finally achieved what I wanted with mini.nvim: a minimal yet powerful setup that meets my needs. |
Beta Was this translation helpful? Give feedback.
-
|
Relatively new to mini.nvim setup---@module 'lazy'
---@type LazyPluginSpec[]
return {
{
"nvim-mini/mini.nvim",
version = false,
event = "BufEnter", -- required for setup_auto_root
config = function()
-- :help mini.ai
-- - va) - [V]isually select [A]round [)]paren
-- - yinq - [Y]ank [I]nside [N]ext [Q]uote
-- - ci' - [C]hange [I]nside [']quote
require("mini.ai").setup() -- repeatable text motions
-- :help mini.surround
-- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren
-- - sd' - [S]urround [D]elete [']quotes
-- - sr)' - [S]urround [R]eplace [)] [']
require("mini.surround").setup()
-- automatically change buffer cwd to the root of the project (vim-rooter-esque)
require("mini.misc").setup_auto_root({ ".git", "Makefile", "stylua.toml" })
-- move visual selection in Visual mode
require("mini.move").setup({
mappings = {
left = "<S-h>",
right = "<S-l>",
down = "<S-j>",
up = "<S-k>",
},
})
local wk = require("which-key")
wk.add({
{
"<leader>z",
function()
require("mini.misc").zoom()
end,
desc = "zoom",
icon = "",
},
})
end,
},
-- this is split so that we can lazy load on filetype effectively
--
-- the default 'gc' (:help commenting) binding works for most things, but react/web frameworks
-- have a different comment syntax, so this plugin only loads on those filetypes
{
"nvim-mini/mini.comment",
dependencies = {
"JoosepAlviste/nvim-ts-context-commentstring",
---@module 'ts_context_commentstring'
---@type ts_context_commentstring.Config
opts = { enable_autocmd = false },
},
ft = {
"javascript",
"typescript",
"javascriptreact",
"typescriptreact",
},
keys = { { "gc", mode = { "n", "x" } }, { "gbc", mode = { "n", "x" } } },
--- NOTE: no setup types
opts = {
options = {
custom_commentstring = function()
return require("ts_context_commentstring").calculate_commentstring() or vim.bo.commentstring
end,
},
},
},
} |
Beta Was this translation helpful? Give feedback.
-
|
I felt like I had to do really battle with very hacky setup-- maximum width of notify
local NOTIFY_WIDTH = 60
--- to display progress when the server supports percentages
local PROGRESS = { '⡀', '⣀', '⣄', '⣤', '⣦', '⣶', '⣷', '⣿' }
--- to display infinite progress, when percentage is unavailable
local INFINITE_PROGRESS = { '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' }
--- @param str string
--- @param length integer
--- @return string truncated string
local function trunc(str, length)
str = str or ''
-- remove "..." present in messages/titles as it only wastes space (looking at you JDTLS)
local smaller = str:gsub('[.][.][.]', '')
-- truncate to length and use "..." to indicate we truncated
return #smaller > length and (smaller:sub(1, length - 3) .. '...') or smaller
end
--- @param item table
--- @return string icon
local function icon(item)
local value = item.data.response.value --[[@as table]]
if value.kind == 'end' then
return '✔'
elseif value.percentage and value.percentage > 0 then
return PROGRESS[math.ceil(math.max(1, value.percentage) / 100 * #PROGRESS)] or '?'
else
local index = assert(vim.uv.gettimeofday()) % #INFINITE_PROGRESS
return INFINITE_PROGRESS[1 + index] or '?'
end
end
--- @param item table
--- @return string message
local function message(item)
local value = item.data.response.value --[[@as table]]
if value.kind == 'end' then
-- when complete, indicate how much time it took the operation
return string.format('%.2fs', item.ts_update - item.ts_add)
elseif value.message and value.title and vim.startswith(value.message, value.title) then
-- best effort to remove redundancy (title == message, title startswith message, etc)
return vim.trim(value.message:sub(#value.title + 1))
else
return value.message or ''
end
end
--- Format LSP message as "message title [client] ICON",
--- this results in the least "movement", only the "message" really changes width
--- @param item table
--- @return string result
local function format_lsp(item)
local client_name = trunc(item.data.client_name, 13) --[[@as string]]
local remaining = NOTIFY_WIDTH - 6 - #client_name
local value = item.data.response.value --[[@as table]]
local title = trunc(value.title, remaining - 10)
remaining = remaining - #title
local msg = trunc(message(item), remaining)
local output = string.format('%s %s [%s] %s', msg, title, client_name, icon(item))
local width = vim.fn.strdisplaywidth(output)
return string.rep(' ', NOTIFY_WIDTH - width) .. output
end
-- replace refresh with one that only happens every 150ms
-- especially rust-based analyzers tend to overexert here.
local notify = require('mini.notify')
local refresh = notify.refresh
local timer = assert(vim.uv.new_timer())
--- @diagnostic disable-next-line: duplicate-set-field
notify.refresh = function()
if not timer:is_active() then
timer:start(150, 0, vim.schedule_wrap(refresh))
end
end
notify.setup({
content = {
format = function(item)
if item.data.source == 'lsp_progress' then
return format_lsp(item)
elseif item.data.source == 'vim.notify' then
local output = string.format('%s ■', trunc(item.msg, NOTIFY_WIDTH - 6))
local width = vim.fn.strdisplaywidth(output)
return string.rep(' ', NOTIFY_WIDTH - width) .. output
else
return notify.default_format(item)
end
end,
-- Sort strictly by recency, this reduces overall movement hence flicker
sort = function(items)
--- @param a table
--- @param b table
--- @return boolean if a > b
table.sort(items, function(a, b)
return a.ts_add > b.ts_add
end)
return items
end,
},
window = {
-- Undo the adjusted height since we aren't wrapping but instead truncating
-- Place at bottom right of screen
config = function(buffer)
local count = vim.api.nvim_buf_line_count(buffer)
local has_statusline = vim.o.laststatus > 0
local pad = vim.o.cmdheight + (has_statusline and 1 or 0)
return {
anchor = 'SE',
col = vim.o.columns,
row = vim.o.lines - pad,
width = NOTIFY_WIDTH,
height = count,
border = 'none',
}
end,
},
lsp_progress = {
duration_last = 2500,
},
}) |
Beta Was this translation helpful? Give feedback.
-
AboutNothing special — just a single-file configuration with a few custom tweaks. The current version isn’t ideal, and I probably won’t update it here too often. https://github.com/drowning-cat/nvim-lean Relatedmini.nvim
Other
Code~1500 lines (version 3)if vim.fn.has("nvim-0.12") == 0 then
return vim.notify("Install Neovim 0.12+", vim.log.levels.ERROR)
end
vim.g.mapleader = " "
vim.g.maplocalleader = " "
vim.o.number = true
vim.o.relativenumber = true
vim.o.signcolumn = "yes"
vim.o.updatetime = 250
vim.o.timeoutlen = 300
vim.o.splitbelow = true
vim.o.splitright = true
vim.o.expandtab = true
vim.o.tabstop = 4
vim.o.shiftwidth = 2
vim.o.softtabstop = 2
vim.o.foldmethod = "indent"
vim.o.foldtext = ""
vim.o.foldlevel = 99
vim.o.foldlevelstart = 99
vim.o.foldnestmax = 10
vim.o.undofile = true
vim.o.undolevels = 10000
vim.o.smartcase = true
vim.o.list = true
vim.o.listchars = "tab:▷ ,trail:·,nbsp:○"
-- Custom settings
vim.g.session_center_cursor = false
vim.g.ts_install = {
"bash",
"c",
"css",
"diff",
"go",
"html",
"javascript",
"json",
"lua",
"python",
"toml",
"tsx",
"typescript",
"yaml",
"zig",
}
vim.g.mason_install = {
"delve",
"deno",
"gopls",
"lua-language-server",
}
vim.g.lsp_enable = {
"lua_ls",
"gopls",
}
local formatters = {
deno = function(c)
c.stdin({ cmd = string.format("deno fmt --ext=%s -", c.ext) })
end,
stylua = function(c)
-- stylua: ignore
c.stdin({ cmd = string.format("stylua --indent-type=Spaces --indent-width=2 --stdin-filepath=%s --range-start=%d --range-end=%d -", c.file, c.b1, c.b2) })
end,
}
vim.g.formatconf = {
["json"] = formatters.deno,
["lua"] = formatters.stylua,
}
-- Core
require("vim._extui").enable({
msg = {
target = "cmd",
timeout = 4000,
},
})
-- -- Commands
vim.api.nvim_create_user_command("Mkdir", function(o)
local path = vim.fn.expand(o.args ~= "" and o.args or "%:p:h")
vim.fn.mkdir(path, "p")
end, { nargs = "?", complete = "dir" })
-- -- Mappings
vim.keymap.set("i", "<C-l>", "<Right>")
vim.keymap.set("n", "<Esc>", "<Cmd>nohlsearch<Enter>")
vim.keymap.set("n", "<Leader>w", "<Cmd>write<Enter>", { desc = "Save" })
vim.keymap.set("n", "<Leader>q", "<Cmd>quit<Enter>", { desc = "Quit" })
vim.keymap.set("n", "<Leader>Q", "<Cmd>quitall!<Enter>", { desc = "Quit all" })
vim.keymap.set("n", "<Leader>R", "<Cmd>write | restart<Enter>", { desc = "Restart" })
vim.keymap.set("n", "gA", "<Cmd>tabnew<Enter>", { desc = "Add tab" })
vim.keymap.set("n", "gC", "<Cmd>tabclose<Enter>", { desc = "Close tab" })
vim.keymap.set("n", "gy", function()
local copy = vim.fn.getreg('"')
if copy == "" then
return
end
local msg = ""
local _, ln = string.gsub(copy, "\n", "")
if ln > 0 then
msg = string.format('%s %s yanked into "+', ln, ln > 1 and "lines" or "line")
else
local ch = #copy
msg = string.format('%s %s yanked into "+', ch, ch > 1 and "chars" or "char")
end
vim.fn.setreg("+", copy)
vim.api.nvim_echo({ { msg } }, false, {})
end, { desc = "Yank last into clipboard" })
-- -- Autocmds
vim.api.nvim_create_autocmd("TextYankPost", {
desc = "Highlight yanking text",
group = vim.api.nvim_create_augroup("yank_highlight", { clear = true }),
callback = function()
vim.hl.on_yank()
end,
})
-- Plugins
local after_update = function(opts)
local autocmd_opts = vim.deepcopy(opts)
autocmd_opts.command = nil
autocmd_opts.delay = nil
autocmd_opts.callback = function(e)
if e.data.kind ~= "update" then
return
end
local run = function()
if opts.command then
vim.cmd(opts.command)
else
opts.callback(e)
end
end
vim.defer_fn(run, opts.delay or 200)
end
vim.api.nvim_create_autocmd("PackChanged", autocmd_opts)
end
-- -- Colorscheme
vim.pack.add({
{ src = "https://github.com/folke/tokyonight.nvim" },
})
vim.cmd.colorscheme("tokyonight")
-- -- Completion
after_update({
pattern = "blink.cmp",
desc = "Run `:BlinkCmp build` after pack update",
group = vim.api.nvim_create_augroup("blink_update", { clear = true }),
command = "echo '' | BlinkCmp build",
})
vim.pack.add({
{ src = "https://github.com/Saghen/blink.cmp", version = "main" },
})
require("blink.cmp").setup({
keymap = {
["<C-n>"] = { "show_and_insert", "select_next" },
["<C-p>"] = { "show_and_insert", "select_prev" },
["<C-j>"] = { "select_and_accept" },
},
})
vim.keymap.set("i", "<C-x><C-o>", function()
require("blink.cmp").show()
require("blink.cmp").show_documentation()
require("blink.cmp").hide_documentation()
end, { desc = "Show completion" })
-- -- Markdown
vim.pack.add({
{ src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" },
})
require("render-markdown").setup({
checkbox = { enabled = false },
code = { sign = false, width = "full" },
heading = { icons = {} },
})
-- -- Mini
vim.pack.add({
{ src = "https://github.com/nvim-mini/mini.nvim" },
})
local MiniAi = require("mini.ai")
MiniAi.setup({
mappings = {
around_next = "",
inside_next = "",
around_last = "",
inside_last = "",
},
custom_textobjects = {
a = MiniAi.gen_spec.argument({ separator = ",%s*" }),
C = MiniAi.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }),
F = MiniAi.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }),
g = function()
local from = { line = 1, col = 1 }
local to = {
line = vim.fn.line("$"),
col = math.max(vim.fn.getline("$"):len(), 1),
}
return { from = from, to = to }
end,
t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" },
e = {
{
"%f[%a]%l+%d*",
"%f[%w]%d+",
"%f[%u]%u%f[%A]%d*",
"%f[%u]%u%l+%d*",
"%f[%u]%u%u+%d*",
},
},
},
})
local expand_separator = function(range)
local from, to = range.from, range.to
local line = function(r)
return assert(vim.api.nvim_buf_get_lines(0, r.line - 1, r.line, true)[1])
end
local left = line(from):sub(1, from.col - 1):find("[_%-]+$")
local _, right = line(to):find("^[_%-]+", to.col + 1)
-- stylua: ignore
if left then from.col = left elseif right then to.col = right end
return from, to
end
vim.keymap.set("o", "ae", function()
local range = MiniAi.find_textobject("i", "e")
if range then
local from, to = expand_separator(range)
vim.api.nvim_win_set_cursor(0, { from.line, from.col - 1 })
vim.cmd("normal! v")
vim.api.nvim_win_set_cursor(0, { to.line, to.col - 1 })
end
end)
vim.keymap.set("n", "saf", "sa_f", { remap = true, desc = "Add fcall" })
vim.keymap.set("n", "sat", "sa_t", { remap = true, desc = "Add tag" })
local MiniSurround = require("mini.surround")
local surround_sel = function()
local mark1, mark2
if vim.v.operator == ":" then
mark1, mark2 = "<", ">"
else
mark1, mark2 = "[", "]"
end
local pos1 = vim.api.nvim_buf_get_mark(0, mark1)
local pos2 = vim.api.nvim_buf_get_mark(0, mark2)
local text = vim.api.nvim_buf_get_text(0, pos1[1] - 1, pos1[2], pos2[1] - 1, pos2[2] + 1, {})
return text, pos1, pos2
end
MiniSurround.setup({
mappings = {
find = "",
find_left = "",
highlight = "",
update_n_lines = "",
suffix_last = "",
suffix_next = "",
},
custom_surroundings = {
t = { input = MiniAi.config.custom_textobjects["t"] },
l = {
output = function()
if vim.b.minisurround_log_insert then
local sel_lines = surround_sel()
local sel = vim.trim(table.concat(sel_lines, "\n"))
local row = vim.fn.line(".")
local log = string.format(vim.b.minisurround_log_insert, sel, sel)
local indent = vim.fn.getline(row):match("^%s+") or ""
vim.api.nvim_buf_set_lines(0, row, row, true, { indent .. log })
vim.api.nvim_win_set_cursor(0, { row + 1, #indent })
end
end,
},
},
})
local MiniClue = require("mini.clue")
local r_prefix = "<C-w>r"
vim.keymap.set("n", r_prefix .. "q", "<nop>", { desc = "Quit" })
vim.keymap.set("n", r_prefix .. "H", "<C-w>h", { remap = true, desc = "Move left" })
vim.keymap.set("n", r_prefix .. "J", "<C-w>j", { remap = true, desc = "Move down" })
vim.keymap.set("n", r_prefix .. "K", "<C-w>k", { remap = true, desc = "Move up" })
vim.keymap.set("n", r_prefix .. "L", "<C-w>l", { remap = true, desc = "Move right" })
local resize = function(dir)
local step = { h = 4, v = 2 }
if dir == "h" then
vim.fn.win_move_separator(vim.fn.winnr("h"), -step.h)
elseif dir == "l" then
vim.fn.win_move_separator(vim.fn.winnr("h"), step.h)
elseif dir == "k" then
vim.fn.win_move_statusline(vim.fn.winnr("k"), -step.v)
elseif dir == "j" then
vim.fn.win_move_statusline(vim.fn.winnr("k"), step.v)
end
end
-- stylua: ignore start
vim.keymap.set("n", r_prefix .. "h", function() resize("h") end, { desc = "Resize left" })
vim.keymap.set("n", r_prefix .. "j", function() resize("j") end, { desc = "Resize down" })
vim.keymap.set("n", r_prefix .. "k", function() resize("k") end, { desc = "Resize up" })
vim.keymap.set("n", r_prefix .. "l", function() resize("l") end, { desc = "Resize right" })
-- stylua: ignore end
MiniClue.gen_clues.resize = function()
return {
{ mode = "n", keys = r_prefix .. "q" },
{ mode = "n", keys = r_prefix .. "H", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "J", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "K", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "L", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "h", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "j", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "k", postkeys = r_prefix },
{ mode = "n", keys = r_prefix .. "l", postkeys = r_prefix },
}
end
MiniClue.setup({
triggers = {
{ mode = "n", keys = r_prefix },
{ mode = "n", keys = "<Leader>" },
{ mode = "x", keys = "<Leader>" },
{ mode = "n", keys = "[" },
{ mode = "n", keys = "]" },
{ mode = "i", keys = "<C-x>" },
{ mode = "n", keys = "g" },
{ mode = "x", keys = "g" },
{ mode = "n", keys = "'" },
{ mode = "n", keys = "`" },
{ mode = "x", keys = "'" },
{ mode = "x", keys = "`" },
{ mode = "n", keys = '"' },
{ mode = "x", keys = '"' },
{ mode = "i", keys = "<C-r>" },
{ mode = "c", keys = "<C-r>" },
{ mode = "n", keys = "<C-w>" },
{ mode = "n", keys = "z" },
{ mode = "x", keys = "z" },
},
clues = {
MiniClue.gen_clues.resize(),
MiniClue.gen_clues.square_brackets(),
MiniClue.gen_clues.builtin_completion(),
MiniClue.gen_clues.g(),
MiniClue.gen_clues.marks(),
MiniClue.gen_clues.registers(),
MiniClue.gen_clues.windows(),
MiniClue.gen_clues.z(),
},
})
local MiniDiff = require("mini.diff")
MiniDiff.setup({
mappings = {
textobject = "ih",
-- apply = "gh",
-- reset = "gH",
goto_prev = "[h",
goto_next = "]h",
},
})
local hunk_action = function(mode)
return function()
return MiniDiff.operator(mode) .. MiniDiff.config.mappings.textobject
end
end
vim.keymap.set("n", "gh", hunk_action("apply"), { expr = true, remap = true, desc = "Apply hunk" })
vim.keymap.set("n", "gH", hunk_action("reset"), { expr = true, remap = true, desc = "Reset hunk" })
local MiniExtra = require("mini.extra")
MiniExtra.setup()
-- stylua: ignore
vim.keymap.set("n", "<Leader>sc", function() MiniExtra.pickers.colorschemes() end, { desc = "Search colorschemes" })
local MiniFiles = require("mini.files")
MiniFiles.setup()
-- stylua: ignore
vim.keymap.set("n", "<Leader>F", function() MiniFiles.open() end, { desc = "Open files" })
vim.api.nvim_create_augroup("mini_files", { clear = true })
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesBufferCreate",
group = "mini_files",
callback = function(e)
MiniFiles.set_bookmark("c", vim.fn.stdpath("config"), { desc = "Config" })
MiniFiles.set_bookmark("p", vim.fn.stdpath("data") .. "/site/pack/core/opt", { desc = "Plugins" })
MiniFiles.set_bookmark("w", vim.fn.getcwd, { desc = "Working directory" })
local buf = e.data.buf_id
local minipick = require("mini.pick")
local get_entry = function()
local entry = MiniFiles.get_fs_entry()
if entry then
local path = entry.path
local is_dir = entry.fs_type == "directory"
local parent = vim.fn.fnamemodify(entry.path, ":h")
return entry, path, is_dir, parent
end
end
vim.keymap.set("n", "<Leader>sg", function()
local entry, path, is_dir, parent = get_entry()
if not entry then
return
end
if is_dir then
minipick.builtin.grep({ pattern = "." }, { source = { cwd = path } })
else
local name = vim.fn.fnamemodify(path, ":t")
minipick.builtin.grep({ pattern = ".", globs = { name } }, { source = { cwd = parent } })
end
end, { buffer = buf, desc = "Search folder" })
vim.keymap.set("n", "<Leader>sf", function()
local entry, path, is_dir, parent = get_entry()
if not entry then
return
end
minipick.builtin.files(nil, { source = { cwd = is_dir and path or parent } })
end, { buffer = buf, desc = "Search folder" })
end,
})
vim.api.nvim_create_autocmd("User", {
pattern = "MiniFilesWindowUpdate",
group = "mini_files",
callback = function(e)
local win = e.data.win_id
vim.wo[win].number = true
vim.wo[win].relativenumber = true
end,
})
local MiniGit = require("mini.git")
MiniGit.setup()
vim.cmd.cnoreabbrev("G", "Git")
vim.api.nvim_set_hl(0, "GitBlameHashRoot", { link = "Tag" })
vim.api.nvim_set_hl(0, "GitBlameHash", { link = "Identifier" })
vim.api.nvim_set_hl(0, "GitBlameAuthor", { link = "String" })
vim.api.nvim_set_hl(0, "GitBlameDate", { link = "Comment" })
vim.api.nvim_create_autocmd("User", {
desc = "Enhance `Git blame`: colorize buffer and set width for vertical split",
pattern = "MiniGitCommandSplit",
callback = function(e)
if e.data.git_subcommand ~= "blame" then
return
end
local win_src = e.data.win_source
local buf = e.buf
local win = e.data.win_stdout
vim.bo[buf].modifiable = false
vim.wo[win].wrap = false
vim.wo[win].cursorline = true
vim.fn.winrestview({ topline = vim.fn.line("w0", win_src) })
vim.api.nvim_win_set_cursor(0, { vim.fn.line(".", win_src), 0 })
vim.wo[win].scrollbind, vim.wo[win_src].scrollbind = true, true
vim.wo[win].cursorbind, vim.wo[win_src].cursorbind = true, true
if e.data.cmd_input.mods == "vertical" then
local lines = vim.api.nvim_buf_get_lines(0, 1, -1, false)
local width = vim.iter(lines):fold(-1, function(acc, ln)
local stat = string.match(ln, "^[%w%p]+ %b()")
return math.max(acc, vim.fn.strwidth(stat))
end)
width = width + vim.fn.getwininfo(win)[1].textoff
vim.api.nvim_win_set_width(win, width)
end
vim.fn.matchadd("GitBlameHashRoot", [[^^\w\+]])
vim.fn.matchadd("GitBlameHash", [[^\w\+]])
local leftmost = [[^.\{-}\zs]]
vim.fn.matchadd("GitBlameAuthor", leftmost .. [[(\zs.\{-} \ze\d\{4}-]])
vim.fn.matchadd("GitBlameDate", leftmost .. [[[0-9-]\{10} [0-9:]\{8} +\d\+]])
end,
})
local MiniHipatterns = require("mini.hipatterns")
vim.api.nvim_create_autocmd({ "VimEnter", "ColorScheme" }, {
desc = "Add additional highlights for `mini.hipatterns`",
group = vim.api.nvim_create_augroup("todo_highlight", { clear = true }),
callback = function()
local get = function(name)
return vim.api.nvim_get_hl(0, { name = name, link = false })
end
local make = function(name, fg, bg)
vim.api.nvim_set_hl(0, name, { bold = true, fg = fg, bg = bg })
end
make("UserHipatternsPerf", "black", get("Identifier").fg)
end,
})
local hi_todo = function(words, hl_name)
local pattern = vim
.iter(words)
:map(function(word)
return { "%f[%w]()" .. word .. "%f[%W]:?()", "() " .. word .. "[: ]()" }
end)
:flatten()
:totable()
return {
pattern = pattern,
group = function(b, _, d)
local parser = vim.treesitter.get_parser(b, nil, { error = false })
if not parser then
return hl_name
end
local node = parser:named_node_for_range({
d.line - 1,
d.from_col - 1,
d.line - 1,
d.to_col - 1,
})
if node and node:type() == "comment_content" then
return hl_name
end
return nil
end,
}
end
local tw_store = {
hl = {},
-- stylua: ignore
cl = {
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"},
},
}
vim.api.nvim_create_autocmd("ColorScheme", {
desc = "Reset tailwind hl-store on colorscheme change",
group = vim.api.nvim_create_augroup("reset_tailwind_hl", { clear = true }),
callback = function()
tw_store.hl = {}
end,
})
MiniHipatterns.setup({
highlighters = {
fix = hi_todo({ "FIX", "FIXME" }, "MiniHipatternsFixme"),
note = hi_todo({ "NOTE" }, "MiniHipatternsNote"),
todo = hi_todo({ "TODO", "FEAT" }, "MiniHipatternsTodo"),
hack = hi_todo({ "HACK" }, "MiniHipatternsHack"),
perf = hi_todo({ "PERF" }, "UserHipatternsPerf"),
hex_color = MiniHipatterns.gen_highlighter.hex_color(),
hex_color_short = {
pattern = "()#%x%x%x()%f[^%x%w]",
group = function(_, _, data)
local match = data.full_match
local r, g, b = match:sub(2, 2), match:sub(3, 3), match:sub(4, 4)
local hex_color = "#" .. r .. r .. g .. g .. b .. b
return MiniHipatterns.compute_hex_color_group(hex_color, "bg")
end,
},
hsl_color = {
-- NOTE: Partial support for CSS hsl()
pattern = "hsl%(%d+[, ] ?%d+%%?[, ] ?%d+%%?%)",
group = function(_, m, _)
-- https://www.w3.org/TR/css-color-3/#hsl-color
local function hsl_to_rgb(h, s, l)
h, s, l = h % 360, s / 100, l / 100
if h < 0 then
h = h + 360
end
local function f(n)
local k = (n + h / 30) % 12
local a = s * math.min(l, 1 - l)
return l - a * math.max(-1, math.min(k - 3, 9 - k, 1))
end
return f(0) * 255, f(8) * 255, f(4) * 255
end
local h, s, l = m:match("(%d+)[, ] ?(%d+)%%?[, ] ?(%d+)%%?")
local r, g, b = hsl_to_rgb(h, s, l)
local hex = string.format("#%02x%02x%02x", r, g, b)
return MiniHipatterns.compute_hex_color_group(hex)
end,
},
tailwind = {
pattern = function()
local ft = {
"css",
"html",
"javascript",
"javascriptreact",
"svelte",
"typescript",
"typescriptreact",
"vue",
}
if not vim.tbl_contains(ft, vim.bo.filetype) then
return
end
return "%f[%w:-]()[%w:-]+%-[a-z%-]+%-%d+()%f[^%w:-]"
-- compact
-- return "%f[%w:-][%w:-]+%-()[a-z%-]+%-%d+()%f[^%w:-]"
end,
group = function(_, _, d)
local match = d.full_match
local color, shade = match:match("[%w-]+%-([a-z%-]+)%-(%d+)")
shade = tonumber(shade)
local bg = vim.tbl_get(tw_store.cl, color, shade)
if bg then
local hl = "MiniHipatternsTailwind" .. color .. shade
if not tw_store.hl[hl] then
tw_store.hl[hl] = true
local bg_shade = shade == 500 and 950 or shade < 500 and 900 or 100
local fg = vim.tbl_get(tw_store.cl, color, bg_shade)
vim.api.nvim_set_hl(0, hl, { bg = "#" .. bg, fg = "#" .. fg })
end
return hl
end
end,
},
},
})
local MiniIndentscope = require("mini.indentscope")
vim.g.miniindentscope_disable = true
MiniIndentscope.setup({
mappings = {
object_scope = "ii",
object_scope_with_border = "ai",
goto_top = "[i",
goto_bottom = "]i",
},
options = {
indent_at_cursor = false,
},
})
vim.keymap.set("n", "grs", function()
return "<Cmd>sil norm " .. (vim.v.count > 1 and vim.v.count - 1 .. "[i" or "") .. "viiyvaipgv<<Enter>"
end, { expr = true, desc = "Replace scope" })
local MiniJump2d = require("mini.jump2d")
MiniJump2d.setup({ mappings = { start_jumping = "" } })
vim.keymap.set("n", "<S-Enter>", function()
MiniJump2d.start(MiniJump2d.builtin_opts.query)
end, { desc = "Jump2d" })
-- local MiniKeymap = require("mini.keymap")
-- MiniKeymap.map_combo("i", ">", function()
-- local row, col = unpack(vim.api.nvim_win_get_cursor(0))
-- local line = vim.api.nvim_get_current_line()
-- if line:sub(col + 1, col + 1) == "<" then
-- return
-- end
-- local tag = line:sub(1, col):match("<([%l%d:%-]+)[^<>]*>$")
-- if not tag then
-- return
-- end
-- local close = ("</%s>"):format(tag)
-- row = row - 1
-- vim.api.nvim_buf_set_text(0, row, col, row, col, { close })
-- end)
local MiniMisc = require("mini.misc")
MiniMisc.setup_restore_cursor({ center = vim.g.session_center_cursor })
local MiniSessions = require("mini.sessions")
function _G.find_root(buf)
return vim.lsp.buf.list_workspace_folders()[1]
or vim.fs.root(buf or 0, {
".git",
"Makefile",
"package.json",
})
end
MiniSessions.get_current = function()
local name = string.gsub(find_root(0) or "", "/", "%%")
return name
end
MiniSessions.setup({
directory = vim.fn.stdpath("state") .. "/sessions",
hooks = {
pre = {
write = function()
vim.fn.mkdir(MiniSessions.config.directory, "p")
end,
},
post = {
read = function()
if vim.g.session_center_cursor then
vim.cmd('normal! zz"')
end
end,
},
},
})
vim.cmd.cnoreabbrev("Lo", "Load")
vim.api.nvim_create_user_command("Load", function()
MiniSessions.read(MiniSessions.get_current())
end, {})
vim.cmd.cnoreabbrev("La", "Last")
vim.api.nvim_create_user_command("Last", function()
MiniSessions.read(MiniSessions.get_latest())
end, {})
-- vim.cmd.cnoreabbrev("L", "Load")
-- vim.api.nvim_create_user_command("Load", function(a)
-- if not a.args or a.args == "current" then
-- MiniSessions.read(MiniSessions.get_current())
-- elseif a.args == "last" then
-- MiniSessions.read(MiniSessions.get_latest())
-- end
-- end, {
-- nargs = "?",
-- complete = function()
-- return { "current", "last" }
-- end,
-- })
if vim.fn.argc() == 0 then
vim.api.nvim_create_autocmd("VimEnter", {
desc = "Read session after entering (no args)",
group = vim.api.nvim_create_augroup("read_session", { clear = true }),
nested = true,
callback = function()
pcall(MiniSessions.read, MiniSessions.get_current())
end,
})
end
vim.api.nvim_create_autocmd("VimLeavePre", {
desc = "Write session before leaving",
group = vim.api.nvim_create_augroup("write_session", { clear = true }),
callback = function()
pcall(MiniSessions.write, MiniSessions.get_current())
end,
})
local MiniMove = require("mini.move")
MiniMove.setup({
mappings = {
left = "<C-h>",
down = "<C-j>",
up = "<C-k>",
right = "<C-l>",
line_left = "",
line_down = "",
line_up = "",
line_right = "",
},
})
local MiniPairs = require("mini.pairs")
MiniPairs.setup({
mappings = {
["("] = { neigh_pattern = "[^\\][%s>)%]},]" },
["["] = { neigh_pattern = "[^\\][%s>)%]},]" },
["{"] = { neigh_pattern = "[^\\][%s>)%]},]" },
['"'] = { neigh_pattern = "[%s<(%[{][%s>)%]},]" },
["'"] = { neigh_pattern = "[%s<(%[{][%s>)%]},]" },
["`"] = { neigh_pattern = "[%s<(%[{][%s>)%]},]" },
["<"] = { action = "open", pair = "<>", neigh_pattern = "[\r%S].", register = { cr = false } },
[">"] = { action = "close", pair = "<>", register = { cr = false } },
},
})
require("mini.keymap").map_combo("i", "<<", function()
local line = vim.api.nvim_get_current_line()
local col = vim.fn.col(".")
-- stylua: ignore
if line:sub(col, col) == ">" then return "<Del><Del>" end
end)
require("mini.keymap").map_combo("i", "=", function()
local line = vim.api.nvim_get_current_line()
local col = vim.fn.col(".")
-- stylua: ignore
if line:sub(col - 2, col) == "<=>" then return "<Del>" end
end)
local MiniPick = require("mini.pick")
local minipick_remap = function(lhs, rhs)
-- stylua: ignore
return { char = lhs, func = function() vim.api.nvim_input(rhs) end }
end
MiniPick.setup({
mappings = {
move_down = "<C-n>",
move_up = "<C-p>",
move_down_2 = minipick_remap("<C-j>", "<C-n>"),
move_up_2 = minipick_remap("<C-k>", "<C-p>"),
reveal_file = {
char = "<S-Enter>",
func = function()
local is_file = function(item)
local ok, stat = pcall(vim.uv.fs_stat, item)
return ok and stat ~= nil
end
local matches = MiniPick.get_picker_matches()
local current = matches.current
if not is_file(current) then
return
end
vim.schedule(function()
local minifiles = require("mini.files")
minifiles.open(current, false)
minifiles.reveal_cwd()
end)
return true
end,
},
},
})
vim.keymap.set("n", "<Leader>sf", function()
MiniPick.builtin.cli({
command = { "fd", "-t=f", "-H", "-I", "-E=.git", "-E=node_modules" },
}, {
source = {
name = "Files (fd)",
show = function(buf, items, query)
MiniPick.default_show(buf, items, query, { show_icons = true })
end,
},
})
end, { desc = "Seach files" })
-- stylua: ignore start
vim.keymap.set("n", "<Leader>sb", function() MiniPick.builtin.buffers() end, { desc = "Seach buffers" })
vim.keymap.set("n", "<Leader>sg", function() MiniPick.builtin.grep_live() end, { desc = "Seach grep" })
vim.keymap.set("n", "<Leader>sh", function() MiniPick.builtin.help() end, { desc = "Seach help" })
-- stylua: ignore end
local MiniSplitjoin = require("mini.splitjoin")
local gen_hook = MiniSplitjoin.gen_hook
MiniSplitjoin.setup({
mappings = { toggle = "gs" },
split = {
hooks_post = {
gen_hook.add_trailing_separator({ brackets = { "%b{}" } }),
},
},
koin = {
hooks_post = {
gen_hook.pad_brackets({ brackets = { "%b{}" } }),
},
},
})
-- -- Treesitter
after_update({
pattern = "nvim-treesitter",
desc = "Run `:TSUpdate` after pack update",
group = vim.api.nvim_create_augroup("ts_update", { clear = true }),
command = "TSUpdate",
})
vim.pack.add({
{ src = "https://github.com/nvim-treesitter/nvim-treesitter", version = "main" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter-textobjects", version = "main" },
})
local ts_install = vim.g.ts_install or {}
local ts_filetypes = vim
.iter(ts_install)
:map(function(lang)
return vim.treesitter.language.get_filetypes(lang)
end)
:flatten()
:totable()
require("nvim-treesitter").install(ts_install)
vim.api.nvim_create_autocmd("FileType", {
desc = "Setup treesitter for a buffer",
pattern = ts_filetypes,
group = vim.api.nvim_create_augroup("ts_setup", { clear = true }),
callback = function(e)
vim.treesitter.start(e.buf)
vim.wo.foldmethod = "expr"
vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()"
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
-- -- Mason
vim.pack.add({
{ src = "https://github.com/mason-org/mason.nvim" },
})
local mason_install = vim.g.mason_install or {}
require("mason").setup()
local mason_available = require("mason-registry").get_installed_package_names()
local mason_rest = {}
for _, inst in ipairs(mason_install) do
if not vim.list_contains(mason_available, inst) then
table.insert(mason_rest, inst)
end
end
if #mason_rest > 0 then
vim.cmd("MasonInstall " .. table.concat(mason_rest, " "))
end
-- -- LSP
vim.pack.add({
{ src = "https://github.com/neovim/nvim-lspconfig" },
})
local lsp_enable = vim.g.lsp_enable or {}
vim.lsp.enable(lsp_enable)
vim.diagnostic.config({ virtual_text = true })
vim.keymap.set("n", "gK", function()
vim.diagnostic.config({
virtual_text = not vim.diagnostic.config().virtual_text,
})
end, { desc = "Toggle diagnostic" })
vim.schedule(function()
local ns = vim.api.nvim_create_namespace("lsp_progress")
local timer = assert(vim.uv.new_timer())
local buf = -1
local win = -1
---@param msg string|string[]
---@param hl? string
---@param keep_ms? integer
local notify = function(msg, hl, keep_ms)
---@cast msg string[]
msg = type(msg) == "string" and vim.split(msg, "\n") or msg
hl = hl or "Normal"
local vpad = 0
local hpad = 0
local min_width = 5
local max_width = vim.iter(msg):fold(min_width, function(acc, v)
return math.max(acc, #v)
end)
local win_config = { ---@type vim.api.keyset.win_config
relative = "editor",
anchor = "SE",
row = vim.o.lines - 2,
col = vim.o.columns,
width = max_width + hpad * 2,
height = #msg + vpad * 2,
zindex = 100,
style = "minimal",
border = "single",
}
if not vim.api.nvim_buf_is_valid(buf) then
buf = vim.api.nvim_create_buf(false, true)
end
if not vim.api.nvim_win_is_valid(win) then
win = vim.api.nvim_open_win(buf, false, win_config)
else
vim.api.nvim_win_set_config(win, win_config)
end
local hp = string.rep(" ", hpad)
local vp = vim.fn["repeat"]({ hp }, vpad)
local lines = {}
vim.list_extend(lines, vp)
-- stylua: ignore
vim.list_extend(lines, vim.tbl_map(function(line) return hp .. line .. hp end, msg))
vim.list_extend(lines, vp)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.hl.range(buf, ns, hl, { 0, 0 }, { #lines, -1 })
if keep_ms and keep_ms > 1 then
timer:start(keep_ms, 0, function()
timer:stop()
vim.schedule(function()
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
end)
end)
end
return win
end
vim.api.nvim_create_autocmd("LspProgress", {
desc = "Show LSP progress status",
group = vim.api.nvim_create_augroup("lsp_progress", { clear = true }),
callback = function()
local msg = string.gsub(vim.lsp.status(), "^%s*%d+%%: ", "")
local msg_lines = vim.split(msg, ", ")
notify(msg_lines, "Conceal", 1000)
end,
})
end)
vim.api.nvim_create_autocmd("LspAttach", {
desc = "Undim current diagnostic on `CursorHold`",
group = vim.api.nvim_create_augroup("lsp_undim", { clear = true }),
callback = function(e)
local client = assert(vim.lsp.get_client_by_id(e.data.client_id))
local ns =
vim.api.nvim_create_namespace(string.format("nvim.nvim.lsp.%s.%d.diagnostic.underline", client.name, client.id))
local undim_diagnostic = function(diagnostic) ---@param diagnostic vim.Diagnostic
local from = { diagnostic.lnum, diagnostic.col }
local to = { diagnostic.end_lnum, diagnostic.end_col }
local extmarks = vim.api.nvim_buf_get_extmarks(e.buf, ns, from, to, {})
for _, extm in ipairs(extmarks) do
vim.api.nvim_buf_del_extmark(e.buf, ns, extm[1])
end
end
local clear_hl = function()
vim.api.nvim_buf_clear_namespace(e.buf, ns, 0, -1)
end
local apply_hl = function()
local lnum, col = vim.fn.line(".") - 1, vim.fn.col(".") - 1
local line_diagnostics = {} ---@type vim.Diagnostic[]
local select_from = vim.diagnostic.get(e.buf, { severity = vim.diagnostic.severity.HINT })
for _, diagnostic in ipairs(select_from) do
if diagnostic._tags and diagnostic._tags.unnecessary then
vim.api.nvim_buf_set_extmark(e.buf, ns, diagnostic.lnum, diagnostic.col, {
hl_group = "DiagnosticUnnecessary",
end_line = diagnostic.end_lnum,
end_col = diagnostic.end_col,
strict = false,
})
if lnum >= diagnostic.lnum and lnum <= diagnostic.end_lnum then
table.insert(line_diagnostics, diagnostic)
end
end
end
for _, diagnostic in ipairs(line_diagnostics) do
if diagnostic.lnum == diagnostic.end_lnum then
if col < diagnostic.end_col then
undim_diagnostic(diagnostic)
end
else
undim_diagnostic(diagnostic)
end
end
end
local refresh_hl = function()
clear_hl()
apply_hl()
end
local aug = vim.api.nvim_create_augroup("undim_diagnostic", { clear = false })
vim.api.nvim_create_autocmd("ModeChanged", {
buffer = e.buf,
group = aug,
callback = function()
local mode = vim.fn.mode()
if mode == "n" then
refresh_hl()
elseif mode == "c" then
else
clear_hl()
end
end,
})
vim.api.nvim_create_autocmd("DiagnosticChanged", {
buffer = e.buf,
group = aug,
callback = function()
if vim.fn.mode() == "n" then
refresh_hl()
end
end,
})
vim.api.nvim_create_autocmd("CursorHold", {
buffer = e.buf,
group = aug,
callback = function()
refresh_hl()
end,
})
end,
})
-- -- Debug
vim.pack.add({
{ src = "https://github.com/mfussenegger/nvim-dap" },
{ src = "https://github.com/igorlfs/nvim-dap-view" },
{ src = "https://github.com/theHamsta/nvim-dap-virtual-text" },
})
local dap = require("dap")
local dap_view = require("dap-view")
dap_view.setup()
require("nvim-dap-virtual-text").setup()
-- stylua: ignore start
vim.keymap.set("n", "<Leader>B", function() dap.toggle_breakpoint() end, { desc = "Debug breakpoint" })
vim.keymap.set("n", "<Leader>dc", function() dap.continue() end, { desc = "Debug continue" })
vim.keymap.set("n", "<Leader>di", function() dap.step_into() end, { desc = "Debug step into" })
vim.keymap.set("n", "<Leader>do", function() dap.step_over() end, { desc = "Debug step over" })
vim.keymap.set("n", "<Leader>dO", function() dap.step_out() end, { desc = "Debug step out" })
vim.keymap.set("n", "<Leader>db", function() dap.step_back() end, { desc = "Debug step back" })
vim.keymap.set("n", "<Leader>de", function() dap.eval(nil, { enter = true }) end, { desc = "Debug eval" })
vim.keymap.set("n", "<Leader>dv", function() dap_view.toggle() end, { desc = "Debug view" })
-- stylua: ignore end
-- stylua: ignore start
dap.listeners.before.attach.dapui_config = function() dap.view.open() end
dap.listeners.before.launch.dapui_config = function() dap.view.open() end
dap.listeners.before.event_terminated.dapui_config = function() dap_view.close() end
dap.listeners.before.event_exited.dapui_config = function() dap_view.close() end
-- stylua: ignore end
-- -- -- Go
-- https://codeberg.org/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#go-using-delve-directly
dap.adapters.delve = function(callback, config)
if config.mode == "remote" and config.request == "attach" then
callback({
type = "server",
host = config.host or "127.0.0.1",
port = config.port or "38697",
})
else
callback({
type = "server",
port = "${port}",
executable = {
command = "dlv",
args = { "dap", "-l", "127.0.0.1:${port}", "--log", "--log-output=dap" },
detached = vim.fn.has("win32") == 0,
},
})
end
end
dap.configurations.go = {
{
type = "delve",
name = "Debug",
request = "launch",
program = "${file}",
},
{
type = "delve",
name = "Debug test",
request = "launch",
mode = "test",
program = "${file}",
},
{
type = "delve",
name = "Debug test (go.mod)",
request = "launch",
mode = "test",
program = "./${relativeFileDirname}",
},
}
-- Custom
-- -- Format
local formatconf = vim.g.formatconf or {}
local format = function(opts)
opts = vim.tbl_extend("keep", opts or {}, {
bufnr = vim.api.nvim_get_current_buf(),
lines = {},
after = function() end,
timeout_ms = 5000,
})
local run = formatconf[vim.bo.ft]
if not run then
local range = {}
if opts.lines[1] and opts.lines[2] then
range["start"] = { opts.lines[1], 0 }
range["end"] = { opts.lines[2], -1 }
end
vim.lsp.buf.format({
bufnr = opts.bufnr,
async = true,
timeout_ms = opts.timeout_ms,
range = range,
})
return false
end
local mode = vim.api.nvim_get_mode().mode
local vi = string.match(mode, "[vV]")
local selected = {}
if vi then
vim.api.nvim_buf_call(opts.bufnr, function()
selected[1] = vim.fn.getpos("v")[2]
selected[2] = vim.fn.getpos(".")[2]
end)
end
local _l1 = opts.lines[1] or selected[1] or 1
local _l2 = opts.lines[2] or selected[2] or vim.fn.line("$")
local ln_1 = math.min(_l1, _l2)
local ln_2 = math.max(_l1, _l2)
local ctx = {
file = vim.fn.expand("%:p"),
ext = vim.fn.expand("%:e"),
vi = vi,
l1 = ln_1,
l2 = ln_2,
}
vim.api.nvim_buf_call(opts.bufnr, function()
ctx.b1 = vim.fn.line2byte(ln_1) - 1
ctx.b2 = vim.fn.line2byte(ln_2 + 1)
end)
ctx.stdin = function(stdin_opts)
stdin_opts = vim.tbl_extend("keep", stdin_opts, {
cmd = {},
diff = true,
-- stylua: ignore
transform = function(lines) return lines end,
})
local stdin_lines = vim.api.nvim_buf_get_lines(opts.bufnr, 0, -1, true)
local stdin_str = table.concat(stdin_lines, "\n")
local on_exit = function(out) ---@param out vim.SystemCompleted
if out.code == 0 then
local stdout_lines = vim.split(out.stdout, "\n")
local fmt_lines = stdin_opts.transform(stdout_lines) or stdout_lines
local fmt_str = table.concat(fmt_lines, "\n")
if not stdin_opts.diff then
vim.api.nvim_buf_set_lines(opts.bufnr, 0, -1, true, fmt_lines)
else
local chunks = vim.text.diff(stdin_str, fmt_str, { algorithm = "histogram", result_type = "indices" })
vim
.iter(chunks)
:filter(function(ch)
local line_a, len_a = unpack(ch)
return ln_1 <= line_a and ln_2 >= line_a + len_a - 1
end)
:rev()
:each(function(ch)
local line_a, len_a, line_b, len_b = unpack(ch)
local repl = vim.list_slice(fmt_lines, line_b, line_b + len_b)
vim.api.nvim_buf_set_lines(opts.bufnr, line_a - 1, line_a + len_a, false, repl)
end)
end
else
vim.notify(out.stderr, vim.log.levels.ERROR)
end
opts.after(out, ctx)
end
local cmd = stdin_opts.cmd
if type(cmd) == "string" then
cmd = vim.split(cmd, "%s+") ---@cast cmd string[]
end
vim.system(cmd, {
cwd = vim.fn.expand("%:p:h"),
stdin = stdin_lines,
timeout = opts.timeout_ms,
}, vim.schedule_wrap(on_exit))
end
run(ctx)
return true
end
vim.keymap.set("n", "gqq", "gq_", { remap = true, desc = "Format" })
-- stylua: ignore
vim.keymap.set("v", "gq", function() format() end, { desc = "Format" })
vim.keymap.set("n", "gq", function()
local view = vim.fn.winsaveview()
function _G.Format()
format({ lines = { vim.fn.getpos("'[")[2], vim.fn.getpos("']")[2] } })
vim.fn.winrestview(view)
end
vim.o.operatorfunc = "v:lua.Format"
return "g@"
end, { expr = true, desc = "Format {motion}" })
-- -- Terminal
vim.api.nvim_create_autocmd("TermOpen", {
desc = "Set options for the terminal window",
group = vim.api.nvim_create_augroup("term_open", { clear = true }),
callback = function()
vim.wo.number = false
vim.wo.relativenumber = false
end,
})
vim.keymap.set("t", "<Esc><Esc>", "<C-\\><C-n>", { desc = "Exit terminal mode" })
vim.cmd.cnoreabbrev("lz", "Lazygit")
vim.cmd.cnoreabbrev("Lz", "Lazygit")
vim.api.nvim_create_user_command("Lazygit", function()
vim.cmd.tabnew()
vim.cmd.terminal("lazygit")
local win = vim.api.nvim_get_current_win()
vim.api.nvim_create_autocmd("WinClosed", {
pattern = tostring(win),
once = true,
callback = function(e)
vim.cmd.bwipeout({ args = { e.buf }, bang = true })
end,
})
pcall(vim.cmd.file, "term:lazygit")
vim.cmd.startinsert()
end, {})
vim.schedule(function()
_G.Terminal = {
store = {},
}
function Terminal.close(id, unload)
local term = Terminal.store[id]
if not term then
return nil
end
local count = nil
if vim.api.nvim_win_is_valid(term.win) then
local buf = vim.api.nvim_win_get_buf(term.win)
count = vim.b[buf].term_count
vim.api.nvim_win_close(term.win, unload)
term.win = -1
end
if unload then
for _, buf in ipairs(term.buflist) do
vim.api.nvim_buf_delete(buf, { force = true })
end
Terminal.store[id] = nil
end
return count
end
function Terminal.open(id, count, win_config)
count = count or 1
win_config = win_config or {}
Terminal.store[id] = Terminal.store[id] or {
win = -1,
buflist = {},
}
local term = Terminal.store[id]
local mods = { mods = { split = "botright" } }
local new = function(buf, win_conf)
buf = buf or -1
win_conf = win_conf or {}
local is_buf = vim.api.nvim_buf_is_valid(buf)
if is_buf then
vim.cmd.split(mods)
else
vim.cmd.terminal(mods)
buf = vim.api.nvim_get_current_buf()
end
local win = vim.api.nvim_get_current_win()
term.win = win
vim.api.nvim_win_set_config(win, win_conf)
if is_buf then
vim.wo[win].winfixbuf = false
vim.api.nvim_win_set_buf(win, buf)
end
vim.wo[win].winfixbuf = true
term.buflist[count] = buf
vim.b[buf].term_count = count
end
if vim.api.nvim_win_is_valid(term.win) then
local buf = term.buflist[count] or -1
if vim.api.nvim_buf_is_valid(buf) then
vim.api.nvim_win_set_config(0, win_config)
vim.wo[term.win].winfixbuf = false
vim.api.nvim_win_set_buf(term.win, buf)
vim.wo[term.win].winfixbuf = true
else
local win_state = vim.api.nvim_win_get_config(term.win)
vim.api.nvim_win_close(term.win, false)
new(nil, win_state)
end
else
local buf = term.buflist[count] or -1
new(buf, win_config)
end
return term.win
end
local last_count = 1 ---@type integer?
local win = -1
local win_config = { height = 15 }
local open_term = function(count)
win = Terminal.open("default", count, win_config)
vim.wo[win].winbar = "Terminal " .. count
end
vim.keymap.set({ "n", "t" }, "<M-`>", function()
if vim.api.nvim_win_is_valid(win) then
win_config = vim.api.nvim_win_get_config(win)
if vim.v.count == 0 then
last_count = Terminal.close("default", false)
else
open_term(vim.v.count1)
end
else
open_term(vim.v.count == 0 and last_count or vim.v.count1)
end
end, { desc = "Terminal" })
end)
-- -- Marks
local mark_ns = vim.api.nvim_create_namespace("mark_virtual")
local marks_group = vim.api.nvim_create_augroup("mark_virtual", { clear = true })
vim.g.virt_marks = true
local get_marks = function(buf, filter)
buf = buf or 0
buf = buf == 0 and vim.api.nvim_get_current_buf() or buf
local file = vim.api.nvim_buf_get_name(buf)
filter = filter or function(m)
return m.mark:match("'%a")
end
-- stylua: ignore
local buffer_marks = vim.iter(vim.fn.getmarklist(buf))
:map(function(m) m.type = "buffer"; return m end)
:totable()
-- stylua: ignore
local global_marks = vim.iter(vim.fn.getmarklist())
:filter(function(m) return vim.fn.fnamemodify(m.file, ":p") == file end)
:map(function(m) m.type = "global"; return m end)
:totable()
return vim.iter({ buffer_marks, global_marks }):flatten(1):filter(filter):totable()
end
local clear_buf_marks = function(buf)
vim.api.nvim_buf_clear_namespace(buf, mark_ns, 0, -1)
end
local draw_buf_marks = function(buf)
clear_buf_marks(buf)
local buf_marks = get_marks(buf)
local lnum_marks = {}
for _, m in ipairs(buf_marks) do
local _, lnum = unpack(m.pos)
lnum = lnum - 1
lnum_marks[lnum] = lnum_marks[lnum] or {}
table.insert(lnum_marks[lnum], m)
end
local get_indent = function(lnum)
local line = table.remove(vim.api.nvim_buf_get_lines(buf, lnum, lnum + 1, false))
line = line or ""
return string.match(line, "^%s+") or ""
end
local line_count = vim.api.nvim_buf_line_count(buf)
for lnum, marks in pairs(lnum_marks) do
if lnum < line_count then
local indent = get_indent(lnum)
local virt_lines = {}
for _, m in ipairs(marks) do
table.insert(virt_lines, { { string.format("%s %s", indent, m.mark), "Comment" } })
end
vim.api.nvim_buf_set_extmark(buf, mark_ns, lnum, 0, {
virt_lines = virt_lines,
virt_lines_above = true,
strict = false,
})
end
end
return buf_marks
end
local apply_buf_marks = function(buf, enabled)
if enabled ~= nil then
vim.b[buf].virt_marks = enabled
end
if vim.b[buf].virt_marks then
draw_buf_marks(buf)
else
clear_buf_marks(buf)
end
end
--
local toggle_marks = function()
local next_val = not vim.b.virt_marks
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
apply_buf_marks(buf, next_val)
end
end
local toggle_buf_marks = function(buf)
buf = buf or 0
apply_buf_marks(buf, not vim.b[buf].virt_marks)
end
-- stylua: ignore start
vim.keymap.set("n", "<Leader>m", function() toggle_buf_marks() end, { desc = "Toggle virt marks" })
vim.keymap.set("n", "<Leader>M", function() toggle_marks() end, { desc = "Toggle virt marks" })
-- stylua: ignore end
vim.api.nvim_create_autocmd({ "BufEnter", "CursorHold" }, {
desc = "Show named vim marks as virtual lines",
group = marks_group,
callback = function(e)
if vim.b[e.buf].virt_marks == nil then
vim.b[e.buf].virt_marks = vim.g.virt_marks
end
apply_buf_marks(e.buf)
end,
}) |
Beta Was this translation helpful? Give feedback.


















Uh oh!
There was an error while loading. Please reload this page.
-
Seeing how other people use
mini.nvimis a very helpful feedback for me. It helps me reason about which modules are used the most and whatconfigvalues are used. This might influence my future decisions in design and default values. And also might other people new ideas.Feel free to share a link to specific part of dotfiles (might be a good idea to pin to specific commit), code or screenshot (if too big, please hide under spoiler).
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions