#!/usr/bin/env bash
# vim:fdm=marker
#
# Fetch info about your system
# https://github.com/dylanaraps/fetch
#
# Required Dependencies:
#   Bash 4.0+
#   Text formatting, dynamic image size and padding: tput
#   [Linux / BSD / Windows] Uptime detection: procps or procps-ng
#
# Optional Dependencies: (You'll lose these features without them)
#   Displaying Images: w3m + w3m-img
#   Image Cropping: ImageMagick
#   More accurate window manager detection: wmctrl
#   [ Linux / BSD ] Wallpaper Display: feh, nitrogen or gsettings
#   [ Linux / BSD ] Current Song: mpc or cmus
#   [ Linux / BSD ] Resolution detection: xorg-xdpyinfo
#
# Created by Dylan Araps
# https://github.com/dylanaraps/

# Speed up script by not using unicode
SYS_LOCALE="$LANG"
export LC_ALL=C
export LANG=C

# Config Options {{{


# Info Options {{{


# Info
# See this wiki page for more info:
# https://github.com/dylanaraps/fetch/wiki/Customizing-Info
printinfo () {
    info linebreak

    info title
    info underline

    info "OS" distro
    info "Kernel" kernel
    info "Uptime" uptime
    info "Packages" packages
    info "Shell" shell
    info "Desktop Environment" de
    info "Window Manager" wm
    info "GTK Theme" gtktheme
    info "Icons" gtkicons
    info "CPU" cpu
    info "GPU" gpu
    info "Memory" memory

    # info "Font" gtkfont
    # info "Disk" disk
    # info "Resolution" resolution
    # info "Battery" battery
    # info "Song" song
    # info "Local IP" localip
    # info "Public IP" public
    # info "Birthday" birthday
    # info "Visual Style" visualstyle

    info linebreak
    info cols
    info linebreak
}


# Kernel

# Show more kernel info
# --kernel_shorthand on/off
kernel_shorthand="on"


# Distro

# Mac OS X hide/show build version
# --osx_buildversion on/off
osx_buildversion="on"

# Show 'x86_64' and 'x86' in 'Distro:' output.
# --os_arch on/off
os_arch="on"


# Uptime

# Shorten the output of the uptime function
# --uptime_shorthand tiny, on, off
uptime_shorthand="off"


# Shell

# Show the path to $SHELL
# --shell_path on/off
shell_path="on"

# Show $SHELL's version
# --shell_version on/off
shell_version="off"


# CPU

# CPU speed type
# Only works on Linux with cpufreq.
# --speed_type current, min, max, bios,
# scaling_current, scaling_min, scaling_max
speed_type="max"


# GPU

# Shorten output of the getgpu funcion
# --gpu_shorthand on/off
gpu_shorthand="on"


# Gtk Theme / Icons

# Shorten output (Hide [GTK2] etc)
# --gtk_shorthand on/off
gtk_shorthand="off"


# Enable/Disable gtk2 theme/icons output
# --gtk2 on/off
gtk2="on"

# Enable/Disable gtk3 theme/icons output
# --gtk3 on/off
gtk3="on"


# Battery

# Which battery to display.
# By default we display all batteries.
# NOTE: Only works on Linux.
# --battery_num all, 0, 1, 2, etc
battery_num="all"

# Whether or not to print each battery on the same line.
# By default each battery gets its own line and title.
# NOTE: Only works on Linux.
# --battery_shorthand on/off
battery_shorthand="off"


# IP Address

# Website to ping for the public IP
# --ip_host url
public_ip_host="http://ident.me"


# Birthday

# Whether to show a long pretty output
# or a shortened one
# NOTE: Long pretty output doesn't work on OpenBSD or NetBSD.
# --birthday_shorthand on/off
birthday_shorthand="off"

# Whether to show the time in the output
# --birthday_time on/off
birthday_time="on"

# Color Blocks

# Color block range
# --block_range start end
start=0
end=7

# Toggle color blocks
# --color_blocks on/off
color_blocks="on"

# Color block width
# --color_block_width num
block_width=3


# }}}

# Text Colors {{{


# --title_color num
title_color=4

# Color of "@" symbol in title
# --at_color num
at_color=6

# --subtitle_color num
subtitle_color=1

# --colon_color num
colon_color=8

# --underline_color num
underline_color=8

# --info_color num
info_color=6


# }}}

# Text Options {{{


# Toggle line wrapping
# --line_wrap on/off
line_wrap="on"

# Toggle bold text
# --bold on/off
bold="on"

# Enable/Disable Underline
# --underline on/off
underline="on"

# Underline character
# --underline_char char
underline_char="-"

# Prompt height
# You should only have to change this if your
# prompt is greater than 2 lines high.
# --prompt_height num
prompt_height=1


# }}}

# Image Options {{{


# Image Source
# --image wall, shuffle, ascii, /path/to/img, off
image="wall"

# Thumbnail directory
thumbnail_dir="$HOME/.cache/thumbnails/fetch"

# Image Backend
# Which program to draw images with
# --image_backend w3m, iterm2
image_backend="w3m"

# W3m-img path
# Some systems have this in another location
w3m_img_path="/usr/lib/w3m/w3mimgdisplay"

# Image position
# Only works with the w3m backend
# --image_position left/right
image_position="left"

# Shuffle dir
shuffle_dir="$HOME/Pictures/wallpapers/wash"

# Crop mode
# --crop_mode normal/fit/fill
crop_mode="normal"

# Crop offset
# Only affects normal mode.
# --crop_offset northwest/north/northeast/west/center
#               east/southwest/south/southeast
crop_offset="center"

# Font width
# Used when calculating dynamic image size
# --font_width num
font_width=5

# Image size
# The image is half the terminal width by default.
# --size half, px
image_size="half"

# Right gap between image and text
# --gap num
gap=4

# Image offsets
# --xoffset px
# --yoffset px
yoffset=0
xoffset=0


# }}}

# Ascii Options {{{


# Default ascii image to use
# When this is set to distro it will use your
# distro's logo as the ascii.
# --ascii 'distro', path/to/ascii
ascii="distro"

# Ascii colors
# When this is set to distro it will use your
# ditro's colors to color the ascii.
# NOTE: You can also set this to a range of colors
# which will allow you to custom color distro logos
# --ascii_colors distro
# --ascii_colors 2 4 5 6
ascii_colors=(distro)


# }}}

# Scrot Options {{{


# Whether or not to always take a screenshot
# You can manually take a screenshot with "--scrot" or "-s"
scrot="off"

# Screenshot program to launch
# --scrot_cmd
scrot_cmd="scrot -c -d 3"

# Scrot dir
# Where to save the screenshots
# --scrot_dir /path/to/screenshot/folder
scrot_dir="$HOME/Pictures"

# Scrot filename
# What to name the screenshots
# --scrot_name str
scrot_name="fetch-%Y-%m-%d-%H:%M.png"


# }}}

# Config Options {{{


# Enable/Disable config file
# --config off, none
config="on"

# Path to custom config file location
# --config path/to/config
config_file="$HOME/.config/fetch/config"


# }}}

# Other Options {{{

# Separator to use in stdout mode.
# --stdout_separator string
stdout_separator="    "

# Hide/Show the title in stdout mode.
# --stdout_title on/off
stdout_title="off"

# Hide/Show each info's subtitle in stdout mode.
# --stdout_subtitles on/off
stdout_subtitles="on"

# }}}


# }}}


# Gather Info {{{


# Operating System {{{

case "$(uname)" in
    "Linux")
        os="Linux"
    ;;

    "Darwin")
        os="Mac OS X"
    ;;

    "OpenBSD")
        os="OpenBSD"
    ;;

    *"BSD")
        os="BSD"
    ;;

    "CYGWIN"*)
        os="Windows"
    ;;

    *)
        printf "%s\n" "Couldn't detect OS, exiting"
        exit 1
    ;;
esac

# }}}

# Distro {{{

# Default bit style
x64="x86_64"
x32="x86"

