aboutsummaryrefslogtreecommitdiffstats
path: root/src/extract-generic.sh
blob: f4aef22d30940745426342346e33753dc6b7eab0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env bash

set -efu

input_file=${1-/dev/stdin}

# note: merge sibling comments into matched comment blocks, as tree-sitter does
# not allow for matching sibling nodes
function merge_matches() {
  matches=$(jq -c .matches[])
  new_matches=
  last_match=
  new_match=
  while read -r cur_match; do
    if test -z "$new_match"; then
      new_match=$cur_match
    fi
    if ! test -z "$last_match"; then
      last_end_row=$(echo "$last_match" | jq -r .end.row)
      cur_start_row=$(echo "$cur_match" | jq -r .start.row)
      if test "$(($last_end_row + 1))" = "$cur_start_row"; then
        new_text=$(echo "$new_match" | jq -r .text)
        cur_text=$(echo "$cur_match" | jq -r .text)
        text=$(printf "%s\n%s" "$new_text" "$cur_text")
        end=$(echo "$cur_match" | jq -c .end)
        new_match=$(
          echo "$new_match" |
          # XXX "$end" seems to be forbidden as variable name
          jq -c \
            --argjson end_ "$end" \
            --arg text "$text" \
            '. + {
              "end": $end_,
              "text": $text
            }'
        )
      else
        new_matches=$(printf "%s\n%s" "$new_matches" "$new_match")
        new_match=$cur_match
      fi
    fi
    last_match=$cur_match
  done <<< "$matches"
  if ! test -z "$new_match"; then
    new_matches=$(printf "%s\n%s" "$new_matches" "$new_match")
  fi
  new_matches=$(echo "$new_matches" | jq -cs .)
  echo "$line" | jq -c --argjson matches "$new_matches" '. + { "matches": $matches }'
}

tree-grepper \
  --query "$TREE_GREPPER_LANGUAGE" "$TREE_GREPPER_QUERY" \
  --format json $input_file |
  jq -c '.[]' |
  while read -r line; do
    echo "$line" | merge_matches
  done | while read -r line; do
    file=$(echo "$line" | jq -r .file)
    file_type=$(echo "$line" | jq -r .file_type)
    items=$(echo "$line" |
      jq '.matches[] | { file: $file, file_type: $file_type, match: . }' --arg file "$file" --arg file_type "$file_type" |
      jq '. | select(.match.text | test("TODO .+"))'
    )
    if test -z "$items"; then
      continue
    fi

    echo "$items" | jq --slurp '.[]' --indent 0 |
      while read -r item; do
        start_row=$(echo "$item" | jq '.match.start.row')
        end_row=$(echo "$item" | jq '.match.end.row')

        last_commit=$(git --no-pager blame -L "$start_row,$start_row" "$file" -p |
          head -n 1 |
          cut -d ' ' -f 1
        )

        text=$(echo "$item" |
          jq .match.text -r |
          sed 's/^'"$LINE_COMMENT_START"'\( *TODO *\| \?\)//g' |
          {
            if test -z "${BLOCK_COMMENT_START-}"; then
              cat
            else
              sed 's/^'"$BLOCK_COMMENT_START"'\( *TODO *\| \?\)//'
            fi
          } |
          {
            if test -z "${BLOCK_COMMENT_END-}"; then
              cat
            else
              sed 's/ *'"$BLOCK_COMMENT_END"' *$//'
            fi
          }
        )

        echo "$item" | jq '. + {"text": $text, "last_commit": $last_commit}' \
          --arg text "$text" \
          --arg last_commit "$last_commit" \
          -c
      done
  done