export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
export XDG_DATA_HOME="$HOME/.local/share"
export EDITOR="vim"
export VIMINIT="source $XDG_CONFIG_HOME/vim/vimrc"
export PAGER="less"
export LS_COLORS='di=34:ow=44;37:tw=44;37:st=44;37:ex=31:su=7;31:sg=7;31:ln=33:or=7;33:pi=32:do=32:bd=35:cd=35:so=32:*.bz2=36:*.dmg=36:*.gz=36:*.gpg=36:*.rar=36:*.tar=36:*.tbz2=36:*.tgz=36:*.xz=36:*.zip=36:*.orig=90:*~=90'
export GNUPGHOME="$XDG_DATA_HOME/gnupg"
export CVS_RSH="ssh"
LISTMAX=32768
WORDCHARS="*?[];!#~"
local grep=""
local grep_color="auto"
local ls=""
local ls_color="auto"
local ls_on_cd="yes"
local ls_on_init="no"
local normal_user="js"

if [ "$COLORTERM" = "24bit" -o "$COLORTERM" = "truecolor" \
    -o "$terminfo[colors]" = 16777216 ]; then
	local color_cwd="#209060"
	local color_host="#176945"
	local color_suffix="#29bc7d"
	local color_vcs="#43d696"
	local color_vcs_braces="#29bc7d"
else
	local color_cwd="29"
	local color_host="23"
	local color_suffix="36"
	local color_vcs="78"
	local color_vcs_braces="36"
fi
local color_jobs="yellow"
local color_status="red"

bindkey -v
# history-incremental-search-backward is much more useful than
# _history-complete-*
bindkey "^R" history-incremental-search-backward
# Add a few other emacs bindings for convenience, as it's sometimes quicker to
# use those than to switch between modes.
bindkey "^A" beginning-of-line
bindkey "^E" end-of-line
bindkey "^D" delete-char-or-list
# backward-kill-word behaves more like vim, whereas vi-backward-kill-word is
# the vi behaviour.
bindkey "^W" backward-kill-word

setopt no_bg_nice
setopt no_nomatch
setopt extended_glob
setopt autocd
setopt auto_pushd

autoload -U compinit
compinit -C

# Ignore case on completion
zstyle ':completion:*' matcher-list 'm:{A-Z}={a-z} m:{a-z}={A-Z}'

__has_command() {
	for i in $@; do
		which $i &>/dev/null && return 0
	done
	return 1
}
__find_command() {
	for i in $@; do
		if __has_command $i; then
			echo $i
			return 0
		fi
	done
	return 1
}

if [ -n "$grep" -o -n "$grep_color" ]; then
	: ${grep:=$(__find_command ggrep grep)}
	[ -n "$grep_color" -a "$grep_color[1]" != - ] &&
		grep_color="--color=$grep_color"
	if echo x | $grep $grep_color x &>/dev/null; then
		alias grep="$grep $grep_color"
	fi
fi
alias fgrep="grep -F"

if [ -n "$ls" -o -n "$ls_color" ]; then
	: ${ls:=$(__find_command gls ls)}
	[ -n "$ls_color" -a "$ls_color[1]" != - ] &&
		ls_color="--color=$ls_color"
	if $ls $ls_color &>/dev/null; then
		alias ls="$ls $ls_color"
	fi
fi
[ "$ls_on_cd" = yes ] && chpwd() { ls }
[ "$ls_on_init" = yes ] && ls

case $TERM_PROGRAM in
	Apple_Terminal)
		__update_terminal_cwd() {
			printf '\e]7;%s\a' "file://$HOSTNAME${PWD// /%20}"
		}
		;;
	*)
		__update_terminal_cwd() {}
		;;
esac

