Last active
May 12, 2026 17:30
-
-
Save limxingzhi/fa3be5045caded9d4e09f2423dbfcec7 to your computer and use it in GitHub Desktop.
My nvim config with lazy, treesitter, telescope, undotree, lspconfig and coc
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
| -- init.lua | |
| -- lines to scroll per page | |
| local page_length = 10 | |
| local page_short_length = 3 | |
| -- configure better defaults | |
| (function() | |
| -- Enable line numbers | |
| vim.o.number = true | |
| -- Set the number of spaces in a tab when editing | |
| vim.o.softtabstop = 2 | |
| -- Set the number of spaces to use for autoindent | |
| vim.o.shiftwidth = 2 | |
| -- Convert tabs to spaces | |
| vim.o.expandtab = true | |
| -- Enable autoindentation | |
| vim.o.autoindent = true | |
| -- Use the system clipboard | |
| vim.o.clipboard = "unnamed" | |
| -- Enable mouse support in all modes | |
| vim.o.mouse = "a" | |
| -- Minimal number of screen lines to keep above and below the cursor. | |
| vim.opt.scrolloff = 3 | |
| -- Set a long timeout for key sequences | |
| vim.opt.timeoutlen = 999999 | |
| -- Ignore case in search patterns | |
| vim.o.ignorecase = true | |
| -- Relative line numbers | |
| vim.wo.relativenumber = true | |
| -- Setting leader key and ex | |
| vim.g.mapleader = " " | |
| -- Set vsplit to open file on right globally | |
| vim.o.splitright = true | |
| -- Set the trailing characters | |
| vim.opt.list = true | |
| vim.opt.listchars = { tab = '>-', trail = '.', lead = '.', } | |
| -- always show gutter | |
| vim.opt.signcolumn = "yes" | |
| -- set update time to 300ms | |
| vim.opt.updatetime = 300 | |
| -- removing octal so increment 07 wouldnt go to 10 | |
| vim.opt.nrformats:remove("octal") | |
| end)(); | |
| -- map cursor movements | |
| (function() | |
| -- Function to map cursor to move x times in y direction | |
| local map_move_cursor = function(length, direction, key) | |
| vim.keymap.set({ 'n', 'v' }, key, function() | |
| vim.cmd('normal! ' .. length .. direction) | |
| end, { noremap = true, silent = true }) | |
| end | |
| -- opening EX with leader key | |
| vim.keymap.set("n", "<leader>ex", vim.cmd.Ex) | |
| -- moving cursor a few positions over | |
| map_move_cursor(page_length, 'h', 'H') | |
| map_move_cursor(page_length, 'l', 'L') | |
| map_move_cursor(page_length, 'j', 'J') | |
| map_move_cursor(page_length, 'k', 'K') | |
| map_move_cursor(page_short_length, 'h', '<M-h>') | |
| map_move_cursor(page_short_length, 'l', '<M-l>') | |
| map_move_cursor(page_short_length, 'j', '<M-j>') | |
| map_move_cursor(page_short_length, 'k', '<M-k>') | |
| end)(); | |
| -- map window movement keys | |
| (function() | |
| -- Function to remap <c-w><key> to <leader>w<key> | |
| local remap_ldr_move = function(key, other_commands) | |
| vim.keymap.set({ 'n', 'v' }, '<leader>w' .. key, '<cmd>wincmd ' .. key .. '<CR>' .. other_commands, | |
| { noremap = true, silent = true }) | |
| end | |
| remap_ldr_move('h', '') | |
| remap_ldr_move('j', '') | |
| remap_ldr_move('k', '') | |
| remap_ldr_move('l', '') | |
| remap_ldr_move('w', '') -- move to the next window | |
| remap_ldr_move('=', '') -- Readjust panels evenly | |
| remap_ldr_move('r', '') -- Rotate opened windows with <leader>wr | |
| -- Split window vertically with <leader>wv | |
| vim.keymap.set('n', '<leader>wv', '<cmd>split<CR>', { noremap = true, silent = true }) | |
| -- Split window horizontally with <leader>ws | |
| vim.keymap.set('n', '<leader>ws', '<cmd>vsplit<CR>', { noremap = true, silent = true }) | |
| -- Close current window with <leader>wc | |
| vim.keymap.set('n', '<leader>wc', '<cmd>close<CR>', { noremap = true, silent = true }) | |
| end)(); | |
| -- custom scroll bindings | |
| (function() | |
| -- Set scroll to only x lines | |
| vim.api.nvim_set_keymap('n', '<C-d>', page_length .. 'j' .. page_length .. '<C-e>', | |
| { noremap = true, silent = true }) | |
| vim.api.nvim_set_keymap('n', '<C-u>', page_length .. 'k' .. page_length .. '<C-y>', | |
| { noremap = true, silent = true }) | |
| vim.api.nvim_set_keymap('n', '<M-d>', page_short_length .. 'j' .. page_short_length .. '<C-e>', | |
| { noremap = true, silent = true }) | |
| vim.api.nvim_set_keymap('n', '<M-u>', page_short_length .. 'k' .. page_short_length .. '<C-y>', | |
| { noremap = true, silent = true }) | |
| -- Replace text without yanking (black hole register) | |
| vim.keymap.set('v', '<leader>p', [["_dP]], { noremap = true, silent = true }); | |
| -- set no highlight | |
| vim.keymap.set('n', '<leader>nn', '<cmd>noh<CR>', { noremap = true, silent = true }); | |
| end)(); | |
| -- Set <leader>nt to open new tab functions | |
| vim.keymap.set({ 'n', 'v' }, '<leader>nt', '<cmd>tab split<CR>', { noremap = true, silent = true }) | |
| -- Set formatoptions globally in Neovim | |
| vim.api.nvim_create_autocmd({ "BufEnter", "BufRead", "BufNewFile" }, { | |
| pattern = "*", | |
| callback = function() | |
| -- Remove 'r' and 'o' from formatoptions for all file types | |
| vim.opt.formatoptions:remove("r") | |
| vim.opt.formatoptions:remove("o") | |
| end, | |
| }) | |
| -- Adds an event listener that highlights the just yanked text | |
| vim.api.nvim_create_autocmd('TextYankPost', { | |
| desc = 'Highlight when yanking text', | |
| group = vim.api.nvim_create_augroup('xz-highlight-yank', { clear = true }), | |
| callback = function() | |
| vim.highlight.on_yank() | |
| end, | |
| }) | |
| ---- # Plugins ---- | |
| -- Configure lazy | |
| local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" | |
| if not vim.loop.fs_stat(lazypath) then | |
| vim.fn.system({ | |
| "git", | |
| "clone", | |
| "--filter=blob:none", | |
| "https://github.com/folke/lazy.nvim.git", | |
| "--branch=stable", -- latest stable release | |
| lazypath, | |
| }) | |
| end | |
| vim.opt.rtp:prepend(lazypath) | |
| require("lazy").setup({ | |
| -- Install gruvbox theme | |
| { | |
| "ellisonleao/gruvbox.nvim", | |
| priority = 1000, | |
| config = function() | |
| require("gruvbox").setup({ | |
| dim_inactive = false, | |
| bold = false, | |
| transparent_mode = false, | |
| contrast = "", -- hard or soft or empty string | |
| }) | |
| vim.o.background = "dark" -- or "light" for light mode | |
| vim.cmd([[colorscheme gruvbox]]) | |
| -- for ghostty transparency | |
| vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) | |
| vim.api.nvim_set_hl(0, "NormalNC", { bg = "none" }) | |
| end | |
| }, | |
| -- endof : Install gruvbox theme | |
| -- Install catppuccino theme | |
| { | |
| "catppuccin/nvim", | |
| name = "catppuccin", | |
| priority = 1000, | |
| config = function() | |
| -- -- catppuccin-latte, catppuccin-frappe, catppuccin-macchiato, catppuccin-mocha | |
| -- vim.o.background = "dark" -- or "light" for light mode | |
| -- vim.cmd.colorscheme "catppuccin-mocha" | |
| -- -- for ghostty transparency | |
| -- vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) | |
| -- vim.api.nvim_set_hl(0, "NormalNC", { bg = "none" }) | |
| end | |
| }, | |
| -- endof : Install catppuccino theme | |
| -- Install Telescope | |
| { | |
| 'nvim-telescope/telescope-ui-select.nvim', | |
| }, | |
| { | |
| 'nvim-telescope/telescope.nvim', | |
| tag = 'v0.2.0', | |
| dependencies = { 'nvim-lua/plenary.nvim' }, | |
| config = function() | |
| local builtin = require('telescope.builtin') | |
| -- local actions = require('telescope.actions') | |
| -- load extension into telescope | |
| require('telescope').load_extension("ui-select") | |
| require('telescope').setup({ | |
| defaults = { | |
| layout_strategy = "horizontal", | |
| }, | |
| pickers = { | |
| find_files = { | |
| find_command = { 'rg', '--files', '--hidden', '-g', '!.git' }, | |
| }, | |
| }, | |
| extensions = { | |
| ["ui-select"] = { | |
| require("telescope.themes").get_dropdown {} | |
| } | |
| } | |
| }) | |
| -- find files in project | |
| vim.keymap.set('n', '<leader>ff', builtin.find_files, {}) | |
| -- find files in buffers | |
| vim.keymap.set('n', '<leader><space>', builtin.buffers, {}) | |
| -- find help | |
| vim.keymap.set('n', '<leader>fh', builtin.help_tags, {}) | |
| -- find register | |
| vim.keymap.set('n', '<leader>fr', builtin.registers, {}) | |
| -- find marks | |
| vim.keymap.set('n', '<leader>fm', builtin.marks, {}) | |
| -- live grep : note, install ripgrep in the system first | |
| vim.keymap.set('n', '<leader>fg', builtin.live_grep, { | |
| vimgrep_arguments = table.insert( | |
| require('telescope.config').values.vimgrep_arguments, | |
| '--fixed-strings' | |
| ), | |
| }) | |
| -- fuzzy find in current buffer | |
| vim.keymap.set('n', '<leader>fz', builtin.current_buffer_fuzzy_find, {}) | |
| end | |
| }, | |
| -- endof : Install Telescope | |
| -- Install Telescope fuzzy finder | |
| { | |
| 'nvim-telescope/telescope-fzf-native.nvim', | |
| build = 'make', | |
| config = function() | |
| -- load extension into telescope | |
| require('telescope').load_extension('fzf') | |
| end | |
| }, | |
| -- endof : Install Telescope fuzzy finder | |
| -- Install Undotree | |
| { | |
| 'mbbill/undotree', | |
| config = function() | |
| vim.keymap.set('n', '<leader>u', vim.cmd.UndotreeToggle) | |
| end | |
| }, | |
| -- endof : Install Undotree | |
| -- Install LSP | |
| { | |
| { | |
| "williamboman/mason.nvim", | |
| config = function() | |
| require("mason").setup() | |
| end | |
| }, | |
| { | |
| "williamboman/mason-lspconfig.nvim", | |
| config = function() | |
| require("mason-lspconfig").setup({ | |
| ensure_installed = { | |
| "lua_ls", | |
| "ts_ls", | |
| "cssls", | |
| -- "prettier", | |
| "eslint@4.8.0", | |
| "denols", | |
| }, | |
| automatic_installation = true | |
| }) | |
| end | |
| }, | |
| { | |
| "neovim/nvim-lspconfig", | |
| config = function() | |
| -- Define LSP server configurations using the new API | |
| vim.lsp.config['lua_ls'] = { | |
| cmd = { 'lua-language-server' }, | |
| filetypes = { 'lua' }, | |
| root_markers = { '.luarc.json', '.git' }, | |
| settings = { Lua = { diagnostics = { globals = { "vim" } } } } | |
| } | |
| vim.lsp.config["ts_ls"] = { | |
| cmd = { "typescript-language-server", "--stdio" }, | |
| filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact" }, | |
| root_dir = vim.fs.root(0, { "package.json" }), | |
| single_file_support = false, | |
| } | |
| vim.lsp.config["denols"] = { | |
| cmd = { "deno", "lsp" }, | |
| filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact" }, | |
| root_dir = vim.fs.root(0, { "deno.json", "deno.jsonc" }), | |
| } | |
| vim.lsp.config["cssls"] = { | |
| cmd = { "vscode-css-language-server", "--stdio" }, | |
| filetypes = { "css", "scss", "less" }, | |
| root_dir = vim.fs.root(0, { "package.json", ".git" }), | |
| } | |
| vim.lsp.config["gopls"] = { | |
| cmd = { "gopls" }, | |
| filetypes = { "go", "gomod", "gowork", "gotmpl" }, | |
| root_dir = vim.fs.root(0, { "go.work", "go.mod", ".git" }), | |
| } | |
| vim.lsp.config["pylsp"] = { | |
| cmd = { "pylsp" }, | |
| filetypes = { "python" }, | |
| root_dir = vim.fs.root(0, { "pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", ".git" }), | |
| } | |
| vim.lsp.config["terraformls"] = { | |
| cmd = { "terraform-ls", "serve" }, | |
| filetypes = { "terraform", "tf", "terraform-vars" }, | |
| root_dir = vim.fs.root(0, { ".terraform", ".git" }), | |
| } | |
| -- Start each LSP automatically for matching filetypes | |
| for name, config in pairs(vim.lsp.config) do | |
| if config.filetypes then | |
| vim.api.nvim_create_autocmd("FileType", { | |
| pattern = config.filetypes, | |
| callback = function(ev) | |
| vim.lsp.enable(name) | |
| end, | |
| }) | |
| end | |
| end | |
| -- Global diagnostics keymaps | |
| vim.keymap.set('n', '<leader>ee', vim.diagnostic.open_float) | |
| vim.keymap.set('n', '[d', vim.diagnostic.goto_prev) | |
| vim.keymap.set('n', ']d', vim.diagnostic.goto_next) | |
| vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist) | |
| -- Buffer-local LSP mappings (on attach) | |
| vim.api.nvim_create_autocmd('LspAttach', { | |
| group = vim.api.nvim_create_augroup('UserLspConfig', {}), | |
| callback = function(ev) | |
| vim.bo[ev.buf].omnifunc = 'v:lua.vim.lsp.omnifunc' | |
| local opts = { buffer = ev.buf, silent = true } | |
| vim.keymap.set('n', 'gk', vim.lsp.buf.hover, opts) | |
| vim.keymap.set('n', 'gd', require('telescope.builtin').lsp_definitions, opts) | |
| vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts) | |
| vim.keymap.set('n', '<leader>wa', vim.lsp.buf.add_workspace_folder, opts) | |
| vim.keymap.set('n', '<leader>D', require('telescope.builtin').lsp_type_definitions, opts) | |
| vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts) | |
| vim.keymap.set({ 'n', 'v' }, '<leader>ca', vim.lsp.buf.code_action, opts) | |
| vim.keymap.set('n', '<leader>gr', require('telescope.builtin').lsp_references, opts) | |
| vim.keymap.set('n', '<leader>wg', ':belowright split<CR>:lua vim.lsp.buf.definition()<CR>', opts) | |
| vim.keymap.set('n', 'gi', require('telescope.builtin').lsp_references, opts) | |
| end, | |
| }) | |
| end | |
| } | |
| }, | |
| -- endof : Install LSP | |
| -- Install lint | |
| { | |
| "mfussenegger/nvim-lint", | |
| config = function() | |
| require("lint").linters_by_ft = { | |
| typescript = { "eslint" }, | |
| typescriptreact = { "eslint" }, | |
| } | |
| vim.keymap.set({ "n", "v" }, "<leader>ll", function() | |
| require("lint").try_lint() | |
| end) | |
| vim.api.nvim_create_autocmd({ "BufWritePost", "InsertEnter", "InsertLeave" }, { | |
| callback = function() | |
| require("lint").try_lint() | |
| end, | |
| }) | |
| end, | |
| }, | |
| -- endof : Install lint | |
| -- Install formatting | |
| { | |
| "stevearc/conform.nvim", | |
| config = function() | |
| local conform = require("conform") | |
| conform.setup({ | |
| formatters_by_ft = { | |
| lua = { "Stylua" }, | |
| javascript = { "prettier" }, | |
| typescript = { "prettier" }, | |
| javascriptreact = { "prettier" }, | |
| typescriptreact = { "prettier" }, | |
| } | |
| }) | |
| vim.keymap.set({ "n", "v" }, "=", function() | |
| conform.format({ | |
| lsp_fallback = true, | |
| async = false, | |
| timeout_ms = 2500 | |
| }) | |
| end) | |
| end, | |
| }, | |
| -- endof : Install formatting | |
| -- Install completion | |
| { | |
| 'nvim-mini/mini.completion', | |
| version = '*', | |
| config = function() | |
| require('mini.completion').setup() | |
| end | |
| }, | |
| -- endof : Install completion | |
| -- Install line indentation | |
| { | |
| "lukas-reineke/indent-blankline.nvim", | |
| main = "ibl", | |
| config = function() | |
| require("ibl").setup() | |
| end | |
| }, | |
| -- endof : Install line indentation | |
| -- Install gitsigns | |
| { | |
| 'lewis6991/gitsigns.nvim', | |
| config = function() | |
| require("gitsigns").setup({ | |
| current_line_blame_opts = { | |
| virt_text_pos = 'overlay', | |
| delay = 200, | |
| }, | |
| signs = { | |
| add = { text = '+' }, | |
| change = { text = '~' }, | |
| delete = { text = '_' }, | |
| topdelete = { text = '?' }, | |
| changedelete = { text = '~' }, | |
| }, | |
| }) | |
| vim.keymap.set({ "v", "n" }, "<leader>gb", function() | |
| vim.cmd("Gitsigns toggle_current_line_blame") | |
| end) | |
| end, | |
| }, | |
| -- endof : Install gitsigns | |
| -- Install : neo tree | |
| { | |
| "nvim-neo-tree/neo-tree.nvim", | |
| branch = "v3.x", | |
| dependencies = { | |
| "nvim-lua/plenary.nvim", | |
| "MunifTanjim/nui.nvim", | |
| }, | |
| config = function() | |
| local opts = { silent = true, noremap = true } | |
| -- open and focus into tree | |
| vim.keymap.set({ "n", "v" }, "<leader>to", function() | |
| vim.cmd("Neotree source=filesystem action=focus position=float reveal=true") | |
| end, opts) | |
| -- close the tree | |
| vim.keymap.set({ "n", "v" }, "<leader>tc", function() | |
| vim.cmd("Neotree action=close") | |
| end, opts) | |
| -- open tree on the right and do not focus | |
| vim.keymap.set({ "n", "v" }, "<leader>tp", function() | |
| vim.cmd("Neotree source=filesystem action=show position=right reveal=true") | |
| end, opts) | |
| -- show git status in tree layout | |
| vim.keymap.set({ "n", "v" }, "<leader>tg", function() | |
| vim.cmd("Neotree source=git_status action=focus position=float reveal=true") | |
| end, opts) | |
| -- show buffers in tree layout | |
| vim.keymap.set({ "n", "v" }, "<leader>tb", function() | |
| vim.cmd("Neotree source=buffers action=focus position=float reveal=true") | |
| end, opts) | |
| -- setting up defaults | |
| require("neo-tree").setup({ | |
| sort_case_insensitive = true, | |
| filesystem = { | |
| filtered_items = { | |
| visible = false, -- when true, they will just be displayed differently than normal items | |
| hide_dotfiles = false, | |
| hide_gitignored = true, | |
| }, | |
| }, | |
| }) | |
| end | |
| }, | |
| -- endof : Install : neo tree | |
| -- Install toychest session helper | |
| { | |
| "limxingzhi/toychest.nvim", | |
| config = function() require("toychest").setup() end | |
| }, | |
| -- endof : Install toychest session helper | |
| -- Install text object helper | |
| { | |
| 'nvim-mini/mini.ai', | |
| version = '*', | |
| config = function() | |
| require('mini.ai').setup({}) | |
| end | |
| }, | |
| -- endof : Install text object helper | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment