diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md index aa789ee..07368c5 100644 --- a/MIGRATION_PLAN.md +++ b/MIGRATION_PLAN.md @@ -261,13 +261,13 @@ Source of truth for the step-by-step rebuild. Keep this concise and up to date. ## Phase 9.1 — Confirm scope and priorities - [x] Confirm scope and priorities for this phase -- [x] Decision: Formatters - prettier (JS/TS/CSS/JSON/MD/HTML), phpcbf (PHP), stylua (Lua) -- [x] Decision: Linters - eslint (JS/TS), phpcs (PHP), markdownlint (Markdown) +- [x] Decision: Formatters - prettier (JS/TS/CSS/JSON/MD/HTML), phpcbf (PHP), stylua (Lua), black (Python) +- [x] Decision: Linters - eslint (JS/TS), phpcs (PHP), markdownlint (Markdown), ruff (Python) - [x] Decision: Project-local executables preferred, fallback to global (node_modules/.bin/, vendor/bin/) - [x] Decision: phpcs/phpcbf already installed globally with WordPress coding standards - no installation needed - [x] Decision: Format-on-save enabled by default with toggle capability - [x] Decision: Manual format keymaps: `lf` (normal), `lf` (visual range) -- [x] Decision: Respect project config files (.prettierrc, phpcs.xml, .eslintrc, etc.) +- [x] Decision: Respect project config files (.prettierrc, phpcs.xml, .eslintrc, pyproject.toml, etc.) - [x] Strategy: Helper function detects project-local executables first, then global - [x] WordPress: phpcs.xml in project root or --standard=WordPress flag for WordPress projects - [x] Philosophy: Formatters are authoritative source of truth; Neovim settings should match formatter rules per filetype @@ -293,17 +293,21 @@ Source of truth for the step-by-step rebuild. Keep this concise and up to date. ## Phase 9.3 — Mason formatter/linter installation - [x] Add `WhoIsSethDaniel/mason-tool-installer.nvim` for automated installation -- [x] Install via Mason: prettier, eslint_d, markdownlint, stylua +- [x] Install via Mason: prettier, eslint_d, markdownlint, stylua, black, ruff - [x] Note: phpcs/phpcbf already installed globally, skip Mason installation - [x] Verify all tools available: Tools installed to ~/.local/share/nvim/mason/bin/ ## Phase 9.4 — Align Neovim settings with formatter rules -- [ ] Configure per-filetype settings to match formatter defaults -- [ ] PHP: Match phpcs/WordPress standards (likely tabs, 4-width) -- [ ] JS/TS/CSS/JSON: Match prettier defaults (likely 2 spaces) -- [ ] Lua: Match stylua defaults (likely tabs or 4 spaces) -- [ ] Use autocmds or after/ftplugin/ for filetype-specific tabstop, shiftwidth, expandtab -- [ ] Goal: Manual editing feels natural and matches what formatter will produce on save +- [x] Configure per-filetype settings to match formatter defaults +- [x] PHP: tabs, 2-width display (WordPress standards) +- [x] JS/TS/CSS/JSON/HTML: spaces, 2-width (Prettier defaults) +- [x] Lua: spaces, 2-width (common Neovim convention) +- [x] Markdown: spaces, 2-width (Prettier defaults) +- [x] Python: spaces, 4-width (Black/PEP 8 defaults) +- [x] Use autocmds in lua/autocmds.lua for filetype-specific tabstop, shiftwidth, expandtab +- [x] Set global defaults: 4-width, spaces (reasonable baseline) +- [x] Goal: Manual editing feels natural and matches what formatter will produce on save +- [x] Note: All settings kept explicit per-filetype for clarity and maintainability ## Phase 10 — Migrate Kept Behaviours diff --git a/lua/autocmds.lua b/lua/autocmds.lua index ba60fe8..01fa9ba 100644 --- a/lua/autocmds.lua +++ b/lua/autocmds.lua @@ -1,7 +1,67 @@ -- Non-plugin autocommands (minimal placeholder for bootstrap) local aug = vim.api.nvim_create_augroup('UserDefaults', { clear = true }) --- Add specific autocmds in later phases +-- Phase 9.4: Per-filetype indentation settings to match formatters + +-- PHP: WordPress coding standards (tabs, displayed as 2 spaces) +vim.api.nvim_create_autocmd("FileType", { + group = aug, + pattern = "php", + callback = function() + vim.opt_local.expandtab = false -- Use actual tabs (WordPress standard) + vim.opt_local.tabstop = 2 -- Display tabs as 2 spaces wide + vim.opt_local.shiftwidth = 2 -- Indent/outdent by 2 columns (one tab) + vim.opt_local.softtabstop = 2 -- Tab key inserts 2 columns (one tab) + end, +}) + +-- JavaScript, TypeScript, JSON, CSS: Prettier defaults (2 spaces) +vim.api.nvim_create_autocmd("FileType", { + group = aug, + pattern = { "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "css", "scss", "html" }, + callback = function() + vim.opt_local.expandtab = true -- Use spaces (Prettier default) + vim.opt_local.tabstop = 2 -- Display as 2 spaces + vim.opt_local.shiftwidth = 2 -- Indent by 2 + vim.opt_local.softtabstop = 2 + end, +}) + +-- Lua: stylua defaults (2 spaces) +vim.api.nvim_create_autocmd("FileType", { + group = aug, + pattern = "lua", + callback = function() + vim.opt_local.expandtab = true -- Use spaces (common for Lua configs) + vim.opt_local.tabstop = 2 -- Display as 2 spaces + vim.opt_local.shiftwidth = 2 -- Indent by 2 + vim.opt_local.softtabstop = 2 + end, +}) + +-- Markdown: Prettier defaults (2 spaces) +vim.api.nvim_create_autocmd("FileType", { + group = aug, + pattern = "markdown", + callback = function() + vim.opt_local.expandtab = true -- Use spaces + vim.opt_local.tabstop = 2 -- Display as 2 spaces + vim.opt_local.shiftwidth = 2 -- Indent by 2 + vim.opt_local.softtabstop = 2 + end, +}) + +-- Python: Black defaults (4 spaces) +vim.api.nvim_create_autocmd("FileType", { + group = aug, + pattern = "python", + callback = function() + vim.opt_local.expandtab = true -- Use spaces (PEP 8) + vim.opt_local.tabstop = 4 -- Display as 4 spaces + vim.opt_local.shiftwidth = 4 -- Indent by 4 + vim.opt_local.softtabstop = 4 + end, +}) return {} diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index eebd3a7..b9b8eac 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -95,8 +95,9 @@ return { configure("intelephense", { single_file_support = false, }) + configure("pyright") -- Python LSP -- Enable all configured servers - vim.lsp.enable({ "lua_ls", "ts_ls", "html", "cssls", "jsonls", "bashls", "marksman", "intelephense" }) + vim.lsp.enable({ "lua_ls", "ts_ls", "html", "cssls", "jsonls", "bashls", "marksman", "intelephense", "pyright" }) end, } diff --git a/lua/plugins/mason-lspconfig.lua b/lua/plugins/mason-lspconfig.lua index e8cba44..910f2d5 100644 --- a/lua/plugins/mason-lspconfig.lua +++ b/lua/plugins/mason-lspconfig.lua @@ -13,6 +13,7 @@ return { "bashls", "marksman", "intelephense", + "pyright", }, automatic_installation = true, }) diff --git a/lua/plugins/mason-tool-installer.lua b/lua/plugins/mason-tool-installer.lua index d107406..84ff1ef 100644 --- a/lua/plugins/mason-tool-installer.lua +++ b/lua/plugins/mason-tool-installer.lua @@ -10,11 +10,13 @@ return { -- Formatters "prettier", -- JS, TS, CSS, JSON, Markdown, HTML "stylua", -- Lua + "black", -- Python -- Note: phpcbf already installed globally -- Linters "eslint_d", -- JS, TS (daemon version for speed) "markdownlint", -- Markdown + "ruff", -- Python (fast linter + import sorter) -- Note: phpcs already installed globally }, auto_update = false, diff --git a/lua/plugins/none-ls.lua b/lua/plugins/none-ls.lua index 7466111..0c14edc 100644 --- a/lua/plugins/none-ls.lua +++ b/lua/plugins/none-ls.lua @@ -74,6 +74,11 @@ return { formatting.stylua.with({ command = find_executable({ "stylua" }), }), + + -- black (Python) + formatting.black.with({ + command = find_executable({ "black" }), + }), }, -- Format on save diff --git a/lua/plugins/nvim-lint.lua b/lua/plugins/nvim-lint.lua index db94efa..073c46d 100644 --- a/lua/plugins/nvim-lint.lua +++ b/lua/plugins/nvim-lint.lua @@ -15,6 +15,7 @@ return { typescriptreact = { "eslint_d" }, markdown = { "markdownlint" }, php = { "phpcs" }, + python = { "ruff" }, } -- Helper: Find project-local executable, fallback to global @@ -68,6 +69,9 @@ return { -- Configure markdownlint lint.linters.markdownlint.cmd = find_executable({ "markdownlint" }) or "markdownlint" + -- Configure ruff for Python + lint.linters.ruff.cmd = find_executable({ "ruff" }) or "ruff" + -- Auto-lint on these events local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, { diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua index f757d68..b72784c 100644 --- a/lua/plugins/treesitter.lua +++ b/lua/plugins/treesitter.lua @@ -26,6 +26,7 @@ return { "markdown", "markdown_inline", "bash", + "python", "regex", }, diff --git a/lua/settings.lua b/lua/settings.lua index 8da4de0..19ae9c0 100644 --- a/lua/settings.lua +++ b/lua/settings.lua @@ -35,3 +35,9 @@ vim.opt.relativenumber = true vim.opt.signcolumn = 'yes' -- Always show sign column (for LSP diagnostics, git signs, etc.) vim.opt.cursorline = true -- Highlight current line vim.opt.colorcolumn = '80,120' -- Visual guides at 80 and 120 characters + +-- Phase 9.4: Default indentation (per-filetype overrides in after/ftplugin/) +vim.opt.tabstop = 4 -- Display tabs as 4 spaces +vim.opt.shiftwidth = 4 -- Indent by 4 +vim.opt.softtabstop = 4 -- Backspace removes 4 spaces +vim.opt.expandtab = true -- Use spaces by default (overridden per-filetype)