Files
infra/dotfiles/desktop/.tmux/plugins/tmux-project/libexec/switch-project.bash
2026-03-31 19:00:15 +02:00

99 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
basedir="$(cd "$(dirname "$0")/.." && pwd)"
# shellcheck source=../lib/tmux.bash
. "$basedir/lib/tmux.bash"
find_projects() {
local -a base_dirs rooters rooter_opts
IFS=',' read -ra base_dirs < <(get_tmux_option '@project-base-dirs')
IFS=',' read -ra rooters < <(get_tmux_option '@project-rooters' '.git')
for rooter in "${rooters[@]}"; do
rooter_opts+=("-o" "-name" "$rooter")
done
rooter_opts=('(' "${rooter_opts[@]:1}" ')')
for base_dir in "${base_dirs[@]}"; do
# If the base_dir is empty, skip it
if [[ -z "$base_dir" ]]; then
continue
fi
local -a tmp
IFS=':' read -ra tmp <<<"$base_dir"
path="${tmp[0]}"
min_depth="${tmp[1]:-0}"
max_depth="${tmp[2]:-${min_depth}}"
if [[ min_depth -eq 0 && max_depth -eq 0 ]]; then
# If min_depth and max_depth are both 0, that means we
# want to add the base_dir itself as a project.
# In that case, add the base_dir as a project even if it
# contains no rooter.
if [[ -d "$path" || -L "$path" ]]; then
echo "$path"
fi
else
find "$path" -mindepth "$((min_depth + 1))" \
-maxdepth "$((max_depth + 1))" \
"${rooter_opts[@]}" \
-printf '%h\n'
fi
done
}
# Convert a path to a session name. The session name is the last component of
# the path. Dots are replaced with underscores. If the path starts with a dot,
# the dot is removed.
# e.g. /home/username/.emacs.d -> emacs_d
to_session_name() {
local session_name="$1"
session_name="${session_name##*/}"
# Dots are not allowed in a tmux session name
# e.g. .emacs.d -> _emacs_d
session_name="${session_name//./_}"
# If the path starts with a slash (a dot), remove it
# e.g. .emacs.d -> _emacs_d -> emacs_d
session_name="${session_name#_}"
echo "$session_name"
}
main() {
local fzf_opts fzf_tmux_layout_opts selected_path session_name
# shellcheck disable=SC2207
fzf_opts="$(get_tmux_option "@project-fzf-opts" "--preview 'ls {}'")"
# shellcheck disable=SC2207
fzf_tmux_layout_opts="$(get_tmux_option "@project-fzf-tmux-layout-opts")"
selected_path="$(find_projects | eval "fzf-tmux ${fzf_tmux_layout_opts} -- ${fzf_opts}")"
if [[ -z "$selected_path" ]]; then
return 0
fi
# If the selected project has .tmuxinator.yml file, use tmuxinator to
# start the session.
if command -v tmuxinator &>/dev/null && [[ -f "${selected_path}/.tmuxinator.yml" ]]; then
tmuxinator start -p "${selected_path}/.tmuxinator.yml"
return 0
fi
session_name="$(to_session_name "$selected_path")"
# If the session already exists, attach to it. Otherwise, create a new
# session and attach to it.
if ! tmux has-session -t "$session_name" 2>/dev/null; then
# Return 0 even if creating the session fails.
tmux new-session -d -s "$session_name" -c "$selected_path" \; \
set -t "$session_name" destroy-unattached off || :
fi
tmux switch-client -t "$session_name"
}
main "$@"