diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2020-01-13 07:48:49 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2020-01-13 08:01:21 +0300 |
commit | 585aeabfd21d1f678f80e3782b3fd3c29c469320 (patch) | |
tree | 73113ba05d8540979f2d3594caf1df93663a5be6 /tools/clang-format | |
parent | AppVeyor: fast_finish (diff) | |
download | cmake-common-585aeabfd21d1f678f80e3782b3fd3c29c469320.tar.gz cmake-common-585aeabfd21d1f678f80e3782b3fd3c29c469320.zip |
add clang-format.sh
This allows to call clang-format in either the in-place editing mode
(default), or the diff mode (`--diff`, will only print the unified diff
between the formatted and the original files.
Diffstat (limited to 'tools/clang-format')
-rw-r--r-- | tools/clang-format/.gitattributes | 1 | ||||
-rwxr-xr-x | tools/clang-format/clang-format.sh | 186 |
2 files changed, 187 insertions, 0 deletions
diff --git a/tools/clang-format/.gitattributes b/tools/clang-format/.gitattributes new file mode 100644 index 0000000..dfdb8b7 --- /dev/null +++ b/tools/clang-format/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/tools/clang-format/clang-format.sh b/tools/clang-format/clang-format.sh new file mode 100755 index 0000000..00fe712 --- /dev/null +++ b/tools/clang-format/clang-format.sh @@ -0,0 +1,186 @@ +#!/usr/bin/env bash + +# Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com> +# This file is part of the "cmake-common" project. +# For details, see https://github.com/egor-tensin/cmake-common. +# Distributed under the MIT License. + +set -o errexit -o nounset -o pipefail + +# Utility + +script_name="$( basename -- "${BASH_SOURCE[0]}" )" +readonly script_name + +dump() { + local prefix="${FUNCNAME[0]}" + [ "${#FUNCNAME[@]}" -gt 1 ] && prefix="${FUNCNAME[1]}" + + local msg + for msg; do + echo "$script_name: $prefix: $msg" + done +} + +# Settings + +clang_format='clang-format' +clang_format_style='file' +clang_format_diff= + +update_clang_format() { + if [ "$#" -ne 1 ]; then + echo "usage: ${FUNCNAME[0]} CLANG_FORMAT_PATH" >&2 + return 1 + fi + + local new_clang_format="$1" + + if ! command -v "$new_clang_format" > /dev/null 2>&1; then + dump "couldn't find clang-format at: $new_clang_format" >&2 + return 1 + fi + + clang_format="$new_clang_format" +} + +# Command line parsing + +script_usage() { + local msg + for msg; do + echo "$script_name: $msg" + done + + echo "usage: $script_name [-h|--help] [-b|--clang-format PATH] [-s|--style STYLE] [--diff] + -h,--help show this message and exit + -b,--clang-format set path to clang-format executable + -s,--style clang-format -style parameter argument + --diff don't edit the files, just show the diff" +} + +parse_script_options() { + while [ "$#" -gt 0 ]; do + local key="$1" + shift + + case "$key" in + -h|--help) + script_usage + exit 0 + ;; + --diff) + clang_format_diff=1 + continue + ;; + -b|--clang-format|-s|--style) + ;; + *) + script_usage "unrecognized parameter: $key" >&2 + exit 1 + ;; + esac + + if [ "$#" -eq 0 ]; then + script_usage "missing argument for parameter: $key" >&2 + exit 1 + fi + + local value="$1" + shift + + case "$key" in + -b|--clang-format) + update_clang_format "$value" + ;; + -s|--style) + clang_format_style="$value" + ;; + *) + script_usage "unrecognized parameter: $key" >&2 + exit 1 + ;; + esac + done +} + +# Routines for running clang-format + +run_clang_format_diff() { + local exit_code=0 + local file + + for file; do + if "$clang_format" "-style=$clang_format_style" -- "$file" | diff --unified --label="$file (original)" --label="$file (clang-format)" -- "$file" -; then + continue + else + exit_code="$?" + [ "$exit_code" -eq 1 ] && continue + break + fi + done + + return "$exit_code" +} + +run_clang_format_edit() { + "$clang_format" -i "-style=$clang_format_style" -- "$@" +} + +run_clang_format() { + if [ -z "$clang_format_diff" ]; then + run_clang_format_edit "$@" + else + run_clang_format_diff "$@" + fi +} + +# File traversal + +list_all_files() { + git ls-tree -r -z --name-only HEAD +} + +declare -a cpp_extensions=(c h cc hh cpp hpp cxx hxx cp c++) + +list_cpp_files() { + local -A cpp_extension_set + local ext + + for ext in ${cpp_extensions[@]+"${cpp_extensions[@]}"}; do + cpp_extension_set[$ext]=1 + done + + local -a files=() + local file + + while IFS= read -d '' -r file; do + basename="$( basename -- "$file" )" + ext="${basename##*.}" + [ "$ext" = "$basename" ] && continue # No .EXTension + + [ -n "${cpp_extension_set[$ext]+x}" ] && files+=("$file") + done < <( list_all_files ) + + printf -- '%s\0' ${files[@]+"${files[@]}"} +} + +# Main routines + +process_cpp_files() { + local -a files=() + local file + + while IFS= read -d '' -r file; do + files+=("$file") + done < <( list_cpp_files ) + + run_clang_format ${files[@]+"${files[@]}"} +} + +main() { + parse_script_options "$@" + process_cpp_files +} + +main "$@" |