package main import ( _ "embed" "github.com/ewy1/pik/completion" "github.com/ewy1/pik/flags" "github.com/ewy1/pik/man/manview" "github.com/ewy1/pik/model" "github.com/ewy1/pik/paths" "github.com/ewy1/pik/run" "github.com/ewy1/pik/spool" "os" "path/filepath" "runtime" "runtime/pprof" ) // ModeMap maps flags to specific operation modes type ModeMap[T any] map[*bool]T //go:embed man/manview/help.txt var help string //go:embed man/manview/version.txt var version string // Traverse checks the entries of the map. If any flags are set on, // pik that mode. If Continue is returned, it's non-exclusive. Otherwise, // we quit after one mode. // // `then` should simply be the method call (necessary due to generics) func (m ModeMap[T]) Traverse(then func(in T) *spool.ExitCode) *spool.ExitCode { for enabled, mode := range m { if !*enabled { continue } return then(mode) } return nil } var profileFd *os.File // uninitializedModes are modes which can run before the program runs initializers var uninitializedModes = ModeMap[func() *spool.ExitCode]{ flags.Version: func() *spool.ExitCode { _, _ = spool.Print("%s\n", version) return &spool.Success }, flags.Completion: func() *spool.ExitCode { return completion.Echo() }, flags.Help: func() *spool.ExitCode { _ = manview.View(help) return &spool.Success }, } // statelessModes are program modes which do not require state to operate. // like --version and --completion var statelessModes = ModeMap[func() *spool.ExitCode]{ flags.InstallCompletion: func() *spool.ExitCode { sh := os.Getenv("SHELL") if sh == "" { return &spool.UnknownShellFailure } _, sh = filepath.Split(sh) return completion.Add(sh) }, flags.Profile: func() *spool.ExitCode { fd, err := os.Create("pik-profile.out") if err != nil { return &spool.ProfilingFailure } runtime.SetCPUProfileRate(1000) err = pprof.StartCPUProfile(profileFd) if err != nil { return &spool.ProfilingFailure } profileFd = fd return nil }, } // statefulModes are program modes which require a built state to be executed var statefulModes = ModeMap[func(st *model.State) *spool.ExitCode]{ flags.List: func(st *model.State) *spool.ExitCode { count := 0 for _, s := range st.Sources { count++ _, _ = spool.Print("%v", s.Label()+paths.Ifs) for _, t := range s.Targets { _, _ = spool.Print("%v", t.ShortestId()+paths.Ifs) count++ } } if count == 0 { return &spool.NoTargetsFailure } return nil }, } // selectionModes are program modes which require a selected target, through menu or args var selectionModes = ModeMap[func(st *model.State, src *model.Source, t model.Target) *spool.ExitCode]{ flags.Edit: func(st *model.State, src *model.Source, t model.Target) *spool.ExitCode { return run.Edit(t, src) }, }