Skip to content

Commit 7384e5b

Browse files
committed
Improve MRU gist labels as owner/filename with collision refs
Render gist history entries like GitHub (owner/filename) instead of the full host URL. Persist the resolved entry file on HistoryEntry so labels survive cache cleanup. When multiple gists share the same owner and file, disambiguate with owner/shortsha:file using the first 7 chars of the gist id. Document multi-file gist :path selection and the new MRU labeling.
1 parent 178687c commit 7384e5b

4 files changed

Lines changed: 398 additions & 5 deletions

File tree

readme.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ With an empty history, or when stdin is redirected / non-interactive (CI, pipes)
5454
Local paths that no longer exist are dropped from the picker; remote refs stay listed
5555
even when their download bundle is gone (the next run re-downloads as usual).
5656

57+
Gists are labeled like GitHub’s UI as `owner/filename` (for example `kzu/run.cs`)
58+
instead of the full host URL. When two or more history entries share the same
59+
owner and file name, the picker switches to a short ref form with the first
60+
seven characters of the gist id: `owner/shortsha:file` (for example
61+
`kzu/0ac826d:run.cs`).
62+
5763
```console
5864
# Interactive: pick a previous run, then optional args
5965
dnx go
@@ -111,9 +117,15 @@ dnx go -- kzu/sandbox@v1.2.3:src/hello.cs
111117
# Full host (GitHub, Gist, GitLab, Azure DevOps)
112118
dnx go -- github.com/kzu/sandbox@main:hello.cs
113119
dnx go -- gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381
120+
# Multi-file gist: pick a specific entry file with :path (same as repos)
121+
dnx go -- gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:run.cs
114122
dnx go -- gitlab.com/kzu/runcs/-/blob/main/program.cs
115123
```
116124

125+
Without `:path`, a gist (or repo) defaults to `program.cs` when present, otherwise
126+
the first top-level `.cs` file. Use `:filename.cs` when a multi-file gist should
127+
run a different entry point.
128+
117129
The first argument is resolved by first checking if it is a local file (`File.Exists`).
118130
If not, it falls back to parsing it as a remote ref (`owner/repo[@ref][:path]`).
119131

src/Tests/RunHistoryTests.cs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,236 @@ public void ParseArgsLine_roundtrips_via_ToRunInputs_as_shipped_path()
315315
Assert.Equal(["arg1", "arg2"], appArgs);
316316
}
317317

