#!/usr/bin/env bash # # Credit to ThePrimeagen, Jess Archer # See https://github.com/jessarcher/dotfiles/blob/master/scripts/t # # Tweaks by Ismo Vuorinen 2025 # vim: ft=bash ts=2 sw=2 et # Set environment variables for configuration with defaults T_ROOT="${T_ROOT:-$HOME/Code}" DOTFILES="${DOTFILES:-$HOME/.dotfiles}" T_MAX_DEPTH="${T_MAX_DEPTH:-3}" # Function to print an error message and exit error_exit() { echo "Error: $1" >&2 exit 1 } # Validate that T_ROOT exists if [[ ! -d "$T_ROOT" ]]; then error_exit "T_ROOT directory '$T_ROOT' does not exist." fi # Check for required dependencies check_dependencies() { local T_DEPS=(tmux fzf find) for cmd in "${T_DEPS[@]}"; do if ! command -v "$cmd" &> /dev/null; then error_exit "$cmd is not installed." fi done } check_dependencies # Generate an array of '-not -path' rules for each exclusion pattern # without using namerefs. generate_exclude_rules() { local result_var="$1" shift local arr=() for pattern in "$@"; do # Exclude both the directory and any subdirectories under it. arr+=(-not -path "*/${pattern}" -not -path "*/${pattern}/*") done # Use eval to assign the array to the variable whose name was passed. eval "$result_var=(\"\${arr[@]}\")" } get_directories() { local exclude_patterns=( ".bzr" ".git" ".hg" ".idea" ".obsidian" ".run" ".svn" ".vscode" "build" "dist" "node_modules" "out" "target" "vendor" ) local exclude_rules=() generate_exclude_rules exclude_rules "${exclude_patterns[@]}" local dirs # Use $'string' to correctly process escape sequences. dirs=$'# Directories\n' dirs+=$( find "$T_ROOT" \ -maxdepth "$T_MAX_DEPTH" \ -mindepth 1 \ -type d \ "${exclude_rules[@]}" ) echo -e "$dirs" } check_tmux() { if ! command -v tmux &> /dev/null; then error_exit "tmux is not installed." fi # Ensure tmux server is running if ! tmux info &> /dev/null; then tmux start-server fi } get_sessions() { check_tmux T_TMUX_SESSIONS=$(tmux list-sessions -F "#{session_name}" 2> /dev/null) if [[ -z "$T_TMUX_SESSIONS" ]]; then echo "" return fi echo -e "# Sessions\n$T_TMUX_SESSIONS" } # Determine selection from command-line argument or interactive fzf menu if [[ $# -eq 1 ]]; then selected="$1" else # Combine sessions and directories for selection T_ITEMS="$(get_sessions | sort) $(get_directories | sort)" # Use sort to order the entries and fzf for interactive selection selected=$(echo "$T_ITEMS" | fzf) || exit 0 fi # Reject selection if it is a header line [[ ${selected:0:1} == "#" ]] && error_exit "Header selected. Please choose a valid session or directory." [[ -z "$selected" ]] && error_exit "No directory or session selected." # Sanitize the session name session_name=$(basename "$selected") if [[ -z "$session_name" ]]; then session_name="$selected" fi # Remove dots since tmux dislikes them session_name="${session_name//./}" # Attempt to switch to an existing session tmux switch-client -t "=$session_name" 2> /dev/null active_session=$(tmux display-message -p -F '#{session_name}' 2> /dev/null) if [[ "$active_session" == "$session_name" ]]; then exit 0 fi # Create a new session (or attach to an existing one) based on the selection if [ -z "$TMUX" ]; then # Not inside tmux: create (or attach to) the session and attach. tmux new-session -A -s "$session_name" -c "$selected" else # Inside tmux: check if the target session exists. if tmux has-session -t "$session_name" 2> /dev/null; then # Session exists; switch to it. tmux switch-client -t "$session_name" else # Session does not exist; create it in detached mode and then switch. tmux new-session -d -s "$session_name" -c "$selected" tmux switch-client -t "$session_name" fi fi