Commit Graph
9 Commits
Author SHA1 Message Date
maxandClaude Opus 5 8eae35af3e Stand the pin upright once a tab is pinned
The pinned state and the hover affordance drew the same slanted pin, so the
only difference was opacity. Rotating the pinned one to vertical separates
"this is pinned" from "click to pin", and the short transition reads as the
toggle landing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:37:57 +02:00
maxandClaude Fable 5.1 c6bd7485f9 Defaults: 3px row spacing, project name off
The left border already says which project a row belongs to, so the
file name gets the whole row by default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0169iPWwKHZoBTNN9qwXiwqk
2026-09-08 19:07:41 +02:00
maxandClaude Opus 5 e60df4bdf6 Restore the code spans a shell heredoc ate in the README
Also corrects the showDirectory entry, which is an enum now, and states
plainly that drag-to-dock is impossible in a webview view.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:53:18 +02:00
maxandClaude Opus 5 2865ced2f0 Colour files by project in the Explorer, Open Editors and tabs
A fair question about the custom list: what does it buy over the built-in
Open Editors view? Most of the answer was the project colours — and those do
not need a custom view. A FileDecorationProvider puts them on the built-in
Open Editors view, the Explorer and the tabs, which keeps everything native
that view already does, including the drag-to-dock this list cannot offer.

verticalTabs.decorateFiles is off / color / colorAndBadge, defaulting to
color. Badges are the two characters a FileDecoration allows, taken from the
first and last segments of the project name so that Acme.Shop.Client and
Acme.Shop.Server read as AC and AS rather than colliding.

Two limits are documented rather than papered over: there is no way to
decorate only the Open Editors view, so the Explorer is coloured too; and Git
decorates modified files with only one colour winning, so a dirty file can
show Git's colour instead of its project's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:52:42 +02:00
maxandClaude Opus 5 925e55d619 Give the file name the row, and stop repeating the project
On a real project the name lost the width fight and the trailing text read
"MyGame.Runtime MyGame.Runtime" — the directory and the project were the
same string, printed twice.

- The detail text now has a shrink factor of 1000 against the name's 1, plus
  a 45% cap, so it gives up its width first and the name is the last thing to
  ellipsize.
- A directory that already begins with the project name says everything the
  project name would, so only one of the two is shown.
- verticalTabs.showDirectory became never / duplicates / always, defaulting
  to duplicates: width goes to a directory only when two open tabs share a
  file name, which is the usual reason to want it. Turning showProject off
  as well gives the name the whole row.
- The trailing text is composed in the extension now rather than the webview,
  so the deduplication is unit-testable and there is one implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:42:14 +02:00
maxandClaude Opus 5 95799c6353 Update the README for the drawn list
The colour is a left border now, not a tinted icon; pinning is one toggle;
row spacing and border width are settings; and file-type icons are gone,
which is worth stating plainly along with the reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:35:01 +02:00
maxandClaude Opus 5 cf168b2e75 Draw the tab list as a webview, VS-style
A tree view row cannot be styled: no border, no spacing, and a long file
name gets middle-ellipsized in a narrow strip — which on a real project left
"ClientDogSurger...nionBehaviour.cs" and hid the project text entirely.
Drawing the rows means controlling all of it.

- A coloured left border per project instead of a tinted icon, so the file
  icon slot is free and the name gets the width. The border uses
  var(--vscode-verticalTabs-projectN): VS Code injects every contributed
  theme colour into a webview, so overrides in colorCustomizations still
  apply and nothing is hardcoded.
- The name is split into stem and extension, and only the stem ellipsizes,
  so ".cs" survives on a long name in a narrow view.
- Configurable row spacing and border width, a rule under the pinned block,
  a dirty dot that the close button replaces on hover, italics for preview
  and for tabs that cannot be focused.
- Selection, arrow/Home/End/Enter/Delete keys, middle-click to close, and an
  HTML context menu, since contributes.menus does not reach webview rows.
- Clicking a webview row posts nothing rather than asking for an open that
  would silently do nothing.

Actions moved to actions.ts so the wiring, the view and the tests share one
implementation; extension.ts is now just registration. The per-row commands
are gone — rows act through webview messages — and the palette keeps
close / closeOthers / togglePin acting on the active editor.

Verified in a browser harness at side-bar width: all twelve project colours
resolve, rows stay a consistent 24px, and click, pin, close, middle-click,
keyboard and both context-menu variants post the right intents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:34:26 +02:00
maxandClaude Opus 5 2e9a43f78b Fix the pin toggle, stale selection, and project detection in Unity repos
Three problems visible on a real project:

- The inline pin button showed twice on every unpinned row: the `when`
  clauses matched /pinned/ and /unpinned/, and "unpinned" contains "pinned".
  Context values now use unambiguous `pin:on` / `pin:off` tokens, and both
  commands call one togglePin — the pair exists only so the button's icon can
  reflect the current state.
- The list selected the tab you just left. followActiveTab read `isActive`
  from the entry snapshot, and after a refresh the tree has not necessarily
  asked for children yet, so it matched against the previous build. It now
  rebuilds the list and compares against the live active tab.
- Every file in a Unity repo resolved to an arbitrary project. Unity generates
  one .csproj per assembly into the repo root, and the walk took whichever
  readDirectory happened to return first. Matches are now sorted, a project
  file named after its directory wins, and .asmdef — which lives in the
  assembly's own directory and is what actually defines a Unity assembly — is
  a default marker, so it is found before reaching the root.

Palette widened from 8 to 12 hues, since a hash-assigned colour collides more
often than it looks like it should.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:24:36 +02:00
maxandClaude Opus 5 7e104450e8 Vertical Tabs: open editors as a project-coloured flat list
For working with the tab bar off, where a side list is the tab bar. VS Code's
Open Editors view already does pinning; what it does not do is colour by
project, and it is a tree rather than a flat list.

- A Tabs view in the Explorer: one row per open editor, no group nodes. A
  TreeDataProvider whose items have no children renders as a list, since
  there is no separate list API.
- Each row's icon is tinted by the project containing the file — the nearest
  .csproj/.fsproj/.vbproj, package.json, Cargo.toml, go.mod, pyproject.toml,
  pom.xml or build.gradle above it, configurable. The colour comes from a
  hash of the project name, so a project keeps its colour across sessions
  rather than depending on the order tabs happened to open in. Eight
  contributed theme colours, all overridable.
- Sort by open order, project (so the colours run in blocks), or file name,
  with pinned tabs lifted to the top.
- Close, close others (keeping pinned), pin/unpin, copy path, reveal.
- The list follows the active editor.

Two API limits shape this, both covered by tests:

- Nothing can activate an arbitrary tab. A file-backed tab is focused by
  re-opening its resource in its own group, which handles text, diffs,
  notebooks and custom editors. Webview tabs have no resource, so they are
  listed and marked as unfocusable instead of pretending.
- Only the *active* editor can be pinned, so pinning another row focuses it
  first.

Commands act on live vscode.Tab objects rather than the row snapshots handed
to them. The first cut compared against a snapshot's isPinned and so silently
did nothing on unpin, and read the provider's cached list, which is empty
until the tree has been rendered.

Also worth recording, both found by the tests: VS Code moves a pinned tab to
the front of its group, so `open` order shows pinned first regardless of the
pinnedFirst setting; and closeAllEditors leaves pinned editors open, so test
cleanup closes through the tab API instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:13:42 +02:00