mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-26 21:36:31 +02:00
fix(tui): clear @-picker filter when browsing into/out of a directory
In flat (non-recursive) mode, typing a filter to locate a directory and then opening it with Right re-applied that same filter inside the directory. Typing "@eda" then Right to open eda/ showed nothing, because no child of eda/ matches "eda". The filter the user typed selected the directory at the current level; it has no meaning one level deeper. Clear the text after the last "@" (keeping the bare "@" so the picker stays open) whenever Right or Left successfully changes the browse level. The filter was scoped to the level just left, so dropping it shows the new directory's full contents. Adds a regression test that opens eda/ after an "@eda" filter and asserts the directory's contents are listed while the stale filter would have matched nothing.
This commit is contained in:
parent
1a3e0a572e
commit
4a8d2ed68e
2 changed files with 73 additions and 4 deletions
|
|
@ -176,6 +176,54 @@ func TestFileSuggesterFuzzyMatch(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestFileSuggesterFlatBrowseIntoDirIgnoresStaleFilter reproduces the
|
||||
// reported bug: in flat (non-recursive) mode, typing "@eda" to find a
|
||||
// directory then opening it with Right must show that directory's
|
||||
// contents, not re-apply the "eda" filter inside it (which matches
|
||||
// nothing). The interactive layer clears the @-query when descending,
|
||||
// so here we model that by browsing with Right and then matching an
|
||||
// empty query against the new level.
|
||||
func TestFileSuggesterFlatBrowseIntoDirIgnoresStaleFilter(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
// eda/rjg/enk-1150 with a file inside, plus a sibling so the filter
|
||||
// is meaningful at the top level.
|
||||
if err := os.MkdirAll(filepath.Join(tmp, "eda", "rjg", "enk-1150"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(tmp, "eda", "rjg", "enk-1150", "pipeline.py"), []byte("x"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(tmp, "unrelated"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := newFileSuggester()
|
||||
s.SetCWD(tmp) // flat mode
|
||||
|
||||
// Top level: "@eda" highlights the eda/ directory. Render populates
|
||||
// lastMatches, which Right/Left act on (it runs every frame before
|
||||
// key handling in the live UI).
|
||||
s.lastMatches = s.matches("@eda")
|
||||
if !containsEntry(s.lastMatches, "eda", true) {
|
||||
t.Fatalf("@eda did not match eda/: %#v", s.lastMatches)
|
||||
}
|
||||
s.cursor = 0 // eda/ is the (only) match, selected.
|
||||
|
||||
// Open it. After the interactive layer clears the query, the picker
|
||||
// is browsing eda/ with an empty filter and must show rjg/.
|
||||
if !s.Right() {
|
||||
t.Fatal("Right() did not open eda/")
|
||||
}
|
||||
if got := s.matches("@"); !containsEntry(got, "rjg", true) {
|
||||
t.Fatalf("after opening eda/, empty filter did not show rjg/: %#v", got)
|
||||
}
|
||||
// The stale filter would have shown nothing: confirm that's the
|
||||
// behavior the fix avoids.
|
||||
if got := s.matches("@eda"); len(got) != 0 {
|
||||
t.Fatalf("stale @eda filter inside eda/ unexpectedly matched: %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestFileSuggesterRecursiveMatch verifies recursive mode flattens the
|
||||
// tree and matches against the cwd-relative path, so a pattern can
|
||||
// span directory boundaries.
|
||||
|
|
|
|||
|
|
@ -1605,6 +1605,18 @@ func (i *Interactive) ctrlCExitArmed() bool {
|
|||
return !t.IsZero() && time.Since(t) <= ctrlCExitWindow
|
||||
}
|
||||
|
||||
// clearFileSuggestQuery strips the filter the user typed after the
|
||||
// last "@", leaving the bare "@" so the picker stays open. Called when
|
||||
// navigating between directory levels (Right/Left): the filter applied
|
||||
// to the level the user was on, not the one being entered, so carrying
|
||||
// it forward would wrongly hide the new directory's contents.
|
||||
func (i *Interactive) clearFileSuggestQuery() {
|
||||
val := i.ed.Value()
|
||||
if idx := strings.LastIndex(val, "@"); idx >= 0 {
|
||||
i.ed.SetValue(val[:idx+1])
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Interactive) handleKey(ctx context.Context, k tui.Key) (done bool) {
|
||||
// Any key that isn't ctrl+c invalidates an armed ctrl+c-exit, so
|
||||
// pressing ctrl+c then typing then ctrl+c much later doesn't quit
|
||||
|
|
@ -2083,12 +2095,21 @@ func (i *Interactive) handleKey(ctx context.Context, k tui.Key) (done bool) {
|
|||
i.fileSuggest.Down()
|
||||
return false
|
||||
case tui.KeyRight:
|
||||
// Open selected directory.
|
||||
i.fileSuggest.Right()
|
||||
// Open selected directory. The filter the user typed picked
|
||||
// that directory at the current level; once we descend it no
|
||||
// longer applies to the directory's contents, so clear it.
|
||||
// Otherwise typing "@eda" then right would re-filter inside
|
||||
// eda/ by "eda" and show nothing.
|
||||
if i.fileSuggest.Right() {
|
||||
i.clearFileSuggestQuery()
|
||||
}
|
||||
return false
|
||||
case tui.KeyLeft:
|
||||
// Go back to parent directory.
|
||||
i.fileSuggest.Left()
|
||||
// Go back to parent directory. Clear the filter for the same
|
||||
// reason as Right: it was scoped to the level we just left.
|
||||
if i.fileSuggest.Left() {
|
||||
i.clearFileSuggestQuery()
|
||||
}
|
||||
return false
|
||||
case tui.KeyEnter:
|
||||
if entry, ok := i.fileSuggest.SelectedEntry(i.ed.Value()); ok {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue