Skip to content

Commit 41ec345

Browse files
committed
Feat: Add sorting options
Adds a new option for `@fzf-url-sort-by`, defaulting to `alphabetical` as before, and adding `recency` to sort urls by recency in the scrollback history. Most of the time when I use this plugin, I want to open the url that just got printed (usually a github PR). Sorting be recency makes it so 9/10 times, I invoke the plugin and hit enter to oepn it right away.
1 parent 16381dc commit 41ec345

File tree

4 files changed

+170
-12
lines changed

4 files changed

+170
-12
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ You can use custom fzf options by defining `@fzf-url-fzf-options`.
5656
set -g @fzf-url-fzf-options '-w 50% -h 50% --multi -0 --no-preview --no-border'
5757
```
5858

59+
You can control how URLs are sorted by setting `@fzf-url-sort-by`:
60+
61+
```tmux
62+
# Sort URLs alphabetically (default)
63+
set -g @fzf-url-sort-by 'alphabetical'
64+
65+
# Sort URLs by recency - most recent URLs closest to search bar
66+
set -g @fzf-url-sort-by 'recency'
67+
```
68+
69+
**Smart Layout Detection**: When using recency sorting, the plugin automatically detects your fzf layout and adjusts the sort order to keep the most recent URLs closest to the search bar:
70+
71+
- **Default layout** (search at bottom): Recent URLs appear first (top of list)
72+
- **Reverse layout** (with `--reverse` option): Recent URLs appear last (bottom of list)
73+
74+
This ensures optimal accessibility regardless of your preferred fzf layout.
75+
5976
By default, `tmux-fzf-url` will use `xdg-open`, `open`, or the `BROWSER`
6077
environment variable to open the url, respectively. If you want to use a
6178
different command, you can set `@fzf-url-open` to the command you want to use.

fzf-url.sh

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fzf_filter() {
1616
}
1717

1818
custom_open=$3
19+
sort_by=$4
1920
open_url() {
2021
if [[ -n $custom_open ]]; then
2122
$custom_open "$@"
@@ -37,21 +38,44 @@ else
3738
content="$(tmux capture-pane -J -p -e -S -"$limit" |sed -r 's/\x1B\[[0-9;]*[mK]//g'))"
3839
fi
3940

40-
urls=$(echo "$content" |grep -oE '(https?|ftp|file):/?//[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]')
41-
wwws=$(echo "$content" |grep -oE '(http?s://)?www\.[a-zA-Z](-?[a-zA-Z0-9])+\.[a-zA-Z]{2,}(/\S+)*' | grep -vE '^https?://' |sed 's/^\(.*\)$/http:\/\/\1/')
42-
ips=$(echo "$content" |grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(:[0-9]{1,5})?(/\S+)*' |sed 's/^\(.*\)$/http:\/\/\1/')
43-
gits=$(echo "$content" |grep -oE '(ssh://)?git@\S*' | sed 's/:/\//g' | sed 's/^\(ssh\/\/\/\)\{0,1\}git@\(.*\)$/https:\/\/\2/')
44-
gh=$(echo "$content" |grep -oE "['\"]([_A-Za-z0-9-]*/[_.A-Za-z0-9-]*)['\"]" | sed "s/['\"]//g" | sed 's#.#https://github.com/&#')
41+
# Extract URLs with line numbers to preserve position
42+
urls=$(echo "$content" | grep -noE '(https?|ftp|file):/?//[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]')
43+
wwws=$(echo "$content" | grep -noE '(http?s://)?www\.[a-zA-Z](-?[a-zA-Z0-9])+\.[a-zA-Z]{2,}(/\S+)*' | grep -vE ':[0-9]*:https?://' | sed 's/^\([0-9]*\):\(.*\)$/\1:http:\/\/\2/')
44+
ips=$(echo "$content" | grep -noE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(:[0-9]{1,5})?(/\S+)*' | sed 's/^\([0-9]*\):\(.*\)$/\1:http:\/\/\2/')
45+
gits=$(echo "$content" | grep -noE '(ssh://)?git@\S*' | sed 's/:/\//g' | sed 's/^\([0-9]*\)\/\/\(ssh\/\/\/\)\{0,1\}git@\(.*\)$/\1:https:\/\/\3/')
46+
gh=$(echo "$content" | grep -noE "['\"]([_A-Za-z0-9-]*/[_.A-Za-z0-9-]*)['\"]" | sed "s/['\"]//g" | sed 's/^\([0-9]*\):\(.*\)$/\1:https:\/\/github.com\/\2/')
4547

4648
if [[ $# -ge 1 && "$1" != '' ]]; then
47-
extras=$(echo "$content" |eval "$1")
49+
extras=$(echo "$content" | nl -nln | eval "$1" | sed 's/^\([0-9]*\)\t\(.*\)$/\1:\2/')
4850
fi
4951

50-
items=$(printf '%s\n' "${urls[@]}" "${wwws[@]}" "${gh[@]}" "${ips[@]}" "${gits[@]}" "${extras[@]}" |
51-
grep -v '^$' |
52-
sort -u |
53-
nl -w3 -s ' '
54-
)
52+
# Combine all URLs with their line numbers
53+
all_urls=$(printf '%s\n' "${urls[@]}" "${wwws[@]}" "${gh[@]}" "${ips[@]}" "${gits[@]}" "${extras[@]}" | grep -v '^$')
54+
55+
# Sort and deduplicate based on sort_by option
56+
if [[ "$sort_by" == "recency" ]]; then
57+
# Recency behavior: adjust sort order based on fzf layout
58+
fzf_options="$(get_fzf_options)"
59+
if [[ "$fzf_options" == *"--reverse"* ]]; then
60+
# Reverse layout (search at top): oldest URLs first so recent ones are closest to search
61+
sort_order="-n"
62+
else
63+
# Default layout (search at bottom): newest URLs first so recent ones are closest to search
64+
sort_order="-nr"
65+
fi
66+
67+
items=$(echo "$all_urls" | awk -F: '
68+
{
69+
url = substr($0, index($0, ":") + 1)
70+
if (!seen[url]) {
71+
seen[url] = 1
72+
print $1 ":" url
73+
}
74+
}' | sort $sort_order | cut -d: -f2- | nl -w3 -s ' ')
75+
else
76+
# Default alphabetical behavior: sort alphabetically and remove duplicates
77+
items=$(echo "$all_urls" | cut -d: -f2- | sort -u | nl -w3 -s ' ')
78+
fi
5579
[ -z "$items" ] && tmux display 'tmux-fzf-url: no URLs found' && exit
5680

5781
fzf_filter <<< "$items" | awk '{print $2}' | \

fzf-url.tmux

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ key="$(tmux_get '@fzf-url-bind' 'u')"
1818
history_limit="$(tmux_get '@fzf-url-history-limit' 'screen')"
1919
extra_filter="$(tmux_get '@fzf-url-extra-filter' '')"
2020
custom_open="$(tmux_get '@fzf-url-open' '')"
21+
sort_by="$(tmux_get '@fzf-url-sort-by' 'alphabetical')"
2122
echo "$extra_filter" > /tmp/filter
2223

23-
tmux bind-key "$key" run -b "$SCRIPT_DIR/fzf-url.sh '$extra_filter' $history_limit '$custom_open'";
24+
tmux bind-key "$key" run -b "$SCRIPT_DIR/fzf-url.sh '$extra_filter' $history_limit '$custom_open' '$sort_by'";

tmux.sample.conf

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Tmux Configuration
2+
# Terminal multiplexer for session management and productivity
3+
4+
# Load reset configuration first
5+
source-file ~/.config/tmux/tmux.reset.conf
6+
7+
# Terminal settings
8+
set -g default-terminal 'screen-256color'
9+
set -g terminal-overrides ',xterm-256color:RGB'
10+
set -g set-titles on
11+
set -g set-titles-string '#{?#{m:[0-9]*,#S},tmux #{pane_current_path},#S}'
12+
13+
# Core settings
14+
set -g mouse on # Enable mouse support
15+
set -g prefix C-g # Use Ctrl-Space as prefix key
16+
set -g base-index 1 # Start indexing windows at 1 instead of 0
17+
setw -g pane-base-index 1 # Start indexing panes at 1 instead of 0
18+
set -g detach-on-destroy off # Don't exit from tmux when closing a session
19+
set -g escape-time 0 # Zero-out escape time delay for faster key response
20+
set -g history-limit 1000000 # Increase history size (from default 2,000)
21+
set -g renumber-windows on # Renumber all windows when any window is closed
22+
set -g set-clipboard on # Use system clipboard
23+
set -g status-position top # macOS / darwin style status bar
24+
set -g default-terminal "${TERM}"
25+
setw -g mode-keys vi # Use vi-style key bindings
26+
27+
# Pane settings
28+
set -g other-pane-height 25%
29+
set -g other-pane-width 80
30+
31+
# Status line configuration
32+
set -g status-right-length 100 # Increase right status length
33+
set -g status-left-length 100 # Increase left status length
34+
set -g status-left "" # Clear default left status
35+
36+
# Pane border styling
37+
set -g pane-active-border-style 'fg=magenta,bg=default' # Active pane border
38+
set -g pane-border-style 'fg=brightblack,bg=default' # Inactive pane border
39+
40+
# Plugin configurations
41+
set -g @fzf-url-fzf-options '-p 60%,30% --prompt=" " --border-label=" Open URL "'
42+
set -g @fzf-url-history-limit '2000'
43+
44+
# Plugin management
45+
set -g @plugin 'tmux-plugins/tpm' # Tmux Plugin Manager
46+
set -g @plugin 'tmux-plugins/tmux-sensible' # Sensible default settings
47+
set -g @plugin 'tmux-plugins/tmux-yank' # Copy to system clipboard
48+
# set -g @plugin 'tmux-plugins/tmux-resurrect' # Save/restore sessions
49+
# set -g @plugin 'tmux-plugins/tmux-continuum' # Automatic session save/restore
50+
51+
# Enhanced functionality plugins
52+
set -g @plugin 'sainnhe/tmux-fzf' # Fuzzy finder integration
53+
# set -g @plugin 'wfxr/tmux-fzf-url' # URL extraction and opening
54+
set -g @plugin 'josephschmitt/tmux-fzf-url' # URL extraction and opening
55+
set -g @plugin 'omerxx/catppuccin-tmux' # Catppuccin theme
56+
set -g @plugin 'christoomey/vim-tmux-navigator' # Seamless vim/tmux navigation
57+
set -g @plugin 'jabirali/tmux-tilish' # i3-like window management
58+
59+
# Session persistence configuration
60+
# set -g @continuum-restore 'on' # Automatically restore sessions
61+
# set -g @resurrect-strategy-nvim 'session' # Save nvim sessions
62+
63+
# Tilish plugin configuration (i3-like window management)
64+
set -g @tilish-default 'main-horizontal'
65+
set -g @tilish-enforce 'size'
66+
67+
# URL handling
68+
set -g @fzf-url-history-limit '2000' # URL history limit
69+
set -g @fzf-url-sort-by 'recency'
70+
71+
# Catppuccin theme configuration
72+
set -g @catppuccin_flavor "mocha" # Dark theme variant
73+
set -g @catppuccin_window_status_style "rounded" # Rounded window tabs
74+
set -g @catppuccin_status_background "none" # Transparent status background
75+
76+
# Window tab styling
77+
set -g @catppuccin_window_left_separator "" # Left separator
78+
set -g @catppuccin_window_right_separator " " # Right separator
79+
set -g @catppuccin_window_middle_separator " █" # Middle separator
80+
set -g @catppuccin_window_number_position "right" # Window number position
81+
set -g @catppuccin_window_default_fill "number" # Default window fill
82+
set -g @catppuccin_window_default_text "#W" # Default window text
83+
set -g @catppuccin_window_current_fill "number" # Current window fill
84+
set -g @catppuccin_window_current_text "#W#{?window_zoomed_flag,(),}" # Current window text with zoom indicator
85+
86+
# Status line modules
87+
set -g @catppuccin_status_modules_right "directory date_time" # Right side modules
88+
set -g @catppuccin_status_modules_left "session" # Left side modules
89+
set -g @catppuccin_status_left_separator " " # Left separator
90+
set -g @catppuccin_status_right_separator " " # Right separator
91+
set -g @catppuccin_status_right_separator_inverse "no" # No inverse separator
92+
set -g @catppuccin_status_fill "icon" # Fill with icons
93+
set -g @catppuccin_status_connect_separator "no" # No connecting separator
94+
95+
# Custom module content
96+
set -g @catppuccin_directory_text "#{b:pane_current_path}" # Show basename of current path
97+
set -g @catppuccin_date_time_text "#(date \"+%I:%M%p\" | tr \"[:upper:]\" \"[:lower:]\")" # Lowercase time format
98+
99+
# Sesh session management
100+
bind-key "o" run-shell "sesh connect \"$(
101+
sesh list --icons | fzf-tmux -p 80%,70% \
102+
--no-sort --ansi --border-label ' sesh ' --prompt '⚡ ' \
103+
--header ' ^a all ^t tmux ^g configs ^x zoxide ^d tmux kill ^f find' \
104+
--bind 'tab:down,btab:up' \
105+
--bind 'ctrl-a:change-prompt(⚡ )+reload(sesh list --icons)' \
106+
--bind 'ctrl-t:change-prompt(🪟 )+reload(sesh list -t --icons)' \
107+
--bind 'ctrl-g:change-prompt(⚙️ )+reload(sesh list -c --icons)' \
108+
--bind 'ctrl-x:change-prompt(📁 )+reload(sesh list -z --icons)' \
109+
--bind 'ctrl-f:change-prompt(🔎 )+reload(fd -H -d 2 -t d -E .Trash . ~)' \
110+
--bind 'ctrl-d:execute(tmux kill-session -t {2..})+change-prompt(⚡ )+reload(sesh list --icons)' \
111+
--preview-window 'right:55%' \
112+
--preview 'sesh preview {}'
113+
)\""
114+
115+
# Initialize Tmux Plugin Manager (keep this line at the very bottom)
116+
run '~/.tmux/plugins/tpm/tpm'

0 commit comments

Comments
 (0)