From 47daa13043d7c8f7dcea09ce818afa27b3594733 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Mon, 25 May 2026 03:17:45 +0530 Subject: [PATCH] fix: search file parent after leaving TUI document When Glow starts directly in TUI document mode, the file listing is never populated. Pressing escape returns to an empty stash view, and the local search path still points at the opened file instead of a searchable directory. Start the local file search when unloading an initially opened document, and resolve file paths to their parent directory before scanning. Fixes #803 --- ui/ui.go | 29 +++++++++++++------- ui/ui_test.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 ui/ui_test.go diff --git a/ui/ui.go b/ui/ui.go index 3537d3f..d216b43 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -124,7 +124,9 @@ func (m *model) unloadDocument() []tea.Cmd { batch = append(batch, tea.ClearScrollArea) //nolint:staticcheck } - if !m.stash.shouldSpin() { + if !m.stash.loadingDone() && m.localFileFinder == nil { + batch = append(batch, findLocalFiles(*m.common), m.stash.spinner.Tick) + } else if !m.stash.shouldSpin() { batch = append(batch, m.stash.spinner.Tick) } return batch @@ -362,15 +364,7 @@ func findLocalFiles(m commonModel) tea.Cmd { err error ) - if cwd == "" { - cwd, err = os.Getwd() - } else { - var info os.FileInfo - info, err = os.Stat(cwd) - if err == nil && info.IsDir() { - cwd, err = filepath.Abs(cwd) - } - } + cwd, err = localFileSearchRoot(cwd) // Note that this is one error check for both cases above if err != nil { @@ -397,6 +391,21 @@ func findLocalFiles(m commonModel) tea.Cmd { } } +func localFileSearchRoot(path string) (string, error) { + if path == "" { + return os.Getwd() + } + + info, err := os.Stat(path) + if err != nil { + return "", err + } + if !info.IsDir() { + path = filepath.Dir(path) + } + return filepath.Abs(path) +} + func findNextLocalFile(m model) tea.Cmd { return func() tea.Msg { res, ok := <-m.localFileFinder diff --git a/ui/ui_test.go b/ui/ui_test.go new file mode 100644 index 0000000..367aa4e --- /dev/null +++ b/ui/ui_test.go @@ -0,0 +1,76 @@ +package ui + +import ( + "os" + "path/filepath" + "testing" + + tea "github.com/charmbracelet/bubbletea" +) + +func TestLocalFileSearchRootUsesParentDirectoryForFiles(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "index.md") + if err := os.WriteFile(path, []byte("# Test\n"), 0o600); err != nil { + t.Fatal(err) + } + + got, err := localFileSearchRoot(path) + if err != nil { + t.Fatal(err) + } + + if got != dir { + t.Fatalf("expected %q, got %q", dir, got) + } +} + +func TestUnloadDocumentStartsSearchWhenListingWasNotLoaded(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "index.md") + if err := os.WriteFile(path, []byte("# Test\n"), 0o600); err != nil { + t.Fatal(err) + } + + initSections() + common := &commonModel{ + cfg: Config{ + Path: path, + ShowAllFiles: true, + }, + } + m := model{ + common: common, + state: stateShowDocument, + stash: newStashModel(common), + pager: newPagerModel(common), + } + t.Cleanup(func() { + if err := m.pager.watcher.Close(); err != nil { + t.Fatal(err) + } + }) + + cmds := m.unloadDocument() + if len(cmds) == 0 { + t.Fatal("expected unload to start a local file search") + } + + var msg tea.Msg + for _, cmd := range cmds { + msg = cmd() + if _, ok := msg.(initLocalFileSearchMsg); ok { + break + } + } + + got, ok := msg.(initLocalFileSearchMsg) + if !ok { + t.Fatalf("expected initLocalFileSearchMsg, got %T", msg) + } + if got.cwd != dir { + t.Fatalf("expected search cwd %q, got %q", dir, got.cwd) + } + for range got.ch { + } +}