diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md index ba760ea..2c84449 100644 --- a/MIGRATION_PLAN.md +++ b/MIGRATION_PLAN.md @@ -53,21 +53,21 @@ Source of truth for the step-by-step rebuild. Keep this concise and up to date. - [x] Decision: No direnv fallback for local config ## Phase 3.2 — Non-plugin settings to Lua -- [ ] Port non-plugin settings to Lua (options, listchars, showbreak, spelllang=en_gb) +- [x] Port non-plugin settings to Lua (options, listchars, showbreak, spelllang=en_gb) ## Phase 3.3 — Core completion stack -- [ ] Add core completion stack: `nvim-cmp`, `cmp-nvim-lsp`, `cmp-buffer`, `cmp-path`, `LuaSnip` +- [x] Add core completion stack: `nvim-cmp`, `cmp-nvim-lsp`, `cmp-buffer`, `cmp-path`, `LuaSnip` ## Phase 3.4 — Project‑local configuration (neoconf) - [ ] Confirm scope and priorities for this subphase - [x] Choose approach: use `folke/neoconf.nvim` (replaces custom loader) -- [ ] Add `folke/neoconf.nvim` plugin spec and minimal setup -- [ ] Document `.neoconf.json` usage and example in README +- [x] Add `folke/neoconf.nvim` plugin spec and minimal setup +- [x] Document `.neoconf.json` usage and example in README - [ ] Verify neoconf merges settings into lspconfig -- [ ] Wire `intelephense.environment.includePaths` via `.neoconf.json` +- [x] Wire `intelephense.environment.includePaths` via `.neoconf.json` ## Phase 3.5 — LSP minimal defaults -- [ ] Add `nvim-lspconfig` with minimal defaults (no over-configuration) +- [x] Add `nvim-lspconfig` with minimal defaults (no over-configuration) ## Phase 4 — Navigation diff --git a/lazy-lock.json b/lazy-lock.json new file mode 100644 index 0000000..ffcc549 --- /dev/null +++ b/lazy-lock.json @@ -0,0 +1,10 @@ +{ + "LuaSnip": { "branch": "master", "commit": "3732756842a2f7e0e76a7b0487e9692072857277" }, + "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, + "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, + "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "neoconf.nvim": { "branch": "main", "commit": "fbf01840998b9f0e6b05a5c3811a882fcbcaf563" }, + "nvim-cmp": { "branch": "main", "commit": "d97d85e01339f01b842e6ec1502f639b080cb0fc" }, + "nvim-lspconfig": { "branch": "master", "commit": "9c923997123ff9071198ea3b594d4c1931fab169" } +} diff --git a/lua/plugins/cmp.lua b/lua/plugins/cmp.lua new file mode 100644 index 0000000..acd1549 --- /dev/null +++ b/lua/plugins/cmp.lua @@ -0,0 +1,39 @@ +return { + "hrsh7th/nvim-cmp", + event = "InsertEnter", + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + "L3MON4D3/LuaSnip", + }, + opts = function() + local cmp = require("cmp") + local luasnip = require("luasnip") + + return { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.confirm({ select = false }), + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.abort(), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "path" }, + { name = "buffer" }, + }), + completion = { completeopt = "menu,menuone,noselect" }, + } + end, + config = function(_, opts) + require("cmp").setup(opts) + end, +} + diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua new file mode 100644 index 0000000..1b56eab --- /dev/null +++ b/lua/plugins/lsp.lua @@ -0,0 +1,36 @@ +return { + "neovim/nvim-lspconfig", + event = { "BufReadPre", "BufNewFile" }, + dependencies = { + "folke/neoconf.nvim", + "hrsh7th/cmp-nvim-lsp", + }, + config = function() + local capabilities = require("cmp_nvim_lsp").default_capabilities() + + local servers = { + lua_ls = { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, + }, + }, + }, + ts_ls = {}, + html = {}, + cssls = {}, + jsonls = {}, + bashls = {}, + marksman = {}, + intelephense = {}, + } + + for name, opts in pairs(servers) do + local ok, mod = pcall(require, "lspconfig." .. name) + if ok and mod and type(mod.setup) == "function" then + opts = vim.tbl_deep_extend("force", { capabilities = capabilities }, opts or {}) + mod.setup(opts) + end + end + end, +} diff --git a/lua/plugins/neoconf.lua b/lua/plugins/neoconf.lua new file mode 100644 index 0000000..f6514ef --- /dev/null +++ b/lua/plugins/neoconf.lua @@ -0,0 +1,10 @@ +return { + "folke/neoconf.nvim", + lazy = false, -- load early so it can influence lspconfig later + priority = 1000, + opts = {}, + config = function(_, opts) + require("neoconf").setup(opts) + end, +} + diff --git a/lua/settings.lua b/lua/settings.lua index 49f1c71..be40ed2 100644 --- a/lua/settings.lua +++ b/lua/settings.lua @@ -1,9 +1,25 @@ --- Minimal settings for bootstrap phase +-- Minimal settings for bootstrap and Phase 3.2 -- Disable unused language providers early; enable later only if a plugin requires them vim.g.loaded_ruby_provider = 0 vim.g.loaded_perl_provider = 0 vim.g.loaded_node_provider = 0 --- Additional non-plugin options will be migrated in Phase 3 +-- Phase 3.2: non-plugin settings (legacy values where specified) +-- Completion UI for nvim-cmp +vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } + +-- Spelling +vim.opt.spelllang = { 'en_gb' } + +-- Visuals +vim.opt.showbreak = ' ↳' +vim.opt.listchars = { + eol = '¬', + tab = '│ ', + trail = '~', + extends = '>', + precedes = '<', + space = '·', +}