Skip to content

Commit 178687c

Browse files
committed
Prune deleted local files from MRU history when listing
When building the MRU picker list, remove non-selectable entries (missing local paths, blank inputs) from go.toml and save once so later lists avoid repeated filesystem checks.
1 parent 4d00124 commit 178687c

3 files changed

Lines changed: 72 additions & 10 deletions

File tree

src/Tests/RunHistoryTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,44 @@ public void List_skips_missing_local_paths_keeps_remote_refs()
237237
var listed = RunHistory.List(path);
238238
Assert.Single(listed);
239239
Assert.Equal("still/here", listed[0].Input);
240+
241+
// Deleted local entries are pruned from storage (single save after list build).
242+
var stored = SettingsStore.Load(path);
243+
Assert.Single(stored.History!);
244+
Assert.Equal("still/here", stored.History![0].Input);
245+
}
246+
finally
247+
{
248+
TryDelete(path);
249+
}
250+
}
251+
252+
[Fact]
253+
public void List_prunes_blank_and_missing_paths_in_one_save()
254+
{
255+
var path = NewSettingsPath();
256+
try
257+
{
258+
var missing1 = Path.Combine(Path.GetTempPath(), "go-hist-m1-" + Guid.NewGuid().ToString("N"), "a.cs");
259+
var missing2 = Path.Combine(Path.GetTempPath(), "go-hist-m2-" + Guid.NewGuid().ToString("N"), "b.cs");
260+
SettingsStore.Save(new Settings
261+
{
262+
History =
263+
[
264+
new HistoryEntry { Input = missing1, LastUsedUtc = DateTimeOffset.UtcNow, UseCount = 3 },
265+
new HistoryEntry { Input = " ", LastUsedUtc = DateTimeOffset.UtcNow, UseCount = 1 },
266+
new HistoryEntry { Input = "keep/ref", LastUsedUtc = DateTimeOffset.UtcNow, UseCount = 2 },
267+
new HistoryEntry { Input = missing2, LastUsedUtc = DateTimeOffset.UtcNow, UseCount = 4 },
268+
],
269+
}, path);
270+
271+
var listed = RunHistory.List(path);
272+
Assert.Single(listed);
273+
Assert.Equal("keep/ref", listed[0].Input);
274+
275+
var stored = SettingsStore.Load(path);
276+
Assert.Single(stored.History!);
277+
Assert.Equal("keep/ref", stored.History![0].Input);
240278
}
241279
finally
242280
{

src/go/RunHistory.cs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,48 @@ public static class RunHistory
1616
/// <summary>
1717
/// Loads history from <paramref name="settingsPath"/> (default: root go.toml),
1818
/// ordered most-used first, then most-recently-used, then alphabetically.
19+
/// Drops non-selectable entries (e.g. deleted local files) from storage so later
20+
/// lists skip the filesystem checks; saves at most once after pruning.
1921
/// </summary>
2022
public static IReadOnlyList<RunHistoryEntry> List(string? settingsPath = null)
2123
{
2224
var settings = SettingsStore.Load(settingsPath);
2325
if (settings.History is not { Count: > 0 })
2426
return [];
2527

26-
return settings.History
27-
.Where(static h => !string.IsNullOrWhiteSpace(h.Input))
28-
.Where(static h => IsSelectable(h.Input))
29-
.Select(static h => new RunHistoryEntry(
28+
var pruned = false;
29+
var listed = new List<RunHistoryEntry>(settings.History.Count);
30+
for (var i = settings.History.Count - 1; i >= 0; i--)
31+
{
32+
var h = settings.History[i];
33+
if (string.IsNullOrWhiteSpace(h.Input) || !IsSelectable(h.Input))
34+
{
35+
settings.History.RemoveAt(i);
36+
pruned = true;
37+
continue;
38+
}
39+
40+
listed.Add(new RunHistoryEntry(
3041
h.Input,
3142
h.LastUsedUtc == default ? DateTimeOffset.MinValue : h.LastUsedUtc,
32-
h.UseCount <= 0 ? 1 : h.UseCount))
33-
.OrderByDescending(static e => e.UseCount)
34-
.ThenByDescending(static e => e.LastUsedUtc)
35-
.ThenBy(static e => e.Display, StringComparer.OrdinalIgnoreCase)
36-
.ToList();
43+
h.UseCount <= 0 ? 1 : h.UseCount));
44+
}
45+
46+
if (pruned)
47+
SettingsStore.Save(settings, settingsPath);
48+
49+
listed.Sort(static (a, b) =>
50+
{
51+
var byCount = b.UseCount.CompareTo(a.UseCount);
52+
if (byCount != 0)
53+
return byCount;
54+
var byTime = b.LastUsedUtc.CompareTo(a.LastUsedUtc);
55+
if (byTime != 0)
56+
return byTime;
57+
return StringComparer.OrdinalIgnoreCase.Compare(a.Display, b.Display);
58+
});
59+
60+
return listed;
3761
}
3862

3963
/// <summary>

src/go/help.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Usage: [command] [arguments...] [options...] [-h|--help] [--version]
44
Runs a file-based .NET app from a .cs entrypoint.
55

66
Arguments:
7-
[0] <string?> Path to an existing .cs file or remote ref (owner/repo[@ref][:path]). When omitted in an interactive terminal, selects from previous runs (MRU) then prompts for optional app args; otherwise shows help.
7+
[0] <string?> Path to an existing .cs file or remote ref (owner/repo[@ref][:path]). When omitted, selects from previous runs (MRU) then prompts for optional app args.
88
[1] <string[]> Arguments to pass to the app.
99

1010
Options:

0 commit comments

Comments
 (0)