case "$os" in
    "Linux" )
        if type -p lsb_release >/dev/null 2>&1; then
            distro="$(lsb_release -a 2>/dev/null | awk -F':' '/Description/ {printf $2}')"
            distro=${distro/[[:space:]]}
        elif type -p crux >/dev/null 2>&1; then
            distro="CRUX"
        else
            distro="$(grep -h '^NAME=' /etc/*ease)"
            distro=${distro#NAME\=*}
            distro=${distro#\"*}
            distro=${distro%*\"}
        fi
    ;;

    "Mac OS X")
        distro="Mac OS X $(sw_vers -productVersion)"

        [ "$osx_buildversion" == "on" ] && \
            distro+=" $(sw_vers -buildVersion)"
    ;;

    "OpenBSD")
        distro="OpenBSD"
    ;;

    "BSD")
        distro="$(uname -v)"
        distro=${distro%% *}
    ;;

    "Windows")
        distro="$(wmic os get Caption /value)"

        # Strip crap from the output of wmic
        distro=${distro/Caption'='}
        distro=${distro//[[:space:]]/ }
        distro=${distro//  }
        distro=${distro/Microsoft }

        # Change bits to xx-bit for Windows
        x64="64-bit"
        x32="32-bit"
    ;;

    *)
        distro="Unknown"
    ;;
esac
ascii_distro="$distro"

getdistro () {
    # Get architecture
    if [ "$os_arch" == "on" ]; then
        case "$(getconf LONG_BIT)" in
            64) distro+=" $x64" ;;
            32) distro+=" $x32" ;;
        esac
    fi
}


# }}}

# Title {{{

gettitle () {
    title="${USER}@$(hostname)"
}

# }}}

# Kernel {{{

getkernel() {
    case "$kernel_shorthand" in
        "on")  kernel="$(uname -r)" ;;
        "off") kernel="$(uname -srm)" ;;
    esac
}

# }}}

# Uptime {{{

getuptime () {
    case "$os" in
        "Linux")
            case "$distro" in
                "Puppy Linux"* | "Quirky Werewolf"* | "Precise Puppy"*)
                    uptime=$(uptime | awk -F ':[0-9]{2}+ |(, ){1}+' '{printf $2}')
                    uptime=${uptime/  / }
                ;;

                "openSUSE"*)
                    uptime=$(uptime | awk -F ':[0-9]{2}+[a-z][a-z]  |(, ){1}+' '{printf $2}')
                    uptime=${uptime/   / }
                ;;

                *)
                    uptime="$(uptime -p)"
                ;;
            esac
        ;;

        "Mac OS X" | *"BSD")
            # Get boot time in seconds
            boot="$(sysctl -n kern.boottime)"
            boot="${boot/{ sec = }"
            boot=${boot/,*}

            # Get current date in seconds
            now=$(date +%s)
            uptime=$((now - boot))

            # Convert uptime to days/hours/mins
            mins=$((uptime / 60%60))
            hours=$((uptime / 3600%24))
            days=$((uptime / 86400))

            # Format the output like Linux's "uptime -p" cmd.
            case "$mins" in
                0) ;;
                1) uptime="up $mins minute" ;;
                *) uptime="up $mins minutes" ;;
            esac

            case "$hours" in
                0) ;;
                1) uptime="up $hours hour, ${uptime/up }" ;;
                *) uptime="up $hours hours, ${uptime/up }" ;;
            esac

            case "$days" in
                0) ;;
                1) uptime="up $days day, ${uptime/up }" ;;
                *) uptime="up $days days, ${uptime/up }" ;;
            esac
        ;;

        "Windows")
            uptime=$(uptime | awk -F ':[0-9]{2}+ |(, ){1}+' '{printf $2}')
            uptime=${uptime/  / }
        ;;

        *)
            uptime="Unknown"
        ;;
    esac

    # Make the output of uptime smaller.
    case "$uptime_shorthand" in
        "on")
            uptime=${uptime/up}
            uptime=${uptime/minutes/mins}
            uptime=${uptime/minute/min}
            uptime=${uptime# }
        ;;

        "tiny")
            uptime=${uptime/up}
            uptime=${uptime/ days/d}
            uptime=${uptime/ day/d}
            uptime=${uptime/ hours/h}
            uptime=${uptime/ hour/h}
            uptime=${uptime/ minutes/m}
            uptime=${uptime/ minute/m}
            uptime=${uptime/,}
            uptime=${uptime# }
        ;;
    esac
}

# }}}

# Package Count {{{

getpackages () {
    case "$distro" in
        "Arch Linux"* | "Parabola"* | "Manjaro"* | "Antergos"*)
            packages="$(pacman -Qq --color never | wc -l)"
        ;;

        "void"*)
            packages="$(xbps-query -l | wc -l)"
        ;;

        "Ubuntu"* | *"Mint"* | "CrunchBang"* | "Debian"* | "Kali"* | "Deepin Linux"* | "elementary"* | "Raspbian"*)
            packages="$(dpkg --get-selections | grep -cv deinstall$)"
        ;;

        "Slackware"*)
            packages="$(ls -1 /var/log/packages | wc -l)"
        ;;

        "Gentoo"* | "Funtoo"*)
            packages="$(ls -d /var/db/pkg/*/* | wc -l)"
        ;;

        "Fedora"* | "openSUSE"* | "Red Hat Enterprise Linux"* | "CentOS"* | "Mageia"*)
            packages="$(rpm -qa | wc -l)"
        ;;

        "CRUX"*)
            packages="$(pkginfo -i | wc -l)"
        ;;

        "Mac OS X"*)
            if [ -d "/usr/local/bin" ]; then
                local_packages=$(ls -l /usr/local/bin/ | grep -v "\(../Cellar/\|brew\)" | wc -l)
                packages=$((local_packages - 1))
            fi

            if type -p port >/dev/null 2>&1; then
                port_packages=$(port installed 2>/dev/null | wc -l)
                packages=$((packages + $((port_packages - 1))))
            fi

            if type -p brew >/dev/null 2>&1; then
                brew_packages=$(brew list -1 2>/dev/null | wc -l)
                packages=$((packages + brew_packages))
            fi

            if type -p pkgin >/dev/null 2>&1; then
                pkgsrc_packages=$(pkgin list 2>/dev/null | wc -l)
                packages=$((packages + pkgsrc_packages))
            fi
        ;;

        "OpenBSD"* | "NetBSD"*)
            packages=$(pkg_info | wc -l)
        ;;

        "FreeBSD"*)
            packages=$(pkg info | wc -l)
        ;;

        "Windows"*)
            packages=$(cygcheck -cd | wc -l)

            # Count chocolatey packages
            if [ -d "/cygdrive/c/ProgramData/chocolatey/lib" ]; then
                choco_packages=$(ls -1 /cygdrive/c/ProgramData/chocolatey/lib | wc -l)
                packages=$((packages + choco_packages))
            fi
        ;;

        *)
            packages="Unknown"
        ;;
    esac

    packages=${packages// }
}

# }}}

# Shell {{{

getshell () {
    case "$shell_path" in
        "on")  shell="$SHELL" ;;
        "off") shell="${SHELL##*/}" ;;
    esac

    if [ "$shell_version" == "on" ]; then
        shell+=" "
        case "$shell" in
            *"bash"*)
                shell+="$(bash --version | head -n 1)"
                shell=${shell/ *, version}
            ;;

            *"zsh"*)
                shell+="$(zsh --version)"
                shell=${shell/ zsh}
            ;;

            *"mksh"* | *"ksh")
                shell+="$("$SHELL" -c 'printf "%s" "$KSH_VERSION"')"
                shell=${shell/ * KSH}
            ;;

            *"tcsh"* | *"csh"*)
                shell+="$("$SHELL" --version)"
                shell=${shell/tcsh}
                shell=${shell/\(*}
            ;;
        esac

        shell="${shell/\(*\)}"
    fi
}

# }}}

# Desktop Environment {{{

getde () {
    [ "$XDG_CURRENT_DESKTOP" ] && de="$XDG_CURRENT_DESKTOP"
}

# }}}

# Window Manager {{{

