main dotfiles / bin / ftags
Eric Bower  ·  2026-09-08
 1#!/usr/bin/env bash
 2set -euo pipefail
 3
 4git_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
 5
 6tag_files=()
 7if [[ $# -gt 0 ]]; then
 8  tag_files=("$@")
 9else
10  for f in tags .tags_deps; do
11    [[ -f "$f" ]] && tag_files+=("$f")
12  done
13  if [[ ${#tag_files[@]} -eq 0 && -n "$git_root" ]]; then
14    for f in "$git_root/tags" "$git_root/.tags_deps"; do
15      [[ -f "$f" ]] && tag_files+=("$f")
16    done
17  fi
18fi
19
20if [[ ${#tag_files[@]} -eq 0 ]]; then
21  echo "ftags: no tags file found (try: ftags <tagfile>)" >&2
22  exit 1
23fi
24
25load_tags() {
26  for tf in "${tag_files[@]}"; do
27    readtags -t "$tf" -e -n -l 2>/dev/null || true
28  done
29}
30
31selected="$(load_tags | awk -F'\t' '{
32  line = 1
33  kind = ""
34  for (i = 4; i <= NF; i++) {
35    if ($i ~ /^line:/) { line = substr($i, 6) }
36    else if ($i ~ /^kind:/) { kind = substr($i, 6) }
37  }
38  printf "%-28s %-5s %s\t%s\t%s\n", $1, kind, $2, $2, line
39}' | fzf \
40  --delimiter=$'\t' \
41  --with-nth=1 \
42  --border=sharp \
43  --pointer='>' \
44  --preview='f={2}; [ ! -f "$f" ] && [ -n "'"$git_root"'" ] && f="'"$git_root"'/$f"; bat --style=numbers --color=always --wrap=never -H {3} "$f" 2>/dev/null || cat "$f" 2>/dev/null' \
45  --preview-window='right,60%,+{3}-10,border-sharp,nowrap,<80(up,50%,border-sharp,nowrap)' \
46  --bind='ctrl-/:toggle-preview' \
47  --prompt='tags> ' || true)"
48
49[[ -z "$selected" ]] && exit 0
50
51file="$(printf '%s' "$selected" | cut -f2)"
52line="$(printf '%s' "$selected" | cut -f3)"
53
54if [[ ! -f "$file" && -n "$git_root" && -f "$git_root/$file" ]]; then
55  file="$git_root/$file"
56fi
57
58editor="${EDITOR:-kak}"
59
60if [[ -n "$line" && "$line" -gt 1 ]]; then
61  exec "$editor" "+$line" "$file"
62else
63  exec "$editor" "$file"
64fi