318+
[Fact]
319+
public void List_formats_gists_as_owner_filename_from_path_suffix()
320+
{
321+
var path = NewSettingsPath();
322+
try
323+
{
324+
SettingsStore.Save(new Settings
325+
{
326+
History =
327+
[
328+
new HistoryEntry
329+
{
330+
Input = "gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:run.cs",
331+
LastUsedUtc = DateTimeOffset.UtcNow,
332+
UseCount = 1,
333+
},
334+
new HistoryEntry
335+
{
336+
Input = "kzu/sandbox",
337+
LastUsedUtc = DateTimeOffset.UtcNow,
338+
UseCount = 1,
339+
},
340+
],
341+
}, path);
342+
343+
var listed = RunHistory.List(path);
344+
var gist = listed.Single(e => e.Input.Contains("0ac826dc", StringComparison.Ordinal));
345+
Assert.Equal("kzu/run.cs", gist.Display);
346+
347+
var repo = listed.Single(e => e.Input == "kzu/sandbox");
348+
Assert.Equal("kzu/sandbox", repo.Display);
349+
}
350+
finally
351+
{
352+
TryDelete(path);
353+
}
354+
}
355+
356+
[Fact]
357+
public void List_formats_gists_as_owner_filename_from_cached_entry()
358+
{
359+
var path = NewSettingsPath();
360+
try
361+
{
362+
SettingsStore.Save(new Settings
363+
{
364+
History =
365+
[
366+
new HistoryEntry
367+
{
368+
Input = "gist.github.com/kzu/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
369+
LastUsedUtc = DateTimeOffset.UtcNow,
370+
UseCount = 1,
371+
Entry = "hello.cs",
372+
},
373+
],
374+
}, path);
375+
376+
var listed = RunHistory.List(path);
377+
Assert.Single(listed);
378+
Assert.Equal("kzu/hello.cs", listed[0].Display);
379+
}
380+
finally
381+
{
382+
TryDelete(path);
383+
}
384+
}
385+
386+
[Fact]
387+
public void List_disambiguates_same_owner_file_with_short_gist_id()
388+
{
389+
var path = NewSettingsPath();
390+
try
391+
{
392+
SettingsStore.Save(new Settings
393+
{
394+
History =
395+
[
396+
new HistoryEntry
397+
{
398+
Input = "gist.github.com/kzu/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
399+
LastUsedUtc = DateTimeOffset.UtcNow,
400+
UseCount = 2,
401+
Entry = "run.cs",
402+
},
403+
new HistoryEntry
404+
{
405+
Input = "gist.github.com/kzu/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
406+
LastUsedUtc = DateTimeOffset.UtcNow,
407+
UseCount = 1,
408+
Entry = "run.cs",
409+
},
410+
new HistoryEntry
411+
{
412+
Input = "gist.github.com/other/cccccccccccccccccccccccccccccccc",
413+
LastUsedUtc = DateTimeOffset.UtcNow,
414+
UseCount = 1,
415+
Entry = "run.cs",
416+
},
417+
],
418+
}, path);
419+
420+
var listed = RunHistory.List(path);
421+
var kzuA = listed.Single(e => e.Input.Contains("aaaaaaaa", StringComparison.Ordinal));
422+
var kzuB = listed.Single(e => e.Input.Contains("bbbbbbbb", StringComparison.Ordinal));
423+
var other = listed.Single(e => e.Input.Contains("cccccccc", StringComparison.Ordinal));
424+
425+
Assert.Equal("kzu/aaaaaaa:run.cs", kzuA.Display);
426+
Assert.Equal("kzu/bbbbbbb:run.cs", kzuB.Display);
427+
// Different owner — no disambiguation needed even though file name matches.
428+
Assert.Equal("other/run.cs", other.Display);
429+
}
430+
finally
431+
{
432+
TryDelete(path);
433+
}
434+
}
435+
436+
[Fact]
437+
public void List_gist_without_known_file_keeps_raw_input()
438+
{
439+
var path = NewSettingsPath();
440+
try
441+
{
442+
var input = "gist.github.com/kzu/dddddddddddddddddddddddddddddddd";
443+
SettingsStore.Save(new Settings
444+
{
445+
History =
446+
[
447+
new HistoryEntry
448+
{
449+
Input = input,
450+
LastUsedUtc = DateTimeOffset.UtcNow,
451+
UseCount = 1,
452+
},
453+
],
454+
}, path);
455+
456+
var listed = RunHistory.List(path);
457+
Assert.Single(listed);
458+
Assert.Equal(input, listed[0].Display);
459+
}
460+
finally
461+
{
462+
TryDelete(path);
463+
}
464+
}
465+
466+
[Fact]
467+
public void FormatBaseDisplay_and_ShortId_helpers()
468+
{
469+
Assert.Equal("aaaaaaa", RunHistory.ShortId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
470+
Assert.Equal("short", RunHistory.ShortId("short"));
471+
472+
var withPath = RunHistory.FormatBaseDisplay(
473+
"gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:app.cs",
474+
cachedEntry: null,
475+
out var owner, out var gistId, out var file);
476+
Assert.Equal("kzu/app.cs", withPath);
477+
Assert.Equal("kzu", owner);
478+
Assert.Equal("0ac826dc7de666546aaedd38e5965381", gistId);
479+
Assert.Equal("app.cs", file);
480+
481+
var withCache = RunHistory.FormatBaseDisplay(
482+
"gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381",
483+
cachedEntry: "from-cache.cs",
484+
out owner, out gistId, out file);
485+
Assert.Equal("kzu/from-cache.cs", withCache);
486+
Assert.Equal("kzu", owner);
487+
Assert.Equal("0ac826dc7de666546aaedd38e5965381", gistId);
488+
Assert.Equal("from-cache.cs", file);
489+
490+
var repo = RunHistory.FormatBaseDisplay("kzu/sandbox", null, out owner, out gistId, out file);
491+
Assert.Equal("kzu/sandbox", repo);
492+
Assert.Null(owner);
493+
Assert.Null(gistId);
494+
Assert.Null(file);
495+
}
496+
497+
[Fact]
498+
public void Record_captures_gist_entry_from_path_suffix()
499+
{
500+
var path = NewSettingsPath();
501+
try
502+
{
503+
RunHistory.Record("gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:run.cs", path);
504+
505+
var settings = SettingsStore.Load(path);
506+
Assert.Single(settings.History!);
507+
Assert.Equal("run.cs", settings.History![0].Entry);
508+
509+
var listed = RunHistory.List(path);
510+
Assert.Equal("kzu/run.cs", listed[0].Display);
511+
}
512+
finally
513+
{
514+
TryDelete(path);
515+
}
516+
}
517+
518+
[Fact]
519+
public void List_formats_https_gist_url_with_cached_entry()
520+
{
521+
var path = NewSettingsPath();
522+
try
523+
{
524+
SettingsStore.Save(new Settings
525+
{
526+
History =
527+
[
528+
new HistoryEntry
529+
{
530+
Input = "https://gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381",
531+
LastUsedUtc = DateTimeOffset.UtcNow,
532+
UseCount = 1,
533+
Entry = "run.cs",
534+
},
535+
],
536+
}, path);
537+
538+
var listed = RunHistory.List(path);
539+
Assert.Single(listed);
540+
Assert.Equal("kzu/run.cs", listed[0].Display);
541+
}
542+
finally
543+
{
544+
TryDelete(path);
545+
}
546+
}
547+
318548
static string NewSettingsPath()
319549
=> Path.Combine(Path.GetTempPath(), "go-hist-test-" + Guid.NewGuid().ToString("N") + ".toml");
320550

0 commit comments

Comments
 (0)