├── README.markdown └── pre-commit /README.markdown: -------------------------------------------------------------------------------- 1 | Git Spell Check 2 | =============== 3 | 4 | This script is a Git pre-commit hook that spell checks changes in files which you are about to commit. 5 | 6 | 7 | Instructions 8 | ------------ 9 | 10 | To use this script, clone the following repo: 11 | 12 | ~]$ git clone git://github.com/mprpic/git-spell-check.git 13 | 14 | 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. That way, each time the script is updated in the GitHub repo, you won't have to replace it in the **.git/hooks/** directory. To create a symlink in your repository, execute: 15 | 16 | book]$ ln -s ~/git-spell-check/pre-commit .git/hooks/pre-commit 17 | 18 | You will need to install [`aspell`](http://aspell.net/). 19 | 20 | On Mac: 21 | 22 | ~]$ brew install aspell 23 | 24 | On Ubuntu: 25 | 26 | ~]$ apt-get install -y aspell 27 | 28 | Each time you try to commit something, this script is run to spell check the content you are committing. If misspelled words are found, you can either save them into a custom Aspell dictionary (which means they will be ignored next time the script is run), or ignore them. The following options are available when the script is run: 29 | 30 | Add any of the misspelled words into your custom dictionary? 31 | * a[ll] (add all words into dict, continue with commit) 32 | * s[ome] (add some words into dict, fix others, no commit) 33 | * i[gnore] (add some words into dict, ignore rest, continue with commit) 34 | * n[one] (no commit) 35 | 36 | Should you want to bypass the pre-commit hook (though not recommended), you can commit with **git commit --no-verify**. 37 | 38 | 39 | To-Do 40 | ----- 41 | 42 | * Aspell considers foo_bar two words, and **grep** greps for word boundaries around foo and bar. 43 | 44 | 45 | Copyright 46 | --------- 47 | 48 | Git Spell Check — spell checking pre-commit Git hook. Copyright (C) 2012 Martin Prpič 49 | 50 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 51 | 52 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 53 | 54 | You should have received a copy of the GNU General Public License along with this program. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). 55 | -------------------------------------------------------------------------------- /pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Instructions: 5 | # 6 | # This script is a Git pre-commit hook that spell checks any content you are about to commit. 7 | # 8 | # Place this script into the ".git/hooks/" directory in your repository. It must be called "pre-commit" and be 9 | # executable. A Git hook only works in a single repository. You need to copy this hook into every repository you wish to 10 | # use it in manually. Optionally, you can set up a symlink in the ".git/hooks/" directory pointing to the script. 11 | # 12 | # Each time you try to commit something, this script is run and spell checks the content you are committing. 13 | # 14 | # Should you want to bypass the pre-commit hook (though not recommended), you can commit with "git commit --no-verify". 15 | 16 | 17 | # The following is a text file that represents your custom dictionary; edit as necessary. Add words to it that you wish 18 | # to ignore for the spell check. 19 | dict=~/.git-spell-check 20 | if [ ! -f $dict ]; then 21 | touch ~/.git-spell-check 22 | dict=~/.git-spell-check 23 | printf "%s\n" "Custom dictionary not found. Created ~/.git-spell-check..." 24 | fi 25 | 26 | 27 | # The following is a temporary dictionary (a binary file) created from the dict text file. It is deleted after the 28 | # script finishes. 29 | temp_dict=$(mktemp docs-dictionary-XXXXXX) 30 | 31 | # Language of your doc. When using a non-English language, make sure you have the appropriate aspell libraries 32 | # installed: "yum search aspell". For example, to spell check in Slovak, you must have the aspell-sk package installed. 33 | lang=en 34 | 35 | # Define an extension for any additional dictionaries (containing words that are ignored during the spell check) that 36 | # are kept locally in your repository. These dictionaries will be loaded on top of the existing global dictionary (by 37 | # default ~/.git-spell-check). 38 | extension=pws 39 | 40 | # Clean up if script is interrupted or terminated. 41 | trap "cleanup" SIGINT SIGTERM 42 | 43 | # Prepares the dictionary from scratch in case new words were added since last time. 44 | function prepare_dictionary() { 45 | 46 | local_dict=$(find . -name *.$extension -exec ls {} \;) 47 | if [ -z "$local_dict" ]; then 48 | sort -u $temp_dict -o $temp_dict 49 | aspell --lang="$lang" create master "$temp_dict" < "$dict" 50 | else 51 | temp_file=$(mktemp temp_file-XXXXXX) 52 | for file in $local_dict; do 53 | cat $file >> $temp_file 54 | done 55 | cat $dict >> $temp_file 56 | sort -u $temp_file -o $temp_file 57 | aspell --lang="$lang" create master "$temp_dict" < "$temp_file" 58 | /bin/rm -f "$temp_file" 59 | fi 60 | 61 | } 62 | 63 | # Removes the temporary dictionary. 64 | function cleanup() { 65 | 66 | /bin/rm -f "$temp_dict" 67 | 68 | } 69 | 70 | # Spell checks content you're about to commit. Writes out words that are misspelled or exits with 0 (i.e. continues with 71 | # commit). 72 | function spell_check() { 73 | 74 | 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) 75 | if [ ! "$words" ]; then 76 | printf "%s\n" "No typos found. Proceeding with commit..." 77 | cleanup; exit 0 78 | fi 79 | printf "%s\n" "Spell check failed on the following words: 80 | -------------------------------------------------" 81 | echo $words 82 | for word in $words; do 83 | 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}' 84 | printf "%s\n" "-------------------" 85 | done 86 | 87 | } 88 | 89 | # Adds all, some, or none of the misspelled words to the custom dictionary. 90 | function add_words_to_dict() { 91 | 92 | printf "%s\n" " 93 | Add any of the misspelled words into your custom dictionary? 94 | * a[ll] (add all words into dict, continue with commit) 95 | * s[ome] (add some words into dict, fix others, no commit) 96 | * i[gnore] (add some words into dict, ignore rest, continue with commit) 97 | * n[one] (no commit) 98 | " 99 | 100 | while true; do 101 | exec < /dev/tty # Simply reading user input does not work because Git hooks have stdin detached. 102 | read answer 103 | shopt -s nocasematch 104 | case "$answer" in 105 | a|all) 106 | add_all 107 | cleanup; exit 0 108 | ;; 109 | s|some) 110 | add_some 111 | printf "%s\n" "Please fix remaining typos, use \"git add\" to add fixed files, and commit." 112 | cleanup; exit 1 113 | ;; 114 | i|ignore) 115 | add_some 116 | cleanup; exit 0 117 | ;; 118 | n|none) 119 | add_none 120 | cleanup; exit 1 121 | ;; 122 | *) 123 | printf "%s\n" "Incorrect answer. Try again." 124 | continue 125 | esac 126 | shopt -u nocasematch 127 | done 128 | 129 | } 130 | 131 | # Adds all words to the custom dictionary and continues with the commit. 132 | function add_all() { 133 | 134 | for word in $words; do 135 | echo $word >> "$dict" 136 | done 137 | 138 | } 139 | 140 | # Adds some (selected by user) of the words to the dictinary and exits with 1. 141 | function add_some() { 142 | 143 | for word in $words; do 144 | printf "%s\n" "Do you want to add the following word to your custom dictionary: $word (y[es] or n[o])" 145 | while true; do 146 | exec < /dev/tty 147 | read answer 148 | shopt -s nocasematch 149 | case "$answer" in 150 | y|yes) 151 | echo $word >> "$dict" 152 | printf "%s\n" "\"$word\" added to your custom dictionary." 153 | break ;; 154 | n|no) 155 | break ;; 156 | *) 157 | printf "%s\n" "Incorrect answer. Try again." 158 | continue 159 | esac 160 | shopt -u nocasematch 161 | done 162 | done 163 | 164 | } 165 | 166 | # Adds none of the words and exits with 1. 167 | function add_none() { 168 | 169 | printf "%s\n" "No words were added to your custom dictionary." 170 | printf "%s\n" "Please fix remaining typos, use \"git add\" to add fixed files, and commit." 171 | 172 | } 173 | 174 | 175 | prepare_dictionary 176 | spell_check 177 | add_words_to_dict 178 | --------------------------------------------------------------------------------