set_prompt() {
	if [ -n "$1" ]; then
	       	local branch="%F{$color_vcs_braces}(%F{$color_vcs}$1"
		branch+="%F{$color_vcs_braces})"
	fi

	if [ "$(whoami)" != "$normal_user" ]; then
		local user="%n@"
	fi

	PS1="%F{$color_host}$user%m %F{$color_cwd}%c$branch"
	PS1+="%F{$color_suffix}%(!.#.>)%f "
	PS2="%B>%b "
	RPS1="%(1j.%F{$color_jobs}%B%j%b%f.)%(?..%(1j. .)"
	RPS1+="%F{$color_status}%B%?%b%f)"
	RPS2="%(1_.%F{black}%B(%_%)%b%f.)"
}
set_prompt

__precmd() {
	__update_terminal_cwd

	local branch=$(fossil branch current 2>/dev/null)

	if [ -z "$branch" ]; then
		branch=$(git symbolic-ref HEAD 2>/dev/null)
		branch=${branch##refs/heads/}
	fi

	set_prompt $branch
}

case $TERM in
	aterm|Eterm|rxvt*|uxterm*|xterm*)
		# Use set_title if you want to change the term title
		set_title() {
			# Without this, precmd would override it
			precmd() { __precmd }
			print -Pn "\e]0;$@\a"
		}

		unset_title() {
			precmd() {
				print -Pn "\e]0;%c · %m\a"
				__precmd
			}
		}
		unset_title
		;;
	*)
		precmd() { __precmd }
		;;
esac

extr() {
	for i in $@; do
		case $i in
			*.7z)
				7za x $i
				;;
			*.lha)
				ofarc -x $i
				;;
			*.tar)
				ofarc -x $i
				;;
			*.tbz | *.tbz2 | *.tar.bz2)
				bzcat $i | ofarc -ttar -x -
				;;
			*.tgz | *.tar.gz)
				ofarc -x $i
				;;
			*.txz | *.tar.xz)
				xzcat $i | ofarc -ttar -x -
				;;
			*.rar)
				unrar x $i
				;;
			*.zip)
				ofarc -x $i
				;;
			# These have to be the last for obvious reasons
			*.bz2)
				bunzip2 $i
				;;
			*.gz)
				ofarc -x $i
				;;
			*.xz)
				unxz $i
				;;
			*)
				echo "$i: Unknown file type"
				false
				;;
		esac
	done
}
for ext in 7z lha tar tbz tbz2 tar.bz2 tgz tar.gz txz tar.xz rar zip bz2 gz xz
do
	alias -s "$ext=extr"
done

__has_command vim && alias vi=vim
__has_command gpg2 && alias gpg=gpg2

make() {
	case "$PWD" in
		# pkgsrc needs bmake and does not like MAKEFLAGS including -j.
		*/pkgsrc*)
			MAKEFLAGS= =$(__find_command bmake make) $@
			;;
		*)
			=make $@
			;;
	esac
}

__has_command tmux && alias tmux="tmux -f $XDG_CONFIG_HOME/tmux/tmux.conf"

if ! __has_command colordiff; then
	colordiff() {
		red="$(tput setaf 1)"
		green="$(tput setaf 2)"
		reset="$(tput sgr0)"
		sed "s/^+.*$/$green&$reset/" | sed "s/^-.*$/$red&$reset/"
	}
fi

