4  Link Shortcuts and References

Chapter 3 introduced the location field and its @ shortcuts as a way to save keystrokes on ordinary web addresses. This chapter covers that in full, along with a second, related facility: references, which let one bookmark’s location build on another’s.

4.1 Why shortcuts exist

Modern browsers let you type google.com instead of https://www.google.com and fill in the rest themselves. hande’s @ shortcuts do the same thing for a bookmark’s location field — you supply the host, and hande fills in the protocol.

Both kinds of shortcut this chapter covers — a plain link shortcut and a reference — are marked the same way: an @ as the very first character of the location field. hande tells them apart by what immediately follows the @. Because of this, the @ has to be the first character — anywhere else in a location, it’s just passed straight through to the handler as ordinary text, and the location simply fails to resolve.

Link shortcuts are a location-field feature only. They aren’t the same thing as the @ shortcut-key chains from Chapter 1, which you type at the shell or command line to open a bookmark — those are a completely separate feature that happens to reuse the same symbol.

4.2 The full shortcut table

Every shortcut resolves to a secure https:// address unless you tell it otherwise:

Symbol after @ Meaning Example
(none) https:// @example.com → https://example.com
= Add the www. subdomain @=example.com → https://www.example.com
! Use plain, insecure http:// instead @!example.com → http://example.com
!= Both of the above at once @!=example.com → http://www.example.com
# A localhost resource, by port @#631 → http://localhost:631
+ The file:// protocol, for an absolute path @+/usr/local/texlive/2024/doc.html → file:///usr/local/texlive/2024/doc.html
~ The file:// protocol, relative to your home directory @~Documents/Notes/recipe.html → a file under $HOME
: The mailto: protocol @:me@example.com → mailto:me@example.com
@ The ftps:// protocol @@example.com → ftps://example.com
@! The ftp:// protocol @@!example.com → ftp://example.com
{name} A reference to another bookmark — covered in the rest of this chapter
* A reference to the category’s own home bookmark — likewise covered below

A worked example for each of the first few:

debian <@debian.org>                          # https://debian.org
the-smith <@=thetextsmith.com>                # https://www.thetextsmith.com
example <@!example.com>                       # http://example.com
printing <@#631>                              # http://localhost:631
tex-documentation <@+/usr/local/texlive/2024/doc.html>
recipe <@~Documents/Notes/recipe.html>

If you type out a full address by hand — <@www.thetextsmith.com>, say, instead of using = — hande still opens it, but lets you know you could have used the shortcut instead. If that notice bothers you, just switch to the shortcut form and it goes away.

4.3 Saving with shortcuts

Typing shortcuts by hand is one thing, but a URL you’ve copied from somewhere else won’t already be in that form. Rather than making you rewrite it yourself, hande does it for you: paste the plain address straight into the location field and save the file, and hande rewrites every http/file: address in it into its shortest matching shortcut the next time it touches that file. A file:// address under your own home directory becomes @~; everything else it can shorten follows the table above.

This is the save-with-shortcuts setting from Chapter 7, on by default. Set it to false if you’d rather hande left your addresses exactly as you typed them.

4.4 References

A reference is a location that, instead of an address, names another bookmark and builds on it. If several bookmarks share a common path, you only have to write that path once — everywhere else just points back to it.

wiki <@en.wikipedia.org/wiki>
linux <@{wiki}/Linux>

Here, “linux” is a reference and “wiki” is its target. linux resolves to https://en.wikipedia.org/wiki/Linux — hande takes “wiki”’s own address and appends what you wrote after the closing brace. Any number of other bookmarks can use “wiki” as a base the same way:

wikipedia <@en.wikipedia.org/wiki>
windows <@{wikipedia}/Windows>
linux <@{wikipedia}/Linux>

A reference can itself be the target of another reference, letting you build up a path in stages:

music <~/Music>
classics <@{music}/international/Classics>
beethoven <@{classics}/yesteryears/Beethoven>

This also means a deactivated bookmark can still serve as a useful base for other, active ones, even though it can’t be opened on its own:

docs- <~/Documents>
projects <@{docs}/work/Projects>

A target is named by its name, never by a tag/alias (see Chapter 5) — a reference’s target must be a real bookmark name.

4.4.1 What a reference can target

A target must be a bookmark whose own location is a link — never a command (a script or one-liner, Chapter 3). hande checks this, and every reference’s target, when the bookmark file is loaded: unlike an ordinary link (which hande has no way to verify without actually opening it), a reference’s target either exists and resolves, or hande refuses to run at all and tells you exactly what’s wrong.

4.4.2 Targeting a category’s own home bookmark

The category home bookmark (see Chapter 2) has no name of its own, so it can’t be targeted with {name}. Instead, use a bare *:

*<~/Documents/seminars/notes>
presentation <@*presentation.docx>

presentation resolves to a file called presentation.docx inside the notes folder above — @* always adds the trailing slash for you, so you just write the path fragment straight after it, with no leading slash of your own.

4.4.3 Targeting bookmarks outside the current scope

