Last active
February 7, 2024 11:02
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
.git/hooks
directory of our local repository.C/C++
extension for VSCode or globally install the clang-format binary in advance.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!