package main import ( "fmt" "io" "maps" "os" "slices" "github.com/cuonglm/gogi" "github.com/manifoldco/promptui" "github.com/spf13/cobra" "github.com/spf13/viper" ) const gitignoreFileName string = ".gitignore" // newCmd represents the new command. var newCmd = &cobra.Command{ Use: "new", Short: "Create a new .gitignore file", RunE: runNewCommand, } func init() { rootCmd.AddCommand(newCmd) } type promptConfig struct { Height int StartSearch bool FilterType string } func runNewCommand(cmd *cobra.Command, _ []string) error { pc := promptConfig{ Height: viper.GetInt("height"), StartSearch: viper.GetBool("start-search"), FilterType: viper.GetString("filter"), } client, ok := ClientFromContext(cmd.Context()) if !ok { return fmt.Errorf("failed to retrieve gogi client from context") } content, err := runPrompt(client, &pc) if err != nil { return fmt.Errorf("failed to run prompt: %w", err) } f, err := os.OpenFile(gitignoreFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) if err != nil { return fmt.Errorf("error opening file '%s': %w", gitignoreFileName, err) } defer func() { if err := f.Close(); err != nil { fmt.Fprintf(os.Stderr, "error closing file '%s': %v\n", gitignoreFileName, err) } }() if err = commitGitignore(content, f); err != nil { return fmt.Errorf("error committing gitignore file: %w", err) } return nil } // runPrompt is a helper function to run the selection prompt for .gitignore templates. func runPrompt(client *gogi.Client, pc *promptConfig) (string, error) { data, err := client.ListJson() if err != nil { return "", fmt.Errorf("error retrieving gitignore templates: %w", err) } templateNames := slices.Sorted(maps.Keys(data)) selectTemplates := &promptui.SelectTemplates{ Label: ` {{ "\U0000007C" | faint }} {{ . | magenta | bold }}`, Active: `{{ "\U0000007C" | faint }} {{ "🌶" | red }} {{ . | cyan | italic }}`, Inactive: `{{ "\U0000007C" | faint }} {{ . | faint }}`, Selected: `{{ "Created" | green }} {{ . }} {{ ".gitignore file ✓" | green }}`, } prompt := promptui.Select{ Label: "Select a .gitignore template", Items: templateNames, Templates: selectTemplates, Size: pc.Height, Searcher: filterFunc(templateNames, pc.FilterType), StartInSearchMode: pc.StartSearch, } i, _, err := prompt.Run() if err != nil { return "", fmt.Errorf("error running prompt: %w", err) } return data[templateNames[i]].Contents, nil } // commitGitignore writes the content of the selected gitignore template to the .gitignore file. func commitGitignore(content string, w io.Writer) error { if _, err := fmt.Fprintf( w, "# Generated by gogn: github.com/onyx-and-iris/gogn\n", ); err != nil { return fmt.Errorf("error writing header to file '%s': %w", gitignoreFileName, err) } if _, err := fmt.Fprintf(w, "%s", content); err != nil { return fmt.Errorf("error writing to file '%s': %w", gitignoreFileName, err) } if _, err := fmt.Fprintf(w, "\n# End of gogn\n"); err != nil { return fmt.Errorf("error writing footer to file '%s': %w", gitignoreFileName, err) } return nil }