charmbracelet / charmbracelet/bubbles

Initial loading of Filepicker isn't working

Open
#564 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Go
Stars
8.9k
Forks
457
Avg merge
1d 18h
Merged PRs (30d)
5

Description

**Describe the bug**
Working on a tui http client [Muninn](https://github.com/9-Realms-Dev/muninn) and I'm using the filepicker bubble to find the `.http` files on my system. Well when the application initialize I get a "no files found" this isn't the same behaivor I get when working on the example you guys have built. I've rewritten the example using all the same steps I use in my code and it produces list of directory as expected but if I copy that code into my code base it still shows "no files found".

**Setup**
Please complete the following information along with version numbers, if applicable.
- OS: Pop-os
- Shell: Fish
- Terminal Emulator: Alacritty
- Terminal Multiplexer: Zellij
- Locale: en_US.UTF-8

**To Reproduce**
Steps to reproduce the behavior:
1. Clone Muninn
2. Start muninn `go run main.go`
3. Notice that it shows the filepicker is empty
4. Hit `h` to go back a directory and see that the filepicker is working fine from there

**Source Code**
Please include source code if needed to reproduce the behavior.
muninn filepicker: `/internal/tui/filepicker_view.go`
```go
package tui

import (
"errors"
"strings"
"time"

"github.com/charmbracelet/bubbles/filepicker"
tea "github.com/charmbracelet/bubbletea"
)

type clearErrorMsg struct{}

func clearErrorAfter(t time.Duration) tea.Cmd {
return tea.Tick(t, func(_ time.Time) tea.Msg {
return clearErrorMsg{}
})
}

type filepickerModel struct {
picker filepicker.Model
selected string
quitting bool
err error
}

func initFilepicker(path string) filepickerModel {
fp := filepicker.New()
fp.AllowedTypes = []string{".http"}
fp.CurrentDirectory = path
fp.ShowPermissions = false
fp.ShowSize = false
fp.AutoHeight = false

return filepickerModel{
picker: fp,
}
}

func (m filepickerModel) Init() tea.Cmd {
return m.picker.Init()
}

func (m filepickerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.picker.Height = msg.Height / 4
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
m.quitting = true
return m, tea.Quit
}
case clearErrorMsg:
m.err = nil
}

var cmd tea.Cmd
m.picker, cmd = m.picker.Update(msg)

// Did the user select a file?
if didSelect, path := m.picker.DidSelectFile(msg); didSelect {
// Get the path of the selected file.
m.selected = path
}

// Did the user select a disabled file?
// This is only necessary to display an error to the user.
if didSelect, path := m.picker.DidSelectDisabledFile(msg); didSelect {
// Let's clear the selectedFile and display an error.
m.err = errors.New(path + " is not valid.")
m.selected = ""
return m, tea.Batch(cmd, clearErrorAfter(2*time.Second))
}

return m, cmd
}

func (m filepickerModel) View() string {
if m.quitting {
return ""
}
var s strings.Builder
s.WriteString("\n ")
if m.err != nil {
s.WriteString(m.picker.Styles.DisabledFile.Render(m.err.Error()))
} else if m.selected == "" {
s.WriteString("Pick a file:")
} else {
s.WriteString("Selected file: " + m.picker.Styles.Selected.Render(m.selected))
}
s.WriteString("\n\n" + m.picker.View() + "\n")
return s.String()
}
```

Minimal standalone file
```go
package main

import (
"errors"
"fmt"
"os"
"strings"
"time"

"github.com/charmbracelet/bubbles/filepicker"
tea "github.com/charmbracelet/bubbletea"
)

type model struct {
filepicker filepicker.Model
selectedFile string
quitting bool
err error
}

type clearErrorMsg struct{}

func clearErrorAfter(t time.Duration) tea.Cmd {
return tea.Tick(t, func(_ time.Time) tea.Msg {
return clearErrorMsg{}
})
}

func (m model) Init() tea.Cmd {
return m.filepicker.Init()
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.filepicker.Height = msg.Height / 4
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
m.quitting = true
return m, tea.Quit
}
case clearErrorMsg:
m.err = nil
}

var cmd tea.Cmd
m.filepicker, cmd = m.filepicker.Update(msg)

// Did the user select a file?
if didSelect, path := m.filepicker.DidSelectFile(msg); didSelect {
// Get the path of the selected file.
m.selectedFile = path
}

// Did the user select a disabled file?
// This is only necessary to display an error to the user.
if didSelect, path := m.filepicker.DidSelectDisabledFile(msg); didSelect {
// Let's clear the selectedFile and display an error.
m.err = errors.New(path + " is not valid.")
m.selectedFile = ""
return m, tea.Batch(cmd, clearErrorAfter(2*time.Second))
}

return m, cmd
}

func (m model) View() string {
if m.quitting {
return ""
}
var s strings.Builder
s.WriteString("\n ")
if m.err != nil {
s.WriteString(m.filepicker.Styles.DisabledFile.Render(m.err.Error()))
} else if m.selectedFile == "" {
s.WriteString("Pick a file:")
} else {
s.WriteString("Selected file: " + m.filepicker.Styles.Selected.Render(m.selectedFile))
}
s.WriteString("\n\n" + m.filepicker.View() + "\n")
return s.String()
}

func main() {
fp := filepicker.New()
path, _ := os.UserHomeDir()
fp.AllowedTypes = []string{".http"}
fp.CurrentDirectory = path
fp.ShowPermissions = false
fp.ShowSize = false
fp.AutoHeight = false

m := model{
filepicker: fp,
}
tm, _ := tea.NewProgram(&m).Run()
mm := tm.(model)
fmt.Println("\n You selected: " + m.filepicker.Styles.Selected.Render(mm.selectedFile) + "\n")
}
```

**Expected behavior**
When my application starts I expect the files and directories to appear just like the minimal example

**Screenshots**
What my application renders
![Screenshot from 2024-07-21 11-27-56](https://github.com/user-attachments/assets/f29eebc5-efd9-48dc-baa3-f3cb9912e2a9)

What I expect it to render in the first box
![Screenshot from 2024-07-21 11-29-03](https://github.com/user-attachments/assets/b6da55fe-064e-4977-b83f-7825b08290c8)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.