synology-prompt.sh
· 13 KiB · Bash
Brut
#!/usr/bin/env bash
#
# synology-prompt.sh
#
# Universal Powerline-style SysAdmin prompt for Synology DSM.
#
# Features:
# - No external prompt framework required
# - Nerd Font / Powerline icons
# - User and hostname
# - Current working directory
# - Git branch and repository state
# - Current filesystem usage
# - Indonesian date
# - Clock
# - Previous command exit status
# - Automatic root warning palette
#
# Requirements:
# - Bash
# - Standard DSM utilities: date, df, awk
#
# Optional:
# - Git
#
# Nerd Font only needs to be installed on the SSH client/terminal.
#
# This file is intended to be installed as:
#
# /etc/synology-prompt.sh
#
# and sourced from the user's interactive Bash environment.
#
# ==============================================================================
# GUARD
# ==============================================================================
# Interactive shell only.
case "$-" in
*i*) ;;
*) return 0 2>/dev/null || exit 0 ;;
esac
# Bash is required.
if [ -z "${BASH_VERSION:-}" ]; then
return 0 2>/dev/null || exit 0
fi
# Prevent loading more than once in the same shell.
if [ "${SYNO_PROMPT_LOADED:-0}" = "1" ]; then
return 0
fi
SYNO_PROMPT_LOADED=1
# ==============================================================================
# CONFIGURATION
# ==============================================================================
# Maximum displayed PWD length.
SYNO_MAX_PWD_LENGTH=35
# Show filesystem usage segment.
SYNO_SHOW_DISK=1
# Show Git segment when inside a Git repository.
SYNO_SHOW_GIT=1
# Show previous command exit code when non-zero.
SYNO_SHOW_EXIT_CODE=1
# ==============================================================================
# NERD FONT ICONS
#
# Fonts are rendered by the SSH client.
# Nothing needs to be installed on DSM.
# ==============================================================================
SYNO_ICON_USER=$'\uf007' #
SYNO_ICON_HOST=$'\uf233' #
SYNO_ICON_FOLDER=$'\uf07b' #
SYNO_ICON_GIT=$'\ue725' #
SYNO_ICON_DISK=$'\uf0a0' #
SYNO_ICON_CALENDAR=$'\uf073' #
SYNO_ICON_CLOCK=$'\uf017' #
SYNO_SEPARATOR=$'\ue0b0' #
# ==============================================================================
# INDONESIAN DATE
#
# Deliberately does not depend on id_ID locale being installed on DSM.
# ==============================================================================
_syno_day()
{
case "$(date +%u)" in
1) printf 'Senin' ;;
2) printf 'Selasa' ;;
3) printf 'Rabu' ;;
4) printf 'Kamis' ;;
5) printf 'Jumat' ;;
6) printf 'Sabtu' ;;
7) printf 'Minggu' ;;
esac
}
_syno_month()
{
case "$(date +%m)" in
01) printf 'Januari' ;;
02) printf 'Februari' ;;
03) printf 'Maret' ;;
04) printf 'April' ;;
05) printf 'Mei' ;;
06) printf 'Juni' ;;
07) printf 'Juli' ;;
08) printf 'Agustus' ;;
09) printf 'September' ;;
10) printf 'Oktober' ;;
11) printf 'November' ;;
12) printf 'Desember' ;;
esac
}
_syno_date()
{
printf '%s, %s %s %s' \
"$(_syno_day)" \
"$(date +%d)" \
"$(_syno_month)" \
"$(date +%Y)"
}
# ==============================================================================
# WORKING DIRECTORY
# ==============================================================================
_syno_pwd()
{
local p="$PWD"
# Replace the current user's home directory with ~.
case "$p" in
"$HOME")
p="~"
;;
"$HOME"/*)
p="~${p#$HOME}"
;;
esac
# Shorten very long paths.
if [ "${#p}" -gt "$SYNO_MAX_PWD_LENGTH" ]; then
p="…${p: -$((SYNO_MAX_PWD_LENGTH - 1))}"
fi
printf '%s' "$p"
}
# ==============================================================================
# GIT STATUS
#
# Symbols:
#
# clean no symbol
# dirty ◔
# ahead ▲
# behind ▼
# diverged ◆
# dirty + ahead ◔ △
# dirty + behind ◔ ▽
# dirty + diverged ◔ ◇
# stash N🗎
#
# The segment automatically disappears outside a Git repository.
# ==============================================================================
_syno_git()
{
[ "$SYNO_SHOW_GIT" = "1" ] || return
command -v git >/dev/null 2>&1 || return
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return
local branch
local status
local first_line
local dirty=0
local ahead=0
local behind=0
local stash=0
local symbol=""
branch="$(git symbolic-ref --quiet --short HEAD 2>/dev/null)"
# Detached HEAD fallback.
if [ -z "$branch" ]; then
branch="$(git rev-parse --short HEAD 2>/dev/null)"
fi
[ -n "$branch" ] || return
status="$(git status --porcelain -b 2>/dev/null)"
first_line="$(printf '%s\n' "$status" | head -n 1)"
# Lines after the ## branch line indicate working-tree/index changes.
if printf '%s\n' "$status" | tail -n +2 | grep -q .; then
dirty=1
fi
case "$first_line" in
*ahead*)
ahead=1
;;
esac
case "$first_line" in
*behind*)
behind=1
;;
esac
if [ "$dirty" -eq 1 ] &&
[ "$ahead" -eq 1 ] &&
[ "$behind" -eq 1 ]; then
symbol=" ◔ ◇"
elif [ "$dirty" -eq 1 ] &&
[ "$ahead" -eq 1 ]; then
symbol=" ◔ △"
elif [ "$dirty" -eq 1 ] &&
[ "$behind" -eq 1 ]; then
symbol=" ◔ ▽"
elif [ "$dirty" -eq 1 ]; then
symbol=" ◔"
elif [ "$ahead" -eq 1 ] &&
[ "$behind" -eq 1 ]; then
symbol=" ◆"
elif [ "$ahead" -eq 1 ]; then
symbol=" ▲"
elif [ "$behind" -eq 1 ]; then
symbol=" ▼"
fi
stash="$(git stash list 2>/dev/null | wc -l | tr -d ' ')"
printf '%s %s%s' \
"$SYNO_ICON_GIT" \
"$branch" \
"$symbol"
if [ "${stash:-0}" -gt 0 ] 2>/dev/null; then
printf ' %s🗎' "$stash"
fi
}
# ==============================================================================
# FILESYSTEM USAGE
#
# Displays usage of the filesystem containing the current working directory.
#
# Example:
#
# /volume1/docker/... -> volume1 usage
# /tmp/... -> filesystem containing /tmp
# /root -> root filesystem usage
# ==============================================================================
_syno_disk_percent()
{
[ "$SYNO_SHOW_DISK" = "1" ] || return
local usage
usage="$(
df -P "$PWD" 2>/dev/null |
awk 'NR==2 {gsub(/%/, "", $5); print $5}'
)"
[ -n "$usage" ] || return
printf '%s' "$usage"
}
# ==============================================================================
# POWERLINE SEGMENT RENDERER
#
# Escape sequences are stored directly in PS1.
#
# \[ and \] tell Bash that ANSI escape sequences consume zero terminal columns.
# This keeps cursor positioning and line editing correct.
# ==============================================================================
_syno_add_segment()
{
local text="$1"
local fg="$2"
local bg="$3"
local next_bg="$4"
PS1+="\[\e[1;38;5;${fg};48;5;${bg}m\]"
PS1+=" ${text} "
# Arrow:
# foreground = current background
# background = next segment background
PS1+="\[\e[0;38;5;${bg};48;5;${next_bg}m\]"
PS1+="${SYNO_SEPARATOR}"
}
_syno_add_last_segment()
{
local text="$1"
local fg="$2"
local bg="$3"
PS1+="\[\e[1;38;5;${fg};48;5;${bg}m\]"
PS1+=" ${text} "
# Final arrow into terminal default background.
PS1+="\[\e[0;38;5;${bg};49m\]"
PS1+="${SYNO_SEPARATOR}"
PS1+="\[\e[0m\]"
}
# ==============================================================================
# PROMPT BUILDER
# ==============================================================================
_syno_prompt()
{
# IMPORTANT:
# This must be the first command so $? still contains the exit status
# of the user's previous command.
local exit_code=$?
local user_text
local host_text
local pwd_text
local git_text=""
local disk_text=""
local disk_percent=""
local date_text
local clock_text
user_text="${SYNO_ICON_USER} ${USER:-$(id -un)}"
host_text="${SYNO_ICON_HOST} ${HOSTNAME:-$(hostname)}"
pwd_text="${SYNO_ICON_FOLDER} $(_syno_pwd)"
git_text="$(_syno_git)"
disk_percent="$(_syno_disk_percent)"
if [ -n "$disk_percent" ]; then
disk_text="${SYNO_ICON_DISK} ${disk_percent}%"
fi
date_text="${SYNO_ICON_CALENDAR} $(_syno_date)"
clock_text="${SYNO_ICON_CLOCK} $(date +%H:%M:%S)"
# ==========================================================================
# NORMAL USER PALETTE
# ==========================================================================
local user_fg=16
local user_bg=46
local host_fg=231
local host_bg=33
local pwd_fg=238
local pwd_bg=255
local git_fg=250
local git_bg=238
local disk_fg=231
local disk_bg=31
local date_fg=231
local date_bg=135
local clock_fg=231
local clock_bg=16
local input_fg=45
# ==========================================================================
# ROOT WARNING PALETTE
#
# Root is deliberately visually obvious.
# ==========================================================================
if [ "$(id -u)" -eq 0 ]; then
user_fg=231
user_bg=196
host_fg=231
host_bg=203
pwd_fg=16
pwd_bg=226
git_fg=231
git_bg=196
disk_fg=16
disk_bg=214
date_fg=231
date_bg=203
clock_fg=231
clock_bg=196
input_fg=203
fi
# ==========================================================================
# BUILD FIRST LINE
# ==========================================================================
PS1="\n╭"
_syno_add_segment \
"$user_text" \
"$user_fg" \
"$user_bg" \
"$host_bg"
_syno_add_segment \
"$host_text" \
"$host_fg" \
"$host_bg" \
"$pwd_bg"
# --------------------------------------------------------------------------
# PWD -> optional Git -> optional Disk -> Date -> Clock
#
# We need to determine the background of the segment following PWD.
# --------------------------------------------------------------------------
if [ -n "$git_text" ]; then
_syno_add_segment \
"$pwd_text" \
"$pwd_fg" \
"$pwd_bg" \
"$git_bg"
if [ -n "$disk_text" ]; then
_syno_add_segment \
"$git_text" \
"$git_fg" \
"$git_bg" \
"$disk_bg"
else
_syno_add_segment \
"$git_text" \
"$git_fg" \
"$git_bg" \
"$date_bg"
fi
else
if [ -n "$disk_text" ]; then
_syno_add_segment \
"$pwd_text" \
"$pwd_fg" \
"$pwd_bg" \
"$disk_bg"
else
_syno_add_segment \
"$pwd_text" \
"$pwd_fg" \
"$pwd_bg" \
"$date_bg"
fi
fi
if [ -n "$disk_text" ]; then
_syno_add_segment \
"$disk_text" \
"$disk_fg" \
"$disk_bg" \
"$date_bg"
fi
_syno_add_segment \
"$date_text" \
"$date_fg" \
"$date_bg" \
"$clock_bg"
_syno_add_last_segment \
"$clock_text" \
"$clock_fg" \
"$clock_bg"
# ==========================================================================
# BUILD SECOND LINE
# ==========================================================================
local symbol='$'
if [ "$(id -u)" -eq 0 ]; then
symbol='#'
fi
PS1+="\n╰> "
# Previous command failed.
if [ "$SYNO_SHOW_EXIT_CODE" = "1" ] &&
[ "$exit_code" -ne 0 ]; then
PS1+="\[\e[1;38;5;196m\]"
PS1+="✘ ${exit_code} "
PS1+="\[\e[0m\]"
fi
PS1+="\[\e[1;38;5;${input_fg}m\]"
PS1+="${symbol} "
PS1+="\[\e[0m\]"
}
# ==============================================================================
# ACTIVATE PROMPT
# ==============================================================================
PROMPT_COMMAND=_syno_prompt
# ==============================================================================
# OPTIONAL CONVENIENCE ALIASES
#
# Only simple commands known to work on DSM are used.
# ==============================================================================
alias ll='ls -lah'
alias la='ls -A'
alias l='ls -CF'
alias dfh='df -h'
alias duh='du -h'
if command -v git >/dev/null 2>&1; then
alias gs='git status'
alias gl='git log --oneline --decorate --graph -15'
fi
# ==============================================================================
# CLEAN TERMINAL FORMATTING ON EXIT
# ==============================================================================
trap 'printf "\033[0m"' EXIT
| 1 | #!/usr/bin/env bash |
| 2 | # |
| 3 | # synology-prompt.sh |
| 4 | # |
| 5 | # Universal Powerline-style SysAdmin prompt for Synology DSM. |
| 6 | # |
| 7 | # Features: |
| 8 | # - No external prompt framework required |
| 9 | # - Nerd Font / Powerline icons |
| 10 | # - User and hostname |
| 11 | # - Current working directory |
| 12 | # - Git branch and repository state |
| 13 | # - Current filesystem usage |
| 14 | # - Indonesian date |
| 15 | # - Clock |
| 16 | # - Previous command exit status |
| 17 | # - Automatic root warning palette |
| 18 | # |
| 19 | # Requirements: |
| 20 | # - Bash |
| 21 | # - Standard DSM utilities: date, df, awk |
| 22 | # |
| 23 | # Optional: |
| 24 | # - Git |
| 25 | # |
| 26 | # Nerd Font only needs to be installed on the SSH client/terminal. |
| 27 | # |
| 28 | # This file is intended to be installed as: |
| 29 | # |
| 30 | # /etc/synology-prompt.sh |
| 31 | # |
| 32 | # and sourced from the user's interactive Bash environment. |
| 33 | # |
| 34 | |
| 35 | |
| 36 | # ============================================================================== |
| 37 | # GUARD |
| 38 | # ============================================================================== |
| 39 | |
| 40 | # Interactive shell only. |
| 41 | case "$-" in |
| 42 | *i*) ;; |
| 43 | *) return 0 2>/dev/null || exit 0 ;; |
| 44 | esac |
| 45 | |
| 46 | # Bash is required. |
| 47 | if [ -z "${BASH_VERSION:-}" ]; then |
| 48 | return 0 2>/dev/null || exit 0 |
| 49 | fi |
| 50 | |
| 51 | # Prevent loading more than once in the same shell. |
| 52 | if [ "${SYNO_PROMPT_LOADED:-0}" = "1" ]; then |
| 53 | return 0 |
| 54 | fi |
| 55 | |
| 56 | SYNO_PROMPT_LOADED=1 |
| 57 | |
| 58 | |
| 59 | # ============================================================================== |
| 60 | # CONFIGURATION |
| 61 | # ============================================================================== |
| 62 | |
| 63 | # Maximum displayed PWD length. |
| 64 | SYNO_MAX_PWD_LENGTH=35 |
| 65 | |
| 66 | # Show filesystem usage segment. |
| 67 | SYNO_SHOW_DISK=1 |
| 68 | |
| 69 | # Show Git segment when inside a Git repository. |
| 70 | SYNO_SHOW_GIT=1 |
| 71 | |
| 72 | # Show previous command exit code when non-zero. |
| 73 | SYNO_SHOW_EXIT_CODE=1 |
| 74 | |
| 75 | |
| 76 | # ============================================================================== |
| 77 | # NERD FONT ICONS |
| 78 | # |
| 79 | # Fonts are rendered by the SSH client. |
| 80 | # Nothing needs to be installed on DSM. |
| 81 | # ============================================================================== |
| 82 | |
| 83 | SYNO_ICON_USER=$'\uf007' # |
| 84 | SYNO_ICON_HOST=$'\uf233' # |
| 85 | SYNO_ICON_FOLDER=$'\uf07b' # |
| 86 | SYNO_ICON_GIT=$'\ue725' # |
| 87 | SYNO_ICON_DISK=$'\uf0a0' # |
| 88 | SYNO_ICON_CALENDAR=$'\uf073' # |
| 89 | SYNO_ICON_CLOCK=$'\uf017' # |
| 90 | |
| 91 | SYNO_SEPARATOR=$'\ue0b0' # |
| 92 | |
| 93 | |
| 94 | # ============================================================================== |
| 95 | # INDONESIAN DATE |
| 96 | # |
| 97 | # Deliberately does not depend on id_ID locale being installed on DSM. |
| 98 | # ============================================================================== |
| 99 | |
| 100 | _syno_day() |
| 101 | { |
| 102 | case "$(date +%u)" in |
| 103 | 1) printf 'Senin' ;; |
| 104 | 2) printf 'Selasa' ;; |
| 105 | 3) printf 'Rabu' ;; |
| 106 | 4) printf 'Kamis' ;; |
| 107 | 5) printf 'Jumat' ;; |
| 108 | 6) printf 'Sabtu' ;; |
| 109 | 7) printf 'Minggu' ;; |
| 110 | esac |
| 111 | } |
| 112 | |
| 113 | |
| 114 | _syno_month() |
| 115 | { |
| 116 | case "$(date +%m)" in |
| 117 | 01) printf 'Januari' ;; |
| 118 | 02) printf 'Februari' ;; |
| 119 | 03) printf 'Maret' ;; |
| 120 | 04) printf 'April' ;; |
| 121 | 05) printf 'Mei' ;; |
| 122 | 06) printf 'Juni' ;; |
| 123 | 07) printf 'Juli' ;; |
| 124 | 08) printf 'Agustus' ;; |
| 125 | 09) printf 'September' ;; |
| 126 | 10) printf 'Oktober' ;; |
| 127 | 11) printf 'November' ;; |
| 128 | 12) printf 'Desember' ;; |
| 129 | esac |
| 130 | } |
| 131 | |
| 132 | |
| 133 | _syno_date() |
| 134 | { |
| 135 | printf '%s, %s %s %s' \ |
| 136 | "$(_syno_day)" \ |
| 137 | "$(date +%d)" \ |
| 138 | "$(_syno_month)" \ |
| 139 | "$(date +%Y)" |
| 140 | } |
| 141 | |
| 142 | |
| 143 | # ============================================================================== |
| 144 | # WORKING DIRECTORY |
| 145 | # ============================================================================== |
| 146 | |
| 147 | _syno_pwd() |
| 148 | { |
| 149 | local p="$PWD" |
| 150 | |
| 151 | # Replace the current user's home directory with ~. |
| 152 | case "$p" in |
| 153 | "$HOME") |
| 154 | p="~" |
| 155 | ;; |
| 156 | "$HOME"/*) |
| 157 | p="~${p#$HOME}" |
| 158 | ;; |
| 159 | esac |
| 160 | |
| 161 | # Shorten very long paths. |
| 162 | if [ "${#p}" -gt "$SYNO_MAX_PWD_LENGTH" ]; then |
| 163 | p="…${p: -$((SYNO_MAX_PWD_LENGTH - 1))}" |
| 164 | fi |
| 165 | |
| 166 | printf '%s' "$p" |
| 167 | } |
| 168 | |
| 169 | |
| 170 | # ============================================================================== |
| 171 | # GIT STATUS |
| 172 | # |
| 173 | # Symbols: |
| 174 | # |
| 175 | # clean no symbol |
| 176 | # dirty ◔ |
| 177 | # ahead ▲ |
| 178 | # behind ▼ |
| 179 | # diverged ◆ |
| 180 | # dirty + ahead ◔ △ |
| 181 | # dirty + behind ◔ ▽ |
| 182 | # dirty + diverged ◔ ◇ |
| 183 | # stash N🗎 |
| 184 | # |
| 185 | # The segment automatically disappears outside a Git repository. |
| 186 | # ============================================================================== |
| 187 | |
| 188 | _syno_git() |
| 189 | { |
| 190 | [ "$SYNO_SHOW_GIT" = "1" ] || return |
| 191 | |
| 192 | command -v git >/dev/null 2>&1 || return |
| 193 | |
| 194 | git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return |
| 195 | |
| 196 | local branch |
| 197 | local status |
| 198 | local first_line |
| 199 | |
| 200 | local dirty=0 |
| 201 | local ahead=0 |
| 202 | local behind=0 |
| 203 | local stash=0 |
| 204 | |
| 205 | local symbol="" |
| 206 | |
| 207 | branch="$(git symbolic-ref --quiet --short HEAD 2>/dev/null)" |
| 208 | |
| 209 | # Detached HEAD fallback. |
| 210 | if [ -z "$branch" ]; then |
| 211 | branch="$(git rev-parse --short HEAD 2>/dev/null)" |
| 212 | fi |
| 213 | |
| 214 | [ -n "$branch" ] || return |
| 215 | |
| 216 | status="$(git status --porcelain -b 2>/dev/null)" |
| 217 | first_line="$(printf '%s\n' "$status" | head -n 1)" |
| 218 | |
| 219 | # Lines after the ## branch line indicate working-tree/index changes. |
| 220 | if printf '%s\n' "$status" | tail -n +2 | grep -q .; then |
| 221 | dirty=1 |
| 222 | fi |
| 223 | |
| 224 | case "$first_line" in |
| 225 | *ahead*) |
| 226 | ahead=1 |
| 227 | ;; |
| 228 | esac |
| 229 | |
| 230 | case "$first_line" in |
| 231 | *behind*) |
| 232 | behind=1 |
| 233 | ;; |
| 234 | esac |
| 235 | |
| 236 | if [ "$dirty" -eq 1 ] && |
| 237 | [ "$ahead" -eq 1 ] && |
| 238 | [ "$behind" -eq 1 ]; then |
| 239 | |
| 240 | symbol=" ◔ ◇" |
| 241 | |
| 242 | elif [ "$dirty" -eq 1 ] && |
| 243 | [ "$ahead" -eq 1 ]; then |
| 244 | |
| 245 | symbol=" ◔ △" |
| 246 | |
| 247 | elif [ "$dirty" -eq 1 ] && |
| 248 | [ "$behind" -eq 1 ]; then |
| 249 | |
| 250 | symbol=" ◔ ▽" |
| 251 | |
| 252 | elif [ "$dirty" -eq 1 ]; then |
| 253 | |
| 254 | symbol=" ◔" |
| 255 | |
| 256 | elif [ "$ahead" -eq 1 ] && |
| 257 | [ "$behind" -eq 1 ]; then |
| 258 | |
| 259 | symbol=" ◆" |
| 260 | |
| 261 | elif [ "$ahead" -eq 1 ]; then |
| 262 | |
| 263 | symbol=" ▲" |
| 264 | |
| 265 | elif [ "$behind" -eq 1 ]; then |
| 266 | |
| 267 | symbol=" ▼" |
| 268 | fi |
| 269 | |
| 270 | stash="$(git stash list 2>/dev/null | wc -l | tr -d ' ')" |
| 271 | |
| 272 | printf '%s %s%s' \ |
| 273 | "$SYNO_ICON_GIT" \ |
| 274 | "$branch" \ |
| 275 | "$symbol" |
| 276 | |
| 277 | if [ "${stash:-0}" -gt 0 ] 2>/dev/null; then |
| 278 | printf ' %s🗎' "$stash" |
| 279 | fi |
| 280 | } |
| 281 | |
| 282 | |
| 283 | # ============================================================================== |
| 284 | # FILESYSTEM USAGE |
| 285 | # |
| 286 | # Displays usage of the filesystem containing the current working directory. |
| 287 | # |
| 288 | # Example: |
| 289 | # |
| 290 | # /volume1/docker/... -> volume1 usage |
| 291 | # /tmp/... -> filesystem containing /tmp |
| 292 | # /root -> root filesystem usage |
| 293 | # ============================================================================== |
| 294 | |
| 295 | _syno_disk_percent() |
| 296 | { |
| 297 | [ "$SYNO_SHOW_DISK" = "1" ] || return |
| 298 | |
| 299 | local usage |
| 300 | |
| 301 | usage="$( |
| 302 | df -P "$PWD" 2>/dev/null | |
| 303 | awk 'NR==2 {gsub(/%/, "", $5); print $5}' |
| 304 | )" |
| 305 | |
| 306 | [ -n "$usage" ] || return |
| 307 | |
| 308 | printf '%s' "$usage" |
| 309 | } |
| 310 | |
| 311 | |
| 312 | # ============================================================================== |
| 313 | # POWERLINE SEGMENT RENDERER |
| 314 | # |
| 315 | # Escape sequences are stored directly in PS1. |
| 316 | # |
| 317 | # \[ and \] tell Bash that ANSI escape sequences consume zero terminal columns. |
| 318 | # This keeps cursor positioning and line editing correct. |
| 319 | # ============================================================================== |
| 320 | |
| 321 | _syno_add_segment() |
| 322 | { |
| 323 | local text="$1" |
| 324 | local fg="$2" |
| 325 | local bg="$3" |
| 326 | local next_bg="$4" |
| 327 | |
| 328 | PS1+="\[\e[1;38;5;${fg};48;5;${bg}m\]" |
| 329 | PS1+=" ${text} " |
| 330 | |
| 331 | # Arrow: |
| 332 | # foreground = current background |
| 333 | # background = next segment background |
| 334 | PS1+="\[\e[0;38;5;${bg};48;5;${next_bg}m\]" |
| 335 | PS1+="${SYNO_SEPARATOR}" |
| 336 | } |
| 337 | |
| 338 | |
| 339 | _syno_add_last_segment() |
| 340 | { |
| 341 | local text="$1" |
| 342 | local fg="$2" |
| 343 | local bg="$3" |
| 344 | |
| 345 | PS1+="\[\e[1;38;5;${fg};48;5;${bg}m\]" |
| 346 | PS1+=" ${text} " |
| 347 | |
| 348 | # Final arrow into terminal default background. |
| 349 | PS1+="\[\e[0;38;5;${bg};49m\]" |
| 350 | PS1+="${SYNO_SEPARATOR}" |
| 351 | |
| 352 | PS1+="\[\e[0m\]" |
| 353 | } |
| 354 | |
| 355 | |
| 356 | # ============================================================================== |
| 357 | # PROMPT BUILDER |
| 358 | # ============================================================================== |
| 359 | |
| 360 | _syno_prompt() |
| 361 | { |
| 362 | # IMPORTANT: |
| 363 | # This must be the first command so $? still contains the exit status |
| 364 | # of the user's previous command. |
| 365 | local exit_code=$? |
| 366 | |
| 367 | local user_text |
| 368 | local host_text |
| 369 | local pwd_text |
| 370 | local git_text="" |
| 371 | local disk_text="" |
| 372 | local disk_percent="" |
| 373 | local date_text |
| 374 | local clock_text |
| 375 | |
| 376 | user_text="${SYNO_ICON_USER} ${USER:-$(id -un)}" |
| 377 | host_text="${SYNO_ICON_HOST} ${HOSTNAME:-$(hostname)}" |
| 378 | pwd_text="${SYNO_ICON_FOLDER} $(_syno_pwd)" |
| 379 | |
| 380 | git_text="$(_syno_git)" |
| 381 | |
| 382 | disk_percent="$(_syno_disk_percent)" |
| 383 | |
| 384 | if [ -n "$disk_percent" ]; then |
| 385 | disk_text="${SYNO_ICON_DISK} ${disk_percent}%" |
| 386 | fi |
| 387 | |
| 388 | date_text="${SYNO_ICON_CALENDAR} $(_syno_date)" |
| 389 | clock_text="${SYNO_ICON_CLOCK} $(date +%H:%M:%S)" |
| 390 | |
| 391 | |
| 392 | # ========================================================================== |
| 393 | # NORMAL USER PALETTE |
| 394 | # ========================================================================== |
| 395 | |
| 396 | local user_fg=16 |
| 397 | local user_bg=46 |
| 398 | |
| 399 | local host_fg=231 |
| 400 | local host_bg=33 |
| 401 | |
| 402 | local pwd_fg=238 |
| 403 | local pwd_bg=255 |
| 404 | |
| 405 | local git_fg=250 |
| 406 | local git_bg=238 |
| 407 | |
| 408 | local disk_fg=231 |
| 409 | local disk_bg=31 |
| 410 | |
| 411 | local date_fg=231 |
| 412 | local date_bg=135 |
| 413 | |
| 414 | local clock_fg=231 |
| 415 | local clock_bg=16 |
| 416 | |
| 417 | local input_fg=45 |
| 418 | |
| 419 | |
| 420 | # ========================================================================== |
| 421 | # ROOT WARNING PALETTE |
| 422 | # |
| 423 | # Root is deliberately visually obvious. |
| 424 | # ========================================================================== |
| 425 | |
| 426 | if [ "$(id -u)" -eq 0 ]; then |
| 427 | |
| 428 | user_fg=231 |
| 429 | user_bg=196 |
| 430 | |
| 431 | host_fg=231 |
| 432 | host_bg=203 |
| 433 | |
| 434 | pwd_fg=16 |
| 435 | pwd_bg=226 |
| 436 | |
| 437 | git_fg=231 |
| 438 | git_bg=196 |
| 439 | |
| 440 | disk_fg=16 |
| 441 | disk_bg=214 |
| 442 | |
| 443 | date_fg=231 |
| 444 | date_bg=203 |
| 445 | |
| 446 | clock_fg=231 |
| 447 | clock_bg=196 |
| 448 | |
| 449 | input_fg=203 |
| 450 | fi |
| 451 | |
| 452 | |
| 453 | # ========================================================================== |
| 454 | # BUILD FIRST LINE |
| 455 | # ========================================================================== |
| 456 | |
| 457 | PS1="\n╭" |
| 458 | |
| 459 | _syno_add_segment \ |
| 460 | "$user_text" \ |
| 461 | "$user_fg" \ |
| 462 | "$user_bg" \ |
| 463 | "$host_bg" |
| 464 | |
| 465 | _syno_add_segment \ |
| 466 | "$host_text" \ |
| 467 | "$host_fg" \ |
| 468 | "$host_bg" \ |
| 469 | "$pwd_bg" |
| 470 | |
| 471 | |
| 472 | # -------------------------------------------------------------------------- |
| 473 | # PWD -> optional Git -> optional Disk -> Date -> Clock |
| 474 | # |
| 475 | # We need to determine the background of the segment following PWD. |
| 476 | # -------------------------------------------------------------------------- |
| 477 | |
| 478 | if [ -n "$git_text" ]; then |
| 479 | |
| 480 | _syno_add_segment \ |
| 481 | "$pwd_text" \ |
| 482 | "$pwd_fg" \ |
| 483 | "$pwd_bg" \ |
| 484 | "$git_bg" |
| 485 | |
| 486 | if [ -n "$disk_text" ]; then |
| 487 | |
| 488 | _syno_add_segment \ |
| 489 | "$git_text" \ |
| 490 | "$git_fg" \ |
| 491 | "$git_bg" \ |
| 492 | "$disk_bg" |
| 493 | |
| 494 | else |
| 495 | |
| 496 | _syno_add_segment \ |
| 497 | "$git_text" \ |
| 498 | "$git_fg" \ |
| 499 | "$git_bg" \ |
| 500 | "$date_bg" |
| 501 | fi |
| 502 | |
| 503 | else |
| 504 | |
| 505 | if [ -n "$disk_text" ]; then |
| 506 | |
| 507 | _syno_add_segment \ |
| 508 | "$pwd_text" \ |
| 509 | "$pwd_fg" \ |
| 510 | "$pwd_bg" \ |
| 511 | "$disk_bg" |
| 512 | |
| 513 | else |
| 514 | |
| 515 | _syno_add_segment \ |
| 516 | "$pwd_text" \ |
| 517 | "$pwd_fg" \ |
| 518 | "$pwd_bg" \ |
| 519 | "$date_bg" |
| 520 | fi |
| 521 | fi |
| 522 | |
| 523 | |
| 524 | if [ -n "$disk_text" ]; then |
| 525 | |
| 526 | _syno_add_segment \ |
| 527 | "$disk_text" \ |
| 528 | "$disk_fg" \ |
| 529 | "$disk_bg" \ |
| 530 | "$date_bg" |
| 531 | fi |
| 532 | |
| 533 | |
| 534 | _syno_add_segment \ |
| 535 | "$date_text" \ |
| 536 | "$date_fg" \ |
| 537 | "$date_bg" \ |
| 538 | "$clock_bg" |
| 539 | |
| 540 | |
| 541 | _syno_add_last_segment \ |
| 542 | "$clock_text" \ |
| 543 | "$clock_fg" \ |
| 544 | "$clock_bg" |
| 545 | |
| 546 | |
| 547 | # ========================================================================== |
| 548 | # BUILD SECOND LINE |
| 549 | # ========================================================================== |
| 550 | |
| 551 | local symbol='$' |
| 552 | |
| 553 | if [ "$(id -u)" -eq 0 ]; then |
| 554 | symbol='#' |
| 555 | fi |
| 556 | |
| 557 | PS1+="\n╰> " |
| 558 | |
| 559 | |
| 560 | # Previous command failed. |
| 561 | if [ "$SYNO_SHOW_EXIT_CODE" = "1" ] && |
| 562 | [ "$exit_code" -ne 0 ]; then |
| 563 | |
| 564 | PS1+="\[\e[1;38;5;196m\]" |
| 565 | PS1+="✘ ${exit_code} " |
| 566 | PS1+="\[\e[0m\]" |
| 567 | fi |
| 568 | |
| 569 | |
| 570 | PS1+="\[\e[1;38;5;${input_fg}m\]" |
| 571 | PS1+="${symbol} " |
| 572 | PS1+="\[\e[0m\]" |
| 573 | } |
| 574 | |
| 575 | |
| 576 | # ============================================================================== |
| 577 | # ACTIVATE PROMPT |
| 578 | # ============================================================================== |
| 579 | |
| 580 | PROMPT_COMMAND=_syno_prompt |
| 581 | |
| 582 | |
| 583 | # ============================================================================== |
| 584 | # OPTIONAL CONVENIENCE ALIASES |
| 585 | # |
| 586 | # Only simple commands known to work on DSM are used. |
| 587 | # ============================================================================== |
| 588 | |
| 589 | alias ll='ls -lah' |
| 590 | alias la='ls -A' |
| 591 | alias l='ls -CF' |
| 592 | |
| 593 | alias dfh='df -h' |
| 594 | alias duh='du -h' |
| 595 | |
| 596 | if command -v git >/dev/null 2>&1; then |
| 597 | alias gs='git status' |
| 598 | alias gl='git log --oneline --decorate --graph -15' |
| 599 | fi |
| 600 | |
| 601 | |
| 602 | # ============================================================================== |
| 603 | # CLEAN TERMINAL FORMATTING ON EXIT |
| 604 | # ============================================================================== |
| 605 | |
| 606 | trap 'printf "\033[0m"' EXIT |