You can easily open a URL in your web browser with a simple keybind right from Vim. The common practice is to use gx
as the keybind. However, you need to place the cursor exactly under the URL to open it.
That’s why I wrote a small script to improve this workflow: it extracts the URL nearest to the cursor, so that you don’t have to place the cursor exactly under the URL anymore.
It also works for Windows via WSL.
Installation
I created a GitHub repository where you can find the scripts, the Vim function, and a shorter version of the instructions below.
Usage
To open a URL in your web browser, just place the cursor near the URL and press gx
. There is no need to have your cursor exactly under the URL.
Setup
This is not a Vim plugin but a set of Unix filters following the philosophy: “Do one thing and do it well.”
This workflow is made of three components:
- a Bash script (to call the web browser);
- a Python script (to extract the URL nearest to the cursor);
- a Vim function and a keybind (to call the scripts).
Adding the Scripts to Your PATH
The two scripts should be in your PATH
. This environment variable contains a list of directories in which the shell looks for executables.
If you don’t have a custom directory for your scripts, you can use /usr/local/bin
. Ensure that the scripts are executable by running chmod +x /path/to/script
.
Creating a Custom Directory for Your Scripts
Personally, I use ~/.scripts
for my custom scripts.
Adding a directory to your PATH
environment variable is done by adding the following line to your .bashrc
or .zshrc
:
Then, source your .bashrc
or .zshrc
file:
Or initialize a new instance of your shell:
Bash Script: Calling your Web Browser
This script just call your web browser’s executable with a URL as an argument. If you’re using WSL and Brave, the script should look like this:
#!/bin/bash
/mnt/c/Program\ Files/BraveSoftware/Brave-Browser/Application/brave.exe "$1" 2> /dev/null &
Adjust the path according to your web browser and operating system.
I named the script brave
, but you can name it whatever you want. Just remember to change the name in the Vim function.
Python Script: Extract the URL Nearest to the Cursor
Like the Bash script, place the code below in an executable file within your PATH
. I named it extract_nearest_url
.
#!/usr/bin/python3
import re
import sys
def main():
line = " ".join(sys.argv[1:-1]) if len(sys.argv) > 1 else ""
try:
cursor_pos = int(sys.argv[-1])
except ValueError:
sys.exit("Error: Cursor position must be an integer")
url = extract_nearest_url(line, cursor_pos)
print(url, end="") # Print without additional newline
def extract_nearest_url(line, cursor_pos):
# Regular expression to extract URLs
url_patterns = (
r"\[.*?\]\((\S+?)\)", # Markdown link
r"<(\S+?)>", # Angle brackets
r"\\href\{(\S+?)\}\{.*?\}", # LaTeX \href{}{}
r"(http[s]?://\S+)", # Plain URLs with protocol
r'(?:src|href|content)=["\'](.*?)["\']', # HTML/XML attributes
)
pattern = "|".join(url_patterns)
matches = re.finditer(pattern, line)
nearest_url = None
min_distance = float("inf")
# Extract URL
for match in matches:
url = next((group for group in match.groups() if group), None)
# Calculate distances to cursor position
start_pos = match.start()
end_pos = match.end()
distance = min(abs(cursor_pos - start_pos), abs(cursor_pos - end_pos))
# Update nearest URL
if distance < min_distance:
min_distance = distance
# Clean the URL by removing any trailing punctuation and whitespace
cleaned_url = re.sub(r"[\"),.\s]*$", "", url)
nearest_url = cleaned_url
return nearest_url if nearest_url else ""
if __name__ == "__main__":
main()
Vim Function and Keybind
Add the following code to your .vimrc
:
" This function opens the URL nearest to the cursor in Brave
function! OpenURLNearestToCursor()
" Get the current line and column
let l:line = getline('.')
let l:col = col('.')
" Extract the URL nearest to the cursor
let l:escaped_line = shellescape(l:line)
let l:command = 'extract_nearest_url ' . l:escaped_line . ' ' . l:col
let l:cleaned_url = system(l:command)
" If a URL has been found, open it in Brave
if l:cleaned_url != ''
silent exec "!brave " . fnameescape(l:cleaned_url)
redraw!
endif
endfunction
" Bind the function to the `gx` key in normal mode
nnoremap gx :call OpenURLNearestToCursor()<CR>
Notice that the function calls the extract_nearest_url
script and the brave
script on lines 5 and 9 respectively. If you named them differently, you should change the names in the function.
Finally, on the last line, you can see the keybind gx
. You can change it to whatever you want.
Conclusion
This workflow is an improvement over the ordinary gx
keybind. You don’t have to place the cursor exactly under the URL anymore. It’s a small change, but it’s pleasant to use.