package cmd import ( "context" "errors" "fmt" "image" "os" "time" config2 "tuxpa.in/t/erm/app/darktile/config" gui2 "tuxpa.in/t/erm/app/darktile/gui" "tuxpa.in/t/erm/app/darktile/hinters" termutil2 "tuxpa.in/t/erm/app/darktile/termutil" "tuxpa.in/t/erm/app/darktile/version" ) type Context struct { context.Context } type Root struct { Term Term `cmd:"" aliases:"t" default:"1" help:"launch term"` ListFonts ListFonts `cmd:"" aliases:"lf" name:"list-fonts" help:"list fonts"` } type Term struct { ShowVersion bool `name:"version" help:"Show erm version information and exit"` RewriteConfig bool `name:"rewrite-config" help:"Write the resultant config after parsing config files and merging with defauls back to the config file"` LogFile string `name:"log-file" help:"Debug log file"` Shell string `name:"shell" short:"s" help:"Shell to launch terminal with - defaults to configured user shell"` Command string `name:"command" short:"c" help:"Command to run when shell starts - use this with caution"` ScreenshotAfterMs int `name:"screenshot-after-ms" help:"Take a screenshot after this many milliseconds"` ScreenshotFilename string `name:"screenshot-filename" help:"Filename to store screenshot taken by --screenshot-after-ms"` ThemePath string `name:"theme-path" help:"Path to a theme file to use instead of the default"` } func (r *Term) Run(ctx *Context) error { if r.ShowVersion { fmt.Println(version.Version) os.Exit(0) } var startupErrors []error var fileNotFound *config2.ErrorFileNotFound conf, err := config2.LoadConfig() if err != nil { if !errors.As(err, &fileNotFound) { startupErrors = append(startupErrors, err) } conf = config2.DefaultConfig() } if r.RewriteConfig { if _, err := conf.Save(); err != nil { return fmt.Errorf("failed to write config file: %w", err) } fmt.Println("Config written.") return nil } var theme *termutil2.Theme if r.ThemePath != "" { theme, err = config2.LoadThemeFromPath(conf, r.ThemePath) if err != nil { return fmt.Errorf("failed to load theme: %s", err) } } else { theme, err = config2.LoadTheme(conf) if err != nil { if !errors.As(err, &fileNotFound) { startupErrors = append(startupErrors, err) } theme, err = config2.DefaultTheme(conf) if err != nil { return fmt.Errorf("failed to load default theme: %w", err) } } } termOpts := []termutil2.Option{ termutil2.WithTheme(theme), } if r.LogFile != "" { termOpts = append(termOpts, termutil2.WithLogFile(r.LogFile)) } if r.Shell != "" { termOpts = append(termOpts, termutil2.WithShell(r.Shell)) } if r.Command != "" { termOpts = append(termOpts, termutil2.WithInitialCommand(r.Command)) } terminal := termutil2.New(termOpts...) options := []gui2.Option{ gui2.WithFontDPI(conf.Font.DPI), gui2.WithFontSize(conf.Font.Size), gui2.WithFontFamily(conf.Font.Family), gui2.WithOpacity(conf.Opacity), gui2.WithLigatures(conf.Font.Ligatures), } if conf.Cursor.Image != "" { img, err := getImageFromFilePath(conf.Cursor.Image) if err != nil { startupErrors = append(startupErrors, err) } else { options = append(options, gui2.WithCursorImage(img)) } } if r.ScreenshotAfterMs > 0 { options = append(options, gui2.WithStartupFunc(func(g *gui2.GUI) { <-time.After(time.Duration(r.ScreenshotAfterMs) * time.Millisecond) g.RequestScreenshot(r.ScreenshotFilename) })) } // load all hinters for _, hinter := range hinters.All() { options = append(options, gui2.WithHinter(hinter)) } g, err := gui2.New(terminal, options...) if err != nil { return err } for _, err := range startupErrors { g.ShowError(err.Error()) } return g.Run(conf) } func getImageFromFilePath(filePath string) (image.Image, error) { f, err := os.Open(filePath) if err != nil { return nil, err } defer f.Close() image, _, err := image.Decode(f) return image, err }