From 25f12ee8b5058483c43f57f05473ba04a6d810a7 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Wed, 20 Sep 2023 14:56:02 -0400 Subject: [PATCH 1/3] First stab --- internal/cmd/common.go | 2 +- internal/cmd/fmt.go | 2 +- internal/cmd/list.go | 2 +- internal/cmd/print.go | 2 +- internal/cmd/run.go | 2 +- internal/cmd/tasks.go | 2 +- internal/cmd/tui.go | 2 +- internal/runner/client/client.go | 2 +- internal/runner/client/client_local.go | 2 +- internal/runner/client/client_multi.go | 2 +- internal/runner/client/client_remote.go | 2 +- internal/runner/client/client_test.go | 2 +- internal/runner/service.go | 2 +- internal/runner/session.go | 2 +- internal/tui/model_list.go | 2 +- {internal => pkg}/project/TEST.md | 0 {internal => pkg}/project/TEST2.md | 0 {internal => pkg}/project/document.go | 0 {internal => pkg}/project/formatter.go | 6 +++--- {internal => pkg}/project/project.go | 0 {internal => pkg}/project/project_test.go | 0 {internal => pkg}/project/repo.go | 0 {internal => pkg}/project/repo_test.go | 0 {internal => pkg}/project/test_project/.env | 0 {internal => pkg}/project/test_project/.env.local | 0 {internal => pkg}/project/test_project/IGNORED.md | 0 {internal => pkg}/project/test_project/README.md | 0 {internal => pkg}/project/test_project/ignored/README.md | 0 {internal => pkg}/project/test_project/src/DOCS.md | 0 29 files changed, 18 insertions(+), 18 deletions(-) rename {internal => pkg}/project/TEST.md (100%) rename {internal => pkg}/project/TEST2.md (100%) rename {internal => pkg}/project/document.go (100%) rename {internal => pkg}/project/formatter.go (95%) rename {internal => pkg}/project/project.go (100%) rename {internal => pkg}/project/project_test.go (100%) rename {internal => pkg}/project/repo.go (100%) rename {internal => pkg}/project/repo_test.go (100%) rename {internal => pkg}/project/test_project/.env (100%) rename {internal => pkg}/project/test_project/.env.local (100%) rename {internal => pkg}/project/test_project/IGNORED.md (100%) rename {internal => pkg}/project/test_project/README.md (100%) rename {internal => pkg}/project/test_project/ignored/README.md (100%) rename {internal => pkg}/project/test_project/src/DOCS.md (100%) diff --git a/internal/cmd/common.go b/internal/cmd/common.go index be04f4f8..90f73549 100644 --- a/internal/cmd/common.go +++ b/internal/cmd/common.go @@ -17,10 +17,10 @@ import ( "github.com/spf13/cobra" "github.com/stateful/runme/internal/document" runnerv1 "github.com/stateful/runme/internal/gen/proto/go/runme/runner/v1" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner/client" "github.com/stateful/runme/internal/tui" "github.com/stateful/runme/internal/tui/prompt" + "github.com/stateful/runme/pkg/project" "golang.org/x/exp/slices" ) diff --git a/internal/cmd/fmt.go b/internal/cmd/fmt.go index 8c7c8727..1daf4591 100644 --- a/internal/cmd/fmt.go +++ b/internal/cmd/fmt.go @@ -5,7 +5,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/stateful/runme/internal/project" + "github.com/stateful/runme/pkg/project" ) func fmtCmd() *cobra.Command { diff --git a/internal/cmd/list.go b/internal/cmd/list.go index 8984bcdb..88d8ab8d 100644 --- a/internal/cmd/list.go +++ b/internal/cmd/list.go @@ -12,8 +12,8 @@ import ( "github.com/cli/go-gh/pkg/tableprinter" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/shell" + "github.com/stateful/runme/pkg/project" ) type row struct { diff --git a/internal/cmd/print.go b/internal/cmd/print.go index 2f4c1f28..0e17f37b 100644 --- a/internal/cmd/print.go +++ b/internal/cmd/print.go @@ -5,7 +5,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/stateful/runme/internal/project" + "github.com/stateful/runme/pkg/project" ) func printCmd() *cobra.Command { diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 3c0b1be2..7a70cf2a 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -19,9 +19,9 @@ import ( "github.com/rwtodd/Go.Sed/sed" "github.com/spf13/cobra" "github.com/stateful/runme/internal/document" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner/client" "github.com/stateful/runme/internal/tui" + "github.com/stateful/runme/pkg/project" "golang.org/x/exp/slices" ) diff --git a/internal/cmd/tasks.go b/internal/cmd/tasks.go index 9f96e009..75a2ed4b 100644 --- a/internal/cmd/tasks.go +++ b/internal/cmd/tasks.go @@ -5,8 +5,8 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/tasks" + "github.com/stateful/runme/pkg/project" ) func tasksCmd() *cobra.Command { diff --git a/internal/cmd/tui.go b/internal/cmd/tui.go index a21f1dc1..58dd1d7c 100644 --- a/internal/cmd/tui.go +++ b/internal/cmd/tui.go @@ -11,10 +11,10 @@ import ( "github.com/mgutz/ansi" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner" "github.com/stateful/runme/internal/runner/client" "github.com/stateful/runme/internal/version" + "github.com/stateful/runme/pkg/project" "golang.org/x/exp/constraints" ) diff --git a/internal/runner/client/client.go b/internal/runner/client/client.go index aea0d5de..0664e910 100644 --- a/internal/runner/client/client.go +++ b/internal/runner/client/client.go @@ -9,8 +9,8 @@ import ( "github.com/go-git/go-billy/v5/osfs" "github.com/muesli/cancelreader" runnerv1 "github.com/stateful/runme/internal/gen/proto/go/runme/runner/v1" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner" + "github.com/stateful/runme/pkg/project" "go.uber.org/zap" ) diff --git a/internal/runner/client/client_local.go b/internal/runner/client/client_local.go index 3b19ff1b..1332c998 100644 --- a/internal/runner/client/client_local.go +++ b/internal/runner/client/client_local.go @@ -13,8 +13,8 @@ import ( "github.com/pkg/errors" "github.com/stateful/runme/internal/document" "github.com/stateful/runme/internal/env" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner" + "github.com/stateful/runme/pkg/project" "go.uber.org/zap" ) diff --git a/internal/runner/client/client_multi.go b/internal/runner/client/client_multi.go index 9d01cdb4..0380732f 100644 --- a/internal/runner/client/client_multi.go +++ b/internal/runner/client/client_multi.go @@ -10,8 +10,8 @@ import ( "sync" "github.com/stateful/runme/internal/document" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner" + "github.com/stateful/runme/pkg/project" ) const stripAnsi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" diff --git a/internal/runner/client/client_remote.go b/internal/runner/client/client_remote.go index e9f5fb2c..f6cc64bb 100644 --- a/internal/runner/client/client_remote.go +++ b/internal/runner/client/client_remote.go @@ -10,8 +10,8 @@ import ( "github.com/muesli/cancelreader" "github.com/pkg/errors" runnerv1 "github.com/stateful/runme/internal/gen/proto/go/runme/runner/v1" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/runner" + "github.com/stateful/runme/pkg/project" "golang.org/x/sync/errgroup" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" diff --git a/internal/runner/client/client_test.go b/internal/runner/client/client_test.go index bae31fa3..3a0d3766 100644 --- a/internal/runner/client/client_test.go +++ b/internal/runner/client/client_test.go @@ -5,7 +5,7 @@ import ( "runtime" "testing" - "github.com/stateful/runme/internal/project" + "github.com/stateful/runme/pkg/project" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/internal/runner/service.go b/internal/runner/service.go index 45cf639d..16ddcd3f 100644 --- a/internal/runner/service.go +++ b/internal/runner/service.go @@ -12,8 +12,8 @@ import ( "github.com/rs/xid" "github.com/stateful/runme/internal/env" runnerv1 "github.com/stateful/runme/internal/gen/proto/go/runme/runner/v1" - "github.com/stateful/runme/internal/project" "github.com/stateful/runme/internal/rbuffer" + "github.com/stateful/runme/pkg/project" "go.uber.org/zap" "golang.org/x/sync/errgroup" "google.golang.org/genproto/googleapis/rpc/errdetails" diff --git a/internal/runner/session.go b/internal/runner/session.go index 6d901e57..d553bf62 100644 --- a/internal/runner/session.go +++ b/internal/runner/session.go @@ -6,7 +6,7 @@ import ( lru "github.com/hashicorp/golang-lru/v2" "github.com/rs/xid" - "github.com/stateful/runme/internal/project" + "github.com/stateful/runme/pkg/project" "go.uber.org/zap" ) diff --git a/internal/tui/model_list.go b/internal/tui/model_list.go index 33c0a1a9..c7c3d6cf 100644 --- a/internal/tui/model_list.go +++ b/internal/tui/model_list.go @@ -19,7 +19,7 @@ import ( "github.com/stateful/runme/internal/client/graphql" "github.com/stateful/runme/internal/client/graphql/query" "github.com/stateful/runme/internal/log" - "github.com/stateful/runme/internal/project" + "github.com/stateful/runme/pkg/project" "go.uber.org/zap" ) diff --git a/internal/project/TEST.md b/pkg/project/TEST.md similarity index 100% rename from internal/project/TEST.md rename to pkg/project/TEST.md diff --git a/internal/project/TEST2.md b/pkg/project/TEST2.md similarity index 100% rename from internal/project/TEST2.md rename to pkg/project/TEST2.md diff --git a/internal/project/document.go b/pkg/project/document.go similarity index 100% rename from internal/project/document.go rename to pkg/project/document.go diff --git a/internal/project/formatter.go b/pkg/project/formatter.go similarity index 95% rename from internal/project/formatter.go rename to pkg/project/formatter.go index 3a502a2c..16b4a41e 100644 --- a/internal/project/formatter.go +++ b/pkg/project/formatter.go @@ -16,9 +16,9 @@ import ( "github.com/stateful/runme/internal/renderer/cmark" ) -type funcFmt func(string, []byte) error +type funcOutput func(string, []byte) error -func Format(files []string, basePath string, flatten bool, formatJSON bool, write bool, formatter funcFmt) error { +func Format(files []string, basePath string, flatten bool, formatJSON bool, write bool, outputter funcOutput) error { for _, relFile := range files { data, err := readMarkdown(basePath, []string{relFile}) if err != nil { @@ -62,7 +62,7 @@ func Format(files []string, basePath string, flatten bool, formatJSON bool, writ if write { err = writeMarkdown(basePath, []string{relFile}, formatted) } else { - err = formatter(relFile, formatted) + err = outputter(relFile, formatted) } if err != nil { diff --git a/internal/project/project.go b/pkg/project/project.go similarity index 100% rename from internal/project/project.go rename to pkg/project/project.go diff --git a/internal/project/project_test.go b/pkg/project/project_test.go similarity index 100% rename from internal/project/project_test.go rename to pkg/project/project_test.go diff --git a/internal/project/repo.go b/pkg/project/repo.go similarity index 100% rename from internal/project/repo.go rename to pkg/project/repo.go diff --git a/internal/project/repo_test.go b/pkg/project/repo_test.go similarity index 100% rename from internal/project/repo_test.go rename to pkg/project/repo_test.go diff --git a/internal/project/test_project/.env b/pkg/project/test_project/.env similarity index 100% rename from internal/project/test_project/.env rename to pkg/project/test_project/.env diff --git a/internal/project/test_project/.env.local b/pkg/project/test_project/.env.local similarity index 100% rename from internal/project/test_project/.env.local rename to pkg/project/test_project/.env.local diff --git a/internal/project/test_project/IGNORED.md b/pkg/project/test_project/IGNORED.md similarity index 100% rename from internal/project/test_project/IGNORED.md rename to pkg/project/test_project/IGNORED.md diff --git a/internal/project/test_project/README.md b/pkg/project/test_project/README.md similarity index 100% rename from internal/project/test_project/README.md rename to pkg/project/test_project/README.md diff --git a/internal/project/test_project/ignored/README.md b/pkg/project/test_project/ignored/README.md similarity index 100% rename from internal/project/test_project/ignored/README.md rename to pkg/project/test_project/ignored/README.md diff --git a/internal/project/test_project/src/DOCS.md b/pkg/project/test_project/src/DOCS.md similarity index 100% rename from internal/project/test_project/src/DOCS.md rename to pkg/project/test_project/src/DOCS.md From 107dc29254ae44f42b4deaae85c98e4aab5f4776 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Wed, 20 Sep 2023 17:01:14 -0400 Subject: [PATCH 2/3] Break out loader from project --- internal/cmd/common.go | 212 +------------------------------------ internal/cmd/fmt.go | 3 +- internal/cmd/list.go | 3 +- internal/cmd/print.go | 3 +- internal/cmd/run.go | 3 +- internal/cmd/tasks.go | 3 +- internal/cmd/tui.go | 3 +- pkg/project/loader.go | 231 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 214 deletions(-) create mode 100644 pkg/project/loader.go diff --git a/internal/cmd/common.go b/internal/cmd/common.go index 90f73549..44912d0b 100644 --- a/internal/cmd/common.go +++ b/internal/cmd/common.go @@ -4,15 +4,12 @@ import ( "bytes" "context" "fmt" - "io" "os" "path/filepath" "regexp" "strconv" "strings" - "github.com/charmbracelet/bubbles/spinner" - tea "github.com/charmbracelet/bubbletea" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/stateful/runme/internal/document" @@ -57,6 +54,10 @@ func getProject() (proj project.Project, err error) { return } +func getLoader(cmd *cobra.Command) project.ProjectLoader { + return project.NewLoader(cmd.OutOrStdout(), cmd.InOrStdin(), isTerminal(os.Stdout.Fd())) +} + func getCodeBlocks() (document.CodeBlocks, error) { return project.GetCodeBlocks( filepath.Join(fChdir, fFileName), @@ -315,208 +316,3 @@ func replaceVarValue(ev CommandExportExtractMatch, newValue string) string { replacedText := fmt.Sprintf("%s=%q", parts[0], newValue) return replacedText } - -type loadTasksModel struct { - spinner spinner.Model - - status string - filename string - - clear bool - - err error - - tasks project.CodeBlocks - files []string - - nextTaskMsg tea.Cmd -} - -type loadTaskFinished struct{} - -func newLoadTasksModel(nextTaskMsg tea.Cmd) loadTasksModel { - return loadTasksModel{ - spinner: spinner.New(spinner.WithSpinner(spinner.MiniDot)), - nextTaskMsg: nextTaskMsg, - status: "Initializing...", - tasks: make(project.CodeBlocks, 0), - } -} - -func loadFiles(proj project.Project, w io.Writer, r io.Reader) ([]string, error) { - m, err := runTasksModel(proj, true, w, r) - if err != nil { - return nil, err - } - - return m.files, nil -} - -func loadTasks(proj project.Project, w io.Writer, r io.Reader, filter bool) (project.CodeBlocks, error) { - m, err := runTasksModel(proj, false, w, r) - if err != nil { - return nil, err - } - - tasks := m.tasks - - if filter { - tasks = project.FilterCodeBlocks[project.CodeBlock](m.tasks, fAllowUnknown, fAllowUnnamed) - - if len(tasks) == 0 { - // try again without filtering unnamed - tasks = project.FilterCodeBlocks[project.CodeBlock](m.tasks, fAllowUnknown, true) - } - } - - return tasks, nil -} - -func runTasksModel(proj project.Project, filesOnly bool, w io.Writer, r io.Reader) (*loadTasksModel, error) { - channel := make(chan interface{}) - go proj.LoadTasks(filesOnly, channel) - - nextTaskMsg := func() tea.Msg { - msg, ok := <-channel - - if !ok { - return loadTaskFinished{} - } - - return msg - } - - m := newLoadTasksModel(nextTaskMsg) - - resultModel := m - - if isTerminal(os.Stdout.Fd()) { - p := tea.NewProgram(m, tea.WithOutput(w), tea.WithInput(r)) - result, err := p.Run() - if err != nil { - return nil, err - } - - resultModel = result.(loadTasksModel) - } else { - if strings.ToLower(os.Getenv("RUNME_VERBOSE")) != "true" { - w = io.Discard - } - - _, _ = fmt.Fprintln(w, "Initializing...") - - outer: - for { - if resultModel.err != nil { - break - } - - switch msg := nextTaskMsg().(type) { - case loadTaskFinished: - _, _ = fmt.Fprintln(w, "") - break outer - case project.LoadTaskStatusSearchingFiles: - _, _ = fmt.Fprintln(w, "Searching for files...") - case project.LoadTaskStatusParsingFiles: - _, _ = fmt.Fprintln(w, "Parsing files...") - default: - if newModel, ok := resultModel.TaskUpdate(msg).(loadTasksModel); ok { - resultModel = newModel - } - } - } - } - - if resultModel.err != nil { - return nil, resultModel.err - } - - return &resultModel, nil -} - -func (m loadTasksModel) Init() tea.Cmd { - return tea.Batch( - func() tea.Msg { - return m.spinner.Tick() - }, - m.nextTaskMsg, - ) -} - -func (m loadTasksModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - if m.err != nil { - return m, tea.Quit - } - - switch msg := msg.(type) { - case spinner.TickMsg: - var cmd tea.Cmd - m.spinner, cmd = m.spinner.Update(msg) - return m, cmd - case loadTaskFinished: - m.clear = true - return m, tea.Quit - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "crtl+d": - m.err = errors.New("aborted") - return m, tea.Quit - } - } - - if m, ok := m.TaskUpdate(msg).(loadTasksModel); ok { - return m, m.nextTaskMsg - } - - return m, nil -} - -func (m loadTasksModel) TaskUpdate(msg tea.Msg) tea.Model { - switch msg := msg.(type) { - - case project.LoadTaskError: - m.err = msg.Err - - // status - case project.LoadTaskStatusSearchingFiles: - m.filename = "" - m.status = "Searching for files..." - case project.LoadTaskStatusParsingFiles: - m.filename = "" - m.status = "Parsing files..." - - // filename - case project.LoadTaskSearchingFolder: - m.filename = msg.Folder - case project.LoadTaskParsingFile: - m.filename = msg.Filename - - // results - case project.LoadTaskFoundFile: - m.files = append(m.files, msg.Filename) - case project.LoadTaskFoundTask: - m.tasks = append(m.tasks, msg.Task) - - default: - return nil - } - - return m -} - -func (m loadTasksModel) View() (s string) { - if m.clear { - return - } - - s += m.spinner.View() - s += " " - - s += m.status - - if m.filename != "" { - s += fmt.Sprintf(" (%s)", m.filename) - } - - return -} diff --git a/internal/cmd/fmt.go b/internal/cmd/fmt.go index 1daf4591..80312b24 100644 --- a/internal/cmd/fmt.go +++ b/internal/cmd/fmt.go @@ -37,7 +37,8 @@ func fmtCmd() *cobra.Command { files := args if len(files) == 0 { - projectFiles, err := loadFiles(proj, cmd.OutOrStdout(), cmd.InOrStdin()) + loader := getLoader(cmd) + projectFiles, err := loader.LoadFiles(proj) if err != nil { return err } diff --git a/internal/cmd/list.go b/internal/cmd/list.go index 88d8ab8d..e48beb0f 100644 --- a/internal/cmd/list.go +++ b/internal/cmd/list.go @@ -43,7 +43,8 @@ func listCmd() *cobra.Command { return err } - allBlocks, err := loadTasks(proj, cmd.OutOrStdout(), cmd.InOrStdin(), true) + loader := getLoader(cmd) + allBlocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err } diff --git a/internal/cmd/print.go b/internal/cmd/print.go index 0e17f37b..f922d2cc 100644 --- a/internal/cmd/print.go +++ b/internal/cmd/print.go @@ -22,7 +22,8 @@ func printCmd() *cobra.Command { } generateBlocks: - blocks, err := loadTasks(proj, cmd.OutOrStdout(), cmd.InOrStdin(), true) + loader := getLoader(cmd) + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err } diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 7a70cf2a..8223ed62 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -75,7 +75,8 @@ func runCmd() *cobra.Command { { searchBlocks: - blocks, err := loadTasks(proj, cmd.OutOrStdout(), cmd.InOrStdin(), true) + loader := getLoader(cmd) + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err } diff --git a/internal/cmd/tasks.go b/internal/cmd/tasks.go index 75a2ed4b..1b0ee948 100644 --- a/internal/cmd/tasks.go +++ b/internal/cmd/tasks.go @@ -22,7 +22,8 @@ func tasksCmd() *cobra.Command { } generateBlocks: - blocks, err := loadTasks(proj, cmd.OutOrStdout(), cmd.InOrStdin(), true) + loader := getLoader(cmd) + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err } diff --git a/internal/cmd/tui.go b/internal/cmd/tui.go index 58dd1d7c..b97da91c 100644 --- a/internal/cmd/tui.go +++ b/internal/cmd/tui.go @@ -37,7 +37,8 @@ func tuiCmd() *cobra.Command { return err } - blocks, err := loadTasks(proj, cmd.OutOrStdout(), cmd.InOrStdin(), false) + loader := getLoader(cmd) + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, false) if err != nil { return err } diff --git a/pkg/project/loader.go b/pkg/project/loader.go new file mode 100644 index 00000000..b3d99f81 --- /dev/null +++ b/pkg/project/loader.go @@ -0,0 +1,231 @@ +package project + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/charmbracelet/bubbles/spinner" + tea "github.com/charmbracelet/bubbletea" + "github.com/pkg/errors" +) + +type ProjectLoader struct { + w io.Writer + r io.Reader + isTerminal bool +} + +func NewLoader(w io.Writer, r io.Reader, isTerminal bool) ProjectLoader { + return ProjectLoader{ + w: w, + r: r, + isTerminal: isTerminal, + } +} + +type loadTasksModel struct { + spinner spinner.Model + + status string + filename string + + clear bool + + err error + + tasks CodeBlocks + files []string + + nextTaskMsg tea.Cmd +} + +type loadTaskFinished struct{} + +func (pl ProjectLoader) newLoadTasksModel(nextTaskMsg tea.Cmd) loadTasksModel { + return loadTasksModel{ + spinner: spinner.New(spinner.WithSpinner(spinner.MiniDot)), + nextTaskMsg: nextTaskMsg, + status: "Initializing...", + tasks: make(CodeBlocks, 0), + } +} + +func (pl ProjectLoader) LoadFiles(proj Project) ([]string, error) { + m, err := pl.runTasksModel(proj, true) + if err != nil { + return nil, err + } + + return m.files, nil +} + +func (pl ProjectLoader) LoadTasks(proj Project, allowUnknown bool, allowUnnamed bool, filter bool) (CodeBlocks, error) { + m, err := pl.runTasksModel(proj, false) + if err != nil { + return nil, err + } + + tasks := m.tasks + + if filter { + tasks = FilterCodeBlocks[CodeBlock](m.tasks, allowUnknown, allowUnnamed) + + if len(tasks) == 0 { + // try again without filtering unnamed + tasks = FilterCodeBlocks[CodeBlock](m.tasks, allowUnknown, true) + } + } + + return tasks, nil +} + +func (pl ProjectLoader) runTasksModel(proj Project, filesOnly bool) (*loadTasksModel, error) { + channel := make(chan interface{}) + go proj.LoadTasks(filesOnly, channel) + + nextTaskMsg := func() tea.Msg { + msg, ok := <-channel + + if !ok { + return loadTaskFinished{} + } + + return msg + } + + m := pl.newLoadTasksModel(nextTaskMsg) + + resultModel := m + + if pl.isTerminal { + p := tea.NewProgram(m, tea.WithOutput(pl.w), tea.WithInput(pl.r)) + result, err := p.Run() + if err != nil { + return nil, err + } + + resultModel = result.(loadTasksModel) + } else { + if strings.ToLower(os.Getenv("RUNME_VERBOSE")) != "true" { + pl.w = io.Discard + } + + _, _ = fmt.Fprintln(pl.w, "Initializing...") + + outer: + for { + if resultModel.err != nil { + break + } + + switch msg := nextTaskMsg().(type) { + case loadTaskFinished: + _, _ = fmt.Fprintln(pl.w, "") + break outer + case LoadTaskStatusSearchingFiles: + _, _ = fmt.Fprintln(pl.w, "Searching for files...") + case LoadTaskStatusParsingFiles: + _, _ = fmt.Fprintln(pl.w, "Parsing files...") + default: + if newModel, ok := resultModel.TaskUpdate(msg).(loadTasksModel); ok { + resultModel = newModel + } + } + } + } + + if resultModel.err != nil { + return nil, resultModel.err + } + + return &resultModel, nil +} + +func (m loadTasksModel) Init() tea.Cmd { + return tea.Batch( + func() tea.Msg { + return m.spinner.Tick() + }, + m.nextTaskMsg, + ) +} + +func (m loadTasksModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + if m.err != nil { + return m, tea.Quit + } + + switch msg := msg.(type) { + case spinner.TickMsg: + var cmd tea.Cmd + m.spinner, cmd = m.spinner.Update(msg) + return m, cmd + case loadTaskFinished: + m.clear = true + return m, tea.Quit + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "crtl+d": + m.err = errors.New("aborted") + return m, tea.Quit + } + } + + if m, ok := m.TaskUpdate(msg).(loadTasksModel); ok { + return m, m.nextTaskMsg + } + + return m, nil +} + +func (m loadTasksModel) TaskUpdate(msg tea.Msg) tea.Model { + switch msg := msg.(type) { + + case LoadTaskError: + m.err = msg.Err + + // status + case LoadTaskStatusSearchingFiles: + m.filename = "" + m.status = "Searching for files..." + case LoadTaskStatusParsingFiles: + m.filename = "" + m.status = "Parsing files..." + + // filename + case LoadTaskSearchingFolder: + m.filename = msg.Folder + case LoadTaskParsingFile: + m.filename = msg.Filename + + // results + case LoadTaskFoundFile: + m.files = append(m.files, msg.Filename) + case LoadTaskFoundTask: + m.tasks = append(m.tasks, msg.Task) + + default: + return nil + } + + return m +} + +func (m loadTasksModel) View() (s string) { + if m.clear { + return + } + + s += m.spinner.View() + s += " " + + s += m.status + + if m.filename != "" { + s += fmt.Sprintf(" (%s)", m.filename) + } + + return +} From 047db90a5cdc49ecf5777a031e3e32792c5dc017 Mon Sep 17 00:00:00 2001 From: Cristian Cepeda <43882+pastuxso@users.noreply.github.com> Date: Tue, 26 Sep 2023 11:30:09 -0500 Subject: [PATCH 3/3] enhance readability - handle potential error. - renames function getLoader to newProjectLoader --- internal/cmd/common.go | 11 +++++++++-- internal/cmd/fmt.go | 6 +++++- internal/cmd/list.go | 6 +++++- internal/cmd/print.go | 6 +++++- internal/cmd/run.go | 6 +++++- internal/cmd/tasks.go | 6 +++++- internal/cmd/tui.go | 6 +++++- 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/internal/cmd/common.go b/internal/cmd/common.go index 44912d0b..0d34fece 100644 --- a/internal/cmd/common.go +++ b/internal/cmd/common.go @@ -54,8 +54,15 @@ func getProject() (proj project.Project, err error) { return } -func getLoader(cmd *cobra.Command) project.ProjectLoader { - return project.NewLoader(cmd.OutOrStdout(), cmd.InOrStdin(), isTerminal(os.Stdout.Fd())) +func newProjectLoader(cmd *cobra.Command) (*project.ProjectLoader, error) { + fd := os.Stdout.Fd() + + if int(fd) >= 0 { + loader := project.NewLoader(cmd.OutOrStdout(), cmd.InOrStdin(), isTerminal(fd)) + return &loader, nil + } + + return nil, fmt.Errorf("invalid file descriptor due to restricted environments, redirected standard output, system configuration issues, or testing/simulation setups") } func getCodeBlocks() (document.CodeBlocks, error) { diff --git a/internal/cmd/fmt.go b/internal/cmd/fmt.go index 80312b24..50933c91 100644 --- a/internal/cmd/fmt.go +++ b/internal/cmd/fmt.go @@ -37,7 +37,11 @@ func fmtCmd() *cobra.Command { files := args if len(files) == 0 { - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + projectFiles, err := loader.LoadFiles(proj) if err != nil { return err diff --git a/internal/cmd/list.go b/internal/cmd/list.go index e48beb0f..2aa206d0 100644 --- a/internal/cmd/list.go +++ b/internal/cmd/list.go @@ -43,7 +43,11 @@ func listCmd() *cobra.Command { return err } - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + allBlocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err diff --git a/internal/cmd/print.go b/internal/cmd/print.go index f922d2cc..c3e2df90 100644 --- a/internal/cmd/print.go +++ b/internal/cmd/print.go @@ -22,7 +22,11 @@ func printCmd() *cobra.Command { } generateBlocks: - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err diff --git a/internal/cmd/run.go b/internal/cmd/run.go index 8223ed62..85154448 100644 --- a/internal/cmd/run.go +++ b/internal/cmd/run.go @@ -75,7 +75,11 @@ func runCmd() *cobra.Command { { searchBlocks: - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err diff --git a/internal/cmd/tasks.go b/internal/cmd/tasks.go index 1b0ee948..a4469c19 100644 --- a/internal/cmd/tasks.go +++ b/internal/cmd/tasks.go @@ -22,7 +22,11 @@ func tasksCmd() *cobra.Command { } generateBlocks: - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, true) if err != nil { return err diff --git a/internal/cmd/tui.go b/internal/cmd/tui.go index b97da91c..b1596454 100644 --- a/internal/cmd/tui.go +++ b/internal/cmd/tui.go @@ -37,7 +37,11 @@ func tuiCmd() *cobra.Command { return err } - loader := getLoader(cmd) + loader, err := newProjectLoader(cmd) + if err != nil { + return err + } + blocks, err := loader.LoadTasks(proj, fAllowUnknown, fAllowUnnamed, false) if err != nil { return err