Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A fuzzy Tmux session manager with preview capabilities, deleting, renaming and m
- [fzf-tmux](https://github.com/junegunn/fzf#fzf-tmux-script)
- [bat](https://github.com/sharkdp/bat)
- Optional: [zoxide](https://github.com/ajeetdsouza/zoxide)
- Optional: [tmuxinator](https://github.com/tmuxinator/tmuxinator)

## Install 💻

Expand All @@ -30,7 +31,7 @@ You can change it by adding this line with your desired key:
set -g @sessionx-bind '<mykey>'
```

### Additional configuration options:
### Additional configuration options

```bash
# By default, tmux `<prefix>` key needs to pressed before `<mykey>` to launch
Expand Down Expand Up @@ -114,6 +115,12 @@ set -g @sessionx-legacy-fzf-support 'on'
# If found, it'll launch the template using tmuxinator
set -g @sessionx-tmuxinator-mode 'off'

# When set to on, with a tmuxinator/default.yml existing, entering a session name
# which doesnt exist will launch a fzf-tmux window in home directory to allow you
# to select a directory to launch new session in
# While selecting directory tab traverses deeper into subdirectories
set -g @sessionx-dir-select 'on'

# Turn on fzf-marks (default: off) mode to launch a new session from your marks
set -g @sessionx-fzf-marks-mode 'off'

Expand Down Expand Up @@ -144,7 +151,7 @@ If you insert a non-existing name and hit enter, a new session with that name wi
- `Ctrl-g` "fzf-marks": show fzf-marks marks
- `?` toggles the preview pane

### Rebind keys:
### Rebind keys

If you want to change the default key bindings, you can do using this configuration options:

Expand Down Expand Up @@ -252,10 +259,10 @@ set -g @sessionx-bind-fzf-marks 'alt-g'

Inspired by these:

- https://github.com/joshmedeski/t-smart-tmux-session-manager
- https://github.com/ThePrimeagen/.dotfiles/blob/master/bin/.local/scripts/tmux-sessionizer
- https://crates.io/crates/tmux-sessionizer
- https://github.com/petobens/dotfiles/commit/c21c306660142d93d283186210ad9d301a2f5186
- <https://github.com/joshmedeski/t-smart-tmux-session-manager>
- <https://github.com/ThePrimeagen/.dotfiles/blob/master/bin/.local/scripts/tmux-sessionizer>
- <https://crates.io/crates/tmux-sessionizer>
- <https://github.com/petobens/dotfiles/commit/c21c306660142d93d283186210ad9d301a2f5186>

## Contributors

Expand Down
240 changes: 132 additions & 108 deletions scripts/sessionx.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,132 +8,156 @@ source "$CURRENT_DIR/tmuxinator.sh"
source "$CURRENT_DIR/fzf-marks.sh"

get_sorted_sessions() {
last_session=$(tmux display-message -p '#{client_last_session}')
sessions=$(tmux list-sessions | sed -E 's/:.*$//' | grep -v "^$last_session$")
filtered_sessios=${extra_options["filtered-sessions"]}
if [[ -n "$filtered_sessios" ]]; then
filtered_and_piped=$(echo "$filtered_sessios" | sed -E 's/,/|/g')
sessions=$(echo "$sessions" | grep -Ev "$filtered_and_piped")
fi
echo -e "$sessions\n$last_session" | awk '!seen[$0]++'
last_session=$(tmux display-message -p '#{client_last_session}')
sessions=$(tmux list-sessions | sed -E 's/:.*$//' | grep -v "^$last_session$")
filtered_sessios=${extra_options["filtered-sessions"]}
if [[ -n "$filtered_sessios" ]]; then
filtered_and_piped=$(echo "$filtered_sessios" | sed -E 's/,/|/g')
sessions=$(echo "$sessions" | grep -Ev "$filtered_and_piped")
fi
echo -e "$sessions\n$last_session" | awk '!seen[$0]++'
}

tmux_option_or_fallback() {
local option_value
option_value="$(tmux show-option -gqv "$1")"
if [ -z "$option_value" ]; then
option_value="$2"
fi
echo "$option_value"
local option_value
option_value="$(tmux show-option -gqv "$1")"
if [ -z "$option_value" ]; then
option_value="$2"
fi
echo "$option_value"
}

input() {
default_window_mode=${extra_options["window-mode"]}
if [[ "$default_window_mode" == "on" ]]; then
tmux list-windows -a -F '#{session_name}:#{window_index} #{window_name}'
else
filter_current_session=${extra_options["filter-current"]}
if [[ "$filter_current_session" == "true" ]]; then
(get_sorted_sessions | grep -v "$CURRENT$") || echo "$CURRENT"
else
(get_sorted_sessions) || echo "$CURRENT"
fi
fi
default_window_mode=${extra_options["window-mode"]}
if [[ "$default_window_mode" == "on" ]]; then
tmux list-windows -a -F '#{session_name}:#{window_index} #{window_name}'
else
filter_current_session=${extra_options["filter-current"]}
if [[ "$filter_current_session" == "true" ]]; then
(get_sorted_sessions | grep -v "$CURRENT$") || echo "$CURRENT"
else
(get_sorted_sessions) || echo "$CURRENT"
fi
fi
}

additional_input() {
sessions=$(get_sorted_sessions)
custom_paths=${extra_options["custom-paths"]}
custom_path_subdirectories=${extra_options["custom-paths-subdirectories"]}
if [[ -z "$custom_paths" ]]; then
echo ""
else
clean_paths=$(echo "$custom_paths" | sed -E 's/ *, */,/g' | sed -E 's/^ *//' | sed -E 's/ *$//' | sed -E 's/ /✗/g')
if [[ "$custom_path_subdirectories" == "true" ]]; then
paths=$(find ${clean_paths//,/ } -mindepth 1 -maxdepth 1 -type d)
else
paths=${clean_paths//,/ }
fi
add_path() {
local path=$1
if ! grep -q "$(basename "$path")" <<< "$sessions"; then
echo "$path"
fi
}
export -f add_path
printf "%s\n" "${paths//,/$IFS}" | xargs -n 1 -P 0 bash -c 'add_path "$@"' _
fi
sessions=$(get_sorted_sessions)
custom_paths=${extra_options["custom-paths"]}
custom_path_subdirectories=${extra_options["custom-paths-subdirectories"]}
if [[ -z "$custom_paths" ]]; then
echo ""
else
clean_paths=$(echo "$custom_paths" | sed -E 's/ *, */,/g' | sed -E 's/^ *//' | sed -E 's/ *$//' | sed -E 's/ /✗/g')
if [[ "$custom_path_subdirectories" == "true" ]]; then
paths=$(find ${clean_paths//,/ } -mindepth 1 -maxdepth 1 -type d)
else
paths=${clean_paths//,/ }
fi
add_path() {
local path=$1
if ! grep -q "$(basename "$path")" <<<"$sessions"; then
echo "$path"
fi
}
export -f add_path
printf "%s\n" "${paths//,/$IFS}" | xargs -n 1 -P 0 bash -c 'add_path "$@"' _
fi
}

handle_output() {
if [ -d "$*" ]; then
# No special handling because there isn't a window number or window name present
# except in unlikely and contrived situations (e.g.
# "/home/person/projects:0\ bash" could be a path on your filesystem.)
target=$(echo "$@" | tr -d '\n')
elif is_fzf-marks_mark "$@" ; then
# Needs to run before session name mode
mark=$(get_fzf-marks_mark "$@")
target=$(get_fzf-marks_target "$@")
elif echo "$@" | grep ':' >/dev/null 2>&1; then
# Colon probably delimits session name and window number
session_name=$(echo "$@" | cut -d: -f1)
num=$(echo "$@" | cut -d: -f2 | cut -d' ' -f1)
target=$(echo "${session_name}:${num}" | tr -d '\n')
else
# All tokens represent a session name
target=$(echo "$@" | tr -d '\n')
fi

if [[ -z "$target" ]]; then
exit 0
fi

if ! tmux has-session -t="$target" 2>/dev/null; then
if is_tmuxinator_enabled && is_tmuxinator_template "$target"; then
tmuxinator start "$target"
elif test -n "$mark"; then
tmux new-session -ds "$mark" -c "$target"
target="$mark"
elif test -d "$target"; then
d_target="$(basename "$target" | tr -d '.')"
tmux new-session -ds $d_target -c "$target"
target=$d_target
else
if [[ "$Z_MODE" == "on" ]]; then
z_target=$(zoxide query "$target")
tmux new-session -ds "$target" -c "$z_target" -n "$z_target"
else
tmux new-session -ds "$target"
fi
fi
fi
tmux switch-client -t "$target"

exit 0
if [ -d "$*" ]; then
# No special handling because there isn't a window number or window name present
# except in unlikely and contrived situations (e.g.
# "/home/person/projects:0\ bash" could be a path on your filesystem.)
target=$(echo "$@" | tr -d '\n')
elif is_fzf-marks_mark "$@"; then
# Needs to run before session name mode
mark=$(get_fzf-marks_mark "$@")
target=$(get_fzf-marks_target "$@")
elif echo "$@" | grep ':' >/dev/null 2>&1; then
# Colon probably delimits session name and window number
session_name=$(echo "$@" | cut -d: -f1)
num=$(echo "$@" | cut -d: -f2 | cut -d' ' -f1)
target=$(echo "${session_name}:${num}" | tr -d '\n')
else
# All tokens represent a session name
session_name=$(echo "$@" | tr -d '\n')

directory_selector=$(tmux_option_or_fallback "@sessionx-dir-select" "off")

if [[ -n "$session_name" ]] && ! tmux has-session -t="$session_name" 2>/dev/null; then
if [[ "$directory_selector" == "on" ]]; then

directory=$(find ~ -mindepth 1 -maxdepth 1 -type d | fzf-tmux -p 80%,80% \
--preview 'ls -la {}' \
--preview-window=right:30% \
--header "Select directory for ${session_name}" \
--bind "tab:reload(find {} -mindepth 1 -maxdepth 1 -type d 2>/dev/null)+down")

fzf_status=$?
if [[ $fzf_status -eq 130 ]] || [[ $fzf_status -eq 1 ]]; then
exit 0
fi

if [[ -n "directory" ]]; then
tmuxinator start default "$session_name" "$directory"
exit 0
fi
fi
fi
target=$session_name
fi

if [[ -z "$target" ]]; then
exit 0
fi

if ! tmux has-session -t="$target" 2>/dev/null; then
if is_tmuxinator_enabled && is_tmuxinator_template "$target"; then
tmuxinator start "$target"
elif test -n "$mark"; then
tmux new-session -ds "$mark" -c "$target"
target="$mark"
elif test -d "$target"; then
d_target="$(basename "$target" | tr -d '.')"
tmux new-session -ds $d_target -c "$target"
target=$d_target
else
if [[ "$Z_MODE" == "on" ]]; then
z_target=$(zoxide query "$target")
tmux new-session -ds "$target" -c "$z_target" -n "$z_target"
else
tmux new-session -ds "$target"
fi
fi
fi
tmux switch-client -t "$target"

exit 0
}

handle_input() {
INPUT=$(input)
ADDITIONAL_INPUT=$(additional_input)
if [[ -n $ADDITIONAL_INPUT ]]; then
INPUT="$(additional_input)\n$INPUT"
fi
bind_back=${extra_options["bind-back"]}
BACK="$bind_back:reload(echo -e \"${INPUT// /}\")+change-preview(${TMUX_PLUGIN_MANAGER_PATH%/}/tmux-sessionx/scripts/preview.sh {1})"
INPUT=$(input)
ADDITIONAL_INPUT=$(additional_input)
if [[ -n $ADDITIONAL_INPUT ]]; then
INPUT="$(additional_input)\n$INPUT"
fi
bind_back=${extra_options["bind-back"]}
BACK="$bind_back:reload(echo -e \"${INPUT// /}\")+change-preview(${TMUX_PLUGIN_MANAGER_PATH%/}/tmux-sessionx/scripts/preview.sh {1})"
}

run_plugin() {
eval $(tmux show-option -gqv @sessionx-_built-args)
eval $(tmux show-option -gqv @sessionx-_built-extra-options)
handle_input
args+=(--bind "$BACK")

if [[ "$FZF_BUILTIN_TMUX" == "on" ]]; then
RESULT=$(echo -e "${INPUT}" | sed -E 's/✗/ /g' | fzf "${fzf_opts[@]}" "${args[@]}" | tail -n1)
else
RESULT=$(echo -e "${INPUT}" | sed -E 's/✗/ /g' | fzf-tmux "${fzf_opts[@]}" "${args[@]}" | tail -n1)
fi
eval $(tmux show-option -gqv @sessionx-_built-args)
eval $(tmux show-option -gqv @sessionx-_built-extra-options)
handle_input
args+=(--bind "$BACK")

if [[ "$FZF_BUILTIN_TMUX" == "on" ]]; then
RESULT=$(echo -e "${INPUT}" | sed -E 's/✗/ /g' | fzf "${fzf_opts[@]}" "${args[@]}" | tail -n1)
else
RESULT=$(echo -e "${INPUT}" | sed -E 's/✗/ /g' | fzf-tmux "${fzf_opts[@]}" "${args[@]}" | tail -n1)
fi
}

run_plugin
Expand Down