summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-05-02 17:07:13 +0200
committerewy <ewy0@protonmail.com>2026-05-02 17:07:13 +0200
commit1c681ad4149f994a2a8caf21133747b9348002c6 (patch)
tree2fee367772f07dbc80fa1b036535abd8aab8bf40
parentf78ac099102715281f27492142ebf0fe6004d0a1 (diff)
add a little abstraction to the main branches
-rw-r--r--README.md4
-rw-r--r--components.go30
-rw-r--r--flags/flags.go6
-rw-r--r--main.go65
-rw-r--r--modes.go62
5 files changed, 123 insertions, 44 deletions
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)
+ },
+}