aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rwxr-xr-xtmux/.local/bin/previewer.sh114
-rwxr-xr-xtmux/.local/bin/timestamp.sh143
-rwxr-xr-xtmux/.local/bin/tmux-sessionizer69
3 files changed, 268 insertions, 58 deletions
diff --git a/tmux/.local/bin/previewer.sh b/tmux/.local/bin/previewer.sh
new file mode 100755
index 0000000..d064a09
--- /dev/null
+++ b/tmux/.local/bin/previewer.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+# shellcheck disable=2046
+
+SCRIPT="$(basename "$0")"
+
+long='remote,verbose,help'
+short='rvh'
+
+if ! opts="$(getopt -o $short -l $long -n "$SCRIPT" -- "$@")"; then
+ exit 1
+fi
+
+eval set -- "$opts"
+
+help() {
+ cat <<-EOF
+ $SCRIPT
+ Toby Vincent <tobyv13@gmail.com>
+
+ $SCRIPT
+ Shows preview of a directory. Designed to be used with fzf's '--preview'.
+
+ USAGE:
+ $SCRIPT [OPTION ...] <PATH> [PATH ...]
+
+ OPTIONS:
+ -r, --remote Treat path as a remote repository
+ -v, --verbose Increase verbosity
+ -h, --help Show this help
+ EOF
+}
+
+say() {
+ printf "%s: %s\n" "$SCRIPT" "$@"
+}
+
+say_verbose() {
+ if [ "$verbose" -gt "0" ]; then
+ say "$@"
+ fi
+}
+
+say_err() {
+ say "$@" >&2
+}
+
+err() {
+ err_dir="$1"
+ shift
+ say_err "cannot preview '$err_dir': $*"
+ exit 1
+}
+
+err_help() {
+ help
+ err "$*"
+}
+
+verbose=0
+remote=false
+width=$(((($(tput cols) * 3) + (4 - 1)) / 4))
+while true; do
+ case "$1" in
+ -h | --help)
+ help
+ exit 0
+ ;;
+ -v | --verbose)
+ verbose=$((verbose + 1))
+ shift
+ ;;
+ -r | --remote)
+ remote=true
+ shift
+ ;;
+ -w | --width)
+ width=$2
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ err_help "Invalid argument: $1"
+ ;;
+ esac
+done
+
+show_logo="always"
+if [ "$width" -lt 80 ]; then
+ show_logo="never"
+fi
+
+if [ "$#" -eq 0 ]; then
+ IFS='
+'
+ set -o noglob
+ set -- $(cat)
+fi
+
+while [ $# -gt 0 ]; do
+ if $remote; then
+ hut git show --repo "$1" 2>/dev/null ||
+ gh repo view "$1" 2>/dev/null ||
+ err "$1" "Failed to find remote repository"
+ else
+ onefetch --hidden --show-logo="$show_logo" "$1" 2>/dev/null ||
+ ([ -e "$1"/README.md ] && glow --local --style=dark "$1"/README.md) 2>/dev/null ||
+ exa --tree --git-ignore --level=3 --icons "$1" 2>/dev/null ||
+ err "$1" "Failed to preview directory"
+ fi
+ shift
+done
diff --git a/tmux/.local/bin/timestamp.sh b/tmux/.local/bin/timestamp.sh
new file mode 100755
index 0000000..752c1a5
--- /dev/null
+++ b/tmux/.local/bin/timestamp.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+# shellcheck disable=2046
+
+SCRIPT="$(basename "$0")"
+
+long='git,sessions::,format:,verbose,help'
+short='gs::f:vh'
+
+if ! opts="$(getopt -o $short -l $long -n "$SCRIPT" -- "$@")"; then
+ exit 1
+fi
+
+eval set -- "$opts"
+
+help() {
+ cat <<-EOF
+ $SCRIPT
+ Toby Vincent <tobyv13@gmail.com>
+
+ $SCRIPT
+ Get a timestamp for a given directory using multiple activity sources. By default, uses stat.
+
+ USAGE:
+ $SCRIPT [OPTION ...] <PATH> [PATH ...]
+
+ OPTIONS:
+ -g, --git Check last git commit for timestamp
+ -s, --sessions=[PATH] Check nvim sessions directory for existing session files.
+ (DEFAULT="$XDG_DATA_HOME/nvim/sessions")
+
+ -f, --format=<FORMAT> Format string for output. '{}' will be replaced directory
+ timestamp and '{1}' will be replaced directory path
+
+ -v, --verbose Increase verbosity
+ -h, --help Show this help
+ EOF
+}
+
+say() {
+ printf "%s: %s\n" "$SCRIPT" "$@"
+}
+
+say_verbose() {
+ if [ "$verbose" -gt "0" ]; then
+ say "$@"
+ fi
+}
+
+say_err() {
+ say "$@" >&2
+}
+
+err() {
+ err_dir="$1"
+ shift
+ say_err "cannot timestamp '$err_dir': $*"
+ exit 1
+}
+err_help() {
+ help
+ err "$*"
+}
+
+verbose=0
+git=false
+sessions=false
+sessions_dir="$XDG_DATA_HOME/nvim/sessions"
+format="{}"
+while true; do
+ case "$1" in
+ -h | --help)
+ help
+ exit 0
+ ;;
+ -v | --verbose)
+ verbose=$((verbose + 1))
+ shift
+ ;;
+ -e | --git)
+ git=true
+ shift
+ ;;
+ -s | --sessions)
+ sessions=true
+ if [ -n "$2" ]; then
+ sessions_dir="$2"
+ fi
+ shift 2
+ ;;
+ -f | --format)
+ format="$2"
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ err_help "Invalid argument: $1"
+ ;;
+ esac
+done
+
+if [ "$#" -eq 0 ]; then
+ IFS='
+'
+ set -o noglob
+ set -- $(cat)
+fi
+
+while [ $# -gt 0 ]; do
+ if [ ! -d "$1" ]; then
+ say_err "$1" "No such file or directory"
+ shift
+ continue
+ fi
+
+ ts_max="0"
+ if ts=$(stat -c "%Y" "$1"); then
+ say_verbose "stat '$1': $ts"
+ if [ "$ts" -gt "$ts_max" ]; then
+ ts_max=$ts
+ fi
+ fi
+
+ if $git && ts=$(git -C "$1" --no-pager log -1 --all --format="%at" 2>/dev/null); then
+ say_verbose "git '$1': $ts"
+ if [ "$ts" -gt "$ts_max" ]; then
+ ts_max=$ts
+ fi
+ fi
+
+ pattern=$(printf %s\\n "$1" | sed 's|/|.{1,2}|g')
+ if $sessions && ts=$(fd "$pattern" "$sessions_dir" -1 --type=f --max-depth=1 -x stat -c "%Y" {} 2>/dev/null); then
+ say_verbose "session '$1': $ts"
+ if [ "$ts" -gt "$ts_max" ]; then
+ ts_max=$ts
+ fi
+ fi
+
+ printf %s\\n "$format" | sed "s|{}|$ts_max|g" | sed "s|{1}|$1|g"
+ shift
+done
diff --git a/tmux/.local/bin/tmux-sessionizer b/tmux/.local/bin/tmux-sessionizer
index 7fe14d7..04f8633 100755
--- a/tmux/.local/bin/tmux-sessionizer
+++ b/tmux/.local/bin/tmux-sessionizer
@@ -2,67 +2,20 @@
# shellcheck disable=2016,2089
PROJECT_DIR="$HOME/src"
-INITIAL_DIRS="$HOME/.dotfiles"
-{ PREVIEW_CMD=$(cat); } <<'EOF'
-selection={}
-query=$(printf %s\\n {q} | sed 's|/$||')
-width=$(((($(tput cols) * 3) + (4 - 1)) / 4))
-ofargs=$([ "$width" -gt 80 ] || echo "--show-logo=never")
-if [ -n "$selection" ]; then
- timeout 1s onefetch --hidden $ofargs $selection 2>/dev/null ||
- ([ -e $selection/README.md ] && timeout 1s glow --local --style=dark $selection/README.md) ||
- timeout 1s exa --tree --git-ignore --level=3 --icons $selection
-elif [ -n "$query" ]; then
- timeout 3s hut git show --repo "$query" 2>/dev/null ||
- timeout 3s gh repo view "$query" 2>/dev/null
-fi
-EOF
+SESSION_DIR="$XDG_DATA_HOME/nvim/sessions"
+PREVIEW_CMD="previewer.sh {} 2>/dev/null || previewer.sh {q} --remote"
+ATTACHED="$(tmux list-sessions -F '#{?session_attached,#{session_path},}' 2>/dev/null | sed '/^$/d')"
if [ "$#" -eq 0 ]; then
- DIRS=""
-
- for initial_dir in $INITIAL_DIRS; do
- if [ -d "$initial_dir" ]; then
- DIRS="$DIRS $(stat -c %Y:"$initial_dir" "$initial_dir")"
- fi
- done
-
- for project in "$PROJECT_DIR"/*; do
- if [ -d "$project" ]; then
- DIRS="$DIRS $(stat -c %Y:"$project" "$project")"
- fi
- done
-
- for session in "$XDG_DATA_HOME/nvim/sessions"/*; do
- entry="$(printf %s\\n "$session" | sed "s|^$XDG_DATA_HOME/nvim/sessions/||" | sed 's#%{2}|_{2}#/#g')"
- if [ -d "$entry" ]; then
- DIRS="$DIRS $(stat -c %Y:"$entry" "$session")"
- fi
- done
-
- if [ -n "$TMUX" ]; then
- attached="$(tmux list-sessions -F '#{?session_attached,#{session_path},}' | sed '/^$/d')"
- fi
-
- DIRS="$(printf %s\\n "$DIRS" | xargs -I{} -d ' ' sh -c '
- timestamp="$(printf %s "{}" | cut -d":" -f1)"
- dir_path="$(printf %s "{}" | cut -d":" -f2)"
- source="$(printf %s "{}" | cut -d":" -f2)"
-
- if [ -e "$dir_path/.git" ]; then
- git_timestamp="$(git -C "$dir_path" --no-pager log -1 --all --format="%at" 2>/dev/null || stat -c %Y "$dir_path"/.git)"
- fi
-
- if [ $git_timestamp -gt $timestamp ]; then
- printf %s:%s\\n $git_timestamp $dir_path
- else
- printf %s\\n {}
- fi
- ' | sort -r | sort -t':' -r -k2 | uniq -s10 | sort -r | cut -d':' -f2 | sed "s#^$attached\$##g" | sed '/^$/d')"
-
# shellcheck disable=2046
- set -- $(printf %s\\n "$DIRS" | fzf-tmux -p -- --multi --print-query -d/ --with-nth -1 \
- --preview-window=right,75% --preview="$PREVIEW_CMD" | tr -s '\n' ' ')
+ set -- $({
+ printf %s\\n "$HOME/.dotfiles"
+ fd . "$PROJECT_DIR" --type=d --max-depth=1
+ fd . "$SESSION_DIR" --type=f --max-depth=1 | sed "s|^$SESSION_DIR/||" | sed 's#%%\|__#/#g'
+ } | sed 's|/$||' | sed "\|^$HOME\$|d" | sed "\|^$ATTACHED\$|d" | sort -u |
+ timestamp.sh --git --sessions="$SESSION_DIR" --format="{}:{1}" | sort -r | cut -d':' -f2 |
+ fzf-tmux -p -- --multi --print-query -d/ --with-nth -1 --preview-window=right,75% --preview="$PREVIEW_CMD" |
+ tr -s '\n' ' ')
fi
while [ $# -gt 0 ]; do