summaryrefslogtreecommitdiff
path: root/kitty/ssh_picker.sh
diff options
context:
space:
mode:
Diffstat (limited to 'kitty/ssh_picker.sh')
-rwxr-xr-xkitty/ssh_picker.sh202
1 files changed, 202 insertions, 0 deletions
diff --git a/kitty/ssh_picker.sh b/kitty/ssh_picker.sh
new file mode 100755
index 0000000..6ad6e3a
--- /dev/null
+++ b/kitty/ssh_picker.sh
@@ -0,0 +1,202 @@
+#!/usr/bin/env bash
+# ~/.config/kitty/ssh_picker.sh
+# Launched by kitty as an overlay window.
+# Reads servers from ~/.ssh/config (Host entries) and lets
+# you fuzzy-filter with arrow keys, then opens kitten ssh.
+#
+# Dependencies: none beyond bash + standard coreutils.
+# Optional: fzf — if present it takes over the picker UI.
+
+set -euo pipefail
+
+# ------------------------------------------------------------
+# config — edit these or let them fall through to ~/.ssh/config
+# ------------------------------------------------------------
+SSH_CONFIG="${HOME}/.ssh/config"
+TERM_FALLBACK="xterm-256color"
+
+# ------------------------------------------------------------
+# gruvbox dark ANSI helpers
+# ------------------------------------------------------------
+RESET=$'\e[0m'
+BOLD=$'\e[1m'
+DIM=$'\e[2m'
+
+GB_BG=$'\e[48;2;40;40;40m' # #282828
+GB_BG1=$'\e[48;2;60;56;54m' # #3c3836
+GB_BG2=$'\e[48;2;80;73;69m' # #504945
+GB_YELLOW=$'\e[38;2;250;189;47m' # #fabd2f
+GB_BLUE=$'\e[38;2;131;165;152m' # #83a598
+GB_GREEN=$'\e[38;2;184;187;38m' # #b8bb26
+GB_RED=$'\e[38;2;251;73;52m' # #fb4934
+GB_ORANGE=$'\e[38;2;254;128;25m' # #fe8019
+GB_FG=$'\e[38;2;235;219;178m' # #ebdbb2
+GB_DIM=$'\e[38;2;168;153;132m' # #a89984
+
+# ------------------------------------------------------------
+# parse servers
+# ------------------------------------------------------------
+get_servers() {
+ local servers=()
+
+ # pull Host entries from ~/.ssh/config (skip wildcards)
+ if [[ -f "$SSH_CONFIG" ]]; then
+ while IFS= read -r line; do
+ if [[ "$line" =~ ^[Hh]ost[[:space:]]+([^*?]+)$ ]]; then
+ local host="${BASH_REMATCH[1]// /}"
+ [[ -n "$host" ]] && servers+=("$host")
+ fi
+ done < "$SSH_CONFIG"
+ fi
+
+ # fallback examples if config is empty
+ if [[ ${#servers[@]} -eq 0 ]]; then
+ servers=(
+ "contabo server"
+ )
+ fi
+
+ printf '%s\n' "${servers[@]}"
+}
+
+# ------------------------------------------------------------
+# fzf path (preferred)
+# ------------------------------------------------------------
+if command -v fzf &>/dev/null; then
+ selected=$(get_servers | fzf \
+ --prompt=" ssh " \
+ --pointer=">" \
+ --marker="*" \
+ --height=40% \
+ --layout=reverse \
+ --border=rounded \
+ --info=inline \
+ --color="dark,\
+bg:#282828,\
+bg+:#3c3836,\
+fg:#ebdbb2,\
+fg+:#fbf1c7,\
+hl:#fabd2f,\
+hl+:#fabd2f,\
+border:#504945,\
+prompt:#83a598,\
+pointer:#fe8019,\
+marker:#b8bb26,\
+spinner:#d3869b,\
+header:#a89984,\
+info:#a89984" \
+ --header=" ctrl+c to cancel" \
+ --preview="echo {} | xargs -I% sh -c 'grep -A10 \"^Host %$\" ~/.ssh/config 2>/dev/null || echo \"no config entry\"'" \
+ --preview-window="right:40%:wrap" \
+ 2>/dev/null) || exit 0
+
+ [[ -z "$selected" ]] && exit 0
+ TERM="$TERM_FALLBACK" kitten ssh "$selected"
+ exit 0
+fi
+
+# ------------------------------------------------------------
+# built-in picker (no fzf)
+# ------------------------------------------------------------
+mapfile -t SERVERS < <(get_servers)
+TOTAL=${#SERVERS[@]}
+SELECTED=0
+QUERY=""
+FILTERED=("${SERVERS[@]}")
+
+draw() {
+ clear
+ printf '%s' "${GB_BG}"
+ printf '\n'
+ printf ' %s%s ssh picker%s\n' "${GB_YELLOW}${BOLD}" "" "${RESET}"
+ printf ' %s%s%s\n\n' "${GB_DIM}" "arrow keys to navigate, enter to connect, esc to quit" "${RESET}"
+
+ # search bar
+ printf ' %ssearch:%s %s%s%s\n\n' \
+ "${GB_DIM}" "${RESET}" \
+ "${GB_FG}${BOLD}" "${QUERY}" "${RESET}"
+
+ # server list
+ local i=0
+ for srv in "${FILTERED[@]}"; do
+ if [[ $i -eq $SELECTED ]]; then
+ printf ' %s%s > %s%s\n' "${GB_BG1}${GB_ORANGE}${BOLD}" "" "$srv" "${RESET}"
+ else
+ printf ' %s %s%s\n' "${GB_DIM}" "$srv" "${RESET}"
+ fi
+ (( i++ ))
+ done
+
+ printf '\n %s%s hosts found • install fzf for preview support%s\n' \
+ "${GB_DIM}" "${#FILTERED[@]}" "${RESET}"
+}
+
+filter() {
+ FILTERED=()
+ SELECTED=0
+ for srv in "${SERVERS[@]}"; do
+ if [[ -z "$QUERY" || "${srv,,}" == *"${QUERY,,}"* ]]; then
+ FILTERED+=("$srv")
+ fi
+ done
+}
+
+# hide cursor
+tput civis
+trap 'tput cnorm; clear' EXIT
+
+while true; do
+ draw
+
+ # read a single keypress (handles escape sequences)
+ IFS= read -r -s -N1 key
+
+ # check for escape sequences (arrow keys)
+ if [[ "$key" == $'\e' ]]; then
+ IFS= read -r -s -N1 -t 0.1 k2 || true
+ if [[ "$k2" == "[" ]]; then
+ IFS= read -r -s -N1 -t 0.1 k3 || true
+ case "$k3" in
+ A) # up
+ (( SELECTED > 0 )) && (( SELECTED-- ))
+ ;;
+ B) # down
+ (( SELECTED < ${#FILTERED[@]} - 1 )) && (( SELECTED++ ))
+ ;;
+ esac
+ else
+ # plain escape — quit
+ exit 0
+ fi
+ continue
+ fi
+
+ case "$key" in
+ $'\n'|$'\r')
+ [[ ${#FILTERED[@]} -eq 0 ]] && continue
+ tput cnorm
+ clear
+ host="${FILTERED[$SELECTED]}"
+ printf '%sconnecting to %s%s%s...\n\n' \
+ "${GB_DIM}" "${GB_BLUE}${BOLD}" "$host" "${RESET}"
+ TERM="$TERM_FALLBACK" kitten ssh "$host"
+ exit 0
+ ;;
+ $'\x7f'|$'\b')
+ # backspace
+ QUERY="${QUERY%?}"
+ filter
+ ;;
+ $'\x03')
+ # ctrl+c
+ exit 0
+ ;;
+ *)
+ # printable character — append to query
+ if [[ "$key" =~ ^[[:print:]]$ ]]; then
+ QUERY+="$key"
+ filter
+ fi
+ ;;
+ esac
+done