- 合併、去重、排序原本寫在兩支技能的步驟文字裡,各寫一份就會各自演化。改由腳本執行,並定下六欄 TSV 的回報格式。格式不對就擋下並指出是第幾列,不猜、不放行、不自行補欄。 - 另一支腳本列出本次改到的註解行,清理範圍不再靠肉眼判讀。 - 註解樣式與非程式碼副檔名清單沿用註解範圍腳本的同一份,不另立第二套判準。markdown 的標題行開頭就是井字號,判準不一致就會把整份文件當成註解。
108 lines
3.8 KiB
Bash
Executable File
108 lines
3.8 KiB
Bash
Executable File
#!/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
|