2727mapfile -t files < <( find " ${PATHS[@]} " -name dist-newstyle -prune -o -name ' *.hs' -print | sort)
2828
2929check () {
30- awk -v max=" $MAX_LINES " -v width=" $WIDTH " '
31- function report(kind, start, n) {
32- printf "%s:%d: %s comment is %d lines (max %d)\n", FILENAME, start, kind, n, max
33- bad = 1
30+ # C locale: count bytes so the UTF-8 continuation-byte regex below is valid
31+ # (gawk in a UTF-8 locale rejects it as an invalid collation character).
32+ LC_ALL=C awk -v max=" $MAX_LINES " -v width=" $WIDTH " -v gha=" ${GITHUB_ACTIONS:- } " '
33+ # One finding: location, what is wrong, the source line, how to fix it.
34+ function report(line, last, title, msg, src, fix, loc) {
35+ loc = (last > line) ? line "-" last : line
36+ printf "%s:%s: %s\n", FILENAME, loc, msg
37+ if (src != "") printf " | %s\n", src
38+ printf " fix: %s\n\n", fix
39+ if (gha == "true")
40+ printf "::error file=%s,line=%d,endLine=%d,title=%s::%s. Fix: %s\n", \
41+ FILENAME, line, (last > line ? last : line), title, msg, fix
42+ problems++
43+ if (!(FILENAME in seen)) { seen[FILENAME] = 1; nfiles++ }
3444 }
3545 function flush() {
36- if (lines > 0 && !(haddock == 2) && lines > max) report("line", start, lines)
46+ if (lines > 0 && !(haddock == 2) && lines > max)
47+ report(start, start + span - 1, "Multi-line comment", \
48+ sprintf("%d-line -- comment; comments must fit on %d line(s)", lines, max), \
49+ first, "condense it to one line, or delete it if the code says it already")
3750 lines = 0; haddock = 0
3851 }
3952 FNR == 1 { flush(); depth = 0 }
4053 {
4154 code = $0; gsub(/"([^"\\]|\\.)*"/, "\"\"", code)
4255 chars = $0; gsub(/[\200-\277]/, "", chars)
4356 if (length(chars) > width && code ~ /--|\{-/)
44- { printf "%s:%d: line is %d chars (max %d)\n", FILENAME, FNR, length(chars), width; bad = 1 }
57+ report(FNR, FNR, "Comment too wide", \
58+ sprintf("comment line is %d columns; the limit is %d", length(chars), width), \
59+ $0, sprintf("shorten the text so the line ends by column %d", width))
4560 }
4661 # Section banners: rulers like `-- -----` or titles like `-- Name -----`.
4762 /^[ \t]*--[ \t]*[-=][-=][-=][-=]+[ \t]*$/ || /^[ \t]*--[ \t]+[^-= \t].*[ \t][-=][-=][-=][-=]+[ \t]*$/ {
48- printf "%s:%d: section banner comment\n", FILENAME, FNR; bad = 1
63+ report(FNR, FNR, "Section banner", "section banner comments are not allowed", \
64+ $0, "delete it, or use a Haddock heading: -- * Title")
4965 }
5066 # Inside a {- -} block: track nesting, report when it closes.
5167 depth > 0 {
5268 n = gsub(/\{-/, "&"); m = gsub(/-\}/, "&"); depth += n - m
5369 if (depth <= 0) {
5470 depth = 0
55- if (!pragma) {
56- printf "%s:%d: {- -} block comment (use a one-line -- instead)\n ", FILENAME, bstart
57- bad = 1
58- }
71+ if (!pragma)
72+ report(bstart, FNR, "Block comment ", \
73+ sprintf("%d-line {- -} block comment; only one-line -- comments are allowed", FNR - bstart + 1), \
74+ bfirst, (bhaddock ? "replace it with a single -- | line" : "replace it with a single -- line"))
5975 }
6076 next
6177 }
@@ -65,28 +81,48 @@ check() {
6581 line = $0
6682 n = gsub(/\{-/, "&", line); m = gsub(/-\}/, "&", line)
6783 if (n > m) {
68- depth = n - m; bstart = FNR
84+ depth = n - m; bstart = FNR; bfirst = $0
6985 bhaddock = ($0 ~ /\{-[ \t]*[|^$*]/); pragma = ($0 ~ /\{-#/)
7086 } else if ($0 !~ /\{-#/) {
71- printf "%s:%d: {- -} block comment (use a one-line -- instead)\n", FILENAME, FNR
72- bad = 1
87+ report(FNR, FNR, "Block comment", \
88+ "{- -} block comment; only one-line -- comments are allowed", \
89+ $0, "rewrite it as a -- comment (on its own line, or at the end of the line)")
7390 }
7491 next
7592 }
7693 # `--` line comments: consecutive comment-only lines form one comment.
7794 /^[ \t]*--/ {
78- if (lines == 0) { start = FNR; haddock = ($0 ~ /^[ \t]*--[ \t]*\*/) ? 2 : 0 }
95+ if (lines == 0) {
96+ start = FNR; span = 0; first = $0
97+ haddock = ($0 ~ /^[ \t]*--[ \t]*\*/) ? 2 : 0
98+ }
99+ span = FNR - start + 1
79100 if ($0 !~ /^[ \t]*--[-= \t]*$/) lines++
80101 next
81102 }
82103 { flush() }
83- END { flush(); exit bad }
104+ END {
105+ flush()
106+ if (problems) printf "%d problem(s) in %d file(s).\n", problems, nfiles
107+ exit (problems > 0)
108+ }
84109 ' " $@ "
85110}
86111
87- if check " ${files[@]} " ; then
112+ rc=0
113+ check " ${files[@]} " || rc=$?
114+ if [[ $rc -eq 0 ]]; then
88115 echo " ✓ Comments OK (max ${MAX_LINES} line(s), ${WIDTH} cols) in ${# files[@]} files."
89- else
90- echo " ✗ Comment lint failed." >&2
116+ elif [[ $rc -eq 1 ]]; then
117+ {
118+ echo " ✗ Comment lint failed."
119+ echo " Rules: comments are one line, at most ${WIDTH} columns, and use --"
120+ echo " (not {- -}). Pragmas and '-- * Heading' lines are exempt."
121+ echo " Re-run locally: ./scripts/lint-comments.sh [paths...]"
122+ } >&2
91123 exit 1
124+ else
125+ echo " ✗ lint-comments.sh crashed (awk exit $rc ); this is a script bug, not a" >&2
126+ echo " comment problem. See the awk error above." >&2
127+ exit " $rc "
92128fi
0 commit comments