refactor(nvim): streamline Neovim configuration and plugin management
This commit is contained in:
1 parent
06e0bab7dd
commit
bdf8ad1bb0
27 files changed
+1797
-476
No files matched your search
@@ -94,6 +94,7 @@ return {
|
||||
-- first key is the mode
|
||||
n = {
|
||||
["<C-!>"] = { "<Cmd>suspend<CR>", desc = "Suspend nvim (return with 'fg')" },
|
||||
["<C-q>Q"] = { "<Cmd>wqa<CR>", desc = "Save all buffers and quit Neovim" },
|
||||
-- navigate buffer tabs
|
||||
["<C-c>"] = { "<Cmd>wa<CR><Cmd>bd<CR>", desc = "Save and close buffer" }, -- Added C-x to save and close buffer
|
||||
["F"] = { "za", desc = "Toggle fold under cursor" },
|
||||
@@ -412,8 +413,90 @@ return {
|
||||
["<C-a>b"] = { "<cmd>ClaudeCodeAdd %<cr>", desc = "Add current buffer" },
|
||||
["<C-a>y"] = { "<cmd>ClaudeCodeDiffAccept<cr>", desc = "Accept diff" },
|
||||
["<C-a>n"] = { "<cmd>ClaudeCodeDiffDeny<cr>", desc = "Deny diff" },
|
||||
["<C-a><C-t>"] = { "<cmd>TemplateSnacks<cr>", desc = "Open template picker" },
|
||||
-- Taskfile
|
||||
["<C-t><C-t>"] = { terminals.mk_toggle, desc = "Taskfile Toggle" },
|
||||
-- UI Toggles with Snacks
|
||||
["<leader>u"] = { desc = "UI Toggles" },
|
||||
["<leader>ud"] = {
|
||||
function() require("snacks").toggle.diagnostics():toggle() end,
|
||||
desc = "Toggle Diagnostics",
|
||||
},
|
||||
["<leader>un"] = {
|
||||
function() require("snacks").toggle.line_number():toggle() end,
|
||||
desc = "Toggle Line Numbers",
|
||||
},
|
||||
["<leader>ur"] = {
|
||||
function() require("snacks").toggle.option("relativenumber"):toggle() end,
|
||||
desc = "Toggle Relative Numbers",
|
||||
},
|
||||
["<leader>uw"] = {
|
||||
function() require("snacks").toggle.option("wrap"):toggle() end,
|
||||
desc = "Toggle Line Wrap",
|
||||
},
|
||||
["<leader>us"] = {
|
||||
function() require("snacks").toggle.option("spell"):toggle() end,
|
||||
desc = "Toggle Spelling",
|
||||
},
|
||||
["<leader>ui"] = {
|
||||
function() require("snacks").toggle.inlay_hints():toggle() end,
|
||||
desc = "Toggle Inlay Hints",
|
||||
},
|
||||
["<leader>ut"] = {
|
||||
function() require("snacks").toggle.treesitter():toggle() end,
|
||||
desc = "Toggle Treesitter",
|
||||
},
|
||||
["<leader>uc"] = {
|
||||
function() require("snacks").toggle.option("conceallevel", { off = 0, on = 2 }):toggle() end,
|
||||
desc = "Toggle Conceal",
|
||||
},
|
||||
["<leader>uI"] = {
|
||||
function() require("snacks").toggle.indent():toggle() end,
|
||||
desc = "Toggle Indent Guides",
|
||||
},
|
||||
["<leader>uz"] = {
|
||||
function() require("snacks").toggle.zen():toggle() end,
|
||||
desc = "Toggle Zen Mode",
|
||||
},
|
||||
["<leader>uZ"] = {
|
||||
function() require("snacks").toggle.zoom():toggle() end,
|
||||
desc = "Toggle Zoom",
|
||||
},
|
||||
["<leader>ua"] = {
|
||||
function() require("snacks").toggle.animate():toggle() end,
|
||||
desc = "Toggle Animations",
|
||||
},
|
||||
["<leader>uS"] = {
|
||||
function() require("snacks").toggle.scroll():toggle() end,
|
||||
desc = "Toggle Smooth Scroll",
|
||||
},
|
||||
["<leader>up"] = {
|
||||
function() require("snacks").toggle.profiler():toggle() end,
|
||||
desc = "Toggle Profiler",
|
||||
},
|
||||
["<leader>uh"] = {
|
||||
function() require("snacks").toggle.profiler_highlights():toggle() end,
|
||||
desc = "Toggle Profiler Highlights",
|
||||
},
|
||||
["<leader>ux"] = {
|
||||
function() require("snacks").toggle.dim():toggle() end,
|
||||
desc = "Toggle Dim Inactive",
|
||||
},
|
||||
["<leader>uf"] = {
|
||||
function()
|
||||
vim.g.disable_autoformat = not vim.g.disable_autoformat
|
||||
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",
|
||||
},
|
||||
["<leader>ul"] = {
|
||||
function()
|
||||
local new_value = not require("lsp_lines").toggle()
|
||||
vim.diagnostic.config { virtual_text = new_value }
|
||||
end,
|
||||
desc = "Toggle LSP Lines",
|
||||
},
|
||||
},
|
||||
i = {
|
||||
["<C-c>"] = { "<Cmd>wa<CR><Cmd>bd<CR><Esc>", desc = "Save, close buffer, and return to normal mode" },
|
||||
|
||||
+387
-5
@@ -1,4 +1,5 @@
|
||||
--- AstroLSP configuration optimized for tech stack:
|
||||
--- Comprehensive LSP, formatting, and linting configuration
|
||||
--- Optimized for tech stack:
|
||||
--- - Cloudflare Workers/Pages
|
||||
--- - Golang (Cosmos SDK)
|
||||
--- - TypeScript/React/Vite
|
||||
@@ -7,9 +8,13 @@
|
||||
--- @module plugins.astrolsp
|
||||
|
||||
return {
|
||||
"AstroNvim/astrolsp",
|
||||
---@type AstroLSPOpts
|
||||
opts = {
|
||||
-- ============================================================================
|
||||
-- AstroLSP - Core LSP Configuration
|
||||
-- ============================================================================
|
||||
{
|
||||
"AstroNvim/astrolsp",
|
||||
---@type AstroLSPOpts
|
||||
opts = {
|
||||
-- Enable LSP features
|
||||
features = {
|
||||
autoformat = true,
|
||||
@@ -176,8 +181,17 @@ return {
|
||||
},
|
||||
},
|
||||
|
||||
-- Tailwind for React components
|
||||
-- Volar for Vue (also helpful for some React scenarios)
|
||||
volar = {
|
||||
filetypes = { "vue", "typescript", "javascript", "typescriptreact", "javascriptreact" },
|
||||
},
|
||||
|
||||
-- Tailwind CSS for React/shadcn components
|
||||
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 = {
|
||||
@@ -202,8 +216,12 @@ return {
|
||||
},
|
||||
},
|
||||
|
||||
-- CSS LSP
|
||||
cssls = {},
|
||||
|
||||
-- HTML for React/templates
|
||||
html = {
|
||||
filetypes = { "html", "typescriptreact", "javascriptreact" },
|
||||
settings = {
|
||||
html = {
|
||||
format = {
|
||||
@@ -380,4 +398,368 @@ return {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- Formatting - Conform.nvim
|
||||
-- ============================================================================
|
||||
{
|
||||
"stevearc/conform.nvim",
|
||||
event = "BufWritePre",
|
||||
cmd = { "ConformInfo" },
|
||||
opts = {
|
||||
formatters_by_ft = {
|
||||
typescript = { "oxfmt" },
|
||||
typescriptreact = { "oxfmt" },
|
||||
javascript = { "oxfmt" },
|
||||
javascriptreact = { "oxfmt" },
|
||||
json = { "oxfmt" },
|
||||
jsonc = { "oxfmt" },
|
||||
css = { "oxfmt" },
|
||||
scss = { "oxfmt" },
|
||||
html = { "oxfmt" },
|
||||
markdown = { "oxfmt" },
|
||||
yaml = { "oxfmt" },
|
||||
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 = {
|
||||
-- oxfmt uses default configuration
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- Linting - nvim-lint
|
||||
-- ============================================================================
|
||||
{
|
||||
"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,
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- Treesitter Configuration
|
||||
-- ============================================================================
|
||||
{
|
||||
"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 Tooling
|
||||
-- ============================================================================
|
||||
{
|
||||
"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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- Mason Configuration
|
||||
-- ============================================================================
|
||||
{
|
||||
"williamboman/mason-lspconfig.nvim",
|
||||
optional = true,
|
||||
opts = function(_, opts)
|
||||
opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, {
|
||||
"tsserver",
|
||||
"tailwindcss",
|
||||
"cssls",
|
||||
"html",
|
||||
"jsonls",
|
||||
})
|
||||
end,
|
||||
},
|
||||
|
||||
-- Mason tool installer for linters/formatters
|
||||
{
|
||||
"WhoIsSethDaniel/mason-tool-installer.nvim",
|
||||
dependencies = { "williamboman/mason.nvim" },
|
||||
cmd = { "MasonToolsInstall", "MasonToolsUpdate" },
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
-- Formatters
|
||||
"stylua",
|
||||
"rustfmt",
|
||||
"taplo",
|
||||
-- Linters
|
||||
"stylelint",
|
||||
"markdownlint",
|
||||
-- Note: oxlint and oxfmt should be installed via cargo/npm separately
|
||||
},
|
||||
auto_update = false,
|
||||
run_on_start = true,
|
||||
},
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- Package Management Tools
|
||||
-- ============================================================================
|
||||
{
|
||||
"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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- ============================================================================
|
||||
-- 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 = "<C-t>",
|
||||
ptogglemode = "z,",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
--- Provides enhanced buffer/tab management with diagnostics and custom close handlers
|
||||
--- @module plugins.bufferline
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
"akinsho/bufferline.nvim",
|
||||
version = "*",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
--- Includes support for bun, vite, and modern JS tooling
|
||||
--- @module plugins.buildtools
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
-- Vim support for various config files
|
||||
{
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
--- Claude Code integration for AI-powered development
|
||||
--- Provides commands and keybindings for Claude Code assistant
|
||||
--- @module plugins.claude
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
"coder/claudecode.nvim",
|
||||
dependencies = { "folke/snacks.nvim" },
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
--- Linting and formatting configuration
|
||||
--- Includes oxlint and oxfmt integration
|
||||
--- @module plugins.linting
|
||||
|
||||
return {
|
||||
-- Conform for formatting
|
||||
{
|
||||
"stevearc/conform.nvim",
|
||||
event = "BufWritePre",
|
||||
cmd = { "ConformInfo" },
|
||||
opts = {
|
||||
formatters_by_ft = {
|
||||
typescript = { "oxfmt" },
|
||||
typescriptreact = { "oxfmt" },
|
||||
javascript = { "oxfmt" },
|
||||
javascriptreact = { "oxfmt" },
|
||||
json = { "oxfmt" },
|
||||
jsonc = { "oxfmt" },
|
||||
css = { "oxfmt" },
|
||||
scss = { "oxfmt" },
|
||||
html = { "oxfmt" },
|
||||
markdown = { "oxfmt" },
|
||||
yaml = { "oxfmt" },
|
||||
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 = {
|
||||
-- oxfmt uses default configuration
|
||||
},
|
||||
},
|
||||
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
|
||||
"stylua",
|
||||
"rustfmt",
|
||||
"taplo",
|
||||
-- Linters
|
||||
"stylelint",
|
||||
"markdownlint",
|
||||
-- Note: oxlint and oxfmt 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 = "<C-t>",
|
||||
ptogglemode = "z,",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
local ignore_patterns = require "config.ignore_patterns"
|
||||
local terminals = require "config.terminals"
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
{
|
||||
"neo-tree.nvim",
|
||||
@@ -65,12 +66,14 @@ return {
|
||||
event = events.FILE_MOVED,
|
||||
handler = function(args)
|
||||
require("astrolsp.file_operations").didRenameFiles { from = args.source, to = args.destination }
|
||||
require("snacks").rename.on_rename_file(args.source, args.destination)
|
||||
end,
|
||||
},
|
||||
{
|
||||
event = events.FILE_RENAMED,
|
||||
handler = function(args)
|
||||
require("astrolsp.file_operations").didRenameFiles { from = args.source, to = args.destination }
|
||||
require("snacks").rename.on_rename_file(args.source, args.destination)
|
||||
end,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
--- 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,
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
--- Template.nvim integration for quick file scaffolding
|
||||
--- Provides templates for Cosmos SDK, Protobuf, and Vite+Cloudflare development
|
||||
--- @module plugins.template
|
||||
|
||||
---@type LazySpec
|
||||
return {
|
||||
"glepnir/template.nvim",
|
||||
cmd = { "Template", "TemProject" },
|
||||
dependencies = { "folke/snacks.nvim" },
|
||||
config = function()
|
||||
local template = require "template"
|
||||
|
||||
-- Setup template.nvim
|
||||
template.setup {
|
||||
temp_dir = vim.fn.stdpath "config" .. "/templates",
|
||||
author = "Prad",
|
||||
email = "prad@sonr.io",
|
||||
}
|
||||
|
||||
-- Custom template picker using Snacks
|
||||
vim.api.nvim_create_user_command("TemplateSnacks", function(opts)
|
||||
local temp_dir = vim.fn.stdpath "config" .. "/templates"
|
||||
local current_ft = vim.bo.filetype
|
||||
|
||||
-- Find all template files
|
||||
local template_files = vim.fn.globpath(temp_dir, "**/*", false, true)
|
||||
|
||||
-- Filter and format templates
|
||||
local templates = {}
|
||||
for _, file in ipairs(template_files) do
|
||||
if vim.fn.isdirectory(file) == 0 then
|
||||
local filename = vim.fn.fnamemodify(file, ":t")
|
||||
local relative_path = vim.fn.fnamemodify(file, ":~:.")
|
||||
local category = vim.fn.fnamemodify(file, ":h:t")
|
||||
|
||||
-- Extract filetype from template
|
||||
local ext = vim.fn.fnamemodify(file, ":e")
|
||||
if ext == "tpl" then
|
||||
-- Read first line to get filetype marker
|
||||
local first_line = vim.fn.readfile(file, "", 1)[1] or ""
|
||||
ext = first_line:match "^;; (%w+)" or ext
|
||||
end
|
||||
|
||||
-- Filter by current filetype if specified
|
||||
local should_include = true
|
||||
if opts.args == "" and current_ft ~= "" then
|
||||
-- Only filter if we have a current filetype and no args
|
||||
should_include = ext == current_ft or ext == "tpl"
|
||||
end
|
||||
|
||||
if should_include then
|
||||
table.insert(templates, {
|
||||
text = string.format("[%s] %s", category, filename),
|
||||
path = file,
|
||||
filename = filename,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #templates == 0 then
|
||||
vim.notify("No templates found", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
-- Use Snacks picker
|
||||
require("snacks").picker.pick {
|
||||
items = templates,
|
||||
format = function(item) return item.text end,
|
||||
confirm = function(item)
|
||||
if not item then return end
|
||||
|
||||
-- Read template content
|
||||
local content = vim.fn.readfile(item.path)
|
||||
|
||||
-- Process template variables
|
||||
local processed = {}
|
||||
local needs_variable = false
|
||||
local variable_name = nil
|
||||
|
||||
for _, line in ipairs(content) do
|
||||
-- Skip filetype marker line
|
||||
if not line:match "^;; %w+" then
|
||||
-- Check for variable placeholder
|
||||
if line:match "{{_variable_}}" and not variable_name then
|
||||
needs_variable = true
|
||||
end
|
||||
table.insert(processed, line)
|
||||
end
|
||||
end
|
||||
|
||||
-- Prompt for variable if needed
|
||||
if needs_variable then
|
||||
require("snacks").input({ prompt = "Variable name:" }, function(input)
|
||||
if not input then return end
|
||||
variable_name = input
|
||||
|
||||
-- Replace variable in content
|
||||
for i, line in ipairs(processed) do
|
||||
processed[i] = line:gsub("{{_variable_}}", variable_name)
|
||||
end
|
||||
|
||||
-- Insert template
|
||||
insert_template(processed)
|
||||
end)
|
||||
else
|
||||
insert_template(processed)
|
||||
end
|
||||
end,
|
||||
}
|
||||
end, { nargs = "?", desc = "Open template picker" })
|
||||
|
||||
-- Helper function to insert template
|
||||
function insert_template(lines)
|
||||
local cursor_line = nil
|
||||
local processed = {}
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
-- Replace template markers
|
||||
line = line:gsub("{{_date_}}", os.date "%Y-%m-%d %H:%M:%S")
|
||||
line = line:gsub("{{_author_}}", "Prad")
|
||||
line = line:gsub("{{_email_}}", "prad@sonr.io")
|
||||
line = line:gsub("{{_file_name_}}", vim.fn.expand "%:t:r")
|
||||
line = line:gsub("{{_upper_file_}}", vim.fn.expand("%:t:r"):upper())
|
||||
|
||||
-- Convert snake_case to CamelCase
|
||||
local file_name = vim.fn.expand "%:t:r"
|
||||
local camel_case = file_name:gsub("_(%w)", function(c) return c:upper() end)
|
||||
camel_case = camel_case:gsub("^%w", string.upper)
|
||||
line = line:gsub("{{_camel_case_file_}}", camel_case)
|
||||
|
||||
-- Handle lua expressions
|
||||
line = line:gsub("{{_lua:(.-)_}}", function(expr)
|
||||
local func, err = load("return " .. expr)
|
||||
if func then
|
||||
local ok, result = pcall(func)
|
||||
if ok then return tostring(result) end
|
||||
end
|
||||
return ""
|
||||
end)
|
||||
|
||||
-- Track cursor position
|
||||
if line:match "{{_cursor_}}" then
|
||||
cursor_line = i
|
||||
line = line:gsub("{{_cursor_}}", "")
|
||||
end
|
||||
|
||||
table.insert(processed, line)
|
||||
end
|
||||
|
||||
-- Insert lines at cursor
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
vim.api.nvim_buf_set_lines(0, row - 1, row - 1, false, processed)
|
||||
|
||||
-- Set cursor position if marker found
|
||||
if cursor_line then
|
||||
vim.api.nvim_win_set_cursor(0, { row + cursor_line - 1, 0 })
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
--- 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" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- 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",
|
||||
"jsonls",
|
||||
})
|
||||
end,
|
||||
},
|
||||
-- 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in new issue
Block a user