aboutsummaryrefslogtreecommitdiff
#!/bin/sh
# shellcheck disable=2034
set -eu

MSG_USAGE_EN='Usage:  git permalink [-phV] FILE [LINENO]'
MSG_USAGE_PT='Uso:  git permalink [-phV] ARQUIVO [NOLINHA]'
MSG_USAGE_FR='Usage:  git permalink [-phV] FICHIER [LINENO]'
MSG_USAGE_EO='Uzmaniero:  git permalink [-phV] DOSIERO [LINIONO]'

MSG_HELP_EN='Options:
  -p             only print the link, don'"'"'t try to open it
  -h, --help     show this help message
  -V, --version  print the version number'
MSG_HELP_PT='Opções:
  -p             somemente imprime o link, não tenta abrí-lo
  -h, --help     mostra esta mensagem de ajuda
  -V, --version  imprime o número de versão'
MSG_HELP_FR='Options:
  -p             seulement imprimez le lien, n'"'"'essayez pas de l'"'"'ouvrir
  -h, --help     afficher ce message d'"'"'aide
  -V, --version  imprime le numeró de version'
MSG_HELP_EO='Ebloj:
  -p             nur presas la ligon, ne provas malfermi ĝin
  -h, --help     montras ĉi tiun helpmesaĝon
  -V, --version  presas la versian numeron'

MSG_MISSING_FILE_EN="Missing FILE argument."
MSG_MISSING_FILE_PT="Faltando argumento ARQUIVO."
MSG_MISSING_FILE_FR="L'argument FICHIER manque."
MSG_MISSING_FILE_EO="La argumento DOSIERO mankas."

MSG_UNSUPPORTED_ORIGIN_EN='Unsupported origin: %s.

Add an template override to use git-permalink (see "man git-permalink.1" for instructions).'

MSG_UNSUPPORTED_ORIGIN_PT='Origem sem suporte: %s.

Adicione um modelo de substituição para usar o git-permalink (veja "man git-permalink.1" para mais instruções).'
MSG_UNSUPPORTED_ORIGIN_FR='Origine n'"'"'es pas supporté: %s.

Ajouter un modèle de remplacement pour utilisér git-permalink (regarde "man git-permalink.1" pour les instructions).'

MSG_UNSUPPORTED_ORIGIN_EO='Origo ne estas subtenata: %s.

Aldoni anstataŭan ŝablonon por uzi git-permalink (vidu "man git-permalink.1" por instrukcioj).'

MSG_OPEN_EN='Opening %s'
MSG_OPEN_PT='Abrindo %s'
MSG_OPEN_FR='Ouverture de %s'
MSG_OPEN_EO='Malfermado de %s'

set_lang() {
	lang="$1"
	eval "
MSG_USAGE=\$MSG_USAGE_$lang
MSG_HELP=\$MSG_HELP_$lang
MSG_MISSING_FILE=\$MSG_MISSING_FILE_$lang
MSG_UNSUPPORTED_ORIGIN=\$MSG_UNSUPPORTED_ORIGIN_$lang
MSG_OPEN=\$MSG_OPEN_$lang
"
}

case "${LANG:-}" in
	pt_BR.UTF-8*)
		set_lang PT
		;;
	fr_FR.UTF-8*)
		set_lang FR
		;;
	eo.UTF-8*)
		set_lang EO
		;;
	*)
		set_lang EN
		;;
esac

usage() {
	printf '%s\n' "$MSG_USAGE"
}

help() {
	printf '\n%s\n' "$MSG_HELP"
}

version() {
	printf 'git-permalink-@VERSION@ @DATE@\n'
}

PRINTONLY=false
if [ "${1:-}" = '-p' ]; then
	PRINTONLY=true
	shift
fi
if [ -z "${1:-}" ]; then
	printf '%s\n\n' "$MSG_MISSING_FILE" >&2
	usage >&2
	exit 2
fi
FILE="$1"

# shellcheck disable=2068
for flag in $@; do
	case "$flag" in
		-h|--help)
			usage
			help
			exit
			;;
		-V|--version)
			version
			exit
			;;
		*)
			;;
	esac
done

FILE="${1:-}"
MYLINENO="${2:-}"
COMMIT="$(git rev-parse HEAD)"
ORIGIN="$(git config remote.origin.url)"
OVERRIDE_CF="$(git config git-permalink.template-commit-file ||:)"
OVERRIDE_FC="$(git config git-permalink.template-file-commit ||:)"
REPOSITORY="$(basename "$PWD")"

normalize_origin() {
	if echo "$ORIGIN" | grep -q '^git@'; then
		NAME="$(echo "$ORIGIN" | cut -d: -f2 | cut -d/ -f1)"
		URL="$(echo "$ORIGIN" | cut -d@ -f2 | cut -d: -f1)"
		ORIGIN="https://$URL/$NAME/$REPOSITORY"
	fi
}

lineno_with_l() {
	if echo "$MYLINENO" | grep -q -- -; then
		P1="$(echo "$MYLINENO" | cut -d- -f1)"
		P2="$(echo "$MYLINENO" | cut -d- -f2)"
		printf '#L%s-L%s' "$P1" "$P2"
	elif [ -n "$MYLINENO" ]; then
		printf '#L%s' "${MYLINENO}"
	else
		printf ''
	fi
}

euandreh() {
	printf 'https://git.euandreh.xyz/%s/tree/%s?id=%s%s\n' "$REPOSITORY" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}"
}

sourcehut() {
	printf '%s/tree/%s/item/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#L$MYLINENO}"
}

kernel() {
	printf '%s/tree/%s?id=%s%s\n' "$ORIGIN" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}"
}

savannah() {
	printf '%s/tree/%s?id=%s%s\n' "$(echo "$ORIGIN" | sed 's|gnu.org/git|gnu.org/cgit|')" "$FILE" "$COMMIT" "${MYLINENO:+#n$MYLINENO}"
}

notabug() {
	normalize_origin
	printf '%s/src/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)"
}

codeberg() {
	normalize_origin
	printf '%s/src/commit/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)"
}

bitbucket() {
	normalize_origin
	printf '%s/src/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#lines-$(echo "$MYLINENO" | tr '-' ':')}"
}

pagure() {
	printf '%s/blob/%s/f/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#_$MYLINENO}"
}

gitlab() {
	normalize_origin
	printf '%s/-/blob/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "${MYLINENO:+#L$MYLINENO}"
}

github() {
	normalize_origin
	printf '%s/blob/%s/%s%s\n' "$ORIGIN" "$COMMIT" "$FILE" "$(lineno_with_l)"
}

guess_permalink() {
	if [ -n "$OVERRIDE_CF" ]; then
		# shellcheck disable=2059
		printf "$OVERRIDE_CF\n" "$COMMIT" "$FILE"
	elif [ -n "$OVERRIDE_FC" ]; then
		# shellcheck disable=2059
		printf "$OVERRIDE_FC\n" "$FILE" "$COMMIT"
	else
		case "$ORIGIN" in
			*euandreh.xyz*)
				euandreh
				;;
			*git.sr.ht*)
				sourcehut
				;;
			*git.kernel.org*)
				kernel
				;;
			*git.savannah.gnu.org*)
				savannah
				;;
			*notabug.org*)
				notabug
				;;
			*codeberg.org*)
				codeberg
				;;
			*bitbucket.org*)
				bitbucket
				;;
			*pagure.io*)
				pagure
				;;
			*gitlab.com*)
				gitlab
				;;
			*github.com*)
				github
				;;
			*)
				# shellcheck disable=2059
				printf "$MSG_UNSUPPORTED_ORIGIN\n" "$ORIGIN" >&2
				exit 1
				;;
		esac
	fi
}

LINK="$(guess_permalink)"
if [ "$PRINTONLY" = true ]; then
	echo "$LINK"
else
	# shellcheck disable=2059
	printf "$MSG_OPEN\n" "$LINK" >&2
	xdg-open "$LINK"
fi