Skip to content

Instantly share code, notes, and snippets.

@hunzo
Last active April 3, 2026 08:32
Show Gist options
  • Select an option

  • Save hunzo/2dffc49bb5f1da798f24fe610ca5ae6d to your computer and use it in GitHub Desktop.

Select an option

Save hunzo/2dffc49bb5f1da798f24fe610ca5ae6d to your computer and use it in GitHub Desktop.
nvim 0.12 v2
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime": {
"version": "LuaJIT"
},
"diagnostics": {
"globals": ["vim"]
},
"workspace": {
"library": ["$VIMRUNTIME/lua", "$VIMRUNTIME/lua/vim/lsp"],
"checkThirdParty": false
}
}
vim.g.mapleader = " "
local opt = vim.opt
local keymap = vim.keymap
-- ============================================================
-- 1. Basic Editor Settings
-- ============================================================
opt.expandtab = true
opt.tabstop = 4
opt.softtabstop = 4
opt.shiftwidth = 4
opt.relativenumber = true
opt.number = true
opt.signcolumn = "yes"
opt.termguicolors = true
opt.wrap = false
opt.winborder = "rounded"
opt.scrolloff = 8
opt.sidescrolloff = 8
opt.cursorline = true
opt.splitright = true
opt.splitbelow = true
opt.undofile = true
opt.ignorecase = true
opt.smartcase = true
opt.clipboard = "unnamedplus"
-- ============================================================
-- 2. Packages
-- ============================================================
vim.pack.add({
-- Colorscheme
{ src = "https://github.com/rose-pine/neovim" },
-- LSP
{ src = "https://github.com/neovim/nvim-lspconfig" },
{ src = "https://github.com/mason-org/mason.nvim" },
{ src = "https://github.com/mason-org/mason-lspconfig.nvim" },
{ src = "https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim" },
{ src = "https://github.com/folke/lazydev.nvim" },
-- Completion & Snippets
{ src = "https://github.com/saghen/blink.cmp" },
{ src = "https://github.com/L3MON4D3/LuaSnip" },
{ src = "https://github.com/rafamadriz/friendly-snippets" },
-- Formatting & Linting
{ src = "https://github.com/stevearc/conform.nvim" },
{ src = "https://github.com/mfussenegger/nvim-lint" },
-- UI & Navigation
{ src = "https://github.com/nvim-mini/mini.nvim" },
{ src = "https://github.com/folke/trouble.nvim" },
{ src = "https://github.com/stevearc/oil.nvim" },
{ src = "https://github.com/akinsho/toggleterm.nvim" },
{ src = "https://github.com/folke/which-key.nvim" },
-- Git
{ src = "https://github.com/lewis6991/gitsigns.nvim" },
-- Treesitter (ดึงมาก่อนแต่ setup ทีหลัง)
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
})
-- ============================================================
-- 3. Safe Setup Helper
-- ============================================================
-- ใช้ pcall ครอบทุก require เพื่อป้องกัน error หยุด config
local function safe_setup(mod, opts)
local ok, plugin = pcall(require, mod)
if not ok then
vim.notify("Plugin not found: " .. mod, vim.log.levels.WARN)
return
end
if opts then
plugin.setup(opts)
end
return plugin
end
-- ============================================================
-- 4. Treesitter (ใช้ vim.schedule เพื่อรอให้ plugin โหลดเสร็จ)
-- ============================================================
vim.schedule(function()
safe_setup("nvim-treesitter.configs", {
ensure_installed = {
"lua",
"python",
"go",
"javascript",
"typescript",
"tsx",
"html",
"css",
"json",
"yaml",
"bash",
"markdown",
"dockerfile",
"hcl",
"sql",
},
auto_install = true,
highlight = { enable = true },
indent = { enable = true },
})
end)
-- ============================================================
-- 5. Mini.nvim
-- ============================================================
safe_setup("mini.pick")
safe_setup("mini.pairs")
safe_setup("mini.surround")
safe_setup("mini.diff")
safe_setup("mini.statusline", {
content = {
active = function()
local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })
local git = MiniStatusline.section_git({ trunc_width = 75 })
local diff = MiniStatusline.section_diff({ trunc_width = 75 })
local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 75 })
local filename = MiniStatusline.section_filename({ trunc_width = 140 })
local fileinfo = MiniStatusline.section_fileinfo({ trunc_width = 120 })
local location = MiniStatusline.section_location({ trunc_width = 75 })
return MiniStatusline.combine_groups({
{ hl = mode_hl, strings = { mode } },
{ hl = "MiniStatuslineDevinfo", strings = { git, diff, diagnostics } },
"%<",
{ hl = "MiniStatuslineFilename", strings = { filename } },
"%=",
{ hl = "MiniStatuslineFileinfo", strings = { fileinfo } },
{ hl = mode_hl, strings = { location } },
})
end,
},
})
-- ============================================================
-- 6. Gitsigns
-- ============================================================
safe_setup("gitsigns", {
signs = {
add = { text = "▎" },
change = { text = "▎" },
delete = { text = "" },
topdelete = { text = "" },
changedelete = { text = "▎" },
},
on_attach = function(bufnr)
local gs = package.loaded.gitsigns
local function map(mode, l, r, desc)
keymap.set(mode, l, r, { buffer = bufnr, desc = desc })
end
map("n", "]h", gs.next_hunk, "Next Hunk")
map("n", "[h", gs.prev_hunk, "Prev Hunk")
map("n", "<leader>hs", gs.stage_hunk, "Stage Hunk")
map("n", "<leader>hr", gs.reset_hunk, "Reset Hunk")
map("v", "<leader>hs", function()
gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") })
end, "Stage Hunk")
map("v", "<leader>hr", function()
gs.reset_hunk({ vim.fn.line("."), vim.fn.line("v") })
end, "Reset Hunk")
map("n", "<leader>hS", gs.stage_buffer, "Stage Buffer")
map("n", "<leader>hu", gs.undo_stage_hunk, "Undo Stage Hunk")
map("n", "<leader>hR", gs.reset_buffer, "Reset Buffer")
map("n", "<leader>hp", gs.preview_hunk, "Preview Hunk")
map("n", "<leader>hb", function()
gs.blame_line({ full = true })
end, "Blame Line")
map("n", "<leader>hd", gs.diffthis, "Diff This")
map("n", "<leader>tb", gs.toggle_current_line_blame, "Toggle Blame")
end,
})
-- ============================================================
-- 7. Blink.cmp
-- ============================================================
safe_setup("blink.cmp", {
keymap = {
preset = "none",
["<C-space>"] = { "show", "show_documentation", "hide_documentation" },
["<C-e>"] = { "hide" },
["<CR>"] = { "accept", "fallback" },
["<C-k>"] = { "select_prev", "fallback" },
["<C-j>"] = { "select_next", "fallback" },
["<C-b>"] = { "scroll_documentation_up", "fallback" },
["<C-f>"] = { "scroll_documentation_down", "fallback" },
},
completion = {
menu = { border = "rounded" },
documentation = {
window = { border = "rounded" },
auto_show = true,
auto_show_delay_ms = 200,
},
list = { selection = { preselect = true, auto_insert = true } },
ghost_text = { enabled = true },
},
snippets = { preset = "luasnip" },
signature = { enabled = true, window = { border = "rounded" } },
sources = {
default = { "lsp", "path", "snippets", "buffer" },
},
})
-- ============================================================
-- 8. LSP
-- ============================================================
safe_setup("lazydev")
safe_setup("mason", { ui = { border = "rounded" } })
local servers = {
"tailwindcss",
"ts_ls",
"gopls",
"pyright",
"emmet_ls",
"html",
"lua_ls",
"yamlls",
"dockerls",
"bashls",
"jsonls",
"cssls",
"ansiblels",
"docker_compose_language_service",
"terraformls",
}
local ok_mlsp, mason_lsp = pcall(require, "mason-lspconfig")
if ok_mlsp then
local capabilities = require("blink.cmp").get_lsp_capabilities()
mason_lsp.setup({
ensure_installed = servers,
handlers = {
-- Default handler
function(server_name)
require("lspconfig")[server_name].setup({
capabilities = capabilities,
})
end,
-- gopls custom
["gopls"] = function()
require("lspconfig").gopls.setup({
capabilities = capabilities,
settings = {
gopls = {
analyses = { unusedparams = true },
staticcheck = true,
gofumpt = true,
},
},
})
end,
-- lua_ls custom
["lua_ls"] = function()
require("lspconfig").lua_ls.setup({
capabilities = capabilities,
settings = {
Lua = {
diagnostics = { globals = { "vim" } },
workspace = { checkThirdParty = false },
telemetry = { enable = false },
},
},
})
end,
},
})
end
safe_setup("mason-tool-installer", {
ensure_installed = {
"prettierd",
"stylua",
"gofumpt",
"golines",
"sqlfmt",
"yamlfmt",
"shfmt",
"goimports-reviser",
"ruff",
"eslint_d",
"djlint",
"golangci-lint",
"ansible-lint",
"hadolint",
},
})
-- LSP Attach Keymaps
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
callback = function(event)
local function map(mode, keys, func, desc)
keymap.set(mode, keys, func, { buffer = event.buf, desc = "LSP: " .. desc })
end
map("n", "gd", vim.lsp.buf.definition, "Go to Definition")
map("n", "gD", vim.lsp.buf.declaration, "Go to Declaration")
map("n", "gr", vim.lsp.buf.references, "References")
map("n", "gi", vim.lsp.buf.implementation, "Go to Implementation")
map("n", "gt", vim.lsp.buf.type_definition, "Type Definition")
map("n", "K", vim.lsp.buf.hover, "Hover Documentation")
map("n", "<C-s>", vim.lsp.buf.signature_help, "Signature Help")
map("i", "<C-s>", vim.lsp.buf.signature_help, "Signature Help")
map("n", "<leader>ca", vim.lsp.buf.code_action, "Code Action")
map("v", "<leader>ca", vim.lsp.buf.code_action, "Code Action")
map("n", "<leader>rn", vim.lsp.buf.rename, "Rename Symbol")
map("n", "<leader>cd", vim.diagnostic.open_float, "Line Diagnostics")
map("n", "]d", function()
vim.diagnostic.jump({ count = 1 })
end, "Next Diagnostic")
map("n", "[d", function()
vim.diagnostic.jump({ count = -1 })
end, "Prev Diagnostic")
map("n", "]e", function()
vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.ERROR })
end, "Next Error")
map("n", "[e", function()
vim.diagnostic.jump({ count = -1, severity = vim.diagnostic.severity.ERROR })
end, "Prev Error")
end,
})
-- Diagnostic Config
vim.diagnostic.config({
severity_sort = true,
float = { border = "rounded", source = true },
signs = {
text = {
[vim.diagnostic.severity.ERROR] = "󰅚 ",
[vim.diagnostic.severity.WARN] = "󰀪 ",
[vim.diagnostic.severity.INFO] = "󰋽 ",
[vim.diagnostic.severity.HINT] = "󰌶 ",
},
},
})
-- ============================================================
-- 9. Formatting & Linting
-- ============================================================
local ok_luasnip = pcall(require, "luasnip")
if ok_luasnip then
require("luasnip.loaders.from_vscode").lazy_load()
end
safe_setup("conform", {
formatters_by_ft = {
javascript = { "prettierd" },
typescript = { "prettierd" },
javascriptreact = { "prettierd" },
typescriptreact = { "prettierd" },
css = { "prettierd" },
json = { "prettierd" },
markdown = { "prettierd" },
yaml = { "yamlfmt" },
lua = { "stylua" },
python = { "ruff_format" },
htmldjango = { "djlint" },
html = { "djlint" },
go = { "gofumpt", "golines", "goimports-reviser" },
sql = { "sqlfmt" },
sh = { "shfmt" },
},
format_on_save = { timeout_ms = 500, lsp_format = "fallback" },
notify_on_error = true,
})
-- Linting
local ok_lint, lint = pcall(require, "lint")
if ok_lint then
lint.linters_by_ft = {
javascript = { "eslint_d" },
typescript = { "eslint_d" },
javascriptreact = { "eslint_d" },
typescriptreact = { "eslint_d" },
python = { "ruff" },
go = { "golangcilint" },
dockerfile = { "hadolint" },
}
vim.api.nvim_create_autocmd({ "BufWritePost", "BufReadPost", "InsertLeave" }, {
callback = function()
lint.try_lint()
end,
})
end
-- ============================================================
-- 10. UI Plugins
-- ============================================================
safe_setup("trouble", {
modes = { diagnostics = { auto_close = true } },
})
safe_setup("toggleterm", {
open_mapping = [[<c-\>]],
direction = "float",
float_opts = { border = "rounded" },
})
safe_setup("oil", {
view_options = { show_hidden = true },
float = { border = "rounded" },
})
safe_setup("which-key")
local ok_wk, wk = pcall(require, "which-key")
if ok_wk then
wk.add({
{ "<leader>f", group = "Find" },
{ "<leader>h", group = "Git Hunks" },
{ "<leader>c", group = "Code" },
{ "<leader>t", group = "Toggle" },
})
end
-- ============================================================
-- 11. Appearance
-- ============================================================
safe_setup("rose-pine", {
styles = { bold = false, italic = true, transparency = false },
})
vim.cmd("colorscheme rose-pine")
-- ============================================================
-- 12. Autocommands
-- ============================================================
-- Indentation per filetype
vim.api.nvim_create_autocmd("FileType", {
pattern = { "html", "javascript", "typescript", "javascriptreact", "typescriptreact", "css", "json", "yaml" },
callback = function()
vim.bo.tabstop = 2
vim.bo.shiftwidth = 2
vim.bo.softtabstop = 2
end,
})
-- Highlight on yank
vim.api.nvim_create_autocmd("TextYankPost", {
callback = function()
vim.highlight.on_yank({ higroup = "IncSearch", timeout = 200 })
end,
})
-- Close with q
vim.api.nvim_create_autocmd("FileType", {
pattern = { "help", "qf", "trouble", "notify" },
callback = function(event)
keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true })
end,
})
-- ============================================================
-- 13. Keymaps
-- ============================================================
local opts = { noremap = true, silent = true }
-- Format
keymap.set({ "n", "v" }, "<leader>fm", function()
require("conform").format({ lsp_fallback = true, async = false, timeout_ms = 500 })
end, { desc = "Format file" })
-- Find
keymap.set("n", "<leader>ff", ":Pick files<CR>", { desc = "Find Files" })
keymap.set("n", "<leader>fg", ":Pick grep_live<CR>", { desc = "Find Grep" })
keymap.set("n", "<leader>fb", ":Pick buffers<CR>", { desc = "Find Buffers" })
keymap.set("n", "<leader>fh", ":Pick help<CR>", { desc = "Find Help" })
keymap.set("n", "<leader>fr", ":Pick oldfiles<CR>", { desc = "Recent Files" })
-- File Explorer
keymap.set("n", "<leader>e", ":Oil<CR>", { desc = "File Explorer" })
keymap.set("n", "-", ":Oil<CR>", { desc = "Open parent directory" })
-- Diagnostics
keymap.set("n", "<leader>d", ":Trouble diagnostics toggle<CR>", { desc = "Toggle Diagnostics" })
keymap.set("n", "<leader>D", ":Trouble diagnostics toggle filter.buf=0<CR>", { desc = "Buffer Diagnostics" })
-- Move lines
keymap.set("v", "J", ":m '>+1<CR>gv=gv", opts)
keymap.set("v", "K", ":m '<-2<CR>gv=gv", opts)
-- Window Navigation
keymap.set("n", "<C-h>", "<C-w>h", opts)
keymap.set("n", "<C-j>", "<C-w>j", opts)
keymap.set("n", "<C-k>", "<C-w>k", opts)
keymap.set("n", "<C-l>", "<C-w>l", opts)
-- Window Resize
keymap.set("n", "<C-Left>", "<C-w><", opts)
keymap.set("n", "<C-Right>", "<C-w>>", opts)
keymap.set("n", "<C-Up>", "<C-w>+", opts)
keymap.set("n", "<C-Down>", "<C-w>-", opts)
-- Tabs
keymap.set("n", "te", ":tabedit<CR>", opts)
keymap.set("n", "<Tab>", ":tabnext<CR>", opts)
keymap.set("n", "<S-Tab>", ":tabprev<CR>", opts)
-- Splits
keymap.set("n", "ss", ":split<CR>", opts)
keymap.set("n", "sv", ":vsplit<CR>", opts)
-- Misc
keymap.set("n", "<leader>n", ":nohlsearch<CR>", opts)
keymap.set("n", "<leader>q", ":q<CR>", opts)
keymap.set("n", "<leader>w", ":w<CR>", opts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment