Eric Bower
·
2026-09-08
1#!/usr/bin/env bash
2set -euo pipefail
3
4if ! command -v ctags >/dev/null 2>&1; then
5 echo "error: ctags not found in PATH" >&2
6 exit 1
7fi
8
9target=".tags_deps"
10generated=0
11
12# 1. Go modules
13if [[ -f "go.mod" ]] && command -v go >/dev/null 2>&1; then
14 echo "Resolving Go dependencies..."
15 go mod download 2>/dev/null || true
16 dirs="$(go list -m -f '{{if not .Main}}{{.Dir}}{{end}}' all 2>/dev/null | grep -v '^$' || true)"
17 if [[ -n "${dirs}" ]]; then
18 echo "Indexing Go dependencies into ${target}..."
19 flags=("-f" "${target}" "--languages=Go" "--exclude=testdata")
20 [[ $generated -eq 1 ]] && flags+=("-a")
21 echo "${dirs}" | ctags "${flags[@]}" -L -
22 generated=1
23 fi
24fi
25
26# 2. Zig dependencies (build.zig.zon)
27if [[ -f "build.zig.zon" ]]; then
28 echo "Resolving Zig dependencies..."
29 cache_p="${ZIG_GLOBAL_CACHE_DIR:-$HOME/.cache/zig}/p"
30 zig_dirs=()
31 if [[ -d "${cache_p}" ]]; then
32 while IFS= read -r hash; do
33 [[ -z "$hash" ]] && continue
34 for d in "${cache_p}"/*"${hash}"*; do
35 if [[ -d "$d" ]]; then
36 zig_dirs+=("$d")
37 fi
38 done
39 done < <(grep -oE '[0-9a-zA-Z_-]{40,}' build.zig.zon | sort -u)
40 fi
41
42 if [[ -d ".zig-cache/p" ]]; then
43 for d in .zig-cache/p/*; do
44 [[ -d "$d" ]] && zig_dirs+=("$d")
45 done
46 fi
47
48 if [[ ${#zig_dirs[@]} -gt 0 ]]; then
49 echo "Indexing ${#zig_dirs[@]} Zig dependencies into ${target}..."
50 flags=("-f" "${target}" "--languages=+Zig")
51 [[ $generated -eq 1 ]] && flags+=("-a")
52 printf "%s\n" "${zig_dirs[@]}" | ctags "${flags[@]}" -L -
53 generated=1
54 fi
55fi
56
57# 3. Python virtualenv
58venv_dir=""
59if [[ -n "${VIRTUAL_ENV:-}" && -d "${VIRTUAL_ENV}" ]]; then
60 venv_dir="${VIRTUAL_ENV}"
61elif [[ -d ".venv" ]]; then
62 venv_dir=".venv"
63elif [[ -d "venv" ]]; then
64 venv_dir="venv"
65fi
66
67if [[ -n "${venv_dir}" ]]; then
68 echo "Resolving Python dependencies from ${venv_dir}..."
69 sp_dirs=()
70 for sp in "${venv_dir}"/lib/python*/site-packages; do
71 [[ -d "$sp" ]] && sp_dirs+=("$sp")
72 done
73
74 if [[ ${#sp_dirs[@]} -gt 0 ]]; then
75 echo "Indexing Python site-packages into ${target}..."
76 flags=("-f" "${target}" "--languages=Python" "--exclude=*.dist-info" "--exclude=*.egg-info" "--exclude=*/tests/*" "--exclude=*/test/*")
77 [[ $generated -eq 1 ]] && flags+=("-a")
78 ctags "${flags[@]}" "${sp_dirs[@]}"
79 generated=1
80 fi
81fi
82
83# 4. TypeScript / Node.js
84if [[ -f "package.json" && -d "node_modules" ]]; then
85 echo "Resolving TypeScript / Node dependencies..."
86 ts_targets=()
87 if [[ -d "node_modules/@types" ]]; then
88 ts_targets+=("node_modules/@types")
89 fi
90 while IFS= read -r dts; do
91 [[ -f "$dts" ]] && ts_targets+=("$dts")
92 done < <(find node_modules -maxdepth 4 -name "*.d.ts" ! -path "*/node_modules/@types/*" 2>/dev/null | head -n 500)
93
94 if [[ ${#ts_targets[@]} -gt 0 ]]; then
95 echo "Indexing TypeScript types into ${target}..."
96 flags=("-f" "${target}" "--languages=TypeScript,JavaScript" "--exclude=*/test/*" "--exclude=*/tests/*")
97 [[ $generated -eq 1 ]] && flags+=("-a")
98 printf "%s\n" "${ts_targets[@]}" | ctags "${flags[@]}" -L -
99 generated=1
100 fi
101fi
102
103if [[ $generated -eq 1 ]]; then
104 echo "Saved dependency tags to ${target} ($(du -h "${target}" | cut -f1))"
105else
106 echo "No third-party dependencies detected in current directory."
107 exit 1
108fi