Skip to content

Instantly share code, notes, and snippets.

@guuzaa
Last active February 7, 2024 11:02
Show Gist options
  • Save guuzaa/48b739c8c755868f21b018045eeb56d9 to your computer and use it in GitHub Desktop.
Save guuzaa/48b739c8c755868f21b018045eeb56d9 to your computer and use it in GitHub Desktop.
Automatically Formatting C/C++ Code with Git Pre-Commit Hook and clang-format
#!/bin/bash
check_dependencies() {
# The tools we need, please check if they are properly installed before running.
dependencies=(which git find test cut read)
for d in "${dependencies[@]}"; do
if [ ! "$(which "$d")" ]; then
echo -e "\nPlease install ${d} first."
exit 1
fi
done
get_clang_format
}
get_clang_format() {
local vscode_path="$HOME/.vscode/extensions/"
local vscode_server_path="$HOME/.vscode-server/extensions/"
if test -d "$vscode_path"; then
clang_format_path=$(get_clang_format_helper "$vscode_path")
elif test -d "$vscode_server_path"; then
clang_format_path=$(get_clang_format_helper "$vscode_server_path")
elif [ ! "$(which clang-format)" ]; then
echo "Make sure to install clang-format! We need it to format the code."
echo "The VSCode C/C++ plugin (https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) integrates clang-format, so it is recommended to install the plugin for convenience and efficiency."
echo "If you haven't installed VSCode(https://code.visualstudio.com/), please download it first."
exit
else
clang_format_path="$(which clang-format)"
fi
}
get_clang_format_helper() {
find "$1" -name "clang-format*" | sort -r
}
get_git_modified_file_list() {
local git_status
git_status=$(git status -u -s)
if [ -z "$git_status" ] || [ "$git_status" != " " ]; then
echo -e "No changes in the workspace :)\n! Formatted files in the last commit:"
get_git_commited_file_list
exit
fi
for info in "${git_status[@]}"; do
info=${info#*[[:space:]]}
mode=$(echo "$info" | cut -d' ' -f 1)
if [ "$mode" == "R" ]; then
filepath=$(echo "$info" | cut -d'>' -f 2)
filepath=${filepath#*[[:space:]]}
elif [ "$mode" != "D" ] && [ "$mode" != "!!" ]; then
filepath=$(echo "$info" | cut -d' ' -f 2)
fi
modified_file_list+=("$filepath")
done
}
get_git_commited_file_list() {
local commited_files
commited_files=$(git diff-index --cached --name-only --diff-filter=d HEAD)
IFS=$'\n' read -d '' -r -a modified_file_list <<<"$commited_files"
}
format_all_files() {
check_dependencies
file_cnt=0
find "$1" -type f \( -name "*.cpp" -o -name "*.cxx" -o -name "*.c" -o -name "*.cc" -o -name "*.h" -o -name "*.hpp" -o -name "*.hxx" \) -print0 |
while IFS= read -r -d '' file; do
format_and_add_file "$file"
done
display_formatted_file_info
}
format_modified_files() {
check_dependencies
modified_file_list=()
get_git_commited_file_list
file_cnt=0
for file in "${modified_file_list[@]}"; do
ext_name="${file##*.}"
if [ "$ext_name" == "cc" ] || [ "$ext_name" == "c" ] || [ "$ext_name" == "h" ] || [ "$ext_name" == "cpp" ] || [ "$ext_name" == "cxx" ] || [ "$ext_name" == "hpp" ] || [ "$ext_name" == "hxx" ]; then
format_and_add_file "$file"
fi
done
display_formatted_file_info
}
format_and_add_file() {
if "$clang_format_path" -i "$1"; then
echo "$1 formatted successfully!"
git add "$1"
((file_cnt += 1))
fi
}
display_formatted_file_info() {
if ((file_cnt > 0)); then
echo "Formatted files:: ${file_cnt}"
else
echo "No files to format :)"
fi
}
main() {
echo "Note: Only source code files with the extensions cpp, cxx, c, cc, h, hpp, hxx will be formatted."
format_modified_files
}
main
@guuzaa
Copy link
Author

guuzaa commented Jan 24, 2024

  • First, we need to copy the bash script to the .git/hooks directory of our local repository.
  • Second, we should either install the C/C++ extension for VSCode or globally install the clang-format binary in advance.
  • Now each time we run git commit, our formatting script will run in the background. It finds any source files modified in the current change and formats them with clang-format. Once complete, we've retained a consistent code style without any extra manual steps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment