Best Way to Open URLs in Your Terminal via Tmux

Efficently open URLs by only using the keyboard. Let me show you the script I made.


I have been using tmux for a while now. It was really worth it, especially after I started using neovim. One thing was really missing though compared to my previous setup and that was opening URLs. I always used my mouse to do that, but now I couldn’t even do that because I am using the good old xterm as a terminal which doesn’t have a built in feature like that.

I looked at some xterm solutions for this problem, but I knew I had to do something in tmux because it has lots of commands and such. Then I found tmux-urlview, so I was sure I can make something cool with tmux.

The script

The full script can be found on my GitHub in my .dotfiles repository’s scripts directory named tmux-select-url.

First I had to understand the basics of the upper mentioned tmux-urlview. It used a basic logic: save the current tmux pane’s text content (buffer) and then parse out the URLs and show a choosing menu by which the URL will be opened. So I implemented the same logic.

Starting with saving the current buffer:

tmux capture-pane
tmux save-buffer "/tmp/tmuxsave"
tmux delete-buffer

Now comes some basic Linux command knowledge: get the URLs out of the file (/tmp/tmuxsave). That means we have to use some regex, but thankfully there are plenty out there on the internet, so we don’t have to write our own. Just so duplicates are removed I also used uniq.

urls=$(grep -Eoi "(http|https)://[a-zA-Z0-9+./?=_%:-]+" /tmp/$buffer_file_name | uniq)

We have the URLs in a variable. I had to figure out a cool way to select from them. It had to be quick and easy. My first thought was to use fzf because I already used it many times with tmux, but then I also stumbled up on tmux’s display-menu which you can see in this post’s thumbnail.

I decided to use both. The menu is good to display few links and it’s really nice because it also provides a way to assign keybinds to items. In the menu I also made it so the http or https is cut off so it is better for my eyes. For more than 5 items I decided to use fzf opened in a new pane.

url_count=$(echo "$urls" | wc -l)
if [ $url_count -gt 5 ]; then tmux neww -n "url-select" "printf '%s\n' '$urls' | fzf --exit-0 --print-query | xargs -I {} sh -c 'xdg-open {} > /dev/null 2>&1 && tmux display-message \"#[bold]$name: Opened {}#[bold]\"'"
else tmux_menu="tmux display-menu -t 1 -T 'url-select'" index=1 for url in ${(f)urls}; do clean_url=${url#*//} tmux_menu="$tmux_menu '$clean_url' $index 'run-shell \"xdg-open $url > /dev/null 2>&1; tmux display-message '\''#[bold]$name: Opened $url#[bold]'\''\"'" ((index++)) if [ $index -gt 9 ]; then break fi done eval $tmux_menu

The code upper isn’t hard to understand, it’s just dense. If you don’t understand something I recommend you to read the manuals via man.

I added some useful things to the script too. For example if there are no URLs don’t show anything or if only one is available just open it right away.

By default capture-buffer only captures the currently visible parts of the pane, but by setting S to - the whole history is saved. So in the final version of the script I added that if "full" is passed as an argument then it will capture the full history. The full script can be found on my GitHub in my .dotfiles repository’s scripts directory named tmux-select-url. Feel free to use my script.

To make it easily accessable I binded it to o and O in my .tmux.conf (NOTE: I also added executable permission to the script and put it in my $PATH):

bind-key o run-shell -b "tmux-select-url"
bind-key O run-shell -b "tmux-select-url full"

I hope that this post encourages you to make your own tmux related scripts.

If you are interested in more of this type of content then I suggest you to read posts from my series about improving my setup and developer productivity.

Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment


No comments yet. Why don’t you start the discussion?

    Leave a Reply

    Your email address will not be published. Required fields are marked *