138 lines
2.6 KiB
Go
138 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"codeberg.org/helvetica/binfo"
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/app"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/widget"
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
var bi = binfo.MustGet()
|
|
|
|
type config struct {
|
|
SpecPath string
|
|
Verbose bool
|
|
Rowcols int
|
|
Exit bool
|
|
}
|
|
|
|
func main() {
|
|
cli.VersionPrinter = func(cmd *cli.Command) {
|
|
_, _ = fmt.Fprintf(
|
|
cmd.Root().Writer,
|
|
"%s\n",
|
|
bi.Summarize(
|
|
cmd.Name,
|
|
cmd.Version,
|
|
binfo.Multiline|binfo.Build|binfo.VCS|binfo.Module|binfo.CGO,
|
|
),
|
|
)
|
|
}
|
|
|
|
cfg := config{}
|
|
|
|
cliApp := &cli.Command{
|
|
Name: "xenumenu",
|
|
Version: bi.Module.Version,
|
|
Arguments: []cli.Argument{
|
|
&cli.StringArg{
|
|
Name: "spec",
|
|
Destination: &cfg.SpecPath,
|
|
},
|
|
},
|
|
Flags: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "verbose",
|
|
Usage: "verbose output",
|
|
Destination: &cfg.Verbose,
|
|
},
|
|
&cli.IntFlag{
|
|
Name: "rowcols",
|
|
Usage: "maximum rows or columns for the grid",
|
|
Destination: &cfg.Rowcols,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "exit",
|
|
Usage: "whether to exit the GUI and shutdown after running the command",
|
|
Destination: &cfg.Exit,
|
|
},
|
|
},
|
|
Action: func(context.Context, *cli.Command) error {
|
|
rawSpec, err := os.ReadFile(cfg.SpecPath)
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
|
|
spec := Spec{}
|
|
|
|
err = json.Unmarshal(rawSpec, &spec)
|
|
if err != nil {
|
|
slog.Error("decoding JSON input failed", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
for key, entry := range spec.Entries {
|
|
if entry.Argv0 == "" {
|
|
entry.Argv0 = entry.Program
|
|
spec.Entries[key] = entry
|
|
}
|
|
}
|
|
|
|
if cfg.Verbose {
|
|
slog.Info("parsed spec", "spec", fmt.Sprintf("%#v", spec))
|
|
}
|
|
|
|
a := app.New()
|
|
w := a.NewWindow("Xenumenu")
|
|
|
|
displayEntries := []fyne.CanvasObject{}
|
|
|
|
for _, entry := range spec.Entries {
|
|
e := widget.NewButton(entry.DisplayName, func() {
|
|
go func() {
|
|
ps, err := entry.Run()
|
|
|
|
if err != nil {
|
|
if _, ok := err.(*exec.ExitError); ok {
|
|
slog.Error("command failed", "error", err)
|
|
} else {
|
|
slog.Error("unable to run command", "error", err)
|
|
if cfg.Exit {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
if cfg.Exit {
|
|
os.Exit(ps.ExitCode())
|
|
}
|
|
}()
|
|
})
|
|
displayEntries = append(displayEntries, e)
|
|
}
|
|
|
|
w.SetContent(container.NewAdaptiveGrid(
|
|
cfg.Rowcols,
|
|
displayEntries...,
|
|
))
|
|
|
|
w.ShowAndRun()
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
if err := cliApp.Run(context.Background(), os.Args); err != nil {
|
|
slog.Error("application error", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|