From ed8743facb6e04d7b7f2d0d7146bda65810015c9 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 22 Apr 2012 11:28:38 +0100 Subject: [PATCH] Initial commit --- bin/tmuxifier | 31 +++++++ completion/tmuxifier.bash | 14 +++ completion/tmuxifier.zsh | 19 ++++ env.sh | 6 ++ init.sh | 22 +++++ libexec/tmuxifier-commands | 13 +++ libexec/tmuxifier-completions | 15 +++ libexec/tmuxifier-current-session | 14 +++ libexec/tmuxifier-list | 11 +++ libexec/tmuxifier-list-sessions | 9 ++ libexec/tmuxifier-list-windows | 9 ++ libexec/tmuxifier-session | 16 ++++ libexec/tmuxifier-window | 22 +++++ runtime.sh | 147 ++++++++++++++++++++++++++++++ 14 files changed, 348 insertions(+) create mode 100755 bin/tmuxifier create mode 100644 completion/tmuxifier.bash create mode 100644 completion/tmuxifier.zsh create mode 100644 env.sh create mode 100644 init.sh create mode 100755 libexec/tmuxifier-commands create mode 100755 libexec/tmuxifier-completions create mode 100755 libexec/tmuxifier-current-session create mode 100755 libexec/tmuxifier-list create mode 100755 libexec/tmuxifier-list-sessions create mode 100755 libexec/tmuxifier-list-windows create mode 100755 libexec/tmuxifier-session create mode 100755 libexec/tmuxifier-window create mode 100644 runtime.sh diff --git a/bin/tmuxifier b/bin/tmuxifier new file mode 100755 index 0000000..2cfaf33 --- /dev/null +++ b/bin/tmuxifier @@ -0,0 +1,31 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +if [ -z "${TMUXIFIER}" ]; then + export TMUXIFIER="${HOME}/.tmuxifier" +else + export TMUXIFIER="${TMUXIFIER%/}" +fi + +# Load tmuxifier environment variables. +source "$TMUXIFIER/env.sh" + +export PATH="$TMUXIFIER/libexec:$PATH" + +command="$1" +case "$command" in + "" | "-h" | "--help" | "help" ) + echo "[ put help message here ]" + ;; + * ) + command_path="$(command -v "tmuxifier-$command" || true)" + if [ -z $command_path ]; then + echo "tmuxifier: no such command '$command'" >&2 + exit 1 + fi + + shift 1 + exec "$command_path" "$@" + ;; +esac diff --git a/completion/tmuxifier.bash b/completion/tmuxifier.bash new file mode 100644 index 0000000..6d26e40 --- /dev/null +++ b/completion/tmuxifier.bash @@ -0,0 +1,14 @@ +_tmuxifier() { + COMPREPLY=() + local word="${COMP_WORDS[COMP_CWORD]}" + + if [ "$COMP_CWORD" -eq 1 ]; then + COMPREPLY=( $(compgen -W "$(tmuxifier commands)" -- "$word") ) + else + local command="${COMP_WORDS[1]}" + local completions="$(tmuxifier completions "$command")" + COMPREPLY=( $(compgen -W "$completions" -- "$word") ) + fi +} + +complete -F _tmuxifier tmuxifier diff --git a/completion/tmuxifier.zsh b/completion/tmuxifier.zsh new file mode 100644 index 0000000..765a2d8 --- /dev/null +++ b/completion/tmuxifier.zsh @@ -0,0 +1,19 @@ +if [[ ! -o interactive ]]; then + return +fi + +compctl -K _tmuxifier tmuxifier + +_tmuxifier() { + local word words completions + read -cA words + word="${words[2]}" + + if [ "${#words}" -eq 2 ]; then + completions="$(tmuxifier commands)" + else + completions="$(tmuxifier completions "${word}")" + fi + + reply=("${(ps:\n:)completions}") +} diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..73d50e1 --- /dev/null +++ b/env.sh @@ -0,0 +1,6 @@ +# Setup layout path. +if [ -z "${TMUXIFIER_LAYOUT_PATH}" ]; then + export TMUXIFIER_LAYOUT_PATH="${TMUXIFIER}/layouts" +else + export TMUXIFIER_LAYOUT_PATH="${TMUXIFIER_LAYOUT_PATH%/}" +fi diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..de9ee2a --- /dev/null +++ b/init.sh @@ -0,0 +1,22 @@ +# Set tmuxifier root path. +if [ -z "${TMUXIFIER}" ]; then + export TMUXIFIER="${HOME}/.tmuxifier" +else + export TMUXIFIER="${TMUXIFIER%/}" +fi + +# Load tmuxifier environment variables. +source "$TMUXIFIER/env.sh" + +# Add `bin` directroy to `$PATH`. +export PATH="$TMUXIFIER/bin:$PATH" + +# If `tmuxifier` is available, and `$TMUXIFIER_NO_COMPLETE` is not set, then +# load tmuxifier shell completion. +if [ ! -z $(command -v "tmuxifier") ] && [ -z "$TMUXIFIER_NO_COMPLETE" ]; then + if [ -n "$BASH_VERSION" ]; then + source "$TMUXIFIER/completion/tmuxifier.bash" + elif [ -n "$ZSH_VERSION" ]; then + source "$TMUXIFIER/completion/tmuxifier.zsh" + fi +fi diff --git a/libexec/tmuxifier-commands b/libexec/tmuxifier-commands new file mode 100755 index 0000000..c2b374e --- /dev/null +++ b/libexec/tmuxifier-commands @@ -0,0 +1,13 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +shopt -s nullglob + +{ for path in ${PATH//:/$'\n'}; do + for command in "${path}/tmuxifier-"*; do + command="${command##*tmuxifier-}" + echo ${command##sh-} + done + done +} | sort | uniq diff --git a/libexec/tmuxifier-completions b/libexec/tmuxifier-completions new file mode 100755 index 0000000..9d604d8 --- /dev/null +++ b/libexec/tmuxifier-completions @@ -0,0 +1,15 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +command="$1" +if [ -z "$command" ]; then + echo "Usage: tmuxifier completions COMMAND [arg1 arg2...]" >&2 + exit 1 +fi + +command_path="$(command -v "tmuxifier-$command")" +if grep -i "^# provide tmuxifier completions" "$command_path" >/dev/null; then + shift + exec "$command_path" --complete "$@" +fi diff --git a/libexec/tmuxifier-current-session b/libexec/tmuxifier-current-session new file mode 100755 index 0000000..c9cb465 --- /dev/null +++ b/libexec/tmuxifier-current-session @@ -0,0 +1,14 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +if [ ! -z $TMUX ]; then + for item in $(tmux list-sessions -F "#{?session_attached,1,0}:#S"); do + if [[ "$item" == "1:"* ]]; then + echo ${item/1:/} + exit 0 + fi + done +fi + +exit 1 diff --git a/libexec/tmuxifier-list b/libexec/tmuxifier-list new file mode 100755 index 0000000..dcfbe4b --- /dev/null +++ b/libexec/tmuxifier-list @@ -0,0 +1,11 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +echo "" +echo "Sessions:" +tmuxifier-list-sessions +echo "" +echo "Windows:" +tmuxifier-list-windows +echo "" diff --git a/libexec/tmuxifier-list-sessions b/libexec/tmuxifier-list-sessions new file mode 100755 index 0000000..02249aa --- /dev/null +++ b/libexec/tmuxifier-list-sessions @@ -0,0 +1,9 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +list=$(find "$TMUXIFIER_LAYOUT_PATH" -name "*.session.sh") +for file in $list; do + file=${file/$TMUXIFIER_LAYOUT_PATH\//} + echo " ${file/.session.sh/}" +done diff --git a/libexec/tmuxifier-list-windows b/libexec/tmuxifier-list-windows new file mode 100755 index 0000000..bd96ed1 --- /dev/null +++ b/libexec/tmuxifier-list-windows @@ -0,0 +1,9 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +list=$(find "$TMUXIFIER_LAYOUT_PATH" -name "*.window.sh") +for file in $list; do + file=${file/$TMUXIFIER_LAYOUT_PATH\//} + echo " ${file/.window.sh/}" +done diff --git a/libexec/tmuxifier-session b/libexec/tmuxifier-session new file mode 100755 index 0000000..a82c0f8 --- /dev/null +++ b/libexec/tmuxifier-session @@ -0,0 +1,16 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +# Provide tmuxifier completions +if [ "$1" == "--complete" ]; then + for item in $(tmuxifier-list-sessions); do + echo "$item" + done + exit +fi + +# Load runtime functions. +source "$TMUXIFIER/runtime.sh" + +load_session "$1" diff --git a/libexec/tmuxifier-window b/libexec/tmuxifier-window new file mode 100755 index 0000000..e3c59b8 --- /dev/null +++ b/libexec/tmuxifier-window @@ -0,0 +1,22 @@ +#! /usr/bin/env bash +set -e +[ -n "$TMUXIFIER_DEBUG" ] && set -x + +# Provide tmuxifier completions +if [ "$1" == "--complete" ]; then + for item in $(tmuxifier-list-windows); do + echo "$item" + done + exit +fi + +# Load runtime functions. +source "$TMUXIFIER/runtime.sh" + +if [ ! -z $TMUX ]; then + session="$(tmuxifier-current-session)" + load_window "$1" +else + echo "ERROR: 'window' command can only be used from within Tmux." + exit 1 +fi diff --git a/runtime.sh b/runtime.sh new file mode 100644 index 0000000..d1501b7 --- /dev/null +++ b/runtime.sh @@ -0,0 +1,147 @@ +# Load tmuxifier environment. +source "$TMUXIFIER/env.sh" + +# +# Defaults +# + +session_root="$HOME" + + +# +# Layout Helpers +# +# These functions are available exclusively within layout files, and enable +# the layout files to function at all, but also provide useful short-hands to +# otherwise more complex means. + +# Load specified window layout. +load_window() { + local file="$TMUXIFIER_LAYOUT_PATH/$1.window.sh" + if [ -f "$file" ]; then + window="$1" + source "$file" + + # Reset `$window_root`. + if [[ "$window_root" != "$session_root" ]]; then + window_root "$session_root" + fi + fi +} + +# Load specified session layout. +load_session() { + local file="$TMUXIFIER_LAYOUT_PATH/$1.session.sh" + if [ -f "$file" ]; then + session="$1" + source "$file" + + # Reset `$session_root`. + if [[ "$session_root" != "$HOME" ]]; then + session_root="$HOME" + fi + fi +} + +# Customize session name. Default is based on the session layout filename. +session_name() { + session="$1" +} + +# Cusomize session root path. Default is `$HOME`. +session_root() { + local dir="$(__expand_path $@)" + if [ -d "$dir" ]; then + session_root="$dir" + fi +} + +# Customize window name. Default is based on the window layout filename. +window_name() { + window="$1" +} + +# Customize window root path. Default is `$session_root`. +window_root() { + local dir="$(__expand_path $@)" + if [ -d "$dir" ]; then + cd "$dir" + fi +} + +# Create a new session, returning 0 on success, 1 on failure. +# +# Example usage: +# +# if initialize_session; then +# load_window "example" +# fi +# +initialize_session() { + # Ensure tmux server is running for has-session check. + tmux start-server + + # Check if the named session already exists. + if ! tmux has-session -t "$session" 2>/dev/null; then + # Create the new session. + env TMUX= tmux new-session -d -s "$session" + + # Set default-path for session + if [ ! -z "$session_root" ] && [ -d "$session_root" ]; then + tmux set-option -t "$session" default-path "$session_root" 1>/dev/null + fi + + # In order to ensure only specified windows are created, we move the + # default window to position 99, and later remove it with the + # `finalize_session` function. + tmux move-window -s "$session:0" -t "$session:99" + + # Ensure correct pane splitting. + __go_to_session + + # Session created, return ok exit status. + return 0 + fi + # Session already existed, return error exit status. + return 1 +} + +# Finalize session creation and then switch to it if needed. +# +# When the session is created, it leaves a unused window in position #99, this +# is the default window which was created with the session, but it's also a +# window that was not explicitly created. Hence we kill it. +# +# If the session was created, we've already been switched to it. If it was not +# created, the session already exists, and we'll need to specifically switch +# to it here. +finalize_and_go_to_session() { + tmux kill-window -t "$session:99" 2>/dev/null + if [[ "$(tmuxifier-current-session)" != "$session" ]]; then + __go_to_session + fi +} + + +# +# Internal functions +# + +# Expands given path. +# +# Example: +# +# $ __expand_path ~/Projects +# /Users/jimeh/Projects +# +__expand_path() { + echo $(eval echo "$@") +} + +__go_to_session() { + if [ -z $TMUX ]; then + tmux -u attach-sessions -t "$session" + else + tmux -u switch-client -t "$session" + fi +}