Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>RelatiTreeNew to Visual Studio Code? Get it now.
RelatiTree

RelatiTree

booksakura

|
1 install
| (0) | Free
View and navigate related project files in a smart, customizable tree view based on filename patterns and groups.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

RelatiTree

RelatiTree adds a Related Files tree view to the Explorer sidebar. It shows the files related to the file you are currently editing (its service, style, test, …), plus file groups discovered by scanning the whole workspace — all driven by rules you define per workspace folder in a .relatedfilesrc.json (or .relatedfilesrc.jsonc) file.

Relationships are described with a single path-pattern language — {x} extracts, ${x} inserts:

{
  "groups": [
    {
      "id": "component",
      "match": "src/components/{dir...}/{name}.tsx",
      "files": [
        { "label": "Style", "path": "src/components/${dir}/${name}.module.css" },
        { "label": "Tests", "find": "test/**/${name}*.test.tsx" }
      ]
    }
  ]
}

Open src/components/user/Profile.tsx and the tree shows Profile.module.css and every matching test. Files that don't exist yet can be listed too and created in place, optionally from a template file.

Features

  • One pattern language — glob wildcards, {name} captures, and ${var|filter} templates in a single string. No separate extract regexes, no secondary filters.
  • Keyboard-first navigation — Open Related File… (Ctrl+Alt+R / Cmd+Alt+R) lists everything in a QuickPick; Open Alternate File (Ctrl+Alt+A / Cmd+Alt+A) jumps across a bidirectional cluster (impl ⇄ test ⇄ style).
  • Alternate clusters — mark a group with "alternate": true and opening any member shows the target and the other members. Reverse matches are round-trip verified, so they are exactly as reliable as forward ones.
  • Explain command — “why doesn’t my file show up?” Run RelatiTree: Explain Matching to see every group’s match trace: expanded patterns, compiled regexes, capture values, exclude hits, and per-entry file resolution.
  • Config diagnostics — JSON errors, schema violations, pattern syntax errors, undefined ${var} references, and workspace-scanning perf hazards appear in the Problems panel at the exact location, as you save.
  • Guided setup — no config yet? The tree offers to create one, pre-filled with a group skeleton derived from the file you have open (RelatiTree: Add Group for Active File…).
  • Sticky anchor — opening a related file from the tree or the QuickPick keeps the view anchored to the file you were navigating from (marked (anchored)), so the grouping doesn’t vanish under you. Any other editor switch re-anchors as usual.
  • Workspace groups — scan the whole workspace for target files (e.g. every *Controller.ts) and browse each one’s related files without opening it.
  • Static & dynamic entries — fixed templated paths (missing ones can be created via New File / New from Template) and workspace searches with per-file captured labels.
  • Display control & result limits — order groups with priority, hide empty sections with hideWhenEmpty, collapse noisy ones with collapsed. Large result sets are capped (default 100) with an explicit Show more (100 / 1,234) row — never silently.
  • Live updates — the tree reacts to file creates/deletes/renames, editor switches, and config saves, refreshing only the affected subtree.
  • Multi-root aware — each workspace folder has its own config; folders without one are simply skipped.

Getting started

Open any file and run RelatiTree: Add Group for Active File… — it creates .relatedfilesrc.jsonc at the workspace folder root with a commented template and a group skeleton derived from that file’s path. Or write the file yourself:

// .relatedfilesrc.jsonc — JSONC: comments and trailing commas are fine
{
  "$schema": "https://gitlab.com/booksakura/vscode-relatitree/-/raw/main/schemas/related-files.schema.json",
  "variables": { "srcDir": "src" },
  "groups": [
    {
      "id": "controller",
      "label": "Controller and its collaborators",
      "alternate": true,
      "match": "${srcDir}/controllers/{feature}Controller.ts",
      "files": [
        {
          "label": "Service",
          "path": "${srcDir}/services/${feature}Service.ts",
          "alwaysShow": true,
          "template": "templates/service.ts"
        },
        { "label": "Test", "path": "${srcDir}/test/${feature}Controller.test.ts" },
        { "label": "Views", "find": "${srcDir}/views/${feature|kebab}/**/*" }
      ]
    },
    {
      "id": "all-controllers",
      "label": "Every controller in the workspace",
      "scope": "workspace",
      "match": "${srcDir}/controllers/{feature}Controller.ts",
      "files": [
        { "label": "Test", "path": "${srcDir}/test/${feature}Controller.test.ts" }
      ]
    }
  ]
}

Open src/controllers/UserProfileController.ts and the Related Files view shows its Service, Test, and Views. Because the group is alternate, opening the Service or the Test shows the controller right back. The all-controllers group lists every controller in the workspace with the same sections under each.

If nothing shows up, run RelatiTree: Explain Matching (Active File) — it renders the full match trace of every group against the current file, and every config problem is also in the Problems panel.

The pattern language

Patterns match against the file path relative to the workspace folder (POSIX-style, e.g. src/foo/bar.ts), anchored at both ends. One string mixes three things:

Element Syntax Meaning
Glob * ** ? {a,b} Wildcards — matched, not captured.
Capture {name} Captures one path-segment portion into the variable name.
{name...} Captures across / boundaries (e.g. nested directories).
{name:regex} Capture constrained by a regular expression.
Template ${var} ${var\|filter} Inserts an already-known variable (expanded before matching).