if __has_command fossil; then
	alias fl="fossil"
	alias flc="fossil changes --differ"

	fld() {
		fossil diff -N "$@" | colordiff | less -FRX
	}

	flgrep() {
		local ret=1
		fossil changes --all . | sed 's/^.*  //' | while read file; do
			grep -H "$@" "$file" && ret=0
			[ $? -gt 1 ] && return $?
		done
		return $ret
	}

	git2fl() {
		local gitdir=$(git rev-parse --show-toplevel)/.git
		local repo=$(fossil info | awk '/^repository:/ { print $2 }')

		[ -z "$repo" ] && repo="$1"

		[ -n "$repo" -a -f "$repo" ] &&
			local incremental="--incremental"

		[ -f "$gitdir/git.marks" ] &&
			local importmarks_git="--import-marks=$gitdir/git.marks"

		if [ -f "$gitdir/fossil.marks" ]; then
			local importmarks_fossil
			importmarks_fossil="--import-marks $gitdir/fossil.marks"
		fi

		LC_ALL=C git fast-export			\
			--signed-tags=warn-strip		\
			--export-marks=$gitdir/git.marks	\
			$=importmarks_git			\
			--all |
		LC_ALL=C fossil import				\
			--git					\
			$=incremental				\
			--rename-master trunk			\
			--export-marks $gitdir/fossil.marks	\
			$=importmarks_fossil			\
			$repo
	}

	fl2git() {
		if [ -n "$1" ]; then
			local gitdir="$1/.git"
		else
			local gitdir=$(git rev-parse --show-toplevel)/.git
		fi

		[ -f "$gitdir/git.marks" ] &&
			local importmarks_git="--import-marks=$gitdir/git.marks"

		if [ -f "$gitdir/fossil.marks" ]; then
			local incremental="--incremental"
			local importmarks_fossil
			importmarks_fossil="--import-marks $gitdir/fossil.marks"
		fi

		LC_ALL=C fossil	export				\
			--git					\
			$=incremental				\
			--rename-trunk master			\
			--export-marks $gitdir/fossil.marks	\
			$=importmarks_fossil |
		LC_ALL=C git fast-import			\
			--export-marks=$gitdir/git.marks	\
			$=importmarks_git
	}
fi

if __has_command cvs; then
	cvsd() {
		cvs diff -uN "$@" | colordiff | less -FRX
	}
fi

# pkgsrc does not like MAKEFLAGS including -j
__has_command pkg_chk &&
	alias pkg_chk="MAKEFLAGS= pkg_chk"
__has_command pkg_rolling-replace &&
	alias pkg_rolling-replace="MAKEFLAGS= pkg_rolling-replace"
__has_command url2pkg &&
	alias url2pkg="MAKEFLAGS= url2pkg"

# mpv does not like locales that use , as decimal point.
__has_command mpv && alias mpv="LC_ALL=C mpv"

if __has_command gpg gpg2; then
	alias gpg-ssh="SSH_AUTH_SOCK=$GNUPGHOME/S.gpg-agent.ssh ssh"
	alias gpg-ssh-add="SSH_AUTH_SOCK=$GNUPGHOME/S.gpg-agent.ssh ssh-add"
	alias gpg-sftp="SSH_AUTH_SOCK=$GNUPGHOME/S.gpg-agent.ssh sftp"
fi

if __has_command cryptopassphrase; then
	pwnk() {
		local clipboard
		if __has_command pbcopy; then
			clipboard=pbcopy
		elif __has_command xclip; then
			clipboard=xclip
		else
			echo "No clipboard handler found!"
			return 1
		fi

		cryptopassphrase $@ | tr -d '\n' | $clipboard
	}
	alias pw="pwnk -k ~/.cryptopassphrase.key"
	alias pws="pwnk -k ~/.cryptopassphrase-server.key"
fi

