From 2c1e70cfdc463fd98e320874460556894f158eaa Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Thu, 16 Oct 2025 10:49:45 -0400 Subject: [PATCH] refactor(nvim): simplify lazy loading configuration --- lazy-lock.json | 2 + lua/plugins/buildtools.lua | 281 +++++++++++++++++++++++++++++++++++ lua/plugins/cloudflare.lua | 293 +++++++++++++++++++++++++++++++++++++ lua/plugins/linting.lua | 200 +++++++++++++++++++++++++ lua/plugins/opencode.lua | 1 - lua/plugins/telescope.lua | 29 ++++ lua/plugins/tsx.lua | 258 ++++++++++++++++++++++++++++++++ 7 files changed, 1063 insertions(+), 1 deletion(-) create mode 100644 lua/plugins/buildtools.lua create mode 100644 lua/plugins/cloudflare.lua create mode 100644 lua/plugins/linting.lua delete mode 100644 lua/plugins/opencode.lua create mode 100644 lua/plugins/telescope.lua create mode 100644 lua/plugins/tsx.lua diff --git a/lazy-lock.json b/lazy-lock.json index 28b0c48..dbf2d1b 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -19,6 +19,7 @@ "conform.nvim": { "branch": "master", "commit": "fbcb4fa7f34bfea9be702ffff481a8e336ebf6ed" }, "cyberdream.nvim": { "branch": "main", "commit": "eba11f590026e74915e13d12a53cdbdc9b98d9f9" }, "deno-nvim": { "branch": "master", "commit": "5c1ef9762f916033bd3b9b37878384cae24ddb4e" }, + "doodle": { "branch": "main", "commit": "2f192d6ec821f9ae14460689047438aae8002ec9" }, "dressing.nvim": { "branch": "master", "commit": "3a45525bb182730fe462325c99395529308f431e" }, "friendly-snippets": { "branch": "main", "commit": "efff286dd74c22f731cdec26a70b46e5b203c619" }, "gitsigns.nvim": { "branch": "main", "commit": "7010000889bfb6c26065e0b0f7f1e6aa9163edd9" }, @@ -65,6 +66,7 @@ "resession.nvim": { "branch": "master", "commit": "cc819b0489938d03e4f3532a583354f0287c015b" }, "schemastore.nvim": { "branch": "main", "commit": "667eaa5da8f66f1dd97c905a12dd1eb544a2d259" }, "smart-splits.nvim": { "branch": "master", "commit": "ddb23c1a1cf1507bda487cda7f6e4690965ef9f5" }, + "sqlite.lua": { "branch": "master", "commit": "50092d60feb242602d7578398c6eb53b4a8ffe7b" }, "supermaven-nvim": { "branch": "main", "commit": "07d20fce48a5629686aefb0a7cd4b25e33947d50" }, "telescope-fzf-native.nvim": { "branch": "main", "commit": "1f08ed60cafc8f6168b72b80be2b2ea149813e55" }, "telescope.nvim": { "branch": "master", "commit": "a17d611a0e111836a1db5295f04945df407c5135" }, diff --git a/lua/plugins/buildtools.lua b/lua/plugins/buildtools.lua new file mode 100644 index 0000000..6157b9d --- /dev/null +++ b/lua/plugins/buildtools.lua @@ -0,0 +1,281 @@ +--- Build tools and development environment optimizations +--- Includes support for bun, vite, and modern JS tooling +--- @module plugins.buildtools + +return { + -- Vim support for various config files + { + "nvim-treesitter/nvim-treesitter", + optional = true, + opts = function(_, opts) + if opts.ensure_installed ~= "all" then + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "toml", + "yaml", + "json", + "jsonc", + }) + end + end, + }, + + -- Enhanced JSON support with schema validation + { + "b0o/schemastore.nvim", + lazy = true, + dependencies = { + { + "AstroNvim/astrolsp", + optional = true, + ---@type AstroLSPOpts + opts = { + ---@diagnostic disable: missing-fields + config = { + jsonls = { + on_new_config = function(config) + if not config.settings.json then config.settings.json = {} end + if not config.settings.json.schemas then config.settings.json.schemas = {} end + vim.list_extend(config.settings.json.schemas, require("schemastore").json.schemas()) + end, + settings = { + json = { + format = { enable = true }, + validate = { enable = true }, + }, + }, + }, + }, + }, + }, + }, + }, + + -- YAML schema support + { + "AstroNvim/astrolsp", + optional = true, + ---@type AstroLSPOpts + opts = { + ---@diagnostic disable: missing-fields + config = { + yamlls = { + on_new_config = function(config) + config.settings.yaml.schemas = vim.tbl_deep_extend( + "force", + config.settings.yaml.schemas or {}, + require("schemastore").yaml.schemas() + ) + end, + settings = { + yaml = { + schemaStore = { + enable = false, + url = "", + }, + }, + }, + }, + }, + }, + }, + + -- Task runner integration (for vite, bun scripts) + { + "stevearc/overseer.nvim", + cmd = { + "OverseerRun", + "OverseerToggle", + "OverseerOpen", + "OverseerClose", + "OverseerLoadBundle", + "OverseerSaveBundle", + "OverseerDeleteBundle", + "OverseerRunCmd", + "OverseerQuickAction", + "OverseerTaskAction", + }, + opts = { + strategy = { + "toggleterm", + direction = "horizontal", + open_on_start = false, + }, + templates = { + "builtin", + "bun.run", + "npm.run", + "vite.dev", + "vite.build", + }, + task_list = { + bindings = { + [""] = false, + [""] = false, + [""] = false, + [""] = false, + }, + }, + }, + config = function(_, opts) + local overseer = require "overseer" + overseer.setup(opts) + + -- Custom task templates for bun + overseer.register_template { + name = "bun.run", + builder = function(params) + return { + cmd = { "bun" }, + args = { "run", params.script }, + name = "bun run " .. params.script, + components = { "default" }, + } + end, + params = { + script = { + type = "string", + default = "dev", + description = "Script to run from package.json", + }, + }, + condition = { + filetype = { "typescript", "javascript", "typescriptreact", "javascriptreact" }, + }, + } + + -- Custom task templates for vite + overseer.register_template { + name = "vite.dev", + builder = function() + return { + cmd = { "bun" }, + args = { "run", "dev" }, + name = "vite dev server", + components = { + { "on_output_quickfix", open = false }, + "default", + }, + } + end, + condition = { + callback = function() + return vim.fn.filereadable "vite.config.ts" == 1 or vim.fn.filereadable "vite.config.js" == 1 + end, + }, + } + + overseer.register_template { + name = "vite.build", + builder = function() + return { + cmd = { "bun" }, + args = { "run", "build" }, + name = "vite build", + components = { + { "on_output_quickfix", open = true }, + "default", + }, + } + end, + condition = { + callback = function() + return vim.fn.filereadable "vite.config.ts" == 1 or vim.fn.filereadable "vite.config.js" == 1 + end, + }, + } + end, + }, + + -- REST client for testing Workers/APIs + { + "rest-nvim/rest.nvim", + ft = "http", + dependencies = { "nvim-lua/plenary.nvim" }, + opts = { + result_split_horizontal = false, + skip_ssl_verification = false, + encode_url = true, + highlight = { + enabled = true, + timeout = 150, + }, + result = { + show_url = true, + show_curl_command = true, + show_http_info = true, + show_headers = true, + }, + jump_to_request = false, + }, + }, + + -- Seamless navigation between build errors + { + "folke/trouble.nvim", + cmd = { "Trouble", "TroubleToggle" }, + opts = { + use_diagnostic_signs = true, + action_keys = { + close = "q", + cancel = "", + refresh = "r", + jump = { "", "" }, + open_split = { "" }, + open_vsplit = { "" }, + open_tab = { "" }, + jump_close = { "o" }, + toggle_mode = "m", + toggle_preview = "P", + hover = "K", + preview = "p", + close_folds = { "zM", "zm" }, + open_folds = { "zR", "zr" }, + toggle_fold = { "zA", "za" }, + previous = "k", + next = "j", + }, + }, + }, + + -- Git integration for collaborative development + { + "lewis6991/gitsigns.nvim", + event = "User AstroGitFile", + opts = { + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, + current_line_blame = false, + current_line_blame_opts = { + virt_text = true, + virt_text_pos = "eol", + delay = 300, + }, + }, + }, + + -- EditorConfig support + { + "editorconfig/editorconfig-vim", + event = { "BufReadPre", "BufNewFile" }, + }, + + -- Development container support + { + "esensar/nvim-dev-container", + dependencies = { "nvim-treesitter/nvim-treesitter" }, + cmd = { + "DevcontainerStart", + "DevcontainerAttach", + "DevcontainerExec", + "DevcontainerStop", + "DevcontainerLogs", + }, + opts = {}, + }, +} diff --git a/lua/plugins/cloudflare.lua b/lua/plugins/cloudflare.lua new file mode 100644 index 0000000..fa18975 --- /dev/null +++ b/lua/plugins/cloudflare.lua @@ -0,0 +1,293 @@ +--- Cloudflare Workers and React/shadcn development tools +--- Includes Workers-specific LSP, React tooling, and UI helpers +--- @module plugins.cloudflare + +return { + -- WASM/WebAssembly support for Workers + { + "nvim-treesitter/nvim-treesitter", + optional = true, + opts = function(_, opts) + if opts.ensure_installed ~= "all" then + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "wgsl", + "wgsl_bevy", + }) + end + end, + }, + + -- TOML support for wrangler.toml + { + "AstroNvim/astrolsp", + optional = true, + ---@type AstroLSPOpts + opts = { + ---@diagnostic disable: missing-fields + config = { + taplo = { + settings = { + evenBetterToml = { + schema = { + enabled = true, + associations = { + ["wrangler\\.toml"] = "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/schemas/wrangler.json", + }, + }, + }, + }, + }, + }, + }, + }, + + -- Enhanced search/replace for refactoring React components + { + "nvim-pack/nvim-spectre", + cmd = "Spectre", + dependencies = { "nvim-lua/plenary.nvim" }, + opts = { + mapping = { + ["toggle_line"] = { + map = "dd", + cmd = "lua require('spectre').toggle_line()", + desc = "toggle item", + }, + ["enter_file"] = { + map = "", + cmd = "lua require('spectre.actions').select_entry()", + desc = "open file", + }, + ["send_to_qf"] = { + map = "q", + cmd = "lua require('spectre.actions').send_to_qf()", + desc = "send all items to quickfix", + }, + ["replace_cmd"] = { + map = "c", + cmd = "lua require('spectre.actions').replace_cmd()", + desc = "input replace command", + }, + ["show_option_menu"] = { + map = "o", + cmd = "lua require('spectre').show_options()", + desc = "show options", + }, + ["run_current_replace"] = { + map = "rc", + cmd = "lua require('spectre.actions').run_current_replace()", + desc = "replace current line", + }, + ["run_replace"] = { + map = "R", + cmd = "lua require('spectre.actions').run_replace()", + desc = "replace all", + }, + }, + }, + }, + + -- React component preview and development + { + "roobert/tailwindcss-colorizer-cmp.nvim", + event = "VeryLazy", + opts = { + color_square_width = 2, + }, + config = function(_, opts) + require("tailwindcss-colorizer-cmp").setup(opts) + end, + }, + + -- Color highlighting for CSS/Tailwind + { + "NvChad/nvim-colorizer.lua", + event = { "BufReadPost", "BufNewFile" }, + opts = { + filetypes = { + "typescript", + "typescriptreact", + "javascript", + "javascriptreact", + "css", + "scss", + "html", + "vue", + "lua", + }, + user_default_options = { + RGB = true, + RRGGBB = true, + names = false, + RRGGBBAA = true, + AARRGGBB = false, + rgb_fn = true, + hsl_fn = true, + css = true, + css_fn = true, + mode = "background", + tailwind = true, + sass = { enable = true, parsers = { "css" } }, + virtualtext = "■", + always_update = false, + }, + buftypes = {}, + }, + }, + + -- Import cost for monitoring bundle size + { + "yardnsm/vim-import-cost", + build = "npm install --production", + ft = { "javascript", "typescript", "javascriptreact", "typescriptreact" }, + }, + + -- Live browser reload for Workers development + { + "Barrett17/browser-sync.nvim", + build = "npm install -g browser-sync", + cmd = { + "BrowserSyncStart", + "BrowserSyncReload", + "BrowserSyncStop", + }, + opts = {}, + }, + + -- Component generator for shadcn/ui + { + "chrisgrieser/nvim-scissors", + dependencies = { "nvim-telescope/telescope.nvim" }, + cmd = { "ScissorsAddNewSnippet", "ScissorsEditSnippet" }, + opts = { + snippetDir = vim.fn.stdpath "config" .. "/snippets", + editSnippetPopup = { + height = 0.4, + width = 0.6, + border = "rounded", + keymaps = { + cancel = "q", + saveChanges = "", + deleteSnippet = "d", + duplicateSnippet = "c", + }, + }, + }, + }, + + -- HTTP client for testing Workers + { + "mistweaverco/kulala.nvim", + ft = "http", + opts = { + default_view = "body", + debug = false, + contenttypes = { + ["application/json"] = { + ft = "json", + formatter = { "jq", "." }, + }, + ["application/xml"] = { + ft = "xml", + formatter = { "xmllint", "--format", "-" }, + }, + ["text/html"] = { + ft = "html", + formatter = { "xmllint", "--format", "--html", "-" }, + }, + }, + }, + }, + + -- Enhanced movement for JSX/TSX + { + "echasnovski/mini.ai", + event = { "BufReadPost", "BufNewFile" }, + opts = function() + local ai = require "mini.ai" + return { + custom_textobjects = { + -- Function calls + f = ai.gen_spec.treesitter { a = "@call.outer", i = "@call.inner" }, + -- Function definitions + F = ai.gen_spec.treesitter { a = "@function.outer", i = "@function.inner" }, + -- Classes + c = ai.gen_spec.treesitter { a = "@class.outer", i = "@class.inner" }, + -- Parameters/arguments + a = ai.gen_spec.treesitter { a = "@parameter.outer", i = "@parameter.inner" }, + -- JSX elements + x = ai.gen_spec.treesitter { + a = { "@jsx_element", "@jsx_self_closing_element" }, + i = { "@jsx_element", "@jsx_self_closing_element" }, + }, + }, + } + end, + }, + + -- React component navigation + { + "someone-stole-my-name/yaml-companion.nvim", + ft = { "yaml" }, + dependencies = { + { "neovim/nvim-lspconfig" }, + { "nvim-lua/plenary.nvim" }, + { "nvim-telescope/telescope.nvim" }, + }, + opts = {}, + }, + + -- Worker-specific terminal commands via toggleterm + { + "akinsho/toggleterm.nvim", + optional = true, + opts = function(_, opts) + local Terminal = require("toggleterm.terminal").Terminal + + -- Wrangler dev server + local wrangler_dev = Terminal:new { + cmd = "bunx wrangler dev", + hidden = true, + direction = "float", + float_opts = { + border = "curved", + }, + on_open = function(term) + vim.cmd "startinsert!" + vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "close", { noremap = true, silent = true }) + end, + } + + -- Wrangler tail (logs) + local wrangler_tail = Terminal:new { + cmd = "bunx wrangler tail", + hidden = true, + direction = "horizontal", + on_open = function(term) + vim.cmd "startinsert!" + vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "close", { noremap = true, silent = true }) + end, + } + + -- Wrangler deploy + local wrangler_deploy = Terminal:new { + cmd = "bunx wrangler deploy", + hidden = true, + direction = "float", + close_on_exit = false, + on_open = function(term) + vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "close", { noremap = true, silent = true }) + end, + } + + -- Extend the opts with custom terminals + opts.on_create = function() + vim.keymap.set("n", "wd", function() wrangler_dev:toggle() end, { desc = "Wrangler Dev" }) + vim.keymap.set("n", "wt", function() wrangler_tail:toggle() end, { desc = "Wrangler Tail" }) + vim.keymap.set("n", "wp", function() wrangler_deploy:toggle() end, { desc = "Wrangler Deploy" }) + end + + return opts + end, + }, +} diff --git a/lua/plugins/linting.lua b/lua/plugins/linting.lua new file mode 100644 index 0000000..96c6bdc --- /dev/null +++ b/lua/plugins/linting.lua @@ -0,0 +1,200 @@ +--- Linting and formatting configuration +--- Includes oxlint, prettier, and ESLint integration +--- @module plugins.linting + +return { + -- Conform for formatting + { + "stevearc/conform.nvim", + event = "BufWritePre", + cmd = { "ConformInfo" }, + opts = { + formatters_by_ft = { + typescript = { "prettier" }, + typescriptreact = { "prettier" }, + javascript = { "prettier" }, + javascriptreact = { "prettier" }, + json = { "prettier" }, + jsonc = { "prettier" }, + css = { "prettier" }, + scss = { "prettier" }, + html = { "prettier" }, + markdown = { "prettier" }, + yaml = { "prettier" }, + lua = { "stylua" }, + rust = { "rustfmt" }, + toml = { "taplo" }, + }, + format_on_save = function(bufnr) + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then return end + return { + timeout_ms = 500, + lsp_fallback = true, + } + end, + formatters = { + prettier = { + prepend_args = { + "--plugin=prettier-plugin-tailwindcss", + }, + }, + }, + }, + config = function(_, opts) + require("conform").setup(opts) + + -- Command to toggle format on save + vim.api.nvim_create_user_command("FormatToggle", function(args) + if args.bang then + -- Toggle buffer-local setting + vim.b.disable_autoformat = not vim.b.disable_autoformat + else + -- Toggle global setting + vim.g.disable_autoformat = not vim.g.disable_autoformat + end + local status = vim.g.disable_autoformat and "disabled" or "enabled" + vim.notify("Format on save " .. status, vim.log.levels.INFO) + end, { + desc = "Toggle format on save", + bang = true, + }) + end, + }, + + -- Lint with nvim-lint (oxlint integration) + { + "mfussenegger/nvim-lint", + event = { "BufReadPre", "BufNewFile" }, + config = function() + local lint = require "lint" + + -- Configure oxlint for TypeScript/JavaScript + lint.linters.oxlint = { + cmd = "oxlint", + stdin = false, + args = { + "--format=json", + }, + stream = "stdout", + ignore_exitcode = true, + parser = function(output) + if output == "" or output == nil then return {} end + + local ok, decoded = pcall(vim.fn.json_decode, output) + if not ok then return {} end + + local diagnostics = {} + for _, item in ipairs(decoded) do + if item.diagnostics then + for _, diagnostic in ipairs(item.diagnostics) do + table.insert(diagnostics, { + lnum = diagnostic.start.line - 1, + end_lnum = diagnostic["end"].line - 1, + col = diagnostic.start.column - 1, + end_col = diagnostic["end"].column - 1, + severity = vim.diagnostic.severity.WARN, + source = "oxlint", + message = diagnostic.message, + code = diagnostic.rule_id, + }) + end + end + end + return diagnostics + end, + } + + -- Configure linters per filetype + lint.linters_by_ft = { + typescript = { "oxlint" }, + typescriptreact = { "oxlint" }, + javascript = { "oxlint" }, + javascriptreact = { "oxlint" }, + css = { "stylelint" }, + scss = { "stylelint" }, + markdown = { "markdownlint" }, + } + + -- Auto-lint on save and text changed + local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) + vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave", "TextChanged" }, { + group = lint_augroup, + callback = function() + -- Only lint if file exists on disk + if vim.fn.filereadable(vim.api.nvim_buf_get_name(0)) == 1 then lint.try_lint() end + end, + }) + end, + }, + + -- Mason tool installer for linters/formatters + { + "WhoIsSethDaniel/mason-tool-installer.nvim", + dependencies = { "williamboman/mason.nvim" }, + cmd = { "MasonToolsInstall", "MasonToolsUpdate" }, + opts = { + ensure_installed = { + -- Formatters + "prettier", + "stylua", + "rustfmt", + "taplo", + -- Linters + "eslint_d", + "stylelint", + "markdownlint", + -- Note: oxlint should be installed via cargo/npm separately + }, + auto_update = false, + run_on_start = true, + }, + }, + + -- Additional diagnostics UI + { + "folke/trouble.nvim", + optional = true, + opts = { + modes = { + lsp = { + win = { position = "right" }, + }, + }, + }, + }, + + -- Inline linting hints + { + "https://git.sr.ht/~whynothugo/lsp_lines.nvim", + event = { "BufReadPost", "BufNewFile" }, + config = function() + require("lsp_lines").setup() + -- Disable virtual_text since lsp_lines will show diagnostics + vim.diagnostic.config { virtual_text = false } + + -- Toggle command + vim.api.nvim_create_user_command("LspLinesToggle", function() + local new_value = not require("lsp_lines").toggle() + vim.diagnostic.config { virtual_text = new_value } + end, { desc = "Toggle LSP lines" }) + end, + }, + + -- Better quickfix for showing lint errors + { + "kevinhwang91/nvim-bqf", + ft = "qf", + opts = { + auto_resize_height = true, + func_map = { + vsplit = "v", + split = "s", + tab = "t", + tabb = "T", + tabc = "", + ptogglemode = "z,", + }, + }, + }, +} diff --git a/lua/plugins/opencode.lua b/lua/plugins/opencode.lua deleted file mode 100644 index 8b13789..0000000 --- a/lua/plugins/opencode.lua +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lua/plugins/telescope.lua b/lua/plugins/telescope.lua new file mode 100644 index 0000000..b7c83b4 --- /dev/null +++ b/lua/plugins/telescope.lua @@ -0,0 +1,29 @@ +--- Telescope configuration with Doodle integration +--- Extends telescope.nvim with doodle extension +--- @module plugins.telescope + +return { + "nvim-telescope/telescope.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "apdot/doodle", + }, + opts = function(_, opts) + -- Ensure extensions table exists + opts.extensions = opts.extensions or {} + + -- Add doodle extension configuration + opts.extensions.doodle = {} + + return opts + end, + config = function(_, opts) + local telescope = require "telescope" + + -- Setup telescope with options + telescope.setup(opts) + + -- Load the doodle extension + telescope.load_extension "doodle" + end, +} diff --git a/lua/plugins/tsx.lua b/lua/plugins/tsx.lua new file mode 100644 index 0000000..5bfc987 --- /dev/null +++ b/lua/plugins/tsx.lua @@ -0,0 +1,258 @@ +--- TypeScript/TSX development optimizations +--- Includes LSP, treesitter, linting, and React-specific tooling +--- @module plugins.tsx + +return { + -- TypeScript LSP with enhanced settings for React/TSX + { + "AstroNvim/astrolsp", + optional = true, + ---@type AstroLSPOpts + opts = { + ---@diagnostic disable: missing-fields + config = { + -- TypeScript/JavaScript LSP + tsserver = { + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayVariableTypeHintsWhenTypeMatchesName = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + suggest = { + includeCompletionsForModuleExports = true, + }, + preferences = { + importModuleSpecifier = "relative", + jsxAttributeCompletionStyle = "auto", + }, + }, + javascript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + }, + }, + -- Volar for Vue (also helpful for some React scenarios) + volar = { + filetypes = { "vue", "typescript", "javascript", "typescriptreact", "javascriptreact" }, + }, + -- Tailwind CSS LSP for shadcn/ui + tailwindcss = { + root_dir = function(fname) + local util = require "lspconfig.util" + return util.root_pattern("tailwind.config.js", "tailwind.config.ts", "postcss.config.js")(fname) + end, + settings = { + tailwindCSS = { + experimental = { + classRegex = { + { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" }, + { "cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" }, + { "cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" }, + }, + }, + }, + }, + }, + -- CSS LSP + cssls = {}, + -- HTML LSP + html = { + filetypes = { "html", "typescriptreact", "javascriptreact" }, + }, + -- ESLint LSP + eslint = { + settings = { + workingDirectories = { mode = "auto" }, + experimental = { + useFlatConfig = true, + }, + }, + }, + }, + }, + }, + + -- Enhanced treesitter for TSX/React + { + "nvim-treesitter/nvim-treesitter", + optional = true, + opts = function(_, opts) + if opts.ensure_installed ~= "all" then + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "typescript", + "tsx", + "javascript", + "jsdoc", + "json", + "jsonc", + "css", + "scss", + "html", + "markdown", + "markdown_inline", + "regex", + "bash", + "vim", + "lua", + }) + end + end, + }, + + -- Treesitter context for React component awareness + { + "nvim-treesitter/nvim-treesitter-context", + event = { "BufReadPost", "BufNewFile" }, + opts = { + enable = true, + max_lines = 3, + patterns = { + default = { + "class", + "function", + "method", + "for", + "while", + "if", + "switch", + "case", + "interface", + "struct", + "enum", + }, + typescript = { + "class_declaration", + "abstract_class_declaration", + "function_declaration", + "method_definition", + "arrow_function", + "function_expression", + "lexical_declaration", + "variable_declaration", + }, + typescriptreact = { + "class_declaration", + "function_declaration", + "method_definition", + "arrow_function", + "function_expression", + "jsx_element", + "jsx_self_closing_element", + }, + }, + }, + }, + + -- TypeScript utilities and tools + { + "pmizio/typescript-tools.nvim", + ft = { "typescript", "typescriptreact", "javascript", "javascriptreact" }, + dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" }, + opts = { + settings = { + separate_diagnostic_server = true, + publish_diagnostic_on = "insert_leave", + expose_as_code_action = "all", + tsserver_file_preferences = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayVariableTypeHintsWhenTypeMatchesName = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + tsserver_format_options = { + allowIncompleteCompletions = false, + allowRenameOfImportPath = true, + }, + }, + }, + }, + + -- Mason LSP configurations + { + "williamboman/mason-lspconfig.nvim", + optional = true, + opts = function(_, opts) + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "tsserver", + "tailwindcss", + "cssls", + "html", + "eslint", + "jsonls", + }) + end, + }, + + -- React/JSX snippets and helpers + { + "dsznajder/vscode-es7-react-js-snippets", + build = "yarn install --frozen-lockfile && yarn compile", + ft = { "javascript", "typescript", "javascriptreact", "typescriptreact" }, + }, + + -- Auto-close and auto-rename JSX tags + { + "windwp/nvim-ts-autotag", + event = { "BufReadPost", "BufNewFile" }, + ft = { + "html", + "javascript", + "typescript", + "javascriptreact", + "typescriptreact", + "xml", + "vue", + "svelte", + }, + opts = { + autotag = { + enable = true, + enable_rename = true, + enable_close = true, + enable_close_on_slash = true, + }, + }, + }, + + -- Package info for package.json + { + "vuki656/package-info.nvim", + event = "BufRead package.json", + dependencies = { "MunifTanjim/nui.nvim" }, + opts = {}, + }, + + -- Crates.io integration (useful for Rust tooling in Workers) + { + "saecki/crates.nvim", + event = "BufRead Cargo.toml", + dependencies = { "nvim-lua/plenary.nvim" }, + opts = { + lsp = { + enabled = true, + actions = true, + completion = true, + hover = true, + }, + }, + }, +}