getwm () {
    if type -p wmctrl >/dev/null 2>&1; then
        wm="$(wmctrl -m | head -n1)"
        wm=${wm/Name: }

    elif [ "$XINITRC" ]; then
        wm=$(grep "^[^#]*exec" "$XINITRC" | tail -n 1)

    elif [ -e "$HOME/.xinitrc" ]; then
        wm=$(grep "^[^#]*exec" "${HOME}/.xinitrc" | tail -n 1)

    else
        case "$os" in
            "Mac OS X") wm="Quartz Compositor" ;;
            "Windows") wm="Explorer" ;;
            *) wm="Unknown" ;;
        esac
    fi

    wm="${wm/exec }"
    wm="${wm/-session}"
    wm="${wm^}"
}

# }}}

# CPU {{{

getcpu () {
    case "$os" in
        "Linux")
            # Get cpu name
            cpu="$(grep -F 'model name' /proc/cpuinfo)"
            cpu=${cpu/model name*: }
            cpu=${cpu/ @*}
            cpu=${cpu%% }

            # Get cpu speed
            if [ -d "/sys/devices/system/cpu/cpu0/cpufreq" ]; then
                case "$speed_type" in
                    current) speed_type="scaling_cur_freq" ;;
                    min) speed_type="scaling_min_freq" ;;
                    max) speed_type="scaling_max_freq" ;;
                    bios) speed_type="bios_limit" ;;
                    scaling_current) speed_type="scaling_cur_freq" ;;
                    scaling_min) speed_type="scaling_min_freq" ;;
                    scaling_max) speed_type="scaling_max_freq" ;;
                esac

                read -r speed < \
                    /sys/devices/system/cpu/cpu0/cpufreq/${speed_type}

            else
                speed=$(awk -F ': ' '/cpu MHz/ {printf $2; exit}' /proc/cpuinfo)
                speed=${speed/\.}
            fi

            # Convert mhz to ghz without bc
            speed=$((speed / 100000))
            speed=${speed:0:1}.${speed:1}

            cpu="$cpu @ ${speed}GHz"
        ;;

        "Mac OS X")
            cpu="$(sysctl -n machdep.cpu.brand_string)"
        ;;

        *"BSD")
            case "$distro" in
                "OpenBSD"* | "FreeBSD"*)
                    # Get cpu name
                    cpu="$(sysctl -n hw.model)"
                    cpu=${cpu/ @*}
                    cpu=${cpu//  }
                    cpu=${cpu% }

                    # Get cpu speed
                    case "$distro" in
                        "OpenBSD"*) speed=$(sysctl -n hw.cpuspeed) ;;
                        "FreeBSD"*) speed=$(sysctl -n hw.clockrate) ;;
                    esac
                    speed=$((speed / 100))
                ;;

                "NetBSD"*)
                    # Get cpu name
                    cpu="$(grep -F 'model name' /proc/cpuinfo)"
                    cpu=${cpu/model name*: }
                    cpu=${cpu/ @*}
                    cpu=${cpu//  }
                    cpu=${cpu% }

                    # Get cpu speed
                    speed="$(grep -F 'cpu MHz' /proc/cpuinfo)"
                    speed=${speed/cpu MHz*: }
                    speed=${speed/\.}
                    speed=$((speed / 10000))
                ;;
            esac

            speed=${speed:0:1}.${speed:1}
            cpu="$cpu @ ${speed}GHz"
        ;;

        "Windows")
            # Get cpu name
            cpu="$(grep -F 'model name' /proc/cpuinfo)"
            cpu=${cpu/model name*: }
            cpu=${cpu/ @*}
            cpu=${cpu//  }
            cpu=${cpu% }

            # Get cpu speed
            speed=$(grep -F 'cpu MHz' /proc/cpuinfo)
            speed=${speed/cpu MHz*: }
            speed=${speed/\.}

            # Convert mhz to ghz without bc
            speed=$((speed / 100000))
            speed=${speed:0:1}.${speed:1}
            cpu="$cpu @ ${speed}GHz"
        ;;

        *)
            cpu="Unknown"
        ;;
    esac

    # Remove uneeded patterns from cpu output
    # This is faster than sed/gsub
    cpu=${cpu//(tm)}
    cpu=${cpu//(TM)}
    cpu=${cpu//(r)}
    cpu=${cpu//(R)}
    cpu=${cpu// CPU}
    cpu=${cpu// Processor}
    cpu=${cpu// Six-Core}
    cpu=${cpu// Eight-Core}
    cpu=${cpu// with Radeon HD Graphics}
}

# }}}

# GPU {{{

getgpu () {
   case "$os" in
       "Linux")
            gpu="$(PATH="/sbin:$PATH" lspci | grep -F "3D")"

            # If a GPU with a prefix of '3D' doesn't exist
            # fallback to looking for a prefix of 'VGA'
            [ -z "$gpu" ] && \
            gpu="$(PATH="/sbin:$PATH" lspci | grep -F "VGA")"
            gpu=${gpu//??':'??'.'?}

            # Count the number of GPUs
            count="$(printf "%s" "$gpu" | uniq -c)"
            count=${count/ VGA*}
            count=${count/ 3D*}
            count=${count//[[:space:]]}

            # If there's more than one gpu
            # Display the count.
            if [ "$count" -gt 1 ]; then
                count=" x $count"
            else
                unset count
            fi

            # Format the output
            gpu=${gpu/* VGA compatible controller: }
            gpu=${gpu/* 3D controller: }
            gpu=${gpu/(rev*)}

            shopt -s nocasematch
            case "$gpu" in
                intel*)
                    gpu=${gpu/Intel Corporation }
                    gpu=${gpu/Haswell-??? }
                    gpu=${gpu/?th Gen Core Processor}

                    brand="Intel "
                ;;

                advanced*)
                    gpu=${gpu/Advanced Micro Devices, Inc\. }
                    gpu=${gpu/'[AMD/ATI]' }
                    gpu=${gpu/Tahiti PRO}
                    gpu=${gpu/Seymour}
                    gpu=${gpu/ OEM}
                    gpu=${gpu/ Cape Verde}
                    gpu=${gpu/ \[}
                    gpu=${gpu/\]}

                    brand="AMD "
                ;;

                nvidia*)
                    gpu=${gpu/NVIDIA Corporation }
                    gpu=${gpu/nVidia Corporation }
                    gpu=${gpu/G????M }
                    gpu=${gpu/G???? }
                    gpu=${gpu/\[}
                    gpu=${gpu/\] }

                    brand="Nvidia "
                ;;

                *virtualbox*)
                    gpu="VirtualBox Graphics Adapter"
                ;;
            esac

            gpu="${brand}${gpu}"
        ;;

        "Mac OS X")
            gpu=$( \
                system_profiler SPDisplaysDataType | \
                awk -F': ' '/^\ *Chipset Model:/ {printf $2}' | \
                awk '{ printf "%s ", $0 }'
            )
            gpu=${gpu//'/ $'}
        ;;

        *"BSD")
            case "$distro" in
                "FreeBSD"*)
                    gpu=$(pciconf -lv 2>/dev/null | grep -B 4 "VGA" | grep "device")
                    gpu=${gpu/device*= }
                    gpu=${gpu//\'}
                    gpu=${gpu//[[:space:]]/ }
                    gpu=${gpu//  }
                ;;

                *)
                    gpu="Unknown"
                ;;
            esac
        ;;


        "Windows")
            gpu=$(wmic path Win32_VideoController get caption /value)
            gpu=${gpu/Caption'='}
            gpu=${gpu//[[:space:]]/ }
            gpu=${gpu//  }
        ;;
    esac

    if [ "$gpu_shorthand" == "on" ]; then
        gpu=${gpu// Rev\. ?}
        gpu=${gpu//AMD\/ATI/AMD}
        gpu=${gpu// Tahiti}
        gpu=${gpu// PRO}
        gpu=${gpu// OEM}
        gpu=${gpu// Mars}
        gpu=${gpu// Series}
        gpu=${gpu// Controller}
        gpu=${gpu/\/*}
    fi

    gpu="${gpu}${count}"
}

# }}}

# Memory {{{

getmemory () {
    case "$os" in
        "Linux")
            # Read first 3 lines
            exec 6< /proc/meminfo
            read -r memtotal <&6
            read -r memfree <&6 # We don't actually use this var
            read -r memavail <&6
            exec 6<&-

            # Do some substitution on each line
            memtotal=${memtotal/MemTotal:}
            memtotal=${memtotal/kB*}
            memavail=${memavail/MemAvailable:}
            memavail=${memavail/kB*}

            memused=$((memtotal - memavail))
            memory="$((memused / 1024))MB / $((memtotal / 1024))MB"
        ;;

        "Mac OS X")
            memtotal=$(printf "%s\n" "$(sysctl -n hw.memsize)"/1024^2 | bc)
            memwired=$(vm_stat | awk '/wired/ { print $4 }')
            memactive=$(vm_stat | awk '/active / { printf $3 }')
            memcompressed=$(vm_stat | awk '/occupied/ { printf $5 }')
            memused=$(((${memwired//.} + ${memactive//.} + ${memcompressed//.}) * 4 / 1024))
            memory="${memused}MB / ${memtotal}MB"
        ;;

        "OpenBSD" | "BSD")
            case "$distro" in
                "OpenBSD"* | "FreeBSD"*)
                    memtotal=$(dmesg | awk '/real mem/ {printf $5}')
                    memtotal=${memtotal/\(}
                    memtotal=${memtotal/MB\)}

                    case "$distro" in
                        "OpenBSD"*) memfree=$(top -d 1 | awk '/Real:/ {printf $6}') ;;
                        "FreeBSD"*) memfree=$(top -d 1 | awk '/Mem:/ {printf $10}') ;;
                    esac
                    memfree=${memfree/M}

                    memused=$((memtotal - memfree))
                    memory="${memused}MB / ${memtotal}MB"
                ;;

                "NetBSD"*)
                    memfree=$(($(vmstat | awk 'END{printf $4}') / 1000))
                    memused=$(($(vmstat | awk 'END{printf $3}') / 1000))
                    memtotal=$((memused + memfree))

                    memused=$((memtotal - memfree))
                    memory="${memused}MB / ${memtotal}MB"
                ;;
            esac

        ;;

        "Windows")
            mem="$(awk 'NR < 3 {printf $2 " "}' /proc/meminfo)"

            # Split the string above into 2 vars
            # This is faster than using an array.
            set $mem

            memtotal=$1
            memfree=$2
            memavail=$((memtotal - memfree))
            memused=$((memtotal - memavail))
            memory="$((${memused%% *} / 1024))MB / "
            memory+="$((${memtotal%% *} / 1024))MB"
        ;;

        *)
            memory="Unknown"
        ;;
    esac
}

# }}}

# Song {{{

getsong () {
    if type -p mpc >/dev/null 2>&1; then
        song="$(mpc current)"

    elif type -p cmus >/dev/null 2>&1; then
        song="$(cmus-remote -Q | grep "tag artist\|title")"
        song=${song/tag artist }
        song=${song/tag title/-}
        song=${song//[[:space:]]/ }

    else
        song="Unknown"
    fi
}

# }}}

# Resolution {{{

getresolution () {
    case "$os" in
        "Linux" | *"BSD")
            if type -p xdpyinfo >/dev/null 2>&1; then
                resolution=$(xdpyinfo 2>/dev/null | awk '/dimensions:/ {printf $2}')
            else
                resolution="Unknown"
            fi
        ;;

        "Mac OS X")
            resolution=$(system_profiler SPDisplaysDataType |\
                        awk '/Resolution:/ {printf $2"x"$4" "}')
        ;;

        "*")
            resolution="Unknown"
        ;;
    esac
}

# }}}

# GTK Theme/Icons/Font {{{

getgtk () {
    # Fix weird output when the function
    # is run multiple times.
    unset gtk2theme gtk3theme

    case "$1" in
        theme)
            name="gtk-theme-name"
            gsettings="gtk-theme"
            gconf="gtk_theme"
            xfconf="ThemeName"
        ;;

        icons)
            name="gtk-icon-theme-name"
            gsettings="icon-theme"
            gconf="icon_theme"
            xfconf="IconThemeName"
        ;;

        font)
            name="gtk-font-name"
            gsettings="font-name"
            gconf="font_theme"
            xfconf="FontName"
        ;;
    esac

    # Current DE
    desktop="$XDG_CURRENT_DESKTOP"
    desktop=${desktop,,}
    desktop=${desktop^}

    case "$desktop" in
        "Cinnamon")
            if type -p gsettings >/dev/null 2>&1; then
                gtk3theme=$(gsettings get org.cinnamon.desktop.interface $gsettings)
                gtk3theme=${gtk3theme//"'"}
                gtk2theme=${gtk3theme}
            fi
        ;;

        "Gnome"* | "Unity"* | "Budgie")
            if type -p gsettings >/dev/null 2>&1; then
                gtk3theme=$(gsettings get org.gnome.desktop.interface $gsettings)
                gtk3theme=${gtk3theme//"'"}
                gtk2theme=${gtk3theme}

            elif type -p gconftool-2 >/dev/null 2>&1; then
                gtk2theme=$(gconftool-2 -g /desktop/gnome/interface/$gconf)
            fi
        ;;

        "Mate"*)
            gtk3theme=$(gsettings get org.mate.interface $gsettings)
            gtk2theme=${gtk3theme}
        ;;

        "Xfce"*)
            if type -p xfconf-query >/dev/null 2>&1; then
                gtk2theme=$(xfconf-query -c xsettings -p /Net/$xfconf)
            fi
        ;;
    esac

    # Check for gtk2 theme
    if [ -z "$gtk2theme" ]; then
        if [ -f "$HOME/.gtkrc-2.0" ]; then
            gtk2theme=$(grep "^[^#]*$name" "$HOME/.gtkrc-2.0")

        elif [ -f "/etc/gtk-2.0/gtkrc" ]; then
            gtk2theme=$(grep "^[^#]*$name" /etc/gtk-2.0/gtkrc)
        fi

        gtk2theme=${gtk2theme/${name}*=}
        gtk2theme=${gtk2theme//\"}
    fi

    # Check for gtk3 theme
    if [ -z "$gtk3theme" ]; then
        if [ -f "$HOME/.config/gtk-3.0/settings.ini" ]; then
            gtk3theme=$(grep "^[^#]*$name" "$HOME/.config/gtk-3.0/settings.ini")

        elif type -p gsettings >/dev/null 2>&1; then
            gtk3theme="$(gsettings get org.gnome.desktop.interface $gsettings)"
            gtk3theme=${gtk3theme//\'}

        else
            gtk3theme=$(grep "^[^#]*$name" /etc/gtk-3.0/settings.ini)
        fi

        gtk3theme=${gtk3theme/${name}*=}
        gtk3theme=${gtk3theme//\"}
        gtk3theme=${gtk3theme/[[:space:]]/ }
    fi

    # Toggle visibility of gtk themes.
    [ "$gtk2" == "off" ] && unset gtk2theme
    [ "$gtk3" == "off" ] && unset gtk3theme

    # Format the string based on which themes exist
    if  [ "$gtk2theme" ] && [ "$gtk2theme" == "$gtk3theme" ]; then
        gtk3theme+=" [GTK2/3]"
        unset gtk2theme

    elif [ "$gtk2theme" ] && [ "$gtk3theme" ]; then
        gtk2theme+=" [GTK2], "
        gtk3theme+=" [GTK3] "
    else
        [ "$gtk2theme" ] && gtk2theme+=" [GTK2] "
        [ "$gtk3theme" ] && gtk3theme+=" [GTK3] "
    fi

    # Final string
    gtktheme="${gtk2theme}${gtk3theme}"

    # If the final string is empty print "None"
    [ -z "$gtktheme" ] && gtktheme="None"

    # Make the output shorter by removing "[GTKX]" from the string
    if [ "$gtk_shorthand" == "on" ]; then
        gtktheme=${gtktheme/ '[GTK2]'}
        gtktheme=${gtktheme/ '[GTK3]'}
        gtktheme=${gtktheme/ '[GTK2/3]'}
    fi
}

getgtktheme () {
    getgtk theme
}

getgtkicons () {
    getgtk icons
    gtkicons="$gtktheme"
}

getgtkfont () {
    getgtk font
    gtkfont="$gtktheme"
}

# }}}

# Disk Usage {{{

getdisk () {
    # df flags
    case "$os" in
        "Linux" | "Windows") df_flags="-h --total" ;;
        "Mac OS X") df_flags="-H /" ;;

        *"BSD")
            case "$os" in
                "FreeBSD") df_flags="-h -c" ;;
                *) disk="Unknown"; return ;;
            esac
        ;;
    esac

    # Get the disk info
    disk=$(df $df_flags 2>/dev/null | awk 'END{print $2 ":" $3 ":" $5}')

    # Format the output
    disk_used=${disk#*:}
    disk_used=${disk_used%%:*}
    disk_total=${disk%%:*}
    disk_total_per=${disk#*:*:}

    # Put it all together
    disk="${disk_used} / ${disk_total} (${disk_total_per})"
}

# }}}

# Battery Usage {{{

getbattery () {
    case "$os" in
        "Linux")
            if [ -d "/sys/class/power_supply/BAT0" ]; then
                # Set the index to the battery number.
                case "$battery_num" in
                    "all") battery_num="*" index=0 ;;
                    *) index="$battery_num" ;;
                esac

                # Create an array of battery usage from each battery.
                batteries=($(cat /sys/class/power_supply/BAT${battery_num}/capacity))

                # Get the subtitle and reassign it so it doesn't change.
                title="$subtitle"

                # If shorthand is on, print each value on the same line
                if [ "$battery_shorthand" == "on" ]; then
                    battery=${batteries[*]}
                    battery=${battery// /%, }
                    battery="${battery}%"

                else
                    # If there's only a single battery and it's battery 0,
                    # don't number the subtitle.
                    if [ "${#batteries[@]}" == 1 ]; then
                        battery="${batteries[0]}%"
                        return
                    fi

                    # Print each battery on a separate line.
                    for bat in "${batteries[@]}"; do
                        prin "${title}${index}: ${bat}%"
                        index=$((index + 1))
                    done
                fi
            else
                battery="None"
            fi
        ;;

        "Mac OS X")
            battery="$(pmset -g batt | grep -o '[0-9]*%')"
        ;;

        "Windows")
            battery="$(wmic Path Win32_Battery get EstimatedChargeRemaining /value)"
            battery=${battery/EstimatedChargeRemaining'='}
            battery=${battery//[[:space:]]/ }
            battery=${battery// }
            battery+="%"
        ;;
    esac
}

# }}}

# IP Address {{{

getlocalip () {
    case "$os" in
        "Linux")
            localip="$(ip route get 1 | awk '{print $NF;exit}')"
        ;;

        "Mac OS X")
            localip="$(ipconfig getifaddr en0)"
            [ -z "$localip" ] && localip="$(ipconfig getifaddr en1)"
        ;;

        *"BSD")
            localip="$(ifconfig | awk '/broadcast/ {print $2}')"
        ;;

        "Windows")
            localip="$(ipconfig | awk -F ': ' '/IPv4 Address/ {printf $2}')"
        ;;

        *)
            localip="Unknown"
        ;;
    esac
}

getpublicip () {
    if type -p curl >/dev/null 2>&1; then
        publicip="$(curl -w '\n' "$public_ip_host")"

    elif type -p wget >/dev/null 2>&1; then
        publicip="$(wget -qO- "$public_ip_host"; printf "%s")"

    else
        publicip="Unknown"
    fi
}

# }}}

# Birthday {{{

getbirthday () {
    case "$os" in
        "Linux")
            birthday="$(ls -alct --full-time / | awk '/lost\+found/ {printf  $6 " " $7}')"
            date_cmd="$(date -d"$birthday" "+%a %d %b %Y %l:%M %p")"
        ;;

        "Mac OS X")
            birthday="$(ls -alctT /var/log/CDIS.custom | awk '{printf $6 " " $7 " " $9 " " $8}')"
            date_cmd="$(date -j -f "%b %d %Y" "$birthday" "+%a %d %b %Y %l:%M %p")"
        ;;

        *"BSD")
            case "$distro" in
                "OpenBSD"*)
                    birthday="$(ls -alctT / | awk '/lost\+found/ {printf $6 " " $7 " " $9 " " $8}')"
                    birthday_shorthand="on"
                ;;

                "FreeBSD"*)
                    birthday="$(ls -alctT /etc/hostid | awk '{printf $6 " " $7 " " $9 " " $8}')"
                    date_cmd="$(date -j -f "%b %d %Y" "$birthday" "+%a %d %b %Y %l:%M %p")"
                ;;

                "NetBSD"*)
                    birthday="$(ls -alctT /etc/defaults/rc.conf | awk '{printf $6 " " $7 " " $9 " " $8}')"
                    birthday_shorthand="on"
                ;;

                *)
                    birthday="Unknown"
                ;;
            esac
        ;;

        "Windows")
            birthday="$(ls -alct --full-time /cygdrive/c/Windows/explorer.exe | awk '{printf $8 " " $9}')"
            date_cmd="$(date -d"$birthday" "+%a %d %b %Y %l:%M %p")"
        ;;

        *)
            birthday="Unknown"
        ;;

    esac

    # Strip seconds from time output
    birthday=${birthday%:*}

    # Pretty output
    if [ "$birthday_shorthand" == "off" ]; then
        birthday="$date_cmd"
        birthday=${birthday/  / }
    fi

    # Toggle showing the time
    [ "$birthday_time" == "off" ] && \
        birthday=${birthday/??:??*}
}

# }}}

# Terminal colors {{{

getcols () {
    if [ "$color_blocks" == "on" ]; then
        printf "${padding}%s"
        while [ $start -le $end ]; do
            printf "\033[48;5;${start}m%${block_width}s"
            start=$((start + 1))

            # Split the blocks at 8 colors
            [ $end -ge 9 ] && [ $start -eq 8 ] && \
                printf "\n%s${clear}${padding}"
        done

        # Clear formatting
        printf "%b%s" "$clear"
    fi
}

# }}}

# Windows Visual Style {{{

getvisualstyle () {
    case "$os" in
        "Windows"*)
            path="/proc/registry/HKEY_CURRENT_USER/Software/Microsoft"
            path+="/Windows/CurrentVersion/Themes/CurrentTheme"
            visualstyle="$(head -n1 $path)"
            visualstyle="${visualstyle##*\\}"
            visualstyle="${visualstyle%.*}"
            visualstyle="${visualstyle^}"
        ;;

        *)
            visualstyle="This feature only works on Windows"
        ;;
    esac
}

# }}}


# }}}


# Images {{{


# Wallpaper {{{

getwallpaper () {
    case "$os" in
        "Linux" | *"BSD")
            if type -p feh >/dev/null 2>&1 && [ -f "$HOME/.fehbg" ]; then
                img="$(awk -F\' '/feh/ {printf $2}' "$HOME/.fehbg")"

            elif type -p nitrogen >/dev/null 2>&1; then
                img="$(awk -F'=' '/file/ {printf $2}' "$HOME/.config/nitrogen/bg-saved.cfg")"

            elif type -p gsettings >/dev/null 2>&1; then
                case "$XDG_CURRENT_DESKTOP" in
                    "MATE"*) img="$(gsettings get org.mate.background picture-filename 2>/dev/null)" ;;
                    *) img="$(gsettings get org.gnome.desktop.background picture-uri 2>/dev/null)" ;;
                esac

                # Strip quotes etc from the path.
                img=${img/'file://'}
                img=${img//\'}
            fi
        ;;

        "Mac OS X")
            img="$(osascript -e 'tell app "finder" to get posix path of (get desktop picture as text)')"
        ;;

        "Windows")
            case "$distro" in
                "Windows XP")
                    img="/cygdrive/c/Documents and Settings/${USER}"
                    img+="/Local Settings/Application Data/Microsoft"
                    img+="/Wallpaper1.bmp"
                ;;

                "Windows"*)
                    img="$APPDATA/Microsoft/Windows/Themes"
                    img+="/TranscodedWallpaper.jpg"
                ;;
            esac
        ;;
    esac

    # If img is an xml file don't use it.
    [ "${img/*\./}" == "xml" ] && img=""
}

# }}}

# Ascii {{{

getascii () {
    # Change color of logo based on distro
    shopt -s nocasematch
    case "$ascii_distro" in
        "Arch Linux"* | "Antergos"*)
            c1=$(color 6)
            c2=$(color 4)
        ;;

        "CentOS"*)
            c1=$(color 3)
            c2=$(color 2)
            c3=$(color 4)
            c4=$(color 5)
            c5=$(color 7)
        ;;

        "CRUX")
            c1=$(color 4)
            c2=$(color 5)
            c3=$(color 7)
        ;;

        "Debian"* | "FreeBSD"* | "Red Hat"* | "elementary"* | "CrunchBang"* | "Ubuntu"*)
            c1=$(color 7)
            c2=$(color 1)
            c3=$(color 3)
        ;;

        "Fedora"*)
            c1=$(color 7)
            c2=$(color 4)
        ;;

        "Gentoo"* | "Funtoo"*)
            c1=$(color 7)
            c2=$(color 5)
        ;;

        "Kali"*)
            c1=$(color 4)
            c2=$(color 8)
        ;;

        "Mac OS X"* | "Manjaro"* | "Deepin"*)
            c1=$(color 2)
            c2=$(color 3)
            c3=$(color 1)
            c4=$(color 1)
            c5=$(color 5)
            c6=$(color 4)
        ;;

        *"Mint"*)
            c1=$(color 7)
            c2=$(color 2)
            ascii_distro="mint"
        ;;

        "NetBSD"* | "Parabola"*)
            c1=$(color 5)
            c2=$(color 7)
        ;;

        "OpenBSD"*)
            c1=$(color 3)
            c2=$(color 3)
            c3=$(color 6)
            c4=$(color 1)
            c5=$(color 8)
        ;;

        "OpenSuse"*)
            c1=$(color 2)
            c2=$(color 7)
        ;;

        "Raspbian"*)
            c1=$(color 2)
            c2=$(color 1)
        ;;

        "Slackware"*)
            c1=$(color 4)
            c2=$(color 7)
        ;;

        "void"*)
            c1=$(color 2)
            c2=$(color 2)
            c3=$(color 8)
        ;;

        "Windows 10"*)
            c1=$(color 6)
            ascii_distro="windows10"
        ;;

        "Windows"*)
            c1=$(color 1)
            c2=$(color 2)
            c3=$(color 4)
            c4=$(color 3)
        ;;
    esac

    # If the ascii file doesn't exist
    # fallback to showing distro ascii.
    [ ! -f "$ascii" ] && ascii="distro"

    if [ "$ascii" == "distro" ]; then
        # Lowercase the distro name
        ascii=${ascii_distro,,}

        # Check /usr/share/fetch for ascii before
        # looking in the script's directory.
        if [ -f "/usr/share/fetch/ascii/distro/${ascii/ *}" ]; then
            ascii="/usr/share/fetch/ascii/distro/${ascii/ *}"
        else
            getscriptdir

            # If the ascii file doesn't exist
            # fallback to text mode.
            if [ ! -f "$script_dir/ascii/distro/${ascii/ *}" ]; then
                padding="\033[0C"
                image="off"
                return
            fi

            ascii="$script_dir/ascii/distro/${ascii/ *}"
        fi

        # Overwrite distro colors if '$ascii_colors' doesn't
        # equal 'distro'.
        if [ "$ascii_colors" != "distro" ]; then
            c1=$(color ${ascii_colors[0]})
            c2=$(color ${ascii_colors[1]})
            c3=$(color ${ascii_colors[2]})
            c4=$(color ${ascii_colors[3]})
            c5=$(color ${ascii_colors[4]})
            c6=$(color ${ascii_colors[5]})
        fi

        # We only use eval in the distro ascii files.
        print="$(eval printf "$(<"$ascii")")"
    else
        case "${ascii_colors[0]}" in
            "distro") ascii_color="$c1" ;;
            *) ascii_color="$(color ${ascii_colors[0]})" ;;
        esac

        print="${ascii_color}$(<"$ascii")"
    fi

    # Set locale to get correct padding
    export LC_ALL="$SYS_LOCALE"

    # Turn the file into a variable.
    ascii_strip=$(<"$ascii")

    # Strip escape codes backslashes from contents of
    ascii_strip=${ascii_strip//\$\{??\}}
    ascii_strip=${ascii_strip//\\}

    # Get length of longest line
    length="$(wc -L 2>/dev/null <<< "$ascii_strip")"

    # Get the height in lines
    lines="$(($(wc -l 2>/dev/null <<< "$ascii_strip") + 1))"

    # Fallback to using awk on systems without 'wc -L'
    [ -z "$length" ] && \
        length="$(awk 'length>max{max=length}END{print max}' <<< "$ascii_strip")"

    # Set the text padding
    padding="\033[$((length + gap))C"

    # Print the ascii
    printf "%b%s" "$print"

    # Set locale to get correct padding
    export LC_ALL=C
}


# }}}

# Image {{{

getimage () {
    # Fallback to ascii mode if imagemagick isn't installed.
    if ! type -p convert >/dev/null 2>&1; then
        image="ascii"
    fi

    # Call function based on $image
    case "$image" in
        "wall")
            getwallpaper
        ;;

        "shuffle")
            img="$(find "$shuffle_dir" -type f \( -name '*.jpg' -o -name '*.png' \) -print0 |
            shuf -n1 -z)"
        ;;

        "ascii")
            getascii
            return
        ;;

        *)
            img="$image"
        ;;
    esac

    # If $img isn't a file, fallback to ascii mode.
    if [ ! -f "$img" ]; then
        # Fallback to ascii mode
        image="ascii"
        getascii

        return
    fi

    # Get lines and columns
    columns=$(tput cols)
    lines=$(tput lines)

    # Image size is half of the terminal
    [ "$image_size" == "half" ] && \
        image_size=$((columns * font_width / 2))

    # Where to draw the image
    case "$image_position" in
        "left")
            # Padding is half the terminal width + gap
            padding="\033[$((image_size / font_width + gap))C"
        ;;

        "right")
            padding="\033[0C"
            xoffset=$((columns * font_width / 2 - gap))
        ;;
    esac

    # Make the directory if it doesn't exist
    mkdir -p "$thumbnail_dir"

    # Check to see if the image has a file extension
    case "${img##*/}" in
        *"."*)
            # Get name of image and prefix it with it's crop mode and offset
            imgname="$crop_mode-$crop_offset-$image_size-${img##*/}"
        ;;

        *)
            # Add a file extension if the image doesn't have one. This
            # fixes w3m not being able to display them.
            imgname="$crop_mode-$crop_offset-$image_size-${img##*/}.jpg"
        ;;
    esac

    # Check to see if the thumbnail exists before we do any cropping.
    if [ ! -f "$thumbnail_dir/$imgname" ]; then
        # Get image size so that we can do a better crop
        size=$(identify -format "%w %h" "$img")
        width=${size%% *}
        height=${size##* }

        # This checks to see if height is geater than width
        # so we can do a better crop of portrait images.
        if [ "$height" -gt "$width" ]; then
            size=$width
        else
            size=$height
        fi

        case "$crop_mode" in
            fit)
                c=$(convert "$img" \
                    -colorspace srgb \
                    -format "%[pixel:p{0,0}]" info:)

                convert \
                    "$img" \
                    -trim +repage \
                    -gravity south \
                    -background "$c" \
                    -extent "$size"x"$size" \
                    -scale "$image_size"x"$image_size" \
                    "$thumbnail_dir/$imgname"
            ;;

            fill)
                convert \
                    "$img" \
                    -trim +repage \
                    -scale "$image_size"x"$image_size"^ \
                    -extent "$image_size"x"$image_size" \
                    "$thumbnail_dir/$imgname"
            ;;

            *)
                convert \
                    "$img" \
                    -gravity $crop_offset \
                    -crop "$size"x"$size"+0+0 \
                    -quality 95 \
                    -scale "$image_size"x"$image_size" \
                    "$thumbnail_dir/$imgname"
            ;;
        esac
    fi

    # The final image
    img="$thumbnail_dir/$imgname"
}

scrot_path="$scrot_dir/$scrot_name"
takescrot () {
    $scrot_cmd "$scrot_path"
}

# }}}

# Find w3m-img {{{

# Find w3mimgdisplay automatically
getw3m_img_path () {
    if [ -x "$w3m_img_path" ]; then
        return

    elif [ -x "/usr/lib/w3m/w3mimgdisplay" ]; then
        w3m_img_path="/usr/lib/w3m/w3mimgdisplay"

    elif [ -x "/usr/libexec/w3m/w3mimgdisplay" ]; then
        w3m_img_path="/usr/libexec/w3m/w3mimgdisplay"

    elif [ -x "/usr/lib64/w3m/w3mimgdisplay" ]; then
        w3m_img_path="/usr/lib64/w3m/w3mimgdisplay"

    elif [ -x  "/usr/libexec64/w3m/w3mimgdisplay" ]; then
        w3m_img_path="/usr/libexec64/w3m/w3mimgdisplay"

    else
        image="ascii"
    fi
}

# }}}


# }}}


# Text Formatting {{{


# Info {{{

info () {
    # $1 is the subtitle
    subtitle="$1"

    # Call the function and update variable
    if [ -z "$2" ]; then
        "get$1" 2>/dev/null
        eval output="\$${1}"

    else
        "get$2" 2>/dev/null
        eval output="\$${2}"
    fi

    # If the output is empty, don't print anything
    [ -z "$output" ] && return

    case "$1" in
        title)
            string="${bold}${title_color}${output}"
            string="${string/@/${at_color}@${title_color}}"
            length=${#output}

            # Hide the title in stdout mode
            [ "$stdout" == "on" ] && \
            [ "$stdout_title" == "off" ] &&\
                string=""
        ;;

        underline)
            string="${underline_color}${output}"
        ;;

        *)
            string="${bold}${subtitle_color}${subtitle}${clear}"
            string+="${colon_color}: ${info_color}${output}"
            length=$((${#subtitle} +  ${#output} + 2))
        ;;
    esac

    # If there's no subtitle don't print one
    [ -z "$2" ] && string=${string/*: }

    # Print the string
    if [ "$stdout" == "on" ]; then

        # Unset the vars containg escape codes as lemonbar doesn't
        # support them.
        unset -v bold subtitle_color clear colon_color info_color \
        underline_color title_color at_color

        # Show/Hide subtitles
        [ "$stdout_subtitles" == "off" ] && string=${string/*: }

        # If the string isn't empty, print it.
        [ ! -z "$string" ] && printf "%s" "${string}${stdout_separator}"

    else
        printf "%b%s\n" "${padding}${string}${clear}"
    fi
}

# }}}

# Prin {{{

prin () {
    case "$1" in
        *:*)
            subtitle=${1%%:*}
            output=${1#*: }

            string="${bold}${subtitle_color}${subtitle}${clear}"
            string+="${colon_color}: ${info_color}${output}"
            length=$((${#subtitle} +  ${#output} + 1))
        ;;

        *)
            string="${info_color}${1}"
            length=${#1}
        ;;
    esac

    # Print the info
    if [ "$stdout" == "on" ]; then
        printf "%s" "${string}${stdout_separator}"
    else
        printf "%b%s\n" "${padding}${string}${clear}"
    fi
}

# }}}

# Stdout {{{

stdout () {
    printinfo () {
        index=1
        for func in "${args[@]}"; do

            case "$func" in
                "--stdout") continue ;;
                "--"*) break ;;
                *)
                    case "${args[$((index + 1))]}" in "--"*) unset stdout_separator ;; esac
                    info "$func"
                ;;
            esac
            index=$((index + 1))
        done
    }
}

# }}}

# Underline {{{

getunderline () {
    case "$underline" in
        "on")
            underline=$(printf %"$length"s)
            underline=${underline// /$underline_char}
         ;;
        "off") underline="" ;;
    esac
}

# }}}

# Colors {{{

colors () {
    title_color="\033[38;5;${title_color}m"
    at_color="\033[38;5;${at_color}m"
    subtitle_color="\033[38;5;${subtitle_color}m"
    colon_color="\033[38;5;${colon_color}m"
    underline_color="\033[38;5;${underline_color}m"
    info_color="\033[38;5;${info_color}m"
}

color () {
   printf "%b%s" "\033[38;5;${1}m"
}

# }}}

# Bold {{{

bold () {
    case "$bold" in
        "on") bold="\033[1m" ;;
        "off") bold="" ;;
    esac
}

# }}}

# Linebreak {{{

getlinebreak () {
   linebreak=" "
}

# }}}

clear="\033[0m"


# }}}


# Other {{{


# Get script directory {{{

getscriptdir () {
    # Use $0 to get the script's physical path.
    cd "${0%/*}" || exit
    script_dir=${0##*/}

    # Iterate down a (possible) chain of symlinks.
    while [ -L "$script_dir" ]; do
        script_dir="$(readlink "$script_dir")"
        cd "${script_dir%/*}" || exit
        script_dir="${script_dir##*/}"
    done

    # Final directory
    script_dir="$(pwd -P)"
}

# }}}

# Source Config {{{

# Check for $config_file first
getconfig () {
    # Check $config_file
    if [ -f "$config_file" ]; then
        source "$config_file"
        return
    fi

    # Make the directory if it doesn't exist
    mkdir -p "$HOME/.config/fetch/"

    # Check $HOME/.config/fetch and create the
    # dir/files if they don't exist.
    if [ -f "$HOME/.config/fetch/config" ]; then
        source "$HOME/.config/fetch/config"

    elif [ -f "/usr/share/fetch/config" ]; then
        cp "/usr/share/fetch/config" "$HOME/.config/fetch"
        source "$HOME/.config/fetch/config"

    elif [ -f "/usr/local/share/fetch/config" ]; then
        cp "/usr/local/share/fetch/config" "$HOME/.config/fetch"
        source "$HOME/.config/fetch/config"

    else
        getscriptdir

        cp "$script_dir/config/config" "$HOME/.config/fetch"
        source "$HOME/.config/fetch/config"
    fi
}

# Check the commandline flags early for '--config none/off'
case "$@" in
    *"--config off"* | *'--config "off"'* | *"--config 'off'"* | \
    *"--config none"* | *'--config "none"'* | *"--config 'none'"*)
        config="off"
    ;;
esac

# If config files are enabled
[ "$config" == "on" ] && getconfig

# }}}


# }}}


# Usage {{{


usage () { cat << EOF

    usage: fetch --option "value" --option "value"

    Info:
    --disable infoname          Allows you to disable an info line from appearing
                                in the output.
                                NOTE: You can supply multiple args. eg.
                                'fetch --disable cpu gpu disk shell'
    --osx_buildversion on/off   Hide/Show Mac OS X build version.
    --os_arch on/off            Hide/Show Windows architecture.
    --speed_type type           Change the type of cpu speed to display.
                                Possible values: current, min, max, bios,
                                scaling_current, scaling_min, scaling_max
                                NOTE: This only support Linux with cpufreq.
    --kernel_shorthand on/off   Shorten the output of kernel
    --uptime_shorthand on/off   Shorten the output of uptime (tiny, on, off)
    --gpu_shorthand on/off      Shorten the output of GPU
    --gtk_shorthand on/off      Shorten output of gtk theme/icons
    --gtk2 on/off               Enable/Disable gtk2 theme/icons output
    --gtk3 on/off               Enable/Disable gtk3 theme/icons output
    --shell_path on/off         Enable/Disable showing \$SHELL path
    --shell_version on/off      Enable/Disable showing \$SHELL version
    --battery_num num           Which battery to display, default value is 'all'
    --battery_shorthand on/off  Whether or not each battery gets its own line/title
    --ip_host url               Url to ping for public IP
    --birthday_shorthand on/off Shorten the output of birthday
    --birthday_time on/off      Enable/Disable showing the time in birthday output

    Text Colors:
    --title_color num           Change the color of the title
    --at_color num              Change the color of "@" in title
    --subtitle_color num        Change the color of the subtitle
    --colon_color num           Change the color of the colons
    --underline_color num       Change the color of the underlines
    --info_color num            Change the color of the info

    Text Formatting:
    --underline_char char       Character to use when underlineing title
    --line_wrap on/off          Enable/Disable line wrapping
    --bold on/off               Enable/Disable bold text
    --prompt_height num         Set this to your prompt height to fix issues with
                                the text going off screen at the top


    Color Blocks:
    --color_blocks on/off       Enable/Disable the color blocks
    --block_width num           Width of color blocks
    --block_range start end     Range of colors to print as blocks


    Image:
    --image type                Image source. Where and what image we display.
                                Possible values: wall, shuffle, ascii,
                                /path/to/img, off
    --size px                   Size in pixels to make the image.
    --image_backend w3m/iterm2  Which program to use to draw images.
    --shuffle_dir path/to/dir   Which directory to shuffle for an image.
    --font_width px             Used to automatically size the image
    --image_position left/right Where to display the image: (Left/Right)
    --crop_mode mode            Which crop mode to use
                                Takes the values: normal, fit, fill
    --crop_offset value         Change the crop offset for normal mode.
                                Possible values: northwest, north, northeast,
                                west, center, east, southwest, south, southeast

    --xoffset px                How close the image will be to the left edge of the
                                window. This only works with w3m.
    --yoffset px                How close the image will be to the top edge of the
                                window. This only works with w3m.
    --gap num                   Gap between image and text.
                                NOTE: --gap can take a negative value which will
                                move the text closer to the left side.
    --clean                     Remove all cropped images


    Ascii:
    --ascii value               Where to get the ascii from, Possible values:
                                distro, /path/to/ascii
    --ascii_color num           Color to print the ascii art
    --ascii_distro distro       Which Distro\'s ascii art to print


    Stdout:
    --stdout info info          Launch fetch in stdout mode which prints the info
                                in a plain-text format that you can use with
                                lemonbar etc.
    --stdout_title on/off       Hide/Show the title in stdout mode.
    --stdout_separator string   String to use as a separator in stdout mode.
    --stdout_subtitles on/off   Hide/Show the subtitles in stdout mode.


    Screenshot:
    --scrot /path/to/img        Take a screenshot, if path is left empty the screen-
                                shot function will use \$scrot_dir and \$scrot_name.
    --scrot_cmd cmd             Screenshot program to launch


    Other:
    --config /path/to/config    Specify a path to a custom config file
    --config none               Launch the script without a config file
    --help                      Print this text and exit

EOF
exit 1
}


# }}}


# Args {{{


while [ "$1" ]; do
    case $1 in
        # Info
        --os_arch) os_arch="$2" ;;
        --osx_buildversion) osx_buildversion="$2" ;;
        --speed_type) speed_type="$2" ;;
        --kernel_shorthand) kernel_shorthand="$2" ;;
        --uptime_shorthand) uptime_shorthand="$2" ;;
        --gpu_shorthand) gpu_shorthand="$2" ;;
        --gtk_shorthand) gtk_shorthand="$2" ;;
        --gtk2) gtk2="$2" ;;
        --gtk3) gtk3="$2" ;;
        --shell_path) shell_path="$2" ;;
        --shell_version) shell_version="$2" ;;
        --battery_num) battery_num="$2" ;;
        --battery_shorthand) battery_shorthand="$2" ;;
        --ip_host) public_ip_host="$2" ;;
        --birthday_shorthand) birthday_shorthand="$2" ;;
        --birthday_time) birthday_time="$2" ;;
        --disable)
            for func in "$@"; do
                case "$func" in
                    "--disable") continue ;;
                    "--"*) return ;;
                    *) unset -f "get$func" ;;
                esac
            done
        ;;

        # Text Colors
        --title_color) title_color=$2 ;;
        --at_color) at_color=$2 ;;
        --subtitle_color) subtitle_color=$2 ;;
        --colon_color) colon_color=$2 ;;
        --underline_color) underline_color=$2 ;;
        --info_color) info_color=$2 ;;

        # Text Formatting
        --underline) underline="$2" ;;
        --underline_char) underline_char="$2" ;;
        --line_wrap) line_wrap="$2" ;;
        --bold) bold="$2" ;;
        --prompt_height) prompt_height="$2" ;;

        # Color Blocks
        --color_blocks) color_blocks="$2" ;;
        --block_range) start=$2; end=$3 ;;
        --block_width) block_width="$2" ;;

        # Image
        --image)
            image="$2"
            case "$2" in "--"* | "") image="ascii" ;; esac
        ;;

        --size) image_size="$2" ;;
        --image_backend) image_backend="$2" ;;
        --shuffle_dir) shuffle_dir="$2" ;;
        --font_width) font_width="$2" ;;
        --image_position) image_position="$2" ;;
        --crop_mode) crop_mode="$2" ;;
        --crop_offset) crop_offset="$2" ;;
        --xoffset) xoffset="$2" ;;
        --yoffset) yoffset="$2" ;;
        --gap) gap="$2" ;;
        --clean) rm -rf "$thumbnail_dir" || exit ;;

        # Ascii
        --ascii)
            image="ascii"
            ascii="$2"
            case "$2" in "--"* | "") ascii="distro" ;; esac
        ;;

        --ascii_colors)
            unset ascii_colors
            for arg in "$2" "$3" "$4" "$5" "$6" "$7"; do
                case "$arg" in
                    "$1") continue ;;
                    "--"*) break ;;
                    *) ascii_colors+=($arg)
                esac
            done
            ascii_colors+=(7 7 7 7 7 7)
        ;;
        --ascii_distro) ascii_distro="$2" ;;

        # Screenshot
        --scrot | -s) scrot="on"; [ "$2" ] && scrot_path="$2" ;;
        --scrot_cmd) scrot_cmd="$2" ;;

        # Stdout
        --stdout_title) stdout_title="$2" ;;
        --stdout_separator) stdout_separator="$2" ;;
        --stdout_subtitles) stdout_subtitles="$2" ;;
        --stdout)
            case "$2" in
                "--"* | "") stdout="on" ;;
                *) stdout="on"; stdout_args="on"; args=("$@"); stdout ;;
            esac

            unset info_color colors
            underline="off"
            image="off"
            color_blocks="off"
        ;;

        # Other
        --config)
            case "$2" in
                "none" | "off") config="off" ;;
                *) config_file="$2"; config="on"; getconfig ;;
            esac
        ;;

        --help) usage ;;
    esac

    shift
