package main import ( "astronaut/styles" "astronaut/ui" "errors" "flag" "fmt" "io" "io/fs" "log" "os" "path/filepath" "time" "git.sr.ht/~adnano/go-xdg" "git.sr.ht/~emersion/go-scfg" ) var ( Version string ShareDir string ) func main() { version := flag.Bool("v", false, "print version") flag.Parse() if *version { fmt.Println("astronaut", Version) return } if err := run(); err != nil { log.Fatal(err) } } func run() error { os.MkdirAll(filepath.Join(xdg.DataHome(), "astronaut"), 0700) configHome := filepath.Join(xdg.ConfigHome(), "astronaut") config := &Config{Binds: Binds{}} if err := parseConfig("astronaut.conf", configHome, ShareDir, config.Parse); err != nil { return err } if err := parseConfig("style.conf", configHome, ShareDir, styles.Parse); err != nil { return err } // Disable logging if os.Stderr is a TTY stat, err := os.Stderr.Stat() if err != nil { return err } if (stat.Mode() & os.ModeCharDevice) != 0 { // Discard log entries log.Default().SetOutput(io.Discard) } ui, err := ui.New() if err != nil { return err } defer ui.Close() browser := NewBrowser(ui, config) ui.Init(browser) for !ui.Exiting() { browser.Update() if !ui.Tick(browser) { // ~60 FPS time.Sleep(16 * time.Millisecond) } } return nil } func openConfigFile(name, dir, sharedir string) (fs.File, error) { // Try to open the file path := filepath.Join(dir, name) f, err := os.Open(path) if err == nil { return f, nil } // Return the error if the file exists or sharedir is empty if !errors.Is(err, os.ErrNotExist) || len(sharedir) == 0 { return nil, err } // Create the directory if it does not exist if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { if err := os.MkdirAll(dir, 0755); err != nil { return nil, err } } // Copy the file data, err := os.ReadFile(filepath.Join(sharedir, name)) if err != nil { return nil, err } if err := os.WriteFile(path, data, 0644); err != nil { return nil, err } return os.Open(path) } func parseConfig(name, dir, sharedir string, parse func(scfg.Block) error) error { f, err := openConfigFile(name, dir, sharedir) if err != nil { return err } defer f.Close() block, err := scfg.Read(f) if err != nil { return err } return parse(block) }