fix-curly-quotes.sh
1 #!/usr/bin/env bash 2 # Pre-commit helper: normalize curly quotes and other characters that break parsers. 3 # Replaces: smart quotes → ASCII, nbsp → space, en/em dash → -, ellipsis → ...; removes ZWSP, ZWNJ, ZWJ, BOM. 4 # Portable: BSD sed (macOS) and GNU sed; uses gsed on macOS when available. 5 6 set -e 7 8 if [[ "$(uname -s)" = Darwin ]] && command -v gsed &>/dev/null; then 9 SED="gsed" 10 else 11 SED="sed" 12 fi 13 14 DQ_LEFT=$(printf '\342\200\234') 15 DQ_RIGHT=$(printf '\342\200\235') 16 SQ_LEFT=$(printf '\342\200\230') 17 SQ_RIGHT=$(printf '\342\200\231') 18 NBSP=$(printf '\302\240') 19 EN_DASH=$(printf '\342\200\223') 20 EM_DASH=$(printf '\342\200\224') 21 ELLIPSIS=$(printf '\342\200\246') 22 ZWSP=$(printf '\342\200\213') 23 ZWNJ=$(printf '\342\200\214') 24 ZWJ=$(printf '\342\200\215') 25 BOM=$(printf '\357\273\277') 26 27 changed=0 28 29 for f in "$@"; do 30 [[ -f "$f" ]] || continue 31 tmp=$(mktemp) 32 if "$SED" \ 33 -e "s/${DQ_LEFT}/\"/g" \ 34 -e "s/${DQ_RIGHT}/\"/g" \ 35 -e "s/${SQ_LEFT}/'/g" \ 36 -e "s/${SQ_RIGHT}/'/g" \ 37 -e "s/${NBSP}/ /g" \ 38 -e "s/${EN_DASH}/-/g" \ 39 -e "s/${EM_DASH}/-/g" \ 40 -e "s/${ELLIPSIS}/.../g" \ 41 -e "s/${ZWSP}//g" \ 42 -e "s/${ZWNJ}//g" \ 43 -e "s/${ZWJ}//g" \ 44 -e "s/${BOM}//g" \ 45 "$f" >"$tmp"; then 46 if ! cmp -s "$f" "$tmp"; then 47 mv "$tmp" "$f" 48 changed=1 49 else 50 rm -f "$tmp" 51 fi 52 else 53 rm -f "$tmp" 54 exit 1 55 fi 56 done 57 58 [[ $changed -eq 0 ]]