mirror of
https://github.com/taigrr/wails.git
synced 2026-04-06 15:12:40 -07:00
Compare commits
184 Commits
v2-alpha-o
...
v2-alpha-x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7661082d58 | ||
|
|
34da4f056a | ||
|
|
642c1d5ec5 | ||
|
|
1f3351ffa5 | ||
|
|
30e96118b1 | ||
|
|
efd768ac5d | ||
|
|
6dbcd4fc45 | ||
|
|
11cd51c9ca | ||
|
|
3de38003bf | ||
|
|
418438b762 | ||
|
|
0a5c43435e | ||
|
|
d7bb831d7f | ||
|
|
824256db6d | ||
|
|
2f311ee403 | ||
|
|
e04db8775f | ||
|
|
2fbc63b458 | ||
|
|
8ac69d6afd | ||
|
|
6dec097184 | ||
|
|
c2015b1d72 | ||
|
|
9c75e61704 | ||
|
|
995d485a43 | ||
|
|
9ac4990f89 | ||
|
|
509c70a97c | ||
|
|
695f78861d | ||
|
|
46ad4f4d18 | ||
|
|
2fc2d63e2d | ||
|
|
d137859d12 | ||
|
|
09cf223aa2 | ||
|
|
909da72eb2 | ||
|
|
2a06e2e577 | ||
|
|
7f841ab85b | ||
|
|
a2d95e1b99 | ||
|
|
d06f563bfe | ||
|
|
c53d44b3ec | ||
|
|
5e51f426fa | ||
|
|
193d9e8ed8 | ||
|
|
2d03d355c2 | ||
|
|
185b7fed63 | ||
|
|
ee6ad0bb27 | ||
|
|
3644f4ae1e | ||
|
|
28d87a8e58 | ||
|
|
cf7d31e432 | ||
|
|
fd40faabe8 | ||
|
|
d521f80dcd | ||
|
|
102a8cc5a6 | ||
|
|
e90f5361be | ||
|
|
afe677d39d | ||
|
|
58e6ce10ad | ||
|
|
b0c522a59a | ||
|
|
62fc489001 | ||
|
|
a269fc9e8c | ||
|
|
7cd6d109d4 | ||
|
|
1f8a2bb9b1 | ||
|
|
eb2ac99067 | ||
|
|
79147c612e | ||
|
|
3d75ba174b | ||
|
|
3933c5ab02 | ||
|
|
aa5ff6ed2e | ||
|
|
407269b0d5 | ||
|
|
67a72cc693 | ||
|
|
955fe1d583 | ||
|
|
82bce89086 | ||
|
|
c13257b9e9 | ||
|
|
3f773f80ac | ||
|
|
5b23122b35 | ||
|
|
d5cbfa6749 | ||
|
|
3ad92192a9 | ||
|
|
466676d99f | ||
|
|
a1d5412465 | ||
|
|
9fdd5148ca | ||
|
|
ac957b27cb | ||
|
|
20bc332720 | ||
|
|
d2507660c2 | ||
|
|
64264c6378 | ||
|
|
ddadcdc18f | ||
|
|
4738a0e0a8 | ||
|
|
d2e4a0b0d2 | ||
|
|
9f365ed85e | ||
|
|
5e733657c2 | ||
|
|
93d9b61366 | ||
|
|
b5d289bda9 | ||
|
|
319b7a3755 | ||
|
|
410d23b4d9 | ||
|
|
003e505c4a | ||
|
|
22f09772d3 | ||
|
|
a300172adc | ||
|
|
1eba408f64 | ||
|
|
be39b293b5 | ||
|
|
31cf04a944 | ||
|
|
f5912d29b6 | ||
|
|
caad3a6b00 | ||
|
|
08f4476087 | ||
|
|
46ea3e6074 | ||
|
|
8be2a39daf | ||
|
|
7591b45ffa | ||
|
|
f5056e7232 | ||
|
|
101d344303 | ||
|
|
6ab1a4adb0 | ||
|
|
5a30425091 | ||
|
|
e9deb248f9 | ||
|
|
7d0ff8b1a2 | ||
|
|
8399cc1e57 | ||
|
|
6b8370daad | ||
|
|
3c4f874db5 | ||
|
|
0966c96ef0 | ||
|
|
6b919808c9 | ||
|
|
590d4fcdbb | ||
|
|
4acb3f83bf | ||
|
|
df32393215 | ||
|
|
ff3e03220e | ||
|
|
5da198de7e | ||
|
|
247df54ef0 | ||
|
|
161eeca62b | ||
|
|
0b8056bcf4 | ||
|
|
62bfe953a1 | ||
|
|
67611d5ae7 | ||
|
|
77b5235c9f | ||
|
|
09755d5bfe | ||
|
|
0224228c46 | ||
|
|
168cd96f56 | ||
|
|
6f6e810432 | ||
|
|
944e1c99ff | ||
|
|
7f54f7bb7e | ||
|
|
2881a5bc0d | ||
|
|
ee05884c9c | ||
|
|
385988989b | ||
|
|
b98c7dd49f | ||
|
|
b3c0cc86d3 | ||
|
|
ad34e55a67 | ||
|
|
1bdbf68ca9 | ||
|
|
84f37c66ba | ||
|
|
f7c65b1705 | ||
|
|
134b41e4be | ||
|
|
df41e8eb3a | ||
|
|
0f668a9038 | ||
|
|
dea6d261ad | ||
|
|
97592fad5c | ||
|
|
8caf277bf1 | ||
|
|
4b480bb085 | ||
|
|
c1d63aff34 | ||
|
|
5fc89c4cad | ||
|
|
5e96bb5a32 | ||
|
|
c5e76c50b0 | ||
|
|
e40226ff7a | ||
|
|
53a3638fa8 | ||
|
|
1344638c52 | ||
|
|
6fdc87454a | ||
|
|
c36f9501a9 | ||
|
|
c23b43c352 | ||
|
|
a76851463b | ||
|
|
e17b432c8f | ||
|
|
5d444cd6dd | ||
|
|
be43049fc6 | ||
|
|
2e01710412 | ||
|
|
1b0193161c | ||
|
|
1b377fb575 | ||
|
|
1203ae64b8 | ||
|
|
26ed8002b9 | ||
|
|
cf23bffc67 | ||
|
|
d70f6fffe7 | ||
|
|
54c99fc386 | ||
|
|
86c1ea5e6a | ||
|
|
b394c1914c | ||
|
|
91c2ddf155 | ||
|
|
712ad96d2a | ||
|
|
86b4a4f2f5 | ||
|
|
4b9786abc9 | ||
|
|
fd96ebc050 | ||
|
|
939e0f5975 | ||
|
|
6a7a288a0f | ||
|
|
0564d0aa98 | ||
|
|
3a136a73ca | ||
|
|
50c219307f | ||
|
|
de3038b302 | ||
|
|
6eb4b0a419 | ||
|
|
41d2158375 | ||
|
|
5d7f57e80b | ||
|
|
4ce3e1d1bf | ||
|
|
e5f2746810 | ||
|
|
92ebf506dd | ||
|
|
9ab06152c5 | ||
|
|
bf36b6a59d | ||
|
|
4b9f6c4fb1 | ||
|
|
b1a42c8dea |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -27,3 +27,7 @@ v2/pkg/parser/testproject/frontend/wails
|
||||
v2/test/kitchensink/frontend/public
|
||||
v2/test/kitchensink/build/darwin/desktop/kitchensink
|
||||
v2/test/kitchensink/frontend/package.json.md5
|
||||
/v2/internal/ffenestri/windows/test/cmake-build-debug/
|
||||
!v2/internal/ffenestri/windows/x64/webview2.dll
|
||||
!v2/internal/ffenestri/windows/x64/WebView2Loader.dll
|
||||
.idea/
|
||||
|
||||
@@ -40,4 +40,5 @@ Wails is what it is because of the time and effort given by these great people.
|
||||
* [Balakrishna Prasad Ganne](https://github.com/aayush420)
|
||||
* [Charaf Rezrazi](https://github.com/Rezrazi)
|
||||
* [misitebao](https://github.com/misitebao)
|
||||
* [Elie Grenon](https://github.com/DrunkenPoney)
|
||||
* [Elie Grenon](https://github.com/DrunkenPoney)
|
||||
* [Amaury Tobias Quiroz](https://github.com/amaury-tobias)
|
||||
13
v2/.vscode/settings.json
vendored
13
v2/.vscode/settings.json
vendored
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"ios": "c",
|
||||
"typeinfo": "c",
|
||||
"sstream": "c",
|
||||
"__functional_03": "c",
|
||||
"functional": "c",
|
||||
"__locale": "c",
|
||||
"locale": "c",
|
||||
"chrono": "c",
|
||||
"system_error": "c"
|
||||
}
|
||||
}
|
||||
48
v2/cmd/wails/internal/commands/build/README.md
Normal file
48
v2/cmd/wails/internal/commands/build/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Build
|
||||
|
||||
The build command processes the Wails project and generates an application binary.
|
||||
|
||||
## Usage
|
||||
|
||||
`wails build <flags>`
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Details | Default |
|
||||
| :------------- | :----------- | :------ |
|
||||
| -clean | Clean the bin directory before building | |
|
||||
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
|
||||
| -ldflags "custom ld flags" | Use given ldflags | |
|
||||
| -o path/to/binary | Compile to given path/filename | |
|
||||
| -k | Keep generated assets | |
|
||||
| -package | Create a platform specific package | |
|
||||
| -production | Compile in production mode: -ldflags="-w -s" + "-h windows" on Windows | |
|
||||
| -tags | Build tags to pass to Go compiler (quoted and space separated) | |
|
||||
| -upx | Compress final binary with UPX (if installed) | |
|
||||
| -upxflags "custom flags" | Flags to pass to upx | |
|
||||
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
|
||||
| -delve | If true, runs delve on the compiled binary | false |
|
||||
|
||||
## The Build Process
|
||||
|
||||
The build process is as follows:
|
||||
|
||||
- The flags are processed, and an Options struct built containing the build context.
|
||||
- The type of target is determined, and a custom build process is followed for target.
|
||||
|
||||
### Desktop Target
|
||||
|
||||
- The frontend dependencies are installed. The command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
|
||||
- The frontend is then built. This command is read from the project file `wails.json` under the key `frontend:install` and executed in the `frontend` directory. If this is not defined, it is ignored.
|
||||
- The project directory is checked to see if the `build` directory exists. If not, it is created and default project assets are copied to it.
|
||||
- An asset bundle is then created by reading the `html` key from `wails.json` and loading the referenced file. This is then parsed, looking for local Javascript and CSS references. Those files are in turn loaded into memory, converted to C data and saved into the asset bundle located at `build/assets.h`, which also includes the original HTML.
|
||||
- The application icon is then processed: if there is no `build/appicon.png`, a default icon is copied. On Windows, an `app.ico` file is generated from this png. On Mac, `icons.icns` is generated.
|
||||
- If there are icons in the `build/tray` directory, these are processed, converted to C data and saved as `build/trayicons.h`, ready for the compilation step.
|
||||
- If there are icons in the `build/dialog` directory, these are processed, converted to C data and saved as `build/userdialogicons.h`, ready for the compilation step.
|
||||
- If the `-package` flag is given for a Windows target, the Windows assets in the `build/windows` directory are processed: manifest + icons compiled to a `.syso` file (deleted after compilation).
|
||||
- If we are building a universal binary for Mac, the application is compiled for both `arm64` and `amd64`. The `lipo` tool is then executed to create the universal binary.
|
||||
- If we are not building a universal binary for Mac, the application is built using `go build`, using build tags to indicate type of application and build mode (debug/production).
|
||||
- If the `-upx` flag was provided, `upx` is invoked to compress the binary. Custom flags may be provided using the `-upxflags` flag.
|
||||
- If the `package` flag is given for a non Windows target, the application is bundled for the platform. On Mac, this creates a `.app` with the processed icons, the `Info.plist` in `build/darwin` and the compiled binary.
|
||||
|
||||
|
||||
@@ -2,19 +2,26 @@ package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/system"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
// AddBuildSubcommand adds the `build` command for the Wails application
|
||||
func AddBuildSubcommand(app *clir.Cli) {
|
||||
func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
|
||||
outputType := "desktop"
|
||||
|
||||
@@ -22,77 +29,201 @@ func AddBuildSubcommand(app *clir.Cli) {
|
||||
|
||||
command := app.NewSubCommand("build", "Builds the application")
|
||||
|
||||
// Setup target type flag
|
||||
description := "Type of application to build. Valid types: " + validTargetTypes.Join(",")
|
||||
command.StringFlag("t", description, &outputType)
|
||||
|
||||
// Setup production flag
|
||||
production := false
|
||||
command.BoolFlag("production", "Build in production mode", &production)
|
||||
|
||||
// Setup pack flag
|
||||
pack := false
|
||||
command.BoolFlag("pack", "Create a platform specific package", &pack)
|
||||
command.BoolFlag("package", "Create a platform specific package", &pack)
|
||||
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
|
||||
compress := false
|
||||
command.BoolFlag("upx", "Compress final binary with UPX (if installed)", &compress)
|
||||
|
||||
compressFlags := ""
|
||||
command.StringFlag("upxflags", "Flags to pass to upx", &compressFlags)
|
||||
|
||||
// Setup Platform flag
|
||||
platform := runtime.GOOS
|
||||
command.StringFlag("platform", "Platform to target", &platform)
|
||||
|
||||
// Quiet Build
|
||||
quiet := false
|
||||
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
|
||||
|
||||
// ldflags to pass to `go`
|
||||
ldflags := ""
|
||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||
|
||||
// Log to file
|
||||
logFile := ""
|
||||
command.StringFlag("l", "Log to file", &logFile)
|
||||
// tags to pass to `go`
|
||||
tags := ""
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Retain assets
|
||||
keepAssets := false
|
||||
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
||||
|
||||
// Retain assets
|
||||
outputFilename := ""
|
||||
command.StringFlag("o", "Output filename", &outputFilename)
|
||||
|
||||
// Clean build directory
|
||||
cleanBuildDirectory := false
|
||||
command.BoolFlag("clean", "Clean the build directory before building", &cleanBuildDirectory)
|
||||
|
||||
webview2 := "download"
|
||||
command.StringFlag("webview2", "WebView2 installer strategy: download,embed,browser,error.", &webview2)
|
||||
|
||||
runDelve := false
|
||||
command.BoolFlag("delve", "Runs the built binary in delve for debugging", &runDelve)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := logger.New()
|
||||
quiet := verbosity == 0
|
||||
|
||||
if !quiet {
|
||||
logger.AddOutput(os.Stdout)
|
||||
}
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
// Validate output type
|
||||
if !validTargetTypes.Contains(outputType) {
|
||||
logger.Fatal(fmt.Sprintf("Output type '%s' is not valid.", outputType))
|
||||
os.Exit(1)
|
||||
return fmt.Errorf("output type '%s' is not valid", outputType)
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
app.PrintBanner()
|
||||
}
|
||||
|
||||
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||
logger.Writeln(task)
|
||||
logger.Writeln(strings.Repeat("-", len(task)))
|
||||
|
||||
// Setup mode
|
||||
mode := build.Debug
|
||||
if production {
|
||||
mode = build.Production
|
||||
}
|
||||
|
||||
// Check platform
|
||||
validPlatformArch := slicer.String([]string{
|
||||
"darwin",
|
||||
"darwin/amd64",
|
||||
"darwin/arm64",
|
||||
"darwin/universal",
|
||||
"linux",
|
||||
//"linux/amd64",
|
||||
//"linux/arm-7",
|
||||
"windows",
|
||||
"windows/amd64",
|
||||
})
|
||||
if !validPlatformArch.Contains(platform) {
|
||||
return fmt.Errorf("platform %s is not supported", platform)
|
||||
}
|
||||
|
||||
if compress && platform == "darwin/universal" {
|
||||
println("Warning: compress flag unsupported for universal binaries. Ignoring.")
|
||||
compress = false
|
||||
}
|
||||
|
||||
// Lookup compiler path
|
||||
compilerPath, err := exec.LookPath(compilerCommand)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find compiler: %s", compilerCommand)
|
||||
}
|
||||
|
||||
// Tags
|
||||
userTags := []string{}
|
||||
for _, tag := range strings.Split(tags, " ") {
|
||||
thisTag := strings.TrimSpace(tag)
|
||||
if thisTag != "" {
|
||||
userTags = append(userTags, thisTag)
|
||||
}
|
||||
}
|
||||
|
||||
// Webview2 installer strategy (download by default)
|
||||
wv2rtstrategy := ""
|
||||
webview2 = strings.ToLower(webview2)
|
||||
if webview2 != "" {
|
||||
validWV2Runtime := slicer.String([]string{"download", "embed", "browser", "error"})
|
||||
if !validWV2Runtime.Contains(webview2) {
|
||||
return fmt.Errorf("invalid option for flag 'webview2': %s", webview2)
|
||||
}
|
||||
// These are the build tags associated with the strategies
|
||||
switch webview2 {
|
||||
case "embed":
|
||||
wv2rtstrategy = "wv2runtime.embed"
|
||||
case "error":
|
||||
wv2rtstrategy = "wv2runtime.error"
|
||||
case "browser":
|
||||
wv2rtstrategy = "wv2runtime.browser"
|
||||
}
|
||||
}
|
||||
|
||||
// If we want to use delve we need to compile in DEBUG mode
|
||||
if runDelve {
|
||||
mode = build.Debug
|
||||
}
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
Mode: mode,
|
||||
Pack: pack,
|
||||
Platform: platform,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
OutputFile: outputFilename,
|
||||
CleanBuildDirectory: cleanBuildDirectory,
|
||||
Mode: mode,
|
||||
Pack: pack,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
KeepAssets: keepAssets,
|
||||
Verbosity: verbosity,
|
||||
Compress: compress,
|
||||
CompressFlags: compressFlags,
|
||||
UserTags: userTags,
|
||||
WebView2Strategy: wv2rtstrategy,
|
||||
RunDelve: runDelve,
|
||||
}
|
||||
|
||||
// Calculate platform and arch
|
||||
platformSplit := strings.Split(platform, "/")
|
||||
buildOptions.Platform = platformSplit[0]
|
||||
if system.IsAppleSilicon() {
|
||||
buildOptions.Arch = "arm64"
|
||||
} else {
|
||||
buildOptions.Arch = runtime.GOARCH
|
||||
}
|
||||
if len(platformSplit) == 2 {
|
||||
buildOptions.Arch = platformSplit[1]
|
||||
}
|
||||
|
||||
println("Build arch =", buildOptions.Arch)
|
||||
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
buildModeText := "debug"
|
||||
if production {
|
||||
buildModeText = "production"
|
||||
}
|
||||
|
||||
// Write out the system information
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintf(w, "App Type: \t%s\n", buildOptions.OutputType)
|
||||
fmt.Fprintf(w, "Platform: \t%s\n", buildOptions.Platform)
|
||||
fmt.Fprintf(w, "Arch: \t%s\n", buildOptions.Arch)
|
||||
fmt.Fprintf(w, "Compiler: \t%s\n", compilerPath)
|
||||
fmt.Fprintf(w, "Compress: \t%t\n", buildOptions.Compress)
|
||||
fmt.Fprintf(w, "Build Mode: \t%s\n", buildModeText)
|
||||
fmt.Fprintf(w, "Package: \t%t\n", buildOptions.Pack)
|
||||
fmt.Fprintf(w, "Clean Build Dir: \t%t\n", buildOptions.CleanBuildDirectory)
|
||||
fmt.Fprintf(w, "KeepAssets: \t%t\n", buildOptions.KeepAssets)
|
||||
fmt.Fprintf(w, "LDFlags: \t\"%s\"\n", buildOptions.LDFlags)
|
||||
fmt.Fprintf(w, "Tags: \t[%s]\n", strings.Join(buildOptions.UserTags, ","))
|
||||
if len(buildOptions.OutputFile) > 0 {
|
||||
fmt.Fprintf(w, "Output File: \t%s\n", buildOptions.OutputFile)
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
w.Flush()
|
||||
|
||||
return doBuild(buildOptions)
|
||||
})
|
||||
}
|
||||
@@ -107,11 +238,47 @@ func doBuild(buildOptions *build.Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
buildOptions.Logger.Writeln("")
|
||||
buildOptions.Logger.Writeln(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||
buildOptions.Logger.Writeln("")
|
||||
buildOptions.Logger.Println("")
|
||||
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||
buildOptions.Logger.Println("")
|
||||
|
||||
if buildOptions.RunDelve {
|
||||
// Check delve exists
|
||||
delveExists := shell.CommandExists("dlv")
|
||||
if !delveExists {
|
||||
return fmt.Errorf("cannot launch delve (Is it installed?)")
|
||||
}
|
||||
|
||||
// Get cwd
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Launch delve
|
||||
buildOptions.Logger.Println("Launching Delve on port 2345...")
|
||||
cmdArgs := slicer.String([]string{"--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", outputFilename})
|
||||
if buildOptions.Verbosity == build.VERBOSE {
|
||||
buildOptions.Logger.Println("\tRunning: dlv %s", cmdArgs.Join(" "))
|
||||
}
|
||||
stdout, stderr, err := shell.RunCommand(cwd, "dlv", cmdArgs.AsSlice()...)
|
||||
if buildOptions.Verbosity == build.VERBOSE || err != nil {
|
||||
trimstdout := strings.TrimSpace(stdout)
|
||||
if trimstdout != "" {
|
||||
buildOptions.Logger.Println(trimstdout)
|
||||
}
|
||||
trimstderr := strings.TrimSpace(stderr)
|
||||
if trimstderr != "" {
|
||||
buildOptions.Logger.Println(trimstderr)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `debug` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
outputType := "desktop"
|
||||
|
||||
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
|
||||
|
||||
command := app.NewSubCommand("debug", "Builds the application then runs delve on the binary")
|
||||
|
||||
// Setup target type flag
|
||||
description := "Type of application to build. Valid types: " + validTargetTypes.Join(",")
|
||||
command.StringFlag("t", description, &outputType)
|
||||
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
|
||||
quiet := false
|
||||
command.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
|
||||
// ldflags to pass to `go`
|
||||
ldflags := ""
|
||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||
|
||||
// Log to file
|
||||
logFile := ""
|
||||
command.StringFlag("l", "Log to file", &logFile)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
// Validate output type
|
||||
if !validTargetTypes.Contains(outputType) {
|
||||
return fmt.Errorf("output type '%s' is not valid", outputType)
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
app.PrintBanner()
|
||||
}
|
||||
|
||||
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||
logger.Println(task)
|
||||
logger.Println(strings.Repeat("-", len(task)))
|
||||
|
||||
// Setup mode
|
||||
mode := build.Debug
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
Mode: mode,
|
||||
Pack: false,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
KeepAssets: false,
|
||||
}
|
||||
|
||||
outputFilename, err := doDebugBuild(buildOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check delve exists
|
||||
delveExists := shell.CommandExists("dlv")
|
||||
if !delveExists {
|
||||
return fmt.Errorf("cannot launch delve (Is it installed?)")
|
||||
}
|
||||
|
||||
// Get cwd
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Launch delve
|
||||
println("Launching Delve on port 2345...")
|
||||
command := shell.CreateCommand(cwd, "dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", outputFilename)
|
||||
return command.Run()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// doDebugBuild is our main build command
|
||||
func doDebugBuild(buildOptions *build.Options) (string, error) {
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
outputFilename, err := build.Build(buildOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
buildOptions.Logger.Println("")
|
||||
buildOptions.Logger.Println(fmt.Sprintf("Built '%s' in %s.", outputFilename, elapsed.Round(time.Millisecond).String()))
|
||||
buildOptions.Logger.Println("")
|
||||
|
||||
return outputFilename, nil
|
||||
}
|
||||
22
v2/cmd/wails/internal/commands/dev/README.md
Normal file
22
v2/cmd/wails/internal/commands/dev/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Dev
|
||||
|
||||
The dev command allows you to develop your application through a standard browser.
|
||||
|
||||
## Usage
|
||||
|
||||
`wails dev <flags>`
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Details | Default |
|
||||
| :------------- | :----------- | :------ |
|
||||
| -compiler path/to/compiler | Use a different go compiler, eg go1.15beta1 | go |
|
||||
| -ldflags "custom ld flags" | Use given ldflags | |
|
||||
| -e list,of,extensions | File extensions to trigger rebuilds | go |
|
||||
| -w | Show warnings | false |
|
||||
| -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 |
|
||||
| -loglevel | Loglevel to pass to the application - Trace, Debug, Info, Warning, Error | Debug |
|
||||
|
||||
## How it works
|
||||
|
||||
The project is built using a special mode that starts a webserver and starts listening to port 34115. When the frontend project is run independently, so long as the JS is wrapped with the runtime method `ready`, then the frontend will connect to the backend code via websockets. The interface should be present in your browser, and you should be able to interact with the backend as you would in a desktop app.
|
||||
@@ -2,35 +2,46 @@ package dev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/colour"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/process"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
func LogGreen(message string, args ...interface{}) {
|
||||
text := fmt.Sprintf(message, args...)
|
||||
println(colour.Green(text))
|
||||
}
|
||||
|
||||
func LogRed(message string, args ...interface{}) {
|
||||
text := fmt.Sprintf(message, args...)
|
||||
println(colour.Red(text))
|
||||
}
|
||||
|
||||
func LogDarkYellow(message string, args ...interface{}) {
|
||||
text := fmt.Sprintf(message, args...)
|
||||
println(colour.DarkYellow(text))
|
||||
}
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli) error {
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("dev", "Development mode")
|
||||
|
||||
outputType := "desktop"
|
||||
|
||||
validTargetTypes := slicer.String([]string{"desktop", "hybrid", "server"})
|
||||
|
||||
// Setup target type flag
|
||||
description := "Type of application to develop. Valid types: " + validTargetTypes.Join(",")
|
||||
command.StringFlag("t", description, &outputType)
|
||||
|
||||
// Passthrough ldflags
|
||||
ldflags := ""
|
||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||
@@ -41,18 +52,23 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
|
||||
// extensions to trigger rebuilds
|
||||
extensions := "go"
|
||||
command.StringFlag("m", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
|
||||
|
||||
// extensions to trigger rebuilds
|
||||
showWarnings := false
|
||||
command.BoolFlag("w", "Show warnings", &showWarnings)
|
||||
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - default, 2 - verbose)", &verbosity)
|
||||
|
||||
loglevel := ""
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Validate inputs
|
||||
if !validTargetTypes.Contains(outputType) {
|
||||
return fmt.Errorf("output type '%s' is not valid", outputType)
|
||||
}
|
||||
|
||||
// Create logger
|
||||
logger := logger.New()
|
||||
logger.AddOutput(os.Stdout)
|
||||
logger := clilogger.New(w)
|
||||
app.PrintBanner()
|
||||
|
||||
// TODO: Check you are in a project directory
|
||||
@@ -61,10 +77,14 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
var debugBinaryProcess *process.Process = nil
|
||||
var buildFrontend bool = true
|
||||
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
||||
|
||||
// Setup signal handler
|
||||
@@ -73,20 +93,35 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
|
||||
debounceQuit := make(chan bool, 1)
|
||||
|
||||
// Do initial build
|
||||
logger.Info("Building application for development...")
|
||||
debugBinaryProcess = restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
||||
var passthruArgs []string
|
||||
//if len(os.Args) > 2 {
|
||||
// passthruArgs = os.Args[2:]
|
||||
//}
|
||||
|
||||
// Do initial build
|
||||
logger.Println("Building application for development...")
|
||||
newProcess, appBinary, err := restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
|
||||
if newProcess != nil {
|
||||
debugBinaryProcess = newProcess
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var newBinaryProcess *process.Process
|
||||
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
|
||||
// logger.Info("event: %+v", event)
|
||||
// logger.Println("event: %+v", event)
|
||||
|
||||
// Check for new directories
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(event.Name) {
|
||||
if !strings.Contains(event.Name, "node_modules") {
|
||||
watcher.Add(event.Name)
|
||||
logger.Info("Watching directory: %s", event.Name)
|
||||
err := watcher.Add(event.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("[New Directory] Watching new directory: %s", event.Name)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -95,38 +130,33 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
// Check for file writes
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
|
||||
// logger.Info("modified file: %s", event.Name)
|
||||
var rebuild bool = false
|
||||
|
||||
// Iterate all file patterns
|
||||
for _, pattern := range extensionsThatTriggerARebuild {
|
||||
rebuild = strings.HasSuffix(event.Name, pattern)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
if rebuild {
|
||||
// Only build frontend when the file isn't a Go file
|
||||
buildFrontend = !strings.HasSuffix(event.Name, "go")
|
||||
if strings.HasSuffix(event.Name, pattern) {
|
||||
rebuild = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !rebuild {
|
||||
logger.Info("Filename change: %s did not match extension list %s", event.Name, extensions)
|
||||
if showWarnings {
|
||||
LogDarkYellow("[File change] %s did not match extension list (%s)", event.Name, extensions)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if buildFrontend {
|
||||
logger.Info("Full rebuild triggered: %s updated", event.Name)
|
||||
} else {
|
||||
logger.Info("Partial build triggered: %s updated", event.Name)
|
||||
}
|
||||
LogGreen("[Attempting rebuild] %s updated", event.Name)
|
||||
|
||||
// Do a rebuild
|
||||
|
||||
// Try and build the app
|
||||
newBinaryProcess := restartApp(logger, outputType, ldflags, compilerCommand, buildFrontend, debugBinaryProcess)
|
||||
|
||||
newBinaryProcess, _, err = restartApp(logger, ldflags, compilerCommand, debugBinaryProcess, loglevel, passthruArgs, verbosity)
|
||||
if err != nil {
|
||||
fmt.Printf("Error during build: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
@@ -136,23 +166,28 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
})
|
||||
|
||||
// Get project dir
|
||||
dir, err := os.Getwd()
|
||||
projectDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(dir)
|
||||
dirs, err := fs.GetSubdirectories(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
LogGreen("Watching (sub)/directory: %s", projectDir)
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
logger.Info("Watching directory: %s", dir)
|
||||
// Ignore build directory
|
||||
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
|
||||
return
|
||||
}
|
||||
err = watcher.Add(dir)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
@@ -164,7 +199,7 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
for quit == false {
|
||||
select {
|
||||
case <-quitChannel:
|
||||
println()
|
||||
LogGreen("\nCaught quit")
|
||||
// Notify debouncer to quit
|
||||
debounceQuit <- true
|
||||
quit = true
|
||||
@@ -173,10 +208,19 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
|
||||
// Kill the current program if running
|
||||
if debugBinaryProcess != nil {
|
||||
debugBinaryProcess.Kill()
|
||||
err := debugBinaryProcess.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Development mode exited")
|
||||
// Remove dev binary
|
||||
err = os.Remove(appBinary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
LogGreen("Development mode exited")
|
||||
|
||||
return nil
|
||||
})
|
||||
@@ -203,15 +247,15 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
func restartApp(logger *logger.Logger, outputType string, ldflags string, compilerCommand string, buildFrontend bool, debugBinaryProcess *process.Process) *process.Process {
|
||||
func restartApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, verbosity int) (*process.Process, string, error) {
|
||||
|
||||
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand, buildFrontend)
|
||||
appBinary, err := buildApp(logger, ldflags, compilerCommand, verbosity)
|
||||
println()
|
||||
if err != nil {
|
||||
logger.Error("Build Failed: %s", err.Error())
|
||||
return nil
|
||||
LogRed("Build error - continuing to run current version")
|
||||
LogDarkYellow(err.Error())
|
||||
return nil, "", nil
|
||||
}
|
||||
logger.Info("Build new binary: %s", appBinary)
|
||||
|
||||
// Kill existing binary if need be
|
||||
if debugBinaryProcess != nil {
|
||||
@@ -226,34 +270,45 @@ func restartApp(logger *logger.Logger, outputType string, ldflags string, compil
|
||||
|
||||
// TODO: Generate `backend.js`
|
||||
|
||||
// Start up new binary
|
||||
newProcess := process.NewProcess(logger, appBinary)
|
||||
// Start up new binary with correct args
|
||||
var args = []string{"-loglevel", loglevel}
|
||||
if len(passthruArgs) > 0 {
|
||||
args = append(args, passthruArgs...)
|
||||
}
|
||||
newProcess := process.NewProcess(logger, appBinary, args...)
|
||||
err = newProcess.Start()
|
||||
if err != nil {
|
||||
// Remove binary
|
||||
fs.DeleteFile(appBinary)
|
||||
deleteError := fs.DeleteFile(appBinary)
|
||||
if deleteError != nil {
|
||||
logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
}
|
||||
logger.Fatal("Unable to start application: %s", err.Error())
|
||||
}
|
||||
|
||||
return newProcess
|
||||
return newProcess, appBinary, nil
|
||||
}
|
||||
|
||||
func buildApp(logger *logger.Logger, outputType string, ldflags string, compilerCommand string, buildFrontend bool) (string, error) {
|
||||
func buildApp(logger *clilogger.CLILogger, ldflags string, compilerCommand string, verbosity int) (string, error) {
|
||||
|
||||
// Create random output file
|
||||
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
||||
outputFile := "wailsdev"
|
||||
if runtime.GOOS == "windows" {
|
||||
outputFile += ".exe"
|
||||
}
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
OutputType: "dev",
|
||||
Mode: build.Debug,
|
||||
Pack: false,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
OutputFile: outputFile,
|
||||
IgnoreFrontend: !buildFrontend,
|
||||
IgnoreFrontend: true,
|
||||
Verbosity: verbosity,
|
||||
}
|
||||
|
||||
return build.Build(buildOptions)
|
||||
|
||||
@@ -2,64 +2,60 @@ package doctor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/system"
|
||||
"github.com/wailsapp/wails/v2/internal/system/packagemanager"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `doctor` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli) error {
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("doctor", "Diagnose your environment")
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := logger.New()
|
||||
logger.AddOutput(os.Stdout)
|
||||
logger := clilogger.New(w)
|
||||
|
||||
app.PrintBanner()
|
||||
print("Scanning system - please wait...")
|
||||
|
||||
logger.Print("Scanning system - Please wait (this may take a long time)...")
|
||||
|
||||
// Get system info
|
||||
info, err := system.GetInfo()
|
||||
if err != nil {
|
||||
logger.Println("Failed.")
|
||||
return err
|
||||
}
|
||||
println("Done.")
|
||||
logger.Println("Done.")
|
||||
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
// Write out the system information
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintf(w, "System\n")
|
||||
fmt.Fprintf(w, "------\n")
|
||||
fmt.Fprintf(w, "%s\t%s\n", "OS:", info.OS.Name)
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Version: ", info.OS.Version)
|
||||
fmt.Fprintf(w, "%s\t%s\n", "ID:", info.OS.ID)
|
||||
|
||||
// Exit early if PM not found
|
||||
if info.PM == nil {
|
||||
fmt.Fprintf(w, "\n%s\t%s", "Package Manager:", "Not Found")
|
||||
w.Flush()
|
||||
println()
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
|
||||
|
||||
// Output Go Information
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Go Version:", runtime.Version())
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Platform:", runtime.GOOS)
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Architecture:", runtime.GOARCH)
|
||||
|
||||
// Exit early if PM not found
|
||||
if info.PM != nil {
|
||||
fmt.Fprintf(w, "%s\t%s\n", "Package Manager: ", info.PM.Name())
|
||||
}
|
||||
|
||||
// Output Dependencies Status
|
||||
var dependenciesMissing = []string{}
|
||||
var externalPackages = []*packagemanager.Dependancy{}
|
||||
@@ -69,12 +65,14 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
fmt.Fprintf(w, "Dependency\tPackage Name\tStatus\tVersion\n")
|
||||
fmt.Fprintf(w, "----------\t------------\t------\t-------\n")
|
||||
|
||||
hasOptionalDependencies := false
|
||||
// Loop over dependencies
|
||||
for _, dependency := range info.Dependencies {
|
||||
|
||||
name := dependency.Name
|
||||
if dependency.Optional {
|
||||
name += "*"
|
||||
name = "*" + name
|
||||
hasOptionalDependencies = true
|
||||
}
|
||||
packageName := "Unknown"
|
||||
status := "Not Found"
|
||||
@@ -109,44 +107,48 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", name, packageName, status, dependency.Version)
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintf(w, "* - Optional Dependency\n")
|
||||
if hasOptionalDependencies {
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintf(w, "* - Optional Dependency\n")
|
||||
}
|
||||
w.Flush()
|
||||
println()
|
||||
println("Diagnosis")
|
||||
println("---------\n")
|
||||
logger.Println("")
|
||||
logger.Println("Diagnosis")
|
||||
logger.Println("---------")
|
||||
|
||||
// Generate an appropriate diagnosis
|
||||
|
||||
if len(dependenciesMissing) == 0 && dependenciesAvailableRequired == 0 {
|
||||
println("Your system is ready for Wails development!")
|
||||
logger.Println("Your system is ready for Wails development!")
|
||||
} else {
|
||||
logger.Println("Your system has missing dependencies!\n")
|
||||
}
|
||||
|
||||
if dependenciesAvailableRequired != 0 {
|
||||
println("Install required packages using: " + info.Dependencies.InstallAllRequiredCommand())
|
||||
logger.Println("Required package(s) installation details: \n" + info.Dependencies.InstallAllRequiredCommand())
|
||||
}
|
||||
|
||||
if dependenciesAvailableOptional != 0 {
|
||||
println("Install optional packages using: " + info.Dependencies.InstallAllOptionalCommand())
|
||||
}
|
||||
|
||||
if len(externalPackages) > 0 {
|
||||
for _, p := range externalPackages {
|
||||
if p.Optional {
|
||||
print("[Optional] ")
|
||||
}
|
||||
println("Install " + p.Name + ": " + p.InstallCommand)
|
||||
}
|
||||
logger.Println("Optional package(s) installation details: \n" + info.Dependencies.InstallAllOptionalCommand())
|
||||
}
|
||||
//
|
||||
//if len(externalPackages) > 0 {
|
||||
// for _, p := range externalPackages {
|
||||
// if p.Optional {
|
||||
// print("[Optional] ")
|
||||
// }
|
||||
// logger.Println("Install " + p.Name + ": " + p.InstallCommand)
|
||||
// }
|
||||
//}
|
||||
|
||||
if len(dependenciesMissing) != 0 {
|
||||
// TODO: Check if apps are available locally and if so, adjust the diagnosis
|
||||
println("Fatal:")
|
||||
println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
||||
println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
|
||||
logger.Println("Fatal:")
|
||||
logger.Println("Required dependencies missing: " + strings.Join(dependenciesMissing, " "))
|
||||
logger.Println("Please read this article on how to resolve this: https://wails.app/guides/resolving-missing-packages")
|
||||
}
|
||||
|
||||
println()
|
||||
logger.Println("")
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
18
v2/cmd/wails/internal/commands/generate/README.md
Normal file
18
v2/cmd/wails/internal/commands/generate/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generate
|
||||
|
||||
The `generate` command provides the ability to generate various Wails related components.
|
||||
|
||||
## Usage
|
||||
|
||||
`wails generate [subcommand] [options]`
|
||||
|
||||
## Template
|
||||
|
||||
`wails generate template -name <name> [-frontend] [-q]`
|
||||
|
||||
Generate a starter template for you to customise.
|
||||
|
||||
| Flag | Details |
|
||||
| :------------- | :----------- |
|
||||
| -frontend | Copies all the files from the current directory into the template's `frontend` directory. Useful for converting frontend projects created by boilerplate generators. |
|
||||
| -q | Suppress output |
|
||||
@@ -2,62 +2,22 @@ package generate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
// AddSubcommand adds the `generate` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||
|
||||
// Backend API
|
||||
backendAPI := command.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||
//AddModuleCommand(app, command, w)
|
||||
template.AddSubCommand(app, command, w)
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
backendAPI.BoolFlag("q", "Supress output to console", &quiet)
|
||||
|
||||
backendAPI.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
app.PrintBanner()
|
||||
|
||||
logger.Print("Generating Javascript module for Go code...")
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
p, err := parser.GenerateWailsFrontendPackage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("done.")
|
||||
logger.Println("")
|
||||
|
||||
elapsed := time.Since(start)
|
||||
packages := p.Packages
|
||||
|
||||
// Print report
|
||||
for _, pkg := range p.Packages {
|
||||
if pkg.ShouldGenerate() {
|
||||
logPackage(pkg, logger)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -85,7 +45,4 @@ func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||
}
|
||||
}
|
||||
logger.Println("")
|
||||
|
||||
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||
}
|
||||
|
||||
58
v2/cmd/wails/internal/commands/generate/module.go
Normal file
58
v2/cmd/wails/internal/commands/generate/module.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
|
||||
// Backend API
|
||||
backendAPI := parent.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
backendAPI.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
|
||||
backendAPI.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
app.PrintBanner()
|
||||
|
||||
logger.Print("Generating Javascript module for Go code...")
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
p, err := parser.GenerateWailsFrontendPackage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("done.")
|
||||
logger.Println("")
|
||||
|
||||
elapsed := time.Since(start)
|
||||
packages := p.Packages
|
||||
|
||||
// Print report
|
||||
for _, pkg := range p.Packages {
|
||||
if pkg.ShouldGenerate() {
|
||||
logPackage(pkg, logger)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# Next Steps
|
||||
|
||||
Congratulations on generating your template!
|
||||
|
||||
## Completing your template
|
||||
|
||||
The next steps to complete the template are:
|
||||
|
||||
1. Complete the fields in the `template.json` file.
|
||||
2. Update `README.md`.
|
||||
3. Edit `wails.tmpl.json` and ensure all fields are correct, especially:
|
||||
- `html` - path to your `index.html`
|
||||
- `frontend:install` - The command to install your frontend dependencies
|
||||
- `frontend:build` - The command to build your frontend
|
||||
4. Remove any `public` or `dist` directories.
|
||||
5. Delete this file.
|
||||
|
||||
## Testing your template
|
||||
|
||||
You can test your template by running this command:
|
||||
|
||||
`wails init -name test -t {{.TemplateDir}}`
|
||||
|
||||
### Checklist
|
||||
Once generated, do the following tests:
|
||||
- Change into the new project directory and run `wails build`. A working binary should be generated in the `build/bin` project directory.
|
||||
- Run `wails dev`. This will compile your backend and run it. You should be able to go into the frontend directory and run `npm run dev` (or whatever your dev command is) and this should run correctly. You should be able to then open a browser to your local dev server and the application should work.
|
||||
|
||||
## Publishing your template
|
||||
|
||||
You can publish a template to a git repository and use it as follows:
|
||||
|
||||
`wails init -name test -t https://your/git/url`
|
||||
|
||||
EG:
|
||||
|
||||
`wails init -name test -t https://github.com/leaanthony/testtemplate`
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
|
||||
About your template
|
||||
|
||||
## Building
|
||||
|
||||
To build this project in debug mode, use `wails build`. For production, use `wails build -production`.
|
||||
To generate a platform native package, add the `-package` flag.
|
||||
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
|
||||
in your browser and connect to your application.
|
||||
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
func NewApp() *App {
|
||||
return &App{}
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (b *App) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello %s!", name)
|
||||
}
|
||||
2605
v2/cmd/wails/internal/commands/generate/template/base/frontend/package-lock.json
generated
Normal file
2605
v2/cmd/wails/internal/commands/generate/template/base/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "vanilla",
|
||||
"version": "1.0.0",
|
||||
"description": "Vanilla Wails v2 template",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv dist"
|
||||
},
|
||||
"author": "{{.AuthorName}}",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-commonjs": "^19.0.0",
|
||||
"@rollup/plugin-image": "^2.0.6",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-url": "^6.0.0",
|
||||
"@wails/runtime": "^1.3.20",
|
||||
"rollup": "^2.50.4",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"sirv-cli": "^1.0.12"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import livereload from 'rollup-plugin-livereload';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import image from '@rollup/plugin-image';
|
||||
import url from '@rollup/plugin-url';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
export default {
|
||||
input: 'src/main.js',
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: 'dist/main.js'
|
||||
},
|
||||
onwarn: handleRollupWarning,
|
||||
plugins: [
|
||||
|
||||
image(),
|
||||
|
||||
copy({
|
||||
targets: [
|
||||
{ src: 'src/index.html', dest: 'dist' },
|
||||
{ src: 'src/main.css', dest: 'dist' },
|
||||
]
|
||||
}),
|
||||
|
||||
// Embed binary files
|
||||
url({
|
||||
include: ['**/*.woff', '**/*.woff2'],
|
||||
limit: Infinity,
|
||||
}),
|
||||
|
||||
// If you have external dependencies installed from
|
||||
// npm, you'll most likely need these plugins. In
|
||||
// some cases you'll need additional configuration -
|
||||
// consult the documentation for details:
|
||||
// https://github.com/rollup/plugins/tree/master/packages/commonjs
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs(),
|
||||
|
||||
// PostCSS preprocessing
|
||||
postcss({
|
||||
extensions: ['.css', '.scss'],
|
||||
extract: true,
|
||||
minimize: false,
|
||||
use: [
|
||||
['sass', {
|
||||
includePaths: [
|
||||
'./src',
|
||||
'./node_modules'
|
||||
]
|
||||
}]
|
||||
],
|
||||
}),
|
||||
|
||||
// In dev mode, call `npm run start` once
|
||||
// the bundle has been generated
|
||||
!production && serve(),
|
||||
|
||||
// Watch the `public` directory and refresh the
|
||||
// browser on changes when not in production
|
||||
!production && livereload('dist'),
|
||||
|
||||
// If we're building for production (npm run build
|
||||
// instead of npm run dev), minify
|
||||
production && terser()
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false
|
||||
}
|
||||
};
|
||||
|
||||
function handleRollupWarning(warning) {
|
||||
console.error('ERROR: ' + warning.toString());
|
||||
}
|
||||
|
||||
function serve() {
|
||||
let server;
|
||||
|
||||
function toExit() {
|
||||
if (server) server.kill(0);
|
||||
}
|
||||
|
||||
return {
|
||||
writeBundle() {
|
||||
if (server) return;
|
||||
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
|
||||
stdio: ['ignore', 'inherit', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
process.on('SIGTERM', toExit);
|
||||
process.on('exit', toExit);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -4,10 +4,10 @@
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body data-wails-drag>
|
||||
<div id="logo"></div>
|
||||
<div id="input">
|
||||
<input id="name" type="text"></input>
|
||||
<div id="input" data-wails-no-drag>
|
||||
<input id="name" type="text">
|
||||
<button onclick="greet()">Greet</button>
|
||||
</div>
|
||||
<div id="result"></div>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
|
||||
import {ready} from '@wails/runtime';
|
||||
|
||||
ready( () => {
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Call Basic.Greet(name)
|
||||
window.backend.main.Basic.Greet(name).then((result) => {
|
||||
// Update result with data back from Basic.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
module test
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/wailsapp/wails/v2 v2.0.0-alpha
|
||||
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := NewApp()
|
||||
|
||||
err := wails.Run(&options.App{
|
||||
Title: "{{.ProjectName}}",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
MinWidth: 400,
|
||||
MinHeight: 400,
|
||||
MaxWidth: 1280,
|
||||
MaxHeight: 1024,
|
||||
DisableResize: false,
|
||||
Fullscreen: false,
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
DevTools: false,
|
||||
RGBA: 0x000000FF,
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Long name",
|
||||
"shortname": "{{.Name}}",
|
||||
"author": "",
|
||||
"description": "Description of the template",
|
||||
"helpurl": "URL for help with the template, eg homepage"
|
||||
}
|
||||
@@ -2,8 +2,10 @@
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"html": "frontend/dist/index.html",
|
||||
"js": "frontend/dist/app.js",
|
||||
"css": "frontend/dist/app.css",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install"
|
||||
}
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
}
|
||||
188
v2/cmd/wails/internal/commands/generate/template/template.go
Normal file
188
v2/cmd/wails/internal/commands/generate/template/template.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/leaanthony/debme"
|
||||
|
||||
"github.com/leaanthony/gosod"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
//go:embed base
|
||||
var base embed.FS
|
||||
|
||||
func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
|
||||
// command
|
||||
command := parent.NewSubCommand("template", "Generates a wails template")
|
||||
|
||||
name := ""
|
||||
command.StringFlag("name", "The name of the template", &name)
|
||||
|
||||
migrate := false
|
||||
command.BoolFlag("migrate", "This indicates that the current directory is a frontend project and should be used by the template", &migrate)
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
command.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// If the current directory is not empty, we create a new directory
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
templateDir := cwd
|
||||
empty, err := fs.DirIsEmpty(templateDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !empty {
|
||||
templateDir = filepath.Join(cwd, name)
|
||||
println("Creating new template directory:", name)
|
||||
err = fs.Mkdir(templateDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create base template
|
||||
baseTemplate, err := debme.FS(base, "base")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g := gosod.New(baseTemplate)
|
||||
g.SetTemplateFilters([]string{".template"})
|
||||
|
||||
err = os.Chdir(templateDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
Name string
|
||||
Description string
|
||||
TemplateDir string
|
||||
}
|
||||
|
||||
println("Extracting base template files...")
|
||||
|
||||
err = g.Extract(templateDir, &templateData{
|
||||
Name: name,
|
||||
TemplateDir: templateDir,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we aren't migrating the files, just exit
|
||||
if migrate == false {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove frontend directory
|
||||
frontendDir := filepath.Join(templateDir, "frontend")
|
||||
err = os.RemoveAll(frontendDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Move the files into a new frontend directory
|
||||
println("Migrating files to frontend directory...")
|
||||
err = fs.MoveDirExtended(cwd, frontendDir, []string{name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process package.json
|
||||
err = processPackageJSON(frontendDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process package-lock.json
|
||||
err = processPackageLockJSON(frontendDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove node_modules - ignore error, eg it doesn't exist
|
||||
_ = os.RemoveAll(filepath.Join(frontendDir, "node_modules"))
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func processPackageJSON(frontendDir string) error {
|
||||
var err error
|
||||
|
||||
packageJSON := filepath.Join(frontendDir, "package.json")
|
||||
if !fs.FileExists(packageJSON) {
|
||||
println("No package.json found - cannot process.")
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(packageJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json := string(data)
|
||||
|
||||
// We will ignore these errors - it's not critical
|
||||
println("Updating package.json data...")
|
||||
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
|
||||
json, _ = sjson.Set(json, "author", "{{.AuthorName}}")
|
||||
|
||||
err = os.WriteFile(packageJSON, []byte(json), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseDir := filepath.Dir(packageJSON)
|
||||
println("Renaming package.json -> package.tmpl.json...")
|
||||
err = os.Rename(packageJSON, filepath.Join(baseDir, "package.tmpl.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processPackageLockJSON(frontendDir string) error {
|
||||
var err error
|
||||
|
||||
filename := filepath.Join(frontendDir, "package-lock.json")
|
||||
if !fs.FileExists(filename) {
|
||||
println("No package-lock.json found - cannot process.")
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json := string(data)
|
||||
|
||||
// We will ignore these errors - it's not critical
|
||||
println("Updating package-lock.json data...")
|
||||
json, _ = sjson.Set(json, "name", "{{.ProjectName}}")
|
||||
|
||||
err = os.WriteFile(filename, []byte(json), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseDir := filepath.Dir(filename)
|
||||
println("Renaming package-lock.json -> package-lock.tmpl.json...")
|
||||
err = os.Rename(filename, filepath.Join(baseDir, "package-lock.tmpl.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2,29 +2,28 @@ package initialise
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
||||
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise/templates"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/templates"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/git"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `init` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli) error {
|
||||
|
||||
// Load the template shortnames
|
||||
validShortNames, err := templates.TemplateShortNames()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("init", "Initialise a new Wails project")
|
||||
|
||||
// Setup template name flag
|
||||
templateName := "vanilla"
|
||||
description := "Name of template to use. Valid tempates: " + validShortNames.Join(" ")
|
||||
description := "Name of built-in template to use, path to template or template url."
|
||||
command.StringFlag("t", description, &templateName)
|
||||
|
||||
// Setup project name
|
||||
@@ -32,12 +31,23 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
command.StringFlag("n", "Name of project", &projectName)
|
||||
|
||||
// Setup project directory
|
||||
projectDirectory := "."
|
||||
projectDirectory := ""
|
||||
command.StringFlag("d", "Project directory", &projectDirectory)
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||
command.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
|
||||
initGit := false
|
||||
gitInstalled := git.IsInstalled()
|
||||
if gitInstalled {
|
||||
// Git Init
|
||||
command.BoolFlag("g", "Initialise git repository", &initGit)
|
||||
}
|
||||
|
||||
// VSCode project files
|
||||
vscode := false
|
||||
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||
|
||||
// List templates
|
||||
list := false
|
||||
@@ -46,32 +56,21 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := logger.New()
|
||||
|
||||
if !quiet {
|
||||
logger.AddOutput(os.Stdout)
|
||||
}
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
// Are we listing templates?
|
||||
if list {
|
||||
app.PrintBanner()
|
||||
err := templates.OutputList(logger)
|
||||
logger.Writeln("")
|
||||
logger.Println("")
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate output type
|
||||
if !validShortNames.Contains(templateName) {
|
||||
logger.Write(fmt.Sprintf("ERROR: Template '%s' is not valid", templateName))
|
||||
logger.Writeln("")
|
||||
command.PrintHelp()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate name
|
||||
if len(projectName) == 0 {
|
||||
logger.Writeln("ERROR: Project name required")
|
||||
logger.Writeln("")
|
||||
logger.Println("ERROR: Project name required")
|
||||
logger.Println("")
|
||||
command.PrintHelp()
|
||||
return nil
|
||||
}
|
||||
@@ -81,17 +80,22 @@ func AddSubcommand(app *clir.Cli) error {
|
||||
}
|
||||
|
||||
task := fmt.Sprintf("Initialising Project %s", strings.Title(projectName))
|
||||
logger.Writeln(task)
|
||||
logger.Writeln(strings.Repeat("-", len(task)))
|
||||
logger.Println(task)
|
||||
logger.Println(strings.Repeat("-", len(task)))
|
||||
|
||||
// Create Template Options
|
||||
options := &templates.Options{
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
GenerateVSCode: vscode,
|
||||
InitGit: initGit,
|
||||
}
|
||||
|
||||
// Try to discover author details from git config
|
||||
findAuthorDetails(options)
|
||||
|
||||
return initProject(options)
|
||||
})
|
||||
|
||||
@@ -105,16 +109,69 @@ func initProject(options *templates.Options) error {
|
||||
start := time.Now()
|
||||
|
||||
// Install the template
|
||||
err := templates.Install(options)
|
||||
remote, err := templates.Install(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Install the default assets
|
||||
err = buildassets.Install(options.TargetDir, options.ProjectName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.InitGit {
|
||||
err = initGit(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
options.Logger.Writeln("")
|
||||
options.Logger.Writeln(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
||||
options.Logger.Writeln("")
|
||||
options.Logger.Println("")
|
||||
options.Logger.Println("Project Name: " + options.ProjectName)
|
||||
options.Logger.Println("Project Directory: " + options.TargetDir)
|
||||
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||
if options.GenerateVSCode {
|
||||
options.Logger.Println("VSCode config files generated.")
|
||||
}
|
||||
if options.InitGit {
|
||||
options.Logger.Println("Git repository initialised.")
|
||||
}
|
||||
|
||||
if remote {
|
||||
options.Logger.Println("\nNOTE: You have created a project using a remote template. The Wails project takes no responsibility for 3rd party templates. Only use remote templates that you trust.")
|
||||
}
|
||||
|
||||
options.Logger.Println("")
|
||||
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
||||
options.Logger.Println("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initGit(options *templates.Options) error {
|
||||
err := git.InitRepo(options.TargetDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to initialise git repository:")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findAuthorDetails tries to find the user's name and email
|
||||
// from gitconfig. If it finds them, it stores them in the project options
|
||||
func findAuthorDetails(options *templates.Options) {
|
||||
if git.IsInstalled() {
|
||||
name, err := git.Name()
|
||||
if err == nil {
|
||||
options.AuthorName = strings.TrimSpace(name)
|
||||
}
|
||||
|
||||
email, err := git.Email()
|
||||
if err == nil {
|
||||
options.AuthorEmail = strings.TrimSpace(email)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
357
v2/cmd/wails/internal/commands/initialise/templates/templates.go
Normal file
357
v2/cmd/wails/internal/commands/initialise/templates/templates.go
Normal file
@@ -0,0 +1,357 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
gofs "io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/leaanthony/debme"
|
||||
"github.com/leaanthony/gosod"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
)
|
||||
|
||||
//go:embed templates
|
||||
var templates embed.FS
|
||||
|
||||
//go:embed ides/*
|
||||
var ides embed.FS
|
||||
|
||||
// Cahce for the templates
|
||||
// We use this because we need different views of the same data
|
||||
var templateCache []Template = nil
|
||||
|
||||
// Data contains the data we wish to embed during template installation
|
||||
type Data struct {
|
||||
ProjectName string
|
||||
BinaryName string
|
||||
WailsVersion string
|
||||
NPMProjectName string
|
||||
AuthorName string
|
||||
AuthorEmail string
|
||||
AuthorNameAndEmail string
|
||||
WailsDirectory string
|
||||
}
|
||||
|
||||
// Options for installing a template
|
||||
type Options struct {
|
||||
ProjectName string
|
||||
TemplateName string
|
||||
BinaryName string
|
||||
TargetDir string
|
||||
Logger *clilogger.CLILogger
|
||||
GenerateVSCode bool
|
||||
PathToDesktopBinary string
|
||||
PathToServerBinary string
|
||||
InitGit bool
|
||||
AuthorName string
|
||||
AuthorEmail string
|
||||
}
|
||||
|
||||
// Template holds data relating to a template
|
||||
// including the metadata stored in template.json
|
||||
type Template struct {
|
||||
|
||||
// Template details
|
||||
Name string `json:"name"`
|
||||
ShortName string `json:"shortname"`
|
||||
Author string `json:"author"`
|
||||
Description string `json:"description"`
|
||||
HelpURL string `json:"helpurl"`
|
||||
|
||||
// Other data
|
||||
FS gofs.FS `json:"-"`
|
||||
}
|
||||
|
||||
func parseTemplate(template gofs.FS) (Template, error) {
|
||||
var result Template
|
||||
data, err := gofs.ReadFile(template, "template.json")
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "Error parsing template")
|
||||
}
|
||||
err = json.Unmarshal(data, &result)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.FS = template
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// List returns the list of available templates
|
||||
func List() ([]Template, error) {
|
||||
|
||||
// If the cache isn't loaded, load it
|
||||
if templateCache == nil {
|
||||
err := loadTemplateCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return templateCache, nil
|
||||
}
|
||||
|
||||
// getTemplateByShortname returns the template with the given short name
|
||||
func getTemplateByShortname(shortname string) (Template, error) {
|
||||
|
||||
var result Template
|
||||
|
||||
// If the cache isn't loaded, load it
|
||||
if templateCache == nil {
|
||||
err := loadTemplateCache()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, template := range templateCache {
|
||||
if template.ShortName == shortname {
|
||||
return template, nil
|
||||
}
|
||||
}
|
||||
|
||||
return result, fmt.Errorf("shortname '%s' is not a valid template shortname", shortname)
|
||||
}
|
||||
|
||||
// Loads the template cache
|
||||
func loadTemplateCache() error {
|
||||
|
||||
templatesFS, err := debme.FS(templates, "templates")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get directories
|
||||
files, err := templatesFS.ReadDir(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reset cache
|
||||
templateCache = []Template{}
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
templateFS, err := templatesFS.FS(file.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
template, err := parseTemplate(templateFS)
|
||||
if err != nil {
|
||||
// Cannot parse this template, continue
|
||||
continue
|
||||
}
|
||||
templateCache = append(templateCache, template)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Install the given template. Returns true if the template is remote.
|
||||
func Install(options *Options) (bool, error) {
|
||||
// Get cwd
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Did the user want to install in current directory?
|
||||
if options.TargetDir == "" {
|
||||
|
||||
// If the current directory is empty, use it
|
||||
isEmpty, err := fs.DirIsEmpty(cwd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if isEmpty {
|
||||
// Yes - use cwd
|
||||
options.TargetDir = cwd
|
||||
} else {
|
||||
options.TargetDir = filepath.Join(cwd, options.ProjectName)
|
||||
if fs.DirExists(options.TargetDir) {
|
||||
return false, fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Get the absolute path of the given directory
|
||||
targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
options.TargetDir = targetDir
|
||||
if !fs.DirExists(options.TargetDir) {
|
||||
err := fs.Mkdir(options.TargetDir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flag to indicate remote template
|
||||
remoteTemplate := false
|
||||
|
||||
// Is this a shortname?
|
||||
template, err := getTemplateByShortname(options.TemplateName)
|
||||
if err != nil {
|
||||
// Is this a filepath?
|
||||
templatePath, err := filepath.Abs(options.TemplateName)
|
||||
if fs.DirExists(templatePath) {
|
||||
templateFS := os.DirFS(templatePath)
|
||||
template, err = parseTemplate(templateFS)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "Error installing template")
|
||||
}
|
||||
} else {
|
||||
// git clone to temporary dir
|
||||
tempdir, err := gitclone(options)
|
||||
defer func(path string) {
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(tempdir)
|
||||
templateFS := os.DirFS(tempdir)
|
||||
template, err = parseTemplate(templateFS)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
remoteTemplate = true
|
||||
}
|
||||
}
|
||||
|
||||
// Use Gosod to install the template
|
||||
installer := gosod.New(template.FS)
|
||||
|
||||
// Ignore template.json files
|
||||
installer.IgnoreFile("template.json")
|
||||
|
||||
// Setup the data.
|
||||
// We use the directory name for the binary name, like Go
|
||||
BinaryName := filepath.Base(options.TargetDir)
|
||||
NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", ""))
|
||||
localWailsDirectory := fs.RelativePath("../../../../../..")
|
||||
templateData := &Data{
|
||||
ProjectName: options.ProjectName,
|
||||
BinaryName: filepath.Base(options.TargetDir),
|
||||
NPMProjectName: NPMProjectName,
|
||||
WailsDirectory: localWailsDirectory,
|
||||
AuthorEmail: options.AuthorEmail,
|
||||
AuthorName: options.AuthorName,
|
||||
}
|
||||
|
||||
// Create a formatted name and email combo.
|
||||
if options.AuthorName != "" {
|
||||
templateData.AuthorNameAndEmail = options.AuthorName + " "
|
||||
}
|
||||
if options.AuthorEmail != "" {
|
||||
templateData.AuthorNameAndEmail += "<" + options.AuthorEmail + ">"
|
||||
}
|
||||
templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail)
|
||||
|
||||
// Extract the template
|
||||
err = installer.Extract(options.TargetDir, templateData)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = generateIDEFiles(options)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return remoteTemplate, nil
|
||||
}
|
||||
|
||||
// Clones the given uri and returns the temporary cloned directory
|
||||
func gitclone(options *Options) (string, error) {
|
||||
// Create temporary directory
|
||||
dirname, err := ioutil.TempDir("", "wails-template-*")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = git.PlainClone(dirname, false, &git.CloneOptions{
|
||||
URL: options.TemplateName,
|
||||
})
|
||||
|
||||
return dirname, err
|
||||
|
||||
}
|
||||
|
||||
// OutputList prints the list of available tempaltes to the given logger
|
||||
func OutputList(logger *clilogger.CLILogger) error {
|
||||
templates, err := List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(logger.Writer)
|
||||
table.SetHeader([]string{"Template", "Short Name", "Description"})
|
||||
table.SetAutoWrapText(false)
|
||||
table.SetAutoFormatHeaders(true)
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetCenterSeparator("")
|
||||
table.SetColumnSeparator("")
|
||||
table.SetRowSeparator("")
|
||||
table.SetHeaderLine(false)
|
||||
table.SetBorder(false)
|
||||
table.SetTablePadding("\t") // pad with tabs
|
||||
table.SetNoWhiteSpace(true)
|
||||
for _, template := range templates {
|
||||
table.Append([]string{template.Name, template.ShortName, template.Description})
|
||||
}
|
||||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateIDEFiles(options *Options) error {
|
||||
|
||||
if options.GenerateVSCode {
|
||||
return generateVSCodeFiles(options)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateVSCodeFiles(options *Options) error {
|
||||
|
||||
targetDir := filepath.Join(options.TargetDir, ".vscode")
|
||||
source, err := debme.FS(ides, "ides/vscode")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use gosod to install the template
|
||||
installer := gosod.New(source)
|
||||
|
||||
binaryName := filepath.Base(options.TargetDir)
|
||||
if runtime.GOOS == "windows" {
|
||||
// yay windows
|
||||
binaryName += ".exe"
|
||||
}
|
||||
|
||||
options.PathToDesktopBinary = filepath.Join("build", runtime.GOOS, "desktop", binaryName)
|
||||
options.PathToServerBinary = filepath.Join("build", runtime.GOOS, "server", binaryName)
|
||||
|
||||
err = installer.Extract(targetDir, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
|
||||
This is a basic Svelte template, using rollup to bundle the assets into a single JS file.
|
||||
Rollup is configured to do the following:
|
||||
|
||||
- Convert imported images to base64 strings
|
||||
- Convert `url()` in `@font-face` declarations to base64 strings
|
||||
- Bundle all css into the JS bundle
|
||||
- Copy `index.html` from `frontend/src/` to `frontend/dist/`
|
||||
|
||||
Clicking the button will call the backend
|
||||
|
||||
## Building
|
||||
|
||||
To build this project in debug mode, use `wails build`. For production, use `wails build -production`.
|
||||
To generate a platform native package, add the `-package` flag.
|
||||
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
|
||||
in your browser and connect to your application.
|
||||
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App application struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
func NewApp() *App {
|
||||
return &App{}
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (b *App) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello %s!", name)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/node_modules/
|
||||
/public/build/
|
||||
/dist/build/
|
||||
|
||||
.DS_Store
|
||||
@@ -35,6 +35,7 @@ Navigate to [localhost:5000](http://localhost:5000). You should see your app run
|
||||
|
||||
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
|
||||
|
||||
If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
|
||||
|
||||
## Building and running in production mode
|
||||
|
||||
@@ -57,26 +58,37 @@ If you're building a single-page app (SPA) with multiple routes, sirv needs to b
|
||||
"start": "sirv public --single"
|
||||
```
|
||||
|
||||
## Using TypeScript
|
||||
|
||||
This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
|
||||
|
||||
```bash
|
||||
node scripts/setupTypeScript.js
|
||||
```
|
||||
|
||||
Or remove the script via:
|
||||
|
||||
```bash
|
||||
rm scripts/setupTypeScript.js
|
||||
```
|
||||
|
||||
## Deploying to the web
|
||||
|
||||
### With [now](https://zeit.co/now)
|
||||
### With [Vercel](https://vercel.com)
|
||||
|
||||
Install `now` if you haven't already:
|
||||
Install `vercel` if you haven't already:
|
||||
|
||||
```bash
|
||||
npm install -g now
|
||||
npm install -g vercel
|
||||
```
|
||||
|
||||
Then, from within your project folder:
|
||||
|
||||
```bash
|
||||
cd public
|
||||
now deploy --name my-project
|
||||
vercel deploy --name my-project
|
||||
```
|
||||
|
||||
As an alternative, use the [Now desktop client](https://zeit.co/download) and simply drag the unzipped project folder to the taskbar icon.
|
||||
|
||||
### With [surge](https://surge.sh/)
|
||||
|
||||
Install `surge` if you haven't already:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "{{.ProjectName}}",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv dist --no-clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-image": "^2.0.6",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"postcss": "^8.3.5",
|
||||
"postcss-url": "^10.1.3",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sirv-cli": "^1.0.0"
|
||||
}
|
||||
,"author":"{{.AuthorName}}"}
|
||||
@@ -1,30 +1,62 @@
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import livereload from 'rollup-plugin-livereload';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
import image from '@rollup/plugin-image';
|
||||
import postcss from 'rollup-plugin-postcss'
|
||||
import url from 'postcss-url';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
function serve() {
|
||||
let server;
|
||||
|
||||
function toExit() {
|
||||
if (server) server.kill(0);
|
||||
}
|
||||
|
||||
return {
|
||||
writeBundle() {
|
||||
if (server) return;
|
||||
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
|
||||
stdio: ['ignore', 'inherit', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
process.on('SIGTERM', toExit);
|
||||
process.on('exit', toExit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
input: 'src/main.js',
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: 'public/bundle.js'
|
||||
file: 'dist/bundle.js'
|
||||
},
|
||||
plugins: [
|
||||
image({
|
||||
include: './src/assets/images/**'
|
||||
}),
|
||||
svelte({
|
||||
// enable run-time checks when not in production
|
||||
dev: !production,
|
||||
// we'll extract any component CSS out into
|
||||
// a separate file - better for performance
|
||||
css: css => {
|
||||
css.write('public/bundle.css');
|
||||
compilerOptions: {
|
||||
// enable run-time checks when not in production
|
||||
dev: !production
|
||||
}
|
||||
}),
|
||||
|
||||
postcss({
|
||||
minimize: true,
|
||||
plugins: [
|
||||
url({
|
||||
url: "inline"
|
||||
})
|
||||
]
|
||||
}),
|
||||
// If you have external dependencies installed from
|
||||
// npm, you'll most likely need these plugins. In
|
||||
// some cases you'll need additional configuration -
|
||||
@@ -35,14 +67,19 @@ export default {
|
||||
dedupe: ['svelte']
|
||||
}),
|
||||
commonjs(),
|
||||
copy({
|
||||
targets: [
|
||||
{ src: 'src/index.html', dest: 'dist/' },
|
||||
]
|
||||
}),
|
||||
|
||||
// In dev mode, call `npm run start` once
|
||||
// the bundle has been generated
|
||||
!production && serve(),
|
||||
|
||||
// Watch the `public` directory and refresh the
|
||||
// Watch the `dist` directory and refresh the
|
||||
// browser on changes when not in production
|
||||
!production && livereload('public'),
|
||||
!production && livereload('dist'),
|
||||
|
||||
// If we're building for production (npm run build
|
||||
// instead of npm run dev), minify
|
||||
@@ -52,20 +89,3 @@ export default {
|
||||
clearScreen: false
|
||||
}
|
||||
};
|
||||
|
||||
function serve() {
|
||||
let started = false;
|
||||
|
||||
return {
|
||||
writeBundle() {
|
||||
if (!started) {
|
||||
started = true;
|
||||
|
||||
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
|
||||
stdio: ['ignore', 'inherit', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// @ts-check
|
||||
|
||||
/** This script modifies the project to support TS code in .svelte files like:
|
||||
|
||||
<script lang="ts">
|
||||
export let name: string;
|
||||
</script>
|
||||
|
||||
As well as validating the code for CI.
|
||||
*/
|
||||
|
||||
/** To work on this script:
|
||||
rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
|
||||
*/
|
||||
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const { argv } = require("process")
|
||||
|
||||
const projectRoot = argv[2] || path.join(__dirname, "..")
|
||||
|
||||
// Add deps to pkg.json
|
||||
const packageJSON = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"))
|
||||
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
|
||||
"svelte-check": "^2.0.0",
|
||||
"svelte-preprocess": "^4.0.0",
|
||||
"@rollup/plugin-typescript": "^8.0.0",
|
||||
"typescript": "^4.0.0",
|
||||
"tslib": "^2.0.0",
|
||||
"@tsconfig/svelte": "^2.0.0"
|
||||
})
|
||||
|
||||
// Add script for checking
|
||||
packageJSON.scripts = Object.assign(packageJSON.scripts, {
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json"
|
||||
})
|
||||
|
||||
// Write the package JSON
|
||||
fs.writeFileSync(path.join(projectRoot, "package.json"), JSON.stringify(packageJSON, null, " "))
|
||||
|
||||
// mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
|
||||
const beforeMainJSPath = path.join(projectRoot, "src", "main.js")
|
||||
const afterMainTSPath = path.join(projectRoot, "src", "main.ts")
|
||||
fs.renameSync(beforeMainJSPath, afterMainTSPath)
|
||||
|
||||
// Switch the app.svelte file to use TS
|
||||
const appSveltePath = path.join(projectRoot, "src", "App.svelte")
|
||||
let appFile = fs.readFileSync(appSveltePath, "utf8")
|
||||
appFile = appFile.replace("<script>", '<script lang="ts">')
|
||||
appFile = appFile.replace("export let name;", 'export let name: string;')
|
||||
fs.writeFileSync(appSveltePath, appFile)
|
||||
|
||||
// Edit rollup config
|
||||
const rollupConfigPath = path.join(projectRoot, "rollup.config.js")
|
||||
let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8")
|
||||
|
||||
// Edit imports
|
||||
rollupConfig = rollupConfig.replace(`'rollup-plugin-terser';`, `'rollup-plugin-terser';
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
import typescript from '@rollup/plugin-typescript';`)
|
||||
|
||||
// Replace name of entry point
|
||||
rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`)
|
||||
|
||||
// Add preprocessor
|
||||
rollupConfig = rollupConfig.replace(
|
||||
'compilerOptions:',
|
||||
'preprocess: sveltePreprocess({ sourceMap: !production }),\n\t\t\tcompilerOptions:'
|
||||
);
|
||||
|
||||
// Add TypeScript
|
||||
rollupConfig = rollupConfig.replace(
|
||||
'commonjs(),',
|
||||
'commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),'
|
||||
);
|
||||
fs.writeFileSync(rollupConfigPath, rollupConfig)
|
||||
|
||||
// Add TSConfig
|
||||
const tsconfig = `{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
|
||||
}`
|
||||
const tsconfigPath = path.join(projectRoot, "tsconfig.json")
|
||||
fs.writeFileSync(tsconfigPath, tsconfig)
|
||||
|
||||
// Add global.d.ts
|
||||
const dtsPath = path.join(projectRoot, "src", "global.d.ts")
|
||||
fs.writeFileSync(dtsPath, `/// <reference types="svelte" />`)
|
||||
|
||||
// Delete this script, but not during testing
|
||||
if (!argv[2]) {
|
||||
// Remove the script
|
||||
fs.unlinkSync(path.join(__filename))
|
||||
|
||||
// Check for Mac's DS_store file, and if it's the only one left remove it
|
||||
const remainingFiles = fs.readdirSync(path.join(__dirname))
|
||||
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
|
||||
fs.unlinkSync(path.join(__dirname, '.DS_store'))
|
||||
}
|
||||
|
||||
// Check if the scripts folder is empty
|
||||
if (fs.readdirSync(path.join(__dirname)).length === 0) {
|
||||
// Remove the scripts folder
|
||||
fs.rmdirSync(path.join(__dirname))
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the extension recommendation
|
||||
fs.mkdirSync(path.join(projectRoot, ".vscode"), { recursive: true })
|
||||
fs.writeFileSync(path.join(projectRoot, ".vscode", "extensions.json"), `{
|
||||
"recommendations": ["svelte.svelte-vscode"]
|
||||
}
|
||||
`)
|
||||
|
||||
console.log("Converted to TypeScript.")
|
||||
|
||||
if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
|
||||
console.log("\nYou will need to re-run your dependency manager to get started.")
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<script>
|
||||
let name = "";
|
||||
let greeting = "";
|
||||
|
||||
function greet() {
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
greeting = result;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<div id="logo"></div>
|
||||
<div id="input" data-wails-no-drag>
|
||||
<input id="name" type="text" bind:value={name}>
|
||||
<button class="button" on:click={greet}>Greet</button>
|
||||
</div>
|
||||
{#if greeting}
|
||||
<div id="result">{greeting}</div>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
|
||||
main {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#result {
|
||||
margin-top: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
-webkit-appearance: default-button;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#name {
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
padding-top: 20%;
|
||||
margin: auto;
|
||||
display: block;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("assets/images/logo-dark.svg");
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 551 436" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1.27527,0,0,1.27527,104.01,410.563)">
|
||||
<path d="M0,-51.891L14.429,-51.891L13.043,-21.183L22.568,-51.891L34.226,-51.891L34.084,-21.183L42.365,-51.891L56.794,-51.891L38.526,0L25.198,0L25.34,-32.45L15.211,0L1.919,0L0,-51.891Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,224.985,367.503)">
|
||||
<path d="M0,15.639L5.793,15.639L5.971,-3.589L0,15.639ZM-20.187,33.765L-0.675,-18.126L16.42,-18.126L20.08,33.765L5.437,33.765L5.509,26.123L-3.057,26.123L-5.332,33.765L-20.187,33.765Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.19929,-1.2596,-1.2596,-0.19929,332.323,396.949)">
|
||||
<path d="M-16.046,33.107L36.491,33.107L38.757,18.784L-13.785,18.82L-16.046,33.107Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,353.217,344.388)">
|
||||
<path d="M0,51.891L8.246,0L22.781,0L16.597,39.024L27.224,39.024L25.199,51.891L0,51.891Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.27527,0,0,1.27527,427.939,364.922)">
|
||||
<path d="M0,19.83C1.611,21.181 3.305,22.224 5.083,22.959C6.859,23.693 8.565,24.06 10.2,24.06C11.645,24.06 12.794,23.663 13.647,22.87C14.5,22.076 14.927,20.992 14.927,19.617C14.927,18.434 14.571,17.254 13.861,16.081C13.15,14.908 11.775,13.351 9.738,11.408C7.273,9.015 5.58,6.906 4.655,5.081C3.731,3.257 3.27,1.243 3.27,-0.96C3.27,-5.912 4.839,-9.846 7.979,-12.76C11.118,-15.674 15.377,-17.132 20.756,-17.132C22.936,-17.132 25.008,-16.889 26.975,-16.403C28.941,-15.917 30.943,-15.165 32.982,-14.146L30.92,-1.493C29.356,-2.583 27.834,-3.412 26.354,-3.981C24.872,-4.551 23.457,-4.835 22.106,-4.835C20.898,-4.835 19.943,-4.521 19.245,-3.894C18.546,-3.265 18.196,-2.406 18.196,-1.316C18.196,0.154 19.535,2.215 22.213,4.868C22.544,5.2 22.805,5.46 22.995,5.649C25.696,8.304 27.473,10.578 28.326,12.475C29.179,14.37 29.605,16.56 29.605,19.049C29.605,24.594 27.893,28.965 24.469,32.163C21.046,35.361 16.36,36.962 10.413,36.962C7.877,36.962 5.479,36.66 3.216,36.056C0.953,35.45 -0.948,34.615 -2.488,33.549L0,19.83Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-166.599,4.57132,4.57132,166.599,147.403,167.648)">
|
||||
<path d="M0.883,-0.081L0.121,0.081L0.256,-0.063L0.883,-0.081Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-106.443,-16.0669,-16.0669,106.443,428.19,188.033)">
|
||||
<path d="M0.878,-0.285L-0.073,0.71L-1.186,0.542L0.015,0.207L-0.846,0.077L0.355,-0.258L-0.505,-0.388L0.649,-0.71L0.878,-0.285Z" style="fill:url(#_Linear2);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-114.484,-162.408,-162.408,114.484,333.291,285.804)">
|
||||
<path d="M0.44,-0.04L0.44,-0.04L0.44,-0.04L0.265,-0.056L0.177,0.437L-0.311,-0.255L0.262,-0.437L0.568,-0.437L0.44,-0.04Z" style="fill:url(#_Linear3);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(61.6919,58.8091,58.8091,-61.6919,258.631,180.413)">
|
||||
<path d="M0.5,0L0.5,-0L0.5,0L0.5,0Z" style="fill:url(#_Linear4);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(238.126,298.893,298.893,-238.126,113.516,-150.536)">
|
||||
<path d="M0.622,-0.115L0.761,-0.115L0.806,-0.013L0.826,0.182L0.622,-0.115Z" style="fill:url(#_Linear5);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-369.529,-97.4118,-97.4118,369.529,582.38,94.027)">
|
||||
<path d="M0.467,0.005L0.49,0.062L0.271,-0.062L0.467,0.005Z" style="fill:url(#_Linear6);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(-496.156,-53.9751,-53.9751,496.156,367.888,125.085)">
|
||||
<path d="M0.2,0.001L0.219,-0.018L0.614,0.012L0.519,0.089L0.282,0.068L0.2,0.135L0.463,0.194L0.374,0.266L0.138,0.186L0.138,0.186L0.138,0.186L0.047,0.033L-0.131,-0.266L0.2,0.001Z" style="fill:url(#_Linear7);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(185.076,176.427,176.427,-185.076,153.446,80.1488)">
|
||||
<path d="M0.735,-0L0.735,-0L0.735,0L0.735,-0Z" style="fill:url(#_Linear8);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,-3.46945e-18,-3.46945e-18,-1,0,-3.05761e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,-2.75467e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,-1.11022e-16,-1.11022e-16,-1,0,-2.61861e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,-5.55112e-17,-5.55112e-17,-1,0,-1.57562e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.801899,-0.59746,-0.59746,0.801899,1.3495,0.447457)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,-2.77556e-17,-2.77556e-17,-1,0,-1.92826e-06)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear7" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,9.68429e-07)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
<linearGradient id="_Linear8" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,1.43665e-07)"><stop offset="0" style="stop-color:rgb(227,50,50);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(107,0,13);stop-opacity:1"/></linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,24 @@
|
||||
|
||||
html {
|
||||
text-align: center;
|
||||
color: white;
|
||||
background-color: rgba(1,1,1,0.1);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
color: white;
|
||||
font-family: 'Nunito', -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Nunito';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local(''),
|
||||
url('./assets/fonts/nunito-v16-latin-regular.woff2') format('woff2')
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||
|
||||
<title>Svelte app</title>
|
||||
|
||||
<script defer src='bundle.js'></script>
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +1,9 @@
|
||||
|
||||
import App from './App.svelte';
|
||||
import './global.css';
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
name: 'Wails User'
|
||||
}
|
||||
});
|
||||
|
||||
export default app;
|
||||
export default app;
|
||||
@@ -1,6 +1,6 @@
|
||||
module test
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/wailsapp/wails/v2 v2.0.0-alpha
|
||||
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := NewApp()
|
||||
|
||||
err := wails.Run(&options.App{
|
||||
Title: "{{.ProjectName}}",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
MinWidth: 400,
|
||||
MinHeight: 400,
|
||||
MaxWidth: 1280,
|
||||
MaxHeight: 1024,
|
||||
DisableResize: false,
|
||||
Fullscreen: false,
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
DevTools: false,
|
||||
RGBA: 0x000000FF,
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Basic Svelte + Rollup",
|
||||
"shortname": "svelte",
|
||||
"author": "Lea Anthony",
|
||||
"description": "Svelte template using rollup to bundle css, images and fonts",
|
||||
"helpurl": "https://github.com/wailsapp/wails"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"html": "frontend/dist/index.html",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
|
||||
This template uses vanilla JS / HTML and CSS. [Rollup](https://rollupjs.org/guide/en/) is used for processing and bundling the files.
|
||||
|
||||
## Building
|
||||
|
||||
To build this project in debug mode, use `wails build`. For production, use `wails build -production`.
|
||||
To generate a platform native package, add the `-package` flag.
|
||||
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
|
||||
in your browser and connect to your application.
|
||||
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
)
|
||||
|
||||
// App struct
|
||||
type App struct {
|
||||
runtime *wails.Runtime
|
||||
}
|
||||
|
||||
// NewApp creates a new App application struct
|
||||
func NewApp() *App {
|
||||
return &App{}
|
||||
}
|
||||
|
||||
// startup is called at application startup
|
||||
func (b *App) startup(runtime *wails.Runtime) {
|
||||
// Perform your setup here
|
||||
b.runtime = runtime
|
||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||
}
|
||||
|
||||
// shutdown is called at application termination
|
||||
func (b *App) shutdown() {
|
||||
// Perform your teardown here
|
||||
}
|
||||
|
||||
// Greet returns a greeting for the given name
|
||||
func (b *App) Greet(name string) string {
|
||||
return fmt.Sprintf("Hello %s!", name)
|
||||
}
|
||||
2605
v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/package-lock.json
generated
Normal file
2605
v2/cmd/wails/internal/commands/initialise/templates/templates/vanilla/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "vanilla",
|
||||
"version": "1.0.0",
|
||||
"description": "Vanilla Wails v2 template",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv dist"
|
||||
},
|
||||
"author": "{{.AuthorName}}",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-commonjs": "^19.0.0",
|
||||
"@rollup/plugin-image": "^2.0.6",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-url": "^6.0.0",
|
||||
"@wails/runtime": "^1.3.20",
|
||||
"rollup": "^2.50.4",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"sirv-cli": "^1.0.12"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import livereload from 'rollup-plugin-livereload';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import image from '@rollup/plugin-image';
|
||||
import url from '@rollup/plugin-url';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
export default {
|
||||
input: 'src/main.js',
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: 'dist/main.js'
|
||||
},
|
||||
onwarn: handleRollupWarning,
|
||||
plugins: [
|
||||
|
||||
image(),
|
||||
|
||||
copy({
|
||||
targets: [
|
||||
{ src: 'src/index.html', dest: 'dist' },
|
||||
{ src: 'src/main.css', dest: 'dist' },
|
||||
]
|
||||
}),
|
||||
|
||||
// Embed binary files
|
||||
url({
|
||||
include: ['**/*.woff', '**/*.woff2'],
|
||||
limit: Infinity,
|
||||
}),
|
||||
|
||||
// If you have external dependencies installed from
|
||||
// npm, you'll most likely need these plugins. In
|
||||
// some cases you'll need additional configuration -
|
||||
// consult the documentation for details:
|
||||
// https://github.com/rollup/plugins/tree/master/packages/commonjs
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs(),
|
||||
|
||||
// PostCSS preprocessing
|
||||
postcss({
|
||||
extensions: ['.css', '.scss'],
|
||||
extract: true,
|
||||
minimize: false,
|
||||
use: [
|
||||
['sass', {
|
||||
includePaths: [
|
||||
'./src',
|
||||
'./node_modules'
|
||||
]
|
||||
}]
|
||||
],
|
||||
}),
|
||||
|
||||
// In dev mode, call `npm run start` once
|
||||
// the bundle has been generated
|
||||
!production && serve(),
|
||||
|
||||
// Watch the `public` directory and refresh the
|
||||
// browser on changes when not in production
|
||||
!production && livereload('dist'),
|
||||
|
||||
// If we're building for production (npm run build
|
||||
// instead of npm run dev), minify
|
||||
production && terser()
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false
|
||||
}
|
||||
};
|
||||
|
||||
function handleRollupWarning(warning) {
|
||||
console.error('ERROR: ' + warning.toString());
|
||||
}
|
||||
|
||||
function serve() {
|
||||
let server;
|
||||
|
||||
function toExit() {
|
||||
if (server) server.kill(0);
|
||||
}
|
||||
|
||||
return {
|
||||
writeBundle() {
|
||||
if (server) return;
|
||||
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
|
||||
stdio: ['ignore', 'inherit', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
process.on('SIGTERM', toExit);
|
||||
process.on('exit', toExit);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
<div id="logo"></div>
|
||||
<div id="input" data-wails-no-drag>
|
||||
<input id="name" type="text">
|
||||
<button onclick="greet()">Greet</button>
|
||||
</div>
|
||||
<div id="result"></div>
|
||||
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
|
||||
import {ready} from '@wails/runtime';
|
||||
|
||||
ready( () => {
|
||||
// Get input + focus
|
||||
let nameElement = document.getElementById("name");
|
||||
nameElement.focus();
|
||||
|
||||
// Setup the greet function
|
||||
window.greet = function () {
|
||||
|
||||
// Get name
|
||||
let name = nameElement.value;
|
||||
|
||||
// Call App.Greet(name)
|
||||
window.backend.main.App.Greet(name).then((result) => {
|
||||
// Update result with data back from App.Greet()
|
||||
document.getElementById("result").innerText = result;
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
module test
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/wailsapp/wails/v2 v2.0.0-alpha
|
||||
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Create application with options
|
||||
app := NewApp()
|
||||
|
||||
err := wails.Run(&options.App{
|
||||
Title: "{{.ProjectName}}",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
MinWidth: 400,
|
||||
MinHeight: 400,
|
||||
MaxWidth: 1280,
|
||||
MaxHeight: 1024,
|
||||
DisableResize: false,
|
||||
Fullscreen: false,
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
DevTools: false,
|
||||
RGBA: 0x000000FF,
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
DisableWindowIcon: true,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
LogLevel: logger.DEBUG,
|
||||
Startup: app.startup,
|
||||
Shutdown: app.shutdown,
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "{{.ProjectName}}",
|
||||
"outputfilename": "{{.BinaryName}}",
|
||||
"html": "frontend/dist/index.html",
|
||||
"frontend:build": "npm run build",
|
||||
"frontend:install": "npm install",
|
||||
"author": {
|
||||
"name": "{{.AuthorName}}",
|
||||
"email": "{{.AuthorEmail}}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
|
||||
is2 := is.New(t)
|
||||
templates, err := List()
|
||||
is2.NoErr(err)
|
||||
|
||||
println("Found these templates:")
|
||||
for _, template := range templates {
|
||||
fmt.Printf("%+v\n", template)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortname(t *testing.T) {
|
||||
|
||||
is2 := is.New(t)
|
||||
|
||||
template, err := getTemplateByShortname("vanilla")
|
||||
is2.NoErr(err)
|
||||
|
||||
println("Found this template:")
|
||||
fmt.Printf("%+v\n", template)
|
||||
}
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
|
||||
is2 := is.New(t)
|
||||
|
||||
options := &Options{
|
||||
ProjectName: "test",
|
||||
TemplateName: "vanilla",
|
||||
AuthorName: "Lea Anthony",
|
||||
AuthorEmail: "lea.anthony@gmail.com",
|
||||
}
|
||||
|
||||
err := Install(options)
|
||||
is2.NoErr(err)
|
||||
}
|
||||
@@ -1,11 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/colour"
|
||||
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
||||
)
|
||||
|
||||
@@ -14,19 +21,40 @@ func fatal(message string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func banner(_ *clir.Cli) string {
|
||||
return fmt.Sprintf("%s %s", colour.Yellow("Wails CLI"), colour.DarkRed(version))
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
var err error
|
||||
version := "v2.0.0-alpha"
|
||||
|
||||
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
||||
app := clir.NewCli("Wails", "Go/HTML Appkit", version)
|
||||
|
||||
build.AddBuildSubcommand(app)
|
||||
err = initialise.AddSubcommand(app)
|
||||
app.SetBannerFunction(banner)
|
||||
|
||||
build.AddBuildSubcommand(app, os.Stdout)
|
||||
err = initialise.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
err = doctor.AddSubcommand(app)
|
||||
|
||||
err = doctor.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = dev.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = generate.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = update.AddSubcommand(app, os.Stdout, version)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
@@ -34,5 +62,6 @@ func main() {
|
||||
err = app.Run()
|
||||
if err != nil {
|
||||
println("\n\nERROR: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v2.0.0-alpha.54"
|
||||
var version = "v2.0.0-alpha.71"
|
||||
|
||||
43
v2/go.mod
43
v2/go.mod
@@ -1,14 +1,43 @@
|
||||
module github.com/wailsapp/wails/v2
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/leaanthony/clir v1.0.2
|
||||
github.com/leaanthony/gosod v0.0.3
|
||||
github.com/leaanthony/slicer v1.4.1
|
||||
github.com/matryer/is v1.3.0
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/go-git/go-billy/v5 v5.2.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.3.0
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/imdario/mergo v0.3.12
|
||||
github.com/jackmordaunt/icns v1.0.0
|
||||
github.com/klauspost/compress v1.11.3 // indirect
|
||||
github.com/leaanthony/clir v1.0.4
|
||||
github.com/leaanthony/debme v1.2.1
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3
|
||||
github.com/leaanthony/gosod v1.0.1
|
||||
github.com/leaanthony/slicer v1.5.0
|
||||
github.com/leaanthony/webview2runtime v1.1.0
|
||||
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0
|
||||
github.com/matryer/is v1.4.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/tdewolff/minify v2.3.6+incompatible
|
||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||
github.com/tdewolff/test v1.0.6 // indirect
|
||||
github.com/tidwall/sjson v1.1.7
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
nhooyr.io/websocket v1.7.4
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/tools v0.1.0
|
||||
nhooyr.io/websocket v1.8.6
|
||||
)
|
||||
|
||||
239
v2/go.sum
239
v2/go.sum
@@ -1,57 +1,240 @@
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.2.0 h1:GcoouCP9J+5slw2uXAocL70z8ml4A8B/H8nEPt6CLPk=
|
||||
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc=
|
||||
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leaanthony/clir v1.0.2 h1:Ham9Ep7NH95il0x/ci5s2ExJa/K4B2dE8L2uaSj2cxo=
|
||||
github.com/leaanthony/clir v1.0.2/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/gosod v0.0.3 h1:VlPilye0zoH4I0WihShyoiTHyiAN1v6dcBW4mMvGJao=
|
||||
github.com/leaanthony/gosod v0.0.3/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
|
||||
github.com/leaanthony/slicer v1.4.1 h1:X/SmRIDhkUAolP79mSTO0jTcVX1k504PJBqvV6TwP0w=
|
||||
github.com/leaanthony/slicer v1.4.1/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/matryer/is v1.3.0 h1:9qiso3jaJrOe6qBRJRBt2Ldht05qDiFP9le0JOIhRSI=
|
||||
github.com/matryer/is v1.3.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/gosod v1.0.1 h1:F+4c3DmEBfigi7oAswCV2RpQ+k4DcNbhuCZUGdBHacQ=
|
||||
github.com/leaanthony/gosod v1.0.1/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c=
|
||||
github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk=
|
||||
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0 h1:FPGYnfxuuxqCZhrGq8nKjthEcYHgHmFbyY953Xv9cNI=
|
||||
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
|
||||
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
|
||||
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8=
|
||||
github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
||||
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
nhooyr.io/websocket v1.7.4 h1:w/LGB2sZT0RV8lZYR7nfyaYz4PUbYZ5oF7NBon2M0NY=
|
||||
nhooyr.io/websocket v1.7.4/go.mod h1:PxYxCwFdFYQ0yRvtQz3s/dC+VEm7CSuC/4b9t8MQQxw=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
|
||||
7
v2/init.go
Normal file
7
v2/init.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build !windows
|
||||
|
||||
package wails
|
||||
|
||||
func Init() error {
|
||||
return nil
|
||||
}
|
||||
15
v2/init_windows.go
Normal file
15
v2/init_windows.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package wails
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Init is called at the start of the application
|
||||
func Init() error {
|
||||
status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call()
|
||||
if status == 0 {
|
||||
return fmt.Errorf("exit status %d: %v %v", status, r, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build !desktop,!hybrid,!server
|
||||
// +build !desktop,!hybrid,!server,!dev
|
||||
|
||||
package app
|
||||
|
||||
@@ -10,7 +10,9 @@ package app
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
@@ -20,12 +22,15 @@ type App struct {
|
||||
Height int
|
||||
Resizable bool
|
||||
|
||||
Features *features.Features
|
||||
// Indicates if the app is running in debug mode
|
||||
debug bool
|
||||
|
||||
logger *logger.Logger
|
||||
}
|
||||
|
||||
// CreateApp returns a null application
|
||||
func CreateApp(options *Options) *App {
|
||||
return &App{}
|
||||
func CreateApp(_ *options.App) (*App, error) {
|
||||
return &App{}, nil
|
||||
}
|
||||
|
||||
// Run the application
|
||||
@@ -34,8 +39,3 @@ func (a *App) Run() error {
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bind the dummy interface
|
||||
func (a *App) Bind(dummy interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,117 +3,161 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
appType string
|
||||
|
||||
window *ffenestri.Application
|
||||
servicebus *servicebus.ServiceBus
|
||||
logger *logger.Logger
|
||||
signal *signal.Manager
|
||||
options *options.App
|
||||
|
||||
// Subsystems
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
event *subsystem.Event
|
||||
binding *subsystem.Binding
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
event *subsystem.Event
|
||||
//binding *subsystem.Binding
|
||||
call *subsystem.Call
|
||||
menu *subsystem.Menu
|
||||
url *subsystem.URL
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
// Indicates if the app is in debug mode
|
||||
debug bool
|
||||
|
||||
// This is our binding DB
|
||||
bindings *binding.Bindings
|
||||
|
||||
// Feature flags
|
||||
Features *features.Features
|
||||
// Application Stores
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
shutdownCallback func()
|
||||
}
|
||||
|
||||
// Create App
|
||||
func CreateApp(options *Options) *App {
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// Merge default options
|
||||
options.mergeDefaults()
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(os.Stdout)
|
||||
myLogger.SetLogLevel(logger.TRACE)
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{
|
||||
Title: options.Title,
|
||||
Width: options.Width,
|
||||
Height: options.Height,
|
||||
MinWidth: options.MinWidth,
|
||||
MinHeight: options.MinHeight,
|
||||
MaxWidth: options.MaxWidth,
|
||||
MaxHeight: options.MaxHeight,
|
||||
Frameless: options.Frameless,
|
||||
// Create the menu manager
|
||||
menuManager := menumanager.NewManager()
|
||||
|
||||
// This should be controlled by the compile time flags...
|
||||
DevTools: true,
|
||||
// Process the application menu
|
||||
menuManager.SetApplicationMenu(options.GetApplicationMenu(appoptions))
|
||||
|
||||
Resizable: !options.DisableResize,
|
||||
Fullscreen: options.Fullscreen,
|
||||
}, myLogger)
|
||||
|
||||
result := &App{
|
||||
window: window,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
Features: features.New(),
|
||||
// Process context menus
|
||||
contextMenus := options.GetContextMenus(appoptions)
|
||||
for _, contextMenu := range contextMenus {
|
||||
menuManager.AddContextMenu(contextMenu)
|
||||
}
|
||||
|
||||
return result
|
||||
// Process tray menus
|
||||
trayMenus := options.GetTrayMenus(appoptions)
|
||||
for _, trayMenu := range trayMenus {
|
||||
menuManager.AddTrayMenu(trayMenu)
|
||||
}
|
||||
|
||||
window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager)
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown}
|
||||
|
||||
result := &App{
|
||||
appType: "desktop",
|
||||
window: window,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions),
|
||||
menuManager: menuManager,
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
}
|
||||
|
||||
result.options = appoptions
|
||||
|
||||
// Initialise the app
|
||||
err := result.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Preflight Checks
|
||||
err = result.PreflightChecks(appoptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
// Run the application
|
||||
func (a *App) Run() error {
|
||||
|
||||
// Setup signal handler
|
||||
signal, err := signal.NewManager(a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.signal = signal
|
||||
a.signal.Start()
|
||||
var err error
|
||||
|
||||
// Setup a context
|
||||
var subsystemWaitGroup sync.WaitGroup
|
||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||
ctx, cancel := context.WithCancel(parentContext)
|
||||
|
||||
// Start the service bus
|
||||
a.servicebus.Debug()
|
||||
a.servicebus.Start()
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||
err = a.servicebus.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Start the binding subsystem
|
||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
||||
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.binding = binding
|
||||
a.binding.Start()
|
||||
a.runtime = runtimesubsystem
|
||||
err = a.runtime.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Application Stores
|
||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
// Start the logging subsystem
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.log = log
|
||||
a.log.Start()
|
||||
err = a.log.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the dispatcher
|
||||
dispatcher, err := messagedispatcher.New(a.servicebus, a.logger)
|
||||
@@ -121,23 +165,56 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
a.dispatcher = dispatcher
|
||||
dispatcher.Start()
|
||||
err = dispatcher.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.options.Mac.URLHandlers != nil {
|
||||
// Start the url handler subsystem
|
||||
url, err := subsystem.NewURL(a.servicebus, a.logger, a.options.Mac.URLHandlers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.url = url
|
||||
err = a.url.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start the eventing subsystem
|
||||
event, err := subsystem.NewEvent(a.servicebus, a.logger)
|
||||
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.event = eventsubsystem
|
||||
err = a.event.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start the menu subsystem
|
||||
menusubsystem, err := subsystem.NewMenu(ctx, a.servicebus, a.logger, a.menuManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.menu = menusubsystem
|
||||
err = a.menu.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.event = event
|
||||
a.event.Start()
|
||||
|
||||
// Start the call subsystem
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
||||
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.call = callSubsystem
|
||||
err = a.call.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.call = call
|
||||
a.call.Start()
|
||||
|
||||
// Dump bindings as a debug
|
||||
bindingDump, err := a.bindings.ToJSON()
|
||||
@@ -145,20 +222,42 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
||||
a.logger.Trace("Ffenestri.Run() exited")
|
||||
a.servicebus.Stop()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
// Setup signal handler
|
||||
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
return err
|
||||
}
|
||||
a.signal = signalsubsystem
|
||||
a.signal.Start()
|
||||
|
||||
err = a.window.Run(dispatcher, bindingDump, a.debug)
|
||||
a.logger.Trace("Ffenestri.Run() exited")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Close down all the subsystems
|
||||
a.logger.Trace("Cancelling subsystems")
|
||||
cancel()
|
||||
subsystemWaitGroup.Wait()
|
||||
|
||||
a.logger.Trace("Cancelling dispatcher")
|
||||
dispatcher.Close()
|
||||
|
||||
// Close log
|
||||
a.logger.Trace("Stopping log")
|
||||
log.Close()
|
||||
|
||||
a.logger.Trace("Stopping Service bus")
|
||||
err = a.servicebus.Stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Shutdown callback
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ func (a *App) Run() error {
|
||||
var subsystemWaitGroup sync.WaitGroup
|
||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||
ctx, cancel := context.WithCancel(parentContext)
|
||||
defer cancel()
|
||||
|
||||
// Start the service bus
|
||||
a.servicebus.Debug()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
@@ -43,8 +42,7 @@ type App struct {
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
servicebus *servicebus.ServiceBus
|
||||
|
||||
// Feature flags
|
||||
Features *features.Features
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Create App
|
||||
@@ -58,17 +56,15 @@ func CreateApp(options *Options) *App {
|
||||
myLogger.SetLogLevel(logger.INFO)
|
||||
|
||||
window := ffenestri.NewApplicationWithConfig(&ffenestri.Config{
|
||||
Title: options.Title,
|
||||
Width: options.Width,
|
||||
Height: options.Height,
|
||||
MinWidth: options.MinWidth,
|
||||
MinHeight: options.MinHeight,
|
||||
MaxWidth: options.MaxWidth,
|
||||
MaxHeight: options.MaxHeight,
|
||||
Frameless: options.Frameless,
|
||||
|
||||
// This should be controlled by the compile time flags...
|
||||
DevTools: true,
|
||||
Title: options.Title,
|
||||
Width: options.Width,
|
||||
Height: options.Height,
|
||||
MinWidth: options.MinWidth,
|
||||
MinHeight: options.MinHeight,
|
||||
MaxWidth: options.MaxWidth,
|
||||
MaxHeight: options.MaxHeight,
|
||||
StartHidden: options.StartHidden,
|
||||
DevTools: options.DevTools,
|
||||
|
||||
Resizable: !options.DisableResize,
|
||||
Fullscreen: options.Fullscreen,
|
||||
@@ -79,9 +75,12 @@ func CreateApp(options *Options) *App {
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
bindings: binding.NewBindings(myLogger, options.Bind),
|
||||
}
|
||||
|
||||
// Initialise the app
|
||||
app.Init()
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
@@ -185,7 +184,7 @@ func (a *App) Run() error {
|
||||
}
|
||||
}()
|
||||
|
||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
||||
result := a.window.Run(dispatcher, bindingDump)
|
||||
a.servicebus.Stop()
|
||||
|
||||
return result
|
||||
@@ -193,14 +192,3 @@ func (a *App) Run() error {
|
||||
|
||||
return cli.Run()
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package app
|
||||
|
||||
// Options for creating the App
|
||||
type Options struct {
|
||||
Title string
|
||||
Width int
|
||||
Height int
|
||||
DisableResize bool
|
||||
Fullscreen bool
|
||||
Frameless bool
|
||||
MinWidth int
|
||||
MinHeight int
|
||||
MaxWidth int
|
||||
MaxHeight int
|
||||
}
|
||||
|
||||
// mergeDefaults will set the minimum default values for an application
|
||||
func (o *Options) mergeDefaults() {
|
||||
|
||||
// Create a default title
|
||||
if len(o.Title) == 0 {
|
||||
o.Title = "My Wails App"
|
||||
}
|
||||
|
||||
// Default width
|
||||
if o.Width == 0 {
|
||||
o.Width = 1024
|
||||
}
|
||||
|
||||
// Default height
|
||||
if o.Height == 0 {
|
||||
o.Height = 768
|
||||
}
|
||||
}
|
||||
9
v2/internal/app/preflight_default.go
Normal file
9
v2/internal/app/preflight_default.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//+build !windows
|
||||
|
||||
package app
|
||||
|
||||
import "github.com/wailsapp/wails/v2/pkg/options"
|
||||
|
||||
func (a *App) PreflightChecks(options *options.App) error {
|
||||
return nil
|
||||
}
|
||||
19
v2/internal/app/preflight_windows.go
Normal file
19
v2/internal/app/preflight_windows.go
Normal file
@@ -0,0 +1,19 @@
|
||||
//+build windows
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri/windows/wv2runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func (a *App) PreflightChecks(options *options.App) error {
|
||||
|
||||
// Process the webview2 runtime situation. We can pass a strategy in via the `webview2` flag for `wails build`.
|
||||
// This will determine how wv2runtime.Process will handle a lack of valid runtime.
|
||||
err := wv2runtime.Process()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -6,10 +6,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
"github.com/wailsapp/wails/v2/internal/webserver"
|
||||
@@ -17,36 +20,57 @@ import (
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
appType string
|
||||
|
||||
binding *subsystem.Binding
|
||||
call *subsystem.Call
|
||||
event *subsystem.Event
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
|
||||
options *options.App
|
||||
|
||||
bindings *binding.Bindings
|
||||
logger *logger.Logger
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
servicebus *servicebus.ServiceBus
|
||||
webserver *webserver.WebServer
|
||||
|
||||
debug bool
|
||||
|
||||
// Application Stores
|
||||
loglevelStore *runtime.Store
|
||||
appconfigStore *runtime.Store
|
||||
|
||||
// Startup/Shutdown
|
||||
startupCallback func(*runtime.Runtime)
|
||||
shutdownCallback func()
|
||||
}
|
||||
|
||||
// Create App
|
||||
func CreateApp(options *Options) *App {
|
||||
options.mergeDefaults()
|
||||
// We ignore the inputs (for now)
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// TODO: Allow logger output override on CLI
|
||||
myLogger := logger.New(os.Stdout)
|
||||
myLogger.SetLogLevel(logger.TRACE)
|
||||
// Merge default options
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
result := &App{
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
appType: "server",
|
||||
bindings: binding.NewBindings(myLogger, options.Bind),
|
||||
logger: myLogger,
|
||||
servicebus: servicebus.New(myLogger),
|
||||
webserver: webserver.NewWebServer(myLogger),
|
||||
startupCallback: appoptions.Startup,
|
||||
shutdownCallback: appoptions.Shutdown,
|
||||
}
|
||||
|
||||
return result
|
||||
// Initialise app
|
||||
result.Init()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Run the application
|
||||
@@ -55,7 +79,7 @@ func (a *App) Run() error {
|
||||
// Default app options
|
||||
var port = 8080
|
||||
var ip = "localhost"
|
||||
var supressLogging = false
|
||||
var SuppressLogging = false
|
||||
var debugMode = false
|
||||
|
||||
// Create CLI
|
||||
@@ -65,7 +89,7 @@ func (a *App) Run() error {
|
||||
cli.IntFlag("p", "Port to serve on", &port)
|
||||
cli.StringFlag("i", "IP to serve on", &ip)
|
||||
cli.BoolFlag("d", "Debug mode", &debugMode)
|
||||
cli.BoolFlag("q", "Supress logging", &supressLogging)
|
||||
cli.BoolFlag("q", "Suppress logging", &SuppressLogging)
|
||||
|
||||
// Setup main action
|
||||
cli.Action(func() error {
|
||||
@@ -74,8 +98,8 @@ func (a *App) Run() error {
|
||||
a.webserver.SetPort(port)
|
||||
a.webserver.SetIP(ip)
|
||||
a.webserver.SetBindings(a.bindings)
|
||||
// Log information (if we aren't supressing it)
|
||||
if !supressLogging {
|
||||
// Log information (if we aren't Suppressing it)
|
||||
if !SuppressLogging {
|
||||
cli.PrintBanner()
|
||||
a.logger.Info("Running server at %s", a.webserver.URL())
|
||||
}
|
||||
@@ -83,8 +107,21 @@ func (a *App) Run() error {
|
||||
if debugMode {
|
||||
a.servicebus.Debug()
|
||||
}
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Application Stores
|
||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
a.servicebus.Start()
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger)
|
||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -97,14 +134,6 @@ func (a *App) Run() error {
|
||||
a.dispatcher = dispatcher
|
||||
a.dispatcher.Start()
|
||||
|
||||
// Start the runtime
|
||||
runtime, err := subsystem.NewRuntime(a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = runtime
|
||||
a.runtime.Start()
|
||||
|
||||
// Start the binding subsystem
|
||||
binding, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, runtime.GoRuntime())
|
||||
if err != nil {
|
||||
@@ -122,7 +151,7 @@ func (a *App) Run() error {
|
||||
a.event.Start()
|
||||
|
||||
// Start the call subsystem
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB())
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -142,14 +171,3 @@ func (a *App) Run() error {
|
||||
|
||||
return cli.Run()
|
||||
}
|
||||
|
||||
// Bind a struct to the application by passing in
|
||||
// a pointer to it
|
||||
func (a *App) Bind(structPtr interface{}) {
|
||||
|
||||
// Add the struct to the bindings
|
||||
err := a.bindings.Add(structPtr)
|
||||
if err != nil {
|
||||
a.logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,30 +2,55 @@ package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
type Bindings struct {
|
||||
db *DB
|
||||
logger logger.CustomLogger
|
||||
db *DB
|
||||
logger logger.CustomLogger
|
||||
exemptions slicer.StringSlicer
|
||||
}
|
||||
|
||||
// NewBindings returns a new Bindings object
|
||||
func NewBindings(logger *logger.Logger) *Bindings {
|
||||
return &Bindings{
|
||||
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}) *Bindings {
|
||||
result := &Bindings{
|
||||
db: newDB(),
|
||||
logger: logger.CustomLogger("Bindings"),
|
||||
}
|
||||
|
||||
for _, exemption := range exemptions {
|
||||
if exemptions == nil {
|
||||
continue
|
||||
}
|
||||
name := runtime.FuncForPC(reflect.ValueOf(exemption).Pointer()).Name()
|
||||
// Yuk yuk yuk! Is there a better way?
|
||||
name = strings.TrimSuffix(name, "-fm")
|
||||
result.exemptions.Add(name)
|
||||
}
|
||||
|
||||
// Add the structs to bind
|
||||
for _, ptr := range structPointersToBind {
|
||||
err := result.Add(ptr)
|
||||
if err != nil {
|
||||
logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Add the given struct methods to the Bindings
|
||||
func (b *Bindings) Add(structPtr interface{}) error {
|
||||
|
||||
methods, err := getMethods(structPtr)
|
||||
methods, err := b.getMethods(structPtr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to Add() - %s", err.Error())
|
||||
return fmt.Errorf("cannot bind value to app: %s", err.Error())
|
||||
}
|
||||
|
||||
for _, method := range methods {
|
||||
@@ -34,29 +59,8 @@ func (b *Bindings) Add(structPtr interface{}) error {
|
||||
structName := splitName[1]
|
||||
methodName := splitName[2]
|
||||
|
||||
// Is this WailsInit?
|
||||
if method.IsWailsInit() {
|
||||
err := b.db.AddWailsInit(method)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.logger.Trace("Registered WailsInit method: %s", method.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Is this WailsShutdown?
|
||||
if method.IsWailsShutdown() {
|
||||
err := b.db.AddWailsShutdown(method)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.logger.Trace("Registered WailsShutdown method: %s", method.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Add it as a regular method
|
||||
b.db.AddMethod(packageName, structName, methodName, method)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BoundMethod defines all the data related to a Go method that is
|
||||
@@ -16,58 +16,6 @@ type BoundMethod struct {
|
||||
Method reflect.Value `json:"-"`
|
||||
}
|
||||
|
||||
// IsWailsInit returns true if the method name is "WailsInit"
|
||||
func (b *BoundMethod) IsWailsInit() bool {
|
||||
return strings.HasSuffix(b.Name, "WailsInit")
|
||||
}
|
||||
|
||||
// IsWailsShutdown returns true if the method name is "WailsShutdown"
|
||||
func (b *BoundMethod) IsWailsShutdown() bool {
|
||||
return strings.HasSuffix(b.Name, "WailsShutdown")
|
||||
}
|
||||
|
||||
// VerifyWailsInit checks if the WailsInit signature is correct
|
||||
func (b *BoundMethod) VerifyWailsInit() error {
|
||||
// Must only have 1 input
|
||||
if b.InputCount() != 1 {
|
||||
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||
}
|
||||
|
||||
// Check input type
|
||||
if !b.Inputs[0].IsType("*goruntime.Runtime") {
|
||||
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||
}
|
||||
|
||||
// Must only have 1 output
|
||||
if b.OutputCount() != 1 {
|
||||
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||
}
|
||||
|
||||
// Check output type
|
||||
if !b.Outputs[0].IsError() {
|
||||
return fmt.Errorf("invalid method signature for %s: expected `WailsInit(*wails.Runtime) error`", b.Name)
|
||||
}
|
||||
|
||||
// Input must be of type Runtime
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyWailsShutdown checks if the WailsShutdown signature is correct
|
||||
func (b *BoundMethod) VerifyWailsShutdown() error {
|
||||
// Must have no inputs
|
||||
if b.InputCount() != 0 {
|
||||
return fmt.Errorf("invalid method signature for WailsShutdown: expected `WailsShutdown()`")
|
||||
}
|
||||
|
||||
// Must have no outputs
|
||||
if b.OutputCount() != 0 {
|
||||
return fmt.Errorf("invalid method signature for WailsShutdown: expected `WailsShutdown()`")
|
||||
}
|
||||
|
||||
// Input must be of type Runtime
|
||||
return nil
|
||||
}
|
||||
|
||||
// InputCount returns the number of inputs this bound method has
|
||||
func (b *BoundMethod) InputCount() int {
|
||||
return len(b.Inputs)
|
||||
@@ -78,6 +26,29 @@ func (b *BoundMethod) OutputCount() int {
|
||||
return len(b.Outputs)
|
||||
}
|
||||
|
||||
// ParseArgs method converts the input json into the types expected by the method
|
||||
func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) {
|
||||
|
||||
result := make([]interface{}, b.InputCount())
|
||||
if len(args) != b.InputCount() {
|
||||
return nil, fmt.Errorf("received %d arguments to method '%s', expected %d", len(args), b.Name, b.InputCount())
|
||||
}
|
||||
for index, arg := range args {
|
||||
typ := b.Inputs[index].reflectType
|
||||
inputValue := reflect.New(typ).Interface()
|
||||
err := json.Unmarshal(arg, inputValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if inputValue == nil {
|
||||
result[index] = reflect.Zero(typ).Interface()
|
||||
} else {
|
||||
result[index] = reflect.ValueOf(inputValue).Elem().Interface()
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Call will attempt to call this bound method with the given args
|
||||
func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
||||
// Check inputs
|
||||
@@ -94,17 +65,8 @@ func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
|
||||
|
||||
// Iterate over given arguments
|
||||
for index, arg := range args {
|
||||
|
||||
// Attempt to convert the argument to the type expected by the method
|
||||
value, err := convertArgToValue(arg, b.Inputs[index])
|
||||
|
||||
// If it fails, return a suitable error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s (parameter %d): %s", b.Name, index+1, err.Error())
|
||||
}
|
||||
|
||||
// Save the converted argument
|
||||
callArgs[index] = value
|
||||
callArgs[index] = reflect.ValueOf(arg)
|
||||
}
|
||||
|
||||
// Do the call
|
||||
|
||||
@@ -15,10 +15,6 @@ type DB struct {
|
||||
// It used for performance gains at runtime
|
||||
methodMap map[string]*BoundMethod
|
||||
|
||||
// These are slices of methods registered using WailsInit and WailsShutdown
|
||||
wailsInitMethods []*BoundMethod
|
||||
wailsShutdownMethods []*BoundMethod
|
||||
|
||||
// Lock to ensure sync access to the data
|
||||
lock sync.RWMutex
|
||||
}
|
||||
@@ -94,38 +90,6 @@ func (d *DB) AddMethod(packageName string, structName string, methodName string,
|
||||
|
||||
}
|
||||
|
||||
// AddWailsInit checks the given method is a WailsInit method and if it
|
||||
// is, adds it to the list of WailsInit methods
|
||||
func (d *DB) AddWailsInit(method *BoundMethod) error {
|
||||
err := method.VerifyWailsInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Lock the db whilst processing and unlock on return
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
|
||||
d.wailsInitMethods = append(d.wailsInitMethods, method)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddWailsShutdown checks the given method is a WailsInit method and if it
|
||||
// is, adds it to the list of WailsShutdown methods
|
||||
func (d *DB) AddWailsShutdown(method *BoundMethod) error {
|
||||
err := method.VerifyWailsShutdown()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Lock the db whilst processing and unlock on return
|
||||
d.lock.Lock()
|
||||
defer d.lock.Unlock()
|
||||
|
||||
d.wailsShutdownMethods = append(d.wailsShutdownMethods, method)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToJSON converts the method map to JSON
|
||||
func (d *DB) ToJSON() (string, error) {
|
||||
|
||||
@@ -138,13 +102,3 @@ func (d *DB) ToJSON() (string, error) {
|
||||
// Return zero copy string as this string will be read only
|
||||
return *(*string)(unsafe.Pointer(&bytes)), err
|
||||
}
|
||||
|
||||
// WailsInitMethods returns the list of registered WailsInit methods
|
||||
func (d *DB) WailsInitMethods() []*BoundMethod {
|
||||
return d.wailsInitMethods
|
||||
}
|
||||
|
||||
// WailsShutdownMethods returns the list of registered WailsInit methods
|
||||
func (d *DB) WailsShutdownMethods() []*BoundMethod {
|
||||
return d.wailsShutdownMethods
|
||||
}
|
||||
|
||||
@@ -14,30 +14,6 @@ import (
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
const _comment = `
|
||||
|
||||
const backend = {
|
||||
main: {
|
||||
"xbarApp": {
|
||||
"GetCategories": () => {
|
||||
window.backend.main.xbarApp.GetCategories.call(arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} arg1
|
||||
*/
|
||||
"InstallPlugin": (arg1) => {
|
||||
window.backend.main.xbarApp.InstallPlugin.call(arguments);
|
||||
},
|
||||
"GetPlugins": () => {
|
||||
window.backend.main.xbarApp.GetPlugins.call(arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default backend;`
|
||||
|
||||
//go:embed assets/package.json
|
||||
var packageJSON []byte
|
||||
|
||||
@@ -100,6 +76,8 @@ const backend = {`)
|
||||
}
|
||||
returnType += ">"
|
||||
returnTypeDetails = " - Go Type: " + methodDetails.Outputs[0].TypeName
|
||||
} else {
|
||||
returnType = "Promise<void>"
|
||||
}
|
||||
output.WriteString(" * @returns {" + returnType + "} " + returnTypeDetails + "\n")
|
||||
output.WriteString(" */\n")
|
||||
@@ -125,13 +103,14 @@ const backend = {`)
|
||||
export default backend;`)
|
||||
output.WriteString("\n")
|
||||
|
||||
// TODO: Make this configurable in wails.json
|
||||
dirname, err := fs.RelativeToCwd("frontend/src/backend")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !fs.DirExists(dirname) {
|
||||
err := fs.Mkdir(dirname)
|
||||
err := fs.MkDirs(dirname)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -165,6 +144,8 @@ func goTypeToJSDocType(input string) string {
|
||||
return "number"
|
||||
case input == "bool":
|
||||
return "boolean"
|
||||
case input == "[]byte":
|
||||
return "string"
|
||||
case strings.HasPrefix(input, "[]"):
|
||||
arrayType := goTypeToJSDocType(input[2:])
|
||||
return "Array.<" + arrayType + ">"
|
||||
|
||||
87
v2/internal/binding/generate_test.go
Normal file
87
v2/internal/binding/generate_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_goTypeToJSDocType(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "string",
|
||||
input: "string",
|
||||
want: "string",
|
||||
},
|
||||
{
|
||||
name: "error",
|
||||
input: "error",
|
||||
want: "Error",
|
||||
},
|
||||
{
|
||||
name: "int",
|
||||
input: "int",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "int32",
|
||||
input: "int32",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "uint",
|
||||
input: "uint",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "uint32",
|
||||
input: "uint32",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "float32",
|
||||
input: "float32",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "float64",
|
||||
input: "float64",
|
||||
want: "number",
|
||||
},
|
||||
{
|
||||
name: "bool",
|
||||
input: "bool",
|
||||
want: "boolean",
|
||||
},
|
||||
{
|
||||
name: "[]byte",
|
||||
input: "[]byte",
|
||||
want: "string",
|
||||
},
|
||||
{
|
||||
name: "[]int",
|
||||
input: "[]int",
|
||||
want: "Array.<number>",
|
||||
},
|
||||
{
|
||||
name: "[]bool",
|
||||
input: "[]bool",
|
||||
want: "Array.<boolean>",
|
||||
},
|
||||
{
|
||||
name: "anything else",
|
||||
input: "foo",
|
||||
want: "any",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := goTypeToJSDocType(tt.input); got != tt.want {
|
||||
t.Errorf("goTypeToJSDocType() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package binding
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// isStructPtr returns true if the value given is a
|
||||
@@ -12,14 +13,35 @@ func isStructPtr(value interface{}) bool {
|
||||
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
// isFunction returns true if the given value is a function
|
||||
func isFunction(value interface{}) bool {
|
||||
return reflect.ValueOf(value).Kind() == reflect.Func
|
||||
}
|
||||
|
||||
// isStructPtr returns true if the value given is a struct
|
||||
func isStruct(value interface{}) bool {
|
||||
return reflect.ValueOf(value).Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
|
||||
// Create result placeholder
|
||||
var result []*BoundMethod
|
||||
|
||||
// Check type
|
||||
if !isStructPtr(value) {
|
||||
return nil, fmt.Errorf("not a pointer to an interface")
|
||||
|
||||
if isStruct(value) {
|
||||
name := reflect.ValueOf(value).Type().Name()
|
||||
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
|
||||
}
|
||||
|
||||
if isFunction(value) {
|
||||
name := runtime.FuncForPC(reflect.ValueOf(value).Pointer()).Name()
|
||||
return nil, fmt.Errorf("%s is a function, not a pointer to a struct. Wails v2 has deprecated the binding of functions. Please wrap your functions up in a struct and bind a pointer to that struct.", name)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("not a pointer to a struct.")
|
||||
}
|
||||
|
||||
// Process Struct
|
||||
@@ -34,6 +56,11 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
fullMethodName := baseName + "." + methodName
|
||||
method := structValue.MethodByName(methodName)
|
||||
|
||||
methodReflectName := runtime.FuncForPC(methodDef.Func.Pointer()).Name()
|
||||
if b.exemptions.Contains(methodReflectName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Create new method
|
||||
boundMethod := &BoundMethod{
|
||||
Name: fullMethodName,
|
||||
@@ -56,6 +83,8 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
boundMethod.Inputs = inputs
|
||||
|
||||
// Iterate outputs
|
||||
// TODO: Determine what to do about limiting return types
|
||||
// especially around errors.
|
||||
outputParamCount := methodType.NumOut()
|
||||
var outputs []*Parameter
|
||||
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
||||
@@ -71,39 +100,3 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// convertArgToValue
|
||||
func convertArgToValue(input interface{}, target *Parameter) (result reflect.Value, err error) {
|
||||
|
||||
// Catch type conversion panics thrown by convert
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// Modify error
|
||||
err = fmt.Errorf("%s", r.(string)[23:])
|
||||
}
|
||||
}()
|
||||
|
||||
// Do the conversion
|
||||
|
||||
// Handle nil values
|
||||
if input == nil {
|
||||
switch target.reflectType.Kind() {
|
||||
case reflect.Chan,
|
||||
reflect.Func,
|
||||
reflect.Interface,
|
||||
reflect.Map,
|
||||
reflect.Ptr,
|
||||
reflect.Slice:
|
||||
result = reflect.ValueOf(input).Convert(target.reflectType)
|
||||
default:
|
||||
return reflect.Zero(target.reflectType), fmt.Errorf("Unable to use null value")
|
||||
}
|
||||
} else {
|
||||
result = reflect.ValueOf(input).Convert(target.reflectType)
|
||||
}
|
||||
|
||||
// We don't like doing this but it's the only way to
|
||||
// handle recover() correctly
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
@@ -26,16 +26,23 @@ func (b BridgeClient) Quit() {
|
||||
}
|
||||
|
||||
func (b BridgeClient) NotifyEvent(message string) {
|
||||
//b.session.sendMessage("n" + message)
|
||||
b.session.sendMessage("n" + message)
|
||||
b.session.log.Info("NotifyEvent: %s", message)
|
||||
b.session.log.Info("NotifyEvent unsupported in Bridge mode")
|
||||
}
|
||||
|
||||
func (b BridgeClient) CallResult(message string) {
|
||||
b.session.sendMessage("c" + message)
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (b BridgeClient) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -37,7 +37,11 @@ func (d *DialogClient) NotifyEvent(message string) {
|
||||
func (d *DialogClient) CallResult(message string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
func (d *DialogClient) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
}
|
||||
func (d *DialogClient) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
}
|
||||
func (d *DialogClient) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
|
||||
1
v2/internal/bridge/linux.js
Normal file
1
v2/internal/bridge/linux.js
Normal file
File diff suppressed because one or more lines are too long
@@ -18,6 +18,12 @@ import (
|
||||
//go:embed darwin.js
|
||||
var darwinRuntime string
|
||||
|
||||
//go:embed windows.js
|
||||
var windowsRuntime string
|
||||
|
||||
//go:embed linux.js
|
||||
var linuxRuntime string
|
||||
|
||||
// session represents a single websocket session
|
||||
type session struct {
|
||||
bindings string
|
||||
@@ -84,6 +90,10 @@ func (s *session) start(firstSession bool) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
wailsRuntime = darwinRuntime
|
||||
case "windows":
|
||||
wailsRuntime = windowsRuntime
|
||||
case "linux":
|
||||
wailsRuntime = linuxRuntime
|
||||
default:
|
||||
log.Fatal("platform not supported")
|
||||
}
|
||||
@@ -92,7 +102,10 @@ func (s *session) start(firstSession bool) {
|
||||
s.log.Info(bindingsMessage)
|
||||
bootstrapMessage := bindingsMessage + wailsRuntime
|
||||
|
||||
s.sendMessage("b" + bootstrapMessage)
|
||||
err := s.sendMessage("b" + bootstrapMessage)
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
|
||||
// Send menus
|
||||
traymenus, err := s.menumanager.GetTrayMenus()
|
||||
@@ -101,7 +114,10 @@ func (s *session) start(firstSession bool) {
|
||||
}
|
||||
|
||||
for _, trayMenu := range traymenus {
|
||||
s.sendMessage("TS" + trayMenu)
|
||||
err := s.sendMessage("TS" + trayMenu)
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
@@ -130,7 +146,10 @@ func (s *session) start(firstSession bool) {
|
||||
|
||||
// Shutdown
|
||||
func (s *session) Shutdown() {
|
||||
s.conn.Close()
|
||||
err := s.conn.Close()
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
s.done = true
|
||||
s.log.Info("session %v exit", s.Identifier())
|
||||
}
|
||||
@@ -146,10 +165,16 @@ func (s *session) writePump() {
|
||||
s.Shutdown()
|
||||
return
|
||||
case msg, ok := <-s.writeChan:
|
||||
s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
|
||||
err := s.conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
if !ok {
|
||||
s.log.Debug("writeChan was closed!")
|
||||
s.conn.WriteMessage(websocket.CloseMessage, []byte{})
|
||||
err := s.conn.WriteMessage(websocket.CloseMessage, []byte{})
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
1
v2/internal/bridge/windows.js
Normal file
1
v2/internal/bridge/windows.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,13 +0,0 @@
|
||||
package features
|
||||
|
||||
// Features holds generic and platform specific feature flags
|
||||
type Features struct {
|
||||
Linux *Linux
|
||||
}
|
||||
|
||||
// New creates a new Features object
|
||||
func New() *Features {
|
||||
return &Features{
|
||||
Linux: &Linux{},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package features
|
||||
|
||||
// Linux holds linux specific feature flags
|
||||
type Linux struct {
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
# 3rd Party Licenses
|
||||
|
||||
## Webview
|
||||
Whilst not using the library directly, there is certainly some code that is inspired by or used from the webview library.
|
||||
|
||||
Homepage: https://github.com/webview/webview
|
||||
License: https://github.com/webview/webview/blob/master/LICENSE
|
||||
|
||||
## vec
|
||||
Homepage: https://github.com/rxi/vec
|
||||
License: https://github.com/rxi/vec/blob/master/LICENSE
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
|
||||
//
|
||||
// Created by Lea Anthony on 6/1/21.
|
||||
//
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "string.h"
|
||||
|
||||
@@ -82,10 +82,10 @@ void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *context
|
||||
FREE_AND_SET(contextMenu->contextMenuData, contextMenuData);
|
||||
|
||||
// Grab the content view and show the menu
|
||||
id contentView = msg(mainWindow, s("contentView"));
|
||||
id contentView = msg_reg(mainWindow, s("contentView"));
|
||||
|
||||
// Get the triggering event
|
||||
id menuEvent = msg(mainWindow, s("currentEvent"));
|
||||
id menuEvent = msg_reg(mainWindow, s("currentEvent"));
|
||||
|
||||
if( contextMenu->nsmenu == NULL ) {
|
||||
// GetMenu creates the NSMenu
|
||||
@@ -93,7 +93,7 @@ void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *context
|
||||
}
|
||||
|
||||
// Show popup
|
||||
msg(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu->nsmenu, menuEvent, contentView);
|
||||
((id(*)(id, SEL, id, id, id))objc_msgSend)(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu->nsmenu, menuEvent, contentView);
|
||||
|
||||
}
|
||||
|
||||
|
||||
64
v2/internal/ffenestri/effectstructs_windows.h
Normal file
64
v2/internal/ffenestri/effectstructs_windows.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// Credit: https://gist.github.com/ysc3839/b08d2bff1c7dacde529bed1d37e85ccf
|
||||
#pragma once
|
||||
|
||||
typedef enum _WINDOWCOMPOSITIONATTRIB
|
||||
{
|
||||
WCA_UNDEFINED = 0,
|
||||
WCA_NCRENDERING_ENABLED = 1,
|
||||
WCA_NCRENDERING_POLICY = 2,
|
||||
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
||||
WCA_ALLOW_NCPAINT = 4,
|
||||
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
||||
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
||||
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
||||
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
||||
WCA_HAS_ICONIC_BITMAP = 9,
|
||||
WCA_THEME_ATTRIBUTES = 10,
|
||||
WCA_NCRENDERING_EXILED = 11,
|
||||
WCA_NCADORNMENTINFO = 12,
|
||||
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
||||
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
||||
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
||||
WCA_DISALLOW_PEEK = 16,
|
||||
WCA_CLOAK = 17,
|
||||
WCA_CLOAKED = 18,
|
||||
WCA_ACCENT_POLICY = 19,
|
||||
WCA_FREEZE_REPRESENTATION = 20,
|
||||
WCA_EVER_UNCLOAKED = 21,
|
||||
WCA_VISUAL_OWNER = 22,
|
||||
WCA_HOLOGRAPHIC = 23,
|
||||
WCA_EXCLUDED_FROM_DDA = 24,
|
||||
WCA_PASSIVEUPDATEMODE = 25,
|
||||
WCA_USEDARKMODECOLORS = 26,
|
||||
WCA_LAST = 27
|
||||
} WINDOWCOMPOSITIONATTRIB;
|
||||
|
||||
typedef struct _WINDOWCOMPOSITIONATTRIBDATA
|
||||
{
|
||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||
PVOID pvData;
|
||||
SIZE_T cbData;
|
||||
} WINDOWCOMPOSITIONATTRIBDATA;
|
||||
|
||||
typedef enum _ACCENT_STATE
|
||||
{
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_GRADIENT = 1,
|
||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
|
||||
ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
|
||||
ACCENT_INVALID_STATE = 6
|
||||
} ACCENT_STATE;
|
||||
|
||||
typedef struct _ACCENT_POLICY
|
||||
{
|
||||
ACCENT_STATE AccentState;
|
||||
DWORD AccentFlags;
|
||||
DWORD GradientColor;
|
||||
DWORD AnimationId;
|
||||
} ACCENT_POLICY;
|
||||
|
||||
typedef BOOL (WINAPI *pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
|
||||
typedef BOOL (WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
@@ -1,23 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package ffenestri
|
||||
|
||||
/*
|
||||
|
||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ffenestri.h"
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "github.com/wailsapp/wails/v2/internal/features"
|
||||
|
||||
func (a *Application) processOSFeatureFlags(features *features.Features) {
|
||||
|
||||
// Process Linux features
|
||||
// linux := features.Linux
|
||||
|
||||
}
|
||||
@@ -5,59 +5,38 @@ import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||
|
||||
#cgo windows CXXFLAGS: -std=c++11
|
||||
#cgo windows,amd64 LDFLAGS: -L./windows/x64 -lWebView2Loader -lgdi32 -lole32 -lShlwapi -luser32 -loleaut32 -ldwmapi
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ffenestri.h"
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// DEBUG is the global Ffenestri debug flag.
|
||||
// TODO: move to compile time.
|
||||
var DEBUG bool = true
|
||||
|
||||
// Config defines how our application should be configured
|
||||
type Config struct {
|
||||
Title string
|
||||
Width int
|
||||
Height int
|
||||
MinWidth int
|
||||
MinHeight int
|
||||
MaxWidth int
|
||||
MaxHeight int
|
||||
DevTools bool
|
||||
Resizable bool
|
||||
Fullscreen bool
|
||||
Frameless bool
|
||||
}
|
||||
|
||||
var defaultConfig = &Config{
|
||||
Title: "My Wails App",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
DevTools: true,
|
||||
Resizable: true,
|
||||
Fullscreen: false,
|
||||
Frameless: false,
|
||||
}
|
||||
|
||||
// Application is our main application object
|
||||
type Application struct {
|
||||
config *Config
|
||||
config *options.App
|
||||
memory []unsafe.Pointer
|
||||
|
||||
// This is the main app pointer
|
||||
app unsafe.Pointer
|
||||
app *C.struct_Application
|
||||
|
||||
// Manages menus
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
// Logger
|
||||
logger logger.CustomLogger
|
||||
@@ -78,18 +57,11 @@ func init() {
|
||||
}
|
||||
|
||||
// NewApplicationWithConfig creates a new application based on the given config
|
||||
func NewApplicationWithConfig(config *Config, logger *logger.Logger) *Application {
|
||||
func NewApplicationWithConfig(config *options.App, logger *logger.Logger, menuManager *menumanager.Manager) *Application {
|
||||
return &Application{
|
||||
config: config,
|
||||
logger: logger.CustomLogger("Ffenestri"),
|
||||
}
|
||||
}
|
||||
|
||||
// NewApplication creates a new Application with the default config
|
||||
func NewApplication(logger *logger.Logger) *Application {
|
||||
return &Application{
|
||||
config: defaultConfig,
|
||||
logger: logger.CustomLogger("Ffenestri"),
|
||||
config: config,
|
||||
logger: logger.CustomLogger("Ffenestri"),
|
||||
menuManager: menuManager,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,18 +93,29 @@ type DispatchClient interface {
|
||||
SendMessage(string)
|
||||
}
|
||||
|
||||
func intToColour(colour int) (C.int, C.int, C.int, C.int) {
|
||||
var alpha = C.int(colour & 0xFF)
|
||||
var blue = C.int((colour >> 8) & 0xFF)
|
||||
var green = C.int((colour >> 16) & 0xFF)
|
||||
var red = C.int((colour >> 24) & 0xFF)
|
||||
return red, green, blue, alpha
|
||||
}
|
||||
|
||||
// Run the application
|
||||
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, features *features.Features) error {
|
||||
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug bool) error {
|
||||
title := a.string2CString(a.config.Title)
|
||||
width := C.int(a.config.Width)
|
||||
height := C.int(a.config.Height)
|
||||
resizable := a.bool2Cint(a.config.Resizable)
|
||||
resizable := a.bool2Cint(!a.config.DisableResize)
|
||||
devtools := a.bool2Cint(a.config.DevTools)
|
||||
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
||||
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen)
|
||||
startHidden := a.bool2Cint(a.config.StartHidden)
|
||||
logLevel := C.int(a.config.LogLevel)
|
||||
hideWindowOnClose := a.bool2Cint(a.config.HideWindowOnClose)
|
||||
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel, hideWindowOnClose)
|
||||
|
||||
// Save app reference
|
||||
a.app = unsafe.Pointer(app)
|
||||
a.app = (*C.struct_Application)(app)
|
||||
|
||||
// Set Min Window Size
|
||||
minWidth := C.int(a.config.MinWidth)
|
||||
@@ -145,26 +128,33 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
||||
C.SetMaxWindowSize(a.app, maxWidth, maxHeight)
|
||||
|
||||
// Set debug if needed
|
||||
C.SetDebug(app, a.bool2Cint(DEBUG))
|
||||
C.SetDebug(app, a.bool2Cint(debug))
|
||||
|
||||
// Set Frameless
|
||||
if a.config.Frameless {
|
||||
C.DisableFrame(a.app)
|
||||
}
|
||||
|
||||
if a.config.RGBA != 0 {
|
||||
r, g, b, alpha := intToColour(a.config.RGBA)
|
||||
C.SetColour(a.app, r, g, b, alpha)
|
||||
}
|
||||
|
||||
// Escape bindings so C doesn't freak out
|
||||
bindings = strings.ReplaceAll(bindings, `"`, `\"`)
|
||||
|
||||
// Set bindings
|
||||
C.SetBindings(app, a.string2CString(bindings))
|
||||
|
||||
// Process feature flags
|
||||
a.processFeatureFlags(features)
|
||||
|
||||
// save the dispatcher in a package variable so that the C callbacks
|
||||
// can access it
|
||||
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
||||
|
||||
// Process platform settings
|
||||
err := a.processPlatformSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check we could initialise the application
|
||||
if app != nil {
|
||||
// Yes - Save memory reference and run app, cleaning up afterwards
|
||||
@@ -174,7 +164,7 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
||||
// Oh no! We couldn't initialise the application
|
||||
a.logger.Fatal("Cannot initialise Application.")
|
||||
}
|
||||
|
||||
//println("\n\n\n\n\n\nhererererer\n\n\n\n")
|
||||
a.freeMemory()
|
||||
return nil
|
||||
}
|
||||
@@ -186,11 +176,3 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
||||
func messageFromWindowCallback(data *C.char) {
|
||||
dispatcher.DispatchMessage(C.GoString(data))
|
||||
}
|
||||
|
||||
func (a *Application) processFeatureFlags(features *features.Features) {
|
||||
|
||||
// Process generic features
|
||||
|
||||
// Process OS Specific flags
|
||||
a.processOSFeatureFlags(features)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,56 @@
|
||||
#ifndef __FFENESTRI_H__
|
||||
#define __FFENESTRI_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen);
|
||||
extern void SetMinWindowSize(void *app, int minWidth, int minHeight);
|
||||
extern void SetMaxWindowSize(void *app, int maxWidth, int maxHeight);
|
||||
extern void Run(void *app, int argc, char **argv);
|
||||
extern void DestroyApplication(void *app);
|
||||
extern void SetDebug(void *app, int flag);
|
||||
extern void SetBindings(void *app, const char *bindings);
|
||||
extern void ExecJS(void *app, const char *script);
|
||||
extern void Quit(void *app);
|
||||
extern void SetTitle(void *app, const char *title);
|
||||
extern void Fullscreen(void *app);
|
||||
extern void UnFullscreen(void *app);
|
||||
extern int SetColour(void *app, const char *colourString);
|
||||
extern void DisableFrame(void *app);
|
||||
extern char *SaveFileDialogOnMainThread(void *appPointer, char *title);
|
||||
extern char *OpenFileDialogOnMainThread(void *appPointer, char *title);
|
||||
extern char *OpenDirectoryDialogOnMainThread(void *appPointer, char *title);
|
||||
#include <stdio.h>
|
||||
struct Application;
|
||||
|
||||
extern struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose);
|
||||
extern void SetMinWindowSize(struct Application*, int minWidth, int minHeight);
|
||||
extern void SetMaxWindowSize(struct Application*, int maxWidth, int maxHeight);
|
||||
extern void Run(struct Application*, int argc, char **argv);
|
||||
extern void DestroyApplication(struct Application*);
|
||||
extern void SetDebug(struct Application*, int flag);
|
||||
extern void SetBindings(struct Application*, const char *bindings);
|
||||
extern void ExecJS(struct Application*, const char *script);
|
||||
extern void Hide(struct Application*);
|
||||
extern void Show(struct Application*);
|
||||
extern void Center(struct Application*);
|
||||
extern void Maximise(struct Application*);
|
||||
extern void Unmaximise(struct Application*);
|
||||
extern void ToggleMaximise(struct Application*);
|
||||
extern void Minimise(struct Application*);
|
||||
extern void Unminimise(struct Application*);
|
||||
extern void ToggleMinimise(struct Application*);
|
||||
extern void SetColour(struct Application*, int red, int green, int blue, int alpha);
|
||||
extern void SetSize(struct Application*, int width, int height);
|
||||
extern void SetPosition(struct Application*, int x, int y);
|
||||
extern void Quit(struct Application*);
|
||||
extern void SetTitle(struct Application*, const char *title);
|
||||
extern void Fullscreen(struct Application*);
|
||||
extern void UnFullscreen(struct Application*);
|
||||
extern void ToggleFullscreen(struct Application*);
|
||||
extern void DisableFrame(struct Application*);
|
||||
extern void OpenDialog(struct Application*, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories);
|
||||
extern void SaveDialog(struct Application*, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories);
|
||||
extern void MessageDialog(struct Application*, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton);
|
||||
extern void DarkModeEnabled(struct Application*, char *callbackID);
|
||||
extern void SetApplicationMenu(struct Application*, const char *);
|
||||
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void SetTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void DeleteTrayMenuByID(struct Application*, const char *id);
|
||||
extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
||||
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
||||
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
||||
extern void WebviewIsTransparent(struct Application*);
|
||||
extern void WindowBackgroundIsTranslucent(struct Application*);
|
||||
extern void* GetWindowHandle(struct Application*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
// +build !windows
|
||||
|
||||
package ffenestri
|
||||
|
||||
/*
|
||||
|
||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ffenestri.h"
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
// Client is our implentation of messageDispatcher.Client
|
||||
// Client is our implementation of messageDispatcher.Client
|
||||
type Client struct {
|
||||
app *Application
|
||||
logger logger.CustomLogger
|
||||
@@ -66,44 +65,209 @@ func (c *Client) WindowUnFullscreen() {
|
||||
C.UnFullscreen(c.app.app)
|
||||
}
|
||||
|
||||
// WindowShow will show the window
|
||||
func (c *Client) WindowShow() {
|
||||
C.Show(c.app.app)
|
||||
}
|
||||
|
||||
// WindowHide will hide the window
|
||||
func (c *Client) WindowHide() {
|
||||
C.Hide(c.app.app)
|
||||
}
|
||||
|
||||
// WindowCenter will hide the window
|
||||
func (c *Client) WindowCenter() {
|
||||
C.Center(c.app.app)
|
||||
}
|
||||
|
||||
// WindowMaximise will maximise the window
|
||||
func (c *Client) WindowMaximise() {
|
||||
C.Maximise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowMinimise will minimise the window
|
||||
func (c *Client) WindowMinimise() {
|
||||
C.Minimise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowUnmaximise will unmaximise the window
|
||||
func (c *Client) WindowUnmaximise() {
|
||||
C.Unmaximise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowUnminimise will unminimise the window
|
||||
func (c *Client) WindowUnminimise() {
|
||||
C.Unminimise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowPosition will position the window to x,y on the
|
||||
// monitor that the window is mostly on
|
||||
func (c *Client) WindowPosition(x int, y int) {
|
||||
C.SetPosition(c.app.app, C.int(x), C.int(y))
|
||||
}
|
||||
|
||||
// WindowSize will resize the window to the given
|
||||
// width and height
|
||||
func (c *Client) WindowSize(width int, height int) {
|
||||
C.SetSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
func (c *Client) WindowSetMinSize(width int, height int) {
|
||||
C.SetMinWindowSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
func (c *Client) WindowSetMaxSize(width int, height int) {
|
||||
C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
// WindowSetColour sets the window colour
|
||||
func (c *Client) WindowSetColour(colour string) bool {
|
||||
result := C.SetColour(c.app.app, c.app.string2CString(colour))
|
||||
return result == 1
|
||||
func (c *Client) WindowSetColour(colour int) {
|
||||
r, g, b, a := intToColour(colour)
|
||||
C.SetColour(c.app.app, r, g, b, a)
|
||||
}
|
||||
|
||||
// OpenFileDialog will open a file dialog with the given title
|
||||
func (c *Client) OpenFileDialog(title string) string {
|
||||
cstring := C.OpenFileDialogOnMainThread(c.app.app, c.app.string2CString(title))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
// OpenFileDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
C.OpenDialog(c.app.app,
|
||||
c.app.string2CString(callbackID),
|
||||
c.app.string2CString(dialogOptions.Title),
|
||||
c.app.string2CString(strings.Join(filters, ";")),
|
||||
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||
c.app.bool2Cint(dialogOptions.AllowFiles),
|
||||
c.app.bool2Cint(dialogOptions.AllowDirectories),
|
||||
c.app.bool2Cint(false),
|
||||
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||
c.app.bool2Cint(dialogOptions.ResolvesAliases),
|
||||
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||
)
|
||||
}
|
||||
|
||||
// SaveFileDialog will open a save file dialog with the given title
|
||||
func (c *Client) SaveFileDialog(title string) string {
|
||||
cstring := C.SaveFileDialogOnMainThread(c.app.app, c.app.string2CString(title))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
|
||||
// OpenDirectoryDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
C.OpenDialog(c.app.app,
|
||||
c.app.string2CString(callbackID),
|
||||
c.app.string2CString(dialogOptions.Title),
|
||||
c.app.string2CString(strings.Join(filters, ";")),
|
||||
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||
c.app.bool2Cint(false), // Files
|
||||
c.app.bool2Cint(true), // Directories
|
||||
c.app.bool2Cint(false), // Multiple
|
||||
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||
c.app.bool2Cint(dialogOptions.ResolvesAliases),
|
||||
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||
)
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog will open a directory dialog with the given title
|
||||
func (c *Client) OpenDirectoryDialog(title string) string {
|
||||
cstring := C.OpenDirectoryDialogOnMainThread(c.app.app, c.app.string2CString(title))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
// OpenMultipleFilesDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
C.OpenDialog(c.app.app,
|
||||
c.app.string2CString(callbackID),
|
||||
c.app.string2CString(dialogOptions.Title),
|
||||
c.app.string2CString(strings.Join(filters, ";")),
|
||||
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||
c.app.bool2Cint(dialogOptions.AllowFiles),
|
||||
c.app.bool2Cint(dialogOptions.AllowDirectories),
|
||||
c.app.bool2Cint(true),
|
||||
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||
c.app.bool2Cint(dialogOptions.ResolvesAliases),
|
||||
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||
)
|
||||
}
|
||||
|
||||
// SaveDialog will open a dialog with the given title and filter
|
||||
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
filters := []string{}
|
||||
if runtime.GOOS == "darwin" {
|
||||
for _, filter := range dialogOptions.Filters {
|
||||
filters = append(filters, strings.Split(filter.Pattern, ",")...)
|
||||
}
|
||||
}
|
||||
C.SaveDialog(c.app.app,
|
||||
c.app.string2CString(callbackID),
|
||||
c.app.string2CString(dialogOptions.Title),
|
||||
c.app.string2CString(strings.Join(filters, ";")),
|
||||
c.app.string2CString(dialogOptions.DefaultFilename),
|
||||
c.app.string2CString(dialogOptions.DefaultDirectory),
|
||||
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
|
||||
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
|
||||
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
|
||||
)
|
||||
}
|
||||
|
||||
// MessageDialog will open a message dialog with the given options
|
||||
func (c *Client) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
|
||||
// Sanity check button length
|
||||
if len(dialogOptions.Buttons) > 4 {
|
||||
c.app.logger.Error("Given %d message dialog buttons. Maximum is 4", len(dialogOptions.Buttons))
|
||||
return
|
||||
}
|
||||
|
||||
// Process buttons
|
||||
buttons := []string{"", "", "", ""}
|
||||
for i, button := range dialogOptions.Buttons {
|
||||
buttons[i] = button
|
||||
}
|
||||
|
||||
C.MessageDialog(c.app.app,
|
||||
c.app.string2CString(callbackID),
|
||||
c.app.string2CString(string(dialogOptions.Type)),
|
||||
c.app.string2CString(dialogOptions.Title),
|
||||
c.app.string2CString(dialogOptions.Message),
|
||||
c.app.string2CString(dialogOptions.Icon),
|
||||
c.app.string2CString(buttons[0]),
|
||||
c.app.string2CString(buttons[1]),
|
||||
c.app.string2CString(buttons[2]),
|
||||
c.app.string2CString(buttons[3]),
|
||||
c.app.string2CString(dialogOptions.DefaultButton),
|
||||
c.app.string2CString(dialogOptions.CancelButton))
|
||||
}
|
||||
|
||||
func (c *Client) DarkModeEnabled(callbackID string) {
|
||||
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
|
||||
}
|
||||
|
||||
func (c *Client) SetApplicationMenu(applicationMenuJSON string) {
|
||||
C.SetApplicationMenu(c.app.app, c.app.string2CString(applicationMenuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) SetTrayMenu(trayMenuJSON string) {
|
||||
C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTrayMenuLabel(JSON string) {
|
||||
C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) DeleteTrayMenuByID(id string) {
|
||||
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
|
||||
}
|
||||
|
||||
309
v2/internal/ffenestri/ffenestri_client_windows.go
Normal file
309
v2/internal/ffenestri/ffenestri_client_windows.go
Normal file
@@ -0,0 +1,309 @@
|
||||
// +build windows
|
||||
|
||||
package ffenestri
|
||||
|
||||
/*
|
||||
#include "ffenestri.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||
"golang.org/x/sys/windows"
|
||||
"log"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
// Client is our implementation of messageDispatcher.Client
|
||||
type Client struct {
|
||||
app *Application
|
||||
logger logger.CustomLogger
|
||||
}
|
||||
|
||||
func newClient(app *Application) *Client {
|
||||
return &Client{
|
||||
app: app,
|
||||
logger: app.logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Quit the application
|
||||
func (c *Client) Quit() {
|
||||
c.app.logger.Trace("Got shutdown message")
|
||||
C.Quit(c.app.app)
|
||||
}
|
||||
|
||||
// NotifyEvent will pass on the event message to the frontend
|
||||
func (c *Client) NotifyEvent(message string) {
|
||||
eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);`
|
||||
c.app.logger.Trace("eventMessage = %+v", eventMessage)
|
||||
C.ExecJS(c.app.app, c.app.string2CString(eventMessage))
|
||||
}
|
||||
|
||||
// CallResult contains the result of the call from JS
|
||||
func (c *Client) CallResult(message string) {
|
||||
callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);`
|
||||
c.app.logger.Trace("callbackMessage = %+v", callbackMessage)
|
||||
C.ExecJS(c.app.app, c.app.string2CString(callbackMessage))
|
||||
}
|
||||
|
||||
// WindowSetTitle sets the window title to the given string
|
||||
func (c *Client) WindowSetTitle(title string) {
|
||||
C.SetTitle(c.app.app, c.app.string2CString(title))
|
||||
}
|
||||
|
||||
// WindowFullscreen will set the window to be fullscreen
|
||||
func (c *Client) WindowFullscreen() {
|
||||
C.Fullscreen(c.app.app)
|
||||
}
|
||||
|
||||
// WindowUnFullscreen will unfullscreen the window
|
||||
func (c *Client) WindowUnFullscreen() {
|
||||
C.UnFullscreen(c.app.app)
|
||||
}
|
||||
|
||||
// WindowShow will show the window
|
||||
func (c *Client) WindowShow() {
|
||||
C.Show(c.app.app)
|
||||
}
|
||||
|
||||
// WindowHide will hide the window
|
||||
func (c *Client) WindowHide() {
|
||||
C.Hide(c.app.app)
|
||||
}
|
||||
|
||||
// WindowCenter will hide the window
|
||||
func (c *Client) WindowCenter() {
|
||||
C.Center(c.app.app)
|
||||
}
|
||||
|
||||
// WindowMaximise will maximise the window
|
||||
func (c *Client) WindowMaximise() {
|
||||
C.Maximise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowMinimise will minimise the window
|
||||
func (c *Client) WindowMinimise() {
|
||||
C.Minimise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowUnmaximise will unmaximise the window
|
||||
func (c *Client) WindowUnmaximise() {
|
||||
C.Unmaximise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowUnminimise will unminimise the window
|
||||
func (c *Client) WindowUnminimise() {
|
||||
C.Unminimise(c.app.app)
|
||||
}
|
||||
|
||||
// WindowPosition will position the window to x,y on the
|
||||
// monitor that the window is mostly on
|
||||
func (c *Client) WindowPosition(x int, y int) {
|
||||
C.SetPosition(c.app.app, C.int(x), C.int(y))
|
||||
}
|
||||
|
||||
// WindowSize will resize the window to the given
|
||||
// width and height
|
||||
func (c *Client) WindowSize(width int, height int) {
|
||||
C.SetSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
// WindowSetMinSize sets the minimum window size
|
||||
func (c *Client) WindowSetMinSize(width int, height int) {
|
||||
C.SetMinWindowSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
// WindowSetMaxSize sets the maximum window size
|
||||
func (c *Client) WindowSetMaxSize(width int, height int) {
|
||||
C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
// WindowSetColour sets the window colour
|
||||
func (c *Client) WindowSetColour(colour int) {
|
||||
r, g, b, a := intToColour(colour)
|
||||
C.SetColour(c.app.app, r, g, b, a)
|
||||
}
|
||||
|
||||
func convertFilters(filters []dialog.FileFilter) []cfd.FileFilter {
|
||||
var result []cfd.FileFilter
|
||||
for _, filter := range filters {
|
||||
result = append(result, cfd.FileFilter(filter))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// OpenFileDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenFileDialog(options *dialog.OpenDialog, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Folder: options.DefaultDirectory,
|
||||
FileFilters: convertFilters(options.Filters),
|
||||
FileName: options.DefaultFilename,
|
||||
}
|
||||
thisdialog, err := cfd.NewOpenFileDialog(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
|
||||
defer func(thisdialog cfd.OpenFileDialog) {
|
||||
err := thisdialog.Release()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(thisdialog)
|
||||
result, err := thisdialog.ShowAndGetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
dispatcher.DispatchMessage("DO" + callbackID + "|" + result)
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "PickFolder",
|
||||
Folder: dialogOptions.DefaultDirectory,
|
||||
}
|
||||
thisDialog, err := cfd.NewSelectFolderDialog(config)
|
||||
if err != nil {
|
||||
log.Fatal()
|
||||
}
|
||||
thisDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
|
||||
defer func(thisDialog cfd.SelectFolderDialog) {
|
||||
err := thisDialog.Release()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(thisDialog)
|
||||
result, err := thisDialog.ShowAndGetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dispatcher.DispatchMessage("DD" + callbackID + "|" + result)
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
config := cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "OpenMultipleFiles",
|
||||
FileFilters: convertFilters(dialogOptions.Filters),
|
||||
FileName: dialogOptions.DefaultFilename,
|
||||
Folder: dialogOptions.DefaultDirectory,
|
||||
}
|
||||
thisdialog, err := cfd.NewOpenMultipleFilesDialog(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
|
||||
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
|
||||
err := thisdialog.Release()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(thisdialog)
|
||||
result, err := thisdialog.ShowAndGetResults()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
log.Fatal(err)
|
||||
}
|
||||
resultJSON, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dispatcher.DispatchMessage("D*" + callbackID + "|" + string(resultJSON))
|
||||
}
|
||||
|
||||
// SaveDialog will open a dialog with the given title and filter
|
||||
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{
|
||||
Title: dialogOptions.Title,
|
||||
Role: "SaveFile",
|
||||
FileFilters: convertFilters(dialogOptions.Filters),
|
||||
FileName: dialogOptions.DefaultFilename,
|
||||
Folder: dialogOptions.DefaultDirectory,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
saveDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
|
||||
err = saveDialog.Show()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result, err := saveDialog.GetResult()
|
||||
if err != nil && err != cfd.ErrorCancelled {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dispatcher.DispatchMessage("DS" + callbackID + "|" + result)
|
||||
}
|
||||
|
||||
// MessageDialog will open a message dialog with the given options
|
||||
func (c *Client) MessageDialog(options *dialog.MessageDialog, callbackID string) {
|
||||
|
||||
title, err := syscall.UTF16PtrFromString(options.Title)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
message, err := syscall.UTF16PtrFromString(options.Message)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var flags uint32
|
||||
switch options.Type {
|
||||
case dialog.InfoDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONINFORMATION
|
||||
case dialog.ErrorDialog:
|
||||
flags = windows.MB_ICONERROR | windows.MB_OK
|
||||
case dialog.QuestionDialog:
|
||||
flags = windows.MB_YESNO
|
||||
case dialog.WarningDialog:
|
||||
flags = windows.MB_OK | windows.MB_ICONWARNING
|
||||
}
|
||||
|
||||
button, _ := windows.MessageBox(windows.HWND(C.GetWindowHandle(c.app.app)), message, title, flags|windows.MB_SYSTEMMODAL)
|
||||
// This maps MessageBox return values to strings
|
||||
responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"}
|
||||
result := "Error"
|
||||
if int(button) < len(responses) {
|
||||
result = responses[button]
|
||||
}
|
||||
dispatcher.DispatchMessage("DM" + callbackID + "|" + result)
|
||||
}
|
||||
|
||||
// DarkModeEnabled sets the application to use dark mode
|
||||
func (c *Client) DarkModeEnabled(callbackID string) {
|
||||
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
|
||||
}
|
||||
|
||||
// SetApplicationMenu sets the application menu
|
||||
func (c *Client) SetApplicationMenu(applicationMenuJSON string) {
|
||||
C.SetApplicationMenu(c.app.app, c.app.string2CString(applicationMenuJSON))
|
||||
}
|
||||
|
||||
// SetTrayMenu sets the tray menu
|
||||
func (c *Client) SetTrayMenu(trayMenuJSON string) {
|
||||
C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
|
||||
}
|
||||
|
||||
// UpdateTrayMenuLabel updates a tray menu label
|
||||
func (c *Client) UpdateTrayMenuLabel(JSON string) {
|
||||
C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON))
|
||||
}
|
||||
|
||||
// UpdateContextMenu will update the current context menu
|
||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||
}
|
||||
|
||||
// DeleteTrayMenuByID will remove a tray menu based on the given id
|
||||
func (c *Client) DeleteTrayMenuByID(id string) {
|
||||
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user