From 16ce1d3448841b1ef273d7f0aa89aa904a7fb205 Mon Sep 17 00:00:00 2001 From: Fabio Massaioli Date: Thu, 23 Jan 2025 11:53:48 +0100 Subject: [PATCH 1/4] [v3] Service API cleanup and comments (#4024) * Gather and document service API * Update changelog * Add NewServiceWithOptions * Revert static analyser change * Remove infinite loop in NewService[WithOptions] * Fix compiler warning in bindings command * Add test for NewServiceWithOptions * Update changelog * Fix service example --------- Co-authored-by: Lea Anthony --- docs/src/content/docs/changelog.mdx | 3 + docs/src/content/docs/learn/services.mdx | 28 ++++++-- v3/examples/services/main.go | 2 +- v3/internal/commands/bindings.go | 2 +- v3/internal/generator/errors.go | 8 +-- .../complex_instantiations/bound_types.json | 3 +- .../testcases/complex_instantiations/funcs.go | 2 +- .../testcases/complex_instantiations/main.go | 2 + .../complex_instantiations/other/funcs.go | 2 +- .../complex_instantiations/other/local.go | 4 +- v3/pkg/application/application_options.go | 34 --------- v3/pkg/application/services.go | 72 +++++++++++++++++++ 12 files changed, 113 insertions(+), 49 deletions(-) diff --git a/docs/src/content/docs/changelog.mdx b/docs/src/content/docs/changelog.mdx index 7ad0571f437..39cb27011f8 100644 --- a/docs/src/content/docs/changelog.mdx +++ b/docs/src/content/docs/changelog.mdx @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `window-call` example to demonstrate how to know which window is calling a service by [@leaanthony](https://github.com/leaanthony) - Better panic handling by [@leaanthony](https://github.com/leaanthony) - New Menu guide by [@leaanthony](https://github.com/leaanthony) +- Add doc comments for Service API by [@fbbdev](https://github.com/fbbdev) in [#4024](https://github.com/wailsapp/wails/pull/4024) +- Add function `application.NewServiceWithOptions` to initialise services with additional configuration by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) ### Fixed @@ -52,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `application.WindowIDKey` and `application.WindowNameKey` (replaced by `application.WindowKey`) by [@leaanthony](https://github.com/leaanthony) - In JS/TS bindings, class fields of fixed-length array types are now initialized with their expected length instead of being empty by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) - ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) +- `application.NewService` does not accept options as an optional parameter anymore (use `application.NewServiceWithOptions` instead) by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) ## v3.0.0-alpha.9 - 2025-01-13 diff --git a/docs/src/content/docs/learn/services.mdx b/docs/src/content/docs/learn/services.mdx index f555fc85623..2e82e944b36 100644 --- a/docs/src/content/docs/learn/services.mdx +++ b/docs/src/content/docs/learn/services.mdx @@ -52,6 +52,24 @@ app := application.New(application.Options{ }) ``` +This registers the `NewMyService` function as a service with the application. + +Services may also be registered with additional options: + +```go +app := application.New(application.Options{ + Services: []application.Service{ + application.NewServiceWithOptions(NewMyService(), application.ServiceOptions{ + // ... + }) + } +}) +``` + +ServiceOptions has the following fields: + - Name - Specify a custom name for the Service + - Route - A route to bind the Service to the frontend (more on this below) + ## Optional Methods Services can implement optional methods to hook into the application lifecycle. @@ -67,8 +85,10 @@ bindings generated for a service, so they are not exposed to your frontend. func (s *Service) ServiceName() string ``` -This method returns the name of the service. It is used for logging purposes -only. +This method returns the name of the service. By default, it will the struct name of the Service but can be +overridden with the `Name` field of the `ServiceOptions`. + +It is used for logging purposes only. ### ServiceStartup @@ -101,7 +121,7 @@ your service to act as an HTTP handler. The route of the handler is defined in the service options: ```go -application.NewService(fileserver.New(&fileserver.Config{ +application.NewServiceWithOptions(fileserver.New(&fileserver.Config{ RootPath: rootPath, }), application.ServiceOptions{ Route: "/files", @@ -144,7 +164,7 @@ We can now use this service in our application: ```go app := application.New(application.Options{ Services: []application.Service{ - application.NewService(fileserver.New(&fileserver.Config{ + application.NewServiceWithOptions(fileserver.New(&fileserver.Config{ RootPath: rootPath, }), application.ServiceOptions{ Route: "/files", diff --git a/v3/examples/services/main.go b/v3/examples/services/main.go index 74668cb9187..a4ebb6bf463 100644 --- a/v3/examples/services/main.go +++ b/v3/examples/services/main.go @@ -43,7 +43,7 @@ func main() { AutoSave: true, })), application.NewService(log.New()), - application.NewService(fileserver.New(&fileserver.Config{ + application.NewServiceWithOptions(fileserver.New(&fileserver.Config{ RootPath: rootPath, }), application.ServiceOptions{ Route: "/files", diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index 478c16b2161..f73285a29b8 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -77,7 +77,7 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) if spinner != nil { spinner.Info(resultMessage) } else { - term.Infofln(resultMessage) + term.Infofln("%s", resultMessage) } // Report output directory. diff --git a/v3/internal/generator/errors.go b/v3/internal/generator/errors.go index d5b8acfd60a..cb000d1ad47 100644 --- a/v3/internal/generator/errors.go +++ b/v3/internal/generator/errors.go @@ -13,16 +13,16 @@ import ( // ErrNoContextPackage indicates that // the canonical path for the standard context package // did not match any actual package. -var ErrNoContextPackage = errors.New("standard context package not found at canonical import path ('context'): is the Wails v3 module properly installed?") +var ErrNoContextPackage = errors.New("standard context package not found at canonical import path ('context'): is the Wails v3 module properly installed? ") // ErrNoApplicationPackage indicates that // the canonical path for the Wails application package // did not match any actual package. -var ErrNoApplicationPackage = errors.New("Wails application package not found at canonical import path ('" + config.WailsAppPkgPath + "'): is the Wails v3 module properly installed?") +var ErrNoApplicationPackage = errors.New("Wails application package not found at canonical import path ('" + config.WailsAppPkgPath + "'): is the Wails v3 module properly installed? ") // ErrBadApplicationPackage indicates that // the Wails application package has invalid content. -var ErrBadApplicationPackage = errors.New("package " + config.WailsAppPkgPath + ": function NewService has wrong signature: is the Wails v3 module properly installed?") +var ErrBadApplicationPackage = errors.New("package " + config.WailsAppPkgPath + ": function NewService has wrong signature: is the Wails v3 module properly installed? ") // ErrNoPackages is returned by [Generator.Generate] // when [LoadPackages] returns no error and no packages. @@ -43,7 +43,7 @@ type ErrorReport struct { errors map[string]bool } -// NewError report initialises an ErrorReport instance +// NewErrorReport report initialises an ErrorReport instance // with the provided Logger implementation. // // If logger is nil, messages will be accumulated but not logged. diff --git a/v3/internal/generator/testcases/complex_instantiations/bound_types.json b/v3/internal/generator/testcases/complex_instantiations/bound_types.json index eeb776de377..ece1b922096 100644 --- a/v3/internal/generator/testcases/complex_instantiations/bound_types.json +++ b/v3/internal/generator/testcases/complex_instantiations/bound_types.json @@ -11,5 +11,6 @@ ".Service10", ".Service11", ".Service12", - "/other.Service13" + ".Service13", + "/other.Service14" ] diff --git a/v3/internal/generator/testcases/complex_instantiations/funcs.go b/v3/internal/generator/testcases/complex_instantiations/funcs.go index 73788baf6c1..7aea0e7e0c6 100644 --- a/v3/internal/generator/testcases/complex_instantiations/funcs.go +++ b/v3/internal/generator/testcases/complex_instantiations/funcs.go @@ -2,7 +2,7 @@ package main import "github.com/wailsapp/wails/v3/pkg/application" -func ServiceInitialiser[T any]() func(*T, ...application.ServiceOptions) application.Service { +func ServiceInitialiser[T any]() func(*T) application.Service { return application.NewService[T] } diff --git a/v3/internal/generator/testcases/complex_instantiations/main.go b/v3/internal/generator/testcases/complex_instantiations/main.go index 872a029d0bb..74e03ba6c17 100644 --- a/v3/internal/generator/testcases/complex_instantiations/main.go +++ b/v3/internal/generator/testcases/complex_instantiations/main.go @@ -20,6 +20,7 @@ type Service9 struct{} type Service10 struct{} type Service11 struct{} type Service12 struct{} +type Service13 struct{} func main() { factory := NewFactory[Service1, Service2]() @@ -36,6 +37,7 @@ func main() { ServiceInitialiser[Service6]()(&Service6{}), other.CustomNewService(Service7{}), other.ServiceInitialiser[Service8]()(&Service8{}), + application.NewServiceWithOptions(&Service13{}, application.ServiceOptions{Name: "custom name"}), other.LocalService, }, CustomNewServices[Service9, Service10]()...), diff --git a/v3/internal/generator/testcases/complex_instantiations/other/funcs.go b/v3/internal/generator/testcases/complex_instantiations/other/funcs.go index 1f413998e3f..daf1ad066f1 100644 --- a/v3/internal/generator/testcases/complex_instantiations/other/funcs.go +++ b/v3/internal/generator/testcases/complex_instantiations/other/funcs.go @@ -6,7 +6,7 @@ func CustomNewService[T any](srv T) application.Service { return application.NewService(&srv) } -func ServiceInitialiser[T any]() func(*T, ...application.ServiceOptions) application.Service { +func ServiceInitialiser[T any]() func(*T) application.Service { return application.NewService[T] } diff --git a/v3/internal/generator/testcases/complex_instantiations/other/local.go b/v3/internal/generator/testcases/complex_instantiations/other/local.go index dea5d0561bd..99cf173d2da 100644 --- a/v3/internal/generator/testcases/complex_instantiations/other/local.go +++ b/v3/internal/generator/testcases/complex_instantiations/other/local.go @@ -2,6 +2,6 @@ package other import "github.com/wailsapp/wails/v3/pkg/application" -type Service13 int +type Service14 int -var LocalService = application.NewService(new(Service13)) +var LocalService = application.NewService(new(Service14)) diff --git a/v3/pkg/application/application_options.go b/v3/pkg/application/application_options.go index 2f52996ed25..d3f02f3ff6d 100644 --- a/v3/pkg/application/application_options.go +++ b/v3/pkg/application/application_options.go @@ -8,40 +8,6 @@ import ( "github.com/wailsapp/wails/v3/internal/assetserver" ) -// Service wraps a bound type instance. -// The zero value of Service is invalid. -// Valid values may only be obtained by calling [NewService]. -type Service struct { - instance any - options ServiceOptions -} - -type ServiceOptions struct { - // Name can be set to override the name of the service - // This is useful for logging and debugging purposes - Name string - // Route is the path to the assets - Route string -} - -var DefaultServiceOptions = ServiceOptions{ - Route: "", -} - -// NewService returns a Service value wrapping the given pointer. -// If T is not a named type, the returned value is invalid. -// The prefix is used if Service implements a http.Handler only one allowed -func NewService[T any](instance *T, options ...ServiceOptions) Service { - if len(options) == 1 { - return Service{instance, options[0]} - } - return Service{instance, DefaultServiceOptions} -} - -func (s Service) Instance() any { - return s.instance -} - // Options contains the options for the application type Options struct { // Name is the name of the application (used in the default about box) diff --git a/v3/pkg/application/services.go b/v3/pkg/application/services.go index 446746299f4..02ac6f04942 100644 --- a/v3/pkg/application/services.go +++ b/v3/pkg/application/services.go @@ -5,14 +5,86 @@ import ( "reflect" ) +// Service wraps a bound type instance. +// The zero value of Service is invalid. +// Valid values may only be obtained by calling [NewService]. +type Service struct { + instance any + options ServiceOptions +} + +// ServiceOptions provides optional parameters for calls to [NewService]. +type ServiceOptions struct { + // Name can be set to override the name of the service + // for logging and debugging purposes. + // + // If empty, it will default + // either to the value obtained through the [ServiceName] interface, + // or to the type name. + Name string + + // If the service instance implements [http.Handler], + // it will be mounted on the internal asset server + // at the prefix specified by Route. + Route string +} + +// DefaultServiceOptions specifies the default values of service options, +// used when no [ServiceOptions] instance is provided to [NewService]. +var DefaultServiceOptions = ServiceOptions{} + +// NewService returns a Service value wrapping the given pointer. +// If T is not a concrete named type, the returned value is invalid. +func NewService[T any](instance *T) Service { + return Service{instance, DefaultServiceOptions} +} + +// NewServiceWithOptions returns a Service value wrapping the given pointer +// and specifying the given service options. +// If T is not a concrete named type, the returned value is invalid. +func NewServiceWithOptions[T any](instance *T, options ServiceOptions) Service { + service := NewService(instance) // Delegate to NewService so that the static analyser may detect T. Do not remove this call. + service.options = options + return service +} + +// Instance returns the service instance provided to [NewService]. +func (s Service) Instance() any { + return s.instance +} + +// ServiceName returns the name of the service +// +// This is an *optional* method that may be implemented by service instances. +// It is used for logging and debugging purposes. +// +// If a non-empty name is provided with [ServiceOptions], +// it takes precedence over the one returned by the ServiceName method. type ServiceName interface { ServiceName() string } +// ServiceStartup is an *optional* method that may be implemented by service instances. +// +// This method will be called during application startup and will receive a copy of the options +// specified at creation time. It can be used for initialising resources. +// +// The context will be valid as long as the application is running, +// and will be canceled right before shutdown. +// +// If the return value is non-nil, it is logged along with the service name, +// the startup process aborts and the application quits. +// When that happens, service instances that have been already initialised +// receive a shutdown notification. type ServiceStartup interface { ServiceStartup(ctx context.Context, options ServiceOptions) error } +// ServiceShutdown is an *optional* method that may be implemented by service instances. +// +// This method will be called during application shutdown. It can be used for cleaning up resources. +// +// If the return value is non-nil, it is logged along with the service name. type ServiceShutdown interface { ServiceShutdown() error } From 3f825823d5064cc3be87af86a92528f51b032812 Mon Sep 17 00:00:00 2001 From: Fabio Massaioli Date: Thu, 23 Jan 2025 11:58:35 +0100 Subject: [PATCH 2/4] [v3] Pass build flags to binding generator (#4023) * Pass build flags to binding generator * Update changelog * Track variable dependencies using task labels * Track JS/TS sources for binding generator The `/wails:include` directive allows for the inclusion of additional JS/TS files in the generated bindings. * Pass production var to frontend task * Track binding generator output as source * Fix generates pattern for frontend build task * Fix typo in function `term.Warningf` * Use facilities from `internal/term` in bindings command instead of `pterm` --------- Co-authored-by: Lea Anthony --- docs/src/content/docs/changelog.mdx | 1 + v3/internal/commands/bindings.go | 20 +++---- .../commands/build_assets/Taskfile.tmpl.yml | 16 ++++-- .../commands/build_assets/darwin/Taskfile.yml | 5 ++ .../commands/build_assets/linux/Taskfile.yml | 11 ++-- .../build_assets/windows/Taskfile.yml | 7 ++- v3/internal/term/term.go | 53 ++++++++++--------- 7 files changed, 68 insertions(+), 45 deletions(-) diff --git a/docs/src/content/docs/changelog.mdx b/docs/src/content/docs/changelog.mdx index 39cb27011f8..9a75e2ae790 100644 --- a/docs/src/content/docs/changelog.mdx +++ b/docs/src/content/docs/changelog.mdx @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix nil menu issue when calling RegisterContextMenu by [@leaanthony](https://github.com/leaanthony) - Fixed dependency cycles in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) - Fixed use-before-define errors in binding generator output by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) +- Pass build flags to binding generator by [@fbbdev](https://github.com/fbbdev) in [#4023](https://github.com/wailsapp/wails/pull/4023) ### Changed diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index f73285a29b8..e26eb723c3a 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -6,8 +6,6 @@ import ( "os" "path/filepath" - "github.com/pterm/pterm" - "github.com/wailsapp/wails/v3/internal/flags" "github.com/wailsapp/wails/v3/internal/generator" "github.com/wailsapp/wails/v3/internal/generator/config" @@ -21,8 +19,8 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) term.DisableOutput() defer term.EnableOutput() } else if options.Verbose { - pterm.EnableDebugMessages() - defer pterm.DisableDebugMessages() + term.EnableDebug() + defer term.DisableDebug() } term.Header("Generate Bindings") @@ -52,20 +50,18 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) } // Start a spinner for progress messages. - var spinner *pterm.SpinnerPrinter - if term.IsTerminal() { - spinner, _ = pterm.DefaultSpinner.Start("Initialising...") - } + spinner := term.StartSpinner("Initialising...") // Initialise and run generator. stats, err := generator.NewGenerator( options, creator, - config.DefaultPtermLogger(spinner), + spinner.Logger(), ).Generate(patterns...) - // Resolve spinner. - resultMessage := fmt.Sprintf( + // Stop spinner and print summary. + term.StopSpinner(spinner) + term.Infof( "Processed: %s, %s, %s, %s, %s in %s.", pluralise(stats.NumPackages, "Package"), pluralise(stats.NumServices, "Service"), @@ -81,7 +77,7 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) } // Report output directory. - term.Infofln("Output directory: %s", absPath) + term.Infof("Output directory: %s", absPath) // Process generator error. if err != nil { diff --git a/v3/internal/commands/build_assets/Taskfile.tmpl.yml b/v3/internal/commands/build_assets/Taskfile.tmpl.yml index 5f3c597f4c7..f4e9be52141 100644 --- a/v3/internal/commands/build_assets/Taskfile.tmpl.yml +++ b/v3/internal/commands/build_assets/Taskfile.tmpl.yml @@ -22,15 +22,19 @@ tasks: - npm install build:frontend: + label: build:frontend (PRODUCTION={{ "{{.PRODUCTION}}" }}) summary: Build the frontend project dir: frontend sources: - "**/*" generates: - - dist/* + - dist/**/* deps: - task: install:frontend:deps - task: generate:bindings + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS cmds: - npm run {{ "{{.BUILD_COMMAND}}" }} -q env: @@ -40,17 +44,21 @@ tasks: generate:bindings: + label: generate:bindings (BUILD_FLAGS={{ "{{.BUILD_FLAGS}}" }}) summary: Generates bindings for the frontend deps: - task: go:mod:tidy sources: + - "**/*.[jt]s" + - exclude: frontend/**/* + - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output - "**/*.go" - go.mod - go.sum generates: - - "frontend/bindings/**/*" + - frontend/bindings/**/* cmds: - - wails3 generate bindings -f {{ "'{{.BUILD_FLAGS}}'" }} -clean=true {{if .Typescript}} -ts{{end}} + - wails3 generate bindings -f {{ "'{{.BUILD_FLAGS}}'" }} -clean=true {{- if .Typescript}} -ts{{end}} generate:icons: summary: Generates Windows `.ico` and Mac `.icns` files from an image @@ -75,4 +83,4 @@ tasks: summary: Updates the build assets dir: build cmds: - - wails3 update build-assets -name {{ "\"{{.APP_NAME}}\"" }} -binaryname {{ "\"{{.APP_NAME}}\"" }} -config config.yml -dir . \ No newline at end of file + - wails3 update build-assets -name {{ "\"{{.APP_NAME}}\"" }} -binaryname {{ "\"{{.APP_NAME}}\"" }} -config config.yml -dir . diff --git a/v3/internal/commands/build_assets/darwin/Taskfile.yml b/v3/internal/commands/build_assets/darwin/Taskfile.yml index 331ee6f3b6c..30e7da823d9 100644 --- a/v3/internal/commands/build_assets/darwin/Taskfile.yml +++ b/v3/internal/commands/build_assets/darwin/Taskfile.yml @@ -9,6 +9,11 @@ tasks: deps: - task: common:go:mod:tidy - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + PRODUCTION: + ref: .PRODUCTION - task: common:generate:icons cmds: - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} diff --git a/v3/internal/commands/build_assets/linux/Taskfile.yml b/v3/internal/commands/build_assets/linux/Taskfile.yml index e37d032a0a0..560cc9c9233 100644 --- a/v3/internal/commands/build_assets/linux/Taskfile.yml +++ b/v3/internal/commands/build_assets/linux/Taskfile.yml @@ -9,6 +9,11 @@ tasks: deps: - task: common:go:mod:tidy - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + PRODUCTION: + ref: .PRODUCTION - task: common:generate:icons cmds: - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} @@ -83,17 +88,17 @@ tasks: generate:deb: summary: Creates a deb package - cmds: + cmds: - wails3 tool package -name {{.APP_NAME}} -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:rpm: summary: Creates a rpm package - cmds: + cmds: - wails3 tool package -name {{.APP_NAME}} -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:aur: summary: Creates a arch linux packager package - cmds: + cmds: - wails3 tool package -name {{.APP_NAME}} -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin generate:dotdesktop: diff --git a/v3/internal/commands/build_assets/windows/Taskfile.yml b/v3/internal/commands/build_assets/windows/Taskfile.yml index d233f62ebe0..3454570b552 100644 --- a/v3/internal/commands/build_assets/windows/Taskfile.yml +++ b/v3/internal/commands/build_assets/windows/Taskfile.yml @@ -10,7 +10,10 @@ tasks: - task: common:go:mod:tidy - task: common:build:frontend vars: - PRODUCTION: '{{.PRODUCTION}}' + BUILD_FLAGS: + ref: .BUILD_FLAGS + PRODUCTION: + ref: .PRODUCTION - task: common:generate:icons cmds: - task: generate:syso @@ -57,4 +60,4 @@ tasks: run: cmds: - - '{{.BIN_DIR}}\\{{.APP_NAME}}.exe' \ No newline at end of file + - '{{.BIN_DIR}}\\{{.APP_NAME}}.exe' diff --git a/v3/internal/term/term.go b/v3/internal/term/term.go index e936ed3768a..9127ff08aac 100644 --- a/v3/internal/term/term.go +++ b/v3/internal/term/term.go @@ -16,13 +16,6 @@ func Header(header string) { pterm.BgLightGreen.Println(pterm.LightWhite(" " + header + " ")) } -func Infof(format string, args ...interface{}) { - pterm.Info.Printf(format, args...) -} -func Infofln(format string, args ...interface{}) { - pterm.Info.Printfln(format, args...) -} - func IsTerminal() bool { return term.IsTerminal(int(os.Stdout.Fd())) && (os.Getenv("CI") != "true") } @@ -31,37 +24,32 @@ type Spinner struct { spinner *pterm.SpinnerPrinter } -func (s *Spinner) Logger() config.Logger { - if s == nil { - return nil - } +func (s Spinner) Logger() config.Logger { return config.DefaultPtermLogger(s.spinner) } -func StartSpinner(text string) *Spinner { +func StartSpinner(text string) Spinner { if !IsTerminal() { - return nil + return Spinner{} } - spin, err := pterm.DefaultSpinner.Start(text) + spinner, err := pterm.DefaultSpinner.Start(text) if err != nil { - return nil - } - return &Spinner{ - spinner: spin, + return Spinner{} } + spinner.RemoveWhenDone = true + return Spinner{spinner} } -func StopSpinner(s *Spinner) { - if s == nil { - return +func StopSpinner(s Spinner) { + if s.spinner != nil { + _ = s.spinner.Stop() } - _ = s.spinner.Stop() } func output(input any, printer pterm.PrefixPrinter, args ...any) { switch v := input.(type) { case string: - printer.Println(fmt.Sprintf(input.(string), args...)) + printer.Printfln(input.(string), args...) case error: printer.Println(v.Error()) default: @@ -69,12 +57,20 @@ func output(input any, printer pterm.PrefixPrinter, args ...any) { } } +func Info(input any) { + output(input, pterm.Info) +} + +func Infof(input any, args ...interface{}) { + output(input, pterm.Info, args...) +} + func Warning(input any) { output(input, pterm.Warning) } func Warningf(input any, args ...any) { - output(input, pterm.Warning, args) + output(input, pterm.Warning, args...) } func Error(input any) { @@ -93,6 +89,7 @@ func Section(s string) { func DisableColor() { pterm.DisableColor() } + func EnableOutput() { pterm.EnableOutput() } @@ -101,6 +98,14 @@ func DisableOutput() { pterm.DisableOutput() } +func EnableDebug() { + pterm.EnableDebugMessages() +} + +func DisableDebug() { + pterm.DisableDebugMessages() +} + func Println(s string) { pterm.Println(s) } From 31487b5a0cd9bee39c9eef0545c706921206f687 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Thu, 23 Jan 2025 22:03:14 +1100 Subject: [PATCH 3/4] Fix bad merge --- v3/internal/commands/bindings.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index e26eb723c3a..bd3277ec906 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -70,11 +70,6 @@ func GenerateBindings(options *flags.GenerateBindingsOptions, patterns []string) pluralise(stats.NumModels, "Model"), stats.Elapsed().String(), ) - if spinner != nil { - spinner.Info(resultMessage) - } else { - term.Infofln("%s", resultMessage) - } // Report output directory. term.Infof("Output directory: %s", absPath) From 631c8a1cc8bfc5211273b07f6eb0b6ce003fd2ab Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Thu, 23 Jan 2025 22:10:23 +1100 Subject: [PATCH 4/4] New ContextMenu API + example (#4013) * New ContextMenu API + example * Remove redundant code * ContextMenuData now returns a string. New Menu guide. * Update readme * Update v3/pkg/application/context.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Add new menubar option * Fix docs --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- docs/src/content/docs/changelog.mdx | 2 ++ v3/examples/window-menu/README.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/changelog.mdx b/docs/src/content/docs/changelog.mdx index 9a75e2ae790..db29e026c5e 100644 --- a/docs/src/content/docs/changelog.mdx +++ b/docs/src/content/docs/changelog.mdx @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add diagnostics section to `wails doctor` by [@leaanthony](https://github.com/leaanthony) - Add window to context when calling a service method by [@leaanthony](https://github.com/leaanthony) - Add `window-call` example to demonstrate how to know which window is calling a service by [@leaanthony](https://github.com/leaanthony) +- New Menu guide by [@leaanthony](https://github.com/leaanthony) - Better panic handling by [@leaanthony](https://github.com/leaanthony) - New Menu guide by [@leaanthony](https://github.com/leaanthony) - Add doc comments for Service API by [@fbbdev](https://github.com/fbbdev) in [#4024](https://github.com/wailsapp/wails/pull/4024) @@ -53,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Removed `application.WindowIDKey` and `application.WindowNameKey` (replaced by `application.WindowKey`) by [@leaanthony](https://github.com/leaanthony) +- ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) - In JS/TS bindings, class fields of fixed-length array types are now initialized with their expected length instead of being empty by [@fbbdev](https://github.com/fbbdev) in [#4001](https://github.com/wailsapp/wails/pull/4001) - ContextMenuData now returns a string instead of any by [@leaanthony](https://github.com/leaanthony) - `application.NewService` does not accept options as an optional parameter anymore (use `application.NewServiceWithOptions` instead) by [@leaanthony](https://github.com/leaanthony) in [#4024](https://github.com/wailsapp/wails/pull/4024) diff --git a/v3/examples/window-menu/README.md b/v3/examples/window-menu/README.md index 7b3a517e410..0d825364f20 100644 --- a/v3/examples/window-menu/README.md +++ b/v3/examples/window-menu/README.md @@ -19,6 +19,6 @@ go run . ## How it Works -The example creates a window with a default menu and binds the F10 key to toggle the menu bar's visibility. The menu bar will hide when F10 is pressed and show when F10 is released. +The example creates a window with a default menu and binds the F1 key to toggle the menu bar's visibility. The menu bar will show when F2 is pressed and hide when F3 is released. -Note: The menu bar toggling functionality only works on Windows. On other platforms, the F10 key binding will have no effect. +Note: The menu bar toggling functionality only works on Windows. On other platforms, the F1 key binding will have no effect.