From 5672967635cc38ad242d20904c3a802b406470c3 Mon Sep 17 00:00:00 2001 From: Tomas Mirchev Date: Thu, 28 May 2026 07:38:39 +0300 Subject: [PATCH] Migrate Neovim config to 0.12 --- README.md | 6 ++-- init.lua | 4 +++ lua/core/events.lua | 55 ++++++++++++++++++++++++-------- lua/core/keymaps.lua | 14 ++++++-- lua/core/options.lua | 6 +++- lua/modules/language-specs.lua | 2 +- lua/plugins/filetree.lua | 2 +- lua/plugins/finder.lua | 2 +- lua/plugins/language-manager.lua | 39 ++++++++++++++++++---- lua/setup/packages.lua | 2 +- paq-lock.json | 2 +- 11 files changed, 103 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index a614e9a..8608084 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ 1. List/update plugins in `lua/setup/packages.lua`. 2. List/update language specs in `lua/modules/language-specs.lua`. -3. Run `nvim --headless +Setup +qa`. -4. Run `nvim --headless +FetchLspConfigs +qa`. +3. Install `tree-sitter` CLI 0.26.1+ with the system package manager. +4. Run `nvim --headless +Setup +qa`. +5. Run `nvim --headless +FetchLspConfigs +qa`. If `prettierd` is stuck, run `pkill prettierd` and re-run install commands. @@ -28,6 +29,7 @@ If `prettierd` is stuck, run `pkill prettierd` and re-run install commands. - `:InstallLanguages` (included in `:Setup`) - installs language tooling from language specs (treesitter + Mason tools) + - requires `tree-sitter` CLI for `nvim-treesitter` parser builds - `:FetchLspConfigs` (manually executed after modifying language-specs) - fetches default `nvim-lspconfig` server config files diff --git a/init.lua b/init.lua index 1225357..d1c3b2f 100644 --- a/init.lua +++ b/init.lua @@ -1,3 +1,7 @@ +if vim.fn.has('nvim-0.12') == 0 then + error('This config requires Neovim 0.12 or newer') +end + if #vim.api.nvim_list_uis() == 0 then require('setup') return diff --git a/lua/core/events.lua b/lua/core/events.lua index efd4274..9053894 100644 --- a/lua/core/events.lua +++ b/lua/core/events.lua @@ -92,7 +92,7 @@ au('VimEnter', { au('TextYankPost', { group = group, callback = function() - vim.highlight.on_yank({ timeout = 200 }) + vim.hl.on_yank({ timeout = 200 }) end, }) @@ -131,6 +131,43 @@ au({ 'WinLeave', 'InsertEnter' }, { }) -- Autocompletion +local function convert_completion_item(item) + local converted = {} + + if item.kind then + local kind = vim.lsp.protocol.CompletionItemKind[item.kind] or '' + converted.menu = '[' .. kind .. ']' + end + + local _, col = unpack(vim.api.nvim_win_get_cursor(0)) + local next_char = vim.api.nvim_get_current_line():sub(col + 1, col + 1) + if next_char ~= '"' and next_char ~= "'" then + return converted + end + + local completion_text + if item.textEdit then + completion_text = item.textEdit.newText + elseif item.insertText and item.insertText ~= '' then + completion_text = item.insertText + else + completion_text = item.label + end + + if completion_text and completion_text:sub(-1) == next_char then + local trimmed = completion_text:sub(1, -2) + converted.word = trimmed + + if item.textEdit and item.textEdit.newText == completion_text then + item.textEdit.newText = trimmed + elseif item.insertText == completion_text then + item.insertText = trimmed + end + end + + return converted +end + au('LspAttach', { group = group, callback = function(event) @@ -141,22 +178,12 @@ au('LspAttach', { -- Enable native completion if client:supports_method('textDocument/completion') then - vim.lsp.completion.enable(true, client.id, event.buf, { autotrigger = true }) + vim.lsp.completion.enable(true, client.id, event.buf, { + convert = convert_completion_item, + }) end end, }) -vim.lsp.handlers['textDocument/completion'] = function(err, result, ctx, config) - if err or not result then - return - end - for _, item in ipairs(result.items or result) do - if item.kind then - local kind = vim.lsp.protocol.CompletionItemKind[item.kind] or '' - item.menu = '[' .. kind .. ']' - end - end - return vim.lsp.completion._on_completion_result(err, result, ctx, config) -end au('InsertEnter', { group = group, diff --git a/lua/core/keymaps.lua b/lua/core/keymaps.lua index ea373fb..4f78584 100644 --- a/lua/core/keymaps.lua +++ b/lua/core/keymaps.lua @@ -84,10 +84,20 @@ map('n', 'E', cmd('NvimTreeOpen')) -- Diagnostics map('n', ']d', function() - vim.diagnostic.jump({ count = 1, float = true }) + vim.diagnostic.jump({ + count = 1, + on_jump = function() + vim.diagnostic.open_float() + end, + }) end) map('n', '[d', function() - vim.diagnostic.jump({ count = -1, float = true }) + vim.diagnostic.jump({ + count = -1, + on_jump = function() + vim.diagnostic.open_float() + end, + }) end) map('n', 'q', vim.diagnostic.setloclist) map('n', 'd', vim.diagnostic.open_float) diff --git a/lua/core/options.lua b/lua/core/options.lua index a10a4d8..7e3a6b1 100644 --- a/lua/core/options.lua +++ b/lua/core/options.lua @@ -86,7 +86,11 @@ vim.opt.hlsearch = true -- Highlight all matches after searching vim.opt.shortmess:remove('S') -- Show search count, e.g. [3/17] vim.opt.inccommand = 'split' -- Preview substitutions live in a split -vim.opt.completeopt = { 'fuzzy', 'menuone', 'popup', 'noselect' } +vim.opt.autocomplete = true +vim.opt.autocompletedelay = 60 +vim.opt.autocompletetimeout = 120 +vim.opt.complete = { 'o' } +vim.opt.completeopt = { 'menuone', 'popup', 'noselect', 'noinsert' } -- Splits vim.opt.splitright = true diff --git a/lua/modules/language-specs.lua b/lua/modules/language-specs.lua index fc62e57..6a538d0 100644 --- a/lua/modules/language-specs.lua +++ b/lua/modules/language-specs.lua @@ -39,7 +39,7 @@ function M.get() { ft = 'markdown', ts = { 'markdown', 'markdown_inline' }, format = 'prettier' }, { ft = 'bash', lsp = 'bash-language-server', lint = 'shellcheck', format = 'shfmt' }, { ft = 'lua', lsp = 'lua-language-server', lint = 'luacheck', format = 'stylua' }, - { ft = { 'json', 'jsonc' }, lsp = 'biome', format = 'biome' }, + { ft = { 'json', 'jsonc' }, ts = 'json', lsp = 'biome', format = 'biome' }, { ft = 'html', lsp = 'html-lsp' }, { ft = 'css', lsp = { 'css-lsp', 'tailwindcss-language-server' } }, { diff --git a/lua/plugins/filetree.lua b/lua/plugins/filetree.lua index 02279f0..54e630d 100644 --- a/lua/plugins/filetree.lua +++ b/lua/plugins/filetree.lua @@ -1,6 +1,6 @@ local function my_on_attach(bufnr) local api = require('nvim-tree.api') - local opts = { buffer = bufnr } + local opts = { buf = bufnr } -- basics: copy/cut/paste/create/rename/remove vim.keymap.set('n', 'c', api.fs.copy.node, opts) diff --git a/lua/plugins/finder.lua b/lua/plugins/finder.lua index 0cfbf1d..0995f65 100644 --- a/lua/plugins/finder.lua +++ b/lua/plugins/finder.lua @@ -877,7 +877,7 @@ end -- Input handlers --------------------------------------------------------------------- local function attach_handlers() - local opts = { buffer = S.buf_inp, nowait = true, silent = true, noremap = true } + local opts = { buf = S.buf_inp, nowait = true, silent = true, noremap = true } vim.keymap.set('i', '', move_down, opts) vim.keymap.set('i', '', move_up, opts) diff --git a/lua/plugins/language-manager.lua b/lua/plugins/language-manager.lua index 2b65136..9c24d36 100644 --- a/lua/plugins/language-manager.lua +++ b/lua/plugins/language-manager.lua @@ -9,6 +9,7 @@ local M = { M.group = vim.api.nvim_create_augroup('language-manager', { clear = true }) local cache_path = vim.fn.stdpath('cache') .. '/language-manager.json' +local cache_version = 2 local function wrap(item) if type(item) == 'string' then @@ -162,6 +163,14 @@ function M.generate_specs(specs_raw) spec.ts = spec.ts or spec.ft specs.add(spec.ts, 'ts_parsers') + local tree_sitter_filetypes = wrap(spec.ft) + if #tree_sitter_filetypes == 0 then + tree_sitter_filetypes = wrap(spec.ts) + end + for _, ft in ipairs(tree_sitter_filetypes) do + specs.add(spec.ts, 'ts_parsers_by_ft', ft) + end + install_spec.add(spec.lsp, 'code_tools') local resolved_lsps = {} for _, language_server in ipairs(wrap(spec.lsp)) do @@ -209,11 +218,11 @@ function M.load_specs() local specs_raw = require('modules.language-specs').get() local hash = hash_spec(specs_raw) local cache = load_cache() - if cache and cache.hash == hash then + if cache and cache.version == cache_version and cache.hash == hash then M.general = cache.spec else M.general, M.mason = M.generate_specs(specs_raw) - save_cache({ hash = hash, spec = M.general }) + save_cache({ version = cache_version, hash = hash, spec = M.general }) end return M.general, M.mason end @@ -231,8 +240,13 @@ end function M.ts.install() vim.cmd.packadd('nvim-treesitter') - local ts_install = require('nvim-treesitter.install').ensure_installed_sync - ts_install(M.general.ts_parsers) + if vim.fn.executable('tree-sitter') == 0 then + error('tree-sitter CLI 0.26.1+ is required to install nvim-treesitter parsers') + end + require('nvim-treesitter').setup({ + install_dir = vim.fn.stdpath('data') .. '/site', + }) + require('nvim-treesitter').install(M.general.ts_parsers):wait(5 * 60 * 1000) end function M.mason_install() @@ -287,9 +301,20 @@ function M.install() end function M.ts.setup() - require('nvim-treesitter.configs').setup({ - highlight = { enable = true }, - incremental_selection = { enable = true }, + require('nvim-treesitter').setup({ + install_dir = vim.fn.stdpath('data') .. '/site', + }) + + vim.api.nvim_create_autocmd('FileType', { + group = M.group, + callback = function(args) + local parsers = M.general + and M.general.ts_parsers_by_ft + and M.general.ts_parsers_by_ft[vim.bo[args.buf].filetype] + if parsers and #parsers > 0 then + vim.treesitter.start(args.buf) + end + end, }) end diff --git a/lua/setup/packages.lua b/lua/setup/packages.lua index f75d828..6a2c2dc 100644 --- a/lua/setup/packages.lua +++ b/lua/setup/packages.lua @@ -11,7 +11,7 @@ function M.get() { 'https://github.com/windwp/nvim-ts-autotag' }, { 'https://github.com/windwp/nvim-autopairs' }, - { 'https://github.com/nvim-treesitter/nvim-treesitter', version = 'master' }, + { 'https://github.com/nvim-treesitter/nvim-treesitter', version = 'main' }, { 'https://github.com/mfussenegger/nvim-lint' }, { 'https://github.com/stevearc/conform.nvim' }, diff --git a/paq-lock.json b/paq-lock.json index 79696b2..35a7041 100644 --- a/paq-lock.json +++ b/paq-lock.json @@ -1 +1 @@ -{"conform.nvim":{"status":0,"hash":"619363c30309d29ffa631e67c8183f2a72caa373","name":"conform.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/conform.nvim","url":"https://github.com/stevearc/conform.nvim"},"nvim-autopairs":{"status":0,"hash":"7b9923abad60b903ece7c52940e1321d39eccc79","name":"nvim-autopairs","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-autopairs","url":"https://github.com/windwp/nvim-autopairs"},"mason.nvim":{"status":0,"hash":"bb639d4bf385a4d89f478b83af4d770be05ab7eb","name":"mason.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/mason.nvim","url":"https://github.com/mason-org/mason.nvim"},"vim-fugitive":{"status":0,"hash":"3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0","name":"vim-fugitive","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/vim-fugitive","url":"https://github.com/tpope/vim-fugitive"},"invero.nvim":{"status":2,"hash":"193065f32af9659a8500c0c093c373cdcac1969a","name":"invero.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/invero.nvim","url":"https://github.com/triimd/invero.nvim"},"nvim-ts-autotag":{"status":0,"hash":"88c1453db4ba7dd24131086fe51fdf74e587d275","name":"nvim-ts-autotag","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-ts-autotag","url":"https://github.com/windwp/nvim-ts-autotag"},"nvim-lint":{"status":0,"hash":"d48f3a76189d03b2239f6df1b2f7e3fa8353743b","name":"nvim-lint","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-lint","url":"https://github.com/mfussenegger/nvim-lint"},"paq-nvim":{"status":0,"hash":"971344d1fe1fd93580961815e7b7c8853c3605e4","name":"paq-nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/paq-nvim","url":"https://github.com/savq/paq-nvim.git"},"nvim-tree.lua":{"status":0,"hash":"7c0f7e906ab6f11b61eec52171eaf7dc06726ef1","name":"nvim-tree.lua","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-tree.lua","url":"https://gitea.tomastm.com/tomas.mirchev/nvim-tree.lua"},"nvim-treesitter":{"status":0,"hash":"cf12346a3414fa1b06af75c79faebe7f76df080a","name":"nvim-treesitter","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-treesitter","url":"https://github.com/nvim-treesitter/nvim-treesitter"}} \ No newline at end of file +{"conform.nvim":{"status":0,"hash":"619363c30309d29ffa631e67c8183f2a72caa373","name":"conform.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/conform.nvim","url":"https://github.com/stevearc/conform.nvim"},"nvim-autopairs":{"status":0,"hash":"7b9923abad60b903ece7c52940e1321d39eccc79","name":"nvim-autopairs","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-autopairs","url":"https://github.com/windwp/nvim-autopairs"},"mason.nvim":{"status":0,"hash":"bb639d4bf385a4d89f478b83af4d770be05ab7eb","name":"mason.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/mason.nvim","url":"https://github.com/mason-org/mason.nvim"},"vim-fugitive":{"status":0,"hash":"3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0","name":"vim-fugitive","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/vim-fugitive","url":"https://github.com/tpope/vim-fugitive"},"invero.nvim":{"status":2,"hash":"193065f32af9659a8500c0c093c373cdcac1969a","name":"invero.nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/invero.nvim","url":"https://github.com/triimd/invero.nvim"},"nvim-ts-autotag":{"status":0,"hash":"88c1453db4ba7dd24131086fe51fdf74e587d275","name":"nvim-ts-autotag","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-ts-autotag","url":"https://github.com/windwp/nvim-ts-autotag"},"nvim-lint":{"status":0,"hash":"d48f3a76189d03b2239f6df1b2f7e3fa8353743b","name":"nvim-lint","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-lint","url":"https://github.com/mfussenegger/nvim-lint"},"paq-nvim":{"status":0,"hash":"971344d1fe1fd93580961815e7b7c8853c3605e4","name":"paq-nvim","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/paq-nvim","url":"https://github.com/savq/paq-nvim.git"},"nvim-tree.lua":{"status":0,"hash":"7c0f7e906ab6f11b61eec52171eaf7dc06726ef1","name":"nvim-tree.lua","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-tree.lua","url":"https://gitea.tomastm.com/tomas.mirchev/nvim-tree.lua"},"nvim-treesitter":{"status":0,"hash":"4916d6592ede8c07973490d9322f187e07dfefac","name":"nvim-treesitter","dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-treesitter","url":"https://github.com/nvim-treesitter/nvim-treesitter"}}