Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions claude/.claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"enabledPlugins": {
"lua-lsp@claude-plugins-official": true
}
}
90 changes: 81 additions & 9 deletions nvim/.config/nvim/after/plugin/conform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,89 @@ if vim.g.vscode then
return
end

require("conform").setup({
format_on_save = {
-- These options will be passed to conform.format()
timeout_ms = 500,
lsp_format = "fallback",
local util = require("conform.util")
local vite_plus = require("greg.vite_plus")

-- vp fmt evaluates vite.config.ts and applies the fmt block. oxfmt LSP cannot load
-- vite.config.ts files that contain functions (e.g. lazyPlugins).
require("conform").formatters.vp_fmt = {
meta = {
url = "https://viteplus.dev",
description = "Vite+ formatter via vp fmt (vite.config.ts fmt block)",
},
command = util.from_node_modules("vp"),
args = { "fmt", "--stdin-filepath", "$FILENAME" },
stdin = true,
cwd = function(_, ctx)
return vim.fs.root(ctx.dirname, { "vite.config.ts", "vite.config.mts", "package.json" })
end,
}

---@param bufnr integer
---@return boolean
local function is_js_ts_buf(bufnr)
local ft = vim.bo[bufnr].filetype
return ft == "typescript" or ft == "typescriptreact" or ft == "javascript" or ft == "javascriptreact"
end

---@param bufnr integer
---@return boolean
local function use_vp_fmt(bufnr)
return vite_plus.is_project(bufnr) and is_js_ts_buf(bufnr)
end

---@param bufnr integer
---@return string|nil project_root
local function js_ts_root(bufnr)
local name = vim.api.nvim_buf_get_name(bufnr)
if name == "" then
return nil
end
return vim.fs.root(name, { "package.json", "prettier.config.js", "prettier.config.mjs", ".prettierrc" })
end

---@param root string
---@return boolean
local function has_local_prettier(root)
return vim.fn.executable(root .. "/node_modules/.bin/prettier") == 1
end

---@param bufnr integer
---@return conform.FiletypeFormatter
local function js_ts_formatters(bufnr)
if vite_plus.is_project(bufnr) then
return { "vp_fmt", lsp_format = "never", timeout_ms = 5000 }
end

-- Prefer project prettier (MilkTea, etc.). Global prettierd comes from fnm/npm, not
-- brew — Homebrew prettierd shebangs break once node lives under fnm.
local root = js_ts_root(bufnr)
if root and has_local_prettier(root) then
return { "prettier", lsp_format = "never" }
end

return { "prettierd", "prettier", lsp_format = "never" }
end

require("conform").setup({
-- vp fmt shells out (~100ms+); run async after save so :w does not block the UI.
format_on_save = function(bufnr)
if use_vp_fmt(bufnr) then
return nil
end
return { timeout_ms = 500 }
end,
format_after_save = function(bufnr)
if not use_vp_fmt(bufnr) then
return nil
end
return { timeout_ms = 5000, async = true }
end,
formatters_by_ft = {
lua = { "stylua" },
typescript = { "prettierd", "prettier", stop_after_first = true },
typescriptreact = { "prettierd", "prettier", stop_after_first = true },
javascript = { "prettierd", "prettier", stop_after_first = true },
javascriptreact = { "prettierd", "prettier", stop_after_first = true },
typescript = js_ts_formatters,
typescriptreact = js_ts_formatters,
javascript = js_ts_formatters,
javascriptreact = js_ts_formatters,
},
})
44 changes: 33 additions & 11 deletions nvim/.config/nvim/after/plugin/none-ls.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,39 @@ end

local null_ls = require("null-ls")

null_ls.setup({
sources = {
null_ls.builtins.formatting.stylua,
null_ls.builtins.completion.spell,
-- requires none-ls-extras.nvim
require("none-ls.diagnostics.eslint_d"),
-- requires none-ls-shellcheck.nvim
require("none-ls-shellcheck.diagnostics"),
require("none-ls-shellcheck.code_actions"),
},
})
local eslint_config_files = {
"eslint.config.js",
"eslint.config.mjs",
"eslint.config.cjs",
"eslint.config.ts",
".eslintrc",
".eslintrc.js",
".eslintrc.json",
".eslintrc.cjs",
".eslintrc.yaml",
".eslintrc.yml",
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

local sources = {
null_ls.builtins.formatting.stylua,
null_ls.builtins.completion.spell,
-- requires none-ls-shellcheck.nvim
require("none-ls-shellcheck.diagnostics"),
require("none-ls-shellcheck.code_actions"),
}

-- Only run eslint_d when an ESLint config exists at the project root.
-- Avoids JSON-decode errors in Vite+ / oxlint-only repos that have no ESLint config.
table.insert(
sources,
require("none-ls.diagnostics.eslint_d").with({
condition = function(utils)
return utils.root_has_file(eslint_config_files)
end,
})
)

null_ls.setup({ sources = sources })

-- Display code actions.
vim.keymap.set("n", "<C-m>", vim.lsp.buf.code_action, { desc = "Code action" })
20 changes: 20 additions & 0 deletions nvim/.config/nvim/after/plugin/oxc.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
if vim.g.vscode then
return
end

-- Oxlint via native LSP. oxfmt LSP stays enabled for non-TS assets; Vite+ TS/JS
-- formatting uses conform's vp_fmt formatter (see after/plugin/conform.lua).

vim.lsp.config("oxlint", {
init_options = {
settings = {
run = "onType",
fixKind = "safe_fix",
},
},
})

vim.lsp.enable("oxlint")
vim.lsp.enable("oxfmt")

vim.keymap.set("n", "<leader>xl", "<cmd>LspOxlintFixAll<CR>", { desc = "Oxlint fix all" })
2 changes: 1 addition & 1 deletion nvim/.config/nvim/lua/greg/pack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ vim.pack.add({

{ src = gh("williamboman/mason.nvim"), version = "cb8445f8ce85d957416c106b780efd51c6298f89" },
{ src = gh("williamboman/mason-lspconfig.nvim"), version = "0c2823e0418f3d9230ff8b201c976e84de1cb401" },
{ src = gh("neovim/nvim-lspconfig"), version = "31026a13eefb20681124706a79fc1df6bf11ab27" },
{ src = gh("neovim/nvim-lspconfig"), version = "bfcc0171a43f22afa61d927ffe9fcb6cb85dc99e" },
{ src = gh("hrsh7th/nvim-cmp"), version = "a1d504892f2bc56c2e79b65c6faded2fd21f3eca" },
{ src = gh("hrsh7th/cmp-nvim-lsp"), version = "cbc7b02bb99fae35cb42f514762b89b5126651ef" },
{ src = gh("L3MON4D3/LuaSnip"), version = "a62e1083a3cfe8b6b206e7d3d33a51091df25357" },
Expand Down
47 changes: 47 additions & 0 deletions nvim/.config/nvim/lua/greg/vite_plus.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
local M = {}

---@param bufnr integer
---@return boolean
function M.is_project(bufnr)
local name = vim.api.nvim_buf_get_name(bufnr)
if name == "" then
return false
end

local root = vim.fs.root(name, { "vite.config.ts", "vite.config.mts", "package.json" })
if not root then
return false
end

local pkg_path = root .. "/package.json"
if vim.fn.filereadable(pkg_path) == 1 then
local ok, data = pcall(vim.json.decode, table.concat(vim.fn.readfile(pkg_path), "\n"))
if ok and type(data) == "table" then
for _, key in ipairs({ "dependencies", "devDependencies" }) do
local deps = data[key]
if type(deps) == "table" and deps["vite-plus"] then
return true
end
end
local overrides = data.overrides
if type(overrides) == "table" and type(overrides.vite) == "string" and overrides.vite:find("vite%-plus") then
return true
end
end
end

for _, filename in ipairs({ "vite.config.ts", "vite.config.mts" }) do
local vite_config = root .. "/" .. filename
if vim.fn.filereadable(vite_config) == 1 then
for _, line in ipairs(vim.fn.readfile(vite_config)) do
if line:find("vite%-plus") then
return true
end
end
end
end

return false
end

return M
4 changes: 2 additions & 2 deletions nvim/.config/nvim/nvim-pack-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@
"version": "'a1d504892f2bc56c2e79b65c6faded2fd21f3eca'"
},
"nvim-lspconfig": {
"rev": "31026a13eefb20681124706a79fc1df6bf11ab27",
"rev": "bfcc0171a43f22afa61d927ffe9fcb6cb85dc99e",
"src": "https://github.com/neovim/nvim-lspconfig",
"version": "'31026a13eefb20681124706a79fc1df6bf11ab27'"
"version": "'bfcc0171a43f22afa61d927ffe9fcb6cb85dc99e'"
},
"nvim-transparent": {
"rev": "8ac59883de84e9cd1850ea25cf087031c5ba7d54",
Expand Down
2 changes: 1 addition & 1 deletion scripts/brews.sh
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ install_python_dev_packages() {

# JavaScript/Node.js developement.
install_javascript_packages() {
prompt_and_install_shell "JavaScript packages" 'brew install fnm oven-sh/bun/bun pnpm fsouza/prettierd/prettierd && fnm install 22 && npm install -g eslint_d typescript-language-server typescript'
prompt_and_install_shell "JavaScript packages" 'brew install fnm oven-sh/bun/bun pnpm && fnm install --lts && fnm default lts-latest && eval "$(fnm env)" && npm install -g @fsouza/prettierd eslint_d@15 typescript-language-server typescript'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In current fnm releases, is fnm default lts-latesta supported way to set the default Node.js version to latest LTS? If not, what is the recommended command sequence afterfnm install --lts?

💡 Result:

No, fnm default lts-latest is not a supported command for setting the default Node.js version [1]. The fnm default command expects a specific version number (e.g., 20 or 22.13.1) to set as the global default [2][3][4]. To set the default Node.js version to the latest LTS after installing it, you should follow this sequence: 1. Install the latest LTS version: fnm install --lts 2. Identify the specific version that was just installed: fnm list 3. Set that specific version as the default: fnm default <VERSION_NUMBER> (Replace <VERSION_NUMBER> with the version identified in step 2, such as 22.13.1.) The fnm default command functions as a shorthand for creating an alias named default [5][2]. Because lts-latest is not a resolvable version string within the fnm default command's logic, attempting to use it will result in an error [1].

Citations:


Fix fnm default lts-latest on line 193 — this command is unsupported and will fail.

The fnm default command requires an explicit version number (e.g., 20 or 22.13.1), not lts-latest. After fnm install --lts, you must identify the installed version and set it explicitly. Replace:

fnm install --lts && fnm default lts-latest && eval "$(fnm env)"

with:

fnm install --lts && fnm default "$(fnm list | grep -v default | head -1)" && eval "$(fnm env)"

Or better, assign to a variable first to ensure clarity and robustness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/brews.sh` at line 193, The `fnm default lts-latest` command in the
JavaScript packages installation block within the `prompt_and_install_shell`
function call is invalid because `fnm default` requires an explicit version
number, not `lts-latest`. After running `fnm install --lts`, extract the
installed version using `fnm list` and pass the result explicitly to `fnm
default`. You can use command substitution to get the installed version (for
example, by filtering the list output and selecting the first matching version)
and pass it to `fnm default` instead of the literal `lts-latest` string.

}

# Gleam.
Expand Down
6 changes: 4 additions & 2 deletions scripts/pacs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ install_lua_packages() {
install_javascript_packages() {
prompt_and_install "JavaScript packages" 'pacman -S nodejs npm &&\
npm install -g fnm &&\
fnm install 22 &&\
npm install -g eslint_d\
fnm install --lts &&\
fnm default lts-latest &&\
eval "$(fnm env)" &&\
npm install -g @fsouza/prettierd eslint_d@15\
typescript-language-server\
typescript'
}
Expand Down