#!/usr/bin/env bash

set -eu

# This Bash script implements custom sanity checks for scripts beyond what
# Vint covers, which are easy to check with regex.
#
# Adopted from ALE (https://github.com/w0rp/ale/blob/10679b29/custom-checks)
#
# Copyright (c) 2016, w0rp <devw0rp@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

RETURN_CODE=0

function print_help() {
    echo "Usage: ./custom-checks FILE|DIRECTORY…" 1>&2
    echo 1>&2
    echo "  -h, --help    Print this help text" 1>&2
    exit 1
}

while [ $# -ne 0 ]; do
    case $1 in
    -h) ;& --help)
        print_help
    ;;
    --)
        shift
        break
    ;;
    -?*)
        echo "Invalid argument: $1" 1>&2
        exit 1
    ;;
    *)
        break
    ;;
    esac
done

if [ $# -eq 0 ] || [ -z "$1" ]; then
    print_help
fi

shopt -s globstar

args=("$@")

expand_arg() {
    if [[ -d $arg ]]; then
        expanded_arg=("$arg"/**/*.vim)
    else
        expanded_arg=("$arg")
    fi
}

check_errors() {
    regex="$1"; shift
    message="$1"; shift

    for arg in "${args[@]}"; do
        expand_arg "$arg"
        # Ensure that errors from grep are not ignored, i.e. busybox's grep
        # does not have "--with-filename".
        set +e
        output="$(grep "$@" --with-filename -n "$regex" "${expanded_arg[@]}" 2>&1)"
        ret=$?
        set -e
        if (( ret > 1 )); then
          echo "$output"
          RETURN_CODE=2
          continue
        fi
        if [[ -z "$output" ]]; then
            continue
        fi

        while IFS= read -r match; do
            RETURN_CODE=1
            echo "$match $message"
        done < <(echo "$output" \
            | grep -o '^[^:]\+\(:[0-9]\+\)\?:' \
            | sed 's:^\./::')
    done
}

check_errors \
    '^\s*function.*) *$' \
    'Function without abort keyword (See :help except-compat)'
check_errors ' \+$' 'Trailing whitespace'
check_errors '^ * end\?i\? *$' 'Write endif, not en, end, or endi'
check_errors '^((    )*([^ ]|$)|\s+\\)' 'Use four spaces for indentation' -v -E
check_errors $'\t' 'Do not use tabs for indentation'
check_errors '^\s*[^" ].*[^&]l:[a-z]' 'Do not use l: prefix for local variables'
for arg in "${args[@]}"; do
    expand_arg "$arg"
    grep --files-without-match '^"[ ]vim: ts=4 sw=4 et' "${expanded_arg[@]}" \
        | while read -r f; do
            echo "$f:$(( $(wc -l "$f" | cut -f1 -d\ ) + 1)): Missing modeline"
        done
done

exit $RETURN_CODE
