+
+
+###########################
+# Interactive shells only #
+###########################
+
+if [ -z "${PS1}" ]; then
+ return
+fi
+
+
+################
+# Source files #
+################
+
+# Debian/Ubuntu don't source this from /etc/bash.bashrc
+[ -z "$BASH_COMPLETION_VERSINFO" ] && [ -r /usr/share/bash-completion/bash_completion ] && source /usr/share/bash-completion/bash_completion
+
+# This isn't sourced for interactive shells on Debian/Ubuntu/Arch
+# https://bugzilla.gnome.org/show_bug.cgi?id=697475
+[ -r /etc/profile.d/vte.sh ] && source /etc/profile.d/vte.sh
+
+
+################
+# bash options #
+################
+
+# Bash should check the terminal size after every command terminates
+shopt -s checkwinsize
+
+# Don't attempt to tab-complete an empty line
+shopt -s no_empty_cmd_completion
+
+# Prevent overwriting existing files on stdout redirection
+set -o noclobber
+
+# Better history
+shopt -s histappend
+shopt -s cmdhist
+export HISTCONTROL='erasedups:ignoredups:ignorespace'
+export HISTSIZE='100000'
+export HISTTIMEFORMAT='%F %T '
+
+
+###############
+# Pager setup #
+###############
+
+export PAGER='less'
+export LESS='RS'
+
+
+##################
+# Terminal setup #
+##################
+
+# Disable CTRL-s / CTRL-q
+stty -ixon
+
+# Use dark background colors in apps like vim
+export COLORFGBG='15;0'
+
+#############
+# Fancy PS1 #
+#############
+
+# Revision control status for git, hg, svn
+
+function find_up_exists {
+ local d="$PWD"
+ while [ -n "$d" ]; do
+ if [ -e "$d/$1" ]; then
+ return 0
+ fi
+ d="${d%/*}"
+ done
+ return 1
+}
+
+for p in /usr/lib/git-core/git-sh-prompt \
+ /usr/share/git/completion/git-prompt.sh \
+ /usr/share/git-core/contrib/completion/git-prompt.sh \
+ /usr/local/share/git-core/contrib/completion/git-prompt.sh
+do
+ [ -r "$p" ] && source "$p" && break
+done
+
+function my_git_ps1 {
+ find_up_exists .git || return
+ GIT_PS1_SHOWDIRTYSTATE=1 \
+ GIT_PS1_SHOWUNTRACKEDFILES=1 \
+ __git_ps1 ' (%s)' 2> /dev/null
+}
+
+function my_hg_ps1 {
+ find_up_exists .hg || return
+ local status
+ status="$(hg status | cut -c1 | sort -u | tr -d ' \n')"
+ echo -n " ($status)"
+}
+
+function my_svn_ps1 {
+ find_up_exists .svn || return
+ local status
+ status="$(svn status --ignore-externals 2> /dev/null | cut -c1 | sort -u | tr -d ' \n')"
+ [ -n "$status" ] && echo -n " ($status)"
+}
+
+# Two line prompt
+PS1=''
+PS1="$PS1"'\[\e[01;31m\]\u@\h\[\e[00m\]:\[\e[01;34m\]\w\[\e[00m\]'
+PS1="$PS1"'\[\e[01;36m\]$(my_git_ps1 ; my_hg_ps1 ; my_svn_ps1)\[\e[00m\]'
+PS1="$PS1"'\n\$ '
+
+
+#################################
+# Display return codes on error #
+#################################
+
+function print_exit_code {
+ local exit_code="$?"
+ if [ -z "${BASH_SOURCE[1]}" ]; then
+ printf '\e[01;33mexit code: %s\e[00m\n' \
+ "$exit_code"
+ fi
+}
+trap print_exit_code ERR
+
+
+
+####################
+# Function aliases #
+####################
+
+# This prevents long/ugly command lines from showing up in xterm titles
+function aliasf {
+ eval "function $1 { $2 \$@; }"
+}
+
+
+##########################
+# ls aliases and colours #
+##########################
+
+# GNU ls colours
+eval "$(TERM=xterm dircolors 2> /dev/null)"
+
+# BSD ls colours
+export LSCOLORS="ExFxCxDxBxEGEDABAGACAD"
+
+# Lets find the ls
+if ls --color=auto -v &> /dev/null; then
+ alias ls='ls --color=auto -v'
+elif gls --color=auto -v &> /dev/null; then
+ alias ls='gls --color=auto -v'
+elif ls -G &> /dev/null; then
+ alias ls='ls -G'
+else
+ alias ls='ls -F'
+fi
+alias ll='ls -hlF'
+alias la='ls -ha'
+alias l='ls -halF'
+
+
+##############
+# ps aliases #
+##############
+
+alias _psresources='ps -wAo pid,user,%cpu,%mem,stat,start,time,args'
+if [ "$(uname)" = "Linux" ]; then
+ aliasf pscpu '_psresources --sort -%cpu|less -S'
+ aliasf psmem '_psresources --sort -%mem|less -S'
+ aliasf pstree 'ps --forest -weo pid,user:16,args --sort start_time|less -S'
+ aliasf pstime 'ps -wAo pid,user,lstart,args --sort start_time|less -S'
+else
+ aliasf pscpu '_psresources -r|less -S'
+ aliasf psmem '_psresources -m|less -S'
+ aliasf pstime 'ps -wAo pid,user,lstart,args|less -S'
+fi
+
+#################
+# Other aliases #
+#################
+
+alias f='find . -iname'
+if echo x | grep -q --color=auto x &> /dev/null; then
+ alias grep='grep --color=auto'
+fi
+alias rg='rg -p'
+alias bc='bc -ql'
+alias watch='watch -n1'
+alias sudo='sudo ' # ability to use aliases with sudo
+aliasf sudosu 'sudo su -l -s /bin/bash'
+aliasf python 'PYTHONSTARTUP=~/.pythonrc.py python3'
+aliasf webshare 'python3 -mhttp.server'
+
+if ! command -v pbcopy &> /dev/null; then
+ alias pbcopy='xsel --clipboard --input'
+ alias pbcopym='xsel --input'
+ alias pbpaste='xsel --clipboard --output'
+ alias pbpastem='xsel --output'
+fi
+
+# man with coloured headings and a terminal title
+function man {
+ env \
+ LESS_TERMCAP_md=$'\E[01;38;5;74m' \
+ LESS_TERMCAP_me=$'\E[0m' \
+ LESS_TERMCAP_us=$'\E[04;38;5;146m' \
+ LESS_TERMCAP_ue=$'\E[0m' \
+ LC_CTYPE=C \
+ man "$@"
+}
+
+# Creates the directory if it doesn't exist, and changes into it
+function mcd {
+ # shellcheck disable=SC2164
+ mkdir -p "$1" && cd "$1"
+}
+
+# Sets the nice and ionice priorities for the current shell to the lowest values
+function slowshell {
+ ionice -c 3 -p $$
+ renice -n 19 -p $$
+}
+
+# SSH to an unknown host and print the new known_hosts entry
+function ssh_new {
+ local new_known_hosts_file
+ new_known_hosts_file="$(mktemp)"
+ ssh -o UserKnownHostsFile="$new_known_hosts_file" "$@" echo 'Connection ok'
+ cat "$new_known_hosts_file"
+ rm -f "$new_known_hosts_file"
+}
+
+# SSH without verifying host key
+function ssh_unsafe {
+ ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$@"
+}
+
+
+##################
+# Editor aliases #
+##################
+
+if emacsclient --version &> /dev/null; then
+ export ALTERNATE_EDITOR='vim'
+ export EDITOR='emacsclient --tty'
+
+ if [[ "$TERM" == screen* ]]; then
+ aliasf edit 'emacsclient --tty'
+ else
+ aliasf edit 'emacsclient --create-frame --no-wait'
+ fi
+else
+ export EDITOR='vim'
+ aliasf edit 'vim'
+fi
+
+
+#########################
+# Optional local config #
+#########################
+
+[ -r ~/.bashrc_local ] && source ~/.bashrc_local
+
+
+########################
+# Terminal integration #
+########################
+
+# When at a prompt display `workingdir (hostname)`
+function print_title_prompt {
+ printf '\e]0;bash:%s (%s)\a' \
+ "${PWD/$HOME/\~}" \
+ "$(hostname -s)"
+
+ if [[ "$TERM" == screen* ]]; then
+ printf '\ekbash\e\\'
+ fi
+}
+
+# Preserve working directory when opening new terminals
+# This depends on /etc/profile/vte.sh
+function record_terminal_cwd {
+ [ "$(type -t __vte_osc7)" = "function" ] && __vte_osc7 || true
+}
+
+function prompt_command {
+ print_title_prompt
+ record_terminal_cwd
+}
+PROMPT_COMMAND=prompt_command
+
+# Display the command about to be executed. This must go at the end of the
+# bashrc to avoid running the trap on commands in the bashrc
+function print_title_exec {
+ [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return
+
+ printf '\e]0;%s (%s)\a' \
+ "$(tr -cd '[:graph:] ' <<< "$BASH_COMMAND")" \
+ "$(hostname -s)"
+
+ if [[ "$TERM" == screen* ]]; then
+ printf '\ek%s\e\\' \
+ "$(sed -n -e 's/sudo //' -e 's/ .*//' -e 1p <<< "$BASH_COMMAND")"
+ fi
+}
+trap print_title_exec DEBUG
+
+
+###########
+# The end #
+###########