gogn/new.go
2026-02-15 15:31:24 +00:00

120 lines
3.1 KiB
Go

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
}