#!/bin/bash set -e # Instructions: # # This script is a Git pre-commit hook that spell checks any content you are about to commit. # # Place this script into the ".git/hooks/" directory in your repository. It must be called "pre-commit" and be # executable. A Git hook only works in a single repository. You need to copy this hook into every repository you wish to # use it in manually. Optionally, you can set up a symlink in the ".git/hooks/" directory pointing to the script. # # Each time you try to commit something, this script is run and spell checks the content you are committing. # # Should you want to bypass the pre-commit hook (though not recommended), you can commit with "git commit --no-verify". # The following is a text file that represents your custom dictionary; edit as necessary. Add words to it that you wish # to ignore for the spell check. dict=~/Qsync/.git-spell-check if [ ! -f $dict ]; then touch ~/Qsync/.git-spell-check dict=~/Qsync/.git-spell-check printf "%s\n" "Custom dictionary not found. Created ~/Qsync/.git-spell-checkk..." fi # The following is a temporary dictionary (a binary file) created from the dict text file. It is deleted after the # script finishes. temp_dict=$(mktemp docs-dictionary-XXXXXX) # Language of your doc. When using a non-English language, make sure you have the appropriate aspell libraries # installed: "yum search aspell". For example, to spell check in Slovak, you must have the aspell-sk package installed. lang=en # Define an extension for any additional dictionaries (containing words that are ignored during the spell check) that # are kept locally in your repository. These dictionaries will be loaded on top of the existing global dictionary (by # default ~/.git-spell-check). extension=pws # Clean up if script is interrupted or terminated. trap "cleanup" SIGINT SIGTERM # Prepares the dictionary from scratch in case new words were added since last time. function prepare_dictionary() { local_dict=$(find . -name *.$extension -exec ls {} \;) if [ -z "$local_dict" ]; then sort -u $temp_dict -o $temp_dict aspell --lang="$lang" create master "$temp_dict" < "$dict" else temp_file=$(mktemp temp_file-XXXXXX) for file in $local_dict; do cat $file >> $temp_file done cat $dict >> $temp_file sort -u $temp_file -o $temp_file aspell --lang="$lang" create master "$temp_dict" < "$temp_file" /bin/rm -f "$temp_file" fi } # Removes the temporary dictionary. function cleanup() { /bin/rm -f "$temp_dict" } # Spell checks content you're about to commit. Writes out words that are misspelled or exits with 0 (i.e. continues with # commit). function spell_check() { words=$(git diff --cached | grep -e "^+[^+]" | aspell --mode=sgml list --add-sgml-skip={ulink,code,literal,firstname,parameter,option,package,replaceable,programlisting,userinput,screen,filename,command,computeroutput,abbrev,accel,orgname,surname,foreignphrase,acronym,hardware,keycap,systemitem,application} --lang="$lang" --extra-dicts="$temp_dict" | sort -u) if [ ! "$words" ]; then printf "%s\n" "No typos found. Proceeding with commit..." cleanup; exit 0 fi printf "%s\n" "Spell check failed on the following words: -------------------------------------------------" echo $words for word in $words; do grep --color=always --exclude-dir={.git,tmp} -HIrone "\<$word\>" $(git diff --cached --name-only --diff-filter=ACMRTUXB) | awk -F ":" '{print "File: " $1 "\ton line: " $2 "\tTypo: " $3}' printf "%s\n" "-------------------" done } # Adds all, some, or none of the misspelled words to the custom dictionary. function add_words_to_dict() { printf "%s\n" " Add any of the misspelled words into your custom dictionary? * a[ll] (add all words into dict, continue with commit) * s[ome] (add some words into dict, fix others, no commit) * i[gnore] (add some words into dict, ignore rest, continue with commit) * n[one] (no commit) " while true; do exec < /dev/tty # Simply reading user input does not work because Git hooks have stdin detached. read answer shopt -s nocasematch case "$answer" in a|all) add_all cleanup; exit 0 ;; s|some) add_some printf "%s\n" "Please fix remaining typos, use \"git add\" to add fixed files, and commit." cleanup; exit 1 ;; i|ignore) add_some cleanup; exit 0 ;; n|none) add_none cleanup; exit 1 ;; *) printf "%s\n" "Incorrect answer. Try again." continue esac shopt -u nocasematch done } # Adds all words to the custom dictionary and continues with the commit. function add_all() { for word in $words; do echo $word >> "$dict" done } # Adds some (selected by user) of the words to the dictinary and exits with 1. function add_some() { for word in $words; do printf "%s\n" "Do you want to add the following word to your custom dictionary: $word (y[es] or n[o])" while true; do exec < /dev/tty read answer shopt -s nocasematch case "$answer" in y|yes) echo $word >> "$dict" printf "%s\n" "\"$word\" added to your custom dictionary." break ;; n|no) break ;; *) printf "%s\n" "Incorrect answer. Try again." continue esac shopt -u nocasematch done done } # Adds none of the words and exits with 1. function add_none() { printf "%s\n" "No words were added to your custom dictionary." printf "%s\n" "Please fix remaining typos, use \"git add\" to add fixed files, and commit." } prepare_dictionary spell_check add_words_to_dict