wrote opening url in kak post
This commit is contained in:
parent
e0881d0a9e
commit
c21bfc5fe6
1 changed files with 151 additions and 0 deletions
151
content/blog/kak/url-open.md
Normal file
151
content/blog/kak/url-open.md
Normal file
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
title: Opening URLs In Kakoune
|
||||
date: 07 Jul 2025
|
||||
---
|
||||
|
||||
[Kakoune]: https://kakoune.org
|
||||
|
||||
One feature built into [Helix](https://docs.helix-editor.com/) is the
|
||||
ability to super-easily open URLs in your browser. All you need to do is
|
||||
move your cursor over a URL, and press `gf`. This is _very_ helpful when
|
||||
reading documentation, emails, et cetera...
|
||||
|
||||
So, how can we do this in [Kakoune]?
|
||||
|
||||
[TOC]
|
||||
|
||||
## Goal
|
||||
|
||||
Here's our target user experience:
|
||||
|
||||
1. The user moves their cursor over a URL.
|
||||
2. The user presses a key.
|
||||
3. The URL is selected, validated, and opened.
|
||||
4. The user is notified of any errors or success.
|
||||
|
||||
Like any bit of custom functionality, the best way to go is to define a
|
||||
**command**. This gives us re-usability, and greater flexibility (since
|
||||
`map` only allows mapping to _key sequences_, not any arbitrary string of
|
||||
commands).
|
||||
|
||||
## Selecting
|
||||
|
||||
First, we need to find the URL under the cursor. Of course, if there
|
||||
_isn't_ one, we should fail at this step. The standard way to do this in
|
||||
Kakoune is by using a regular expression to filter the selection. If
|
||||
there's no matches at all, that's something we can `try/catch`.
|
||||
|
||||
We won't get far without a URL regex. When I'm including long regexes in
|
||||
`#!kak execute-keys` commands, I like saving them to a register, like so:
|
||||
|
||||
```kak
|
||||
set-register b 'https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)'
|
||||
```
|
||||
|
||||
Then, we just need to check if this regex exists around the user's cursor.
|
||||
Since URLs don't have spaces, we can select the surrounding `WORD`, and
|
||||
filter from there:
|
||||
|
||||
```kak
|
||||
execute-keys -draft '<a-a><a-w>s<c-r>b<ret>"ay'
|
||||
```
|
||||
|
||||
The above command selects the outer `WORD`, then runs the select command
|
||||
with our regex (stored in register `b`). Once the URL has been selected,
|
||||
it's copied to the `a` register. If there is no URL, the command fails.
|
||||
|
||||
## Cleaning
|
||||
|
||||
It's usually better to allow regex to be a bit greedier, and then
|
||||
filter unwanted characters out of the result. In our case, some
|
||||
trailing punctuation is included in the capture -- we can use `sed`
|
||||
in a shell block to strip them.
|
||||
|
||||
```sh
|
||||
clean_url="$(echo "$kak_reg_a" | sed 's/[][(){}.,;!?]*$//')"
|
||||
```
|
||||
|
||||
## Opening
|
||||
|
||||
Our next step is to figure out how we'd open a URL from the shell --
|
||||
after all, anything we implement in Kakoune ends up running shell
|
||||
commands! If you have `xdg-open` available (part of the `xdg-utils`
|
||||
package on Arch Linux), this is simple:
|
||||
|
||||
```sh
|
||||
xdg-open https://ficd.ca
|
||||
```
|
||||
|
||||
XDG handles figuring out the correct application to forward the URL to. If
|
||||
your environment is set up properly, this is probably your default
|
||||
browser. If you don't have (or don't want to use) `xdg-open`, most
|
||||
browsers let you open URLs from the command line directly:
|
||||
|
||||
```sh
|
||||
firefox https://ficd.ca
|
||||
```
|
||||
|
||||
Depending on the browser -- if you already have an open session, the link
|
||||
will be opened as a new tab in an existing window. Nice!
|
||||
|
||||
Let's define an **option** which contains the shell command we'll
|
||||
use to open the link:
|
||||
|
||||
```kak
|
||||
# %s gets replaced with the URL
|
||||
declare-option str url_open_cmd 'xdg-open %s'
|
||||
```
|
||||
|
||||
Then, in our shell block, we can substitute the cleaned URL into the `%s`
|
||||
format specifier, and evaluate the resulting string as a command:
|
||||
|
||||
```sh
|
||||
if eval "$(printf "$kak_opt_url_open_cmd" "$clean_url")" >/dev/null 2>&1; then
|
||||
echo "info -title 'URL Opened' '$clean_url'"
|
||||
else
|
||||
echo "fail 'url_open_cmd failed!'"
|
||||
fi
|
||||
```
|
||||
|
||||
## Completed Plugin
|
||||
|
||||
That's it, that's all! We now have a command called `url-open`,
|
||||
which we can easily bind to something like `gu`:
|
||||
|
||||
```kak
|
||||
map global goto u '<esc>: url-open<ret>'
|
||||
```
|
||||
|
||||
Here's the complete plugin code:
|
||||
|
||||
```kak
|
||||
declare-option -docstring %{
|
||||
Command for opening URLs.
|
||||
} str url_open_cmd 'xdg-open %s'
|
||||
define-command -docstring %{
|
||||
Open the URL the cursor is on with url_open_cmd.
|
||||
} url-open %{
|
||||
evaluate-commands -save-regs 'ab' %{
|
||||
set-register b 'https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)'
|
||||
try %{
|
||||
try %{
|
||||
execute-keys -draft '<a-a><a-w>s<c-r>b<ret>"ay'
|
||||
} catch %{
|
||||
fail 'No URL found!'
|
||||
}
|
||||
evaluate-commands %sh{
|
||||
# strip trailing punctuation
|
||||
clean_url="$(echo "$kak_reg_a" | sed 's/[][(){}.,;!?]*$//')"
|
||||
if eval "$(printf "$kak_opt_url_open_cmd" "$clean_url")" >/dev/null 2>&1; then
|
||||
echo "info -title 'URL Opened' '$clean_url'"
|
||||
else
|
||||
echo "fail 'url_open_cmd failed!'"
|
||||
fi
|
||||
}
|
||||
} catch %{
|
||||
info -title 'URL Open' "Couldn't open URL: %val{error}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue