From 1c681ad4149f994a2a8caf21133747b9348002c6 Mon Sep 17 00:00:00 2001 From: ewy Date: Sat, 2 May 2026 17:07:13 +0200 Subject: add a little abstraction to the main branches --- README.md | 4 +++- components.go | 30 +++++++++++++++++++++++++++ flags/flags.go | 6 ++++-- main.go | 65 ++++++++++++++++++++++------------------------------------ modes.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 44 deletions(-) create mode 100644 components.go create mode 100644 modes.go diff --git a/README.md b/README.md index 669d463..89fccb1 100644 --- a/README.md +++ b/README.md @@ -102,4 +102,6 @@ attach to these features. ## thanks -this repository lives [here](https://git.ewy.one/pik/) \ No newline at end of file +this repository lives [here](https://git.ewy.one/pik/) + +this software is and was intentionally produced without llms \ No newline at end of file diff --git a/components.go b/components.go new file mode 100644 index 0000000..6f59f58 --- /dev/null +++ b/components.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/ewy1/pik/spool" + "sync" +) + +type ComponentList[T any] []T + +func (c ComponentList[T]) RunAsync(fire func(T) error) { + wg := sync.WaitGroup{} + for _, i := range c { + wg.Go(func() { + err := fire(i) + if err != nil { + _, _ = spool.Warn("%v\n", err) + } + }) + } + wg.Wait() +} + +func (c ComponentList[T]) RunSync(fire func(T) error) { + for _, i := range c { + err := fire(i) + if err != nil { + _, _ = spool.Warn("%v\n", err) + } + } +} diff --git a/flags/flags.go b/flags/flags.go index 756d95b..7138522 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -24,6 +24,8 @@ var ( // List means we should output available targets separated by $IFS List = pflag.BoolP("list", "l", false, "list available targets and exit") // Inline means pik does not go to the terminal alt screen - Inline = pflag.BoolP("inline", "i", false, "if true, will force alt screen; if forced false, will disable alt screen") - Edit = pflag.Bool("edit", false, "edit the target in $EDITOR") + // unused because it is accessed by `flags.Get("inline")` + Inline = pflag.BoolP("inline", "i", false, "if true, will force alt screen; if forced false, will disable alt screen") + Edit = pflag.Bool("edit", false, "edit the target in $EDITOR") + Completion = pflag.Bool("completion", false, "echo completion scrip and exit") ) diff --git a/main.go b/main.go index af5cb9f..18ef298 100644 --- a/main.go +++ b/main.go @@ -21,26 +21,25 @@ import ( "github.com/ewy1/pik/spool" "github.com/spf13/pflag" "os" - "sync" ) // syncInitializers are ran before the initializers. // useful for initializing stuff like paths, preparing directories, and reading the environment -var syncInitializers = []model.Initializer{ +var syncInitializers = ComponentList[model.Initializer]{ paths.Paths, cache.Init, } // initializers are ran before indexing with the indexers, // data from the syncInitializers can be accessed at this time. -var initializers = []model.Initializer{ +var initializers = ComponentList[model.Initializer]{ pikdex.Indexer, python.Python, git.Git, } // indexers are methods which scan a directory and return a number of targets. -var indexers = []model.Indexer{ +var indexers = ComponentList[model.Indexer]{ pikdex.Indexer, just.Indexer, gnumake.Indexer, @@ -48,7 +47,7 @@ var indexers = []model.Indexer{ // runners are modules which know how to turn a file into an exec.Cmd // all indexers have access to these but only pikdex uses it -var runners = []model.Runner{ +var runners = ComponentList[model.Runner]{ shell.Runner, python.Python, exc.Exc, @@ -56,7 +55,7 @@ var runners = []model.Runner{ // hydrators are ran when the menu is required // for example adding git info, descriptions, icons... -var hydrators = []model.Modder{ +var hydrators = ComponentList[model.Modder]{ pikdex.Indexer, git.Git, } @@ -74,29 +73,17 @@ var version string func main() { pflag.Parse() - switch { - case *flags.Version: - _, _ = spool.Print("%s\n", version) - os.Exit(0) - } + statelessModes.Traverse(func(in func() error) error { + return in() + }) - for _, i := range syncInitializers { - err := i.Init() - if err != nil { - _, _ = spool.Warn("%v\n", err) - } - } + syncInitializers.RunSync(func(initializer model.Initializer) error { + return initializer.Init() + }) - wg := sync.WaitGroup{} - for _, i := range initializers { - wg.Go(func() { - err := i.Init() - if err != nil { - _, _ = spool.Warn("%v\n", err) - } - }) - } - wg.Wait() + initializers.RunAsync(func(initializer model.Initializer) error { + return initializer.Init() + }) here, err := os.Getwd() if err != nil { @@ -137,15 +124,9 @@ func main() { _, _ = spool.Warn("%v\n", stateErrors) } - if *flags.List { - for _, s := range st.Sources { - _, _ = spool.Print("%v", s.Label()+paths.Ifs) - for _, t := range s.Targets { - _, _ = spool.Print("%v", t.ShortestId()+paths.Ifs) - } - } - os.Exit(0) - } + statefulModes.Traverse(func(in func(st *model.State) error) error { + return in(st) + }) args := pflag.Args() @@ -196,11 +177,13 @@ func main() { if result.Overridden { _, _ = fmt.Fprintln(os.Stderr, menu.OverrideWarning(result.Target)) } - if *flags.Edit { - err = run.Edit(result.Target, result.Source) - } else { - err = run.Run(result.Source, result.Target, result.Args...) - } + + selectionModes.Traverse(func(in func(st *model.State, src *model.Source, t model.Target) error) error { + return in(st, result.Source, result.Target) + }) + + err = run.Run(result.Source, result.Target, result.Args...) + if err != nil { _, _ = spool.Warn("%v\n", err) os.Exit(1) diff --git a/modes.go b/modes.go new file mode 100644 index 0000000..8f652fa --- /dev/null +++ b/modes.go @@ -0,0 +1,62 @@ +package main + +import ( + "errors" + "github.com/ewy1/pik/completion" + "github.com/ewy1/pik/flags" + "github.com/ewy1/pik/model" + "github.com/ewy1/pik/paths" + "github.com/ewy1/pik/run" + "github.com/ewy1/pik/spool" + "os" +) + +type ModeMap[T any] map[*bool]T + +func (m ModeMap[T]) Traverse(then func(in T) error) { + for enabled, mode := range m { + var err error + if *enabled { + err = then(mode) + } + if errors.Is(err, Continue) { + continue + } else if err != nil { + _, _ = spool.Warn("%v\n", err) + os.Exit(1) + } else { + os.Exit(0) + } + } +} + +var statelessModes = ModeMap[func() error]{ + flags.Version: func() error { + _, err := spool.Print("%s\n", version) + return err + }, + flags.Completion: func() error { + return completion.Echo() + + }, +} + +var Continue = errors.New("not an error; continue flow") + +var statefulModes = ModeMap[func(st *model.State) error]{ + flags.List: func(st *model.State) error { + for _, s := range st.Sources { + _, _ = spool.Print("%v", s.Label()+paths.Ifs) + for _, t := range s.Targets { + _, _ = spool.Print("%v", t.ShortestId()+paths.Ifs) + } + } + return nil + }, +} + +var selectionModes = ModeMap[func(st *model.State, src *model.Source, t model.Target) error]{ + flags.Edit: func(st *model.State, src *model.Source, t model.Target) error { + return run.Edit(t, src) + }, +} -- cgit v1.3.1