From eec71b5f82c887ed2ab2bd354eb41de2860445a1 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Sun, 12 Jul 2026 18:49:36 -0700 Subject: [PATCH 1/8] Add gitea-pr script and PR review workflow (#1) Adds bin/gitea-pr script for gitea PR workflow. Reviewed-on: https://gitbox.branderson.io/branderson/dotfiles/pulls/1 Co-authored-by: Brad Anderson Co-committed-by: Brad Anderson --- bin/gitea-pr | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100755 bin/gitea-pr diff --git a/bin/gitea-pr b/bin/gitea-pr new file mode 100755 index 0000000..634eced --- /dev/null +++ b/bin/gitea-pr @@ -0,0 +1,189 @@ +#!/bin/bash +set -euo pipefail + +GITEA_TOKEN_FILE="${GITEA_TOKEN_FILE:-$HOME/.config/gitea/token}" + +function usage() { + echo "Usage: gitea-pr create [--title TITLE] [--body BODY] [--base BRANCH]" + echo " gitea-pr comments PR_NUMBER" + echo " gitea-pr merge PR_NUMBER" + echo "" + echo "Requires GITEA_SSH_HOST and GITEA_API set in the environment (e.g. in" \ + "your shell profile), and a token at $GITEA_TOKEN_FILE (or GITEA_TOKEN" \ + "set for this invocation only)." +} + +function require_config() { + if [ -z "${GITEA_SSH_HOST:-}" ]; then + echo "GITEA_SSH_HOST is not set. Add 'export GITEA_SSH_HOST='" \ + "(e.g. gitbox.bradina.localdomain) to ~/.profile.local" >&2 + exit 1 + fi + if [ -z "${GITEA_API:-}" ]; then + echo "GITEA_API is not set. Add 'export GITEA_API=https:///api/v1'" \ + "(e.g. https://gitbox.branderson.io/api/v1) to ~/.profile.local" >&2 + exit 1 + fi +} + +function require_token() { + if [ -z "${GITEA_TOKEN:-}" ] && [ -f "$GITEA_TOKEN_FILE" ]; then + GITEA_TOKEN=$(<"$GITEA_TOKEN_FILE") + fi + if [ -z "${GITEA_TOKEN:-}" ]; then + echo "No Gitea token found. Generate one in the Gitea web UI" \ + "(Settings > Applications, scopes write:repository + write:issue)" \ + "and save it to $GITEA_TOKEN_FILE (chmod 600), or set GITEA_TOKEN" \ + "in the environment for this invocation only." >&2 + exit 1 + fi +} + +function gitea_owner_repo() { + local remote_url host owner_repo + remote_url=$(git remote get-url origin 2>/dev/null) || { + echo "No 'origin' remote found in this repository" >&2 + exit 1 + } + host=$(echo "$remote_url" | sed -E 's#^[^@]+@([^:]+):.*#\1#') + if [ "$host" != "$GITEA_SSH_HOST" ]; then + echo "origin remote ($remote_url) is not on $GITEA_SSH_HOST; gitea-pr only supports this host" >&2 + exit 1 + fi + owner_repo=$(echo "$remote_url" | sed -E 's#^[^@]+@[^:]+:##; s#\.git$##') + echo "$owner_repo" +} + +if [ "$#" -lt 1 ]; then + usage + exit 1 +fi + +subcommand="$1" +shift + +case "$subcommand" in + create|comments|merge) + require_config + require_token + owner_repo=$(gitea_owner_repo) + owner="${owner_repo%%/*}" + repo="${owner_repo##*/}" + ;; + *) + usage + exit 1 + ;; +esac + +case "$subcommand" in + create) + title="" + body="" + base="" + while [ "$#" -gt 0 ]; do + case "$1" in + --title) title="$2"; shift 2 ;; + --body) body="$2"; shift 2 ;; + --base) base="$2"; shift 2 ;; + *) echo "Unknown option: $1" >&2; usage; exit 1 ;; + esac + done + + current_branch=$(git rev-parse --abbrev-ref HEAD) + if [ "$current_branch" = "HEAD" ]; then + echo "Detached HEAD: check out the feature branch before creating a PR" >&2 + exit 1 + fi + if [ -z "$base" ]; then + base=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's#refs/remotes/origin/##' || true) + base="${base:-main}" + fi + if [ -z "$title" ]; then + title="$current_branch" + fi + + response=$(curl -sS -w '\n%{http_code}' -X POST "${GITEA_API}/repos/${owner}/${repo}/pulls" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "$(jq -n --arg head "$current_branch" --arg base "$base" --arg title "$title" --arg body "$body" \ + '{head: $head, base: $base, title: $title, body: $body}')") + http_code=$(echo "$response" | tail -1) + json=$(echo "$response" | sed '$d') + + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to create PR (HTTP $http_code):" >&2 + echo "$json" >&2 + exit 1 + fi + echo "$json" | jq -r '.html_url' + ;; + comments) + pr_number="${1:-}" + if [ -z "$pr_number" ]; then + echo "Usage: gitea-pr comments PR_NUMBER" >&2 + exit 1 + fi + + echo "=== Issue comments ===" + response=$(curl -sS -w '\n%{http_code}' "${GITEA_API}/repos/${owner}/${repo}/issues/${pr_number}/comments" \ + -H "Authorization: token ${GITEA_TOKEN}") + http_code=$(echo "$response" | tail -1) + json=$(echo "$response" | sed '$d') + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to fetch issue comments (HTTP $http_code):" >&2 + echo "$json" >&2 + exit 1 + fi + echo "$json" | jq -r '.[] | "[\(.user.login) @ \(.created_at)]\n\(.body)\n"' + + echo "=== Reviews ===" + response=$(curl -sS -w '\n%{http_code}' "${GITEA_API}/repos/${owner}/${repo}/pulls/${pr_number}/reviews" \ + -H "Authorization: token ${GITEA_TOKEN}") + http_code=$(echo "$response" | tail -1) + reviews_json=$(echo "$response" | sed '$d') + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to fetch reviews (HTTP $http_code):" >&2 + echo "$reviews_json" >&2 + exit 1 + fi + echo "$reviews_json" | jq -r '.[] | select(.body != "") | "[\(.user.login) @ \(.submitted_at) — \(.state)]\n\(.body)\n"' + + echo "=== Inline review comments ===" + review_ids=$(echo "$reviews_json" | jq -r '.[] | select(.comments_count > 0) | .id') + for review_id in $review_ids; do + response=$(curl -sS -w '\n%{http_code}' \ + "${GITEA_API}/repos/${owner}/${repo}/pulls/${pr_number}/reviews/${review_id}/comments" \ + -H "Authorization: token ${GITEA_TOKEN}") + http_code=$(echo "$response" | tail -1) + json=$(echo "$response" | sed '$d') + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to fetch comments for review ${review_id} (HTTP $http_code):" >&2 + echo "$json" >&2 + exit 1 + fi + echo "$json" | jq -r '.[] | "[\(.user.login) @ \(.path):\(.line // "?")]\n\(.body)\n"' + done + ;; + merge) + pr_number="${1:-}" + if [ -z "$pr_number" ]; then + echo "Usage: gitea-pr merge PR_NUMBER" >&2 + exit 1 + fi + + response=$(curl -sS -w '\n%{http_code}' -X POST "${GITEA_API}/repos/${owner}/${repo}/pulls/${pr_number}/merge" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"Do": "merge"}') + http_code=$(echo "$response" | tail -1) + json=$(echo "$response" | sed '$d') + + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to merge PR #${pr_number} (HTTP $http_code):" >&2 + echo "$json" >&2 + exit 1 + fi + echo "Merged PR #${pr_number}" + ;; +esac From 567d0a171804c97a5826ef5be9e4f585ca631331 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Sun, 12 Jul 2026 22:04:33 -0700 Subject: [PATCH 2/8] Skip creating a duplicate PR when one is already open for the branch gitea-pr create now checks for an existing open PR on the current branch first and returns its URL instead of creating a new one. Only matches open PRs by design -- once merged, new commits on the same branch correctly get a new PR. --- bin/gitea-pr | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bin/gitea-pr b/bin/gitea-pr index 634eced..b8a4662 100755 --- a/bin/gitea-pr +++ b/bin/gitea-pr @@ -95,6 +95,23 @@ case "$subcommand" in echo "Detached HEAD: check out the feature branch before creating a PR" >&2 exit 1 fi + + response=$(curl -sS -w '\n%{http_code}' "${GITEA_API}/repos/${owner}/${repo}/pulls?state=open" \ + -H "Authorization: token ${GITEA_TOKEN}") + http_code=$(echo "$response" | tail -1) + json=$(echo "$response" | sed '$d') + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "Failed to check for an existing PR (HTTP $http_code):" >&2 + echo "$json" >&2 + exit 1 + fi + existing_url=$(echo "$json" | jq -r --arg head "$current_branch" \ + '.[] | select(.head.ref == $head) | .html_url' | head -1) + if [ -n "$existing_url" ]; then + echo "$existing_url" + exit 0 + fi + if [ -z "$base" ]; then base=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's#refs/remotes/origin/##' || true) base="${base:-main}" From 06e60bda8c0d2a556ee670f671c958156d0db2fb Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Sun, 12 Jul 2026 22:14:02 -0700 Subject: [PATCH 3/8] Match existing-PR check on base branch too, not just head The lookup was matching on head.ref alone, so running create with a different --base for the same branch would silently return an unrelated PR's URL instead of opening a new one. Resolve base before the check and filter on both head.ref and base.ref. --- bin/gitea-pr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/gitea-pr b/bin/gitea-pr index b8a4662..234750f 100755 --- a/bin/gitea-pr +++ b/bin/gitea-pr @@ -96,6 +96,11 @@ case "$subcommand" in exit 1 fi + if [ -z "$base" ]; then + base=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's#refs/remotes/origin/##' || true) + base="${base:-main}" + fi + response=$(curl -sS -w '\n%{http_code}' "${GITEA_API}/repos/${owner}/${repo}/pulls?state=open" \ -H "Authorization: token ${GITEA_TOKEN}") http_code=$(echo "$response" | tail -1) @@ -105,17 +110,12 @@ case "$subcommand" in echo "$json" >&2 exit 1 fi - existing_url=$(echo "$json" | jq -r --arg head "$current_branch" \ - '.[] | select(.head.ref == $head) | .html_url' | head -1) + existing_url=$(echo "$json" | jq -r --arg head "$current_branch" --arg base "$base" \ + '.[] | select(.head.ref == $head and .base.ref == $base) | .html_url' | head -1) if [ -n "$existing_url" ]; then echo "$existing_url" exit 0 fi - - if [ -z "$base" ]; then - base=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's#refs/remotes/origin/##' || true) - base="${base:-main}" - fi if [ -z "$title" ]; then title="$current_branch" fi From 46ca53e0c006c59ab447acf6179b8df4c04a9a10 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Mon, 13 Jul 2026 18:09:43 -0700 Subject: [PATCH 4/8] Prevent runaway claude-code --- .gitignore | 1 + config/zshrc | 13 +++++++++++++ packages/apt.global | 2 ++ 3 files changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index 61f9f25..228c29f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ config/icons config/VSCodium dependencies/dotfiles-local packages/*.local +.claude diff --git a/config/zshrc b/config/zshrc index 5dedcf7..4acc14a 100755 --- a/config/zshrc +++ b/config/zshrc @@ -186,6 +186,19 @@ fi # Tool options export SHELLCHECK_OPTS="-e SC2029 -e SC2155" +# Limit claude-code: cap CPU/memory/process count so a runaway subprocess +# (or its children, e.g. from the Bash tool) can't overheat the laptop. +# Adjust the -p values if these limits are ever too tight. +if program_installed claude && program_installed systemd-run; then + claude() { + systemd-run --user --scope --quiet \ + -p CPUQuota=50% \ + -p MemoryMax=6G \ + -p TasksMax=512 \ + -- command claude "$@" + } +fi + # Syntax highlighting if [ -f /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]; then source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh diff --git a/packages/apt.global b/packages/apt.global index fd493cf..d12d3f4 100644 --- a/packages/apt.global +++ b/packages/apt.global @@ -11,6 +11,8 @@ npm tree-sitter-cli ripgrep shellcheck +bubblewrap +socat # Useless stuff fortune-mod From d0a4cb0db79f3a5674454cc076c311cf4d1df158 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Mon, 13 Jul 2026 18:28:08 -0700 Subject: [PATCH 5/8] Add authorship disclaimer to LLM generated PR summaries --- bin/gitea-pr | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/gitea-pr b/bin/gitea-pr index 234750f..efca63f 100755 --- a/bin/gitea-pr +++ b/bin/gitea-pr @@ -89,6 +89,9 @@ case "$subcommand" in *) echo "Unknown option: $1" >&2; usage; exit 1 ;; esac done + body="**Summary generated by LLM agent** + +${body}" current_branch=$(git rev-parse --abbrev-ref HEAD) if [ "$current_branch" = "HEAD" ]; then From 9ffe7544103314aeb8ab0a3ff3d692172b55bd88 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 14 Jul 2026 13:48:36 -0700 Subject: [PATCH 6/8] Add claude gruvbox theme, fix nvim errors with custom npm --- config/claude/themes/gruvbox.json | 30 ++++++++++++++++++++++++++++++ config/nvim/lazy-lock.json | 2 +- config/nvim/lua/plugins/lsp.lua | 12 ++++++++++-- install.sh | 1 + packages/brew.global | 5 ++++- 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 config/claude/themes/gruvbox.json diff --git a/config/claude/themes/gruvbox.json b/config/claude/themes/gruvbox.json new file mode 100644 index 0000000..688282d --- /dev/null +++ b/config/claude/themes/gruvbox.json @@ -0,0 +1,30 @@ +{ + "name": "Gruvbox Dark", + "base": "dark", + "overrides": { + "claude": "#d3869b", + "text": "#ebdbb2", + "inactive": "#665c54", + "subtle": "#7c6f64", + "muted": "#928374", + "success": "#b8bb26", + "error": "#fb4934", + "warning": "#fabd2f", + "link": "#83a598", + "highlight": "#fabd2f", + "selection": "#504945", + "diffAdded": "#b8bb26", + "diffRemoved": "#fb4934", + "promptBorder": "#504945", + "bashBorder": "#504945", + "mcpBorder": "#504945", + "planMode": "#83a598", + "spinner": "#d3869b", + "header": "#8ec07c", + "separator": "#3c3836", + "badge": "#fe8019", + "permission": "#fe8019", + "suggestion": "#8ec07c", + "fastMode": "#fabd2f" + } +} diff --git a/config/nvim/lazy-lock.json b/config/nvim/lazy-lock.json index 4275985..a76c6e1 100644 --- a/config/nvim/lazy-lock.json +++ b/config/nvim/lazy-lock.json @@ -11,7 +11,7 @@ "gitsigns.nvim": { "branch": "main", "commit": "eb60cc7b94c46005237fd34170d76f3a089a90aa" }, "gruvbox.nvim": { "branch": "main", "commit": "154eb5ff5b96d0641307113fa385eaf0d36d9796" }, "indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" }, - "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, "lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" }, "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, "mason-lspconfig.nvim": { "branch": "main", "commit": "47059d71b42d74b0a1e9f61c1d99d301039c3b5b" }, diff --git a/config/nvim/lua/plugins/lsp.lua b/config/nvim/lua/plugins/lsp.lua index f0df15c..00d97db 100644 --- a/config/nvim/lua/plugins/lsp.lua +++ b/config/nvim/lua/plugins/lsp.lua @@ -1,11 +1,19 @@ local servers = { "basedpyright", "ruff" } local npm_servers = { "ts_ls", "svelte", "html", "cssls", "bashls" } -if vim.fn.executable("npm") == 1 then +local function has_public_npm() + if vim.fn.executable("npm") ~= 1 then + return false + end + local result = vim.fn.system("npm config get registry") + return result:find("registry.npmjs.org") ~= nil +end + +if has_public_npm() then vim.list_extend(servers, npm_servers) else vim.notify( - "npm not found: skipping LSP servers " .. table.concat(npm_servers, ", "), + "public npm registry unavailable: skipping LSP servers " .. table.concat(npm_servers, ", "), vim.log.levels.WARN ) end diff --git a/install.sh b/install.sh index 1cbb236..8b9dd3c 100755 --- a/install.sh +++ b/install.sh @@ -40,6 +40,7 @@ # mkdir ~/dotfiles/config/themes ~/dotfiles/config/icons # cp -r ~/dotfiles/dependencies/Gruvbox-GTK-Theme/themes/* ~/dotfiles/config/themes # cp -r ~/dotfiles/dependencies/Gruvbox-GTK-Theme/icons/* ~/dotfiles/config/icons +# cp -r ~/dotfiles/config/claude/themes/* ~/.claude/themes/ # TODO: Customize lightdm # Move some wallpaper assets into this repo diff --git a/packages/brew.global b/packages/brew.global index a1b69fb..c232998 100644 --- a/packages/brew.global +++ b/packages/brew.global @@ -1,4 +1,4 @@ -nvim +neovim coreutils tree ag @@ -10,3 +10,6 @@ fortune tmuxinator python pipx +tree-sitter-cli +ripgrep +shellcheck From 1deb25008fb41094ddc56ab5e51c29a7c2bfef39 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 14 Jul 2026 14:11:42 -0700 Subject: [PATCH 7/8] Make nvim installation helpers platform-aware and add local install helper for tree-sitter-cli --- config/nvim/init.lua | 31 +++++++++++++++----------- config/nvim/lua/plugins/treesitter.lua | 13 ++++++++++- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/config/nvim/init.lua b/config/nvim/init.lua index 3d39d05..4f5c786 100644 --- a/config/nvim/init.lua +++ b/config/nvim/init.lua @@ -30,23 +30,28 @@ if vim.fn.has("nvim-0.12") == 0 then os.exit(1) end - local asset = "nvim-linux-" .. asset_arch - vim.api.nvim_echo({ + local sysname = ((vim.loop.os_uname() or {}).sysname or ""):lower() + local is_mac = sysname == "darwin" + local asset = (is_mac and "nvim-macos-" or "nvim-linux-") .. asset_arch + + local lines = { { "This config requires Neovim 0.12.0 or newer (found " .. current .. ", " .. machine .. ").\n\n", "ErrorMsg" }, - { "Install a current build -- locally, no root needed:\n", "None" }, + { "Install a current build into ~/.local (no root needed):\n", "None" }, { " curl -LO https://github.com/neovim/neovim/releases/latest/download/" .. asset .. ".tar.gz\n", "None" }, - { " tar xzf " .. asset .. ".tar.gz\n", "None" }, - { " rm -rf ~/.local/nvim && mv " .. asset .. " ~/.local/nvim\n", "None" }, - { " mkdir -p ~/.local/bin && ln -sf ~/.local/nvim/bin/nvim ~/.local/bin/nvim\n", "None" }, + { " mkdir -p ~/.local && tar xzf " .. asset .. ".tar.gz --strip-components=1 -C ~/.local\n", "None" }, { " rm " .. asset .. ".tar.gz\n", "None" }, { " # then make sure ~/.local/bin is on your PATH\n\n", "Comment" }, - { "Or system-wide (needs root):\n", "None" }, - { " curl -LO https://github.com/neovim/neovim/releases/latest/download/" .. asset .. ".tar.gz\n", "None" }, - { " tar xzf " .. asset .. ".tar.gz\n", "None" }, - { " sudo rm -rf /opt/nvim && sudo mv " .. asset .. " /opt/nvim\n", "None" }, - { " sudo ln -sf /opt/nvim/bin/nvim /usr/local/bin/nvim\n", "None" }, - { " rm " .. asset .. ".tar.gz\n", "None" }, - }, true, {}) + } + if not is_mac then + vim.list_extend(lines, { + { "Or system-wide (needs root):\n", "None" }, + { " curl -LO https://github.com/neovim/neovim/releases/latest/download/" .. asset .. ".tar.gz\n", "None" }, + { " sudo mkdir -p /opt/nvim && sudo tar xzf " .. asset .. ".tar.gz --strip-components=1 -C /opt/nvim\n", "None" }, + { " sudo ln -sf /opt/nvim/bin/nvim /usr/local/bin/nvim\n", "None" }, + { " rm " .. asset .. ".tar.gz\n", "None" }, + }) + end + vim.api.nvim_echo(lines, true, {}) vim.fn.getchar() os.exit(1) end diff --git a/config/nvim/lua/plugins/treesitter.lua b/config/nvim/lua/plugins/treesitter.lua index 9827ffb..81a9ae8 100644 --- a/config/nvim/lua/plugins/treesitter.lua +++ b/config/nvim/lua/plugins/treesitter.lua @@ -30,8 +30,19 @@ return { if vim.fn.executable("tree-sitter") == 1 then require("nvim-treesitter").install(parsers) else + local uname = vim.uv.os_uname() + local sysname = (uname.sysname or ""):lower() + local machine = uname.machine or "" + local os_part = sysname == "darwin" and "macos" or "linux" + local arch_part = ({ x86_64 = "x64", amd64 = "x64", aarch64 = "arm64", arm64 = "arm64" })[machine] or "x64" + local asset = "tree-sitter-" .. os_part .. "-" .. arch_part + vim.notify( - "tree-sitter CLI not found: skipping install of missing parsers", + "tree-sitter CLI not found: skipping install of missing parsers.\n" + .. "Install into ~/.local/bin:\n" + .. " curl -L https://github.com/tree-sitter/tree-sitter/releases/latest/download/" + .. asset + .. ".gz | gunzip > ~/.local/bin/tree-sitter && chmod +x ~/.local/bin/tree-sitter", vim.log.levels.WARN ) end From b26e56467221e58db2a219ac5e06acab782f7369 Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Tue, 14 Jul 2026 14:23:06 -0700 Subject: [PATCH 8/8] Use cargo build instead of prebuilt binary for tree-sitter-cli manual install --- config/nvim/lua/plugins/treesitter.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/config/nvim/lua/plugins/treesitter.lua b/config/nvim/lua/plugins/treesitter.lua index 81a9ae8..9efb8a6 100644 --- a/config/nvim/lua/plugins/treesitter.lua +++ b/config/nvim/lua/plugins/treesitter.lua @@ -33,16 +33,23 @@ return { local uname = vim.uv.os_uname() local sysname = (uname.sysname or ""):lower() local machine = uname.machine or "" - local os_part = sysname == "darwin" and "macos" or "linux" - local arch_part = ({ x86_64 = "x64", amd64 = "x64", aarch64 = "arm64", arm64 = "arm64" })[machine] or "x64" - local asset = "tree-sitter-" .. os_part .. "-" .. arch_part + local is_mac = sysname == "darwin" + + local install_cmd + if is_mac then + local arch_part = ({ x86_64 = "x64", amd64 = "x64", aarch64 = "arm64", arm64 = "arm64" })[machine] or "x64" + local asset = "tree-sitter-macos-" .. arch_part + install_cmd = " curl -L https://github.com/tree-sitter/tree-sitter/releases/latest/download/" + .. asset + .. ".gz | gunzip > ~/.local/bin/tree-sitter && chmod +x ~/.local/bin/tree-sitter" + else + install_cmd = " cargo install --root ~/.local tree-sitter-cli" + end vim.notify( "tree-sitter CLI not found: skipping install of missing parsers.\n" .. "Install into ~/.local/bin:\n" - .. " curl -L https://github.com/tree-sitter/tree-sitter/releases/latest/download/" - .. asset - .. ".gz | gunzip > ~/.local/bin/tree-sitter && chmod +x ~/.local/bin/tree-sitter", + .. install_cmd, vim.log.levels.WARN ) end