By default, a reference’s target is looked up in the reference’s own scope: a local reference looks for its target in its own category; a global reference looks for its target in the global scope. Reaching outside that default takes one of these forms:

  • A bookmark in a different category: write the category name, a period, then the bookmark’s own name — @{electronics.printers}.
  • Another category’s own home bookmark: write a leading * before that category’s name, inside braces — @{*electronics}.

A global target needs no special marking at all, from anywhere: its own name already starts with an uppercase letter (see Chapter 2), and that alone is enough for hande to look for it in the global scope regardless of which category the reference itself lives in.

printers <~/shopping/gadgets/printers>          # in the "electronics" category
favorite <@{electronics.printers}/best-printer.rtf>   # from "specs"

Documentary <~/Videos/wildlife>                 # global
elephants <@{Documentary}/elephants.mp4>        # from a local category, no marker needed

machine <@{*electronics}/artificial-intelligence/big-machine>

Don’t add a period after a leading * — the scope is already fully decided by the * itself, and a period there is an error rather than a further qualifier.

The reverse also holds: when a reference and its target genuinely share the same scope, use a bare name, not a qualified one — a local reference doesn’t need its own category’s name to reach a sibling in the same file, the same way a global reference doesn’t need anything extra to reach another global bookmark. hande treats a needlessly qualified same-scope target as an error.

radios <~/shopping/radios>
records <@{radios}/peoples-radio/recordings>    # same category, bare name

Phones <~/gadgets/smartphones>
Dialler <@{Phones}/basics/dialler>              # both global, bare name

4.4.4 Things to watch with references

  • A reference always needs its own path fragment or subdomain. A “dead” reference — one that just points at a target with nothing added — behaves like a plain alias for it and raises the risk of an unnecessary chain, so hande refuses to save one. Every reference in the examples above adds something of its own after the target; that’s what keeps it a genuine reference rather than a dead one.
  • Only one target per reference. There’s no way to build a path out of two different references at once — every bookmark, targeted or not, is meant to resolve to one complete, valid location on its own.
  • Two levels of chaining, no more. A reference may target another reference, which may itself target a plain bookmark — that’s two levels, and as far as hande allows. If you find yourself wanting a third, it’s usually a sign that something in the chain belongs in the global scope instead, since a global bookmark can reach any local bookmark directly by its fully-qualified name.
  • No cycles. A reference can never, directly or through a chain, end up targeting itself. hande checks for this and refuses to run rather than loop forever.

4.5 Subdomain references

Many large sites split themselves across subdomains — a “wiki,” a “blog,” a “support” or “news” section, and so on. A subdomain reference adds one of these to an existing bookmark without needing a whole new base bookmark for it.

Write the subdomain right after the @, before the reference’s own braces:

arch <@archlinux.org>
wiki <@wiki{arch}>

wiki resolves to https://wiki.archlinux.org/ — hande takes “arch”’s own address and prepends “wiki.” to its host. Add further path fragments exactly as you would for any other reference:

mate <@wiki{arch}/title/MATE>

A subdomain reference can target bookmarks outside its own scope exactly the same way a plain reference can — no marker needed for a global target, since its name’s own uppercase first letter already says so; category.name for another category’s bookmark:

Google <@google.com>
keyword <@blog{Google}>               # global target, no marker needed

keyword <@blog{tech.google}>          # target in another category

4.5.1 Subdomain references to a category’s own home

Combine the * from earlier with a subdomain the same way:

*<@archlinux.org>
wiki <@wiki*>                 # local reference: no braces needed
mate <@wiki*title/MATE>

From outside that category, braces are needed, exactly as for a plain reference to another category’s home:

wiki <@wiki{*linux}>
mate <@wiki{*linux}/title/MATE>

A bare * always adds its own trailing slash; inside braces it doesn’t, since there you’re naming a category rather than appending directly to a resolved path.

4.5.2 Domain codes

Since a handful of subdomains — “blog,” “wiki,” and the like — come up constantly, hande lets you define a single-character shorthand for one, called a domain code, in the configuration file (see Chapter 7):

[[domain-codes]]
code = "n"
value = "news"

Once defined, the code can be used anywhere a subdomain reference expects one:

yahoo <@yahoo.com>
news <@n{yahoo}>              # same as @news{yahoo}

hande ships with two domain codes already defined — b for “blog” and w for “wiki” — which is why @w* works out of the box against any category’s own home bookmark. Feel free to redefine either, or add more of your own, in the configuration file. A domain code only ever applies where a subdomain is expected; if the character you pick happens to be a real, single-letter subdomain you actually meant literally, define your own code for something else instead.

4.5.3 Replacing, rather than adding, a subdomain

A subdomain reference normally prepends its subdomain to the target’s own address. But if the target already points at a www. address, prepending would give you wiki.www.example.com — not what you want. Add a ! right after the subdomain to replace the www. instead of adding to it:

arch <@=archlinux.org>        # https://www.archlinux.org
wiki <@wiki!{arch}>           # https://wiki.archlinux.org, not wiki.www...

This only ever replaces a www. subdomain specifically — it has no effect on any other subdomain the target might already carry.

Subdomain references and domain codes only apply to web addresses; they have no effect on the file://-based shortcuts (+, ~) or on command locations.