ixio() { curl -F 'f:1=<-' ix.io }
0x0st() { curl -F'file=@-' https://0x0.st }

cross() {
	if [ $# = 0 ]; then
		echo 'Usage: cross platform [architecture1] [architecture2]' \
		     1>&2
		return 1
	fi

	case "$1" in
		3ds | nds)
			if [ -z "$DEVKITPRO" ]; then
				echo "Please set DEVKITPRO!" 1>&2
				return 1
			fi
			if [ -z "$DEVKITARM" ]; then
				echo "Please set DEVKITARM!" 1>&2
				return 1
			fi

			export PATH="$DEVKITARM/bin:$PATH"
			export cross_host="arm-none-eabi"
			export objfw_configure_flags="--with-$1"
			;;
		amiga)
			case "$2" in
				m68k)
					if [ -z "$amiga_gcc_path" ]; then
						echo -n "Please set " 1>&2
						echo "amiga_gcc_path!" 1>&2
						return 1
					fi

					export PATH="$amiga_gcc_path/bin:$PATH"
					export cross_host="m68k-amigaos"
					;;
				ppc)
					if [ -z "$adtools_path" ]; then
						echo -n "Please set " 1>&2
						echo "adtools_path!" 1>&2
						return 1
					fi

					export PATH="$adtools_path/bin:$PATH"
					export cross_host="ppc-amigaos"
					;;
			esac

			if [ $# != 2 -o -z "$cross_host" ]; then
				echo "Usage: cross amiga m68k|ppc" 1>&2
				return 1
			fi
			;;
		ios | iossim)
			if ! __has_command xcrun; then
				echo -n "Can only cross-compile for iOS " 1>&2
				echo "on a Mac with Xcode!" 1>&2
				return 1
			fi

			case "$1" in
				ios)
					local sdk_type=iphoneos
					local default_archs="arm64"
					;;
				iossim)
					local sdk_type=iphonesimulator
					local default_archs="x86_64"
					;;
			esac

			local sdk="$(xcrun --show-sdk-path --sdk $sdk_type)"
			local archs="${@:2}"

			if [ ${(w)#archs} = 0 ]; then
				archs="$default_archs"
			fi

			export CC="clang --sysroot $sdk"
			export CPP="clang -E --sysroot $sdk"
			export CXX="clang++ --sysroot $sdk"
			export CXXPP="clang++ -E -=sysroot $sdk"

			for arch in $=archs; do
				export CC="$CC -arch $arch"
				export CXX="$CXX -arch $arch"
			done
			export CPP="$CPP -arch $archs[(w)1]"
			export CXXPP="$CXXPP -arch $archs[(w)1]"

			export OBJC="$CC"
			export OBJCPP="$CPP"
			export OBJCXX="$CXX"
			export OBJCPPXX="$CXXPP"
			export IPHONEOS_DEPLOYMENT_TARGET="10.0"
			export cross_host="$archs[(w)1]-apple-darwin"
			;;
		mingw)
			case "$2" in
				i686 | x86_64)
					local pkg="mingw-w64-$2-gcc"
					export cross_host="$2-w64-mingw32"
					;;
			esac

			if [ $# != 2 -o -z "$cross_host" ]; then
				echo "Usage: cross mingw i686|x86_64" 1>&2
				return 1
			fi

			local prefix="$(pkg_info -qp $pkg 2>/dev/null |
			                awk '/^@cwd/ { print $2; exit }')"
			if [ -z "$prefix" ]; then
				echo "Please install $pkg from pkgsrc!" 1>&2
				return 1
			fi

			export PATH="$prefix/cross/$cross_host/bin:$PATH"
			;;
		morphos)
			local pkg="ppc-morphos-gcc-9"
			local prefix="$(pkg_info -qp $pkg 2>/dev/null |
			                awk '/^@cwd/ { print $2; exit }')"
			if [ -z "$prefix" ]; then
				echo "Please install $pkg from pkgsrc!" 1>&2
				return 1
			fi

			export PATH="$prefix/gg/bin:$PATH"
			export CC="ppc-morphos-gcc-9"
			export CXX="ppc-morphos-g++-9"
			export OBJC="$CC"
			export OBJCXX="$CXX"
			export cross_host="ppc-morphos"
			;;
		switch)
			if [ -z "$DEVKITPRO" ]; then
				echo "Please set DEVKITPRO!"
				return 1
			fi
			if [ -z $"DEVKITA64" ]; then
				echo "Please set DEVKITA64!"
				return 1
			fi

			export PATH="$DEVKITA64/bin:$PATH"
			export cross_host="aarch64-none-elf"
			export objfw_configure_flags="--with-$1"
			;;
		wii | wii-u)
			if [ -z "$DEVKITPRO" ]; then
				echo "Please set DEVKITPRO!"
				return 1
			fi
			if [ -z "$DEVKITPPC" ]; then
				echo "Please set DEVKITPPC!"
				return 1
			fi

			export PATH="$DEVKITPPC/bin:$PATH"
			export cross_host="powerpc-eabi"
			export objfw_configure_flags="--with-$1"
			;;
		*)
			echo "Unknown target: $1" 1>&2
			return 1
			;;
	esac

	export objfw_configure_flags=(
		--host=$cross_host
		$=objfw_configure_flags
	)
}

unset fgrep grep grep_color ls ls_color ls_on_cd ls_on_init simple_prompt
unset HISTFILE