Mnemonic: {x} extracts, ${x} inserts. Brace content that isn’t a valid capture form (e.g. {ts,tsx}) is glob alternation. \{ escapes a literal brace. A raw regular expression can be used as { "regex": "..." } inside a pattern array (named groups become variables), at the cost of scanning the whole workspace when used for searches.

match, find, and exclude each accept a single pattern or an array.

Configuration reference

Top level

Field Description
variables Config-wide name → value map, usable in all groups.
groups The group list (see below).

Groups

Field Description
id Unique identifier ([A-Za-z0-9_-]+). Also the display name when label is omitted.
label Display name shown in the tree.
scope "active" (default) — match the active editor file. "workspace" — scan the folder for every matching file.
match / exclude Path pattern(s) the target file must match / must not match. Captures in match become template variables.
alternate Treat the group as a bidirectional cluster (see below).
priority Display order among groups — higher shows first, ties keep config order.
hideWhenEmpty Hide the group when no entry has anything to show (resolved eagerly).
maxResults scope: "workspace" only: target files shown before Show more (default 100).
variables Group-level variables (override config-level ones).
files Related-file entries: static (path) or dynamic (find).

Static entries (path)

Field Description
label Description shown next to the file.
path Templated path (${var\|filter}), resolved against the workspace folder.
alwaysShow Show the entry even while the file doesn’t exist (with create actions).
template Templated path to a template file used by New from Template — the template’s content is expanded too.

Dynamic entries (find)

Field Description
label Section name (defaults to the first pattern).
find / exclude Path pattern(s) searched across the workspace folder. May use ${var} for match captures and {name} to capture per-file variables.
itemLabel Per-file label template — may use captures from find (e.g. "${variant}").
hideWhenEmpty Hide the section when nothing matches (costs an eager search).
maxResults Files shown before Show more (default 100).
collapsed Render the section initially collapsed.

Alternate (bidirectional) groups

With "alternate": true, a group becomes a cluster: opening any member shows the target file plus the other entries (the file you are on is never listed), and Open Alternate File (Ctrl+Alt+A) jumps between them.

Reverse matching is defined as a round trip — a file reverse-matches only if a target exists on disk such that opening it would have shown this file in that entry. Reverse entry points are static entries whose capture references use no filters and cover every capture of the match pattern; the match pattern itself must contain only literals and captures (no wildcards). Run Explain Matching to see each entry’s eligibility, and watch the Problems panel: an alternate flag that can never fire is warned about at load time.

Template expansion

${name} is replaced by the variable’s value; ${name|filter1|filter2} pipes it through filters. Templates may nest (${a${b}}), and \${ escapes a literal ${.

Variables are resolved most-specific-last:

  1. Built-ins: workspaceFolder (name), workspaceFolderPath, workspaceFolderFsPath, workspaceFolderUri
  2. Config-level variables
  3. Group-level variables
  4. Captures from the matched file’s path (and, for itemLabel, from find)

Available filters:

Filter Effect
upper / lower Whole-string case change.
upperfirst / lowerfirst Change only the first character.
camel, pascal, snake, kebab, constant, dot, path, sentence, title, train, swap, sponge, no Case conversions (via change-case-all).
slice:start[:end] String.prototype.slice semantics, e.g. ${name\|slice:0:-3}.
replace:/pattern/flags:replacement Regex replace (flags default to g).
replace:pattern:replacement[:flags] Literal-string replace.

Filter names are case-insensitive; unknown or malformed filters leave the value unchanged.

Commands & keybindings

Command Default keybinding Description
RelatiTree: Open Related File… Ctrl+Alt+R / Cmd+Alt+R QuickPick over the active file’s related files. Enter opens (missing static entries are created first); the ⧉ button opens to the side without closing the picker.
RelatiTree: Open Alternate File Ctrl+Alt+A / Cmd+Alt+A Jump across an alternate cluster. One candidate opens immediately; several go through a QuickPick.
RelatiTree: Explain Matching (Active File) — Live markdown document with every group’s match trace and all config problems. Also the ? button on the view title.
RelatiTree: Add Group for Active File… — Create the config (or append a group skeleton) for the file you have open.

Tree actions: Open, Open to the Side (inline ⧉), Open and Set as Anchor, Copy Path / Relative Path, Reveal in Explorer View / OS File Manager, New File / New from Template on missing static entries, Open All Related Files / Open All, per-node Refresh, and Open Configuration (jumps to the group’s definition). Re-anchor to Active Editor sits on the Active File row while the anchor is detached.

Notes

  • Opening from the tree or the QuickPick keeps the anchor; Open Alternate File moves it — jumping means your work moved there.
  • .relatedfilesrc.json and .relatedfilesrc.jsonc are both recognized (in that precedence order) and parsed with jsonc-parser — comments and trailing commas are supported either way. schemas/related-files.schema.json (generated from the source of truth) provides editor autocompletion/validation.
  • A broken config never takes the tree down: the affected folder shows a clickable Configuration error row, details go to the Problems panel, and other folders keep working.
  • Workspace searches are bounded: a hard scan cap of 5,000 candidates per pattern plus a display cap (default 100, maxResults) with an explicit Show more row. Patterns that would scan the entire workspace are flagged in the Problems panel when you save the config.
  • Saving the config reloads the tree and re-publishes diagnostics automatically — no manual refresh needed.

Development

npm install
npm run compile          # type-check, lint, and bundle to dist/extension.js
npm run watch            # esbuild + tsc in watch mode
npm test                 # compile + lint + vscode-test (src/test/**/*.test.ts)
npm run generate-schema  # regenerate schemas/related-files.schema.json from the Zod schema

Press F5 in VS Code to launch an Extension Development Host with the extension loaded. The examples/ folder is a self-contained sample workspace (examples/examples.code-workspace) exercising every config feature.

Design records live in docs/redesign/ (pattern language & schema, QuickPick, empty-state guides, display control, alternate).

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft