Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial loading of Filepicker isn't working #564

Open
justin-9rd opened this issue Jul 21, 2024 · 1 comment
Open

Initial loading of Filepicker isn't working #564

justin-9rd opened this issue Jul 21, 2024 · 1 comment

Comments

@justin-9rd
Copy link

Describe the bug
Working on a tui http client 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

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

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

What I expect it to render in the first box
Screenshot from 2024-07-21 11-29-03

@justin-9rd
Copy link
Author

After some debugging and having to pull the filepicker into my own project I found that I can resolve this issue in my code base by up dated the WindowSize msg check

  case tea.WindowSizeMsg:
    if m.AutoHeight {
	    m.Height = msg.Height - marginBottom
    }
    m.max = m.Height - 1
    if len(m.files) == 0 {
	    return m, m.readDir(m.CurrentDirectory, m.ShowHidden)
    }

This does not feel like the right solution.

Overall seems that the readDirMsg isn't getting picked up in time as my WindowSizeMsg is begin the first thing I pick up in my logs even though I can see the Init function firing in my logs. Not sure what would be the best fix without understanding how the underlining system is processing the messages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant