Skip to content

Instantly share code, notes, and snippets.

@whexy
Created November 16, 2025 00:43
Show Gist options
  • Select an option

  • Save whexy/15e2eee18048b0176f5796591e651455 to your computer and use it in GitHub Desktop.

Select an option

Save whexy/15e2eee18048b0176f5796591e651455 to your computer and use it in GitHub Desktop.
neovim v0.12 config in one file
vim.g.mapleader = ","
vim.g.maplocalleader = ","
-- color scheme
vim.pack.add({
{ src = 'https://github.com/Mofiqul/dracula.nvim' },
{ src = "https://github.com/neovim/nvim-lspconfig" },
{ src = "https://github.com/rachartier/tiny-inline-diagnostic.nvim" },
{ src = "https://github.com/saghen/blink.cmp" },
{ src = "https://github.com/stevearc/conform.nvim" },
{ src = "https://github.com/sphamba/smear-cursor.nvim" },
{ src = "https://github.com/gbprod/yanky.nvim" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/nvim-telescope/telescope.nvim" },
{ src = "https://github.com/akinsho/bufferline.nvim" },
{ src = "https://github.com/nvim-neo-tree/neo-tree.nvim" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/MunifTanjim/nui.nvim" },
{ src = "https://github.com/nvim-tree/nvim-web-devicons" },
})
require("dracula").setup({
colors = {
bg = "#29202B", -- hsl(289,14%,15%)
fg = "#F7F7F1", -- hsl(60,30%,96%)
red = "#FF947F", -- hsl(10,100%,75%)
orange = "#FFC97F", -- hsl(35,100%,75%)
yellow = "#FEFF7F", -- hsl(60,100%,75%)
green = "#8AFF7F", -- hsl(115,100%,75%)
cyan = "#7FFFE9", -- hsl(170,100%,75%)
blue = "#7FBFFF", -- hsl(210,100%,75%)
pink = "#FF7FBF", -- hsl(330,100%,75%)
purple = "#947FFF", -- hsl(250,100%,75%)
shadow = "#000000", -- hsl(0,0%,0%)
darken = "#212121", -- hsl(0,0%,13%)
selection = "#534157", -- color(bg) s(15%) l(30%)
comment = "#9E6FA8", -- color(bg) s(25%) l(55%)
visual = "#492F4F", -- color(bg) s(25%) l(25%)
stack = "#E77FFF", -- color(comment) s(100%) l(75%)
bright_red = "#FFBFB2", -- red l+10%
bright_orange = "#FFDFB2", -- orange l+10%
bright_yellow = "#FFFFB2", -- yellow l+10%
bright_green = "#B8FFB2", -- green l+10%
bright_cyan = "#B2FFF2", -- cyan l+10%
bright_blue = "#B2D8FF", -- blue l+10%
bright_pink = "#FFB2D8", -- pink l+10%
bright_purple = "#BFB2FF", -- purple l+10%
bright_white = "#FFFFFF", -- pure white
white = "#F7F7F1", -- same as fg
black = "#000000", -- same as shadow
menu = "#241C25", -- bg.l - 2
gutter_fg = "#84568F", -- comment.l - 10
nontext = "#584D5A", -- invisibles: color(comment) s×0.3, l×0.6
},
transparent_bg = false,
overrides = {
NormalFloat = { bg = "#241C25" },
FloatBorder = { fg = "#BFB2FF", bg = "#241C25" },
NoiceCmdlinePopupBorder = { fg = "#BFB2FF" },
},
})
vim.cmd.colorscheme("dracula")
vim.lsp.enable({ "lua_ls", "clangd", "rust_analyzer" })
-- Diagnostic
require("tiny-inline-diagnostic").setup({})
vim.diagnostic.config({ virtual_text = false })
-- CMP
require("blink.cmp").setup({
keymap = { preset = "enter" },
appearance = {
nerd_font_variant = "mono",
},
completion = { documentation = { auto_show = false } },
sources = {
default = { "lsp", "path", "snippets", "buffer" },
},
fuzzy = { implementation = "prefer_rust_with_warning" },
})
-- Formatter
vim.keymap.set(
{ "n" },
"<leader>cf",
function()
require("conform").format({
async = true,
lsp_fallback = true,
timeout_ms = 500,
})
end,
{ desc = "Format file" }
)
require("conform").setup(
{
format_on_save = {
lsp_fallback = true,
timeout_ms = 500,
},
-- formatters_by_ft = language_config.FORMATTER_MAP,
}
)
require("smear_cursor").setup({
smear_between_buffers = true,
})
-- custom paste function
local function paste_from_unnamed()
local lines = vim.split(vim.fn.getreg(""), "\n", { plain = true })
if #lines == 0 then
lines = { "" }
end
local rtype = vim.fn.getregtype(""):sub(1, 1)
return { lines, rtype }
end
vim.g.clipboard = {
name = "OSC 52",
copy = {
["+"] = require("vim.ui.clipboard.osc52").copy("+"),
["*"] = require("vim.ui.clipboard.osc52").copy("*"),
},
paste = {
["+"] = paste_from_unnamed,
["*"] = paste_from_unnamed,
},
}
vim.api.nvim_create_autocmd("TextYankPost", {
callback = function()
local ev = vim.v.event
if ev.operator == "y" and ev.regname == "" then
vim.fn.setreg("+", ev.regcontents, ev.regtype)
end
end,
})
require("yanky").setup({
system_clipboard = {
sync_with_ring = false,
}
})
-- options
-- show the absolute line number for the current line
vim.opt.number = true
-- show relative line numbers
vim.opt.relativenumber = true
-- Confirm before quitting unsaved changes
vim.opt.confirm = true
-- Persistent undo across sessions
vim.opt.undofile = true
-- Practically infinite undo (safe)
vim.opt.undolevels = 1000000
-- Enable mouse in all modes
vim.opt.mouse = "a"
-- Use spaces instead of tabs
vim.opt.expandtab = true
-- Indent size
vim.opt.shiftwidth = 2
-- Tab character width
vim.opt.tabstop = 2
-- Round indent to nearest multiple of shiftwidth
vim.opt.shiftround = true
-- Auto-indent new lines intelligently
vim.opt.smartindent = true
-- Keep comments, wrap text, autoformat when possible
vim.opt.formatoptions = "jcroqlnt"
-- Case-insensitive by default
vim.opt.ignorecase = true
-- But smart if uppercase is used
vim.opt.smartcase = true
-- Live preview for :substitute
vim.opt.inccommand = "nosplit"
vim.opt.grepprg = "rg --vimgrep" -- Use ripgrep for :grep
-- Match file:line:col:message format
vim.opt.grepformat = "%f:%l:%c:%m"
-- Highlight current line
vim.opt.cursorline = true
-- Always show sign column
vim.opt.signcolumn = "yes"
-- Show cursor position in statusline
vim.opt.ruler = true
-- Global statusline (once you add one)
vim.opt.laststatus = 3
-- Enable true colors
vim.opt.termguicolors = true
-- Prevent tiny splits
vim.opt.winminwidth = 5
-- Keep 4 lines visible around cursor
vim.opt.scrolloff = 4
-- Keep 8 columns visible horizontally
vim.opt.sidescrolloff = 8
-- Disable line wrapping
vim.opt.wrap = false
-- (If wrapping) break at words
vim.opt.linebreak = true
-- Show invisible characters (tabs, etc.)
vim.opt.list = false
vim.opt.showmode = false
vim.opt.colorcolumn = "80"
-- Fold by indentation level
vim.opt.foldmethod = "indent"
-- Start unfolded
vim.opt.foldlevel = 99
-- Simple fold indicator (first line + …)
vim.opt.foldtext = "v:lua.vim.fn.getline(v:foldstart) .. ' …'"
-- Restore view after jump
vim.opt.jumpoptions = "view"
-- Allow cursor past EOL in block mode
vim.opt.virtualedit = "block"
-- Enhanced command completion
vim.opt.wildmode = "longest:full,full"
-- Horizontal splits below
vim.opt.splitbelow = true
-- Vertical splits to the right
vim.opt.splitright = true
-- Preserve layout when splitting
vim.opt.splitkeep = "screen"
-- keymaps
local map = vim.keymap.set
-- better up/down
map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
map({ "n", "x" }, "<Down>", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true, silent = true })
map({ "n", "x" }, "<Up>", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true, silent = true })
-- Move Lines
map("n", "<A-j>", "<cmd>execute 'move .+' . v:count1<cr>==", { desc = "Move Down" })
map("n", "<A-k>", "<cmd>execute 'move .-' . (v:count1 + 1)<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>", ":<C-u>execute \"'<,'>move '>+\" . v:count1<cr>gv=gv", { desc = "Move Down" })
map("v", "<A-k>", ":<C-u>execute \"'<,'>move '<-\" . (v:count1 + 1)<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", "<leader>bd", function()
local cur = vim.api.nvim_get_current_buf()
local alt = vim.fn.bufnr("#")
if alt > 0 and vim.api.nvim_buf_is_loaded(alt) then
vim.cmd("buffer #")
else
vim.cmd("bnext")
end
vim.cmd("bdelete " .. cur)
end, { desc = "Delete Buffer" })
map("n", "<leader>bo", function()
local current = vim.api.nvim_get_current_buf()
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) and buf ~= current then
vim.cmd("bdelete " .. buf)
end
end
end, { desc = "Delete Other Buffers" })
map("n", "<leader>bD", "<cmd>:bd<cr>", { desc = "Delete Buffer and Window" })
-- Clear search and stop snippet on escape
map({ "i", "n", "s" }, "<esc>", function()
vim.cmd("noh")
return "<esc>"
end, { expr = true, desc = "Escape and Clear hlsearch" })
-- 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" })
-- quick save
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("x", "<", "<gv")
map("x", ">", ">gv")
-- commenting
map("n", "gco", "o<esc>Vcx<esc><cmd>normal gcc<cr>fxa<bs>", { desc = "Add Comment Below" })
map("n", "gcO", "O<esc>Vcx<esc><cmd>normal gcc<cr>fxa<bs>", { desc = "Add Comment Above" })
-- lazy
map("n", "<leader>l", "<cmd>Lazy<cr>", { desc = "Lazy" })
-- new file
map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
-- location list
map("n", "<leader>xl", function()
local success, err = pcall(vim.fn.getloclist(0, { winid = 0 }).winid ~= 0 and vim.cmd.lclose or vim.cmd.lopen)
if not success and err then
vim.notify(err, vim.log.levels.ERROR)
end
end, { desc = "Location List" })
-- quickfix list
map("n", "<leader>xq", function()
local success, err = pcall(vim.fn.getqflist({ winid = 0 }).winid ~= 0 and vim.cmd.cclose or vim.cmd.copen)
if not success and err then
vim.notify(err, vim.log.levels.ERROR)
end
end, { desc = "Quickfix List" })
map("n", "[q", vim.cmd.cprev, { desc = "Previous Quickfix" })
map("n", "]q", vim.cmd.cnext, { desc = "Next Quickfix" })
-- diagnostic
local diagnostic_goto = function(next, severity)
return function()
vim.diagnostic.jump({
count = (next and 1 or -1) * vim.v.count1,
severity = severity and vim.diagnostic.severity[severity] or nil,
float = true,
})
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" })
-- quit
map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit All" })
-- windows
map("n", "<C-h>", "<C-w>h", { desc = "Move to left window" })
map("n", "<C-j>", "<C-w>j", { desc = "Move to below window" })
map("n", "<C-k>", "<C-w>k", { desc = "Move to above window" })
map("n", "<C-l>", "<C-w>l", { desc = "Move to right window" })
map("n", "<leader>-", "<C-W>s", { desc = "Split Window Below", remap = true })
map("n", "<leader>|", "<C-W>v", { desc = "Split Window Right", remap = true })
map("n", "<leader>wd", "<C-W>c", { desc = "Delete Window", remap = true })
-- tabs
-- map("n", "<leader><tab>l", "<cmd>tablast<cr>", { desc = "Last Tab" })
-- map("n", "<leader><tab>o", "<cmd>tabonly<cr>", { desc = "Close Other Tabs" })
-- 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" })
-- LSP (when attached)
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("LspKepmap", {}),
callback = function(ev)
-- Use buffer-local keymaps
local opts = function(desc)
return { buffer = ev.buf, desc = desc }
end
-- LSP keymaps
map("n", "K", vim.lsp.buf.hover, opts("LSP Hover"))
map("n", "gd", vim.lsp.buf.definition, opts("Goto Definition"))
map("n", "gD", vim.lsp.buf.declaration, opts("Goto Declaration"))
map("n", "gr", vim.lsp.buf.references, opts("List References"))
map("n", "gi", vim.lsp.buf.implementation, opts("Goto Implementation"))
map("n", "gt", vim.lsp.buf.type_definition, opts("Type Definition"))
map("n", "<leader>cr", vim.lsp.buf.rename, opts("Rename Symbol"))
map({ "n", "x" }, "<leader>ca", vim.lsp.buf.code_action, opts("Code Action"))
map("i", "<C-k>", vim.lsp.buf.signature_help, opts("Signature Help"))
end,
})
map("n", "<leader><space>", "<cmd>Telescope find_files<cr>", { desc = "Find files" })
map("n", "<leader>/", "<cmd>Telescope live_grep<cr>", { desc = "Grep in files" })
map("n", "<leader>,", "<cmd>Telescope buffers sort_mru=true sort_lastused=true ignore_current_buffer=true<cr>",
{ desc = "Switch buffers" })
map("n", "<leader>:", "<cmd>Telescope command_history<cr>", { desc = "Command History" })
require("bufferline").setup({
options = {
close_command = function(bufnr)
vim.cmd("bdelete " .. bufnr)
end,
right_mouse_command = function(bufnr)
vim.cmd("bdelete " .. bufnr)
end,
diagnostics = "nvim_lsp",
always_show_bufferline = true,
diagnostics_indicator = function(_, _, diag)
local icons = {
Error = "",
Warn = "",
Hint = "",
Info = "",
}
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",
},
},
get_element_icon = function(opts)
-- fallback to nvim-web-devicons if available
local ok, devicons = pcall(require, "nvim-web-devicons")
if ok then
local icon, _ = devicons.get_icon_by_filetype(opts.filetype)
return icon
end
return ""
end,
}
}
)
map("n", "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", { desc = "Toggle Pin" })
map("n", "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", { desc = "Delete Non-Pinned Buffers" })
map("n", "<S-h>", "<cmd>BufferLineCyclePrev<cr>", { desc = "Prev Buffer" })
map("n", "<S-l>", "<cmd>BufferLineCycleNext<cr>", { desc = "Next Buffer" })
map("n", "<leader>e", function()
require("neo-tree.command").execute({ toggle = true, dir = vim.uv.cwd() })
end, { desc = "Explorer NeoTree (cwd)" })
@whexy
Copy link
Author

whexy commented Nov 16, 2025

Watch me live coding this config at iPad | Neovim v0.12 原生插件初探.
This gist will be updated every time I do a new video about Neovim config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment