Optimize init.lua untuk Neovim 0.13: dari 470ms ke 130ms
Neovim sekarang di 0.13 (development). Kalau korang masih guna config lama (0.12 atau sebelumnya), ada beberapa benda 0.13 yang patut diambil kira — dan ada juga bug senyap yang makan masa startup tanpa kita sedar.
Dulu aku guna init.lua yang aku share di dev.to/hardyweb/neovim-012-native-autocomplete-and-native-plugin-manager-for-laravel-and-go
Spec Neovim Nighly
NVIM v0.13.0-dev-1862+g254551ea39
Build type: Debug
LuaJIT 2.1
ini init.lua ready untuk Neovim 0.13
-- =========================================
-- NeoVim 0.13+ Native Pack + LSP Config
-- =========================================
-- Faster Lua module loading (bytecode cache)
vim.loader.enable()
-- Leader must be set before mappings / plugin setup
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Bootstrap plugins (native pack)
vim.pack.add({
{ src = "https://github.com/mason-org/mason.nvim.git" },
{ src = "https://github.com/mason-org/mason-lspconfig.nvim.git" },
{ src = "https://github.com/neovim/nvim-lspconfig.git" },
{ src = "https://github.com/nvim-treesitter/nvim-treesitter.git", build = ":TSUpdate" },
{ src = "https://github.com/hrsh7th/nvim-cmp.git" },
{ src = "https://github.com/hrsh7th/cmp-nvim-lsp.git" },
{ src = "https://github.com/hrsh7th/cmp-buffer.git" },
{ src = "https://github.com/L3MON4D3/LuaSnip.git" },
{ src = "https://github.com/echasnovski/mini.pairs.git" },
{ src = "https://github.com/echasnovski/mini.icons.git" },
{ src = "https://github.com/nvim-lualine/lualine.nvim.git" },
{ src = "https://github.com/ibhagwan/fzf-lua.git" },
{ src = "https://github.com/folke/tokyonight.nvim.git" },
{ src = "https://github.com/akinsho/toggleterm.nvim.git" },
{ src = "https://github.com/wakatime/vim-wakatime.git"},
{ src = "https://github.com/nvim-lua/plenary.nvim" },
})
-- =========================================
-- Mason setup (must run before lsp.enable: adds mason/bin to PATH)
-- =========================================
require("mason").setup()
require("mason-lspconfig").setup({
ensure_installed = { "lua_ls", "html", "intelephense", "ts_ls", "gopls", "pyright" },
})
-- =========================================
-- Autocompletion (nvim-cmp) - lazy on first insert
-- =========================================
local function __setup_cmp()
local cmp = require("cmp")
local luasnip = require("luasnip")
require("luasnip.loaders.from_vscode").lazy_load() -- optional: load VS Code snippets
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
}),
sources = {
{ name = "nvim_lsp" },
{ name = "luasnip" }, -- Added
{ name = "buffer" },
},
experimental = { ghost_text = true },
})
end
vim.api.nvim_create_autocmd("InsertEnter", { once = true, callback = __setup_cmp })
-- =========================================
-- LSP (New Native API)
-- =========================================
local lsp = vim.lsp
local capabilities = require("cmp_nvim_lsp").default_capabilities() -- Now safe to call
local servers = { "lua_ls", "html", "intelephense", "ts_ls", "gopls", "pyright" }
for _, server in ipairs(servers) do
lsp.config(server, {
capabilities = capabilities,
settings = {},
})
lsp.enable(server)
end
-- Optional: enhance lua_ls
lsp.config("lua_ls", {
settings = {
Lua = {
diagnostics = { globals = { "vim" } },
workspace = { checkThirdParty = false },
},
},
})
-- =========================================
-- Treesitter (Syntax Highlight)
-- =========================================
require("nvim-treesitter.configs").setup({
ensure_installed = { "lua", "php", "blade", "html", "javascript", "json", "go" },
highlight = { enable = true },
})
-- =========================================
-- UI & Aesthetic
-- =========================================
vim.cmd.colorscheme("tokyonight")
-- Mock nvim-web-devicons for compatibility
require("mini.icons").setup()
require("mini.icons").mock_nvim_web_devicons()
require("lualine").setup({
options = { theme = "tokyonight" },
})
require("mini.pairs").setup()
require("toggleterm").setup({
size = 15,
open_mapping = [[<c-\>]],
shade_terminals = true,
shading_factor = 2,
direction = "float",
float_opts = { border = "curved", winblend = 0 },
})
-- Helper: Toggle lazygit (if installed)
local Terminal = require("toggleterm.terminal").Terminal
local lazygit = Terminal:new({ cmd = "lazygit", hidden = true, direction = "float" })
function _lazygit_toggle()
lazygit:toggle()
end
-- =========================================
-- Display Settings
-- =========================================
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.signcolumn = "yes"
vim.opt.termguicolors = true
vim.opt.scrolloff = 8
vim.opt.sidescrolloff = 8
-- 0.13: diagnostic current_line virtual text follows CursorHold; keep it snappy
vim.opt.updatetime = 300
-- 0.13: 'autoread' now uses filesystem watchers (real-time external change detect)
vim.opt.autoread = true
-- =========================================
-- Clipboard Integration (WSL - manual yank -> clip.exe, deferred provider)
-- =========================================
if vim.fn.has("wsl") == 1 then
-- Simple manual yank -> clip.exe
vim.api.nvim_create_autocmd("TextYankPost", {
callback = function()
vim.fn.system("clip.exe", vim.fn.getreg('"'))
end,
})
-- Defer clipboard provider to load after UI ready (for speed)
vim.api.nvim_create_autocmd("VimEnter", {
once = true,
callback = function()
vim.defer_fn(function()
vim.opt.clipboard = "unnamedplus"
end, 300) -- delay 300ms after startup
end,
})
end
-- =========================================
-- Diagnostics / Auto Lint + Format
-- =========================================
vim.diagnostic.config({
virtual_text = { prefix = "●" },
signs = true,
underline = true,
update_in_insert = false,
severity_sort = true,
})
-- Auto format before save
local lsp_format_group = vim.api.nvim_create_augroup("LspAutoFormat", { clear = true })
vim.api.nvim_create_autocmd("BufWritePre", {
group = lsp_format_group,
callback = function(event)
local client = vim.lsp.get_clients({ bufnr = event.buf })[1]
if client and client.supports_method("textDocument/formatting") then
vim.lsp.buf.format({ async = false })
end
end,
})
-- =========================================
-- Keymaps
-- =========================================
local keymap = vim.keymap.set
local opts = { noremap = true, silent = true }
-- Q = native multiple cursor (0.13 default). Replay last register moved to <leader>r
keymap("n", "<leader>r", function()
local reg = vim.fn.reg_recorded()
return reg == "" and "" or ("@" .. reg)
end, { expr = true, silent = true, desc = "Replay last recorded register" })
-- FZF
keymap("n", "<leader>ff", function() require("fzf-lua").files() end, opts)
keymap("n", "<leader>fg", function() require("fzf-lua").live_grep() end, opts)
keymap("n", "<leader>fb", function() require("fzf-lua").buffers() end, opts)
keymap("n", "<leader>fh", function() require("fzf-lua").help_tags() end, opts)
-- Format & Diagnostics
keymap("n", "<leader>lf", function() vim.lsp.buf.format({ async = true }) end, opts)
keymap("n", "<leader>ld", vim.diagnostic.open_float, opts)
keymap("n", "<leader>ln", vim.diagnostic.goto_next, opts)
keymap("n", "<leader>lp", vim.diagnostic.goto_prev, opts)
-- Quick actions
keymap("n", "<leader>w", "<cmd>w<CR>", opts)
keymap("n", "<leader>q", "<cmd>q<CR>", opts)
keymap("n", "<leader>ft", "<cmd>ToggleTerm<CR>", opts)
keymap("n", "<leader>fu", "<cmd>lua _lazygit_toggle()<CR>", opts)
keymap("t", "<Esc>", [[<C-\><C-n>]], opts)
-- Buffer navigation
keymap("n", "<leader>bb", "<cmd>bnext<CR>", opts)
keymap("n", "<leader>bp", "<cmd>bprevious<CR>", opts)
keymap("n", "<leader>bd", "<cmd>bd<CR>", opts)
-- =========================================
-- Memory Watcher
-- =========================================
local api = vim.api
local timer = vim.uv.new_timer()
local win, buf
local last = 0
local function create_win()
buf = api.nvim_create_buf(false, true)
local opts = {
relative = "editor",
width = 25,
height = 3,
row = 1,
col = vim.o.columns - 28,
style = "minimal",
border = "rounded",
}
win = api.nvim_open_win(buf, false, opts)
end
local function update_mem()
local current = vim.uv.resident_set_memory() / (1024 * 1024)
local diff = current - last
local sign = diff >= 0 and "+" or "-"
local text = {
string.format("Mem: %.2f MB", current),
string.format("Change: %s%.2f MB", sign, math.abs(diff)),
}
api.nvim_buf_set_lines(buf, 0, -1, false, text)
last = current
end
vim.api.nvim_create_user_command("MemWatch", function()
if win and api.nvim_win_is_valid(win) then
print("Memory watcher already running")
return
end
create_win()
timer:start(0, 2000, vim.schedule_wrap(update_mem))
print("Memory watcher started")
end, {})
vim.api.nvim_create_user_command("MemWatchStop", function()
timer:stop()
timer:close()
if win and api.nvim_win_is_valid(win) then
api.nvim_win_close(win, true)
end
print("Memory watcher stopped")
end, {})
-- Auto-stop memory watcher on exit
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
pcall(vim.cmd.MemWatchStop)
end,
})
-- =========================================
-- Plugin Update Helper
-- =========================================
vim.api.nvim_create_user_command("PackUpdate", function()
print("Updating plugins...")
vim.pack.update()
print("Plugins updated!")
end, { desc = "Update all plugins (vim.pack)" })
keymap("n", "<leader>pu", "<cmd>PackUpdate<CR>", { noremap = true, silent = true })
Ambil perhatian: ini build Debug, jadi angka startup lebih tinggi berbanding release build. Tapi perbandingan before/after tetap sah kerana mesin sama.
Top comments (0)