diff --git a/SSH.conf b/SSH.conf new file mode 100644 index 0000000..77e2db5 --- /dev/null +++ b/SSH.conf @@ -0,0 +1,81 @@ +# use the same prefix as dwm +set -g prefix C-g +# needed for e.g. mutt +bind C-g send-prefix + +set -g set-titles on +set -g status-position top +set -g status-keys vi +set -g mode-keys vi +set -g base-index 1 +set -g pane-base-index 1 + +set history-file ~/.tmux_SSH_history +set -g history-limit 100000 +set -s set-clipboard on +set -g display-time 3000 +set -g display-panes-time 3000 + +set -g pane-border-fg colour240 +set -g pane-active-border-fg colour250 +set -g pane-border-status top + +setw -g window-status-current-bg colour240 +setw -g window-status-current-fg colour250 +setw -g window-status-separator "|" +set -g status-bg colour235 +set -g status-fg colour245 + +# Use the user option set by script to display the host name, +# set two blanks if there are no flags set for fixed tab width +set -g window-status-format " #I #{@HOST} #{=-2:?window_flags, #{window_flags}, }" +set -g window-status-current-format " #I #{@HOST} #{=-2:?window_flags, #{window_flags}, }" +CMD="sh ~/.tmux/SSH.sh -r" + +# disable!!! 'cause tmux crashes if on and hook is set +set -g renumber-windows off +############################################################## +## if You use a tmux version which not supports hooks run +## the script hidden in the status +#set -g status-right-length 0 +#set -g status-right "#($CMD)" +#set -g status-interval 1 +############################################################## + +############################################################## +# I want to use hooks +set-hook -g 'after-join-pane' 'run "$CMD"' +set-hook -g 'after-move-pane' 'run "$CMD"' +set-hook -g 'after-break-pane' 'run "$CMD"' +set-hook -g 'after-select-pane' 'run "$CMD"' +set-hook -g 'pane-exited' 'run "$CMD"' +set-hook -g 'after-new-window' 'run "$CMD"' +set-hook -g 'after-split-window' 'run "$CMD"' +############################################################## + +# I prefer not to have a status for my tabbed term +set -g status-right "" +set -g status-right-length 0 +set -g status-left-length 0 +set -g status-left "" + +bind R source-file ~/.tmux/SSH.conf \; display-message "source-file done" + +# some settings for "navigation" +bind -n C-PageUp copy-mode -eu +unbind -n C-Left +unbind -n C-Right +bind -n C-Left select-window -t :- +bind -n C-Right select-window -t :+ + +# I prefer a tiled layout and easy joining of current active pane via windows' +# index +bind F1 join-pane -s 1.\; select-layout tiled +bind F2 join-pane -s 2.\; select-layout tiled +bind F3 join-pane -s 3.\; select-layout tiled +bind F4 join-pane -s 4.\; select-layout tiled +bind F5 join-pane -s 5.\; select-layout tiled +bind F6 join-pane -s 6.\; select-layout tiled +bind F7 join-pane -s 7.\; select-layout tiled +bind F8 join-pane -s 8.\; select-layout tiled +bind F9 join-pane -s 9.\; select-layout tiled diff --git a/SSH.sh b/SSH.sh new file mode 100644 index 0000000..4951323 --- /dev/null +++ b/SSH.sh @@ -0,0 +1,223 @@ +# Copyright (c) 2016 Uwe Werler +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +_sock="SSH" +_sess="SSH" +_tabw="15" # width of the tabs created + +# run tmux with some defaults like utf-8 support and at an separate socket +_tmux="tmux -2 -u -L ${_sock}" + +# set the variable "%#{pane_id}" in tmux environment to the hostname +_setenv="${_tmux} setenv -t ${_sess}" + +usage(){ + +echo \ + " +usage: /bin/sh $0 -cgsu [args] + -c : start server and connect xterm or attach term to detached session + -c args: start server and run ssh with args or start ssh and attach xterm + -r refresh all \"tabs\" with vals from active panes + -s %num value: set value to var %num + -u %num: unset var %num + + where %num is the pane ID. + + For usage from within shell create an alias like this: + alias ssh=\"sh ~/.tmux/SSH.sh -c\" + + For usage from within cwm put this in Your ~/.cwmrc: + command term \'ksh -c \". ~/.tmux/SSH.sh -c \$1\"\' + bind CM-Return xterm + #...and if autogroup preferred + autogroup 1 \"${_sess},XTerm\" + + If xdotool is installed it focusses automatically to the xterm running this + tmux session or reattaches a xterm if the session is detached. +" +exit 1 +} + +_checkname(){ + + # parse the output from ssh -G + for _l; do + + case $_l in hostname) + + # make stupid check if hostname is an IP + _ip=${2##+([0-9]).+([0-9]).+([0-9]).+([0-9])} + _ip=${_ip##+([0-9a-f]):+([0-9a-f]):+([0-9a-f]):*([0-9a-f:]):+([0-9a-f])} + + if [[ -z ${_ip} ]]; then + + _host=$(dig +short -x $2) + [[ -n "$_host" ]] && _host=${_host%%.*} || _host=$2 + else + + _host=${2%%.*} + fi + break + ;; + esac + + shift + done +} + +_runxdotool(){ + + # with xdotool installed, activate the window or reattach to a detached + # session + if type xdotool >/dev/null; then + + _winid="xdotool search --classname ${_sess}" + + [[ -z $(${_winid}) ]] && { xterm -title ${_sess} -name ${_sess} -e \ + $_tmux attach -t ${_sess} & sleep 0.5; } 2>/dev/null + + xdotool search --classname ${_sess} windowactivate + fi +} + +_setwin(){ + # get all environment variables and store them + for _var in $($_tmux show-env -t ${_sess}); do + + case $_var in + + %+([0-9a-f])*) + + _index=${_var%%=*} + # make a list of existing variables + INDEX="${INDEX} ${_index}" + _index=${_index##%} + _value=${_var##*=} + # make an array with values + VALS[$_index]=${_value} + ;; + esac + done + + $_tmux list-windows -F "#{window_id} #{pane_id} #{@HOST}" -t ${_sess} | { + + while read _winid _paneid _val; do + + _host=${VALS[${_paneid##%}]} + + [[ -z ${_host} ]] && _host=$(hostname -s) + + [[ ${_val} == ${_host} ]] || \ + $_tmux setw -q -t ${_winid} "@HOST" "$(printf %-${_tabw}.${_tabw}s ${_host})" + done + } + + for _pane in $($_tmux list-panes -s -t ${_sess} -F '#D'); do + + # make a list of all panes in session + CURPANES="${CURPANES} X${_pane}X" + done + + # compare environment with current panes and delete unused variables + for _pane in ${INDEX}; do + + [[ ${CURPANES} == *X${_pane}X* ]] || \ + $_setenv -ur ${_pane} + done + + # workaround as long as tmux crashes by setting "renumber-windows on" and hook + # "after-join-pane" or "after-move-pain" at the same time + $_tmux move-window -r -t ${_sess} + $_tmux refresh-client -S 2>/dev/null +} + +_ssh() { + + # remove string when invoked via cwm + [[ $1 == "[ssh]" ]] && shift + + if [[ -n $1 ]]; then + + # force a tty e.g. when running a command at the remote side like tmux ;) + _cmd="ssh -t $@" + + # let ssh parse the command line so we are sane + # avoid override the hostname via main config + _checkname $(unalias ssh; ssh -F /dev/null -G $@) + fi + + [[ $($_tmux list-session -F "#S" 2>/dev/null) == *${_sess}* ]] && _s=${_sess} + + # check if called from inside our tabbed tmux to avoid a new window + if [[ $TMUX == *${_sock}* && ${_s} == ${_sess} ]]; then + + trap "$_setenv -ur $TMUX_PANE; sh $0 -r" INT EXIT + + $_setenv $TMUX_PANE ${_host} + _setwin + $_cmd + exit + + elif [[ ${_s} == ${_sess} ]]; then + + [[ -z ${_cmd} ]] && _runxdotool && exit + + _paneid=$($_tmux new-window -P -t ${_sess} -F '#D' ${_cmd}) + $_setenv ${_paneid} ${_host} + _setwin + _runxdotool + else + + _paneid=$($_tmux -f ~/.tmux/SSH.conf new-session -P -d -F '#D' -s ${_sess} ${_cmd}) + + [[ -n ${_paneid} ]] || exit 1 + + [[ -n ${_host} ]] && $_setenv ${_paneid} ${_host} + _setwin + + xterm -title ${_sess} -name ${_sess} -e \ + $_tmux attach -t ${_sess} 2>/dev/null & + fi +} + +getopts ":s:u:cr" _opt +shift $((OPTIND-1)) + +case "$_opt" in + + c) + _ssh $OPTARG $@ + ;; + + r) + _setwin + exit 0 + ;; + + s) + [[ $OPTARG != %+([0-9]) ]] && usage + $_setenv $OPTARG $@ + ;; + + u) + [[ $OPTARG != %+([0-9]) ]] && usage + $_setenv -ur $OPTARG + ;; + + *) usage + ;; +esac + +#vim: set ai:ts=2:et:sw=2