LazyVim/Q/In LazyVim, how can I open a Markdown link with a keyboard shortcut?
In LazyVim, how can I open a Markdown link with a keyboard shortcut?
My Answer
What's a LazyVim Keyshort that uses the system to follow a url under the cursor? card
What's a LazyVim Keyshort that follows a relative markdown link 1.) in current file 2.) in a split, 3.) in a new tab? card
1. What's a LazyVim Keyshort that follows a relative markdown link with the LSP, and 2. how do you go back 2. and forth after following it, and 4. how do you get a list of references to the destination? card
AI Answer
- Short answer: there are two keys, and the target decides which one.
gxhands the target to the operating system — the right key for anhttpURL, which lands in the default browser.gdfollows the link inside the editor and is the better key for a link to another file in the same repository: it fires from anywhere on the link, resolves a target with no extension, and jumps to the exact heading when the link carries a#anchor. Link target gxgfgdhttps://…default browser tries to fetch it as a file nothing ./file.mdthe Mac app bound to .mdopens it, destination only opens it, anywhere on the link ./file.md#headingfails fails lands on the heading ./file(no extension)fails needs suffixesadd=.mdresolves to file.mddestination with a space truncated fails resolves in <…>or%20formgx— hand the target to the system- Stock nvim binds
gxin normal and visual mode as a core default. LazyVim does not rebind it; it only relabels it "Open with system app" in nvim/Plugin/which-key.nvim. Answer/Official from :help gx. - The mapping collects the target at the cursor and passes it to
vim.ui.open, which shells out toopenon macOS. That is the whole story:gxnever opens anything in the current editor. - The
markdown_inlinetreesitter highlights query tags the entire[text](destination)node with its destination, sogxfires from the label as readily as from inside the parentheses. It needs treesitter highlighting live on the buffer, which the Markdown extra provides. - Two consequences worth knowing for a relative link: the raw path goes to
openverbatim, so a.mdfile opens in whatever app macOS has bound to.mdrather than in the buffer; and that path is resolved against the working directory, not against the directory of the file being edited. - A language server advertising
textDocument/documentLinkwould take priority over the treesitter path. Marksman does not advertise it, so on a Markdown buffer here the treesitter path is always the one that runs.
- Stock nvim binds
gf— follow a file path in the editor- Plain vim, no plugin involved:
gfedits the filename under the cursor,<C-w>fopens it in a split,<C-w>gfin a new tab, andgFjumps to a line number trailing the path. - Unlike
gx, the cursor must sit on the destination inside the parentheses. On the link label,gfgrabs the label word and fails. - Resolution runs through
path, which defaults to.,,— the leading.is the directory of the current file, so an ordinary relative link resolves the way the Markdown means it. - The gaps are real:
suffixesaddis empty for Markdown, so an extensionless./filefails until it is set to.md; and a destination containing a space never resolves, with or without the<…>escape, because the filename is read throughisfname, which stops at the space.
- Plain vim, no plugin involved:
gd— follow the link with the language server- The LazyVim/plugins/extras/lang/markdown extra installs the Marksman language server, and LazyVim binds
gdto go-to-definition for any server advertisingdefinition. Marksman advertisesdefinitionandreferences, sogdandgrboth work on a Markdown buffer. Answer/Official from the Marksman README. - This is the strongest of the three for an in-repository link. It fires from anywhere on the link, follows
./target.md#some-headingto the heading line rather than the top of the file, resolves an extensionless./baretobare.md, and handles a spaced destination written either<./My Page.md>or./My%20Page.md. A raw unescaped space is not a link at all, so nothing follows it. grlists references to the destination.<C-o>returns from the jump and<C-i>moves forward again — see vim/Keyshort/Jump/Back and Forward.- Marksman only resolves cross-file links inside a project, meaning a Git repository or a directory holding a
.marksman.toml. It finds that project by walking up from the file, not from the working directory, so a single note opened from anywhere still resolves — a garden that is neither a repository nor holds a.marksman.tomlis the case that silently returns nothing. Opening from the root withnvim .is a separate habit, and what it buys is the pickers searching the whole garden. - When
gddoes nothing,<leader>clshows the attached clients and:Masonshows whether Marksman is installed — see LazyVim/Keyshort/LSP/Navigation.
- The LazyVim/plugins/extras/lang/markdown extra installs the Marksman language server, and LazyVim binds
When the built-ins are not enough
- Short answer: there are two keys, and the target decides which one.