You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Repo and compare browsers can't go below the first folder level, and Give/Take/X throw on the render thread or create stray src/src/... folders #440
The file browsers have two path-handling defects in ProjectDirector/ProjectDirector.cs.
(a) The compare browser never recognises a directory.
formatPath (~line 2233) appends a directory separator to directory entries, but RelativePath.Create strips it again. A probe showed RelativePath.Create("only/") has WeakString == "only".
So the directories filter in ShowCompareBrowser (~line 1888, EndsWith(DirectorySeparatorChar)) is always empty, and every folder is listed as a file.
For a folder that exists in only one repo:
the Give/Take arrow calls File.Copy on a directory, and
"X" calls File.Delete on it.
Both throw UnauthorizedAccessException: Access to the path '.../A/only' is denied. The exception is uncaught and is raised inside the render callback.
(b) The current folder is added to the path twice.
formatPath removes only LocalPath from each entry, so entries are relative to the repo root and already include BrowsePath.
The code then combines those entries with BrowsePath again, for example:
Probe: a repo containing src/Inner/ and src/a.cs, after clicking src:
The repo browser checks <root>/src/src/Inner, finds nothing, and shows Inner as a file. You can never navigate below the first level, and "Propagate" is offered on folders.
Compare navigation goes to src/src/Inner, so the listing is empty.
"Give" on a file runs File.Copy(<A>/src/src/a.cs, ...). The source doesn't exist, so it throws on the render thread.
"Give" on a folder runs Directory.CreateDirectory(<B>/src/src/Inner), which quietly creates a stray folder in the other repo.
These were verified with MSTest probes against a local build of current main. The browser methods are private ImGui code, so their path expressions were copied into the probe verbatim.
Why it matters
Browsing and comparing repo contents is a core feature, and today it only works at the top level. The failures either crash the frame or write junk directories into a sibling repo.
Suggested fix / acceptance criteria
Decide whether an entry is a directory with Directory.Exists(Path.Combine(LocalPath, entry)), or keep a separate list of directories, instead of relying on a trailing separator that RelativePath normalises away.
Combine entries with LocalPath only, since they already include BrowsePath. Navigation should go to the entry path itself.
Route directory actions to Directory.* APIs and catch IO errors so they go to the log instead of escaping the render loop.
Extract the listing and classification into a static helper, in the style of FilePropagation, and unit-test nested navigation and copying.
Priority: High. Browsing and comparing repos, a core feature, only works at the top level. Give/Take/X either throw an uncaught exception inside the render callback or quietly create stray src/src/... folders in a sibling repository.
Area / suggested owner:ShowRepoBrowser / ShowCompareBrowser / formatPath in ProjectDirector.cs.
Duplicates / in progress: None found. No open PR covers this.
Next step: Fix (b), the double BrowsePath combine, first, because it causes the stray writes into other repos. Then classify directories with Directory.Exists instead of a trailing separator, and wrap the IO actions so failures are logged instead of escaping the frame. Extracting the path logic into a testable static helper, as the issue proposes, is what lets nested navigation be regression-tested.
Activity
matt-edmondson commentedon Sep 27, 2026
Triage
src/src/...folders in a sibling repository.ShowRepoBrowser/ShowCompareBrowser/formatPathinProjectDirector.cs.BrowsePathcombine, first, because it causes the stray writes into other repos. Then classify directories withDirectory.Existsinstead of a trailing separator, and wrap the IO actions so failures are logged instead of escaping the frame. Extracting the path logic into a testable static helper, as the issue proposes, is what lets nested navigation be regression-tested.Generated by Claude Code
Classify browser entries from the repository root