done


# }}}


# Call Functions and Finish Up {{{


# Restore cursor and clear screen on ctrl+c
trap 'printf "\033[?25h"; clear; exit' 2

if [ "$image" != "off" ]; then
    # If the script exits for any reason, unhide the cursor.
    trap 'printf "\033[?25h"' EXIT

    # Clear the scren
    clear

    # Hide the cursor
    printf "\033[?25l"

    # Find w3mimgdisplay
    [ "$image_backend" == "w3m" ] && \
    [ "$image" != "ascii" ] && \
        getw3m_img_path

    # Get the image
    getimage
fi

# Display the image if enabled
if [ "$image" != "off" ] && [ "$image" != "ascii" ]; then
    case "$image_backend" in
        "w3m")
            printf "%b%s\n" "0;1;$xoffset;$yoffset;$image_size;$image_size;;;;;$img\n4;\n3;" |\
            $w3m_img_path 2>/dev/null || padding="\033[0C"
        ;;

        "iterm2")
            printf "%b%s\a\n" "\033]1337;File=width=${image_size}px;height=${image_size}px;inline=1:$(base64 < "$img")"
        ;;
    esac
fi

# Disable line wrap
[ "$line_wrap" == "off" ] && printf "\033[?7l"

# Move cursor to the top
[ "$image" != "off" ] && printf "\033[0H"

# Get colors / bold
colors 2>/dev/null
bold

# Print the info
printinfo

if [ "$image" != "off" ]; then
    # Get cursor position
    info_height="$(IFS=';' read -srdR -p $'\E[6n' ROW COL; printf "%s" "${ROW#*[}")"

    # Set cursor position dynamically based on height of ascii/text.
    [ "$lines" -lt "$info_height" ] && lines="$info_height"

    printf "%b%s" "\033[${lines}H\033[${prompt_height}A"
fi

# Re-enable line wrap
[ "$line_wrap" == "off" ] && printf "%b%s" "\033[?7h"

# If enabled take a screenshot
if [ "$scrot" == "on" ]; then
    takescrot
fi


# }}}