diff --git a/v3/go.mod b/v3/go.mod index 8b15d833e7a..f63602d78c8 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -43,6 +43,18 @@ require ( modernc.org/sqlite v1.21.0 ) +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/catppuccin/go v0.2.0 // indirect + github.com/charmbracelet/bubbles v0.20.0 // indirect + github.com/charmbracelet/bubbletea v1.1.0 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect +) + require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect @@ -62,8 +74,9 @@ require ( github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect github.com/cavaliergopher/cpio v1.0.1 // indirect github.com/chainguard-dev/git-urls v1.0.2 // indirect - github.com/charmbracelet/lipgloss v0.12.1 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect + github.com/charmbracelet/huh v0.6.0 + github.com/charmbracelet/lipgloss v0.13.0 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/cloudflare/circl v1.5.0 // indirect github.com/containerd/console v1.0.4 // indirect github.com/cyphar/filepath-securejoin v0.4.0 // indirect diff --git a/v3/go.sum b/v3/go.sum index fa60e714248..3dd5ef673e3 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -55,6 +55,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atterpac/refresh v0.8.3 h1:Xj0rtd6Wfv/u03wZOdauASBOPxGZOJeik065S0wISNg= github.com/atterpac/refresh v0.8.3/go.mod h1:fJpWySLdpbANS8Ej5OvfZVZIVvi/9bmnhTjKS5EjQes= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -69,18 +71,34 @@ github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8= github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ= github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c= +github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= +github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8= +github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU= github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs= github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4 h1:6KzMkQeAF56rggw2NZu1L+TH7j9+DM1/2Kmh7KUxg1I= github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= @@ -105,6 +123,8 @@ github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -224,6 +244,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= @@ -244,6 +266,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -373,6 +397,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/v3/internal/commands/init.go b/v3/internal/commands/init.go index 8a346f88883..1c9f4c0132a 100644 --- a/v3/internal/commands/init.go +++ b/v3/internal/commands/init.go @@ -2,17 +2,19 @@ package commands import ( "fmt" - "github.com/go-git/go-git/v5/config" - "github.com/wailsapp/wails/v3/internal/term" "os" "path/filepath" "regexp" "strings" + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" "github.com/pterm/pterm" "github.com/wailsapp/wails/v3/internal/flags" "github.com/wailsapp/wails/v3/internal/templates" + "github.com/wailsapp/wails/v3/internal/term" ) var DisableFooter bool @@ -120,7 +122,14 @@ func Init(options *flags.Init) error { } if options.ProjectName == "" { - return fmt.Errorf("please use the -n flag to specify a project name") + interactiveOptions, err := startInteractive(options) + if err != nil { + return err + } + options = interactiveOptions + if options.ProjectName == "" { + return fmt.Errorf("project name is required") + } } options.ProjectName = sanitizeFileName(options.ProjectName) @@ -188,3 +197,132 @@ func sanitizeFileName(fileName string) string { // Replace matched characters with an underscore or any other safe character return reg.ReplaceAllString(fileName, "_") } + +func startInteractive(initialOptions *flags.Init) (*flags.Init, error) { + var templateOptions []huh.Option[string] + var templateSelect *huh.Select[string] + confirmProjectCreation := false + + options := initialOptions + + if options == nil { + options = &flags.Init{ + ProductVersion: "1.0.0", + } + } else if options.ProductVersion == "" { + options.ProductVersion = "1.0.0" + } + templateName := &options.TemplateName + + templateSelect = huh.NewSelect[string](). + Title("Template"). + Description("Project template to use (Enter to list)"). + Options(templateOptions...). + Value(templateName) + + form := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title("Project Name"). + Description("Name of project"). + Value(&options.ProjectName), + + huh.NewInput(). + Title("Project Dir"). + Description("Target directory (empty for default)"). + Value(&options.ProjectDir), + + templateSelect, + ), + huh.NewGroup( + huh.NewInput(). + Title("Git Repo URL (optional)"). + Description("Git repo to initialize (optional)"). + Value(&options.Git), + ), + huh.NewGroup( + huh.NewInput(). + Title("Company (optional)"). + Value(&options.ProductCompany), + huh.NewInput(). + Title("Product Name (optional)"). + Value(&options.ProductName), + huh.NewInput(). + Title("Version (optional)"). + Value(&options.ProductVersion), + huh.NewInput(). + Title("ID (optional)"). + Value(&options.ProductIdentifier), + huh.NewInput(). + Title("Copyright (optional)"). + Value(&options.ProductCopyright), + huh.NewText(). + Title("Description (optional)"). + Lines(1). + Value(&options.ProductDescription), + huh.NewText(). + Title("Comments (optional)"). + Lines(1). + Value(&options.ProductComments), + ), + huh.NewGroup( + huh.NewConfirm(). + Title("Confirm?"). + Value(&confirmProjectCreation), + ), + ) + + templateSelect.OptionsFunc(func() []huh.Option[string] { + defaultTemplates := templates.GetDefaultTemplates() + + vanillaTemplate := templates.TemplateData{Name: "vanilla", Description: ""} + orderedTemplates := []templates.TemplateData{} + vanillaFound := false + for _, t := range defaultTemplates { + if t.Name == vanillaTemplate.Name { + orderedTemplates = append([]templates.TemplateData{t}, orderedTemplates...) + vanillaFound = true + } else { + orderedTemplates = append(orderedTemplates, t) + } + } + if !vanillaFound { + orderedTemplates = append([]templates.TemplateData{vanillaTemplate}, orderedTemplates...) + } + + templateOptions = nil + for _, t := range orderedTemplates { + templateOptions = append(templateOptions, huh.NewOption(t.Name, t.Name)) + } + + *templateName = "vanilla" + + return templateOptions + }, nil) + + formStyle := lipgloss.NewStyle(). + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(lipgloss.Color("62")). + Padding(1, 2). + Margin(1, 0) + + formRenderer := lipgloss.NewRenderer(os.Stdout) + + err := form.Run() + if err != nil { + term.Error(fmt.Errorf("Interactive form failed: %w", err)) + return nil, fmt.Errorf("form execution failed: %w", err) + } + + formString := formRenderer.NewStyle().Render(form.View()) + styledForm := formStyle.Render(formString) + fmt.Println(styledForm) + + if confirmProjectCreation { + fmt.Println("Creating project...") + return options, nil + } else { + fmt.Println("Project creation cancelled.") + return nil, fmt.Errorf("project creation cancelled by user") + } +}