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
This commit is contained in:
Asish Kumar 2026-05-25 03:17:45 +05:30
commit 47daa13043
No known key found for this signature in database
GPG key ID: 0EF072B1E0BA6FBA
2 changed files with 95 additions and 10 deletions

View file

@ -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

76
ui/ui_test.go Normal file
View file

@ -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 {
}
}