#+TITLE: Links #+DESCRIPTION: Link syntax, the link types Orgstar follows, storing and inserting links, IDs, backlinks and inline images. #+LEDE: Write links as Org does, follow them with a key or a click, and see which headings link to the one you are reading. * Link syntax Orgstar reads links the way =org-element-link-parser= does. There are three forms. | Form | Example | Notes | |---------------+-------------------------------------------+-------------------------------------------------------------| | Bracket link | =[[https://orgmode.org][Org website]]= | Any link type. The description after =][= is optional. | | Angle link | == | For =http=, =https=, =mailto=, =file=, =id=, =doi=, =ftp=, =news=, =shell=, =elisp=, =info=, =help= and =attachment=. | | Plain link | =https://orgmode.org= | Only =https://=, =http://=, =mailto:= and =file:= are recognized in running text. | Inside a bracket link, a target that starts with =/=, =~=, =./= or =../= is a file link. A target in parentheses, =(name)=, is a coderef. One that starts with =#= is a custom ID. Anything without a known =type:= prefix is a search for text in the current file (a "fuzzy" link). A link may run over a line break; the break and surrounding blanks read as one space. Backslashes before brackets are escaped as in =org-link-escape=: when Orgstar writes a link it doubles backslashes that come before a bracket or the end, and it reads them back the same way. * How links display With View ▸ Show Markup off (the default, =⇧⌘M= toggles it), a link with a description shows only its description, and its brackets and target are hidden. This is =org-link-descriptive=. The full text appears on the line that holds the caret, so you can edit it. With Show Markup on, every link shows as written. The setting is =show-markup= under =[orgstar]= in the config file (see [[file:13-configuration.org][Configuration]]). Links without a description show their target, with the brackets hidden in the same way. Radio targets (=<<>>=) turn every other occurrence of those words in the file into a link, matched case-insensitively, as in Org. * Following links =org-open-at-point= follows the link at the caret, or opens the agenda for a timestamp. | Preset | Key | |--------+---------------------------------------------------------------------------------------| | Emacs | =C-c C-o= | | Mac | =⌃⌘O= | | Doom | =C-c C-o= in any state; =RET= in normal state follows a link before doing anything else | | All | =⌘=-click on the link; =o= at the start of a heading line when speed commands are on | A message in the echo area explains a link that can't be followed. ** What each link type does | Link | Example | Result | |----------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------------------| | =http=, =https=, =ftp=, =news=, =mailto= | =[[mailto:me@example.com]]= | Opened by macOS in your default browser or mail app. | | =doi= | =[[doi:10.1000/182]]= | Opens =https://doi.org/= followed by the DOI. | | =file= (also =file+sys:=, =file+emacs:=) | =[[file:notes.org::*Ideas]]= | See /File links/ below. | | =id= | =[[id:6a3c…]]= | Opens the file with the heading whose =ID= property matches, and moves to the heading. | | Custom ID | =[[#setup]]= | Moves to the heading in this file whose =CUSTOM_ID= property is =setup=. | | Heading | =[[*Weekly review]]= | Moves to the heading in this file with that title. | | Text | =[[budget table]]= | Searches this file: a =<>= target, then =#+NAME: budget table=, then a heading. | | Coderef | =[[(ref)]]= | Not supported. The echo area says so. | | =shell=, =elisp= | =[[shell:ls]]= | Not run. Orgstar never executes these links. | | =attachment= | =[[attachment:scan.pdf]]= | Opens the file in the entry's attachment folder; see /Attachment links/ below. | | Radio link | Text matching a =<<>>= | Moves to the radio target. | | =info=, =help=, others | | Not followed. The echo area says Orgstar can't open the type. | The text search follows =org-link-search=. A dedicated =<>= matches its words case-insensitively, with any run of blanks between them. A heading matches when its title, with statistics cookies such as =[2/5]= and a leading =COMMENT= removed, has the same words as the link, ignoring case. A search that starts with =*= looks at headings only. Regular-expression searches (=/re/=) are not supported. Following a radio link moves to its =<<>>=, matching the words without regard to case, as =org-link--search-radio-target= does. When the target is gone, the echo area shows =No match for radio target:= and the text. ** File links A relative path is resolved against the folder of the file that holds the link, as Org does; =~= is your home folder; an absolute path is used as written. Links between files in different sidebar folders work the same way, for example =[[file:../work/projects.org]]= or =[[file:~/Documents/org/inbox.org]]=. What happens depends on the file: - An =.org= or =.org_archive= file opens as a buffer in Orgstar. - Another text file opens in Orgstar as a plain buffer. - Anything else (images, PDFs, archives, media) is handed to macOS, which opens it in the default app for that type. If the file doesn't exist, the echo area shows =No file= and the path. After =::=, a file link can carry a search option: | Option | Example | Moves to | |-----------------+----------------------------------+---------------------------------------------| | A number | =[[file:log.txt::120]]= | Line 120. | | =*Title= | =[[file:notes.org::*Ideas]]= | The heading with that title. | | =#custom-id= | =[[file:notes.org::#setup]]= | The heading with that =CUSTOM_ID=. | | Other text | =[[file:notes.org::budget]]= | A target, a =#+NAME= or a heading, as above. | ** Attachment links An =attachment:= link names a file in the attachment folder of the entry that holds the link, with org-attach's default settings. Relative folders are resolved against the folder of the file that holds the link: 1. When the entry has a =DIR= property, or the older =ATTACH_DIR=, that folder. 2. Otherwise, for an entry with an =ID=, the first of these folders that exists: =data/= followed by the ID's first two characters, =/= and the rest of the ID; =data/= followed by its first six characters, =/= and the rest; =data/__/=, the ID's first character, =/= and the whole ID. When the folder does not exist, the path is relative to the file's own folder. The file then opens as a =file:= link would, and a search option after =::= works the same way. ** id links =id:= links are resolved through the index, so the target heading must be in a file under one of your sidebar folders. A link to an ID that isn't indexed shows =No heading has the ID= followed by the ID. ** Timestamps =C-c C-o= (Mac =⌃⌘O=) or =⌘=-click on a timestamp opens the agenda on that day, as =org-follow-timestamp-link= does. On a date range such as =<2026-10-05 Mon>--<2026-10-09 Fri>=, the agenda shows the whole span. See [[file:07-agenda.org][Agenda]]. * Inserting and editing links =org-insert-link= asks for a link and a description in the echo area. | Preset | Key | |--------+------------------------------| | Emacs | =C-c C-l= | | Mac | =⌘K= | | Doom | =SPC m l l=, or =C-c C-l= | The first prompt reads =Insert link:=, or =Insert link (default …):= when you have stored links. It completes from: - your stored links, most recent first, and their descriptions; - the link abbreviations defined in the file (see /Link abbreviations/); - the link types =attachment=, =id=, =eww=, =rmail=, =mhe=, =irc=, =info=, =gnus=, =docview=, =bibtex=, =bbdb=, =w3m=, =doi=, =file+sys=, =file+emacs=, =shell=, =news=, =mailto=, =https=, =http=, =ftp=, =shortdoc=, =help=, =file= and =elisp=, each followed by =:=. Pressing Return on an empty answer inserts the most recent stored link. Choosing a description inserts the link it belongs to. If you choose a bare type such as =https:=, a second prompt, =Link (no completion support):=, asks for the rest. The next prompt, =Description:=, offers the stored link's description, or the selected text if you selected some before running the command. An empty description inserts a link without one. With text selected, the link replaces the selection. When the caret is on an existing link, the same command edits it: the =Link:= prompt starts with the current target and =Description:= with the current description. A stored link that you insert is removed from the stored list, as with =org-link-keep-stored-after-insertion= set to nil. ** File paths in inserted links When the inserted link is a =file:= link, Orgstar rewrites it as =org-link-make-string-for-buffer= does: - A link to a heading or target in the file you are editing loses its =file:= part and keeps only the search, for example =[[*Ideas]]=. - A path under the current file's folder becomes relative to it. - Any other path is written with =~= for your home folder. ** Completion while typing You can also type a link by hand. With the caret right after =[[=, completion at point offers =attachment:=, =doi:=, =file:=, =http:=, =https:=, =id:= and =mailto:=, plus the file's link abbreviations. After =[[*=, it offers the headings of the current file. Completion at point is =C-M-i= in the Emacs preset and =C-SPC= in Doom's insert state; see [[file:02-the-editor.org][The editor]]. * Storing links =org-store-link= remembers a link to where the caret is, for a later Insert Link. | Preset | Key | |--------+---------------------------------------| | Emacs | =C-c l= | | Mac | =⌃⌘L= | | Doom | =SPC m l s= or =SPC n l= | The stored link is a =file:= link to the current file, written with =~= for your home folder, followed by a search option chosen as Org does with =org-link-context-for-files= on: 1. If the caret touches a =<>= on its line, the link points at the target. 2. Otherwise, if text is selected, the link searches for that text. 3. Otherwise, if the caret is in an element with a =#+NAME=, the link uses the name. 4. Otherwise, inside a heading's entry, the link uses =#custom-id= if the heading has a =CUSTOM_ID= property, and =*Title= if not. The title becomes the description. 5. Before the first heading, the link searches for the text of the current line. The echo area shows =Stored:= and the description or link. Storing the same link again moves it to the front of the list. Stored links last until you quit Orgstar; they aren't saved between sessions, as in Emacs. * IDs Org identifies headings across files with an =ID= property. Two commands manage it. | Command | Org function | Keys | |-----------------------+---------------------------------------+-----------------------------------| | Org ▸ Create ID | =org-id-get-create= | No default key | | Org ▸ Store ID Link | =org-id-get-create= + =org-id-store-link= | Doom =SPC m l i=; no key in Emacs or Mac | Create ID gives the heading at the caret an =ID= property if it doesn't have one. The ID is a new UUID in lower case, for example =6a3c2f9e-…=, as =org-id-uuid= makes them. Before the first heading, the property goes into the file-level property drawer. Store ID Link does the same, then stores an =id:= link to the heading with its title as the description. Before the first heading, the description is the =#+TITLE=, or the file name. If the caret is on a target or named element inside the entry, the link carries that search, as =id:…::search=, which mirrors =org-id-link-use-context=. =CUSTOM_ID= is a property you set yourself, with the property commands in [[file:04-outlines.org][Outlines]]. Link to it with =[[#name]]= in the same file or =[[file:other.org::#name]]= from another. Store Link uses it when the heading has one. * Targets and radio targets =<>= marks a place in the text that a link with the same words reaches: =[[target]]=. Store Link with the caret on a target stores a link to it. =<<>>= makes every other occurrence of its words in the file a link, matched case-insensitively and between non-word characters. Radio links are highlighted as links and exported as links to the target (see [[file:12-export.org][Export]]). Following one moves to the radio target. * Link abbreviations A =#+LINK:= line defines an abbreviation, as =org-link-abbrev-alist-local= does: #+BEGIN_SRC org ,#+LINK: gh https://github.com/%s ,#+LINK: search https://duckduckgo.com/?q=%h ,#+LINK: wiki https://en.wikipedia.org/wiki/ [[gh:orgmode/org-mode]] → https://github.com/orgmode/org-mode [[search:org tables]] → https://duckduckgo.com/?q=org%20tables [[wiki:Org-mode]] → https://en.wikipedia.org/wiki/Org-mode #+END_SRC In the template, =%s= is replaced by the text after the colon, =%h= by the same text percent-encoded, and a template with neither has the text appended. Function templates (=%(…)=) are not supported. Abbreviations from a =#+SETUPFILE= count too. When a key is defined twice, the first definition wins. * The backlinks pane View ▸ Show or Hide Backlinks shows a pane beside the editor of an org file. It has two sections: - *Links to* the heading at the caret, named after that heading. - *Links to this file*. Each row shows the linking heading and its file name; a link in the text before a file's first heading is listed under the file's name. Click a row to open it. The pane is shown by default and updates as you move the caret and edit. The pane looks at every org file in your sidebar folders, including unsaved changes in open buffers. A link counts when following it would lead to the heading or the file: - =id:= links to the heading's =ID=; - =file:= links and plain paths (=./=, =../=, =/=, =~/=) to the file, with no search option for the file section, or with =::*Title=, =::#custom-id= or =::Title= for a heading; - within the same file, =[[*Title]]=, =[[#custom-id]]= and =[[Title]]=. Links to targets, names and line numbers are not counted. A heading's links to itself are left out. * Inline images =org-toggle-inline-images= shows image links as images. | Preset | Key | |--------+----------------------------------------------| | Emacs | =C-c C-x C-v= | | Mac | Org ▸ Show or Hide Inline Images | | Doom | =C-c C-x C-v= | The echo area reports how many images are shown, or that inline display is off. A line shows an image when it holds nothing but a bracket link, without a description, to a file ending in =.png=, =.jpg=, =.jpeg=, =.gif=, =.svg=, =.webp=, =.tif=, =.tiff=, =.bmp=, =.heic= or =.avif= (in any case): #+BEGIN_SRC org [[file:images/diagram.png]] [[./photo.jpg]] #+END_SRC Relative paths are resolved against the file's folder. Web addresses and =attachment:= links are not shown as images. The link text is hidden while the image is shown, except on the line that holds the caret. ** Sizing An image is drawn at its own width, up to the width of the text area. To set a width, put =#+ATTR_ORG: :width= with a number of points among the keywords above the link: #+BEGIN_SRC org ,#+CAPTION: Network layout ,#+ATTR_ORG: :width 300 [[file:images/network.png]] #+END_SRC The height follows the image's proportions. =#+ATTR_HTML= and other exporters' attributes don't affect the editor. ** Showing images when a file opens The config key =org-startup-with-inline-images= (default =false=) shows images in every file when it opens. In a file, =#+STARTUP: inlineimages= or =#+STARTUP: noinlineimages= overrides it. * org-protocol store-link Orgstar handles =org-protocol://store-link= URLs, in the new form ~org-protocol://store-link?url=…&title=…~ and the old form =org-protocol://store-link:/URL/TITLE=. The URL is added to your stored links with the title as its description, and is also copied to the clipboard. Insert it with Insert Link. Setting up a browser bookmarklet, and =org-protocol://capture=, are in [[file:08-capture.org][Capture]]. * On iOS The iOS app follows links: tap a link in the reader. Org files open in the app, and web, mail and other files go to the system. The iOS editor shows inline images as the Mac does; the reader doesn't. In the editor, Store Link, Store ID Link and Insert Link… are in Commands, and on a hardware keyboard the Emacs keys run them; they work as described above, and stored links last until the app quits. =org-protocol://store-link= links opened on the device are stored and copied too. The backlinks pane is Mac only. See [[file:14-ios.org][iOS]].