Last active
April 3, 2026 08:32
-
-
Save hunzo/2dffc49bb5f1da798f24fe610ca5ae6d to your computer and use it in GitHub Desktop.
nvim 0.12 v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "$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 | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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