Files
review/tools/changed-comments.sh
T
jiantw83 a0bd488ac8 feat(tools): 新增發現合併與變更註解兩支腳本
- 合併、去重、排序原本寫在兩支技能的步驟文字裡,各寫一份就會各自演化。改由腳本執行,並定下六欄 TSV 的回報格式。格式不對就擋下並指出是第幾列,不猜、不放行、不自行補欄。
- 另一支腳本列出本次改到的註解行,清理範圍不再靠肉眼判讀。
- 註解樣式與非程式碼副檔名清單沿用註解範圍腳本的同一份,不另立第二套判準。markdown 的標題行開頭就是井字號,判準不一致就會把整份文件當成註解。
2026-08-31 11:07:05 +08:00

108 lines
3.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env sh
# changed-comments.sh — 列出本次變更裡新增或修改的註解行,供 comment-cleanup 決定清理範圍。
#
# 用法:
# changed-comments.sh 比對工作區與 HEAD(git diff HEAD),即尚未提交的變更
# changed-comments.sh <base> 比對基準版本(git diff {base}...HEAD),實作完成時用
# 一律在要檢查的存取庫目錄下執行;本腳本不吃路徑參數,也不切換目錄。
#
# 輸出(TSV,一列一行註解,三欄,欄位之間一個 tab,只走 stdout):
# 1 檔案 路徑,相對存取庫根目錄
# 2 行號 該註解行在新版檔案裡的行號,正整數
# 3 內容 該行原文;行內的 tab 換成一個空白,欄位才不會錯位
#
# 結束碼:
# 0 有結果,至少印出一列
# 1 沒有結果,本次變更沒有新增或修改的註解行(呼叫端回報「無發現」)
# 2 參數或環境錯誤:參數超過一個、目前目錄不在 git 工作區、基準版本無效、缺 git 或 awk
#
# 判準的來源:註解行樣式與「不受本規則限制的非程式碼副檔名」兩份判準,都沿用 jsc-hooks 的
# hooks/comment-scope.sh(scan_file 裡的那兩份),一字不差地照抄。那支 hook 是規則實作的
# 正本,這裡只是把同一份判準搬到 git diff 上;哪天正本改了樣式,這裡要跟著改,不得各自演化。
# 跳過非程式碼檔不是可有可無的:markdown 的標題行開頭就是 #,不跳過就會把整份文件當成註解。
set -u
usage() {
echo '用法:changed-comments.sh [base](不給基準時比對工作區與 HEAD)' >&2
exit 2
}
[ "$#" -le 1 ] || usage
for cmd in git awk; do
command -v "$cmd" >/dev/null 2>&1 || {
echo "錯誤:環境缺 $cmd,無法列出變更的註解行。" >&2
exit 2
}
done
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
echo '錯誤:目前目錄不在 git 工作區內,取不到變更範圍。' >&2
exit 2
}
# git diff 的失敗一律原樣往上帶:判不出範圍卻回「無發現」,等於把環境問題講成沒有東西要清。
if [ "$#" -eq 1 ]; then
base=$1
case "$base" in
-*) usage ;;
esac
git rev-parse --verify --quiet "$base^{commit}" >/dev/null 2>&1 || {
echo "錯誤:基準版本「$base」不是有效的 commit。" >&2
exit 2
}
DIFF=$(git diff --no-color -U0 "$base...HEAD" 2>&1) || {
printf '%s\n' "$DIFF" >&2
exit 2
}
else
DIFF=$(git diff --no-color -U0 HEAD 2>&1) || {
printf '%s\n' "$DIFF" >&2
exit 2
}
fi
# 樣式走環境變數交給 awk:走 -v 的話 awk 會先解釋字串裡的跳脫序列,樣式中的 \* 會被吃成
# 量詞 *,整條 ERE 的意思就變了。ENVIRON 不做這層處理,樣式進到 awk 時與正本一字不差。
COMMENT_RE='^[[:space:]]*(//|#|--|\*|/\*|<!--|;|%)|[[:space:]](//|#)[[:space:]]'
OUT=$(printf '%s\n' "$DIFF" | COMMENT_RE="$COMMENT_RE" awk '
BEGIN { OFS = "\t"; re = ENVIRON["COMMENT_RE"]; skip = 1 }
# 非程式碼檔沒有「程式碼註解」,整檔跳過(副檔名清單同 comment-scope.sh)。
function skipped(p) {
return (p ~ /\.(md|markdown|txt|rst|json|csv|tsv|svg|lock|log)$/ || p ~ /COMMIT_EDITMSG$/)
}
/^\+\+\+ / {
f = substr($0, 5) # 去掉開頭的「+++ 」
sub(/^b\//, "", f)
skip = (f == "" || f == "/dev/null" || skipped(f))
next
}
# 區塊標頭 @@ -a,b +c,d @@:第三欄的 +c 就是這一段在新版檔案裡的起始行號。
/^@@ / {
t = $3
sub(/^\+/, "", t)
sub(/,.*$/, "", t)
ln = t + 0
next
}
/^\+/ {
if (skip || ln < 1) next
line = substr($0, 2)
if (line ~ re) {
out = line
gsub(/\t/, " ", out)
print f, ln, out
}
ln++ # 只有新增行會佔掉新版檔案的行號,刪除行不會
}
')
[ -n "$OUT" ] || exit 1
printf '%s\n' "$OUT"
exit 0