Skip to content

Add hyperlinks language server - #6949

Merged
MrSubidubi merged 10 commits into
zed-industries:mainfrom
krawitzzZ:feat/hyperlinks
Aug 21, 2026
Merged

Add hyperlinks language server#6949
MrSubidubi merged 10 commits into
zed-industries:mainfrom
krawitzzZ:feat/hyperlinks

Conversation

@krawitzzZ

@krawitzzZ krawitzzZ commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Hyperlinks, an extension that turns text matching user-defined regex patterns into clickable links in the editor — e.g. ISSUE-123 → your issue tracker, #42 → a GitHub issue. It's a port of the VS Code extension dlevs/vscode-pattern-links to Zed.

How it works

Zed renders links returned by language servers through the LSP textDocument/documentLink request (added in zed#56011, enabled by default). The extension provides a tiny language server that scans open documents for the configured regex rules and returns a DocumentLink for each match, with the target URL built from a template ($0 = whole match, $1, $2, … = capture groups; \$ for a literal $). Matching semantics mirror the upstream VS Code extension (JS RegExp).

The server additionally reports a custom hyperlink LSP semantic token for every match, so matched text can be visually highlighted (see Highlighting).

Why the language server is downloaded, not bundled

Per the publishing guidelines, the extension does not ship the language server. Instead, the WASM extension downloads it at runtime from a pinned GitHub release of the separate zed-hyperlinks-server repo (main.js asset, version pinned in src/lib.rs), caches it under the extension's work dir, cleans up older cached versions, and runs it with Zed's bundled Node (node_binary_path). Download failures surface via set_language_server_installation_status(Failed).

Configuration

There is no per-extension settings UI, so rules live under the language server's settings:

{
  "lsp": {
    "hyperlinks": {
      "settings": {
        "hyperlinkRules": [
          {
            "linkPattern": "ISSUE-\\d+",
            "linkTarget": "https://myorg.atlassian.net/browse/$0"
          },
          {
            "linkPattern": "#(\\d+)",
            "linkTarget": "https://github.com/my-org/my-repo/issues/$1",
            "languages": ["markdown", "plaintext"]
          }
        ]
      }
    }
  }
}

Per-rule fields:

  • linkPattern (required)
  • linkTarget (required)
  • linkPatternFlags (optional JS regex flags; g always applied)
  • languages (optional list of LSP languageIds to scope the rule; empty = all)

Highlighting

Zed doesn't style document links on its own, so matches are clickable but look like ordinary text by default. The server therefore emits a custom hyperlink semantic token per match (multi-line matches are split into one token per line, as LSP requires). Users opt in via settings.json by enabling semantic tokens (off by default) and adding a rule for the hyperlink token type:

{
  "semantic_tokens": "combined",
  "global_lsp_settings": {
    "semantic_token_rules": [
      { "token_type": "hyperlink", "underline": true, "foreground_color": "#4c9df3" }
    ]
  }
}

The extension intentionally does not ship default semantic token rules: it provides a language server (not a language), and per Zed's docs shipping rules that way can override/break other language servers' configuration. Styling is left to the user's semantic_token_rules.

Note on supported languages

Zed has no "all languages" wildcard for extension-provided language servers, so the server is attached to an explicit list of common languages in extension.toml (Plain Text, Markdown, and popular programming languages). This is the closest equivalent to the VS Code extension's "all languages" default; more can be added on request.

Testing

  • Installed and tested locally as a dev extension (links appear and open on Cmd/Ctrl-click; matches highlight once semantic_tokens + a hyperlink rule are set).

  • Language server (node --test, 31 tests): substitution, rule normalization, offset/position math, link computation, semantic-token encoding (single-line, delta-encoded multi-match, multi-line splitting, language filtering), plus end-to-end stdio LSP sessions covering documentLink and semanticTokens/full.

  • Extension: cargo test for the version/path helpers; cargo build --target wasm32-wasip1 passes.

  • I've read CONTRIBUTING.md and followed the relevant guidance for adding or updating my extension.

Turns text matching regex rules into clickable links via a language
server implementing textDocument/documentLink, configured through the
hyperlinkRules array in Zed LSP settings.
Adds semantic-token highlighting of matches.
@cla-bot

cla-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @krawitzzZ on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@krawitzzZ

Copy link
Copy Markdown
Contributor Author

We require contributors to sign our Contributor License Agreement, and we don't have @krawitzzZ on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed label Jul 24, 2026
@cla-bot

cla-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

@MrSubidubi MrSubidubi changed the title Feat/hyperlinks Add hyperlinks language server Jul 27, 2026

@MrSubidubi MrSubidubi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this!

Please make sure your extension fulfills the extension publishing prerequisites. Particularly, you will need to update your extension ID as outlined in the documentation. Once you did the necessary updates, please update everything related here. Thanks!

@krawitzzZ
krawitzzZ requested a review from MrSubidubi July 27, 2026 17:52
@krawitzzZ

Copy link
Copy Markdown
Contributor Author

Thanks for this!

Please make sure your extension fulfills the extension publishing prerequisites. Particularly, you will need to update your extension ID as outlined in the documentation. Once you did the necessary updates, please update everything related here. Thanks!

Thanks for the review!

I've renamed the extension into hyperlinks-lsp to be consistent with similar extensions

@MrSubidubi MrSubidubi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please elaborate why https://github.com/krawitzzZ/zed-hyperlinks/blob/cc667162dfc90f4304744280b6d412290db6b4e9/src/lib.rs#L42-L51 is needed?

Also, you are invoking a JS language server - please publish that to NPM as described in our extension publishing prerequisites - we'll soon clarify this.

Also, you seem to use the same settings for both the initialization as well as the workspace settings request, which seems odd.

@krawitzzZ

Copy link
Copy Markdown
Contributor Author

Could you please elaborate why https://github.com/krawitzzZ/zed-hyperlinks/blob/cc667162dfc90f4304744280b6d412290db6b4e9/src/lib.rs#L42-L51 is needed?

Also, you are invoking a JS language server - please publish that to NPM as described in our extension publishing prerequisites - we'll soon clarify this.

Also, you seem to use the same settings for both the initialization as well as the workspace settings request, which seems odd.

Thanks for the review!

sanitize_windows_path — that was a workaround for the WASI current_dir() leading-/ issue on Windows (zed#15004). Zed now strips that prefix when spawning language servers (zed#44477), so the helper is no longer needed and I've removed it.

NPM — the language server is now published to npm as hyperlinks-lsp, and the extension installs it via npm_package_latest_version / npm_install_package (same pattern as the built-in HTML/Astro extensions) instead of downloading a GitHub release asset.

Init vs workspace settings — that was incorrect. They now map separately:

  • language_server_initialization_optionslsp.hyperlinks.initialization_options
  • language_server_workspace_configurationlsp.hyperlinks.settings

Rules stay under settings.hyperlinkRules as documented; Zed already pushes those through workspace/didChangeConfiguration after initialize.

I've updated the submodule to 0.0.4 accordingly.

@krawitzzZ
krawitzzZ requested a review from MrSubidubi August 21, 2026 11:54

@MrSubidubi MrSubidubi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@MrSubidubi
MrSubidubi added this pull request to the merge queue Aug 21, 2026
Merged via the queue into zed-industries:main with commit 5959b83 Aug 21, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants