diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7cb7b615..79465e94 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to
[Semantic Versioning](https://semver.org).
+## 4.0.5
+
+- Fixes runtime crash #135
+- Option to disable colors in cli help `mangal config info -k cli.colored` (why not? =P)
+- Improved `config info` command output. It now shows default value and env variable name.
+- Internal improvements
+
## 4.0.4
- Fix manga tags and genres being the same inside ComicInfo.xml #133
diff --git a/anilist/search.go b/anilist/search.go
index d855e16d..e2eb7dbd 100644
--- a/anilist/search.go
+++ b/anilist/search.go
@@ -86,7 +86,6 @@ func GetByID(id int) (*Manga, error) {
}
// SearchByName returns a list of mangas that match the given name.
-// TODO: keep failed names in cache for a minute
func SearchByName(name string) ([]*Manga, error) {
name = normalizedName(name)
_ = query.Remember(name, 1)
diff --git a/cmd/config.go b/cmd/config.go
index f5f8c2a6..3c3e8646 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -94,6 +94,7 @@ var configInfoCmd = &cobra.Command{
if i < len(fields)-1 {
fmt.Println()
+ fmt.Println()
}
}
},
diff --git a/cmd/inline.go b/cmd/inline.go
index 34da2691..923bedf9 100644
--- a/cmd/inline.go
+++ b/cmd/inline.go
@@ -6,10 +6,10 @@ import (
"fmt"
"github.com/invopop/jsonschema"
"github.com/metafates/mangal/anilist"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/converter"
"github.com/metafates/mangal/filesystem"
"github.com/metafates/mangal/inline"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/query"
"github.com/metafates/mangal/source"
@@ -36,7 +36,7 @@ func init() {
inlineCmd.Flags().BoolP("populate-pages", "p", false, "Populate chapters pages")
inlineCmd.Flags().BoolP("fetch-metadata", "f", false, "Populate manga metadata")
inlineCmd.Flags().BoolP("include-anilist-manga", "a", false, "Include anilist manga in the output")
- lo.Must0(viper.BindPFlag(constant.MetadataFetchAnilist, inlineCmd.Flags().Lookup("fetch-metadata")))
+ lo.Must0(viper.BindPFlag(key.MetadataFetchAnilist, inlineCmd.Flags().Lookup("fetch-metadata")))
inlineCmd.Flags().StringP("output", "o", "", "output file")
@@ -81,7 +81,7 @@ When using the json flag manga selector could be omitted. That way, it will sele
lo.Must0(cmd.MarkFlagRequired("json"))
}
- if _, err := converter.Get(viper.GetString(constant.FormatsUse)); err != nil {
+ if _, err := converter.Get(viper.GetString(key.FormatsUse)); err != nil {
handleErr(err)
}
},
@@ -91,7 +91,7 @@ When using the json flag manga selector could be omitted. That way, it will sele
err error
)
- for _, name := range viper.GetStringSlice(constant.DownloaderDefaultSources) {
+ for _, name := range viper.GetStringSlice(key.DownloaderDefaultSources) {
if name == "" {
handleErr(errors.New("source not set"))
}
diff --git a/cmd/integration.go b/cmd/integration.go
index 4a1b8201..91fa95ad 100644
--- a/cmd/integration.go
+++ b/cmd/integration.go
@@ -3,9 +3,9 @@ package cmd
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/icon"
"github.com/metafates/mangal/integration/anilist"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/open"
"github.com/samber/lo"
@@ -32,15 +32,15 @@ var integrationAnilistCmd = &cobra.Command{
See https://github.com/metafates/mangal/wiki/Anilist-Integration for more information`,
Run: func(cmd *cobra.Command, args []string) {
if lo.Must(cmd.Flags().GetBool("disable")) {
- viper.Set(constant.AnilistEnable, false)
- viper.Set(constant.AnilistCode, "")
- viper.Set(constant.AnilistSecret, "")
- viper.Set(constant.AnilistID, "")
+ viper.Set(key.AnilistEnable, false)
+ viper.Set(key.AnilistCode, "")
+ viper.Set(key.AnilistSecret, "")
+ viper.Set(key.AnilistID, "")
log.Info("Anilist integration disabled")
handleErr(viper.WriteConfig())
}
- if !viper.GetBool(constant.AnilistEnable) {
+ if !viper.GetBool(key.AnilistEnable) {
confirm := survey.Confirm{
Message: "Anilist is disabled. Enable?",
Default: false,
@@ -53,7 +53,7 @@ See https://github.com/metafates/mangal/wiki/Anilist-Integration for more inform
return
}
- viper.Set(constant.AnilistEnable, response)
+ viper.Set(key.AnilistEnable, response)
err = viper.WriteConfig()
if err != nil {
switch err.(type) {
@@ -67,7 +67,7 @@ See https://github.com/metafates/mangal/wiki/Anilist-Integration for more inform
}
}
- if viper.GetString(constant.AnilistID) == "" {
+ if viper.GetString(key.AnilistID) == "" {
input := survey.Input{
Message: "Anilsit client ID is not set. Please enter it:",
Help: "",
@@ -80,12 +80,12 @@ See https://github.com/metafates/mangal/wiki/Anilist-Integration for more inform
return
}
- viper.Set(constant.AnilistID, response)
+ viper.Set(key.AnilistID, response)
err = viper.WriteConfig()
handleErr(err)
}
- if viper.GetString(constant.AnilistSecret) == "" {
+ if viper.GetString(key.AnilistSecret) == "" {
input := survey.Input{
Message: "Anilsit client secret is not set. Please enter it:",
Help: "",
@@ -98,12 +98,12 @@ See https://github.com/metafates/mangal/wiki/Anilist-Integration for more inform
return
}
- viper.Set(constant.AnilistSecret, response)
+ viper.Set(key.AnilistSecret, response)
err = viper.WriteConfig()
handleErr(err)
}
- if viper.GetString(constant.AnilistCode) == "" {
+ if viper.GetString(key.AnilistCode) == "" {
authURL := anilist.New().AuthURL()
confirmOpenInBrowser := survey.Confirm{
Message: "Open browser to authenticate with Anilist?",
@@ -134,7 +134,7 @@ See https://github.com/metafates/mangal/wiki/Anilist-Integration for more inform
return
}
- viper.Set(constant.AnilistCode, response)
+ viper.Set(key.AnilistCode, response)
err = viper.WriteConfig()
handleErr(err)
}
diff --git a/cmd/mini.go b/cmd/mini.go
index 9b16aa7e..0225e9a4 100644
--- a/cmd/mini.go
+++ b/cmd/mini.go
@@ -1,8 +1,8 @@
package cmd
import (
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/converter"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/mini"
"github.com/samber/lo"
"github.com/spf13/cobra"
@@ -24,7 +24,7 @@ var miniCmd = &cobra.Command{
Long: `Launch mangal in the mini mode.
Will try to mimic ani-cli.`,
PreRun: func(cmd *cobra.Command, args []string) {
- if _, err := converter.Get(viper.GetString(constant.FormatsUse)); err != nil {
+ if _, err := converter.Get(viper.GetString(key.FormatsUse)); err != nil {
handleErr(err)
}
},
diff --git a/cmd/root.go b/cmd/root.go
index 08fa018f..0970c65a 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -7,6 +7,7 @@ import (
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/converter"
"github.com/metafates/mangal/icon"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/style"
@@ -28,16 +29,16 @@ func init() {
lo.Must0(rootCmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return converter.Available(), cobra.ShellCompDirectiveDefault
}))
- lo.Must0(viper.BindPFlag(constant.FormatsUse, rootCmd.PersistentFlags().Lookup("format")))
+ lo.Must0(viper.BindPFlag(key.FormatsUse, rootCmd.PersistentFlags().Lookup("format")))
rootCmd.PersistentFlags().StringP("icons", "I", "", "icons variant")
lo.Must0(rootCmd.RegisterFlagCompletionFunc("icons", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return icon.AvailableVariants(), cobra.ShellCompDirectiveDefault
}))
- lo.Must0(viper.BindPFlag(constant.IconsVariant, rootCmd.PersistentFlags().Lookup("icons")))
+ lo.Must0(viper.BindPFlag(key.IconsVariant, rootCmd.PersistentFlags().Lookup("icons")))
rootCmd.PersistentFlags().BoolP("write-history", "H", true, "write history of the read chapters")
- lo.Must0(viper.BindPFlag(constant.HistorySaveOnRead, rootCmd.PersistentFlags().Lookup("write-history")))
+ lo.Must0(viper.BindPFlag(key.HistorySaveOnRead, rootCmd.PersistentFlags().Lookup("write-history")))
rootCmd.PersistentFlags().StringSliceP("source", "S", []string{}, "default source to use")
lo.Must0(rootCmd.RegisterFlagCompletionFunc("source", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
@@ -53,7 +54,7 @@ func init() {
return sources, cobra.ShellCompDirectiveDefault
}))
- lo.Must0(viper.BindPFlag(constant.DownloaderDefaultSources, rootCmd.PersistentFlags().Lookup("source")))
+ lo.Must0(viper.BindPFlag(key.DownloaderDefaultSources, rootCmd.PersistentFlags().Lookup("source")))
rootCmd.Flags().BoolP("continue", "c", false, "continue reading")
@@ -76,7 +77,7 @@ var rootCmd = &cobra.Command{
Long: constant.AsciiArtLogo + "\n" +
style.New().Italic(true).Foreground(color.HiRed).Render(" - The ultimate cli manga downloader"),
PreRun: func(cmd *cobra.Command, args []string) {
- if _, err := converter.Get(viper.GetString(constant.FormatsUse)); err != nil {
+ if _, err := converter.Get(viper.GetString(key.FormatsUse)); err != nil {
handleErr(err)
}
},
@@ -95,16 +96,18 @@ var rootCmd = &cobra.Command{
// Execute adds all child commands to the root command and sets flags appropriately.
func Execute() {
- // colored cobra injection
- cc.Init(&cc.Config{
- RootCmd: rootCmd,
- Headings: cc.HiCyan + cc.Bold + cc.Underline,
- Commands: cc.HiYellow + cc.Bold,
- Example: cc.Italic,
- ExecName: cc.Bold,
- Flags: cc.Bold,
- FlagsDataType: cc.Italic + cc.HiBlue,
- })
+ if viper.GetBool(key.CliColored) {
+ // colored cobra injection
+ cc.Init(&cc.Config{
+ RootCmd: rootCmd,
+ Headings: cc.HiCyan + cc.Bold + cc.Underline,
+ Commands: cc.HiYellow + cc.Bold,
+ Example: cc.Italic,
+ ExecName: cc.Bold,
+ Flags: cc.Bold,
+ FlagsDataType: cc.Italic + cc.HiBlue,
+ })
+ }
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
diff --git a/cmd/sources.go b/cmd/sources.go
index 362f8181..12c624bf 100644
--- a/cmd/sources.go
+++ b/cmd/sources.go
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/metafates/mangal/color"
"github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/tui"
"github.com/metafates/mangal/util"
"github.com/spf13/viper"
@@ -147,7 +148,7 @@ var sourcesGenCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
cmd.SetOut(os.Stdout)
- author := viper.GetString(constant.GenAuthor)
+ author := viper.GetString(key.GenAuthor)
if author == "" {
usr, err := user.Current()
if err == nil {
diff --git a/config/config.go b/config/config.go
index 3d808bb9..db6628cd 100644
--- a/config/config.go
+++ b/config/config.go
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/where"
"github.com/samber/lo"
"github.com/spf13/viper"
@@ -74,7 +75,7 @@ func setDefaults() {
// resolveAliases resolves the aliases for the paths
func resolveAliases() {
home := lo.Must(os.UserHomeDir())
- path := viper.GetString(constant.DownloaderPath)
+ path := viper.GetString(key.DownloaderPath)
if path == "~" {
path = home
@@ -84,5 +85,5 @@ func resolveAliases() {
path = os.ExpandEnv(path)
- viper.Set(constant.DownloaderPath, path)
+ viper.Set(key.DownloaderPath, path)
}
diff --git a/config/default.go b/config/default.go
index 909bdca8..96d6b400 100644
--- a/config/default.go
+++ b/config/default.go
@@ -5,8 +5,14 @@ import (
"fmt"
"github.com/metafates/mangal/color"
"github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/style"
+ "github.com/samber/lo"
"github.com/spf13/viper"
+ "reflect"
+ "strconv"
+ "strings"
+ "text/template"
)
// Field represents a single config field
@@ -55,24 +61,73 @@ func (f *Field) MarshalJSON() ([]byte, error) {
return json.Marshal(field)
}
-// Pretty format field as string for further cli output
+var prettyTemplate = lo.Must(template.New("pretty").Funcs(template.FuncMap{
+ "faint": style.Faint,
+ "bold": style.Bold,
+ "purple": style.Fg(color.Purple),
+ "blue": style.Fg(color.Blue),
+ "cyan": style.Fg(color.Cyan),
+ "value": func(k string) any { return viper.Get(k) },
+ "hl": func(v any) string {
+ switch value := v.(type) {
+ case bool:
+ b := strconv.FormatBool(value)
+ if value {
+ return style.Fg(color.Green)(b)
+ }
+
+ return style.Fg(color.Red)(b)
+ case string:
+ return style.Fg(color.Yellow)(value)
+ default:
+ return fmt.Sprint(value)
+ }
+ },
+ "typename": func(v any) string { return reflect.TypeOf(v).String() },
+}).Parse(`{{ faint .Description }}
+{{ blue "Key:" }} {{ purple .Key }}
+{{ blue "Env:" }} {{ .Env }}
+{{ blue "Value:" }} {{ hl (value .Key) }}
+{{ blue "Default:" }} {{ hl (.Value) }}
+{{ blue "Type:" }} {{ typename .Value }}`))
+
func (f *Field) Pretty() string {
- return fmt.Sprintf(
- `%s
-%s: %s = %s
-`,
- style.Faint(f.Description),
- style.Fg(color.Purple)(f.Key),
- style.Fg(color.Yellow)(f.typeName()),
- style.Fg(color.Cyan)(fmt.Sprintf("%v", viper.Get(f.Key))),
- )
+ var b strings.Builder
+
+ lo.Must0(prettyTemplate.Execute(&b, f))
+
+ return b.String()
}
+func (f *Field) Env() string {
+ env := strings.ToUpper(EnvKeyReplacer.Replace(f.Key))
+ appPrefix := strings.ToUpper(constant.Mangal + "_")
+
+ if strings.HasPrefix(env, appPrefix) {
+ return env
+ }
+
+ return appPrefix + env
+}
+
+// Pretty format field as string for further cli output
+//func (f *Field) Pretty() string {
+// return fmt.Sprintf(
+// `%s
+//%s: %s = %s
+//`,
+// style.Faint(f.Description),
+// style.Fg(color.Purple)(f.Key),
+// style.Fg(color.Yellow)(f.typeName()),
+// style.Fg(color.Cyan)(fmt.Sprintf("%v", viper.Get(f.Key))),
+// )
+//}
+
// defaults contains all default values for the config.
// It must contain all fields defined in the constant package.
-var defaults = [constant.DefinedFieldsCount]Field{
+var defaults = [key.DefinedFieldsCount]Field{
{
- constant.DownloaderPath,
+ key.DownloaderPath,
".",
`Where to download manga
Absolute or relative.
@@ -80,7 +135,7 @@ You can also use tilde (~) to refer to your home directory or use env variables.
Examples: ~/... or $HOME/... or ${MANGA_PATH}-mangal`,
},
{
- constant.DownloaderChapterNameTemplate,
+ key.DownloaderChapterNameTemplate,
"[{padded-index}] {chapter}",
`Key template of the downloaded chapters
Path forbidden symbols will be replaced with "_"
@@ -94,261 +149,266 @@ Available variables:
{source} - name of the source`,
},
{
- constant.DownloaderAsync,
+ key.DownloaderAsync,
true,
`Use asynchronous downloader (faster)
Do no turn it off unless you have some issues`,
},
{
- constant.DownloaderCreateMangaDir,
+ key.DownloaderCreateMangaDir,
true,
`Create a subdirectory for each manga`,
},
{
- constant.DownloaderCreateVolumeDir,
+ key.DownloaderCreateVolumeDir,
false,
`Create a subdirectory for each volume`,
},
{
- constant.DownloaderReadDownloaded,
+ key.DownloaderReadDownloaded,
true,
"If chapter is already downloaded, read it instead of downloading it to temp",
},
{
- constant.DownloaderRedownloadExisting,
+ key.DownloaderRedownloadExisting,
false,
`Redownload chapters that already exist`,
},
{
- constant.DownloaderDefaultSources,
+ key.DownloaderDefaultSources,
[]string{},
`Default sources to use.
Will prompt if not set.
Type "mangal sources list" to show available sources`,
},
{
- constant.DownloaderStopOnError,
+ key.DownloaderStopOnError,
false,
`Stop downloading other chapters on error`,
},
{
- constant.DownloaderDownloadCover,
+ key.DownloaderDownloadCover,
true,
`Whether to download manga cover or not`,
},
{
- constant.FormatsUse,
+ key.FormatsUse,
"pdf",
`Default format to export chapters
Available options are: pdf, zip, cbz, plain`,
},
{
- constant.FormatsSkipUnsupportedImages,
+ key.FormatsSkipUnsupportedImages,
true,
`Will skip images that can't be converted to the specified format
Example: if you want to export to pdf, but some images are gifs, they will be skipped`,
},
{
- constant.MetadataFetchAnilist,
+ key.MetadataFetchAnilist,
true,
`Fetch metadata from Anilist
It will also cache the results to not spam the API`,
},
{
- constant.MetadataComicInfoXML,
+ key.MetadataComicInfoXML,
true,
`Generate ComicInfo.xml file for each chapter`,
},
{
- constant.MetadataComicInfoXMLAddDate,
+ key.MetadataComicInfoXMLAddDate,
true,
`Add series release date to each chapter in ComicInfo.xml file`,
},
{
- constant.MetadataComicInfoXMLAlternativeDate,
+ key.MetadataComicInfoXMLAlternativeDate,
false,
"Use download date instead of series release date in ComicInfo.xml file",
},
{
- constant.MetadataComicInfoXMLTagRelevanceThreshold,
+ key.MetadataComicInfoXMLTagRelevanceThreshold,
60,
"Minimum relevance of a tag to be added to ComicInfo.xml file. From 0 to 100",
},
{
- constant.MetadataSeriesJSON,
+ key.MetadataSeriesJSON,
true,
`Generate series.json file for each manga`,
},
{
- constant.MiniSearchLimit,
+ key.MiniSearchLimit,
20,
`Limit of search results to show`,
},
{
- constant.IconsVariant,
+ key.IconsVariant,
"plain",
`Icons variant.
Available options are: emoji, kaomoji, plain, squares, nerd (nerd-font required)`,
},
{
- constant.ReaderPDF,
+ key.ReaderPDF,
"",
"What app to use to open pdf files",
},
{
- constant.ReaderCBZ,
+ key.ReaderCBZ,
"",
"What app to use to open cbz files",
},
{
- constant.ReaderZIP,
+ key.ReaderZIP,
"",
"What app to use to open zip files",
},
{
- constant.RaderPlain,
+ key.RaderPlain,
"",
"What app to use to open folders",
},
{
- constant.ReaderBrowser,
+ key.ReaderBrowser,
"",
"What browser to use to open webpages",
},
{
- constant.ReaderFolder,
+ key.ReaderFolder,
"",
"What app to use to open folders",
},
{
- constant.ReaderReadInBrowser,
+ key.ReaderReadInBrowser,
false,
"Open chapter url in browser instead of downloading it",
},
{
- constant.HistorySaveOnRead,
+ key.HistorySaveOnRead,
true,
"Save history on chapter read",
},
{
- constant.HistorySaveOnDownload,
+ key.HistorySaveOnDownload,
false,
"Save history on chapter download",
},
{
- constant.SearchShowQuerySuggestions,
+ key.SearchShowQuerySuggestions,
true,
"Show query suggestions in when searching",
},
{
- constant.MangadexLanguage,
+ key.MangadexLanguage,
"en",
`Preferred language for mangadex
Use "any" to show all languages`,
},
{
- constant.MangadexNSFW,
+ key.MangadexNSFW,
false,
"Show NSFW content",
},
{
- constant.MangadexShowUnavailableChapters,
+ key.MangadexShowUnavailableChapters,
false,
"Show chapters that cannot be downloaded",
},
{
- constant.InstallerUser,
+ key.InstallerUser,
"metafates",
"Custom scrapers repository owner",
},
{
- constant.InstallerRepo,
+ key.InstallerRepo,
"mangal-scrapers",
"Custom scrapers repository name",
},
{
- constant.InstallerBranch,
+ key.InstallerBranch,
"main",
"Custom scrapers repository branch",
},
{
- constant.GenAuthor,
+ key.GenAuthor,
"",
"Key to use in generated scrapers as author",
},
{
- constant.LogsWrite,
+ key.LogsWrite,
false,
"Write logs",
},
{
- constant.LogsLevel,
+ key.LogsLevel,
"info",
`Available options are: (from less to most verbose)
panic, fatal, error, warn, info, debug, trace`,
},
{
- constant.LogsJson,
+ key.LogsJson,
false,
"Use json format for logs",
},
{
- constant.AnilistEnable,
+ key.AnilistEnable,
false,
"Enable Anilist integration",
},
{
- constant.AnilistCode,
+ key.AnilistCode,
"",
"Anilist code to use for authentication",
},
{
- constant.AnilistID,
+ key.AnilistID,
"",
"Anilist ID to use for authentication",
},
{
- constant.AnilistSecret,
+ key.AnilistSecret,
"",
"Anilist secret to use for authentication",
},
{
- constant.AnilistLinkOnMangaSelect,
+ key.AnilistLinkOnMangaSelect,
true,
"Show link to Anilist on manga select",
},
{
- constant.TUIItemSpacing,
+ key.TUIItemSpacing,
1,
"Spacing between items in the TUI",
},
{
- constant.TUIReadOnEnter,
+ key.TUIReadOnEnter,
true,
"Read chapter on enter if other chapters aren't selected",
},
{
- constant.TUISearchPromptString,
+ key.TUISearchPromptString,
"> ",
"Search prompt string to use",
},
{
- constant.TUIShowURLs,
+ key.TUIShowURLs,
true,
"Show URLs under list items",
},
{
- constant.TUIReverseChapters,
+ key.TUIReverseChapters,
false,
"Reverse chapters order",
},
{
- constant.TUIShowDownloadedPath,
+ key.TUIShowDownloadedPath,
true,
"Show path where chapters were downloaded",
},
+ {
+ key.CliColored,
+ true,
+ "Use colors in CLI help page",
+ },
}
func init() {
@@ -364,9 +424,9 @@ func init() {
count++
}
- if count != constant.DefinedFieldsCount {
- panic(fmt.Sprintf("Expected %d default values, got %d", constant.DefinedFieldsCount, count))
+ if count != key.DefinedFieldsCount {
+ panic(fmt.Sprintf("Expected %d default values, got %d", key.DefinedFieldsCount, count))
}
}
-var Default = make(map[string]Field, constant.DefinedFieldsCount)
+var Default = make(map[string]Field, key.DefinedFieldsCount)
diff --git a/constant/meta.go b/constant/meta.go
index 233a338e..3146c864 100644
--- a/constant/meta.go
+++ b/constant/meta.go
@@ -2,6 +2,6 @@ package constant
const (
Mangal = "mangal"
- Version = "4.0.4"
+ Version = "4.0.5"
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
)
diff --git a/constant/template.go b/constant/template.go
index b10bc17f..31d243ac 100644
--- a/constant/template.go
+++ b/constant/template.go
@@ -14,6 +14,9 @@ const SourceTemplate = `{{ $divider := repeat "-" (plus (max (len .URL) (len .Na
{{ $divider }}
+---@alias manga { name: string, url: string, author: string|nil, genres: string|nil, summary: string|nil }
+---@alias chapter { name: string, url: string, volume: string|nil, manga_summary: string|nil, manga_author: string|nil, manga_genres: string|nil }
+---@alias page { url: string, index: number }
----- IMPORTS -----
@@ -30,46 +33,24 @@ const SourceTemplate = `{{ $divider := repeat "-" (plus (max (len .URL) (len .Na
----- MAIN -----
--- Searches for manga with given query.
---[[
-Manga fields:
- name - string, required
- url - string, required
- author - string, optional
- genres - string (multiple genres are divided by comma ','), optional
- summary - string, optional
---]]
--- @param query Query to search for
--- @return Table of mangas
+-- @param query string Query to search for
+-- @return manga[] Table of mangas
function {{ .SearchMangaFn }}(query)
return {}
end
--- Gets the list of all manga chapters.
---[[
-Chapter fields:
- name - string, required
- url - string, required
- volume - string, optional
- manga_summary - string, optional (in case you can't get it from search page)
- manga_author - string, optional
- manga_genres - string (multiple genres are divided by comma ','), optional
---]]
--- @param mangaURL URL of the manga
--- @return Table of chapters
+-- @param mangaURL string URL of the manga
+-- @return chapter[] Table of chapters
function {{ .MangaChaptersFn }}(mangaURL)
return {}
end
--- Gets the list of all pages of a chapter.
---[[
-Page fields:
- url - string, required
- index - uint, required
---]]
--- @param chapterURL URL of the chapter
--- @return Table of pages
+-- @param chapterURL string URL of the chapter
+-- @return page[]
function {{ .ChapterPagesFn }}(chapterURL)
return {}
end
diff --git a/converter/cbz/cbz.go b/converter/cbz/cbz.go
index dbb6390d..6fe479da 100644
--- a/converter/cbz/cbz.go
+++ b/converter/cbz/cbz.go
@@ -4,8 +4,8 @@ import (
"archive/zip"
"bytes"
"encoding/xml"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/util"
"github.com/spf13/viper"
@@ -57,7 +57,7 @@ func SaveTo(chapter *source.Chapter, to string) error {
}
}
- if viper.GetBool(constant.MetadataComicInfoXML) {
+ if viper.GetBool(key.MetadataComicInfoXML) {
comicInfo := chapter.ComicInfo()
marshalled, err := xml.MarshalIndent(comicInfo, "", " ")
if err == nil {
diff --git a/converter/cbz/cbz_test.go b/converter/cbz/cbz_test.go
index 9525e585..7f4feb59 100644
--- a/converter/cbz/cbz_test.go
+++ b/converter/cbz/cbz_test.go
@@ -6,6 +6,7 @@ import (
"github.com/metafates/mangal/config"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/samber/lo"
. "github.com/smartystreets/goconvey/convey"
@@ -18,7 +19,7 @@ import (
func init() {
filesystem.SetMemMapFs()
lo.Must0(config.Setup())
- viper.Set(constant.FormatsUse, constant.FormatCBZ)
+ viper.Set(key.FormatsUse, constant.FormatCBZ)
}
func TestCBZ(t *testing.T) {
diff --git a/converter/pdf/pdf.go b/converter/pdf/pdf.go
index 0123a9ab..18d98028 100644
--- a/converter/pdf/pdf.go
+++ b/converter/pdf/pdf.go
@@ -1,8 +1,8 @@
package pdf
import (
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/util"
"github.com/pdfcpu/pdfcpu/pkg/api"
@@ -74,7 +74,7 @@ func pagesToPDF(w io.Writer, pages []*source.Page) error {
indRef, err := pdfcpu.NewPageForImage(ctx.XRefTable, r, pagesIndRef, imp)
if err != nil {
- if viper.GetBool(constant.FormatsSkipUnsupportedImages) {
+ if viper.GetBool(key.FormatsSkipUnsupportedImages) {
continue
}
diff --git a/converter/pdf/pdf_test.go b/converter/pdf/pdf_test.go
index 35410579..87fd8ba2 100644
--- a/converter/pdf/pdf_test.go
+++ b/converter/pdf/pdf_test.go
@@ -5,6 +5,7 @@ import (
"github.com/metafates/mangal/config"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/samber/lo"
. "github.com/smartystreets/goconvey/convey"
@@ -17,7 +18,7 @@ import (
func init() {
filesystem.SetMemMapFs()
lo.Must0(config.Setup())
- viper.Set(constant.FormatsUse, constant.FormatPDF)
+ viper.Set(key.FormatsUse, constant.FormatPDF)
}
func TestPDF(t *testing.T) {
diff --git a/converter/zip/zip_test.go b/converter/zip/zip_test.go
index b3b38b29..22e78959 100644
--- a/converter/zip/zip_test.go
+++ b/converter/zip/zip_test.go
@@ -6,6 +6,7 @@ import (
"github.com/metafates/mangal/config"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/samber/lo"
. "github.com/smartystreets/goconvey/convey"
@@ -18,7 +19,7 @@ import (
func init() {
filesystem.SetMemMapFs()
lo.Must0(config.Setup())
- viper.Set(constant.FormatsUse, constant.FormatZIP)
+ viper.Set(key.FormatsUse, constant.FormatZIP)
}
func TestCBZ(t *testing.T) {
diff --git a/downloader/download.go b/downloader/download.go
index 84fcd41a..0d597b05 100644
--- a/downloader/download.go
+++ b/downloader/download.go
@@ -4,10 +4,10 @@ import (
"encoding/json"
"fmt"
"github.com/metafates/mangal/color"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/converter"
"github.com/metafates/mangal/filesystem"
"github.com/metafates/mangal/history"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/style"
@@ -25,7 +25,7 @@ func Download(chapter *source.Chapter, progress func(string)) (string, error) {
return "", err
}
- if viper.GetBool(constant.DownloaderRedownloadExisting) {
+ if viper.GetBool(key.DownloaderRedownloadExisting) {
log.Info("chapter already downloaded, deleting and redownloading")
err = filesystem.Api().Remove(path)
if err != nil {
@@ -53,14 +53,14 @@ func Download(chapter *source.Chapter, progress func(string)) (string, error) {
return "", err
}
- if viper.GetBool(constant.MetadataFetchAnilist) {
+ if viper.GetBool(key.MetadataFetchAnilist) {
err := chapter.Manga.PopulateMetadata(progress)
if err != nil {
log.Warn(err)
}
}
- if viper.GetBool(constant.MetadataSeriesJSON) {
+ if viper.GetBool(key.MetadataSeriesJSON) {
path, err := chapter.Manga.Path(false)
if err != nil {
log.Warn(err)
@@ -80,34 +80,34 @@ func Download(chapter *source.Chapter, progress func(string)) (string, error) {
}
}
- if viper.GetBool(constant.DownloaderDownloadCover) {
+ if viper.GetBool(key.DownloaderDownloadCover) {
coverDir, err := chapter.Manga.Path(false)
if err == nil {
_ = chapter.Manga.DownloadCover(false, coverDir, progress)
}
}
- log.Info("getting " + viper.GetString(constant.FormatsUse) + " converter")
+ log.Info("getting " + viper.GetString(key.FormatsUse) + " converter")
progress(fmt.Sprintf(
"Converting %d pages to %s %s",
len(pages),
- style.Fg(color.Yellow)(viper.GetString(constant.FormatsUse)),
+ style.Fg(color.Yellow)(viper.GetString(key.FormatsUse)),
style.Faint(chapter.SizeHuman())),
)
- conv, err := converter.Get(viper.GetString(constant.FormatsUse))
+ conv, err := converter.Get(viper.GetString(key.FormatsUse))
if err != nil {
log.Error(err)
return "", err
}
- log.Info("converting " + viper.GetString(constant.FormatsUse))
+ log.Info("converting " + viper.GetString(key.FormatsUse))
path, err = conv.Save(chapter)
if err != nil {
log.Error(err)
return "", err
}
- if viper.GetBool(constant.HistorySaveOnDownload) {
+ if viper.GetBool(key.HistorySaveOnDownload) {
go func() {
err = history.Save(chapter)
if err != nil {
diff --git a/downloader/read.go b/downloader/read.go
index 8f954bb7..3a8223f6 100644
--- a/downloader/read.go
+++ b/downloader/read.go
@@ -6,6 +6,7 @@ import (
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/converter"
"github.com/metafates/mangal/history"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/open"
"github.com/metafates/mangal/source"
@@ -16,14 +17,14 @@ import (
// Read the chapter by downloading it with the given source
// and opening it with the configured reader.
func Read(chapter *source.Chapter, progress func(string)) error {
- if viper.GetBool(constant.ReaderReadInBrowser) {
+ if viper.GetBool(key.ReaderReadInBrowser) {
return open.StartWith(
chapter.URL,
- viper.GetString(constant.ReaderBrowser),
+ viper.GetString(key.ReaderBrowser),
)
}
- if viper.GetBool(constant.DownloaderReadDownloaded) && chapter.IsDownloaded() {
+ if viper.GetBool(key.DownloaderReadDownloaded) && chapter.IsDownloaded() {
path, err := chapter.Path(false)
if err == nil {
return openRead(path, chapter, progress)
@@ -45,18 +46,18 @@ func Read(chapter *source.Chapter, progress func(string)) error {
return err
}
- log.Info("getting " + viper.GetString(constant.FormatsUse) + " converter")
- conv, err := converter.Get(viper.GetString(constant.FormatsUse))
+ log.Info("getting " + viper.GetString(key.FormatsUse) + " converter")
+ conv, err := converter.Get(viper.GetString(key.FormatsUse))
if err != nil {
log.Error(err)
return err
}
- log.Info("converting " + viper.GetString(constant.FormatsUse))
+ log.Info("converting " + viper.GetString(key.FormatsUse))
progress(fmt.Sprintf(
"Converting %d pages to %s %s",
len(pages),
- style.Fg(color.Yellow)(viper.GetString(constant.FormatsUse)),
+ style.Fg(color.Yellow)(viper.GetString(key.FormatsUse)),
style.Faint(chapter.SizeHuman())),
)
path, err := conv.SaveTemp(chapter)
@@ -76,7 +77,7 @@ func Read(chapter *source.Chapter, progress func(string)) error {
}
func openRead(path string, chapter *source.Chapter, progress func(string)) error {
- if viper.GetBool(constant.HistorySaveOnRead) {
+ if viper.GetBool(key.HistorySaveOnRead) {
go func() {
err := history.Save(chapter)
if err != nil {
@@ -92,15 +93,15 @@ func openRead(path string, chapter *source.Chapter, progress func(string)) error
err error
)
- switch viper.GetString(constant.FormatsUse) {
+ switch viper.GetString(key.FormatsUse) {
case constant.FormatPDF:
- reader = viper.GetString(constant.ReaderPDF)
+ reader = viper.GetString(key.ReaderPDF)
case constant.FormatCBZ:
- reader = viper.GetString(constant.ReaderCBZ)
+ reader = viper.GetString(key.ReaderCBZ)
case constant.FormatZIP:
- reader = viper.GetString(constant.ReaderZIP)
+ reader = viper.GetString(key.ReaderZIP)
case constant.FormatPlain:
- reader = viper.GetString(constant.RaderPlain)
+ reader = viper.GetString(key.RaderPlain)
}
if reader != "" {
diff --git a/go.mod b/go.mod
index 31d73120..64172521 100644
--- a/go.mod
+++ b/go.mod
@@ -6,12 +6,12 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/PuerkitoBio/goquery v1.8.0
github.com/charmbracelet/bubbles v0.14.0
- github.com/charmbracelet/bubbletea v0.22.1
+ github.com/charmbracelet/bubbletea v0.23.1
github.com/charmbracelet/lipgloss v0.6.0
github.com/darylhjd/mangodex v0.0.0-20211231093527-e4a91c518fa0
github.com/dustin/go-humanize v1.0.0
github.com/gocolly/colly/v2 v2.1.0
- github.com/invopop/jsonschema v0.6.0
+ github.com/invopop/jsonschema v0.7.0
github.com/ivanpirog/coloredcobra v1.0.1
github.com/ka-weihe/fast-levenshtein v0.0.0-20201227151214-4c99ee36a1ba
github.com/lithammer/fuzzysearch v1.1.5
@@ -19,23 +19,23 @@ require (
github.com/metafates/mangal-lua-libs v0.4.2
github.com/muesli/reflow v0.3.0
github.com/pdfcpu/pdfcpu v0.3.13
- github.com/samber/lo v1.33.0
- github.com/samber/mo v1.5.1
+ github.com/samber/lo v1.37.0
+ github.com/samber/mo v1.7.0
github.com/sirupsen/logrus v1.9.0
github.com/smartystreets/goconvey v1.7.2
- github.com/spf13/afero v1.9.2
+ github.com/spf13/afero v1.9.3
github.com/spf13/cobra v1.6.1
- github.com/spf13/viper v1.13.0
- github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
- golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
- golang.org/x/term v0.1.0
+ github.com/spf13/viper v1.14.0
+ github.com/yuin/gopher-lua v0.0.0-20221210110428-332342483e3f
+ golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15
+ golang.org/x/term v0.3.0
)
require (
github.com/alessio/shellescape v1.4.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/antchfx/htmlquery v1.2.5 // indirect
- github.com/antchfx/xmlquery v1.3.12 // indirect
+ github.com/antchfx/xmlquery v1.3.13 // indirect
github.com/antchfx/xpath v1.2.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
@@ -44,7 +44,7 @@ require (
github.com/containerd/console v1.0.3 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
- github.com/go-rod/rod v0.112.0 // indirect
+ github.com/go-rod/rod v0.112.2 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
@@ -53,12 +53,12 @@ require (
github.com/hhrutter/lzw v0.0.0-20190829144645-6f07a24e8650 // indirect
github.com/hhrutter/tiff v0.0.0-20190829141212-736cae8d0bc7 // indirect
github.com/iancoleman/orderedmap v0.2.0 // indirect
- github.com/inconshreveable/mousetrap v1.0.1 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
- github.com/magiconair/properties v1.8.6 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
@@ -66,13 +66,13 @@ require (
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/montanaflynn/stats v0.6.6 // indirect
- github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
+ github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.13.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
- github.com/pelletier/go-toml/v2 v2.0.5 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
- github.com/rivo/uniseg v0.4.2 // indirect
+ github.com/rivo/uniseg v0.4.3 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
github.com/smartystreets/assertions v1.2.0 // indirect
@@ -82,13 +82,13 @@ require (
github.com/subosito/gotenv v1.4.1 // indirect
github.com/temoto/robotstxt v1.1.2 // indirect
github.com/ysmood/goob v0.4.0 // indirect
- github.com/ysmood/gson v0.7.2 // indirect
+ github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.8.0 // indirect
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 // indirect
- golang.org/x/image v0.1.0 // indirect
- golang.org/x/net v0.1.0 // indirect
- golang.org/x/sys v0.1.0 // indirect
- golang.org/x/text v0.4.0 // indirect
+ golang.org/x/image v0.2.0 // indirect
+ golang.org/x/net v0.4.0 // indirect
+ golang.org/x/sys v0.3.0 // indirect
+ golang.org/x/text v0.5.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
diff --git a/go.sum b/go.sum
index ad098733..3f0ff953 100644
--- a/go.sum
+++ b/go.sum
@@ -59,6 +59,8 @@ github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61c
github.com/antchfx/xmlquery v1.2.4/go.mod h1:KQQuESaxSlqugE2ZBcM/qn+ebIpt+d+4Xx7YcSGAIrM=
github.com/antchfx/xmlquery v1.3.12 h1:6TMGpdjpO/P8VhjnaYPXuqT3qyJ/VsqoyNTmJzNBTQ4=
github.com/antchfx/xmlquery v1.3.12/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ=
+github.com/antchfx/xmlquery v1.3.13 h1:wqhTv2BN5MzYg9rnPVtZb3IWP8kW6WV/ebAY0FCTI7Y=
+github.com/antchfx/xmlquery v1.3.13/go.mod h1:3w2RvQvTz+DaT5fSgsELkSJcdNgkmg6vuXDEuhdwsPQ=
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.1.8/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
@@ -78,6 +80,8 @@ github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWo
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
github.com/charmbracelet/bubbletea v0.22.1 h1:z66q0LWdJNOWEH9zadiAIXp2GN1AWrwNXU8obVY9X24=
github.com/charmbracelet/bubbletea v0.22.1/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0=
+github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck=
+github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
@@ -122,6 +126,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-rod/rod v0.112.0 h1:U9Yc+quw4hxZ6GrdbWFBeylvaYElEKM9ijFW2LYkGlA=
github.com/go-rod/rod v0.112.0/go.mod h1:GZDtmEs6RpF6kBRYpGCZXxXlKNneKVPiKOjaMbmVVjE=
+github.com/go-rod/rod v0.112.2 h1:dwauKYC/H2em8/BcGk3gC0LTzZHf5MIDKf2DVM4z9gU=
+github.com/go-rod/rod v0.112.2/go.mod h1:ElViL9ABbcshNQw93+11FrYRH92RRhMKleuILo6+5V0=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gocolly/colly v1.2.0 h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI=
@@ -210,8 +216,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/jsonschema v0.6.0 h1:8e+xY8ZEn8gDHUYylSlLHy22P+SLeIRIHv3nM3hCbmY=
github.com/invopop/jsonschema v0.6.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
+github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So=
+github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/ivanpirog/coloredcobra v1.0.1 h1:aURSdEmlR90/tSiWS0dMjdwOvCVUeYLfltLfbgNxrN4=
github.com/ivanpirog/coloredcobra v1.0.1/go.mod h1:iho4nEKcnwZFiniGSdcgdvRgZNjxm+h20acv8vqmN6Q=
github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg=
@@ -241,6 +251,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -273,6 +285,8 @@ github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a h1:jlDOeO5TU0pYlbc/y6PFguab5IjANI0Knrpg3u/ton4=
+github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
@@ -289,6 +303,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
+github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
+github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -299,6 +315,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
+github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -308,8 +326,16 @@ github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxT
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/samber/lo v1.33.0 h1:2aKucr+rQV6gHpY3bpeZu69uYoQOzVhGT3J22Op6Cjk=
github.com/samber/lo v1.33.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
+github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw=
+github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
+github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw=
+github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA=
github.com/samber/mo v1.5.1 h1:5dRSevAB33Q/OrYwTmtksHHxquuf2urnRSUTsdTFysY=
github.com/samber/mo v1.5.1/go.mod h1:pDuQgWscOVGGoEz+NAeth/Xq+MPAcXxCeph1XIAm/DU=
+github.com/samber/mo v1.5.2 h1:MINtAxMiorTmlWWPmd8LBms0OoHZJsEEBY5yI/DXFa8=
+github.com/samber/mo v1.5.2/go.mod h1:pDuQgWscOVGGoEz+NAeth/Xq+MPAcXxCeph1XIAm/DU=
+github.com/samber/mo v1.7.0 h1:wYI97e2+CHUvhkRGK1dl5FWpv/XDieaEYIAEJ9XVu2o=
+github.com/samber/mo v1.7.0/go.mod h1:gELW3aXN9Utq0gz969NbLMeZo6dkUW8QTohmafdFEEA=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
@@ -318,6 +344,8 @@ github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hg
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
+github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
+github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
@@ -329,9 +357,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
+github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
+github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -342,6 +373,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
@@ -352,11 +384,15 @@ github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
github.com/ysmood/got v0.31.3 h1:UvvF+TDVsZLO7MSzm/Bd/H4HVp+7S5YwsxgdwaKq8uA=
github.com/ysmood/got v0.31.3/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
+github.com/ysmood/got v0.32.0 h1:aAHdQgfgMb/lo4v+OekM+SSqEJYFI035h5YYvLXsVyU=
+github.com/ysmood/got v0.32.0/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY=
github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.7.1/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/gson v0.7.2 h1:1iWUvpi5DPvd2j59W7ifRPR9DiAZ3Ga+fmMl1mJrRbM=
github.com/ysmood/gson v0.7.2/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
+github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
+github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak=
github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs=
@@ -368,6 +404,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
+github.com/yuin/gopher-lua v0.0.0-20221210110428-332342483e3f h1:wihIB0V/mGpVYrL8I7n/WxVqWnP07CBXZ5uCgxUP1tI=
+github.com/yuin/gopher-lua v0.0.0-20221210110428-332342483e3f/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -396,11 +434,19 @@ golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4=
+golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20221208044002-44028be4359e h1:lTjJJUAuWTLRn0pXoNLiVZIFYOIpvmg3MxmZxgO09bM=
+golang.org/x/exp v0.0.0-20221208044002-44028be4359e/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 h1:5oN1Pz/eDhCpbMbLstvIPa0b/BEQo6g6nwV3pLjfM6w=
+golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190823064033-3a9bac650e44/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
+golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ=
+golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -462,6 +508,10 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -532,11 +582,19 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -547,6 +605,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/history/history.go b/history/history.go
index 4c0d0c66..235f3397 100644
--- a/history/history.go
+++ b/history/history.go
@@ -2,9 +2,9 @@ package history
import (
"github.com/metafates/gache"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
"github.com/metafates/mangal/integration"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/where"
@@ -35,7 +35,7 @@ func Get() (chapters map[string]*SavedChapter, err error) {
// Save saves the chapter to the history file
func Save(chapter *source.Chapter) error {
- if viper.GetBool(constant.AnilistEnable) {
+ if viper.GetBool(key.AnilistEnable) {
go func() {
log.Info("Saving chapter to anilist")
err := integration.Anilist.MarkRead(chapter)
diff --git a/icon/icon.go b/icon/icon.go
index 89b181d4..08f6b736 100644
--- a/icon/icon.go
+++ b/icon/icon.go
@@ -1,7 +1,7 @@
package icon
import (
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/spf13/viper"
)
@@ -26,7 +26,7 @@ type iconDef struct {
}
func (i *iconDef) Get() string {
- switch viper.GetString(constant.IconsVariant) {
+ switch viper.GetString(key.IconsVariant) {
case emoji:
return i.emoji
case nerd:
diff --git a/icon/icon_test.go b/icon/icon_test.go
index 3ef3fb69..78d54dd4 100644
--- a/icon/icon_test.go
+++ b/icon/icon_test.go
@@ -1,7 +1,7 @@
package icon
import (
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
. "github.com/smartystreets/goconvey/convey"
"github.com/spf13/viper"
"testing"
@@ -11,7 +11,7 @@ func TestGet(t *testing.T) {
Convey("Given a icon", t, func() {
i := Lua
Convey("When getting the icon with emoji setting", func() {
- viper.Set(constant.IconsVariant, emoji)
+ viper.Set(key.IconsVariant, emoji)
result := Get(i)
Convey("Then the result should be emoji icon", func() {
So(result, ShouldEqual, icons[i].emoji)
@@ -19,7 +19,7 @@ func TestGet(t *testing.T) {
})
Convey("When getting the icon with nerd setting", func() {
- viper.Set(constant.IconsVariant, nerd)
+ viper.Set(key.IconsVariant, nerd)
result := Get(i)
Convey("Then the result should be nerd icon", func() {
So(result, ShouldEqual, icons[i].nerd)
@@ -27,7 +27,7 @@ func TestGet(t *testing.T) {
})
Convey("When getting the icon with plain setting", func() {
- viper.Set(constant.IconsVariant, plain)
+ viper.Set(key.IconsVariant, plain)
result := Get(i)
Convey("Then the result should be plain icon", func() {
So(result, ShouldEqual, icons[i].plain)
@@ -35,7 +35,7 @@ func TestGet(t *testing.T) {
})
Convey("When getting the icon with kaomoji setting", func() {
- viper.Set(constant.IconsVariant, kaomoji)
+ viper.Set(key.IconsVariant, kaomoji)
result := Get(i)
Convey("Then the result should be kaomoji icon", func() {
So(result, ShouldEqual, icons[i].kaomoji)
@@ -43,7 +43,7 @@ func TestGet(t *testing.T) {
})
Convey("When getting the icon with no setting", func() {
- viper.Set(constant.IconsVariant, "")
+ viper.Set(key.IconsVariant, "")
result := Get(i)
Convey("Then the result should be empty icon", func() {
So(result, ShouldBeEmpty)
diff --git a/inline/inline.go b/inline/inline.go
index 44d2ff22..26ad0c6a 100644
--- a/inline/inline.go
+++ b/inline/inline.go
@@ -1,8 +1,8 @@
package inline
import (
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/downloader"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/source"
"github.com/spf13/viper"
@@ -25,7 +25,7 @@ func Run(options *Options) (err error) {
}
if options.MangaPicker.IsAbsent() && options.ChaptersFilter.IsAbsent() {
- if viper.GetBool(constant.MetadataFetchAnilist) {
+ if viper.GetBool(key.MetadataFetchAnilist) {
for _, manga := range mangas {
_ = manga.PopulateMetadata(func(string) {})
}
@@ -119,8 +119,12 @@ func Run(options *Options) (err error) {
for _, chapter := range chapters {
if options.Download {
path, err := downloader.Download(chapter, func(string) {})
- if err != nil && viper.GetBool(constant.DownloaderStopOnError) {
- return err
+ if err != nil {
+ if viper.GetBool(key.DownloaderStopOnError) {
+ return err
+ }
+
+ continue
}
_, err = options.Out.Write([]byte(path + "\n"))
diff --git a/inline/json.go b/inline/json.go
index 42c9b6ff..96a41e38 100644
--- a/inline/json.go
+++ b/inline/json.go
@@ -3,7 +3,7 @@ package inline
import (
"encoding/json"
"github.com/metafates/mangal/anilist"
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/spf13/viper"
)
@@ -79,7 +79,7 @@ func prepareManga(manga *source.Manga, options *Options) error {
manga.Chapters = make([]*source.Chapter, 0)
}
- if viper.GetBool(constant.MetadataFetchAnilist) {
+ if viper.GetBool(key.MetadataFetchAnilist) {
_ = manga.PopulateMetadata(func(string) {})
}
diff --git a/installer/collector.go b/installer/collector.go
index d2a3c96d..e0becec1 100644
--- a/installer/collector.go
+++ b/installer/collector.go
@@ -1,7 +1,7 @@
package installer
import (
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/util"
"github.com/samber/lo"
"github.com/spf13/viper"
@@ -36,8 +36,8 @@ func Scrapers() ([]*Scraper, error) {
func setupCollector() {
collector = &githubFilesCollector{
- user: viper.GetString(constant.InstallerUser),
- repo: viper.GetString(constant.InstallerRepo),
- branch: viper.GetString(constant.InstallerBranch),
+ user: viper.GetString(key.InstallerUser),
+ repo: viper.GetString(key.InstallerRepo),
+ branch: viper.GetString(key.InstallerBranch),
}
}
diff --git a/integration/anilist/anilist.go b/integration/anilist/anilist.go
index 078c1933..2238a782 100644
--- a/integration/anilist/anilist.go
+++ b/integration/anilist/anilist.go
@@ -1,7 +1,7 @@
package anilist
import (
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/spf13/viper"
)
@@ -15,15 +15,15 @@ func New() *Anilist {
}
func (a *Anilist) id() string {
- return viper.GetString(constant.AnilistID)
+ return viper.GetString(key.AnilistID)
}
func (a *Anilist) secret() string {
- return viper.GetString(constant.AnilistSecret)
+ return viper.GetString(key.AnilistSecret)
}
func (a *Anilist) code() string {
- return viper.GetString(constant.AnilistCode)
+ return viper.GetString(key.AnilistCode)
}
// AuthURL returns the URL to authenticate with Anilist
diff --git a/constant/config.go b/key/keys.go
similarity index 97%
rename from constant/config.go
rename to key/keys.go
index 6add2886..2b139c16 100644
--- a/constant/config.go
+++ b/key/keys.go
@@ -1,9 +1,9 @@
-package constant
+package key
// DefinedFieldsCount is the number of fields defined in this package.
// You have to manually update this number when you add a new field
// to check later if every field has a defined default value
-const DefinedFieldsCount = 51
+const DefinedFieldsCount = 52
const (
DownloaderPath = "downloader.path"
@@ -97,3 +97,7 @@ const (
LogsLevel = "logs.level"
LogsJson = "logs.json"
)
+
+const (
+ CliColored = "cli.colored"
+)
diff --git a/log/log.go b/log/log.go
index 61612cb5..54b63683 100644
--- a/log/log.go
+++ b/log/log.go
@@ -3,8 +3,8 @@ package log
import (
"errors"
"fmt"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/where"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
@@ -17,7 +17,7 @@ import (
var writeLogs bool
func Setup() error {
- writeLogs = viper.GetBool(constant.LogsWrite)
+ writeLogs = viper.GetBool(key.LogsWrite)
if !writeLogs {
return nil
@@ -41,13 +41,13 @@ func Setup() error {
log.SetOutput(logFile)
- if viper.GetBool(constant.LogsJson) {
+ if viper.GetBool(key.LogsJson) {
log.SetFormatter(&log.JSONFormatter{PrettyPrint: true})
} else {
log.SetFormatter(&log.TextFormatter{})
}
- switch viper.GetString(constant.LogsLevel) {
+ switch viper.GetString(key.LogsLevel) {
case "panic":
log.SetLevel(log.PanicLevel)
case "fatal":
diff --git a/mini/states.go b/mini/states.go
index a39db722..7028f5a8 100644
--- a/mini/states.go
+++ b/mini/states.go
@@ -2,9 +2,9 @@ package mini
import (
"fmt"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/downloader"
"github.com/metafates/mangal/history"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/util"
@@ -32,7 +32,7 @@ const (
func (m *mini) handleSourceSelectState() error {
var err error
- if name := viper.GetString(constant.DownloaderDefaultSources); name != "" {
+ if name := viper.GetString(key.DownloaderDefaultSources); name != "" {
p, ok := provider.Get(name)
if !ok {
return fmt.Errorf("unknown source \"%s\"", name)
@@ -91,7 +91,7 @@ func (m *mini) handleMangaSearchState() error {
erase := progress("Searching Query..")
m.cachedMangas[query], err = m.selectedSource.Search(query)
- max := lo.Min([]int{len(m.cachedMangas[query]), viper.GetInt(constant.MiniSearchLimit)})
+ max := lo.Min([]int{len(m.cachedMangas[query]), viper.GetInt(key.MiniSearchLimit)})
m.cachedMangas[query] = m.cachedMangas[query][:max]
erase()
@@ -324,7 +324,7 @@ func (m *mini) handleChaptersDownloadState() error {
erase()
- if err != nil && viper.GetBool(constant.DownloaderStopOnError) {
+ if err != nil && viper.GetBool(key.DownloaderStopOnError) {
return err
}
diff --git a/provider/mangadex/chapters.go b/provider/mangadex/chapters.go
index 35985398..5255ea36 100644
--- a/provider/mangadex/chapters.go
+++ b/provider/mangadex/chapters.go
@@ -3,7 +3,7 @@ package mangadex
import (
"fmt"
"github.com/darylhjd/mangodex"
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/spf13/viper"
"golang.org/x/exp/slices"
@@ -27,7 +27,7 @@ func (m *Mangadex) ChaptersOf(manga *source.Manga) ([]*source.Chapter, error) {
params.Add("contentRating[]", rating)
}
- if viper.GetBool(constant.MangadexNSFW) {
+ if viper.GetBool(key.MangadexNSFW) {
params.Add("contentRating[]", mangodex.Porn)
params.Add("contentRating[]", mangodex.Erotica)
}
@@ -41,7 +41,7 @@ func (m *Mangadex) ChaptersOf(manga *source.Manga) ([]*source.Chapter, error) {
currOffset = 0
)
- language := viper.GetString(constant.MangadexLanguage)
+ language := viper.GetString(key.MangadexLanguage)
for {
params.Set("offset", strconv.Itoa(currOffset))
@@ -52,7 +52,7 @@ func (m *Mangadex) ChaptersOf(manga *source.Manga) ([]*source.Chapter, error) {
for i, chapter := range list.Data {
// Skip external chapters. Their pages cannot be downloaded.
- if chapter.Attributes.ExternalURL != nil && !viper.GetBool(constant.MangadexShowUnavailableChapters) {
+ if chapter.Attributes.ExternalURL != nil && !viper.GetBool(key.MangadexShowUnavailableChapters) {
continue
}
diff --git a/provider/mangadex/search.go b/provider/mangadex/search.go
index b3c839c0..a589d72e 100644
--- a/provider/mangadex/search.go
+++ b/provider/mangadex/search.go
@@ -3,7 +3,7 @@ package mangadex
import (
"fmt"
"github.com/darylhjd/mangodex"
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/source"
"github.com/spf13/viper"
"log"
@@ -29,7 +29,7 @@ func (m *Mangadex) Search(query string) ([]*source.Manga, error) {
params.Add("contentRating[]", rating)
}
- if viper.GetBool(constant.MangadexNSFW) {
+ if viper.GetBool(key.MangadexNSFW) {
params.Add("contentRating[]", mangodex.Porn)
params.Add("contentRating[]", mangodex.Erotica)
}
@@ -47,7 +47,7 @@ func (m *Mangadex) Search(query string) ([]*source.Manga, error) {
for i, manga := range mangaList.Data {
m := source.Manga{
- Name: manga.GetTitle(viper.GetString(constant.MangadexLanguage)),
+ Name: manga.GetTitle(viper.GetString(key.MangadexLanguage)),
URL: fmt.Sprintf("https://mangadex.org/title/%s", manga.ID),
Index: uint16(i),
ID: manga.ID,
diff --git a/provider/provider.go b/provider/provider.go
index 505a5e2c..42cdb6f6 100644
--- a/provider/provider.go
+++ b/provider/provider.go
@@ -51,6 +51,7 @@ func Customs() []*Provider {
[]byte("require(\"headless\")"),
[]byte("require('headless')"),
[]byte("require(headless)"),
+ []byte("require'headless'"),
})
name := util.FileStem(path)
diff --git a/query/suggest.go b/query/suggest.go
index 0459186d..16bc302f 100644
--- a/query/suggest.go
+++ b/query/suggest.go
@@ -2,7 +2,7 @@ package query
import (
"github.com/lithammer/fuzzysearch/fuzzy"
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/samber/lo"
"github.com/samber/mo"
"github.com/spf13/viper"
@@ -14,7 +14,7 @@ var (
)
func SuggestMany(query string) []string {
- if !viper.GetBool(constant.SearchShowQuerySuggestions) {
+ if !viper.GetBool(key.SearchShowQuerySuggestions) {
return []string{}
}
diff --git a/source/chapter.go b/source/chapter.go
index 2dc3a816..2db74035 100644
--- a/source/chapter.go
+++ b/source/chapter.go
@@ -5,6 +5,7 @@ import (
"github.com/dustin/go-humanize"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/style"
"github.com/metafates/mangal/util"
"github.com/samber/mo"
@@ -58,6 +59,10 @@ func (c *Chapter) DownloadPages(temp bool, progress func(string)) (err error) {
wg.Add(len(c.Pages))
for _, page := range c.Pages {
+ if page == nil {
+ return fmt.Errorf("page #%d is empty, aborting download", page.Index)
+ }
+
d := func(page *Page) {
defer wg.Done()
@@ -71,7 +76,7 @@ func (c *Chapter) DownloadPages(temp bool, progress func(string)) (err error) {
progress(status())
}
- if viper.GetBool(constant.DownloaderAsync) {
+ if viper.GetBool(key.DownloaderAsync) {
go d(page)
} else {
d(page)
@@ -79,13 +84,19 @@ func (c *Chapter) DownloadPages(temp bool, progress func(string)) (err error) {
}
wg.Wait()
- c.isDownloaded = mo.Some(!temp && err == nil)
+
+ if err != nil {
+ c.isDownloaded = mo.Some(false)
+ return err
+ }
+
+ c.isDownloaded = mo.Some(!temp)
return
}
// formattedName of the chapter according to the template in the config.
func (c *Chapter) formattedName() (name string) {
- name = viper.GetString(constant.DownloaderChapterNameTemplate)
+ name = viper.GetString(key.DownloaderChapterNameTemplate)
var sourceName string
if c.Source() != nil {
@@ -117,7 +128,7 @@ func (c *Chapter) Filename() (filename string) {
// plain format assumes that chapter is a directory with images
// rather than a single file. So no need to add extension to it
- if f := viper.GetString(constant.FormatsUse); f != constant.FormatPlain {
+ if f := viper.GetString(key.FormatsUse); f != constant.FormatPlain {
return filename + "." + f
}
@@ -155,7 +166,7 @@ func (c *Chapter) Path(temp bool) (path string, err error) {
return
}
- return c.path(manga, c.Volume != "" && viper.GetBool(constant.DownloaderCreateVolumeDir))
+ return c.path(manga, c.Volume != "" && viper.GetBool(key.DownloaderCreateVolumeDir))
}
func (c *Chapter) Source() Source {
@@ -167,8 +178,8 @@ func (c *Chapter) ComicInfo() *ComicInfo {
day, month, year int
)
- if viper.GetBool(constant.MetadataComicInfoXMLAddDate) {
- if viper.GetBool(constant.MetadataComicInfoXMLAlternativeDate) {
+ if viper.GetBool(key.MetadataComicInfoXMLAddDate) {
+ if viper.GetBool(key.MetadataComicInfoXMLAlternativeDate) {
// get current date
t := time.Now()
day = t.Day()
diff --git a/source/chapter_test.go b/source/chapter_test.go
index 92dc539b..ae85bd3c 100644
--- a/source/chapter_test.go
+++ b/source/chapter_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/util"
. "github.com/smartystreets/goconvey/convey"
"github.com/spf13/viper"
@@ -12,7 +13,7 @@ import (
func init() {
filesystem.SetMemMapFs()
- viper.Set(constant.FormatsUse, constant.FormatPDF)
+ viper.Set(key.FormatsUse, constant.FormatPDF)
}
var testChapter = Chapter{
@@ -30,7 +31,7 @@ func TestChapter_Filename(t *testing.T) {
Convey("When Filename is called", func() {
Convey("It should return a sanitized filename", func() {
const template = "&{index}! {chapter}// {volume} 28922@ {manga}"
- viper.Set(constant.DownloaderChapterNameTemplate, template)
+ viper.Set(key.DownloaderChapterNameTemplate, template)
filename := testChapter.Filename()
Convey("It should match the given template", func() {
diff --git a/source/manga.go b/source/manga.go
index d3e4a501..9ad0ccb3 100644
--- a/source/manga.go
+++ b/source/manga.go
@@ -3,8 +3,8 @@ package source
import (
"fmt"
"github.com/metafates/mangal/anilist"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/util"
"github.com/metafates/mangal/where"
@@ -103,7 +103,7 @@ func (m *Manga) Dirname() string {
func (m *Manga) peekPath() string {
path := where.Downloads()
- if viper.GetBool(constant.DownloaderCreateMangaDir) {
+ if viper.GetBool(key.DownloaderCreateMangaDir) {
path = filepath.Join(path, m.Dirname())
}
@@ -263,7 +263,7 @@ func (m *Manga) PopulateMetadata(progress func(string)) error {
var tags = make([]string, 0)
for _, tag := range manga.Tags {
- if tag.Rank >= viper.GetInt(constant.MetadataComicInfoXMLTagRelevanceThreshold) {
+ if tag.Rank >= viper.GetInt(key.MetadataComicInfoXMLTagRelevanceThreshold) {
tags = append(tags, tag.Name)
}
}
diff --git a/tui/bubble.go b/tui/bubble.go
index 0ac9a827..6054424a 100644
--- a/tui/bubble.go
+++ b/tui/bubble.go
@@ -11,9 +11,9 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/metafates/mangal/anilist"
"github.com/metafates/mangal/color"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/history"
"github.com/metafates/mangal/installer"
+ key2 "github.com/metafates/mangal/key"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/source"
"github.com/metafates/mangal/style"
@@ -196,7 +196,7 @@ func newBubble() *statefulBubble {
makeList := func(title string, description bool, options *listOptions) list.Model {
delegate := list.NewDefaultDelegate()
- delegate.SetSpacing(viper.GetInt(constant.TUIItemSpacing))
+ delegate.SetSpacing(viper.GetInt(key2.TUIItemSpacing))
delegate.ShowDescription = description
delegate.Styles.SelectedTitle = lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), false, false, false, true).
@@ -234,7 +234,7 @@ func newBubble() *statefulBubble {
bubble.inputC = textinput.New()
bubble.inputC.Placeholder = "Search"
bubble.inputC.CharLimit = 60
- bubble.inputC.Prompt = viper.GetString(constant.TUISearchPromptString)
+ bubble.inputC.Prompt = viper.GetString(key2.TUISearchPromptString)
bubble.progressC = progress.New(progress.WithDefaultGradient())
@@ -255,7 +255,7 @@ func newBubble() *statefulBubble {
})
bubble.sourcesC.SetStatusBarItemName("source", "sources")
- showURLs := viper.GetBool(constant.TUIShowURLs)
+ showURLs := viper.GetBool(key2.TUIShowURLs)
bubble.mangasC = makeList("Mangas", showURLs, &listOptions{
TitleStyle: mo.Some(
style.NewColored("#f2e8cf", "#386641").Padding(0, 1),
diff --git a/tui/handlers.go b/tui/handlers.go
index 5c98a94a..db6cbe21 100644
--- a/tui/handlers.go
+++ b/tui/handlers.go
@@ -6,9 +6,9 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/metafates/mangal/anilist"
"github.com/metafates/mangal/color"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/downloader"
"github.com/metafates/mangal/installer"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/source"
@@ -252,7 +252,7 @@ func (b *statefulBubble) downloadChapter(chapter *source.Chapter) tea.Cmd {
})
if err != nil {
- if viper.GetBool(constant.DownloaderStopOnError) {
+ if viper.GetBool(key.DownloaderStopOnError) {
b.errorChannel <- err
} else {
b.failedChapters = append(b.failedChapters, chapter)
diff --git a/tui/init.go b/tui/init.go
index af47c4dc..e44270e3 100644
--- a/tui/init.go
+++ b/tui/init.go
@@ -4,13 +4,13 @@ import (
"fmt"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
- "github.com/metafates/mangal/constant"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/provider"
"github.com/spf13/viper"
)
func (b *statefulBubble) Init() tea.Cmd {
- if names := viper.GetStringSlice(constant.DownloaderDefaultSources); b.state != historyState && len(names) != 0 {
+ if names := viper.GetStringSlice(key.DownloaderDefaultSources); b.state != historyState && len(names) != 0 {
var providers []*provider.Provider
for _, name := range names {
diff --git a/tui/keymap.go b/tui/keymap.go
index 292b0fb2..8186e25d 100644
--- a/tui/keymap.go
+++ b/tui/keymap.go
@@ -133,7 +133,6 @@ func newStatefulKeymap() *statefulKeymap {
}
// help returns short and full help for the state
-// TODO: add more information for full help
func (k *statefulKeymap) help() ([]key.Binding, []key.Binding) {
h := func(bindings ...key.Binding) []key.Binding {
return bindings
diff --git a/tui/update.go b/tui/update.go
index afd9b28d..5baa8375 100644
--- a/tui/update.go
+++ b/tui/update.go
@@ -8,9 +8,9 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/metafates/mangal/anilist"
"github.com/metafates/mangal/color"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/history"
"github.com/metafates/mangal/installer"
+ key2 "github.com/metafates/mangal/key"
"github.com/metafates/mangal/open"
"github.com/metafates/mangal/provider"
"github.com/metafates/mangal/query"
@@ -450,7 +450,7 @@ func (b *statefulBubble) updateMangas(msg tea.Msg) (tea.Model, tea.Cmd) {
case []*source.Chapter:
items := make([]list.Item, len(msg))
- if viper.GetBool(constant.TUIReverseChapters) {
+ if viper.GetBool(key2.TUIReverseChapters) {
for i, c := range msg {
items[len(msg)-i-1] = &listItem{internal: c}
}
@@ -464,7 +464,7 @@ func (b *statefulBubble) updateMangas(msg tea.Msg) (tea.Model, tea.Cmd) {
b.newState(chaptersState)
b.stopLoading()
- if viper.GetBool(constant.AnilistLinkOnMangaSelect) {
+ if viper.GetBool(key2.AnilistLinkOnMangaSelect) {
return b, tea.Batch(cmd, b.fetchAndSetAnilist(b.selectedManga), b.waitForAnilistFetchAndSet())
}
@@ -568,7 +568,7 @@ func (b *statefulBubble) updateChapters(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, b.keymap.confirm):
if len(b.selectedChapters) != 0 {
b.newState(confirmState)
- } else if viper.GetBool(constant.TUIReadOnEnter) {
+ } else if viper.GetBool(key2.TUIReadOnEnter) {
if b.chaptersC.SelectedItem() == nil {
break
}
@@ -704,7 +704,7 @@ func (b *statefulBubble) updateDownloadDone(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, b.keymap.openFolder):
err := open.StartWith(
lo.Must(b.currentDownloadingChapter.Manga.Path(false)),
- viper.GetString(constant.ReaderFolder),
+ viper.GetString(key2.ReaderFolder),
)
if err != nil {
diff --git a/tui/view.go b/tui/view.go
index 80248479..688cf06d 100644
--- a/tui/view.go
+++ b/tui/view.go
@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/metafates/mangal/color"
- "github.com/metafates/mangal/constant"
"github.com/metafates/mangal/icon"
+ "github.com/metafates/mangal/key"
"github.com/metafates/mangal/style"
"github.com/metafates/mangal/util"
"github.com/muesli/reflow/wrap"
@@ -125,7 +125,7 @@ func (b *statefulBubble) downloadingChapterMetainfo() string {
metainfo.WriteString(" as ")
}
- metainfo.WriteString(style.Fg(color.Purple)(viper.GetString(constant.FormatsUse)))
+ metainfo.WriteString(style.Fg(color.Purple)(viper.GetString(key.FormatsUse)))
return metainfo.String()
}
@@ -196,7 +196,7 @@ func (b *statefulBubble) viewDownloadDone() string {
msg,
}
- if succeded > 0 && viper.GetBool(constant.TUIShowDownloadedPath) {
+ if succeded > 0 && viper.GetBool(key.TUIShowDownloadedPath) {
path, err := b.selectedManga.Path(false)
if err == nil {
lines = append(lines, "")
diff --git a/vendor/github.com/antchfx/xmlquery/README.md b/vendor/github.com/antchfx/xmlquery/README.md
index f9f7a3fd..ac65ddcc 100644
--- a/vendor/github.com/antchfx/xmlquery/README.md
+++ b/vendor/github.com/antchfx/xmlquery/README.md
@@ -235,6 +235,9 @@ title.FirstChild = title_text
channel.FirstChild = title
fmt.Println(doc.OutputXML(true))
// W3Schools Home Page
+
+fmt.Println(doc.OutputXMLWithOptions(WithOutputSelf()))
+// W3Schools Home Page
```
Questions
diff --git a/vendor/github.com/antchfx/xmlquery/node.go b/vendor/github.com/antchfx/xmlquery/node.go
index 46436957..e49358cf 100644
--- a/vendor/github.com/antchfx/xmlquery/node.go
+++ b/vendor/github.com/antchfx/xmlquery/node.go
@@ -50,6 +50,37 @@ type Node struct {
level int // node level in the tree
}
+type outputConfiguration struct {
+ printSelf bool
+ preserveSpaces bool
+ emptyElementTagSupport bool
+ skipComments bool
+}
+
+type OutputOption func(*outputConfiguration)
+
+// WithOutputSelf configures the Node to print the root node itself
+func WithOutputSelf() OutputOption {
+ return func(oc *outputConfiguration) {
+ oc.printSelf = true
+ }
+}
+
+// WithEmptyTagSupport empty tags should be written as and
+// not as
+func WithEmptyTagSupport() OutputOption {
+ return func(oc *outputConfiguration) {
+ oc.emptyElementTagSupport = true
+ }
+}
+
+// WithoutComments will skip comments in output
+func WithoutComments() OutputOption {
+ return func(oc *outputConfiguration) {
+ oc.skipComments = true
+ }
+}
+
// InnerText returns the text between the start and end tags of the object.
func (n *Node) InnerText() string {
var output func(*bytes.Buffer, *Node)
@@ -86,7 +117,7 @@ func calculatePreserveSpaces(n *Node, pastValue bool) bool {
return pastValue
}
-func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
+func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool, config *outputConfiguration) {
preserveSpaces = calculatePreserveSpaces(n, preserveSpaces)
switch n.Type {
case TextNode:
@@ -98,9 +129,11 @@ func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
buf.WriteString("]]>")
return
case CommentNode:
- buf.WriteString("")
+ if !config.skipComments {
+ buf.WriteString("")
+ }
return
case DeclarationNode:
buf.WriteString("" + n.Data)
@@ -125,10 +158,15 @@ func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
if n.Type == DeclarationNode {
buf.WriteString("?>")
} else {
- buf.WriteString(">")
+ if n.FirstChild != nil || !config.emptyElementTagSupport {
+ buf.WriteString(">")
+ } else {
+ buf.WriteString("/>")
+ return
+ }
}
for child := n.FirstChild; child != nil; child = child.NextSibling {
- outputXML(buf, child, preserveSpaces)
+ outputXML(buf, child, preserveSpaces, config)
}
if n.Type != DeclarationNode {
if n.Prefix == "" {
@@ -141,13 +179,40 @@ func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
// OutputXML returns the text that including tags name.
func (n *Node) OutputXML(self bool) string {
+
+ config := &outputConfiguration{
+ printSelf: true,
+ emptyElementTagSupport: false,
+ }
preserveSpaces := calculatePreserveSpaces(n, false)
var buf bytes.Buffer
if self && n.Type != DocumentNode {
- outputXML(&buf, n, preserveSpaces)
+ outputXML(&buf, n, preserveSpaces, config)
} else {
for n := n.FirstChild; n != nil; n = n.NextSibling {
- outputXML(&buf, n, preserveSpaces)
+ outputXML(&buf, n, preserveSpaces, config)
+ }
+ }
+
+ return buf.String()
+}
+
+// OutputXMLWithOptions returns the text that including tags name.
+func (n *Node) OutputXMLWithOptions(opts ...OutputOption) string {
+
+ config := &outputConfiguration{}
+ // Set the options
+ for _, opt := range opts {
+ opt(config)
+ }
+
+ preserveSpaces := calculatePreserveSpaces(n, false)
+ var buf bytes.Buffer
+ if config.printSelf && n.Type != DocumentNode {
+ outputXML(&buf, n, preserveSpaces, config)
+ } else {
+ for n := n.FirstChild; n != nil; n = n.NextSibling {
+ outputXML(&buf, n, preserveSpaces, config)
}
}
@@ -172,6 +237,55 @@ func AddAttr(n *Node, key, val string) {
n.Attr = append(n.Attr, attr)
}
+// SetAttr allows an attribute value with the specified name to be changed.
+// If the attribute did not previously exist, it will be created.
+func (n *Node) SetAttr(key, value string) {
+ if i := strings.Index(key, ":"); i > 0 {
+ space := key[:i]
+ local := key[i+1:]
+ for idx := 0; idx < len(n.Attr); idx++ {
+ if n.Attr[idx].Name.Space == space && n.Attr[idx].Name.Local == local {
+ n.Attr[idx].Value = value
+ return
+ }
+ }
+
+ AddAttr(n, key, value)
+ } else {
+ for idx := 0; idx < len(n.Attr); idx++ {
+ if n.Attr[idx].Name.Local == key {
+ n.Attr[idx].Value = value
+ return
+ }
+ }
+
+ AddAttr(n, key, value)
+ }
+}
+
+// RemoveAttr removes the attribute with the specified name.
+func (n *Node) RemoveAttr(key string) {
+ removeIdx := -1
+ if i := strings.Index(key, ":"); i > 0 {
+ space := key[:i]
+ local := key[i+1:]
+ for idx := 0; idx < len(n.Attr); idx++ {
+ if n.Attr[idx].Name.Space == space && n.Attr[idx].Name.Local == local {
+ removeIdx = idx
+ }
+ }
+ } else {
+ for idx := 0; idx < len(n.Attr); idx++ {
+ if n.Attr[idx].Name.Local == key {
+ removeIdx = idx
+ }
+ }
+ }
+ if removeIdx != -1 {
+ n.Attr = append(n.Attr[:removeIdx], n.Attr[removeIdx+1:]...)
+ }
+}
+
// AddChild adds a new node 'n' to a node 'parent' as its last child.
func AddChild(parent, n *Node) {
n.Parent = parent
diff --git a/vendor/github.com/antchfx/xmlquery/parse.go b/vendor/github.com/antchfx/xmlquery/parse.go
index 1e8f6a4e..76f49aad 100644
--- a/vendor/github.com/antchfx/xmlquery/parse.go
+++ b/vendor/github.com/antchfx/xmlquery/parse.go
@@ -3,7 +3,6 @@ package xmlquery
import (
"bufio"
"encoding/xml"
- "errors"
"fmt"
"io"
"net/http"
@@ -92,7 +91,15 @@ func (p *parser) parse() (*Node, error) {
case xml.StartElement:
if p.level == 0 {
// mising XML declaration
- node := &Node{Type: DeclarationNode, Data: "xml", level: 1}
+ attributes := make([]Attr, 1)
+ attributes[0].Name = xml.Name{Local: "version"}
+ attributes[0].Value = "1.0"
+ node := &Node{
+ Type: DeclarationNode,
+ Data: "xml",
+ Attr: attributes,
+ level: 1,
+ }
AddChild(p.prev, node)
p.level = 1
p.prev = node
@@ -106,9 +113,9 @@ func (p *parser) parse() (*Node, error) {
}
}
- if tok.Name.Space != "" {
- if _, found := p.space2prefix[tok.Name.Space]; !found {
- return nil, errors.New("xmlquery: invalid XML document, namespace is missing")
+ if space := tok.Name.Space; space != "" {
+ if _, found := p.space2prefix[space]; !found && p.decoder.Strict {
+ return nil, fmt.Errorf("xmlquery: invalid XML document, namespace %s is missing", space)
}
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/.gitignore b/vendor/github.com/charmbracelet/bubbletea/.gitignore
index 59194486..9cc52352 100644
--- a/vendor/github.com/charmbracelet/bubbletea/.gitignore
+++ b/vendor/github.com/charmbracelet/bubbletea/.gitignore
@@ -20,4 +20,3 @@ tutorials/basics/basics
tutorials/commands/commands
.idea
coverage.txt
-README.md.*
diff --git a/vendor/github.com/charmbracelet/bubbletea/README.md b/vendor/github.com/charmbracelet/bubbletea/README.md
index 4889573d..fe1b5cf5 100644
--- a/vendor/github.com/charmbracelet/bubbletea/README.md
+++ b/vendor/github.com/charmbracelet/bubbletea/README.md
@@ -1,5 +1,4 @@
-Bubble Tea
-==========
+# Bubble Tea
@@ -13,7 +12,7 @@ based on [The Elm Architecture][elm]. Bubble Tea is well-suited for simple and
complex terminal applications, either inline, full-window, or a mix of both.
-
+
Bubble Tea is in use in production and includes a number of features and
@@ -21,29 +20,243 @@ performance optimizations we’ve added along the way. Among those is a standard
framerate-based renderer, a renderer for high-performance scrollable
regions which works alongside the main renderer, and mouse support.
-## Getting Started
+To get started, see the tutorial below, the [examples][examples], the
+[docs][docs], the [video tutorials][youtube] and some common [resources](#libraries-we-use-with-bubble-tea).
-We recommend starting with the [basics tutorial][basics] followed by the
-[commands tutorial][commands], both of which should give you a good
-understanding of how things work.
+[youtube]: https://charm.sh/yt
-There are a bunch of [examples][examples], too!
+## By the way
-[basics]: https://github.com/charmbracelet/bubbletea/tree/master/tutorials/basics
-[commands]: https://github.com/charmbracelet/bubbletea/tree/master/tutorials/commands
-[documentation]: https://github.com/charmbracelet/bubbletea/tree/master/docs
-[examples]: https://github.com/charmbracelet/bubbletea/tree/master/examples
-
-## Components
-
-For a bunch of basic user interface components check out [Bubbles][bubbles],
-the official Bubble Tea component library.
+Be sure to check out [Bubbles][bubbles], a library of common UI components for Bubble Tea.
+***
+
+## Tutorial
+
+Bubble Tea is based on the functional design paradigms of [The Elm
+Architecture][elm], which happens to work nicely with Go. It's a delightful way
+to build applications.
+
+This tutorial assumes you have a working knowledge of Go.
+
+By the way, the non-annotated source code for this program is available
+[on GitHub][tut-source].
+
+[elm]: https://guide.elm-lang.org/architecture/
+[tut-source]:https://github.com/charmbracelet/bubbletea/tree/master/tutorials/basics
+
+### Enough! Let's get to it.
+
+For this tutorial, we're making a shopping list.
+
+To start we'll define our package and import some libraries. Our only external
+import will be the Bubble Tea library, which we'll call `tea` for short.
+
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ tea "github.com/charmbracelet/bubbletea"
+)
+```
+
+Bubble Tea programs are comprised of a **model** that describes the application
+state and three simple methods on that model:
+
+* **Init**, a function that returns an initial command for the application to run.
+* **Update**, a function that handles incoming events and updates the model accordingly.
+* **View**, a function that renders the UI based on the data in the model.
+
+### The Model
+
+So let's start by defining our model which will store our application's state.
+It can be any type, but a `struct` usually makes the most sense.
+
+```go
+type model struct {
+ choices []string // items on the to-do list
+ cursor int // which to-do list item our cursor is pointing at
+ selected map[int]struct{} // which to-do items are selected
+}
+```
+
+### Initialization
+
+Next, we’ll define our application’s initial state. In this case, we’re defining
+a function to return our initial model, however, we could just as easily define
+the initial model as a variable elsewhere, too.
+
+```go
+func initialModel() model {
+ return model{
+ // Our to-do list is a grocery list
+ choices: []string{"Buy carrots", "Buy celery", "Buy kohlrabi"},
+
+ // A map which indicates which choices are selected. We're using
+ // the map like a mathematical set. The keys refer to the indexes
+ // of the `choices` slice, above.
+ selected: make(map[int]struct{}),
+ }
+}
+```
+
+Next, we define the `Init` method. `Init` can return a `Cmd` that could perform
+some initial I/O. For now, we don't need to do any I/O, so for the command,
+we'll just return `nil`, which translates to "no command."
+
+```go
+func (m model) Init() tea.Cmd {
+ // Just return `nil`, which means "no I/O right now, please."
+ return nil
+}
+```
+
+### The Update Method
+
+Next up is the update method. The update function is called when ”things
+happen.” Its job is to look at what has happened and return an updated model in
+response. It can also return a `Cmd` to make more things happen, but for now
+don't worry about that part.
+
+In our case, when a user presses the down arrow, `Update`’s job is to notice
+that the down arrow was pressed and move the cursor accordingly (or not).
+
+The “something happened” comes in the form of a `Msg`, which can be any type.
+Messages are the result of some I/O that took place, such as a keypress, timer
+tick, or a response from a server.
+
+We usually figure out which type of `Msg` we received with a type switch, but
+you could also use a type assertion.
+
+For now, we'll just deal with `tea.KeyMsg` messages, which are automatically
+sent to the update function when keys are pressed.
+
+```go
+func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+ switch msg := msg.(type) {
+
+ // Is it a key press?
+ case tea.KeyMsg:
+
+ // Cool, what was the actual key pressed?
+ switch msg.String() {
+
+ // These keys should exit the program.
+ case "ctrl+c", "q":
+ return m, tea.Quit
+
+ // The "up" and "k" keys move the cursor up
+ case "up", "k":
+ if m.cursor > 0 {
+ m.cursor--
+ }
+
+ // The "down" and "j" keys move the cursor down
+ case "down", "j":
+ if m.cursor < len(m.choices)-1 {
+ m.cursor++
+ }
+
+ // The "enter" key and the spacebar (a literal space) toggle
+ // the selected state for the item that the cursor is pointing at.
+ case "enter", " ":
+ _, ok := m.selected[m.cursor]
+ if ok {
+ delete(m.selected, m.cursor)
+ } else {
+ m.selected[m.cursor] = struct{}{}
+ }
+ }
+ }
+
+ // Return the updated model to the Bubble Tea runtime for processing.
+ // Note that we're not returning a command.
+ return m, nil
+}
+```
+
+You may have noticed that ctrl+c and q above return
+a `tea.Quit` command with the model. That’s a special command which instructs
+the Bubble Tea runtime to quit, exiting the program.
+
+### The View Method
+
+At last, it’s time to render our UI. Of all the methods, the view is the
+simplest. We look at the model in its current state and use it to return
+a `string`. That string is our UI!
+
+Because the view describes the entire UI of your application, you don’t have to
+worry about redrawing logic and stuff like that. Bubble Tea takes care of it
+for you.
+
+```go
+func (m model) View() string {
+ // The header
+ s := "What should we buy at the market?\n\n"
+
+ // Iterate over our choices
+ for i, choice := range m.choices {
+
+ // Is the cursor pointing at this choice?
+ cursor := " " // no cursor
+ if m.cursor == i {
+ cursor = ">" // cursor!
+ }
+
+ // Is this choice selected?
+ checked := " " // not selected
+ if _, ok := m.selected[i]; ok {
+ checked = "x" // selected!
+ }
+
+ // Render the row
+ s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
+ }
+
+ // The footer
+ s += "\nPress q to quit.\n"
+
+ // Send the UI for rendering
+ return s
+}
+```
+
+### All Together Now
+
+The last step is to simply run our program. We pass our initial model to
+`tea.NewProgram` and let it rip:
+
+```go
+func main() {
+ p := tea.NewProgram(initialModel())
+ if _, err := p.Run(); err != nil {
+ fmt.Printf("Alas, there's been an error: %v", err)
+ os.Exit(1)
+ }
+}
+```
+
+## What’s Next?
+
+This tutorial covers the basics of building an interactive terminal UI, but
+in the real world you'll also need to perform I/O. To learn about that have a
+look at the [Command Tutorial][cmd]. It's pretty simple.
+
+There are also several [Bubble Tea examples][examples] available and, of course,
+there are [Go Docs][docs].
+
+[cmd]: http://github.com/charmbracelet/bubbletea/tree/master/tutorials/commands/
+[examples]: http://github.com/charmbracelet/bubbletea/tree/master/examples
+[docs]: https://pkg.go.dev/github.com/charmbracelet/bubbletea?tab=doc
+
## Debugging
### Debugging with Delve
@@ -65,8 +278,9 @@ actually watch out what address the first `dlv` run tells you to connect to.
### Logging Stuff
-You can log to a debug file to print debug Bubble Tea applications. To do so,
-include something like…
+You can’t really log to stdout with Bubble Tea because your TUI is busy
+occupying that! You can, however, log to a file by including something like
+the following prior to starting your Bubble Tea program:
```go
if len(os.Getenv("DEBUG")) > 0 {
@@ -79,8 +293,8 @@ if len(os.Getenv("DEBUG")) > 0 {
}
```
-…before you start your Bubble Tea program. To see what’s printed in real time,
-run `tail -f debug.log` while you run your program in another window.
+To see what’s being logged in real time, run `tail -f debug.log` while you run
+your program in another window.
## Libraries we use with Bubble Tea
@@ -106,14 +320,15 @@ For some Bubble Tea programs in production, see:
* [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform
* [Canard](https://github.com/mrusme/canard): an RSS client
* [charm](https://github.com/charmbracelet/charm): the official Charm user account manager
+* [chezmoi](https://github.com/twpayne/chezmoi): manage your dotfiles across multiple machines, securely
* [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in your terminal
* [clidle](https://github.com/ajeetdsouza/clidle): a Wordle clone for your terminal
* [container-canary](https://github.com/NVIDIA/container-canary): a container validator
* [dns53](https://github.com/purpleclay/dns53): dynamic DNS with Amazon Route53. Expose your EC2 quickly, securely and privately
-* [fm](https://github.com/knipferrc/fm): a terminal-based file manager
* [flapioca](https://github.com/kbrgl/flapioca): Flappy Bird on the CLI!
-* [fztea](https://github.com/jon4hz/fztea): connect to your Flipper's UI over serial or make it accessible via SSH
+* [fm](https://github.com/knipferrc/fm): a terminal-based file manager
* [fork-cleaner](https://github.com/caarlos0/fork-cleaner): cleans up old and inactive forks in your GitHub account
+* [fztea](https://github.com/jon4hz/fztea): connect to your Flipper's UI over serial or make it accessible via SSH
* [gambit](https://github.com/maaslalani/gambit): play chess in the terminal
* [gembro](https://git.sr.ht/~rafael/gembro): a mouse-driven Gemini browser
* [gh-b](https://github.com/joaom00/gh-b): GitHub CLI extension to easily manage your branches
@@ -121,14 +336,16 @@ For some Bubble Tea programs in production, see:
* [gitflow-toolkit](https://github.com/mritd/gitflow-toolkit): a GitFlow submission tool
* [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser and online markdown stash
* [gocovsh](https://github.com/orlangure/gocovsh): explore Go coverage reports from the CLI
+* [got](https://github.com/fedeztk/got): a simple translator and text-to-speech app build on top of simplytranslate's APIs
* [httpit](https://github.com/gonetx/httpit): a rapid http(s) benchmark tool
* [IDNT](https://github.com/r-darwish/idnt): batch software uninstaller
* [kboard](https://github.com/CamiloGarciaLaRotta/kboard): a typing game
* [mandelbrot-cli](https://github.com/MicheleFiladelfia/mandelbrot-cli): Multiplatform terminal mandelbrot set explorer
-* [mergestat](https://github.com/mergestat/mergestat): run SQL queries on git repositories
* [mc](https://github.com/minio/mc): the official [MinIO](https://min.io) client
+* [mergestat](https://github.com/mergestat/mergestat): run SQL queries on git repositories
+* [Noted](https://github.com/torbratsberg/noted): Note viewer and manager
* [pathos](https://github.com/chip/pathos): pathos - CLI for editing a PATH env variable
-* [portal][portal]: securely send transfer between computers
+* [portal](https://github.com/ZinoKader/portal): securely send transfer between computers
* [redis-viewer](https://github.com/SaltFishPr/redis-viewer): browse Redis databases
* [sku](https://github.com/fedeztk/sku): a simple TUI for playing sudoku inside the terminal
* [Slides](https://github.com/maaslalani/slides): a markdown-based presentation tool
@@ -140,21 +357,19 @@ For some Bubble Tea programs in production, see:
* [termdbms](https://github.com/mathaou/termdbms): a keyboard and mouse driven database browser
* [ticker](https://github.com/achannarasappa/ticker): a terminal stock watcher and stock position tracker
* [tran](https://github.com/abdfnx/tran): securely transfer stuff between computers (based on [portal][portal])
+* [Typer](https://github.com/maaslalani/typer): a typing test
* [tz](https://github.com/oz/tz): an aid for scheduling across multiple time zones
* [ugm](https://github.com/ariasmn/ugm): a unix user and group browser
-* [Typer](https://github.com/maaslalani/typer): a typing test
+* [wander](https://github.com/robinovitch61/wander): HashiCorp Nomad terminal client
* [wishlist](https://github.com/charmbracelet/wishlist): an SSH directory
-* [Noted](https://github.com/torbratsberg/noted): Note viewer and manager
-
-[portal]: https://github.com/ZinoKader/portal
## Feedback
-We'd love to hear your thoughts on this tutorial. Feel free to drop us a note!
+We'd love to hear your thoughts on this project. Feel free to drop us a note!
* [Twitter](https://twitter.com/charmcli)
-* [The Fediverse](https://mastodon.technology/@charm)
-* [Slack](https://charm.sh/slack)
+* [The Fediverse](https://mastodon.social/@charmcli)
+* [Discord](https://charm.sh/chat)
## Acknowledgments
@@ -177,4 +392,4 @@ Part of [Charm](https://charm.sh).
-Charm热爱开源 • Charm loves open source
+Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة
diff --git a/vendor/github.com/charmbracelet/bubbletea/commands.go b/vendor/github.com/charmbracelet/bubbletea/commands.go
index 91116388..7c30a121 100644
--- a/vendor/github.com/charmbracelet/bubbletea/commands.go
+++ b/vendor/github.com/charmbracelet/bubbletea/commands.go
@@ -1,12 +1,48 @@
package tea
-// Convenience commands. Not part of the Bubble Tea core, but potentially
-// handy.
-
import (
"time"
)
+// Batch performs a bunch of commands concurrently with no ordering guarantees
+// about the results. Use a Batch to return several commands.
+//
+// Example:
+//
+// func (m model) Init() Cmd {
+// return tea.Batch(someCommand, someOtherCommand)
+// }
+func Batch(cmds ...Cmd) Cmd {
+ var validCmds []Cmd
+ for _, c := range cmds {
+ if c == nil {
+ continue
+ }
+ validCmds = append(validCmds, c)
+ }
+ if len(validCmds) == 0 {
+ return nil
+ }
+ return func() Msg {
+ return BatchMsg(validCmds)
+ }
+}
+
+// BatchMsg is a message used to perform a bunch of commands concurrently with
+// no ordering guarantees. You can send a BatchMsg with Batch.
+type BatchMsg []Cmd
+
+// Sequence runs the given commands one at a time, in order. Contrast this with
+// Batch, which runs commands concurrently.
+func Sequence(cmds ...Cmd) Cmd {
+ return func() Msg {
+ return sequenceMsg(cmds)
+ }
+}
+
+// sequenceMsg is used internally to run the given commands in order.
+type sequenceMsg []Cmd
+
// Every is a command that ticks in sync with the system clock. So, if you
// wanted to tick with the system clock every second, minute or hour you
// could use this. It's also handy for having different things tick in sync.
@@ -63,7 +99,7 @@ func Every(duration time.Duration, fn func(time.Time) Msg) Cmd {
}
// Tick produces a command at an interval independent of the system clock at
-// the given duration. That is, the timer begins when precisely when invoked,
+// the given duration. That is, the timer begins precisely when invoked,
// and runs for its entire duration.
//
// To produce the command, pass a duration and a function which returns
@@ -119,6 +155,8 @@ func Tick(d time.Duration, fn func(time.Time) Msg) Cmd {
// }
//
// cmd := Sequentially(saveStateCmd, Quit)
+//
+// Deprecated: use Sequence instead.
func Sequentially(cmds ...Cmd) Cmd {
return func() Msg {
for _, cmd := range cmds {
diff --git a/vendor/github.com/charmbracelet/bubbletea/exec.go b/vendor/github.com/charmbracelet/bubbletea/exec.go
index 587d91a8..fb6d91ed 100644
--- a/vendor/github.com/charmbracelet/bubbletea/exec.go
+++ b/vendor/github.com/charmbracelet/bubbletea/exec.go
@@ -13,7 +13,7 @@ type execMsg struct {
}
// Exec is used to perform arbitrary I/O in a blocking fashion, effectively
-// pausing the Program while execution is runnning and resuming it when
+// pausing the Program while execution is running and resuming it when
// execution has completed.
//
// Most of the time you'll want to use ExecProcess, which runs an exec.Cmd.
@@ -39,7 +39,7 @@ func Exec(c ExecCommand, fn ExecCallback) Cmd {
// c := exec.Command("vim", "file.txt")
//
// cmd := ExecProcess(c, func(err error) Msg {
-// return VimFinishedMsg{err: error}
+// return VimFinishedMsg{err: err}
// })
//
// Or, if you don't care about errors, you could simply:
@@ -109,7 +109,7 @@ func (p *Program) exec(c ExecCommand, fn ExecCallback) {
}
c.SetStdin(p.input)
- c.SetStdout(p.output)
+ c.SetStdout(p.output.TTY())
c.SetStderr(os.Stderr)
// Execute system command.
diff --git a/vendor/github.com/charmbracelet/bubbletea/key.go b/vendor/github.com/charmbracelet/bubbletea/key.go
index 07bc6519..c2e5e3ab 100644
--- a/vendor/github.com/charmbracelet/bubbletea/key.go
+++ b/vendor/github.com/charmbracelet/bubbletea/key.go
@@ -2,7 +2,6 @@ package tea
import (
"errors"
- "fmt"
"io"
"unicode/utf8"
@@ -198,20 +197,29 @@ const (
KeyEnd
KeyPgUp
KeyPgDown
+ KeyCtrlPgUp
+ KeyCtrlPgDown
KeyDelete
+ KeyInsert
KeySpace
KeyCtrlUp
KeyCtrlDown
KeyCtrlRight
KeyCtrlLeft
+ KeyCtrlHome
+ KeyCtrlEnd
KeyShiftUp
KeyShiftDown
KeyShiftRight
KeyShiftLeft
+ KeyShiftHome
+ KeyShiftEnd
KeyCtrlShiftUp
KeyCtrlShiftDown
KeyCtrlShiftLeft
KeyCtrlShiftRight
+ KeyCtrlShiftHome
+ KeyCtrlShiftEnd
KeyF1
KeyF2
KeyF3
@@ -281,9 +289,18 @@ var keyNames = map[KeyType]string{
KeyShiftTab: "shift+tab",
KeyHome: "home",
KeyEnd: "end",
+ KeyCtrlHome: "ctrl+home",
+ KeyCtrlEnd: "ctrl+end",
+ KeyShiftHome: "shift+home",
+ KeyShiftEnd: "shift+end",
+ KeyCtrlShiftHome: "ctrl+shift+home",
+ KeyCtrlShiftEnd: "ctrl+shift+end",
KeyPgUp: "pgup",
KeyPgDown: "pgdown",
+ KeyCtrlPgUp: "ctrl+pgup",
+ KeyCtrlPgDown: "ctrl+pgdown",
KeyDelete: "delete",
+ KeyInsert: "insert",
KeyCtrlUp: "ctrl+up",
KeyCtrlDown: "ctrl+down",
KeyCtrlRight: "ctrl+right",
@@ -375,100 +392,175 @@ var sequences = map[string]Key{
"\x1b[1;8D": {Type: KeyCtrlShiftLeft, Alt: true},
// Miscellaneous keys
- "\x1b[Z": {Type: KeyShiftTab},
+ "\x1b[Z": {Type: KeyShiftTab},
+
+ "\x1b[2~": {Type: KeyInsert},
+ "\x1b[3;2~": {Type: KeyInsert, Alt: true},
+ "\x1b\x1b[2~": {Type: KeyInsert, Alt: true}, // urxvt
+
"\x1b[3~": {Type: KeyDelete},
"\x1b[3;3~": {Type: KeyDelete, Alt: true},
- "\x1b[1~": {Type: KeyHome},
- "\x1b[1;3H~": {Type: KeyHome, Alt: true},
- "\x1b[4~": {Type: KeyEnd},
- "\x1b[1;3F~": {Type: KeyEnd, Alt: true},
+ "\x1b\x1b[3~": {Type: KeyDelete, Alt: true}, // urxvt
+
"\x1b[5~": {Type: KeyPgUp},
"\x1b[5;3~": {Type: KeyPgUp, Alt: true},
+ "\x1b\x1b[5~": {Type: KeyPgUp, Alt: true}, // urxvt
+ "\x1b[5;5~": {Type: KeyCtrlPgUp},
+ "\x1b[5^": {Type: KeyCtrlPgUp}, // urxvt
+ "\x1b[5;7~": {Type: KeyCtrlPgUp, Alt: true},
+ "\x1b\x1b[5^": {Type: KeyCtrlPgUp, Alt: true}, // urxvt
+
"\x1b[6~": {Type: KeyPgDown},
"\x1b[6;3~": {Type: KeyPgDown, Alt: true},
- "\x1b[7~": {Type: KeyHome}, // urxvt
- "\x1b[8~": {Type: KeyEnd}, // urxvt
- "\x1b\x1b[3~": {Type: KeyDelete, Alt: true}, // urxvt
- "\x1b\x1b[5~": {Type: KeyPgUp, Alt: true}, // urxvt
"\x1b\x1b[6~": {Type: KeyPgDown, Alt: true}, // urxvt
- "\x1b\x1b[7~": {Type: KeyHome, Alt: true}, // urxvt
- "\x1b\x1b[8~": {Type: KeyEnd, Alt: true}, // urxvt
+ "\x1b[6;5~": {Type: KeyCtrlPgDown},
+ "\x1b[6^": {Type: KeyCtrlPgDown}, // urxvt
+ "\x1b[6;7~": {Type: KeyCtrlPgDown, Alt: true},
+ "\x1b\x1b[6^": {Type: KeyCtrlPgDown, Alt: true}, // urxvt
+
+ "\x1b[1~": {Type: KeyHome},
+ "\x1b[H": {Type: KeyHome}, // xterm, lxterm
+ "\x1b[1;3H": {Type: KeyHome, Alt: true}, // xterm, lxterm
+ "\x1b[1;5H": {Type: KeyCtrlHome}, // xterm, lxterm
+ "\x1b[1;7H": {Type: KeyCtrlHome, Alt: true}, // xterm, lxterm
+ "\x1b[1;2H": {Type: KeyShiftHome}, // xterm, lxterm
+ "\x1b[1;4H": {Type: KeyShiftHome, Alt: true}, // xterm, lxterm
+ "\x1b[1;6H": {Type: KeyCtrlShiftHome}, // xterm, lxterm
+ "\x1b[1;8H": {Type: KeyCtrlShiftHome, Alt: true}, // xterm, lxterm
+
+ "\x1b[4~": {Type: KeyEnd},
+ "\x1b[F": {Type: KeyEnd}, // xterm, lxterm
+ "\x1b[1;3F": {Type: KeyEnd, Alt: true}, // xterm, lxterm
+ "\x1b[1;5F": {Type: KeyCtrlEnd}, // xterm, lxterm
+ "\x1b[1;7F": {Type: KeyCtrlEnd, Alt: true}, // xterm, lxterm
+ "\x1b[1;2F": {Type: KeyShiftEnd}, // xterm, lxterm
+ "\x1b[1;4F": {Type: KeyShiftEnd, Alt: true}, // xterm, lxterm
+ "\x1b[1;6F": {Type: KeyCtrlShiftEnd}, // xterm, lxterm
+ "\x1b[1;8F": {Type: KeyCtrlShiftEnd, Alt: true}, // xterm, lxterm
+
+ "\x1b[7~": {Type: KeyHome}, // urxvt
+ "\x1b\x1b[7~": {Type: KeyHome, Alt: true}, // urxvt
+ "\x1b[7^": {Type: KeyCtrlHome}, // urxvt
+ "\x1b\x1b[7^": {Type: KeyCtrlHome, Alt: true}, // urxvt
+ "\x1b[7$": {Type: KeyShiftHome}, // urxvt
+ "\x1b\x1b[7$": {Type: KeyShiftHome, Alt: true}, // urxvt
+ "\x1b[7@": {Type: KeyCtrlShiftHome}, // urxvt
+ "\x1b\x1b[7@": {Type: KeyCtrlShiftHome, Alt: true}, // urxvt
+
+ "\x1b[8~": {Type: KeyEnd}, // urxvt
+ "\x1b\x1b[8~": {Type: KeyEnd, Alt: true}, // urxvt
+ "\x1b[8^": {Type: KeyCtrlEnd}, // urxvt
+ "\x1b\x1b[8^": {Type: KeyCtrlEnd, Alt: true}, // urxvt
+ "\x1b[8$": {Type: KeyShiftEnd}, // urxvt
+ "\x1b\x1b[8$": {Type: KeyShiftEnd, Alt: true}, // urxvt
+ "\x1b[8@": {Type: KeyCtrlShiftEnd}, // urxvt
+ "\x1b\x1b[8@": {Type: KeyCtrlShiftEnd, Alt: true}, // urxvt
+
+ // Function keys, Linux console
+ "\x1b[[A": {Type: KeyF1}, // linux console
+ "\x1b[[B": {Type: KeyF2}, // linux console
+ "\x1b[[C": {Type: KeyF3}, // linux console
+ "\x1b[[D": {Type: KeyF4}, // linux console
+ "\x1b[[E": {Type: KeyF5}, // linux console
// Function keys, X11
- "\x1bOP": {Type: KeyF1}, // vt100
- "\x1bOQ": {Type: KeyF2}, // vt100
- "\x1bOR": {Type: KeyF3}, // vt100
- "\x1bOS": {Type: KeyF4}, // vt100
- "\x1b[15~": {Type: KeyF5}, // also urxvt
- "\x1b[17~": {Type: KeyF6}, // also urxvt
- "\x1b[18~": {Type: KeyF7}, // also urxvt
- "\x1b[19~": {Type: KeyF8}, // also urxvt
- "\x1b[20~": {Type: KeyF9}, // also urxvt
- "\x1b[21~": {Type: KeyF10}, // also urxvt
- "\x1b[23~": {Type: KeyF11}, // also urxvt
- "\x1b[24~": {Type: KeyF12}, // also urxvt
- "\x1b[1;2P": {Type: KeyF13},
- "\x1b[1;2Q": {Type: KeyF14},
- "\x1b[1;2R": {Type: KeyF15},
- "\x1b[1;2S": {Type: KeyF16},
+ "\x1bOP": {Type: KeyF1}, // vt100, xterm
+ "\x1bOQ": {Type: KeyF2}, // vt100, xterm
+ "\x1bOR": {Type: KeyF3}, // vt100, xterm
+ "\x1bOS": {Type: KeyF4}, // vt100, xterm
+
+ "\x1b[1;3P": {Type: KeyF1, Alt: true}, // vt100, xterm
+ "\x1b[1;3Q": {Type: KeyF2, Alt: true}, // vt100, xterm
+ "\x1b[1;3R": {Type: KeyF3, Alt: true}, // vt100, xterm
+ "\x1b[1;3S": {Type: KeyF4, Alt: true}, // vt100, xterm
+
+ "\x1b[11~": {Type: KeyF1}, // urxvt
+ "\x1b[12~": {Type: KeyF2}, // urxvt
+ "\x1b[13~": {Type: KeyF3}, // urxvt
+ "\x1b[14~": {Type: KeyF4}, // urxvt
+
+ "\x1b\x1b[11~": {Type: KeyF1, Alt: true}, // urxvt
+ "\x1b\x1b[12~": {Type: KeyF2, Alt: true}, // urxvt
+ "\x1b\x1b[13~": {Type: KeyF3, Alt: true}, // urxvt
+ "\x1b\x1b[14~": {Type: KeyF4, Alt: true}, // urxvt
+
+ "\x1b[15~": {Type: KeyF5}, // vt100, xterm, also urxvt
+
+ "\x1b[15;3~": {Type: KeyF5, Alt: true}, // vt100, xterm, also urxvt
+
+ "\x1b\x1b[15~": {Type: KeyF5, Alt: true}, // urxvt
+
+ "\x1b[17~": {Type: KeyF6}, // vt100, xterm, also urxvt
+ "\x1b[18~": {Type: KeyF7}, // vt100, xterm, also urxvt
+ "\x1b[19~": {Type: KeyF8}, // vt100, xterm, also urxvt
+ "\x1b[20~": {Type: KeyF9}, // vt100, xterm, also urxvt
+ "\x1b[21~": {Type: KeyF10}, // vt100, xterm, also urxvt
+
+ "\x1b\x1b[17~": {Type: KeyF6, Alt: true}, // urxvt
+ "\x1b\x1b[18~": {Type: KeyF7, Alt: true}, // urxvt
+ "\x1b\x1b[19~": {Type: KeyF8, Alt: true}, // urxvt
+ "\x1b\x1b[20~": {Type: KeyF9, Alt: true}, // urxvt
+ "\x1b\x1b[21~": {Type: KeyF10, Alt: true}, // urxvt
+
+ "\x1b[17;3~": {Type: KeyF6, Alt: true}, // vt100, xterm
+ "\x1b[18;3~": {Type: KeyF7, Alt: true}, // vt100, xterm
+ "\x1b[19;3~": {Type: KeyF8, Alt: true}, // vt100, xterm
+ "\x1b[20;3~": {Type: KeyF9, Alt: true}, // vt100, xterm
+ "\x1b[21;3~": {Type: KeyF10, Alt: true}, // vt100, xterm
+
+ "\x1b[23~": {Type: KeyF11}, // vt100, xterm, also urxvt
+ "\x1b[24~": {Type: KeyF12}, // vt100, xterm, also urxvt
+
+ "\x1b[23;3~": {Type: KeyF11, Alt: true}, // vt100, xterm
+ "\x1b[24;3~": {Type: KeyF12, Alt: true}, // vt100, xterm
+
+ "\x1b\x1b[23~": {Type: KeyF11, Alt: true}, // urxvt
+ "\x1b\x1b[24~": {Type: KeyF12, Alt: true}, // urxvt
+
+ "\x1b[1;2P": {Type: KeyF13},
+ "\x1b[1;2Q": {Type: KeyF14},
+
+ "\x1b[25~": {Type: KeyF13}, // vt100, xterm, also urxvt
+ "\x1b[26~": {Type: KeyF14}, // vt100, xterm, also urxvt
+
+ "\x1b[25;3~": {Type: KeyF13, Alt: true}, // vt100, xterm
+ "\x1b[26;3~": {Type: KeyF14, Alt: true}, // vt100, xterm
+
+ "\x1b\x1b[25~": {Type: KeyF13, Alt: true}, // urxvt
+ "\x1b\x1b[26~": {Type: KeyF14, Alt: true}, // urxvt
+
+ "\x1b[1;2R": {Type: KeyF15},
+ "\x1b[1;2S": {Type: KeyF16},
+
+ "\x1b[28~": {Type: KeyF15}, // vt100, xterm, also urxvt
+ "\x1b[29~": {Type: KeyF16}, // vt100, xterm, also urxvt
+
+ "\x1b[28;3~": {Type: KeyF15, Alt: true}, // vt100, xterm
+ "\x1b[29;3~": {Type: KeyF16, Alt: true}, // vt100, xterm
+
+ "\x1b\x1b[28~": {Type: KeyF15, Alt: true}, // urxvt
+ "\x1b\x1b[29~": {Type: KeyF16, Alt: true}, // urxvt
+
"\x1b[15;2~": {Type: KeyF17},
"\x1b[17;2~": {Type: KeyF18},
"\x1b[18;2~": {Type: KeyF19},
"\x1b[19;2~": {Type: KeyF20},
- // Function keys with the alt modifier, X11
- "\x1b[1;3P": {Type: KeyF1, Alt: true},
- "\x1b[1;3Q": {Type: KeyF2, Alt: true},
- "\x1b[1;3R": {Type: KeyF3, Alt: true},
- "\x1b[1;3S": {Type: KeyF4, Alt: true},
- "\x1b[15;3~": {Type: KeyF5, Alt: true},
- "\x1b[17;3~": {Type: KeyF6, Alt: true},
- "\x1b[18;3~": {Type: KeyF7, Alt: true},
- "\x1b[19;3~": {Type: KeyF8, Alt: true},
- "\x1b[20;3~": {Type: KeyF9, Alt: true},
- "\x1b[21;3~": {Type: KeyF10, Alt: true},
- "\x1b[23;3~": {Type: KeyF11, Alt: true},
- "\x1b[24;3~": {Type: KeyF12, Alt: true},
-
- // Function keys, urxvt
- "\x1b[11~": {Type: KeyF1},
- "\x1b[12~": {Type: KeyF2},
- "\x1b[13~": {Type: KeyF3},
- "\x1b[14~": {Type: KeyF4},
- "\x1b[25~": {Type: KeyF13},
- "\x1b[26~": {Type: KeyF14},
- "\x1b[28~": {Type: KeyF15},
- "\x1b[29~": {Type: KeyF16},
"\x1b[31~": {Type: KeyF17},
"\x1b[32~": {Type: KeyF18},
"\x1b[33~": {Type: KeyF19},
"\x1b[34~": {Type: KeyF20},
- // Function keys with the alt modifier, urxvt
- "\x1b\x1b[11~": {Type: KeyF1, Alt: true},
- "\x1b\x1b[12~": {Type: KeyF2, Alt: true},
- "\x1b\x1b[13~": {Type: KeyF3, Alt: true},
- "\x1b\x1b[14~": {Type: KeyF4, Alt: true},
- "\x1b\x1b[25~": {Type: KeyF13, Alt: true},
- "\x1b\x1b[26~": {Type: KeyF14, Alt: true},
- "\x1b\x1b[28~": {Type: KeyF15, Alt: true},
- "\x1b\x1b[29~": {Type: KeyF16, Alt: true},
- "\x1b\x1b[31~": {Type: KeyF17, Alt: true},
- "\x1b\x1b[32~": {Type: KeyF18, Alt: true},
- "\x1b\x1b[33~": {Type: KeyF19, Alt: true},
- "\x1b\x1b[34~": {Type: KeyF20, Alt: true},
-}
+ "\x1b\x1b[31~": {Type: KeyF17, Alt: true}, // urxvt
+ "\x1b\x1b[32~": {Type: KeyF18, Alt: true}, // urxvt
+ "\x1b\x1b[33~": {Type: KeyF19, Alt: true}, // urxvt
+ "\x1b\x1b[34~": {Type: KeyF20, Alt: true}, // urxvt
-// Hex code mappings.
-var hexes = map[string]Key{
- "1b0d": {Type: KeyEnter, Alt: true},
- "1b7f": {Type: KeyBackspace, Alt: true},
-
- // Powershell
- "1b4f41": {Type: KeyUp, Alt: false},
- "1b4f42": {Type: KeyDown, Alt: false},
- "1b4f43": {Type: KeyRight, Alt: false},
- "1b4f44": {Type: KeyLeft, Alt: false},
+ // Powershell sequences.
+ "\x1bOA": {Type: KeyUp, Alt: false},
+ "\x1bOB": {Type: KeyDown, Alt: false},
+ "\x1bOC": {Type: KeyRight, Alt: false},
+ "\x1bOD": {Type: KeyLeft, Alt: false},
}
// readInputs reads keypress and mouse inputs from a TTY and returns messages
@@ -534,37 +626,37 @@ func readInputs(input io.Reader) ([]Msg, error) {
continue
}
- // Some of these need special handling.
- hex := fmt.Sprintf("%x", runes)
- if k, ok := hexes[hex]; ok {
- msgs = append(msgs, KeyMsg(k))
+ // Is this an unrecognized CSI sequence? If so, ignore it.
+ if len(runes) > 2 && runes[0] == 0x1b && (runes[1] == '[' ||
+ (len(runes) > 3 && runes[1] == 0x1b && runes[2] == '[')) {
continue
}
// Is the alt key pressed? If so, the buffer will be prefixed with an
// escape.
+ alt := false
if len(runes) > 1 && runes[0] == 0x1b {
- msgs = append(msgs, KeyMsg(Key{Alt: true, Type: KeyRunes, Runes: runes[1:]}))
- continue
+ alt = true
+ runes = runes[1:]
}
for _, v := range runes {
// Is the first rune a control character?
r := KeyType(v)
if r <= keyUS || r == keyDEL {
- msgs = append(msgs, KeyMsg(Key{Type: r}))
+ msgs = append(msgs, KeyMsg(Key{Type: r, Alt: alt}))
continue
}
// If it's a space, override the type with KeySpace (but still include
// the rune).
if r == ' ' {
- msgs = append(msgs, KeyMsg(Key{Type: KeySpace, Runes: []rune{v}}))
+ msgs = append(msgs, KeyMsg(Key{Type: KeySpace, Runes: []rune{v}, Alt: alt}))
continue
}
// Welp, just regular, ol' runes.
- msgs = append(msgs, KeyMsg(Key{Type: KeyRunes, Runes: []rune{v}}))
+ msgs = append(msgs, KeyMsg(Key{Type: KeyRunes, Runes: []rune{v}, Alt: alt}))
}
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/logging.go b/vendor/github.com/charmbracelet/bubbletea/logging.go
index 54a4350a..97ffcb70 100644
--- a/vendor/github.com/charmbracelet/bubbletea/logging.go
+++ b/vendor/github.com/charmbracelet/bubbletea/logging.go
@@ -19,7 +19,7 @@ import (
// }
// defer f.Close()
func LogToFile(path string, prefix string) (*os.File, error) {
- f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
+ f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
index 03dd9494..a0226364 100644
--- a/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
@@ -2,10 +2,18 @@ package tea
type nilRenderer struct{}
-func (n nilRenderer) start() {}
-func (n nilRenderer) stop() {}
-func (n nilRenderer) kill() {}
-func (n nilRenderer) write(v string) {}
-func (n nilRenderer) repaint() {}
-func (n nilRenderer) altScreen() bool { return false }
-func (n nilRenderer) setAltScreen(v bool) {}
+func (n nilRenderer) start() {}
+func (n nilRenderer) stop() {}
+func (n nilRenderer) kill() {}
+func (n nilRenderer) write(v string) {}
+func (n nilRenderer) repaint() {}
+func (n nilRenderer) clearScreen() {}
+func (n nilRenderer) altScreen() bool { return false }
+func (n nilRenderer) enterAltScreen() {}
+func (n nilRenderer) exitAltScreen() {}
+func (n nilRenderer) showCursor() {}
+func (n nilRenderer) hideCursor() {}
+func (n nilRenderer) enableMouseCellMotion() {}
+func (n nilRenderer) disableMouseCellMotion() {}
+func (n nilRenderer) enableMouseAllMotion() {}
+func (n nilRenderer) disableMouseAllMotion() {}
diff --git a/vendor/github.com/charmbracelet/bubbletea/options.go b/vendor/github.com/charmbracelet/bubbletea/options.go
index b60d23c2..d9ce42c7 100644
--- a/vendor/github.com/charmbracelet/bubbletea/options.go
+++ b/vendor/github.com/charmbracelet/bubbletea/options.go
@@ -1,6 +1,11 @@
package tea
-import "io"
+import (
+ "context"
+ "io"
+
+ "github.com/muesli/termenv"
+)
// ProgramOption is used to set options when initializing a Program. Program can
// accept a variable number of options.
@@ -10,20 +15,29 @@ import "io"
// p := NewProgram(model, WithInput(someInput), WithOutput(someOutput))
type ProgramOption func(*Program)
+// WithContext lets you specify a context in which to run the Program. This is
+// useful if you want to cancel the execution from outside. When a Program gets
+// cancelled it will exit with an error ErrProgramKilled.
+func WithContext(ctx context.Context) ProgramOption {
+ return func(p *Program) {
+ p.ctx = ctx
+ }
+}
+
// WithOutput sets the output which, by default, is stdout. In most cases you
// won't need to use this.
func WithOutput(output io.Writer) ProgramOption {
- return func(m *Program) {
- m.output = output
+ return func(p *Program) {
+ p.output = termenv.NewOutput(output, termenv.WithColorCache(true))
}
}
// WithInput sets the input which, by default, is stdin. In most cases you
// won't need to use this.
func WithInput(input io.Reader) ProgramOption {
- return func(m *Program) {
- m.input = input
- m.startupOptions |= withCustomInput
+ return func(p *Program) {
+ p.input = input
+ p.startupOptions |= withCustomInput
}
}
@@ -34,13 +48,21 @@ func WithInputTTY() ProgramOption {
}
}
+// WithoutSignalHandler disables the signal handler that Bubble Tea sets up for
+// Programs. This is useful if you want to handle signals yourself.
+func WithoutSignalHandler() ProgramOption {
+ return func(p *Program) {
+ p.startupOptions |= withoutSignalHandler
+ }
+}
+
// WithoutCatchPanics disables the panic catching that Bubble Tea does by
// default. If panic catching is disabled the terminal will be in a fairly
// unusable state after a panic because Bubble Tea will not perform its usual
// cleanup on exit.
func WithoutCatchPanics() ProgramOption {
- return func(m *Program) {
- m.CatchPanics = false
+ return func(p *Program) {
+ p.startupOptions |= withoutCatchPanics
}
}
@@ -51,7 +73,7 @@ func WithoutCatchPanics() ProgramOption {
// Example:
//
// p := tea.NewProgram(Model{}, tea.WithAltScreen())
-// if err := p.Start(); err != nil {
+// if _, err := p.Run(); err != nil {
// fmt.Println("Error running program:", err)
// os.Exit(1)
// }
@@ -114,8 +136,8 @@ func WithMouseAllMotion() ProgramOption {
// programs. For example, your program could behave like a daemon if output is
// not a TTY.
func WithoutRenderer() ProgramOption {
- return func(m *Program) {
- m.renderer = &nilRenderer{}
+ return func(p *Program) {
+ p.renderer = &nilRenderer{}
}
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/renderer.go b/vendor/github.com/charmbracelet/bubbletea/renderer.go
index aedbb666..a6f41627 100644
--- a/vendor/github.com/charmbracelet/bubbletea/renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/renderer.go
@@ -21,12 +21,35 @@ type renderer interface {
// in succession.
repaint()
+ // Clears the terminal.
+ clearScreen()
+
// Whether or not the alternate screen buffer is enabled.
altScreen() bool
-
- // Record internally that the alternate screen buffer is enabled. This
- // does not actually toggle the alternate screen buffer.
- setAltScreen(bool)
+ // Enable the alternate screen buffer.
+ enterAltScreen()
+ // Disable the alternate screen buffer.
+ exitAltScreen()
+
+ // Show the cursor.
+ showCursor()
+ // Hide the cursor.
+ hideCursor()
+
+ // enableMouseCellMotion enables mouse click, release, wheel and motion
+ // events if a mouse button is pressed (i.e., drag events).
+ enableMouseCellMotion()
+
+ // DisableMouseCellMotion disables Mouse Cell Motion tracking.
+ disableMouseCellMotion()
+
+ // EnableMouseAllMotion enables mouse click, release, wheel and motion
+ // events, regardless of whether a mouse button is pressed. Many modern
+ // terminals support this, but not all.
+ enableMouseAllMotion()
+
+ // DisableMouseAllMotion disables All Motion mouse tracking.
+ disableMouseAllMotion()
}
// repaintMsg forces a full repaint.
diff --git a/vendor/github.com/charmbracelet/bubbletea/screen.go b/vendor/github.com/charmbracelet/bubbletea/screen.go
index 63db7ae6..899db3d2 100644
--- a/vendor/github.com/charmbracelet/bubbletea/screen.go
+++ b/vendor/github.com/charmbracelet/bubbletea/screen.go
@@ -1,53 +1,169 @@
package tea
-import (
- "fmt"
- "io"
+// WindowSizeMsg is used to report the terminal size. It's sent to Update once
+// initially and then on every terminal resize. Note that Windows does not
+// have support for reporting when resizes occur as it does not support the
+// SIGWINCH signal.
+type WindowSizeMsg struct {
+ Width int
+ Height int
+}
+
+// ClearScreen is a special command that tells the program to clear the screen
+// before the next update. This can be used to move the cursor to the top left
+// of the screen and clear visual clutter when the alt screen is not in use.
+//
+// Note that it should never be necessary to call ClearScreen() for regular
+// redraws.
+func ClearScreen() Msg {
+ return clearScreenMsg{}
+}
+
+// clearScreenMsg is an internal message that signals to clear the screen.
+// You can send a clearScreenMsg with ClearScreen.
+type clearScreenMsg struct{}
+
+// EnterAltScreen is a special command that tells the Bubble Tea program to
+// enter the alternate screen buffer.
+//
+// Because commands run asynchronously, this command should not be used in your
+// model's Init function. To initialize your program with the altscreen enabled
+// use the WithAltScreen ProgramOption instead.
+func EnterAltScreen() Msg {
+ return enterAltScreenMsg{}
+}
+
+// enterAltScreenMsg in an internal message signals that the program should
+// enter alternate screen buffer. You can send a enterAltScreenMsg with
+// EnterAltScreen.
+type enterAltScreenMsg struct{}
- te "github.com/muesli/termenv"
-)
+// ExitAltScreen is a special command that tells the Bubble Tea program to exit
+// the alternate screen buffer. This command should be used to exit the
+// alternate screen buffer while the program is running.
+//
+// Note that the alternate screen buffer will be automatically exited when the
+// program quits.
+func ExitAltScreen() Msg {
+ return exitAltScreenMsg{}
+}
+
+// exitAltScreenMsg in an internal message signals that the program should exit
+// alternate screen buffer. You can send a exitAltScreenMsg with ExitAltScreen.
+type exitAltScreenMsg struct{}
-func hideCursor(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.HideCursorSeq)
+// EnableMouseCellMotion is a special command that enables mouse click,
+// release, and wheel events. Mouse movement events are also captured if
+// a mouse button is pressed (i.e., drag events).
+//
+// Because commands run asynchronously, this command should not be used in your
+// model's Init function. Use the WithMouseCellMotion ProgramOption instead.
+func EnableMouseCellMotion() Msg {
+ return enableMouseCellMotionMsg{}
}
-func showCursor(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.ShowCursorSeq)
+// enableMouseCellMotionMsg is a special command that signals to start
+// listening for "cell motion" type mouse events (ESC[?1002l). To send an
+// enableMouseCellMotionMsg, use the EnableMouseCellMotion command.
+type enableMouseCellMotionMsg struct{}
+
+// EnableMouseAllMotion is a special command that enables mouse click, release,
+// wheel, and motion events, which are delivered regardless of whether a mouse
+// button is pressed, effectively enabling support for hover interactions.
+//
+// Many modern terminals support this, but not all. If in doubt, use
+// EnableMouseCellMotion instead.
+//
+// Because commands run asynchronously, this command should not be used in your
+// model's Init function. Use the WithMouseAllMotion ProgramOption instead.
+func EnableMouseAllMotion() Msg {
+ return enableMouseAllMotionMsg{}
}
-func clearLine(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.EraseLineSeq, 2)
+// enableMouseAllMotionMsg is a special command that signals to start listening
+// for "all motion" type mouse events (ESC[?1003l). To send an
+// enableMouseAllMotionMsg, use the EnableMouseAllMotion command.
+type enableMouseAllMotionMsg struct{}
+
+// DisableMouse is a special command that stops listening for mouse events.
+func DisableMouse() Msg {
+ return disableMouseMsg{}
}
-func cursorUp(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.CursorUpSeq, 1)
+// disableMouseMsg is an internal message that signals to stop listening
+// for mouse events. To send a disableMouseMsg, use the DisableMouse command.
+type disableMouseMsg struct{}
+
+// HideCursor is a special command for manually instructing Bubble Tea to hide
+// the cursor. In some rare cases, certain operations will cause the terminal
+// to show the cursor, which is normally hidden for the duration of a Bubble
+// Tea program's lifetime. You will most likely not need to use this command.
+func HideCursor() Msg {
+ return hideCursorMsg{}
}
-func cursorDown(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.CursorDownSeq, 1)
+// hideCursorMsg is an internal command used to hide the cursor. You can send
+// this message with HideCursor.
+type hideCursorMsg struct{}
+
+// ShowCursor is a special command for manually instructing Bubble Tea to show
+// the cursor.
+func ShowCursor() Msg {
+ return showCursorMsg{}
}
-func insertLine(w io.Writer, numLines int) {
- fmt.Fprintf(w, te.CSI+"%dL", numLines)
+// showCursorMsg is an internal command used to show the cursor. You can send
+// this message with ShowCursor.
+type showCursorMsg struct{}
+
+// EnterAltScreen enters the alternate screen buffer, which consumes the entire
+// terminal window. ExitAltScreen will return the terminal to its former state.
+//
+// Deprecated: Use the WithAltScreen ProgramOption instead.
+func (p *Program) EnterAltScreen() {
+ if p.renderer != nil {
+ p.renderer.enterAltScreen()
+ }
}
-func moveCursor(w io.Writer, row, col int) {
- fmt.Fprintf(w, te.CSI+te.CursorPositionSeq, row, col)
+// ExitAltScreen exits the alternate screen buffer.
+//
+// Deprecated: The altscreen will exited automatically when the program exits.
+func (p *Program) ExitAltScreen() {
+ if p.renderer != nil {
+ p.renderer.exitAltScreen()
+ }
}
-func changeScrollingRegion(w io.Writer, top, bottom int) {
- fmt.Fprintf(w, te.CSI+te.ChangeScrollingRegionSeq, top, bottom)
+// EnableMouseCellMotion enables mouse click, release, wheel and motion events
+// if a mouse button is pressed (i.e., drag events).
+//
+// Deprecated: Use the WithMouseCellMotion ProgramOption instead.
+func (p *Program) EnableMouseCellMotion() {
+ p.renderer.enableMouseCellMotion()
}
-func cursorBack(w io.Writer, n int) {
- fmt.Fprintf(w, te.CSI+te.CursorBackSeq, n)
+// DisableMouseCellMotion disables Mouse Cell Motion tracking. This will be
+// called automatically when exiting a Bubble Tea program.
+//
+// Deprecated: The mouse will automatically be disabled when the program exits.
+func (p *Program) DisableMouseCellMotion() {
+ p.renderer.disableMouseCellMotion()
}
-func enterAltScreen(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.AltScreenSeq)
- moveCursor(w, 0, 0)
+// EnableMouseAllMotion enables mouse click, release, wheel and motion events,
+// regardless of whether a mouse button is pressed. Many modern terminals
+// support this, but not all.
+//
+// Deprecated: Use the WithMouseAllMotion ProgramOption instead.
+func (p *Program) EnableMouseAllMotion() {
+ p.renderer.enableMouseAllMotion()
}
-func exitAltScreen(w io.Writer) {
- fmt.Fprintf(w, te.CSI+te.ExitAltScreenSeq)
+// DisableMouseAllMotion disables All Motion mouse tracking. This will be
+// called automatically when exiting a Bubble Tea program.
+//
+// Deprecated: The mouse will automatically be disabled when the program exits.
+func (p *Program) DisableMouseAllMotion() {
+ p.renderer.disableMouseAllMotion()
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
index ef9ed9a3..826f58b9 100644
--- a/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
+++ b/vendor/github.com/charmbracelet/bubbletea/signals_unix.go
@@ -4,18 +4,15 @@
package tea
import (
- "context"
"os"
"os/signal"
"syscall"
-
- "golang.org/x/term"
)
// listenForResize sends messages (or errors) when the terminal resizes.
// Argument output should be the file descriptor for the terminal; usually
// os.Stdout.
-func listenForResize(ctx context.Context, output *os.File, msgs chan Msg, errs chan error, done chan struct{}) {
+func (p *Program) listenForResize(done chan struct{}) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGWINCH)
@@ -26,20 +23,11 @@ func listenForResize(ctx context.Context, output *os.File, msgs chan Msg, errs c
for {
select {
- case <-ctx.Done():
+ case <-p.ctx.Done():
return
case <-sig:
}
- w, h, err := term.GetSize(int(output.Fd()))
- if err != nil {
- errs <- err
- }
-
- select {
- case <-ctx.Done():
- return
- case msgs <- WindowSizeMsg{w, h}:
- }
+ p.checkResize()
}
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/signals_windows.go b/vendor/github.com/charmbracelet/bubbletea/signals_windows.go
index 71da4f00..2fc6f8ae 100644
--- a/vendor/github.com/charmbracelet/bubbletea/signals_windows.go
+++ b/vendor/github.com/charmbracelet/bubbletea/signals_windows.go
@@ -3,14 +3,8 @@
package tea
-import (
- "context"
- "os"
-)
-
// listenForResize is not available on windows because windows does not
// implement syscall.SIGWINCH.
-func listenForResize(ctx context.Context, output *os.File, msgs chan Msg,
- errs chan error, done chan struct{}) {
+func (p *Program) listenForResize(done chan struct{}) {
close(done)
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
index d2bc387f..17b44e23 100644
--- a/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
+++ b/vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
@@ -10,6 +10,7 @@ import (
"github.com/muesli/ansi/compressor"
"github.com/muesli/reflow/truncate"
+ "github.com/muesli/termenv"
)
const (
@@ -24,18 +25,22 @@ const (
// In cases where very high performance is needed the renderer can be told
// to exclude ranges of lines, allowing them to be written to directly.
type standardRenderer struct {
- out io.Writer
+ mtx *sync.Mutex
+ out *termenv.Output
+
buf bytes.Buffer
queuedMessageLines []string
framerate time.Duration
ticker *time.Ticker
- mtx *sync.Mutex
done chan struct{}
lastRender string
linesRendered int
useANSICompressor bool
once sync.Once
+ // cursor visibility state
+ cursorHidden bool
+
// essentially whether or not we're using the full size of the terminal
altScreenActive bool
@@ -49,16 +54,16 @@ type standardRenderer struct {
// newRenderer creates a new renderer. Normally you'll want to initialize it
// with os.Stdout as the first argument.
-func newRenderer(out io.Writer, mtx *sync.Mutex, useANSICompressor bool) renderer {
+func newRenderer(out *termenv.Output, useANSICompressor bool) renderer {
r := &standardRenderer{
out: out,
- mtx: mtx,
+ mtx: &sync.Mutex{},
framerate: defaultFramerate,
useANSICompressor: useANSICompressor,
queuedMessageLines: []string{},
}
if r.useANSICompressor {
- r.out = &compressor.Writer{Forward: out}
+ r.out = termenv.NewOutput(&compressor.Writer{Forward: out})
}
return r
}
@@ -74,14 +79,19 @@ func (r *standardRenderer) start() {
// stop permanently halts the renderer, rendering the final frame.
func (r *standardRenderer) stop() {
+ // flush locks the mutex
r.flush()
- clearLine(r.out)
+
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.ClearLine()
r.once.Do(func() {
close(r.done)
})
if r.useANSICompressor {
- if w, ok := r.out.(io.WriteCloser); ok {
+ if w, ok := r.out.TTY().(io.WriteCloser); ok {
_ = w.Close()
}
}
@@ -89,7 +99,10 @@ func (r *standardRenderer) stop() {
// kill halts the renderer. The final frame will not be rendered.
func (r *standardRenderer) kill() {
- clearLine(r.out)
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.ClearLine()
r.once.Do(func() {
close(r.done)
})
@@ -122,9 +135,19 @@ func (r *standardRenderer) flush() {
}
// Output buffer
- out := new(bytes.Buffer)
+ buf := &bytes.Buffer{}
+ out := termenv.NewOutput(buf)
newLines := strings.Split(r.buf.String(), "\n")
+
+ // If we know the output's height, we can use it to determine how many
+ // lines we can render. We drop lines from the top of the render buffer if
+ // necessary, as we can't navigate the cursor into the terminal's scrollback
+ // buffer.
+ if r.height > 0 && len(newLines) > r.height {
+ newLines = newLines[len(newLines)-r.height:]
+ }
+
numLinesThisFlush := len(newLines)
oldLines := strings.Split(r.lastRender, "\n")
skipLines := make(map[int]struct{})
@@ -145,10 +168,10 @@ func (r *standardRenderer) flush() {
if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) {
skipLines[i] = struct{}{}
} else if _, exists := r.ignoreLines[i]; !exists {
- clearLine(out)
+ out.ClearLine()
}
- cursorUp(out)
+ out.CursorUp(1)
}
if _, exists := r.ignoreLines[0]; !exists {
@@ -161,8 +184,8 @@ func (r *standardRenderer) flush() {
// standard (whereas others are proprietary to, say, VT100/VT52).
// If cursor previous line (ESC[ + + F) were better supported
// we could use that above to eliminate this step.
- cursorBack(out, r.width)
- clearLine(out)
+ out.CursorBack(r.width)
+ out.ClearLine()
}
}
@@ -179,7 +202,7 @@ func (r *standardRenderer) flush() {
if _, skip := skipLines[i]; skip {
// Unless this is the last line, move the cursor down.
if i < len(newLines)-1 {
- cursorDown(out)
+ out.CursorDown(1)
}
} else {
line := newLines[i]
@@ -195,10 +218,10 @@ func (r *standardRenderer) flush() {
line = truncate.String(line, uint(r.width))
}
- _, _ = io.WriteString(out, line)
+ _, _ = out.WriteString(line)
if i < len(newLines)-1 {
- _, _ = io.WriteString(out, "\r\n")
+ _, _ = out.WriteString("\r\n")
}
}
}
@@ -210,12 +233,12 @@ func (r *standardRenderer) flush() {
// This case fixes a bug in macOS terminal. In other terminals the
// other case seems to do the job regardless of whether or not we're
// using the full terminal window.
- moveCursor(out, r.linesRendered, 0)
+ out.MoveCursor(r.linesRendered, 0)
} else {
- cursorBack(out, r.width)
+ out.CursorBack(r.width)
}
- _, _ = r.out.Write(out.Bytes())
+ _, _ = r.out.Write(buf.Bytes())
r.lastRender = r.buf.String()
r.buf.Reset()
}
@@ -242,15 +265,122 @@ func (r *standardRenderer) repaint() {
r.lastRender = ""
}
+func (r *standardRenderer) clearScreen() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.ClearScreen()
+ r.out.MoveCursor(1, 1)
+
+ r.repaint()
+}
+
func (r *standardRenderer) altScreen() bool {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
return r.altScreenActive
}
-func (r *standardRenderer) setAltScreen(v bool) {
- r.altScreenActive = v
+func (r *standardRenderer) enterAltScreen() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ if r.altScreenActive {
+ return
+ }
+
+ r.altScreenActive = true
+ r.out.AltScreen()
+
+ // Ensure that the terminal is cleared, even when it doesn't support
+ // alt screen (or alt screen support is disabled, like GNU screen by
+ // default).
+ //
+ // Note: we can't use r.clearScreen() here because the mutex is already
+ // locked.
+ r.out.ClearScreen()
+ r.out.MoveCursor(1, 1)
+
+ // cmd.exe and other terminals keep separate cursor states for the AltScreen
+ // and the main buffer. We have to explicitly reset the cursor visibility
+ // whenever we enter AltScreen.
+ if r.cursorHidden {
+ r.out.HideCursor()
+ } else {
+ r.out.ShowCursor()
+ }
+
r.repaint()
}
+func (r *standardRenderer) exitAltScreen() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ if !r.altScreenActive {
+ return
+ }
+
+ r.altScreenActive = false
+ r.out.ExitAltScreen()
+
+ // cmd.exe and other terminals keep separate cursor states for the AltScreen
+ // and the main buffer. We have to explicitly reset the cursor visibility
+ // whenever we exit AltScreen.
+ if r.cursorHidden {
+ r.out.HideCursor()
+ } else {
+ r.out.ShowCursor()
+ }
+
+ r.repaint()
+}
+
+func (r *standardRenderer) showCursor() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.cursorHidden = false
+ r.out.ShowCursor()
+}
+
+func (r *standardRenderer) hideCursor() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.cursorHidden = true
+ r.out.HideCursor()
+}
+
+func (r *standardRenderer) enableMouseCellMotion() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.EnableMouseCellMotion()
+}
+
+func (r *standardRenderer) disableMouseCellMotion() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.DisableMouseCellMotion()
+}
+
+func (r *standardRenderer) enableMouseAllMotion() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.EnableMouseAllMotion()
+}
+
+func (r *standardRenderer) disableMouseAllMotion() {
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ r.out.DisableMouseAllMotion()
+}
+
// setIgnoredLines specifies lines not to be touched by the standard Bubble Tea
// renderer.
func (r *standardRenderer) setIgnoredLines(from int, to int) {
@@ -270,15 +400,17 @@ func (r *standardRenderer) setIgnoredLines(from int, to int) {
// Erase ignored lines
if r.linesRendered > 0 {
- out := new(bytes.Buffer)
+ buf := &bytes.Buffer{}
+ out := termenv.NewOutput(buf)
+
for i := r.linesRendered - 1; i >= 0; i-- {
if _, exists := r.ignoreLines[i]; exists {
- clearLine(out)
+ out.ClearLine()
}
- cursorUp(out)
+ out.CursorUp(1)
}
- moveCursor(out, r.linesRendered, 0) // put cursor back
- _, _ = r.out.Write(out.Bytes())
+ out.MoveCursor(r.linesRendered, 0) // put cursor back
+ _, _ = r.out.Write(buf.Bytes())
}
}
@@ -311,18 +443,19 @@ func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary
r.mtx.Lock()
defer r.mtx.Unlock()
- b := new(bytes.Buffer)
+ buf := &bytes.Buffer{}
+ out := termenv.NewOutput(buf)
- changeScrollingRegion(b, topBoundary, bottomBoundary)
- moveCursor(b, topBoundary, 0)
- insertLine(b, len(lines))
- _, _ = io.WriteString(b, strings.Join(lines, "\r\n"))
- changeScrollingRegion(b, 0, r.height)
+ out.ChangeScrollingRegion(topBoundary, bottomBoundary)
+ out.MoveCursor(topBoundary, 0)
+ out.InsertLines(len(lines))
+ _, _ = out.WriteString(strings.Join(lines, "\r\n"))
+ out.ChangeScrollingRegion(0, r.height)
// Move cursor back to where the main rendering routine expects it to be
- moveCursor(b, r.linesRendered, 0)
+ out.MoveCursor(r.linesRendered, 0)
- _, _ = r.out.Write(b.Bytes())
+ _, _ = r.out.Write(buf.Bytes())
}
// insertBottom effectively scrolls down. It inserts lines at the bottom of
@@ -338,17 +471,18 @@ func (r *standardRenderer) insertBottom(lines []string, topBoundary, bottomBound
r.mtx.Lock()
defer r.mtx.Unlock()
- b := new(bytes.Buffer)
+ buf := &bytes.Buffer{}
+ out := termenv.NewOutput(buf)
- changeScrollingRegion(b, topBoundary, bottomBoundary)
- moveCursor(b, bottomBoundary, 0)
- _, _ = io.WriteString(b, "\r\n"+strings.Join(lines, "\r\n"))
- changeScrollingRegion(b, 0, r.height)
+ out.ChangeScrollingRegion(topBoundary, bottomBoundary)
+ out.MoveCursor(bottomBoundary, 0)
+ _, _ = out.WriteString("\r\n" + strings.Join(lines, "\r\n"))
+ out.ChangeScrollingRegion(0, r.height)
// Move cursor back to where the main rendering routine expects it to be
- moveCursor(b, r.linesRendered, 0)
+ out.MoveCursor(r.linesRendered, 0)
- _, _ = r.out.Write(b.Bytes())
+ _, _ = r.out.Write(buf.Bytes())
}
// handleMessages handles internal messages for the renderer.
@@ -365,6 +499,7 @@ func (r *standardRenderer) handleMessages(msg Msg) {
r.mtx.Lock()
r.width = msg.Width
r.height = msg.Height
+ r.repaint()
r.mtx.Unlock()
case clearScrollAreaMsg:
diff --git a/vendor/github.com/charmbracelet/bubbletea/tea.go b/vendor/github.com/charmbracelet/bubbletea/tea.go
index 28065a00..03734bc5 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tea.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tea.go
@@ -11,6 +11,7 @@ package tea
import (
"context"
+ "errors"
"fmt"
"io"
"os"
@@ -18,15 +19,16 @@ import (
"runtime/debug"
"sync"
"syscall"
- "time"
"github.com/containerd/console"
isatty "github.com/mattn/go-isatty"
"github.com/muesli/cancelreader"
- te "github.com/muesli/termenv"
- "golang.org/x/term"
+ "github.com/muesli/termenv"
)
+// ErrProgramKilled is returned by [Program.Run] when the program got killed.
+var ErrProgramKilled = errors.New("program was killed")
+
// Msg contain data from the result of a IO operation. Msgs trigger the update
// function and, henceforth, the UI.
type Msg interface{}
@@ -55,6 +57,8 @@ type Model interface {
// update function.
type Cmd func() Msg
+type handlers []chan struct{}
+
// Options to customize the program during its initialization. These are
// generally set with ProgramOptions.
//
@@ -72,6 +76,13 @@ const (
withInputTTY
withCustomInput
withANSICompressor
+ withoutSignalHandler
+
+ // Catching panics is incredibly useful for restoring the terminal to a
+ // usable state after a panic occurs. When this is set, Bubble Tea will
+ // recover from panics, print the stack trace, and disable raw mode. This
+ // feature is on by default.
+ withoutCatchPanics
)
// Program is a terminal user interface.
@@ -82,32 +93,26 @@ type Program struct {
// treated as bits. These options can be set via various ProgramOptions.
startupOptions startupOptions
- ctx context.Context
- mtx *sync.Mutex
-
- msgs chan Msg
- errs chan error
- readLoopDone chan struct{}
-
- output io.Writer // where to send output. this will usually be os.Stdout.
- input io.Reader // this will usually be os.Stdin.
- cancelReader cancelreader.CancelReader
-
- renderer renderer
- altScreenActive bool
- altScreenWasActive bool // was the altscreen active before releasing the terminal?
+ ctx context.Context
+ cancel context.CancelFunc
- // CatchPanics is incredibly useful for restoring the terminal to a usable
- // state after a panic occurs. When this is set, Bubble Tea will recover
- // from panics, print the stack trace, and disable raw mode. This feature
- // is on by default.
- CatchPanics bool
+ msgs chan Msg
+ errs chan error
- ignoreSignals bool
+ // where to send output, this will usually be os.Stdout.
+ output *termenv.Output
+ restoreOutput func() error
+ renderer renderer
- killc chan bool
+ // where to read inputs from, this will usually be os.Stdin.
+ input io.Reader
+ cancelReader cancelreader.CancelReader
+ readLoopDone chan struct{}
+ console console.Console
- console console.Console
+ // was the altscreen active before releasing the terminal?
+ altScreenWasActive bool
+ ignoreSignals bool
// Stores the original reference to stdin for cases where input is not a
// TTY on windows and we've automatically opened CONIN$ to receive input.
@@ -119,34 +124,6 @@ type Program struct {
windowsStdin *os.File //nolint:golint,structcheck,unused
}
-// Batch performs a bunch of commands concurrently with no ordering guarantees
-// about the results. Use a Batch to return several commands.
-//
-// Example:
-//
-// func (m model) Init() Cmd {
-// return tea.Batch(someCommand, someOtherCommand)
-// }
-func Batch(cmds ...Cmd) Cmd {
- var validCmds []Cmd
- for _, c := range cmds {
- if c == nil {
- continue
- }
- validCmds = append(validCmds, c)
- }
- if len(validCmds) == 0 {
- return nil
- }
- return func() Msg {
- return batchMsg(validCmds)
- }
-}
-
-// batchMsg is the internal message used to perform a bunch of commands. You
-// can send a batchMsg with Batch.
-type batchMsg []Cmd
-
// Quit is a special command that tells the Bubble Tea program to exit.
func Quit() Msg {
return quitMsg{}
@@ -156,150 +133,210 @@ func Quit() Msg {
// send a quitMsg with Quit.
type quitMsg struct{}
-// EnterAltScreen is a special command that tells the Bubble Tea program to
-// enter the alternate screen buffer.
-//
-// Because commands run asynchronously, this command should not be used in your
-// model's Init function. To initialize your program with the altscreen enabled
-// use the WithAltScreen ProgramOption instead.
-func EnterAltScreen() Msg {
- return enterAltScreenMsg{}
-}
+// NewProgram creates a new Program.
+func NewProgram(model Model, opts ...ProgramOption) *Program {
+ p := &Program{
+ initialModel: model,
+ input: os.Stdin,
+ msgs: make(chan Msg),
+ }
-// enterAltScreenMsg in an internal message signals that the program should
-// enter alternate screen buffer. You can send a enterAltScreenMsg with
-// EnterAltScreen.
-type enterAltScreenMsg struct{}
+ // Apply all options to the program.
+ for _, opt := range opts {
+ opt(p)
+ }
-// ExitAltScreen is a special command that tells the Bubble Tea program to exit
-// the alternate screen buffer. This command should be used to exit the
-// alternate screen buffer while the program is running.
-//
-// Note that the alternate screen buffer will be automatically exited when the
-// program quits.
-func ExitAltScreen() Msg {
- return exitAltScreenMsg{}
-}
+ // A context can be provided with a ProgramOption, but if none was provided
+ // we'll use the default background context.
+ if p.ctx == nil {
+ p.ctx = context.Background()
+ }
+ // Initialize context and teardown channel.
+ p.ctx, p.cancel = context.WithCancel(p.ctx)
-// exitAltScreenMsg in an internal message signals that the program should exit
-// alternate screen buffer. You can send a exitAltScreenMsg with ExitAltScreen.
-type exitAltScreenMsg struct{}
+ // if no output was set, set it to stdout
+ if p.output == nil {
+ p.output = termenv.DefaultOutput()
-// EnableMouseCellMotion is a special command that enables mouse click,
-// release, and wheel events. Mouse movement events are also captured if
-// a mouse button is pressed (i.e., drag events).
-//
-// Because commands run asynchronously, this command should not be used in your
-// model's Init function. Use the WithMouseCellMotion ProgramOption instead.
-func EnableMouseCellMotion() Msg {
- return enableMouseCellMotionMsg{}
-}
+ // cache detected color values
+ termenv.WithColorCache(true)(p.output)
+ }
-// enableMouseCellMotionMsg is a special command that signals to start
-// listening for "cell motion" type mouse events (ESC[?1002l). To send an
-// enableMouseCellMotionMsg, use the EnableMouseCellMotion command.
-type enableMouseCellMotionMsg struct{}
+ p.restoreOutput, _ = termenv.EnableVirtualTerminalProcessing(p.output)
-// EnableMouseAllMotion is a special command that enables mouse click, release,
-// wheel, and motion events, which are delivered regardless of whether a mouse
-// button is pressed, effectively enabling support for hover interactions.
-//
-// Many modern terminals support this, but not all. If in doubt, use
-// EnableMouseCellMotion instead.
-//
-// Because commands run asynchronously, this command should not be used in your
-// model's Init function. Use the WithMouseAllMotion ProgramOption instead.
-func EnableMouseAllMotion() Msg {
- return enableMouseAllMotionMsg{}
+ return p
}
-// enableMouseAllMotionMsg is a special command that signals to start listening
-// for "all motion" type mouse events (ESC[?1003l). To send an
-// enableMouseAllMotionMsg, use the EnableMouseAllMotion command.
-type enableMouseAllMotionMsg struct{}
+func (p *Program) handleSignals() chan struct{} {
+ ch := make(chan struct{})
-// DisableMouse is a special command that stops listening for mouse events.
-func DisableMouse() Msg {
- return disableMouseMsg{}
-}
+ // Listen for SIGINT and SIGTERM.
+ //
+ // In most cases ^C will not send an interrupt because the terminal will be
+ // in raw mode and ^C will be captured as a keystroke and sent along to
+ // Program.Update as a KeyMsg. When input is not a TTY, however, ^C will be
+ // caught here.
+ //
+ // SIGTERM is sent by unix utilities (like kill) to terminate a process.
+ go func() {
+ sig := make(chan os.Signal, 1)
+ signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
+ defer func() {
+ signal.Stop(sig)
+ close(ch)
+ }()
-// disableMouseMsg is an internal message that that signals to stop listening
-// for mouse events. To send a disableMouseMsg, use the DisableMouse command.
-type disableMouseMsg struct{}
-
-// WindowSizeMsg is used to report the terminal size. It's sent to Update once
-// initially and then on every terminal resize. Note that Windows does not
-// have support for reporting when resizes occur as it does not support the
-// SIGWINCH signal.
-type WindowSizeMsg struct {
- Width int
- Height int
-}
+ for {
+ select {
+ case <-p.ctx.Done():
+ return
-// HideCursor is a special command for manually instructing Bubble Tea to hide
-// the cursor. In some rare cases, certain operations will cause the terminal
-// to show the cursor, which is normally hidden for the duration of a Bubble
-// Tea program's lifetime. You will most likely not need to use this command.
-func HideCursor() Msg {
- return hideCursorMsg{}
+ case <-sig:
+ if !p.ignoreSignals {
+ p.msgs <- quitMsg{}
+ return
+ }
+ }
+ }
+ }()
+
+ return ch
}
-// hideCursorMsg is an internal command used to hide the cursor. You can send
-// this message with HideCursor.
-type hideCursorMsg struct{}
+// handleResize handles terminal resize events.
+func (p *Program) handleResize() chan struct{} {
+ ch := make(chan struct{})
-// NewProgram creates a new Program.
-func NewProgram(model Model, opts ...ProgramOption) *Program {
- p := &Program{
- mtx: &sync.Mutex{},
- initialModel: model,
- output: os.Stdout,
- input: os.Stdin,
- msgs: make(chan Msg),
- CatchPanics: true,
- killc: make(chan bool, 1),
- }
+ if f, ok := p.output.TTY().(*os.File); ok && isatty.IsTerminal(f.Fd()) {
+ // Get the initial terminal size and send it to the program.
+ go p.checkResize()
- // Apply all options to the program.
- for _, opt := range opts {
- opt(p)
+ // Listen for window resizes.
+ go p.listenForResize(ch)
+ } else {
+ close(ch)
}
- return p
+ return ch
}
-// StartReturningModel initializes the program. Returns the final model.
-func (p *Program) StartReturningModel() (Model, error) {
- cmds := make(chan Cmd)
- p.errs = make(chan error)
+// handleCommands runs commands in a goroutine and sends the result to the
+// program's message channel.
+func (p *Program) handleCommands(cmds chan Cmd) chan struct{} {
+ ch := make(chan struct{})
+
+ go func() {
+ defer close(ch)
+
+ for {
+ select {
+ case <-p.ctx.Done():
+ return
+
+ case cmd := <-cmds:
+ if cmd == nil {
+ continue
+ }
+
+ // Don't wait on these goroutines, otherwise the shutdown
+ // latency would get too large as a Cmd can run for some time
+ // (e.g. tick commands that sleep for half a second). It's not
+ // possible to cancel them so we'll have to leak the goroutine
+ // until Cmd returns.
+ go func() {
+ msg := cmd() // this can be long.
+ p.Send(msg)
+ }()
+ }
+ }
+ }()
+
+ return ch
+}
+
+// eventLoop is the central message loop. It receives and handles the default
+// Bubble Tea messages, update the model and triggers redraws.
+func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
+ for {
+ select {
+ case <-p.ctx.Done():
+ return model, nil
+
+ case err := <-p.errs:
+ return model, err
+
+ case msg := <-p.msgs:
+ // Handle special internal messages.
+ switch msg := msg.(type) {
+ case quitMsg:
+ return model, nil
+
+ case clearScreenMsg:
+ p.renderer.clearScreen()
- // Channels for managing goroutine lifecycles.
- var (
- sigintLoopDone = make(chan struct{})
- cmdLoopDone = make(chan struct{})
- resizeLoopDone = make(chan struct{})
- initSignalDone = make(chan struct{})
-
- waitForGoroutines = func(withReadLoop bool) {
- if withReadLoop {
- select {
- case <-p.readLoopDone:
- case <-time.After(500 * time.Millisecond):
- // The read loop hangs, which means the input
- // cancelReader's cancel function has returned true even
- // though it was not able to cancel the read.
+ case enterAltScreenMsg:
+ p.renderer.enterAltScreen()
+
+ case exitAltScreenMsg:
+ p.renderer.exitAltScreen()
+
+ case enableMouseCellMotionMsg:
+ p.renderer.enableMouseCellMotion()
+
+ case enableMouseAllMotionMsg:
+ p.renderer.enableMouseAllMotion()
+
+ case disableMouseMsg:
+ p.renderer.disableMouseCellMotion()
+ p.renderer.disableMouseAllMotion()
+
+ case showCursorMsg:
+ p.renderer.showCursor()
+
+ case hideCursorMsg:
+ p.renderer.hideCursor()
+
+ case execMsg:
+ // NB: this blocks.
+ p.exec(msg.cmd, msg.fn)
+
+ case BatchMsg:
+ for _, cmd := range msg {
+ cmds <- cmd
}
+ continue
+
+ case sequenceMsg:
+ go func() {
+ // Execute commands one at a time, in order.
+ for _, cmd := range msg {
+ p.Send(cmd())
+ }
+ }()
+ }
+
+ // Process internal messages for the renderer.
+ if r, ok := p.renderer.(*standardRenderer); ok {
+ r.handleMessages(msg)
}
- <-cmdLoopDone
- <-resizeLoopDone
- <-sigintLoopDone
- <-initSignalDone
+
+ var cmd Cmd
+ model, cmd = model.Update(msg) // run update
+ cmds <- cmd // process command (if any)
+ p.renderer.write(model.View()) // send view to renderer
}
- )
+ }
+}
+
+// Run initializes the program and runs its event loops, blocking until it gets
+// terminated by either [Program.Quit], [Program.Kill], or its signal handler.
+// Returns the final model.
+func (p *Program) Run() (Model, error) {
+ handlers := handlers{}
+ cmds := make(chan Cmd)
+ p.errs = make(chan error)
- var cancelContext context.CancelFunc
- p.ctx, cancelContext = context.WithCancel(context.Background())
- defer cancelContext()
+ defer p.cancel()
switch {
case p.startupOptions.has(withInputTTY):
@@ -308,9 +345,7 @@ func (p *Program) StartReturningModel() (Model, error) {
if err != nil {
return p.initialModel, err
}
-
- defer f.Close() // nolint:errcheck
-
+ defer f.Close() //nolint:errcheck
p.input = f
case !p.startupOptions.has(withCustomInput):
@@ -322,7 +357,6 @@ func (p *Program) StartReturningModel() (Model, error) {
if !isFile {
break
}
-
if isatty.IsTerminal(f.Fd()) {
break
}
@@ -331,38 +365,17 @@ func (p *Program) StartReturningModel() (Model, error) {
if err != nil {
return p.initialModel, err
}
-
- defer f.Close() // nolint:errcheck
-
+ defer f.Close() //nolint:errcheck
p.input = f
}
- // Listen for SIGINT. Note that in most cases ^C will not send an
- // interrupt because the terminal will be in raw mode and thus capture
- // that keystroke and send it along to Program.Update. If input is not a
- // TTY, however, ^C will be caught here.
- go func() {
- sig := make(chan os.Signal, 1)
- signal.Notify(sig, syscall.SIGINT)
- defer func() {
- signal.Stop(sig)
- close(sigintLoopDone)
- }()
-
- for {
- select {
- case <-p.ctx.Done():
- return
- case <-sig:
- if !p.ignoreSignals {
- p.msgs <- quitMsg{}
- return
- }
- }
- }
- }()
+ // Handle signals.
+ if !p.startupOptions.has(withoutSignalHandler) {
+ handlers.add(p.handleSignals())
+ }
- if p.CatchPanics {
+ // Recover from panics.
+ if !p.startupOptions.has(withoutCatchPanics) {
defer func() {
if r := recover(); r != nil {
p.shutdown(true)
@@ -373,44 +386,45 @@ func (p *Program) StartReturningModel() (Model, error) {
}()
}
+ // If no renderer is set use the standard one.
+ if p.renderer == nil {
+ p.renderer = newRenderer(p.output, p.startupOptions.has(withANSICompressor))
+ }
+
// Check if output is a TTY before entering raw mode, hiding the cursor and
// so on.
if err := p.initTerminal(); err != nil {
return p.initialModel, err
}
- // If no renderer is set use the standard one.
- if p.renderer == nil {
- p.renderer = newRenderer(p.output, p.mtx, p.startupOptions.has(withANSICompressor))
- }
-
// Honor program startup options.
if p.startupOptions&withAltScreen != 0 {
- p.EnterAltScreen()
+ p.renderer.enterAltScreen()
}
if p.startupOptions&withMouseCellMotion != 0 {
- p.EnableMouseCellMotion()
+ p.renderer.enableMouseCellMotion()
} else if p.startupOptions&withMouseAllMotion != 0 {
- p.EnableMouseAllMotion()
+ p.renderer.enableMouseAllMotion()
}
// Initialize the program.
model := p.initialModel
if initCmd := model.Init(); initCmd != nil {
+ ch := make(chan struct{})
+ handlers.add(ch)
+
go func() {
- defer close(initSignalDone)
+ defer close(ch)
+
select {
case cmds <- initCmd:
case <-p.ctx.Done():
}
}()
- } else {
- close(initSignalDone)
}
// Start the renderer.
p.renderer.start()
- p.renderer.setAltScreen(p.altScreenActive)
// Render the initial view.
p.renderer.write(model.View())
@@ -420,132 +434,58 @@ func (p *Program) StartReturningModel() (Model, error) {
if err := p.initCancelReader(); err != nil {
return model, err
}
- } else {
- defer close(p.readLoopDone)
}
- defer p.cancelReader.Close() // nolint:errcheck
- if f, ok := p.output.(*os.File); ok && isatty.IsTerminal(f.Fd()) {
- // Get the initial terminal size and send it to the program.
- go func() {
- w, h, err := term.GetSize(int(f.Fd()))
- if err != nil {
- p.errs <- err
- }
+ // Handle resize events.
+ handlers.add(p.handleResize())
- select {
- case <-p.ctx.Done():
- case p.msgs <- WindowSizeMsg{w, h}:
- }
- }()
+ // Process commands.
+ handlers.add(p.handleCommands(cmds))
- // Listen for window resizes.
- go listenForResize(p.ctx, f, p.msgs, p.errs, resizeLoopDone)
+ // Run event loop, handle updates and draw.
+ model, err := p.eventLoop(model, cmds)
+ killed := p.ctx.Err() != nil
+ if killed {
+ err = ErrProgramKilled
} else {
- close(resizeLoopDone)
+ // Ensure we rendered the final state of the model.
+ p.renderer.write(model.View())
}
- // Process commands.
- go func() {
- defer close(cmdLoopDone)
-
- for {
- select {
- case <-p.ctx.Done():
-
- return
- case cmd := <-cmds:
- if cmd == nil {
- continue
- }
-
- // Don't wait on these goroutines, otherwise the shutdown
- // latency would get too large as a Cmd can run for some time
- // (e.g. tick commands that sleep for half a second). It's not
- // possible to cancel them so we'll have to leak the goroutine
- // until Cmd returns.
- go func() {
- select {
- case p.msgs <- cmd():
- case <-p.ctx.Done():
- }
- }()
- }
- }
- }()
-
- // Handle updates and draw.
- for {
- select {
- case <-p.killc:
- return nil, nil
- case err := <-p.errs:
- cancelContext()
- waitForGoroutines(p.cancelReader.Cancel())
- p.shutdown(false)
- return model, err
-
- case msg := <-p.msgs:
-
- // Handle special internal messages.
- switch msg := msg.(type) {
- case quitMsg:
- cancelContext()
- waitForGoroutines(p.cancelReader.Cancel())
- p.shutdown(false)
- return model, nil
-
- case batchMsg:
- for _, cmd := range msg {
- cmds <- cmd
- }
- continue
-
- case WindowSizeMsg:
- p.mtx.Lock()
- p.renderer.repaint()
- p.mtx.Unlock()
-
- case enterAltScreenMsg:
- p.EnterAltScreen()
-
- case exitAltScreenMsg:
- p.ExitAltScreen()
-
- case enableMouseCellMotionMsg:
- p.EnableMouseCellMotion()
+ // Tear down.
+ p.cancel()
- case enableMouseAllMotionMsg:
- p.EnableMouseAllMotion()
+ // Wait for input loop to finish.
+ if p.cancelReader.Cancel() {
+ p.waitForReadLoop()
+ }
+ _ = p.cancelReader.Close()
- case disableMouseMsg:
- p.DisableMouseCellMotion()
- p.DisableMouseAllMotion()
+ // Wait for all handlers to finish.
+ handlers.shutdown()
- case hideCursorMsg:
- hideCursor(p.output)
+ // Restore terminal state.
+ p.shutdown(killed)
- case execMsg:
- // NB: this blocks.
- p.exec(msg.cmd, msg.fn)
- }
-
- // Process internal messages for the renderer.
- if r, ok := p.renderer.(*standardRenderer); ok {
- r.handleMessages(msg)
- }
+ return model, err
+}
- var cmd Cmd
- model, cmd = model.Update(msg) // run update
- cmds <- cmd // process command (if any)
- p.renderer.write(model.View()) // send view to renderer
- }
- }
+// StartReturningModel initializes the program and runs its event loops,
+// blocking until it gets terminated by either [Program.Quit], [Program.Kill],
+// or its signal handler. Returns the final model.
+//
+// Deprecated: please use [Program.Run] instead.
+func (p *Program) StartReturningModel() (Model, error) {
+ return p.Run()
}
-// Start initializes the program. Ignores the final model.
+// Start initializes the program and runs its event loops, blocking until it
+// gets terminated by either [Program.Quit], [Program.Kill], or its signal
+// handler.
+//
+// Deprecated: please use [Program.Run] instead.
func (p *Program) Start() error {
- _, err := p.StartReturningModel()
+ _, err := p.Run()
return err
}
@@ -553,10 +493,14 @@ func (p *Program) Start() error {
// messages to be injected from outside the program for interoperability
// purposes.
//
-// If the program is not running this this will be a no-op, so it's safe to
-// send messages if the program is unstarted, or has exited.
+// If the program hasn't started yet this will be a blocking operation.
+// If the program has already been terminated this will be a no-op, so it's safe
+// to send messages after the program has exited.
func (p *Program) Send(msg Msg) {
- p.msgs <- msg
+ select {
+ case <-p.ctx.Done():
+ case p.msgs <- msg:
+ }
}
// Quit is a convenience function for quitting Bubble Tea programs. Use it
@@ -572,9 +516,9 @@ func (p *Program) Quit() {
// Kill stops the program immediately and restores the former terminal state.
// The final render that you would normally see when quitting will be skipped.
+// [program.Run] returns a [ErrProgramKilled] error.
func (p *Program) Kill() {
- p.killc <- true
- p.shutdown(true)
+ p.cancel()
}
// shutdown performs operations to free up resources and restore the terminal
@@ -587,102 +531,21 @@ func (p *Program) shutdown(kill bool) {
p.renderer.stop()
}
}
- p.ExitAltScreen()
- p.DisableMouseCellMotion()
- p.DisableMouseAllMotion()
- _ = p.restoreTerminalState()
-}
-
-// EnterAltScreen enters the alternate screen buffer, which consumes the entire
-// terminal window. ExitAltScreen will return the terminal to its former state.
-//
-// Deprecated: Use the WithAltScreen ProgramOption instead.
-func (p *Program) EnterAltScreen() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
-
- if p.altScreenActive {
- return
- }
-
- enterAltScreen(p.output)
-
- p.altScreenActive = true
- if p.renderer != nil {
- p.renderer.setAltScreen(p.altScreenActive)
- }
-}
-
-// ExitAltScreen exits the alternate screen buffer.
-//
-// Deprecated: The altscreen will exited automatically when the program exits.
-func (p *Program) ExitAltScreen() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
-
- if !p.altScreenActive {
- return
- }
- exitAltScreen(p.output)
-
- p.altScreenActive = false
- if p.renderer != nil {
- p.renderer.setAltScreen(p.altScreenActive)
+ _ = p.restoreTerminalState()
+ if p.restoreOutput != nil {
+ _ = p.restoreOutput()
}
}
-// EnableMouseCellMotion enables mouse click, release, wheel and motion events
-// if a mouse button is pressed (i.e., drag events).
-//
-// Deprecated: Use the WithMouseCellMotion ProgramOption instead.
-func (p *Program) EnableMouseCellMotion() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
- fmt.Fprintf(p.output, te.CSI+te.EnableMouseCellMotionSeq)
-}
-
-// DisableMouseCellMotion disables Mouse Cell Motion tracking. This will be
-// called automatically when exiting a Bubble Tea program.
-//
-// Deprecated: The mouse will automatically be disabled when the program exits.
-func (p *Program) DisableMouseCellMotion() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
- fmt.Fprintf(p.output, te.CSI+te.DisableMouseCellMotionSeq)
-}
-
-// EnableMouseAllMotion enables mouse click, release, wheel and motion events,
-// regardless of whether a mouse button is pressed. Many modern terminals
-// support this, but not all.
-//
-// Deprecated: Use the WithMouseAllMotion ProgramOption instead.
-func (p *Program) EnableMouseAllMotion() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
- fmt.Fprintf(p.output, te.CSI+te.EnableMouseAllMotionSeq)
-}
-
-// DisableMouseAllMotion disables All Motion mouse tracking. This will be
-// called automatically when exiting a Bubble Tea program.
-//
-// Deprecated: The mouse will automatically be disabled when the program exits.
-func (p *Program) DisableMouseAllMotion() {
- p.mtx.Lock()
- defer p.mtx.Unlock()
- fmt.Fprintf(p.output, te.CSI+te.DisableMouseAllMotionSeq)
-}
-
// ReleaseTerminal restores the original terminal state and cancels the input
// reader. You can return control to the Program with RestoreTerminal.
func (p *Program) ReleaseTerminal() error {
p.ignoreSignals = true
- p.cancelInput()
- p.altScreenWasActive = p.altScreenActive
- if p.altScreenActive {
- p.ExitAltScreen()
- time.Sleep(time.Millisecond * 10) // give the terminal a moment to catch up
- }
+ p.cancelReader.Cancel()
+ p.waitForReadLoop()
+
+ p.altScreenWasActive = p.renderer.altScreen()
return p.restoreTerminalState()
}
@@ -695,16 +558,22 @@ func (p *Program) RestoreTerminal() error {
if err := p.initTerminal(); err != nil {
return err
}
-
if err := p.initCancelReader(); err != nil {
return err
}
if p.altScreenWasActive {
- p.EnterAltScreen()
+ p.renderer.enterAltScreen()
+ } else {
+ // entering alt screen already causes a repaint.
+ go p.Send(repaintMsg{})
}
- go p.Send(repaintMsg{})
+ // If the output is a terminal, it may have been resized while another
+ // process was at the foreground, in which case we may not have received
+ // SIGWINCH. Detect any size change now and propagate the new size as
+ // needed.
+ go p.checkResize()
return nil
}
@@ -732,3 +601,22 @@ func (p *Program) Printf(template string, args ...interface{}) {
messageBody: fmt.Sprintf(template, args...),
}
}
+
+// Adds a handler to the list of handlers. We wait for all handlers to terminate
+// gracefully on shutdown.
+func (h *handlers) add(ch chan struct{}) {
+ *h = append(*h, ch)
+}
+
+// Shutdown waits for all handlers to terminate.
+func (h handlers) shutdown() {
+ var wg sync.WaitGroup
+ for _, ch := range h {
+ wg.Add(1)
+ go func(ch chan struct{}) {
+ <-ch
+ wg.Done()
+ }(ch)
+ }
+ wg.Wait()
+}
diff --git a/vendor/github.com/charmbracelet/bubbletea/tty.go b/vendor/github.com/charmbracelet/bubbletea/tty.go
index 17e508b9..3ab6639b 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tty.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tty.go
@@ -3,8 +3,12 @@ package tea
import (
"errors"
"io"
+ "os"
+ "time"
+ isatty "github.com/mattn/go-isatty"
"github.com/muesli/cancelreader"
+ "golang.org/x/term"
)
func (p *Program) initTerminal() error {
@@ -20,14 +24,25 @@ func (p *Program) initTerminal() error {
}
}
- hideCursor(p.output)
+ p.renderer.hideCursor()
return nil
}
// restoreTerminalState restores the terminal to the state prior to running the
// Bubble Tea program.
-func (p Program) restoreTerminalState() error {
- showCursor(p.output)
+func (p *Program) restoreTerminalState() error {
+ if p.renderer != nil {
+ p.renderer.showCursor()
+ p.renderer.disableMouseCellMotion()
+ p.renderer.disableMouseAllMotion()
+
+ if p.renderer.altScreen() {
+ p.renderer.exitAltScreen()
+
+ // give the terminal a moment to catch up
+ time.Sleep(time.Millisecond * 10)
+ }
+ }
if p.console != nil {
err := p.console.Reset()
@@ -48,33 +63,69 @@ func (p *Program) initCancelReader() error {
}
p.readLoopDone = make(chan struct{})
- go func() {
- defer close(p.readLoopDone)
+ go p.readLoop()
- for {
- if p.ctx.Err() != nil {
- return
- }
+ return nil
+}
- msgs, err := readInputs(p.cancelReader)
- if err != nil {
- if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
- p.errs <- err
- }
+func (p *Program) readLoop() {
+ defer close(p.readLoopDone)
- return
- }
+ for {
+ if p.ctx.Err() != nil {
+ return
+ }
- for _, msg := range msgs {
- p.msgs <- msg
+ msgs, err := readInputs(p.cancelReader)
+ if err != nil {
+ if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
+ select {
+ case <-p.ctx.Done():
+ case p.errs <- err:
+ }
}
+
+ return
}
- }()
- return nil
+ for _, msg := range msgs {
+ p.msgs <- msg
+ }
+ }
}
-// cancelInput cancels the input reader.
-func (p *Program) cancelInput() {
- p.cancelReader.Cancel()
+// waitForReadLoop waits for the cancelReader to finish its read loop.
+func (p *Program) waitForReadLoop() {
+ select {
+ case <-p.readLoopDone:
+ case <-time.After(500 * time.Millisecond):
+ // The read loop hangs, which means the input
+ // cancelReader's cancel function has returned true even
+ // though it was not able to cancel the read.
+ }
+}
+
+// checkResize detects the current size of the output and informs the program
+// via a WindowSizeMsg.
+func (p *Program) checkResize() {
+ f, ok := p.output.TTY().(*os.File)
+ if !ok || !isatty.IsTerminal(f.Fd()) {
+ // can't query window size
+ return
+ }
+
+ w, h, err := term.GetSize(int(f.Fd()))
+ if err != nil {
+ select {
+ case <-p.ctx.Done():
+ case p.errs <- err:
+ }
+
+ return
+ }
+
+ p.Send(WindowSizeMsg{
+ Width: w,
+ Height: h,
+ })
}
diff --git a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
index 9cfc7d9c..be415aef 100644
--- a/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
+++ b/vendor/github.com/charmbracelet/bubbletea/tty_windows.go
@@ -4,11 +4,9 @@
package tea
import (
- "io"
"os"
"github.com/containerd/console"
- "golang.org/x/sys/windows"
)
func (p *Program) initInput() error {
@@ -26,8 +24,6 @@ func (p *Program) initInput() error {
p.console = c
}
- enableAnsiColors(p.output)
-
return nil
}
@@ -49,18 +45,3 @@ func openInputTTY() (*os.File, error) {
}
return f, nil
}
-
-// enableAnsiColors enables support for ANSI color sequences in Windows
-// default console. Note that this only works with Windows 10.
-func enableAnsiColors(w io.Writer) {
- f, ok := w.(*os.File)
- if !ok {
- return
- }
-
- stdout := windows.Handle(f.Fd())
- var originalMode uint32
-
- _ = windows.GetConsoleMode(stdout, &originalMode)
- _ = windows.SetConsoleMode(stdout, originalMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
-}
diff --git a/vendor/github.com/go-rod/rod/.golangci.yml b/vendor/github.com/go-rod/rod/.golangci.yml
index e54b0f94..8bff6df2 100644
--- a/vendor/github.com/go-rod/rod/.golangci.yml
+++ b/vendor/github.com/go-rod/rod/.golangci.yml
@@ -6,7 +6,6 @@ linters:
- gofmt
- revive
- gocyclo
- - misspell
- bodyclose
gocyclo:
diff --git a/vendor/github.com/go-rod/rod/README.md b/vendor/github.com/go-rod/rod/README.md
index 827e878e..42590c9e 100644
--- a/vendor/github.com/go-rod/rod/README.md
+++ b/vendor/github.com/go-rod/rod/README.md
@@ -3,12 +3,14 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/go-rod/rod.svg)](https://pkg.go.dev/github.com/go-rod/rod)
[![Discord Chat](https://img.shields.io/discord/719933559456006165.svg)][discord room]
-## [Documentation](https://go-rod.github.io/) | [API reference](https://pkg.go.dev/github.com/go-rod/rod?tab=doc) | [中文 API 参考文档](https://github.com/go-rod/go-rod-chinese) | [Management](https://github.com/orgs/go-rod/projects/1) | [FAQ](https://go-rod.github.io/#/faq/README)
+## [Documentation](https://go-rod.github.io/) | [API reference](https://pkg.go.dev/github.com/go-rod/rod?tab=doc) | [FAQ](https://go-rod.github.io/#/faq/README)
Rod is a high-level driver directly based on [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol).
It's designed for web automation and scraping for both high-level and low-level use, senior developers can use the low-level packages and functions to easily
customize or build up their own version of Rod, the high-level functions are just examples to build a default version of Rod.
+[中文 API 文档](https://pkg.go.dev/github.com/go-rod/go-rod-chinese)
+
## Features
- Chained context design, intuitive to timeout or cancel the long-running task
@@ -42,7 +44,7 @@ Your help is more than welcome! Even just open an issue to ask a question may gr
Please read [How To Ask Questions The Smart Way](http://www.catb.org/~esr/faqs/smart-questions.html) before you ask questions.
-We use Github Projects to manage tasks, you can see the priority and progress of the issues [here](https://github.com/orgs/go-rod/projects/1).
+We use Github Projects to manage tasks, you can see the priority and progress of the issues [here](https://github.com/go-rod/rod/projects).
If you want to contribute please read the [Contributor Guide](.github/CONTRIBUTING.md).
diff --git a/vendor/github.com/go-rod/rod/browser.go b/vendor/github.com/go-rod/rod/browser.go
index 715406af..42770980 100644
--- a/vendor/github.com/go-rod/rod/browser.go
+++ b/vendor/github.com/go-rod/rod/browser.go
@@ -71,7 +71,7 @@ func New() *Browser {
trace: defaults.Trace,
monitor: defaults.Monitor,
logger: DefaultLogger,
- defaultDevice: devices.LaptopWithMDPIScreen.Landescape(),
+ defaultDevice: devices.LaptopWithMDPIScreen.Landscape(),
targetsLock: &sync.Mutex{},
states: &sync.Map{},
}).WithPanic(utils.Panic)
diff --git a/vendor/github.com/go-rod/rod/dev_helpers.go b/vendor/github.com/go-rod/rod/dev_helpers.go
index 3532b6e4..e245388c 100644
--- a/vendor/github.com/go-rod/rod/dev_helpers.go
+++ b/vendor/github.com/go-rod/rod/dev_helpers.go
@@ -93,7 +93,7 @@ func (b *Browser) ServeMonitor(host string) string {
}
// check method and sleep if needed
-func (b *Browser) trySlowmotion() {
+func (b *Browser) trySlowMotion() {
if b.slowMotion == 0 {
return
}
@@ -176,7 +176,7 @@ func (p *Page) tryTraceReq(includes, excludes []string) func(map[proto.NetworkRe
}
go func() {
- var waitlist map[string]string
+ var waitList map[string]string
t := time.NewTicker(time.Second)
for {
select {
@@ -184,9 +184,9 @@ func (p *Page) tryTraceReq(includes, excludes []string) func(map[proto.NetworkRe
t.Stop()
cleanup()
return
- case waitlist = <-ch:
+ case waitList = <-ch:
case <-t.C:
- p.browser.logger.Println(TraceTypeWaitRequests, p, waitlist)
+ p.browser.logger.Println(TraceTypeWaitRequests, p, waitList)
}
}
}()
diff --git a/vendor/github.com/go-rod/rod/element.go b/vendor/github.com/go-rod/rod/element.go
index 83e5dee0..f6d6e684 100644
--- a/vendor/github.com/go-rod/rod/element.go
+++ b/vendor/github.com/go-rod/rod/element.go
@@ -66,7 +66,7 @@ func (el *Element) Focus() error {
// window if it's not already within the visible area.
func (el *Element) ScrollIntoView() error {
defer el.tryTrace(TraceTypeInput, "scroll into view")()
- el.page.browser.trySlowmotion()
+ el.page.browser.trySlowMotion()
err := el.WaitStableRAF()
if err != nil {
@@ -190,9 +190,9 @@ func (el *Element) Interactable() (pt *proto.Point, err error) {
return
}
-// Shape of the DOM element content. The shape is a group of 4-sides polygons (4-gons).
-// A 4-gon is not necessary a rectangle. 4-gons can be apart from each other.
-// For example, we use 2 4-gons to describe the shape below:
+// Shape of the DOM element content. The shape is a group of 4-sides polygons.
+// A 4-sides polygon is not necessary a rectangle. 4-sides polygons can be apart from each other.
+// For example, we use 2 4-sides polygons to describe the shape below:
//
// ____________ ____________
// / ___/ = /___________/ + _________
@@ -231,7 +231,7 @@ func (el *Element) SelectText(regex string) error {
}
defer el.tryTrace(TraceTypeInput, "select text: "+regex)()
- el.page.browser.trySlowmotion()
+ el.page.browser.trySlowMotion()
_, err = el.Evaluate(evalHelper(js.SelectText, regex).ByUser())
return err
@@ -246,7 +246,7 @@ func (el *Element) SelectAllText() error {
}
defer el.tryTrace(TraceTypeInput, "select all text")()
- el.page.browser.trySlowmotion()
+ el.page.browser.trySlowMotion()
_, err = el.Evaluate(evalHelper(js.SelectAllText).ByUser())
return err
@@ -317,7 +317,7 @@ func (el *Element) Select(selectors []string, selected bool, t SelectorType) err
}
defer el.tryTrace(TraceTypeInput, fmt.Sprintf(`select "%s"`, strings.Join(selectors, "; ")))()
- el.page.browser.trySlowmotion()
+ el.page.browser.trySlowMotion()
res, err := el.Evaluate(evalHelper(js.Select, selectors, selected, t).ByUser())
if err != nil {
@@ -370,7 +370,7 @@ func (el *Element) SetFiles(paths []string) error {
absPaths := utils.AbsolutePaths(paths)
defer el.tryTrace(TraceTypeInput, fmt.Sprintf("set files: %v", absPaths))()
- el.page.browser.trySlowmotion()
+ el.page.browser.trySlowMotion()
err := proto.DOMSetFileInputFiles{
Files: absPaths,
diff --git a/vendor/github.com/go-rod/rod/go.work.sum b/vendor/github.com/go-rod/rod/go.work.sum
new file mode 100644
index 00000000..3497548a
--- /dev/null
+++ b/vendor/github.com/go-rod/rod/go.work.sum
@@ -0,0 +1,2 @@
+github.com/ysmood/got v0.32.0 h1:aAHdQgfgMb/lo4v+OekM+SSqEJYFI035h5YYvLXsVyU=
+github.com/ysmood/got v0.32.0/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
diff --git a/vendor/github.com/go-rod/rod/input.go b/vendor/github.com/go-rod/rod/input.go
index 945ca594..0104f9eb 100644
--- a/vendor/github.com/go-rod/rod/input.go
+++ b/vendor/github.com/go-rod/rod/input.go
@@ -44,7 +44,7 @@ func (k *Keyboard) modifiers() int {
// use method like Page.InsertText .
func (k *Keyboard) Press(key input.Key) error {
defer k.page.tryTrace(TraceTypeInput, "press key: "+key.Info().Code)()
- k.page.browser.trySlowmotion()
+ k.page.browser.trySlowMotion()
k.Lock()
defer k.Unlock()
@@ -184,7 +184,7 @@ func (ka *KeyActions) balance() []KeyAction {
// InsertText is like pasting text into the page
func (p *Page) InsertText(text string) error {
defer p.tryTrace(TraceTypeInput, "insert text "+text)()
- p.browser.trySlowmotion()
+ p.browser.trySlowMotion()
err := proto.InputInsertText{Text: text}.Call(p)
return err
@@ -223,7 +223,7 @@ func (m *Mouse) MoveTo(p proto.Point) error {
button, buttons := input.EncodeMouseButton(m.buttons)
- m.page.browser.trySlowmotion()
+ m.page.browser.trySlowMotion()
err := proto.InputDispatchMouseEvent{
Type: proto.InputDispatchMouseEventTypeMouseMoved,
@@ -291,7 +291,7 @@ func (m *Mouse) Scroll(offsetX, offsetY float64, steps int) error {
defer m.Unlock()
defer m.page.tryTrace(TraceTypeInput, fmt.Sprintf("scroll (%.2f, %.2f)", offsetX, offsetY))()
- m.page.browser.trySlowmotion()
+ m.page.browser.trySlowMotion()
if steps < 1 {
steps = 1
@@ -379,7 +379,7 @@ func (m *Mouse) Up(button proto.InputMouseButton, clickCount int) error {
// Click the button. It's the combination of Mouse.Down and Mouse.Up
func (m *Mouse) Click(button proto.InputMouseButton, clickCount int) error {
- m.page.browser.trySlowmotion()
+ m.page.browser.trySlowMotion()
err := m.Down(button, clickCount)
if err != nil {
@@ -444,7 +444,7 @@ func (t *Touch) Cancel() error {
// Tap dispatches a touchstart and touchend event.
func (t *Touch) Tap(x, y float64) error {
defer t.page.tryTrace(TraceTypeInput, "touch")()
- t.page.browser.trySlowmotion()
+ t.page.browser.trySlowMotion()
p := &proto.InputTouchPoint{X: x, Y: y}
diff --git a/vendor/github.com/go-rod/rod/lib/defaults/defaults.go b/vendor/github.com/go-rod/rod/lib/defaults/defaults.go
index a3583ff9..35bb1e44 100644
--- a/vendor/github.com/go-rod/rod/lib/defaults/defaults.go
+++ b/vendor/github.com/go-rod/rod/lib/defaults/defaults.go
@@ -18,7 +18,7 @@ import (
// Option name is "trace".
var Trace bool
-// Slow is the default of rod.Browser.Slowmotion .
+// Slow is the default of rod.Browser.SlowMotion .
// The format is same as https://golang.org/pkg/time/#ParseDuration
// Option name is "slow".
var Slow time.Duration
diff --git a/vendor/github.com/go-rod/rod/lib/devices/device.go b/vendor/github.com/go-rod/rod/lib/devices/device.go
index 8ce04a3d..058bff87 100644
--- a/vendor/github.com/go-rod/rod/lib/devices/device.go
+++ b/vendor/github.com/go-rod/rod/lib/devices/device.go
@@ -31,8 +31,8 @@ type ScreenSize struct {
Height int
}
-// Landescape clones the device and set it to landscape mode
-func (device Device) Landescape() Device {
+// Landscape clones the device and set it to landscape mode
+func (device Device) Landscape() Device {
d := device
d.landscape = true
return d
diff --git a/vendor/github.com/go-rod/rod/lib/js/helper.js b/vendor/github.com/go-rod/rod/lib/js/helper.js
index 680d9825..8b201a2b 100644
--- a/vendor/github.com/go-rod/rod/lib/js/helper.js
+++ b/vendor/github.com/go-rod/rod/lib/js/helper.js
@@ -41,6 +41,7 @@ const functions = {
elementR(selector, regex) {
var reg
var m = regex.match(/(\/?)(.+)\1([a-z]*)/i)
+ // cSpell:ignore gmix
if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3]))
reg = new RegExp(regex)
else reg = new RegExp(m[2], m[3])
diff --git a/vendor/github.com/go-rod/rod/lib/launcher/launcher.go b/vendor/github.com/go-rod/rod/lib/launcher/launcher.go
index 204e8c07..af2a33ca 100644
--- a/vendor/github.com/go-rod/rod/lib/launcher/launcher.go
+++ b/vendor/github.com/go-rod/rod/lib/launcher/launcher.go
@@ -3,6 +3,7 @@ package launcher
import (
"context"
+ "crypto"
"errors"
"fmt"
"io"
@@ -253,6 +254,23 @@ func (l *Launcher) Devtools(autoOpenForTabs bool) *Launcher {
return l.Delete("auto-open-devtools-for-tabs")
}
+// IgnoreCerts configure the Chrome's ignore-certificate-errors-spki-list argument with the public keys.
+func (l *Launcher) IgnoreCerts(pks []crypto.PublicKey) error {
+ spkis := make([]string, 0, len(pks))
+
+ for _, pk := range pks {
+ spki, err := certSPKI(pk)
+ if err != nil {
+ return fmt.Errorf("certSPKI: %w", err)
+ }
+ spkis = append(spkis, string(spki))
+ }
+
+ l.Set("ignore-certificate-errors-spki-list", spkis...)
+
+ return nil
+}
+
// UserDataDir is where the browser will look for all of its state, such as cookie and cache.
// When set to empty, browser will use current OS home dir.
// Related doc: https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md
@@ -284,7 +302,7 @@ func (l *Launcher) RemoteDebuggingPort(port int) *Launcher {
return l.Set(flags.RemoteDebuggingPort, fmt.Sprintf("%d", port))
}
-// Proxy switch. When disabled leakless will be disabled.
+// Proxy for the browser
func (l *Launcher) Proxy(host string) *Launcher {
return l.Set(flags.ProxyServer, host)
}
@@ -307,7 +325,7 @@ func (l *Launcher) StartURL(u string) *Launcher {
return l.Set("", u)
}
-// FormatArgs returns the formated arg list for cli
+// FormatArgs returns the formatted arg list for cli
func (l *Launcher) FormatArgs() []string {
execArgs := []string{}
for k, v := range l.Flags {
diff --git a/vendor/github.com/go-rod/rod/lib/launcher/manager.go b/vendor/github.com/go-rod/rod/lib/launcher/manager.go
index 1ab4cd37..237f35b6 100644
--- a/vendor/github.com/go-rod/rod/lib/launcher/manager.go
+++ b/vendor/github.com/go-rod/rod/lib/launcher/manager.go
@@ -90,7 +90,7 @@ func (l *Launcher) mustManaged() {
var _ http.Handler = &Manager{}
// Manager is used to launch browsers via http server on another machine.
-// The reason why we have Manager is after we launcher a browser, we can't dynamicall change its
+// The reason why we have Manager is after we launcher a browser, we can't dynamically change its
// CLI arguments, such as "--headless". The Manager allows us to decide what CLI arguments to
// pass to the browser when launch it remotely.
// The work flow looks like:
@@ -133,7 +133,7 @@ func NewManager() *Manager {
for f, allowed := range allowedPath {
p := l.Get(f)
if p != "" && !strings.HasPrefix(p, allowed) {
- b := []byte(fmt.Sprintf("not allowed %s path: %s", f, p))
+ b := []byte(fmt.Sprintf("[rod-manager] not allowed %s path: %s (use --allow-all to disable the protection)", f, p))
w.Header().Add("Content-Length", fmt.Sprintf("%d", len(b)))
w.WriteHeader(http.StatusBadRequest)
utils.E(w.Write(b))
diff --git a/vendor/github.com/go-rod/rod/lib/launcher/revision.go b/vendor/github.com/go-rod/rod/lib/launcher/revision.go
index 51153b05..76beb074 100644
--- a/vendor/github.com/go-rod/rod/lib/launcher/revision.go
+++ b/vendor/github.com/go-rod/rod/lib/launcher/revision.go
@@ -3,7 +3,7 @@
package launcher
// RevisionDefault for chromium
-const RevisionDefault = 1033860
+const RevisionDefault = 1065323
// RevisionPlaywright for arm linux
-const RevisionPlaywright = 1019
+const RevisionPlaywright = 1028
diff --git a/vendor/github.com/go-rod/rod/lib/launcher/utils.go b/vendor/github.com/go-rod/rod/lib/launcher/utils.go
index 70e802cc..a2d80cb5 100644
--- a/vendor/github.com/go-rod/rod/lib/launcher/utils.go
+++ b/vendor/github.com/go-rod/rod/lib/launcher/utils.go
@@ -2,6 +2,10 @@ package launcher
import (
"archive/zip"
+ "crypto"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/base64"
"fmt"
"io"
"net/url"
@@ -110,3 +114,18 @@ func unzip(logger utils.Logger, from, to string) (err error) {
return zr.Close()
}
+
+// certSPKI generates the SPKI of a certificate public key
+// https://blog.afoolishmanifesto.com/posts/golang-self-signed-and-pinned-certs/
+func certSPKI(pk crypto.PublicKey) ([]byte, error) {
+ pubDER, err := x509.MarshalPKIXPublicKey(pk)
+ if err != nil {
+ return nil, fmt.Errorf("x509.MarshalPKIXPublicKey: %w", err)
+ }
+
+ sum := sha256.Sum256(pubDER)
+ pin := make([]byte, base64.StdEncoding.EncodedLen(len(sum)))
+ base64.StdEncoding.Encode(pin, sum[:])
+
+ return pin, nil
+}
diff --git a/vendor/github.com/go-rod/rod/lib/proto/accessibility.go b/vendor/github.com/go-rod/rod/lib/proto/accessibility.go
index 8ae4177e..5a9eaba2 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/accessibility.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/accessibility.go
@@ -435,7 +435,7 @@ type AccessibilityGetFullAXTree struct {
Depth *int `json:"depth,omitempty"`
// FrameID (optional) The frame for whose document the AX tree should be retrieved.
- // If omitted, the root frame is used.
+ // If omited, the root frame is used.
FrameID PageFrameID `json:"frameId,omitempty"`
}
diff --git a/vendor/github.com/go-rod/rod/lib/proto/audits.go b/vendor/github.com/go-rod/rod/lib/proto/audits.go
index c24004f1..d583d053 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/audits.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/audits.go
@@ -531,6 +531,9 @@ const (
// AuditsAttributionReportingIssueTypePermissionPolicyDisabled enum const
AuditsAttributionReportingIssueTypePermissionPolicyDisabled AuditsAttributionReportingIssueType = "PermissionPolicyDisabled"
+ // AuditsAttributionReportingIssueTypePermissionPolicyNotDelegated enum const
+ AuditsAttributionReportingIssueTypePermissionPolicyNotDelegated AuditsAttributionReportingIssueType = "PermissionPolicyNotDelegated"
+
// AuditsAttributionReportingIssueTypeUntrustworthyReportingOrigin enum const
AuditsAttributionReportingIssueTypeUntrustworthyReportingOrigin AuditsAttributionReportingIssueType = "UntrustworthyReportingOrigin"
@@ -689,9 +692,6 @@ const (
// AuditsDeprecationIssueTypeInsecurePrivateNetworkSubresourceRequest enum const
AuditsDeprecationIssueTypeInsecurePrivateNetworkSubresourceRequest AuditsDeprecationIssueType = "InsecurePrivateNetworkSubresourceRequest"
- // AuditsDeprecationIssueTypeLegacyConstraintGoogIPv6 enum const
- AuditsDeprecationIssueTypeLegacyConstraintGoogIPv6 AuditsDeprecationIssueType = "LegacyConstraintGoogIPv6"
-
// AuditsDeprecationIssueTypeLocalCSSFileExtensionRejected enum const
AuditsDeprecationIssueTypeLocalCSSFileExtensionRejected AuditsDeprecationIssueType = "LocalCSSFileExtensionRejected"
@@ -701,12 +701,6 @@ const (
// AuditsDeprecationIssueTypeMediaSourceDurationTruncatingBuffered enum const
AuditsDeprecationIssueTypeMediaSourceDurationTruncatingBuffered AuditsDeprecationIssueType = "MediaSourceDurationTruncatingBuffered"
- // AuditsDeprecationIssueTypeNavigateEventRestoreScroll enum const
- AuditsDeprecationIssueTypeNavigateEventRestoreScroll AuditsDeprecationIssueType = "NavigateEventRestoreScroll"
-
- // AuditsDeprecationIssueTypeNavigateEventTransitionWhile enum const
- AuditsDeprecationIssueTypeNavigateEventTransitionWhile AuditsDeprecationIssueType = "NavigateEventTransitionWhile"
-
// AuditsDeprecationIssueTypeNoSysexWebMIDIWithoutPermission enum const
AuditsDeprecationIssueTypeNoSysexWebMIDIWithoutPermission AuditsDeprecationIssueType = "NoSysexWebMIDIWithoutPermission"
@@ -725,6 +719,12 @@ const (
// AuditsDeprecationIssueTypeOverflowVisibleOnReplacedElement enum const
AuditsDeprecationIssueTypeOverflowVisibleOnReplacedElement AuditsDeprecationIssueType = "OverflowVisibleOnReplacedElement"
+ // AuditsDeprecationIssueTypePaymentInstruments enum const
+ AuditsDeprecationIssueTypePaymentInstruments AuditsDeprecationIssueType = "PaymentInstruments"
+
+ // AuditsDeprecationIssueTypePaymentRequestCSPViolation enum const
+ AuditsDeprecationIssueTypePaymentRequestCSPViolation AuditsDeprecationIssueType = "PaymentRequestCSPViolation"
+
// AuditsDeprecationIssueTypePersistentQuotaType enum const
AuditsDeprecationIssueTypePersistentQuotaType AuditsDeprecationIssueType = "PersistentQuotaType"
@@ -837,8 +837,8 @@ type AuditsFederatedAuthRequestIssueDetails struct {
type AuditsFederatedAuthRequestIssueReason string
const (
- // AuditsFederatedAuthRequestIssueReasonApprovalDeclined enum const
- AuditsFederatedAuthRequestIssueReasonApprovalDeclined AuditsFederatedAuthRequestIssueReason = "ApprovalDeclined"
+ // AuditsFederatedAuthRequestIssueReasonShouldEmbargo enum const
+ AuditsFederatedAuthRequestIssueReasonShouldEmbargo AuditsFederatedAuthRequestIssueReason = "ShouldEmbargo"
// AuditsFederatedAuthRequestIssueReasonTooManyRequests enum const
AuditsFederatedAuthRequestIssueReasonTooManyRequests AuditsFederatedAuthRequestIssueReason = "TooManyRequests"
@@ -911,6 +911,9 @@ const (
// AuditsFederatedAuthRequestIssueReasonCanceled enum const
AuditsFederatedAuthRequestIssueReasonCanceled AuditsFederatedAuthRequestIssueReason = "Canceled"
+
+ // AuditsFederatedAuthRequestIssueReasonRpPageNotVisible enum const
+ AuditsFederatedAuthRequestIssueReasonRpPageNotVisible AuditsFederatedAuthRequestIssueReason = "RpPageNotVisible"
)
// AuditsClientHintIssueDetails This issue tracks client hints related issues. It's used to deprecate old
diff --git a/vendor/github.com/go-rod/rod/lib/proto/css.go b/vendor/github.com/go-rod/rod/lib/proto/css.go
index 8c228dda..6c505c14 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/css.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/css.go
@@ -298,6 +298,10 @@ type CSSCSSProperty struct {
// Range (optional) The entire property range in the enclosing style declaration (if available).
Range *CSSSourceRange `json:"range,omitempty"`
+
+ // LonghandProperties (experimental) (optional) Parsed longhand components of this property if it is a shorthand.
+ // This field will be empty if the given property is not a shorthand.
+ LonghandProperties []*CSSCSSProperty `json:"longhandProperties,omitempty"`
}
// CSSCSSMediaSource enum
diff --git a/vendor/github.com/go-rod/rod/lib/proto/debugger.go b/vendor/github.com/go-rod/rod/lib/proto/debugger.go
index 24282597..c1c982c3 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/debugger.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/debugger.go
@@ -574,7 +574,7 @@ const (
// DebuggerRestartFrame Restarts particular call frame from the beginning. The old, deprecated
// behavior of `restartFrame` is to stay paused and allow further CDP commands
// after a restart was scheduled. This can cause problems with restarting, so
-// we now continue execution immediately after it has been scheduled until we
+// we now continue execution immediatly after it has been scheduled until we
// reach the beginning of the restarted frame.
//
// To stay back-wards compatible, `restartFrame` now expects a `mode`
diff --git a/vendor/github.com/go-rod/rod/lib/proto/definitions.go b/vendor/github.com/go-rod/rod/lib/proto/definitions.go
index cefccb46..46d4bba2 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/definitions.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/definitions.go
@@ -723,6 +723,8 @@ var types = map[string]reflect.Type{
"Page.getManifestIconsResult": reflect.TypeOf(PageGetManifestIconsResult{}),
"Page.getAppId": reflect.TypeOf(PageGetAppID{}),
"Page.getAppIdResult": reflect.TypeOf(PageGetAppIDResult{}),
+ "Page.getAdScriptId": reflect.TypeOf(PageGetAdScriptID{}),
+ "Page.getAdScriptIdResult": reflect.TypeOf(PageGetAdScriptIDResult{}),
"Page.getCookies": reflect.TypeOf(PageGetCookies{}),
"Page.getCookiesResult": reflect.TypeOf(PageGetCookiesResult{}),
"Page.getFrameTree": reflect.TypeOf(PageGetFrameTree{}),
@@ -852,6 +854,11 @@ var types = map[string]reflect.Type{
"Storage.TrustTokens": reflect.TypeOf(StorageTrustTokens{}),
"Storage.InterestGroupAd": reflect.TypeOf(StorageInterestGroupAd{}),
"Storage.InterestGroupDetails": reflect.TypeOf(StorageInterestGroupDetails{}),
+ "Storage.SharedStorageEntry": reflect.TypeOf(StorageSharedStorageEntry{}),
+ "Storage.SharedStorageMetadata": reflect.TypeOf(StorageSharedStorageMetadata{}),
+ "Storage.SharedStorageReportingMetadata": reflect.TypeOf(StorageSharedStorageReportingMetadata{}),
+ "Storage.SharedStorageUrlWithMetadata": reflect.TypeOf(StorageSharedStorageURLWithMetadata{}),
+ "Storage.SharedStorageAccessParams": reflect.TypeOf(StorageSharedStorageAccessParams{}),
"Storage.getStorageKeyForFrame": reflect.TypeOf(StorageGetStorageKeyForFrame{}),
"Storage.getStorageKeyForFrameResult": reflect.TypeOf(StorageGetStorageKeyForFrameResult{}),
"Storage.clearDataForOrigin": reflect.TypeOf(StorageClearDataForOrigin{}),
@@ -876,11 +883,17 @@ var types = map[string]reflect.Type{
"Storage.getInterestGroupDetails": reflect.TypeOf(StorageGetInterestGroupDetails{}),
"Storage.getInterestGroupDetailsResult": reflect.TypeOf(StorageGetInterestGroupDetailsResult{}),
"Storage.setInterestGroupTracking": reflect.TypeOf(StorageSetInterestGroupTracking{}),
+ "Storage.getSharedStorageMetadata": reflect.TypeOf(StorageGetSharedStorageMetadata{}),
+ "Storage.getSharedStorageMetadataResult": reflect.TypeOf(StorageGetSharedStorageMetadataResult{}),
+ "Storage.getSharedStorageEntries": reflect.TypeOf(StorageGetSharedStorageEntries{}),
+ "Storage.getSharedStorageEntriesResult": reflect.TypeOf(StorageGetSharedStorageEntriesResult{}),
+ "Storage.setSharedStorageTracking": reflect.TypeOf(StorageSetSharedStorageTracking{}),
"Storage.cacheStorageContentUpdated": reflect.TypeOf(StorageCacheStorageContentUpdated{}),
"Storage.cacheStorageListUpdated": reflect.TypeOf(StorageCacheStorageListUpdated{}),
"Storage.indexedDBContentUpdated": reflect.TypeOf(StorageIndexedDBContentUpdated{}),
"Storage.indexedDBListUpdated": reflect.TypeOf(StorageIndexedDBListUpdated{}),
"Storage.interestGroupAccessed": reflect.TypeOf(StorageInterestGroupAccessed{}),
+ "Storage.sharedStorageAccessed": reflect.TypeOf(StorageSharedStorageAccessed{}),
"SystemInfo.GPUDevice": reflect.TypeOf(SystemInfoGPUDevice{}),
"SystemInfo.Size": reflect.TypeOf(SystemInfoSize{}),
"SystemInfo.VideoDecodeAcceleratorCapability": reflect.TypeOf(SystemInfoVideoDecodeAcceleratorCapability{}),
@@ -1104,9 +1117,6 @@ var types = map[string]reflect.Type{
"Profiler.CoverageRange": reflect.TypeOf(ProfilerCoverageRange{}),
"Profiler.FunctionCoverage": reflect.TypeOf(ProfilerFunctionCoverage{}),
"Profiler.ScriptCoverage": reflect.TypeOf(ProfilerScriptCoverage{}),
- "Profiler.TypeObject": reflect.TypeOf(ProfilerTypeObject{}),
- "Profiler.TypeProfileEntry": reflect.TypeOf(ProfilerTypeProfileEntry{}),
- "Profiler.ScriptTypeProfile": reflect.TypeOf(ProfilerScriptTypeProfile{}),
"Profiler.disable": reflect.TypeOf(ProfilerDisable{}),
"Profiler.enable": reflect.TypeOf(ProfilerEnable{}),
"Profiler.getBestEffortCoverage": reflect.TypeOf(ProfilerGetBestEffortCoverage{}),
@@ -1115,15 +1125,11 @@ var types = map[string]reflect.Type{
"Profiler.start": reflect.TypeOf(ProfilerStart{}),
"Profiler.startPreciseCoverage": reflect.TypeOf(ProfilerStartPreciseCoverage{}),
"Profiler.startPreciseCoverageResult": reflect.TypeOf(ProfilerStartPreciseCoverageResult{}),
- "Profiler.startTypeProfile": reflect.TypeOf(ProfilerStartTypeProfile{}),
"Profiler.stop": reflect.TypeOf(ProfilerStop{}),
"Profiler.stopResult": reflect.TypeOf(ProfilerStopResult{}),
"Profiler.stopPreciseCoverage": reflect.TypeOf(ProfilerStopPreciseCoverage{}),
- "Profiler.stopTypeProfile": reflect.TypeOf(ProfilerStopTypeProfile{}),
"Profiler.takePreciseCoverage": reflect.TypeOf(ProfilerTakePreciseCoverage{}),
"Profiler.takePreciseCoverageResult": reflect.TypeOf(ProfilerTakePreciseCoverageResult{}),
- "Profiler.takeTypeProfile": reflect.TypeOf(ProfilerTakeTypeProfile{}),
- "Profiler.takeTypeProfileResult": reflect.TypeOf(ProfilerTakeTypeProfileResult{}),
"Profiler.consoleProfileFinished": reflect.TypeOf(ProfilerConsoleProfileFinished{}),
"Profiler.consoleProfileStarted": reflect.TypeOf(ProfilerConsoleProfileStarted{}),
"Profiler.preciseCoverageDeltaUpdate": reflect.TypeOf(ProfilerPreciseCoverageDeltaUpdate{}),
diff --git a/vendor/github.com/go-rod/rod/lib/proto/dom.go b/vendor/github.com/go-rod/rod/lib/proto/dom.go
index 2072a5c4..e87b10ce 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/dom.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/dom.go
@@ -1546,7 +1546,7 @@ type DOMChildNodeInserted struct {
// ParentNodeID Id of the node that has changed.
ParentNodeID DOMNodeID `json:"parentNodeId"`
- // PreviousNodeID If of the previous siblint.
+ // PreviousNodeID Id of the previous sibling.
PreviousNodeID DOMNodeID `json:"previousNodeId"`
// Node Inserted node data.
diff --git a/vendor/github.com/go-rod/rod/lib/proto/fetch.go b/vendor/github.com/go-rod/rod/lib/proto/fetch.go
index b59e0360..b81a6b47 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/fetch.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/fetch.go
@@ -211,7 +211,9 @@ type FetchContinueRequest struct {
// PostData (optional) If set, overrides the post data in the request.
PostData []byte `json:"postData,omitempty"`
- // Headers (optional) If set, overrides the request headers.
+ // Headers (optional) If set, overrides the request headers. Note that the overrides do not
+ // extend to subsequent redirect hops, if a redirect happens. Another override
+ // may be applied to a different request produced by a redirect.
Headers []*FetchHeaderEntry `json:"headers,omitempty"`
// InterceptResponse (experimental) (optional) If set, overrides response interception behavior for this request.
@@ -374,7 +376,11 @@ type FetchRequestPaused struct {
// NetworkID (optional) If the intercepted request had a corresponding Network.requestWillBeSent event fired for it,
// then this networkId will be the same as the requestId present in the requestWillBeSent event.
- NetworkID FetchRequestID `json:"networkId,omitempty"`
+ NetworkID NetworkRequestID `json:"networkId,omitempty"`
+
+ // RedirectedRequestID (experimental) (optional) If the request is due to a redirect response from the server, the id of the request that
+ // has caused the redirect.
+ RedirectedRequestID FetchRequestID `json:"redirectedRequestId,omitempty"`
}
// ProtoEvent name
diff --git a/vendor/github.com/go-rod/rod/lib/proto/headless_experimental.go b/vendor/github.com/go-rod/rod/lib/proto/headless_experimental.go
index e2de1ff9..ec5c3bfc 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/headless_experimental.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/headless_experimental.go
@@ -19,6 +19,9 @@ const (
// HeadlessExperimentalScreenshotParamsFormatPng enum const
HeadlessExperimentalScreenshotParamsFormatPng HeadlessExperimentalScreenshotParamsFormat = "png"
+
+ // HeadlessExperimentalScreenshotParamsFormatWebp enum const
+ HeadlessExperimentalScreenshotParamsFormatWebp HeadlessExperimentalScreenshotParamsFormat = "webp"
)
// HeadlessExperimentalScreenshotParams Encoding options for a screenshot.
@@ -29,6 +32,9 @@ type HeadlessExperimentalScreenshotParams struct {
// Quality (optional) Compression quality from range [0..100] (jpeg only).
Quality *int `json:"quality,omitempty"`
+
+ // OptimizeForSpeed (optional) Optimize image encoding for speed, not for resulting size (defaults to false)
+ OptimizeForSpeed bool `json:"optimizeForSpeed,omitempty"`
}
// HeadlessExperimentalBeginFrame Sends a BeginFrame to the target and returns when the frame was completed. Optionally captures a
diff --git a/vendor/github.com/go-rod/rod/lib/proto/heap_profiler.go b/vendor/github.com/go-rod/rod/lib/proto/heap_profiler.go
index 313e2f30..1ced51da 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/heap_profiler.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/heap_profiler.go
@@ -182,6 +182,24 @@ type HeapProfilerStartSampling struct {
// SamplingInterval (optional) Average sample interval in bytes. Poisson distribution is used for the intervals. The
// default value is 32768 bytes.
SamplingInterval *float64 `json:"samplingInterval,omitempty"`
+
+ // IncludeObjectsCollectedByMajorGC (optional) By default, the sampling heap profiler reports only objects which are
+ // still alive when the profile is returned via getSamplingProfile or
+ // stopSampling, which is useful for determining what functions contribute
+ // the most to steady-state memory usage. This flag instructs the sampling
+ // heap profiler to also include information about objects discarded by
+ // major GC, which will show which functions cause large temporary memory
+ // usage or long GC pauses.
+ IncludeObjectsCollectedByMajorGC bool `json:"includeObjectsCollectedByMajorGC,omitempty"`
+
+ // IncludeObjectsCollectedByMinorGC (optional) By default, the sampling heap profiler reports only objects which are
+ // still alive when the profile is returned via getSamplingProfile or
+ // stopSampling, which is useful for determining what functions contribute
+ // the most to steady-state memory usage. This flag instructs the sampling
+ // heap profiler to also include information about objects discarded by
+ // minor GC, which is useful when tuning a latency-sensitive application
+ // for minimal GC activity.
+ IncludeObjectsCollectedByMinorGC bool `json:"includeObjectsCollectedByMinorGC,omitempty"`
}
// ProtoReq name
diff --git a/vendor/github.com/go-rod/rod/lib/proto/network.go b/vendor/github.com/go-rod/rod/lib/proto/network.go
index 7d7d5ebd..d34a4f0b 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/network.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/network.go
@@ -670,6 +670,35 @@ const (
NetworkTrustTokenOperationTypeSigning NetworkTrustTokenOperationType = "Signing"
)
+// NetworkAlternateProtocolUsage (experimental) The reason why Chrome uses a specific transport protocol for HTTP semantics.
+type NetworkAlternateProtocolUsage string
+
+const (
+ // NetworkAlternateProtocolUsageAlternativeJobWonWithoutRace enum const
+ NetworkAlternateProtocolUsageAlternativeJobWonWithoutRace NetworkAlternateProtocolUsage = "alternativeJobWonWithoutRace"
+
+ // NetworkAlternateProtocolUsageAlternativeJobWonRace enum const
+ NetworkAlternateProtocolUsageAlternativeJobWonRace NetworkAlternateProtocolUsage = "alternativeJobWonRace"
+
+ // NetworkAlternateProtocolUsageMainJobWonRace enum const
+ NetworkAlternateProtocolUsageMainJobWonRace NetworkAlternateProtocolUsage = "mainJobWonRace"
+
+ // NetworkAlternateProtocolUsageMappingMissing enum const
+ NetworkAlternateProtocolUsageMappingMissing NetworkAlternateProtocolUsage = "mappingMissing"
+
+ // NetworkAlternateProtocolUsageBroken enum const
+ NetworkAlternateProtocolUsageBroken NetworkAlternateProtocolUsage = "broken"
+
+ // NetworkAlternateProtocolUsageDNSAlpnH3JobWonWithoutRace enum const
+ NetworkAlternateProtocolUsageDNSAlpnH3JobWonWithoutRace NetworkAlternateProtocolUsage = "dnsAlpnH3JobWonWithoutRace"
+
+ // NetworkAlternateProtocolUsageDNSAlpnH3JobWonRace enum const
+ NetworkAlternateProtocolUsageDNSAlpnH3JobWonRace NetworkAlternateProtocolUsage = "dnsAlpnH3JobWonRace"
+
+ // NetworkAlternateProtocolUsageUnspecifiedReason enum const
+ NetworkAlternateProtocolUsageUnspecifiedReason NetworkAlternateProtocolUsage = "unspecifiedReason"
+)
+
// NetworkResponse HTTP response data.
type NetworkResponse struct {
@@ -736,6 +765,9 @@ type NetworkResponse struct {
// Protocol (optional) Protocol used to fetch this request.
Protocol string `json:"protocol,omitempty"`
+ // AlternateProtocolUsage (experimental) (optional) The reason why Chrome uses a specific transport protocol for HTTP semantics.
+ AlternateProtocolUsage NetworkAlternateProtocolUsage `json:"alternateProtocolUsage,omitempty"`
+
// SecurityState Security state of the request resource.
SecurityState SecuritySecurityState `json:"securityState"`
diff --git a/vendor/github.com/go-rod/rod/lib/proto/page.go b/vendor/github.com/go-rod/rod/lib/proto/page.go
index dfe5787c..59107ee0 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/page.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/page.go
@@ -147,11 +147,14 @@ const (
PagePermissionsPolicyFeatureChDownlink PagePermissionsPolicyFeature = "ch-downlink"
// PagePermissionsPolicyFeatureChEct enum const
- PagePermissionsPolicyFeatureChEct PagePermissionsPolicyFeature = "ch-etc"
+ PagePermissionsPolicyFeatureChEct PagePermissionsPolicyFeature = "ch-ect"
// PagePermissionsPolicyFeatureChPrefersColorScheme enum const
PagePermissionsPolicyFeatureChPrefersColorScheme PagePermissionsPolicyFeature = "ch-prefers-color-scheme"
+ // PagePermissionsPolicyFeatureChPrefersReducedMotion enum const
+ PagePermissionsPolicyFeatureChPrefersReducedMotion PagePermissionsPolicyFeature = "ch-prefers-reduced-motion"
+
// PagePermissionsPolicyFeatureChRtt enum const
PagePermissionsPolicyFeatureChRtt PagePermissionsPolicyFeature = "ch-rtt"
@@ -209,6 +212,9 @@ const (
// PagePermissionsPolicyFeatureClipboardWrite enum const
PagePermissionsPolicyFeatureClipboardWrite PagePermissionsPolicyFeature = "clipboard-write"
+ // PagePermissionsPolicyFeatureComputePressure enum const
+ PagePermissionsPolicyFeatureComputePressure PagePermissionsPolicyFeature = "compute-pressure"
+
// PagePermissionsPolicyFeatureCrossOriginIsolated enum const
PagePermissionsPolicyFeatureCrossOriginIsolated PagePermissionsPolicyFeature = "cross-origin-isolated"
@@ -230,9 +236,6 @@ const (
// PagePermissionsPolicyFeatureExecutionWhileNotRendered enum const
PagePermissionsPolicyFeatureExecutionWhileNotRendered PagePermissionsPolicyFeature = "execution-while-not-rendered"
- // PagePermissionsPolicyFeatureFederatedCredentials enum const
- PagePermissionsPolicyFeatureFederatedCredentials PagePermissionsPolicyFeature = "federated-credentials"
-
// PagePermissionsPolicyFeatureFocusWithoutUserActivation enum const
PagePermissionsPolicyFeatureFocusWithoutUserActivation PagePermissionsPolicyFeature = "focus-without-user-activation"
@@ -254,6 +257,9 @@ const (
// PagePermissionsPolicyFeatureHid enum const
PagePermissionsPolicyFeatureHid PagePermissionsPolicyFeature = "hid"
+ // PagePermissionsPolicyFeatureIdentityCredentialsGet enum const
+ PagePermissionsPolicyFeatureIdentityCredentialsGet PagePermissionsPolicyFeature = "identity-credentials-get"
+
// PagePermissionsPolicyFeatureIdleDetection enum const
PagePermissionsPolicyFeatureIdleDetection PagePermissionsPolicyFeature = "idle-detection"
@@ -305,8 +311,8 @@ const (
// PagePermissionsPolicyFeatureSharedStorage enum const
PagePermissionsPolicyFeatureSharedStorage PagePermissionsPolicyFeature = "shared-storage"
- // PagePermissionsPolicyFeatureStorageAccessAPI enum const
- PagePermissionsPolicyFeatureStorageAccessAPI PagePermissionsPolicyFeature = "storage-access-api"
+ // PagePermissionsPolicyFeatureStorageAccess enum const
+ PagePermissionsPolicyFeatureStorageAccess PagePermissionsPolicyFeature = "storage-access"
// PagePermissionsPolicyFeatureSyncXhr enum const
PagePermissionsPolicyFeatureSyncXhr PagePermissionsPolicyFeature = "sync-xhr"
@@ -1144,9 +1150,6 @@ const (
// PageBackForwardCacheNotRestoredReasonOutstandingIndexedDBTransaction enum const
PageBackForwardCacheNotRestoredReasonOutstandingIndexedDBTransaction PageBackForwardCacheNotRestoredReason = "OutstandingIndexedDBTransaction"
- // PageBackForwardCacheNotRestoredReasonRequestedNotificationsPermission enum const
- PageBackForwardCacheNotRestoredReasonRequestedNotificationsPermission PageBackForwardCacheNotRestoredReason = "RequestedNotificationsPermission"
-
// PageBackForwardCacheNotRestoredReasonRequestedMIDIPermission enum const
PageBackForwardCacheNotRestoredReasonRequestedMIDIPermission PageBackForwardCacheNotRestoredReason = "RequestedMIDIPermission"
@@ -1237,6 +1240,9 @@ const (
// PageBackForwardCacheNotRestoredReasonInjectedStyleSheet enum const
PageBackForwardCacheNotRestoredReasonInjectedStyleSheet PageBackForwardCacheNotRestoredReason = "InjectedStyleSheet"
+ // PageBackForwardCacheNotRestoredReasonKeepaliveRequest enum const
+ PageBackForwardCacheNotRestoredReasonKeepaliveRequest PageBackForwardCacheNotRestoredReason = "KeepaliveRequest"
+
// PageBackForwardCacheNotRestoredReasonDummy enum const
PageBackForwardCacheNotRestoredReasonDummy PageBackForwardCacheNotRestoredReason = "Dummy"
@@ -1371,12 +1377,6 @@ const (
// PagePrerenderFinalStatusLowEndDevice enum const
PagePrerenderFinalStatusLowEndDevice PagePrerenderFinalStatus = "LowEndDevice"
- // PagePrerenderFinalStatusCrossOriginRedirect enum const
- PagePrerenderFinalStatusCrossOriginRedirect PagePrerenderFinalStatus = "CrossOriginRedirect"
-
- // PagePrerenderFinalStatusCrossOriginNavigation enum const
- PagePrerenderFinalStatusCrossOriginNavigation PagePrerenderFinalStatus = "CrossOriginNavigation"
-
// PagePrerenderFinalStatusInvalidSchemeRedirect enum const
PagePrerenderFinalStatusInvalidSchemeRedirect PagePrerenderFinalStatus = "InvalidSchemeRedirect"
@@ -1452,20 +1452,53 @@ const (
// PagePrerenderFinalStatusTriggerBackgrounded enum const
PagePrerenderFinalStatusTriggerBackgrounded PagePrerenderFinalStatus = "TriggerBackgrounded"
- // PagePrerenderFinalStatusEmbedderTriggeredAndSameOriginRedirected enum const
- PagePrerenderFinalStatusEmbedderTriggeredAndSameOriginRedirected PagePrerenderFinalStatus = "EmbedderTriggeredAndSameOriginRedirected"
-
// PagePrerenderFinalStatusEmbedderTriggeredAndCrossOriginRedirected enum const
PagePrerenderFinalStatusEmbedderTriggeredAndCrossOriginRedirected PagePrerenderFinalStatus = "EmbedderTriggeredAndCrossOriginRedirected"
- // PagePrerenderFinalStatusEmbedderTriggeredAndDestroyed enum const
- PagePrerenderFinalStatusEmbedderTriggeredAndDestroyed PagePrerenderFinalStatus = "EmbedderTriggeredAndDestroyed"
-
// PagePrerenderFinalStatusMemoryLimitExceeded enum const
PagePrerenderFinalStatusMemoryLimitExceeded PagePrerenderFinalStatus = "MemoryLimitExceeded"
// PagePrerenderFinalStatusFailToGetMemoryUsage enum const
PagePrerenderFinalStatusFailToGetMemoryUsage PagePrerenderFinalStatus = "FailToGetMemoryUsage"
+
+ // PagePrerenderFinalStatusDataSaverEnabled enum const
+ PagePrerenderFinalStatusDataSaverEnabled PagePrerenderFinalStatus = "DataSaverEnabled"
+
+ // PagePrerenderFinalStatusHasEffectiveURL enum const
+ PagePrerenderFinalStatusHasEffectiveURL PagePrerenderFinalStatus = "HasEffectiveUrl"
+
+ // PagePrerenderFinalStatusActivatedBeforeStarted enum const
+ PagePrerenderFinalStatusActivatedBeforeStarted PagePrerenderFinalStatus = "ActivatedBeforeStarted"
+
+ // PagePrerenderFinalStatusInactivePageRestriction enum const
+ PagePrerenderFinalStatusInactivePageRestriction PagePrerenderFinalStatus = "InactivePageRestriction"
+
+ // PagePrerenderFinalStatusStartFailed enum const
+ PagePrerenderFinalStatusStartFailed PagePrerenderFinalStatus = "StartFailed"
+
+ // PagePrerenderFinalStatusTimeoutBackgrounded enum const
+ PagePrerenderFinalStatusTimeoutBackgrounded PagePrerenderFinalStatus = "TimeoutBackgrounded"
+
+ // PagePrerenderFinalStatusCrossSiteRedirect enum const
+ PagePrerenderFinalStatusCrossSiteRedirect PagePrerenderFinalStatus = "CrossSiteRedirect"
+
+ // PagePrerenderFinalStatusCrossSiteNavigation enum const
+ PagePrerenderFinalStatusCrossSiteNavigation PagePrerenderFinalStatus = "CrossSiteNavigation"
+
+ // PagePrerenderFinalStatusSameSiteCrossOriginRedirect enum const
+ PagePrerenderFinalStatusSameSiteCrossOriginRedirect PagePrerenderFinalStatus = "SameSiteCrossOriginRedirect"
+
+ // PagePrerenderFinalStatusSameSiteCrossOriginNavigation enum const
+ PagePrerenderFinalStatusSameSiteCrossOriginNavigation PagePrerenderFinalStatus = "SameSiteCrossOriginNavigation"
+
+ // PagePrerenderFinalStatusSameSiteCrossOriginRedirectNotOptIn enum const
+ PagePrerenderFinalStatusSameSiteCrossOriginRedirectNotOptIn PagePrerenderFinalStatus = "SameSiteCrossOriginRedirectNotOptIn"
+
+ // PagePrerenderFinalStatusSameSiteCrossOriginNavigationNotOptIn enum const
+ PagePrerenderFinalStatusSameSiteCrossOriginNavigationNotOptIn PagePrerenderFinalStatus = "SameSiteCrossOriginNavigationNotOptIn"
+
+ // PagePrerenderFinalStatusActivationNavigationParameterMismatch enum const
+ PagePrerenderFinalStatusActivationNavigationParameterMismatch PagePrerenderFinalStatus = "ActivationNavigationParameterMismatch"
)
// PageAddScriptToEvaluateOnLoad (deprecated) (experimental) Deprecated, please use addScriptToEvaluateOnNewDocument instead.
@@ -1568,6 +1601,9 @@ type PageCaptureScreenshot struct {
// CaptureBeyondViewport (experimental) (optional) Capture the screenshot beyond the viewport. Defaults to false.
CaptureBeyondViewport bool `json:"captureBeyondViewport,omitempty"`
+
+ // OptimizeForSpeed (experimental) (optional) Optimize image encoding for speed, not for resulting size (defaults to false)
+ OptimizeForSpeed bool `json:"optimizeForSpeed,omitempty"`
}
// ProtoReq name
@@ -1821,8 +1857,33 @@ type PageGetAppIDResult struct {
RecommendedID string `json:"recommendedId,omitempty"`
}
-// PageGetCookies (deprecated) (experimental) Returns all browser cookies. Depending on the backend support, will return detailed cookie
-// information in the `cookies` field.
+// PageGetAdScriptID (experimental) ...
+type PageGetAdScriptID struct {
+
+ // FrameID ...
+ FrameID PageFrameID `json:"frameId"`
+}
+
+// ProtoReq name
+func (m PageGetAdScriptID) ProtoReq() string { return "Page.getAdScriptId" }
+
+// Call the request
+func (m PageGetAdScriptID) Call(c Client) (*PageGetAdScriptIDResult, error) {
+ var res PageGetAdScriptIDResult
+ return &res, call(m.ProtoReq(), m, &res, c)
+}
+
+// PageGetAdScriptIDResult (experimental) ...
+type PageGetAdScriptIDResult struct {
+
+ // AdScriptID (optional) Identifies the bottom-most script which caused the frame to be labelled
+ // as an ad. Only sent if frame is labelled as an ad and id is available.
+ AdScriptID *PageAdScriptID `json:"adScriptId,omitempty"`
+}
+
+// PageGetCookies (deprecated) (experimental) Returns all browser cookies for the page and all of its subframes. Depending
+// on the backend support, will return detailed cookie information in the
+// `cookies` field.
type PageGetCookies struct {
}
@@ -2851,10 +2912,6 @@ type PageFrameAttached struct {
// Stack (optional) JavaScript stack trace of when frame was attached, only set if frame initiated from script.
Stack *RuntimeStackTrace `json:"stack,omitempty"`
-
- // AdScriptID (experimental) (optional) Identifies the bottom-most script which caused the frame to be labelled
- // as an ad. Only sent if frame is labelled as an ad and id is available.
- AdScriptID *PageAdScriptID `json:"adScriptId,omitempty"`
}
// ProtoEvent name
@@ -3215,9 +3272,9 @@ type PagePrerenderAttemptCompleted struct {
// FinalStatus ...
FinalStatus PagePrerenderFinalStatus `json:"finalStatus"`
- // ReasonDetails (optional) This is used to give users more information about the cancellation details,
- // and this will be formatted for display.
- ReasonDetails string `json:"reasonDetails,omitempty"`
+ // DisallowedAPIMethod (optional) This is used to give users more information about the name of the API call
+ // that is incompatible with prerender and has caused the cancellation of the attempt
+ DisallowedAPIMethod string `json:"disallowedApiMethod,omitempty"`
}
// ProtoEvent name
diff --git a/vendor/github.com/go-rod/rod/lib/proto/profiler.go b/vendor/github.com/go-rod/rod/lib/proto/profiler.go
index 0850fd7b..2675eb47 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/profiler.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/profiler.go
@@ -100,36 +100,6 @@ type ProfilerScriptCoverage struct {
Functions []*ProfilerFunctionCoverage `json:"functions"`
}
-// ProfilerTypeObject (experimental) Describes a type collected during runtime.
-type ProfilerTypeObject struct {
-
- // Name Name of a type collected with type profiling.
- Name string `json:"name"`
-}
-
-// ProfilerTypeProfileEntry (experimental) Source offset and types for a parameter or return value.
-type ProfilerTypeProfileEntry struct {
-
- // Offset Source offset of the parameter or end of function for return values.
- Offset int `json:"offset"`
-
- // Types The types for this parameter or return value.
- Types []*ProfilerTypeObject `json:"types"`
-}
-
-// ProfilerScriptTypeProfile (experimental) Type profile data collected during runtime for a JavaScript script.
-type ProfilerScriptTypeProfile struct {
-
- // ScriptID JavaScript script id.
- ScriptID RuntimeScriptID `json:"scriptId"`
-
- // URL JavaScript script name or url.
- URL string `json:"url"`
-
- // Entries Type profile entries for parameters and return values of the functions in the script.
- Entries []*ProfilerTypeProfileEntry `json:"entries"`
-}
-
// ProfilerDisable ...
type ProfilerDisable struct {
}
@@ -233,18 +203,6 @@ type ProfilerStartPreciseCoverageResult struct {
Timestamp float64 `json:"timestamp"`
}
-// ProfilerStartTypeProfile (experimental) Enable type profile.
-type ProfilerStartTypeProfile struct {
-}
-
-// ProtoReq name
-func (m ProfilerStartTypeProfile) ProtoReq() string { return "Profiler.startTypeProfile" }
-
-// Call sends the request
-func (m ProfilerStartTypeProfile) Call(c Client) error {
- return call(m.ProtoReq(), m, nil, c)
-}
-
// ProfilerStop ...
type ProfilerStop struct {
}
@@ -278,18 +236,6 @@ func (m ProfilerStopPreciseCoverage) Call(c Client) error {
return call(m.ProtoReq(), m, nil, c)
}
-// ProfilerStopTypeProfile (experimental) Disable type profile. Disabling releases type profile data collected so far.
-type ProfilerStopTypeProfile struct {
-}
-
-// ProtoReq name
-func (m ProfilerStopTypeProfile) ProtoReq() string { return "Profiler.stopTypeProfile" }
-
-// Call sends the request
-func (m ProfilerStopTypeProfile) Call(c Client) error {
- return call(m.ProtoReq(), m, nil, c)
-}
-
// ProfilerTakePreciseCoverage Collect coverage data for the current isolate, and resets execution counters. Precise code
// coverage needs to have started.
type ProfilerTakePreciseCoverage struct {
@@ -314,26 +260,6 @@ type ProfilerTakePreciseCoverageResult struct {
Timestamp float64 `json:"timestamp"`
}
-// ProfilerTakeTypeProfile (experimental) Collect type profile.
-type ProfilerTakeTypeProfile struct {
-}
-
-// ProtoReq name
-func (m ProfilerTakeTypeProfile) ProtoReq() string { return "Profiler.takeTypeProfile" }
-
-// Call the request
-func (m ProfilerTakeTypeProfile) Call(c Client) (*ProfilerTakeTypeProfileResult, error) {
- var res ProfilerTakeTypeProfileResult
- return &res, call(m.ProtoReq(), m, &res, c)
-}
-
-// ProfilerTakeTypeProfileResult (experimental) ...
-type ProfilerTakeTypeProfileResult struct {
-
- // Result Type profile for all scripts since startTypeProfile() was turned on.
- Result []*ProfilerScriptTypeProfile `json:"result"`
-}
-
// ProfilerConsoleProfileFinished ...
type ProfilerConsoleProfileFinished struct {
diff --git a/vendor/github.com/go-rod/rod/lib/proto/storage.go b/vendor/github.com/go-rod/rod/lib/proto/storage.go
index 0e1455a3..73766c8f 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/storage.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/storage.go
@@ -45,6 +45,9 @@ const (
// StorageStorageTypeInterestGroups enum const
StorageStorageTypeInterestGroups StorageStorageType = "interest_groups"
+ // StorageStorageTypeSharedStorage enum const
+ StorageStorageTypeSharedStorage StorageStorageType = "shared_storage"
+
// StorageStorageTypeAll enum const
StorageStorageTypeAll StorageStorageType = "all"
@@ -143,6 +146,147 @@ type StorageInterestGroupDetails struct {
AdComponents []*StorageInterestGroupAd `json:"adComponents"`
}
+// StorageSharedStorageAccessType Enum of shared storage access types.
+type StorageSharedStorageAccessType string
+
+const (
+ // StorageSharedStorageAccessTypeDocumentAddModule enum const
+ StorageSharedStorageAccessTypeDocumentAddModule StorageSharedStorageAccessType = "documentAddModule"
+
+ // StorageSharedStorageAccessTypeDocumentSelectURL enum const
+ StorageSharedStorageAccessTypeDocumentSelectURL StorageSharedStorageAccessType = "documentSelectURL"
+
+ // StorageSharedStorageAccessTypeDocumentRun enum const
+ StorageSharedStorageAccessTypeDocumentRun StorageSharedStorageAccessType = "documentRun"
+
+ // StorageSharedStorageAccessTypeDocumentSet enum const
+ StorageSharedStorageAccessTypeDocumentSet StorageSharedStorageAccessType = "documentSet"
+
+ // StorageSharedStorageAccessTypeDocumentAppend enum const
+ StorageSharedStorageAccessTypeDocumentAppend StorageSharedStorageAccessType = "documentAppend"
+
+ // StorageSharedStorageAccessTypeDocumentDelete enum const
+ StorageSharedStorageAccessTypeDocumentDelete StorageSharedStorageAccessType = "documentDelete"
+
+ // StorageSharedStorageAccessTypeDocumentClear enum const
+ StorageSharedStorageAccessTypeDocumentClear StorageSharedStorageAccessType = "documentClear"
+
+ // StorageSharedStorageAccessTypeWorkletSet enum const
+ StorageSharedStorageAccessTypeWorkletSet StorageSharedStorageAccessType = "workletSet"
+
+ // StorageSharedStorageAccessTypeWorkletAppend enum const
+ StorageSharedStorageAccessTypeWorkletAppend StorageSharedStorageAccessType = "workletAppend"
+
+ // StorageSharedStorageAccessTypeWorkletDelete enum const
+ StorageSharedStorageAccessTypeWorkletDelete StorageSharedStorageAccessType = "workletDelete"
+
+ // StorageSharedStorageAccessTypeWorkletClear enum const
+ StorageSharedStorageAccessTypeWorkletClear StorageSharedStorageAccessType = "workletClear"
+
+ // StorageSharedStorageAccessTypeWorkletGet enum const
+ StorageSharedStorageAccessTypeWorkletGet StorageSharedStorageAccessType = "workletGet"
+
+ // StorageSharedStorageAccessTypeWorkletKeys enum const
+ StorageSharedStorageAccessTypeWorkletKeys StorageSharedStorageAccessType = "workletKeys"
+
+ // StorageSharedStorageAccessTypeWorkletEntries enum const
+ StorageSharedStorageAccessTypeWorkletEntries StorageSharedStorageAccessType = "workletEntries"
+
+ // StorageSharedStorageAccessTypeWorkletLength enum const
+ StorageSharedStorageAccessTypeWorkletLength StorageSharedStorageAccessType = "workletLength"
+
+ // StorageSharedStorageAccessTypeWorkletRemainingBudget enum const
+ StorageSharedStorageAccessTypeWorkletRemainingBudget StorageSharedStorageAccessType = "workletRemainingBudget"
+)
+
+// StorageSharedStorageEntry Struct for a single key-value pair in an origin's shared storage.
+type StorageSharedStorageEntry struct {
+
+ // Key ...
+ Key string `json:"key"`
+
+ // Value ...
+ Value string `json:"value"`
+}
+
+// StorageSharedStorageMetadata Details for an origin's shared storage.
+type StorageSharedStorageMetadata struct {
+
+ // CreationTime ...
+ CreationTime TimeSinceEpoch `json:"creationTime"`
+
+ // Length ...
+ Length int `json:"length"`
+
+ // RemainingBudget ...
+ RemainingBudget float64 `json:"remainingBudget"`
+}
+
+// StorageSharedStorageReportingMetadata Pair of reporting metadata details for a candidate URL for `selectURL()`.
+type StorageSharedStorageReportingMetadata struct {
+
+ // EventType ...
+ EventType string `json:"eventType"`
+
+ // ReportingURL ...
+ ReportingURL string `json:"reportingUrl"`
+}
+
+// StorageSharedStorageURLWithMetadata Bundles a candidate URL with its reporting metadata.
+type StorageSharedStorageURLWithMetadata struct {
+
+ // URL Spec of candidate URL.
+ URL string `json:"url"`
+
+ // ReportingMetadata Any associated reporting metadata.
+ ReportingMetadata []*StorageSharedStorageReportingMetadata `json:"reportingMetadata"`
+}
+
+// StorageSharedStorageAccessParams Bundles the parameters for shared storage access events whose
+// presence/absence can vary according to SharedStorageAccessType.
+type StorageSharedStorageAccessParams struct {
+
+ // ScriptSourceURL (optional) Spec of the module script URL.
+ // Present only for SharedStorageAccessType.documentAddModule.
+ ScriptSourceURL string `json:"scriptSourceUrl,omitempty"`
+
+ // OperationName (optional) Name of the registered operation to be run.
+ // Present only for SharedStorageAccessType.documentRun and
+ // SharedStorageAccessType.documentSelectURL.
+ OperationName string `json:"operationName,omitempty"`
+
+ // SerializedData (optional) The operation's serialized data in bytes (converted to a string).
+ // Present only for SharedStorageAccessType.documentRun and
+ // SharedStorageAccessType.documentSelectURL.
+ SerializedData string `json:"serializedData,omitempty"`
+
+ // UrlsWithMetadata (optional) Array of candidate URLs' specs, along with any associated metadata.
+ // Present only for SharedStorageAccessType.documentSelectURL.
+ UrlsWithMetadata []*StorageSharedStorageURLWithMetadata `json:"urlsWithMetadata,omitempty"`
+
+ // Key (optional) Key for a specific entry in an origin's shared storage.
+ // Present only for SharedStorageAccessType.documentSet,
+ // SharedStorageAccessType.documentAppend,
+ // SharedStorageAccessType.documentDelete,
+ // SharedStorageAccessType.workletSet,
+ // SharedStorageAccessType.workletAppend,
+ // SharedStorageAccessType.workletDelete, and
+ // SharedStorageAccessType.workletGet.
+ Key string `json:"key,omitempty"`
+
+ // Value (optional) Value for a specific entry in an origin's shared storage.
+ // Present only for SharedStorageAccessType.documentSet,
+ // SharedStorageAccessType.documentAppend,
+ // SharedStorageAccessType.workletSet, and
+ // SharedStorageAccessType.workletAppend.
+ Value string `json:"value,omitempty"`
+
+ // IgnoreIfPresent (optional) Whether or not to set an entry for a key if that key is already present.
+ // Present only for SharedStorageAccessType.documentSet and
+ // SharedStorageAccessType.workletSet.
+ IgnoreIfPresent bool `json:"ignoreIfPresent,omitempty"`
+}
+
// StorageGetStorageKeyForFrame Returns a storage key given a frame id.
type StorageGetStorageKeyForFrame struct {
@@ -500,6 +644,67 @@ func (m StorageSetInterestGroupTracking) Call(c Client) error {
return call(m.ProtoReq(), m, nil, c)
}
+// StorageGetSharedStorageMetadata (experimental) Gets metadata for an origin's shared storage.
+type StorageGetSharedStorageMetadata struct {
+
+ // OwnerOrigin ...
+ OwnerOrigin string `json:"ownerOrigin"`
+}
+
+// ProtoReq name
+func (m StorageGetSharedStorageMetadata) ProtoReq() string { return "Storage.getSharedStorageMetadata" }
+
+// Call the request
+func (m StorageGetSharedStorageMetadata) Call(c Client) (*StorageGetSharedStorageMetadataResult, error) {
+ var res StorageGetSharedStorageMetadataResult
+ return &res, call(m.ProtoReq(), m, &res, c)
+}
+
+// StorageGetSharedStorageMetadataResult (experimental) ...
+type StorageGetSharedStorageMetadataResult struct {
+
+ // Metadata ...
+ Metadata *StorageSharedStorageMetadata `json:"metadata"`
+}
+
+// StorageGetSharedStorageEntries (experimental) Gets the entries in an given origin's shared storage.
+type StorageGetSharedStorageEntries struct {
+
+ // OwnerOrigin ...
+ OwnerOrigin string `json:"ownerOrigin"`
+}
+
+// ProtoReq name
+func (m StorageGetSharedStorageEntries) ProtoReq() string { return "Storage.getSharedStorageEntries" }
+
+// Call the request
+func (m StorageGetSharedStorageEntries) Call(c Client) (*StorageGetSharedStorageEntriesResult, error) {
+ var res StorageGetSharedStorageEntriesResult
+ return &res, call(m.ProtoReq(), m, &res, c)
+}
+
+// StorageGetSharedStorageEntriesResult (experimental) ...
+type StorageGetSharedStorageEntriesResult struct {
+
+ // Entries ...
+ Entries []*StorageSharedStorageEntry `json:"entries"`
+}
+
+// StorageSetSharedStorageTracking (experimental) Enables/disables issuing of sharedStorageAccessed events.
+type StorageSetSharedStorageTracking struct {
+
+ // Enable ...
+ Enable bool `json:"enable"`
+}
+
+// ProtoReq name
+func (m StorageSetSharedStorageTracking) ProtoReq() string { return "Storage.setSharedStorageTracking" }
+
+// Call sends the request
+func (m StorageSetSharedStorageTracking) Call(c Client) error {
+ return call(m.ProtoReq(), m, nil, c)
+}
+
// StorageCacheStorageContentUpdated A cache's contents have been modified.
type StorageCacheStorageContentUpdated struct {
@@ -583,3 +788,29 @@ type StorageInterestGroupAccessed struct {
func (evt StorageInterestGroupAccessed) ProtoEvent() string {
return "Storage.interestGroupAccessed"
}
+
+// StorageSharedStorageAccessed Shared storage was accessed by the associated page.
+// The following parameters are included in all events.
+type StorageSharedStorageAccessed struct {
+
+ // AccessTime Time of the access.
+ AccessTime TimeSinceEpoch `json:"accessTime"`
+
+ // Type Enum value indicating the Shared Storage API method invoked.
+ Type StorageSharedStorageAccessType `json:"type"`
+
+ // MainFrameID DevTools Frame Token for the primary frame tree's root.
+ MainFrameID PageFrameID `json:"mainFrameId"`
+
+ // OwnerOrigin Serialized origin for the context that invoked the Shared Storage API.
+ OwnerOrigin string `json:"ownerOrigin"`
+
+ // Params The sub-parameters warapped by `params` are all optional and their
+ // presence/absence depends on `type`.
+ Params *StorageSharedStorageAccessParams `json:"params"`
+}
+
+// ProtoEvent name
+func (evt StorageSharedStorageAccessed) ProtoEvent() string {
+ return "Storage.sharedStorageAccessed"
+}
diff --git a/vendor/github.com/go-rod/rod/lib/proto/target.go b/vendor/github.com/go-rod/rod/lib/proto/target.go
index 2b1aebae..4509fc71 100644
--- a/vendor/github.com/go-rod/rod/lib/proto/target.go
+++ b/vendor/github.com/go-rod/rod/lib/proto/target.go
@@ -68,6 +68,10 @@ type TargetTargetInfo struct {
// BrowserContextID (experimental) (optional) ...
BrowserContextID BrowserBrowserContextID `json:"browserContextId,omitempty"`
+
+ // Subtype (experimental) (optional) Provides additional details for specific target types. For example, for
+ // the type of "page", this may be set to "portal" or "prerender".
+ Subtype string `json:"subtype,omitempty"`
}
// TargetFilterEntry (experimental) A filter used by target query/discovery/auto-attach operations.
diff --git a/vendor/github.com/go-rod/rod/lib/utils/sleeper.go b/vendor/github.com/go-rod/rod/lib/utils/sleeper.go
index dd4976cf..7423ba60 100644
--- a/vendor/github.com/go-rod/rod/lib/utils/sleeper.go
+++ b/vendor/github.com/go-rod/rod/lib/utils/sleeper.go
@@ -14,7 +14,7 @@ func Sleep(seconds float64) {
time.Sleep(d)
}
-// Sleeper sleeps the current gouroutine for sometime, returns the reason to wake, if ctx is done release resource
+// Sleeper sleeps the current goroutine for sometime, returns the reason to wake, if ctx is done release resource
type Sleeper func(context.Context) error
// ErrMaxSleepCount type
diff --git a/vendor/github.com/go-rod/rod/lib/utils/utils.go b/vendor/github.com/go-rod/rod/lib/utils/utils.go
index 1bd91d80..91936ac1 100644
--- a/vendor/github.com/go-rod/rod/lib/utils/utils.go
+++ b/vendor/github.com/go-rod/rod/lib/utils/utils.go
@@ -27,6 +27,11 @@ import (
"github.com/ysmood/gson"
)
+// TestEnvs for testing
+var TestEnvs = map[string]string{
+ "GODEBUG": "tracebackancestors=100",
+}
+
// InContainer will be true if is inside container environment, such as docker
var InContainer = FileExists("/.dockerenv") || FileExists("/.containerenv")
@@ -274,7 +279,7 @@ func Exec(line string, rest ...string) string {
return ExecLine(true, line, rest...)
}
-var execLogger = log.New(os.Stdout, "[exec]", log.LstdFlags)
+var execLogger = log.New(os.Stdout, "[exec] ", 0)
// ExecLine of command
func ExecLine(std bool, line string, rest ...string) string {
@@ -298,6 +303,9 @@ func ExecLine(std bool, line string, rest ...string) string {
}
if err := cmd.Run(); err != nil {
+ if std {
+ panic(err)
+ }
panic(fmt.Sprintf("%v\n%v", err, buf.String()))
}
diff --git a/vendor/github.com/go-rod/rod/page.go b/vendor/github.com/go-rod/rod/page.go
index d5d399f6..9eb052b2 100644
--- a/vendor/github.com/go-rod/rod/page.go
+++ b/vendor/github.com/go-rod/rod/page.go
@@ -301,7 +301,7 @@ func (p *Page) Close() error {
for {
err := proto.PageClose{}.Call(p)
if errors.Is(err, cdp.ErrNotAttachedToActivePage) {
- // TODO: I don't know why chromium doesn't allow to close a page while it's navigating.
+ // TODO: I don't know why chromium doesn't allow us to close a page while it's navigating.
// Looks like a bug in chromium.
utils.Sleep(0.1)
continue
@@ -390,11 +390,11 @@ func (p *Page) HandleFileDialog() (func([]string) error, error) {
}
// Screenshot captures the screenshot of current page.
-func (p *Page) Screenshot(fullpage bool, req *proto.PageCaptureScreenshot) ([]byte, error) {
+func (p *Page) Screenshot(fullPage bool, req *proto.PageCaptureScreenshot) ([]byte, error) {
if req == nil {
req = &proto.PageCaptureScreenshot{}
}
- if fullpage {
+ if fullPage {
metrics, err := proto.PageGetLayoutMetrics{}.Call(p)
if err != nil {
return nil, err
@@ -536,15 +536,15 @@ func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string) fun
p, cancel := p.WithCancel()
match := genRegMatcher(includes, excludes)
- waitlist := map[proto.NetworkRequestID]string{}
+ waitList := map[proto.NetworkRequestID]string{}
idleCounter := utils.NewIdleCounter(d)
update := p.tryTraceReq(includes, excludes)
update(nil)
checkDone := func(id proto.NetworkRequestID) {
- if _, has := waitlist[id]; has {
- delete(waitlist, id)
- update(waitlist)
+ if _, has := waitList[id]; has {
+ delete(waitList, id)
+ update(waitList)
idleCounter.Done()
}
}
@@ -553,9 +553,9 @@ func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string) fun
if match(sent.Request.URL) {
// Redirect will send multiple NetworkRequestWillBeSent events with the same RequestID,
// we should filter them out.
- if _, has := waitlist[sent.RequestID]; !has {
- waitlist[sent.RequestID] = sent.Request.URL
- update(waitlist)
+ if _, has := waitList[sent.RequestID]; !has {
+ waitList[sent.RequestID] = sent.Request.URL
+ update(waitList)
idleCounter.Add()
}
}
diff --git a/vendor/github.com/go-rod/rod/page_eval.go b/vendor/github.com/go-rod/rod/page_eval.go
index 23d52e9f..e20d6b96 100644
--- a/vendor/github.com/go-rod/rod/page_eval.go
+++ b/vendor/github.com/go-rod/rod/page_eval.go
@@ -225,22 +225,22 @@ func (p *Page) Expose(name string, fn func(gson.JSON) (interface{}, error)) (sto
}
func (p *Page) formatArgs(opts *EvalOptions) ([]*proto.RuntimeCallArgument, error) {
- formated := []*proto.RuntimeCallArgument{}
+ formatted := []*proto.RuntimeCallArgument{}
for _, arg := range opts.JSArgs {
if obj, ok := arg.(*proto.RuntimeRemoteObject); ok { // remote object
- formated = append(formated, &proto.RuntimeCallArgument{ObjectID: obj.ObjectID})
+ formatted = append(formatted, &proto.RuntimeCallArgument{ObjectID: obj.ObjectID})
} else if obj, ok := arg.(*js.Function); ok { // js helper
id, err := p.ensureJSHelper(obj)
if err != nil {
return nil, err
}
- formated = append(formated, &proto.RuntimeCallArgument{ObjectID: id})
+ formatted = append(formatted, &proto.RuntimeCallArgument{ObjectID: id})
} else { // plain json data
- formated = append(formated, &proto.RuntimeCallArgument{Value: gson.New(arg)})
+ formatted = append(formatted, &proto.RuntimeCallArgument{Value: gson.New(arg)})
}
}
- return formated, nil
+ return formatted, nil
}
// Check the doc of EvalHelper
diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go
index 9d2d8a4b..06a91f08 100644
--- a/vendor/github.com/inconshreveable/mousetrap/trap_others.go
+++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go
@@ -1,3 +1,4 @@
+//go:build !windows
// +build !windows
package mousetrap
diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go
index 336142a5..0c568802 100644
--- a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go
+++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go
@@ -1,81 +1,32 @@
-// +build windows
-// +build !go1.4
-
package mousetrap
import (
- "fmt"
- "os"
"syscall"
"unsafe"
)
-const (
- // defined by the Win32 API
- th32cs_snapprocess uintptr = 0x2
-)
-
-var (
- kernel = syscall.MustLoadDLL("kernel32.dll")
- CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
- Process32First = kernel.MustFindProc("Process32FirstW")
- Process32Next = kernel.MustFindProc("Process32NextW")
-)
-
-// ProcessEntry32 structure defined by the Win32 API
-type processEntry32 struct {
- dwSize uint32
- cntUsage uint32
- th32ProcessID uint32
- th32DefaultHeapID int
- th32ModuleID uint32
- cntThreads uint32
- th32ParentProcessID uint32
- pcPriClassBase int32
- dwFlags uint32
- szExeFile [syscall.MAX_PATH]uint16
-}
-
-func getProcessEntry(pid int) (pe *processEntry32, err error) {
- snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
- if snapshot == uintptr(syscall.InvalidHandle) {
- err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
- return
+func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
+ snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
+ if err != nil {
+ return nil, err
}
- defer syscall.CloseHandle(syscall.Handle(snapshot))
-
- var processEntry processEntry32
- processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
- ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
- if ok == 0 {
- err = fmt.Errorf("Process32First: %v", e1)
- return
+ defer syscall.CloseHandle(snapshot)
+ var procEntry syscall.ProcessEntry32
+ procEntry.Size = uint32(unsafe.Sizeof(procEntry))
+ if err = syscall.Process32First(snapshot, &procEntry); err != nil {
+ return nil, err
}
-
for {
- if processEntry.th32ProcessID == uint32(pid) {
- pe = &processEntry
- return
+ if procEntry.ProcessID == uint32(pid) {
+ return &procEntry, nil
}
-
- ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
- if ok == 0 {
- err = fmt.Errorf("Process32Next: %v", e1)
- return
+ err = syscall.Process32Next(snapshot, &procEntry)
+ if err != nil {
+ return nil, err
}
}
}
-func getppid() (pid int, err error) {
- pe, err := getProcessEntry(os.Getpid())
- if err != nil {
- return
- }
-
- pid = int(pe.th32ParentProcessID)
- return
-}
-
// StartedByExplorer returns true if the program was invoked by the user double-clicking
// on the executable from explorer.exe
//
@@ -83,16 +34,9 @@ func getppid() (pid int, err error) {
// It does not guarantee that the program was run from a terminal. It only can tell you
// whether it was launched from explorer.exe
func StartedByExplorer() bool {
- ppid, err := getppid()
+ pe, err := getProcessEntry(syscall.Getppid())
if err != nil {
return false
}
-
- pe, err := getProcessEntry(ppid)
- if err != nil {
- return false
- }
-
- name := syscall.UTF16ToString(pe.szExeFile[:])
- return name == "explorer.exe"
+ return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
}
diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
deleted file mode 100644
index 9a28e57c..00000000
--- a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// +build windows
-// +build go1.4
-
-package mousetrap
-
-import (
- "os"
- "syscall"
- "unsafe"
-)
-
-func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
- snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
- if err != nil {
- return nil, err
- }
- defer syscall.CloseHandle(snapshot)
- var procEntry syscall.ProcessEntry32
- procEntry.Size = uint32(unsafe.Sizeof(procEntry))
- if err = syscall.Process32First(snapshot, &procEntry); err != nil {
- return nil, err
- }
- for {
- if procEntry.ProcessID == uint32(pid) {
- return &procEntry, nil
- }
- err = syscall.Process32Next(snapshot, &procEntry)
- if err != nil {
- return nil, err
- }
- }
-}
-
-// StartedByExplorer returns true if the program was invoked by the user double-clicking
-// on the executable from explorer.exe
-//
-// It is conservative and returns false if any of the internal calls fail.
-// It does not guarantee that the program was run from a terminal. It only can tell you
-// whether it was launched from explorer.exe
-func StartedByExplorer() bool {
- pe, err := getProcessEntry(os.Getppid())
- if err != nil {
- return false
- }
- return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
-}
diff --git a/vendor/github.com/invopop/jsonschema/reflect.go b/vendor/github.com/invopop/jsonschema/reflect.go
index 1b6732d2..6ebc6be5 100644
--- a/vendor/github.com/invopop/jsonschema/reflect.go
+++ b/vendor/github.com/invopop/jsonschema/reflect.go
@@ -108,7 +108,14 @@ type customSchemaImpl interface {
JSONSchema() *Schema
}
+// Function to be run after the schema has been generated.
+// this will let you modify a schema afterwards
+type extendSchemaImpl interface {
+ JSONSchemaExtend(*Schema)
+}
+
var customType = reflect.TypeOf((*customSchemaImpl)(nil)).Elem()
+var extendType = reflect.TypeOf((*extendSchemaImpl)(nil)).Elem()
// customSchemaGetFieldDocString
type customSchemaGetFieldDocString interface {
@@ -395,6 +402,8 @@ func (r *Reflector) reflectTypeToSchema(definitions Definitions, t reflect.Type)
panic("unsupported type " + t.String())
}
+ r.reflectSchemaExtend(definitions, t, st)
+
// Always try to reference the definition which may have just been created
if def := r.refDefinition(definitions, t); def != nil {
return def
@@ -422,6 +431,19 @@ func (r *Reflector) reflectCustomSchema(definitions Definitions, t reflect.Type)
return nil
}
+func (r *Reflector) reflectSchemaExtend(definitions Definitions, t reflect.Type, s *Schema) *Schema {
+ if t.Implements(extendType) {
+ v := reflect.New(t)
+ o := v.Interface().(extendSchemaImpl)
+ o.JSONSchemaExtend(s)
+ if ref := r.refDefinition(definitions, t); ref != nil {
+ return ref
+ }
+ }
+
+ return s
+}
+
func (r *Reflector) reflectSliceOrArray(definitions Definitions, t reflect.Type, st *Schema) {
if t == rawMessageType {
return
@@ -683,6 +705,21 @@ func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName str
parent.OneOf = append(parent.OneOf, typeFound)
}
typeFound.Required = append(typeFound.Required, propertyName)
+ case "anyof_required":
+ var typeFound *Schema
+ for i := range parent.AnyOf {
+ if parent.AnyOf[i].Title == nameValue[1] {
+ typeFound = parent.AnyOf[i]
+ }
+ }
+ if typeFound == nil {
+ typeFound = &Schema{
+ Title: nameValue[1],
+ Required: []string{},
+ }
+ parent.AnyOf = append(parent.AnyOf, typeFound)
+ }
+ typeFound.Required = append(typeFound.Required, propertyName)
case "oneof_type":
if t.OneOf == nil {
t.OneOf = make([]*Schema, 0, 1)
@@ -694,6 +731,17 @@ func (t *Schema) genericKeywords(tags []string, parent *Schema, propertyName str
Type: ty,
})
}
+ case "anyof_type":
+ if t.AnyOf == nil {
+ t.AnyOf = make([]*Schema, 0, 1)
+ }
+ t.Type = ""
+ types := strings.Split(nameValue[1], ";")
+ for _, ty := range types {
+ t.AnyOf = append(t.AnyOf, &Schema{
+ Type: ty,
+ })
+ }
case "enum":
switch t.Type {
case "string":
@@ -855,7 +903,7 @@ func (t *Schema) arrayKeywords(tags []string) {
func (t *Schema) extraKeywords(tags []string) {
for _, tag := range tags {
- nameValue := strings.Split(tag, "=")
+ nameValue := strings.SplitN(tag, "=", 2)
if len(nameValue) == 2 {
t.setExtra(nameValue[0], nameValue[1])
}
@@ -874,13 +922,23 @@ func (t *Schema) setExtra(key, val string) {
t.Extras[key] = append(existingVal, val)
case int:
t.Extras[key], _ = strconv.Atoi(val)
+ case bool:
+ t.Extras[key] = (val == "true" || val == "t")
}
} else {
switch key {
case "minimum":
t.Extras[key], _ = strconv.Atoi(val)
default:
- t.Extras[key] = val
+ var x interface{}
+ if val == "true" {
+ x = true
+ } else if val == "false" {
+ x = false
+ } else {
+ x = val
+ }
+ t.Extras[key] = x
}
}
}
@@ -955,6 +1013,11 @@ func (r *Reflector) reflectFieldName(f reflect.StructField) (string, bool, bool,
if f.Type.Kind() == reflect.Struct {
return "", true, false, false
}
+
+ // As per JSON Marshal rules, anonymous pointer to structs are inherited
+ if f.Type.Kind() == reflect.Ptr && f.Type.Elem().Kind() == reflect.Struct {
+ return "", true, false, false
+ }
}
// Try to determine the name from the different combos
diff --git a/vendor/github.com/magiconair/properties/.travis.yml b/vendor/github.com/magiconair/properties/.travis.yml
deleted file mode 100644
index baf9031d..00000000
--- a/vendor/github.com/magiconair/properties/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-go:
- - 1.3.x
- - 1.4.x
- - 1.5.x
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - "1.10.x"
- - "1.11.x"
- - "1.12.x"
- - "1.13.x"
- - "1.14.x"
- - "1.15.x"
- - "1.16.x"
- - tip
diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md
index ff8d0253..842e8e24 100644
--- a/vendor/github.com/magiconair/properties/CHANGELOG.md
+++ b/vendor/github.com/magiconair/properties/CHANGELOG.md
@@ -1,5 +1,50 @@
## Changelog
+### [1.8.7](https://github.com/magiconair/properties/tree/v1.8.7) - 08 Dec 2022
+
+ * [PR #65](https://github.com/magiconair/properties/pull/65): Speedup Merge
+
+ Thanks to [@AdityaVallabh](https://github.com/AdityaVallabh) for the patch.
+
+ * [PR #66](https://github.com/magiconair/properties/pull/66): use github actions
+
+### [1.8.6](https://github.com/magiconair/properties/tree/v1.8.6) - 23 Feb 2022
+
+ * [PR #57](https://github.com/magiconair/properties/pull/57):Fix "unreachable code" lint error
+
+ Thanks to [@ellie](https://github.com/ellie) for the patch.
+
+ * [PR #63](https://github.com/magiconair/properties/pull/63): Make TestMustGetParsedDuration backwards compatible
+
+ This patch ensures that the `TestMustGetParsedDuration` still works with `go1.3` to make the
+ author happy until it affects real users.
+
+ Thanks to [@maage](https://github.com/maage) for the patch.
+
+### [1.8.5](https://github.com/magiconair/properties/tree/v1.8.5) - 24 Mar 2021
+
+ * [PR #55](https://github.com/magiconair/properties/pull/55): Fix: Encoding Bug in Comments
+
+ When reading comments \ are loaded correctly, but when writing they are then
+ replaced by \\. This leads to wrong comments when writing and reading multiple times.
+
+ Thanks to [@doxsch](https://github.com/doxsch) for the patch.
+
+### [1.8.4](https://github.com/magiconair/properties/tree/v1.8.4) - 23 Sep 2020
+
+ * [PR #50](https://github.com/magiconair/properties/pull/50): enhance error message for circular references
+
+ Thanks to [@sriv](https://github.com/sriv) for the patch.
+
+### [1.8.3](https://github.com/magiconair/properties/tree/v1.8.3) - 14 Sep 2020
+
+ * [PR #49](https://github.com/magiconair/properties/pull/49): Include the key in error message causing the circular reference
+
+ The change is include the key in the error message which is causing the circular
+ reference when parsing/loading the properties files.
+
+ Thanks to [@haroon-sheikh](https://github.com/haroon-sheikh) for the patch.
+
### [1.8.2](https://github.com/magiconair/properties/tree/v1.8.2) - 25 Aug 2020
* [PR #36](https://github.com/magiconair/properties/pull/36): Escape backslash on write
diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go
index 3ebf8049..8e6aa441 100644
--- a/vendor/github.com/magiconair/properties/decode.go
+++ b/vendor/github.com/magiconair/properties/decode.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -48,49 +48,49 @@ import (
//
// Examples:
//
-// // Field is ignored.
-// Field int `properties:"-"`
+// // Field is ignored.
+// Field int `properties:"-"`
//
-// // Field is assigned value of 'Field'.
-// Field int
+// // Field is assigned value of 'Field'.
+// Field int
//
-// // Field is assigned value of 'myName'.
-// Field int `properties:"myName"`
+// // Field is assigned value of 'myName'.
+// Field int `properties:"myName"`
//
-// // Field is assigned value of key 'myName' and has a default
-// // value 15 if the key does not exist.
-// Field int `properties:"myName,default=15"`
+// // Field is assigned value of key 'myName' and has a default
+// // value 15 if the key does not exist.
+// Field int `properties:"myName,default=15"`
//
-// // Field is assigned value of key 'Field' and has a default
-// // value 15 if the key does not exist.
-// Field int `properties:",default=15"`
+// // Field is assigned value of key 'Field' and has a default
+// // value 15 if the key does not exist.
+// Field int `properties:",default=15"`
//
-// // Field is assigned value of key 'date' and the date
-// // is in format 2006-01-02
-// Field time.Time `properties:"date,layout=2006-01-02"`
+// // Field is assigned value of key 'date' and the date
+// // is in format 2006-01-02
+// Field time.Time `properties:"date,layout=2006-01-02"`
//
-// // Field is assigned the non-empty and whitespace trimmed
-// // values of key 'Field' split by commas.
-// Field []string
+// // Field is assigned the non-empty and whitespace trimmed
+// // values of key 'Field' split by commas.
+// Field []string
//
-// // Field is assigned the non-empty and whitespace trimmed
-// // values of key 'Field' split by commas and has a default
-// // value ["a", "b", "c"] if the key does not exist.
-// Field []string `properties:",default=a;b;c"`
+// // Field is assigned the non-empty and whitespace trimmed
+// // values of key 'Field' split by commas and has a default
+// // value ["a", "b", "c"] if the key does not exist.
+// Field []string `properties:",default=a;b;c"`
//
-// // Field is decoded recursively with "Field." as key prefix.
-// Field SomeStruct
+// // Field is decoded recursively with "Field." as key prefix.
+// Field SomeStruct
//
-// // Field is decoded recursively with "myName." as key prefix.
-// Field SomeStruct `properties:"myName"`
+// // Field is decoded recursively with "myName." as key prefix.
+// Field SomeStruct `properties:"myName"`
//
-// // Field is decoded recursively with "Field." as key prefix
-// // and the next dotted element of the key as map key.
-// Field map[string]string
+// // Field is decoded recursively with "Field." as key prefix
+// // and the next dotted element of the key as map key.
+// Field map[string]string
//
-// // Field is decoded recursively with "myName." as key prefix
-// // and the next dotted element of the key as map key.
-// Field map[string]string `properties:"myName"`
+// // Field is decoded recursively with "myName." as key prefix
+// // and the next dotted element of the key as map key.
+// Field map[string]string `properties:"myName"`
func (p *Properties) Decode(x interface{}) error {
t, v := reflect.TypeOf(x), reflect.ValueOf(x)
if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct {
diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go
index f8822da2..7c797931 100644
--- a/vendor/github.com/magiconair/properties/doc.go
+++ b/vendor/github.com/magiconair/properties/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -13,7 +13,7 @@
//
// To load a single properties file use MustLoadFile():
//
-// p := properties.MustLoadFile(filename, properties.UTF8)
+// p := properties.MustLoadFile(filename, properties.UTF8)
//
// To load multiple properties files use MustLoadFiles()
// which loads the files in the given order and merges the
@@ -23,25 +23,25 @@
// Filenames can contain environment variables which are expanded
// before loading.
//
-// f1 := "/etc/myapp/myapp.conf"
-// f2 := "/home/${USER}/myapp.conf"
-// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
+// f1 := "/etc/myapp/myapp.conf"
+// f2 := "/home/${USER}/myapp.conf"
+// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
//
// All of the different key/value delimiters ' ', ':' and '=' are
// supported as well as the comment characters '!' and '#' and
// multi-line values.
//
-// ! this is a comment
-// # and so is this
+// ! this is a comment
+// # and so is this
//
-// # the following expressions are equal
-// key value
-// key=value
-// key:value
-// key = value
-// key : value
-// key = val\
-// ue
+// # the following expressions are equal
+// key value
+// key=value
+// key:value
+// key = value
+// key : value
+// key = val\
+// ue
//
// Properties stores all comments preceding a key and provides
// GetComments() and SetComments() methods to retrieve and
@@ -55,62 +55,62 @@
// and malformed expressions are not allowed and cause an
// error. Expansion of environment variables is supported.
//
-// # standard property
-// key = value
+// # standard property
+// key = value
//
-// # property expansion: key2 = value
-// key2 = ${key}
+// # property expansion: key2 = value
+// key2 = ${key}
//
-// # recursive expansion: key3 = value
-// key3 = ${key2}
+// # recursive expansion: key3 = value
+// key3 = ${key2}
//
-// # circular reference (error)
-// key = ${key}
+// # circular reference (error)
+// key = ${key}
//
-// # malformed expression (error)
-// key = ${ke
+// # malformed expression (error)
+// key = ${ke
//
-// # refers to the users' home dir
-// home = ${HOME}
+// # refers to the users' home dir
+// home = ${HOME}
//
-// # local key takes precedence over env var: u = foo
-// USER = foo
-// u = ${USER}
+// # local key takes precedence over env var: u = foo
+// USER = foo
+// u = ${USER}
//
// The default property expansion format is ${key} but can be
// changed by setting different pre- and postfix values on the
// Properties object.
//
-// p := properties.NewProperties()
-// p.Prefix = "#["
-// p.Postfix = "]#"
+// p := properties.NewProperties()
+// p.Prefix = "#["
+// p.Postfix = "]#"
//
// Properties provides convenience functions for getting typed
// values with default values if the key does not exist or the
// type conversion failed.
//
-// # Returns true if the value is either "1", "on", "yes" or "true"
-// # Returns false for every other value and the default value if
-// # the key does not exist.
-// v = p.GetBool("key", false)
+// # Returns true if the value is either "1", "on", "yes" or "true"
+// # Returns false for every other value and the default value if
+// # the key does not exist.
+// v = p.GetBool("key", false)
//
-// # Returns the value if the key exists and the format conversion
-// # was successful. Otherwise, the default value is returned.
-// v = p.GetInt64("key", 999)
-// v = p.GetUint64("key", 999)
-// v = p.GetFloat64("key", 123.0)
-// v = p.GetString("key", "def")
-// v = p.GetDuration("key", 999)
+// # Returns the value if the key exists and the format conversion
+// # was successful. Otherwise, the default value is returned.
+// v = p.GetInt64("key", 999)
+// v = p.GetUint64("key", 999)
+// v = p.GetFloat64("key", 123.0)
+// v = p.GetString("key", "def")
+// v = p.GetDuration("key", 999)
//
// As an alternative properties may be applied with the standard
// library's flag implementation at any time.
//
-// # Standard configuration
-// v = flag.Int("key", 999, "help message")
-// flag.Parse()
+// # Standard configuration
+// v = flag.Int("key", 999, "help message")
+// flag.Parse()
//
-// # Merge p into the flag set
-// p.MustFlag(flag.CommandLine)
+// # Merge p into the flag set
+// p.MustFlag(flag.CommandLine)
//
// Properties provides several MustXXX() convenience functions
// which will terminate the app if an error occurs. The behavior
@@ -119,30 +119,30 @@
// of logging the error set a different ErrorHandler before
// you use the Properties package.
//
-// properties.ErrorHandler = properties.PanicHandler
+// properties.ErrorHandler = properties.PanicHandler
//
-// # Will panic instead of logging an error
-// p := properties.MustLoadFile("config.properties")
+// # Will panic instead of logging an error
+// p := properties.MustLoadFile("config.properties")
//
// You can also provide your own ErrorHandler function. The only requirement
// is that the error handler function must exit after handling the error.
//
-// properties.ErrorHandler = func(err error) {
-// fmt.Println(err)
-// os.Exit(1)
-// }
+// properties.ErrorHandler = func(err error) {
+// fmt.Println(err)
+// os.Exit(1)
+// }
//
-// # Will write to stdout and then exit
-// p := properties.MustLoadFile("config.properties")
+// # Will write to stdout and then exit
+// p := properties.MustLoadFile("config.properties")
//
// Properties can also be loaded into a struct via the `Decode`
// method, e.g.
//
-// type S struct {
-// A string `properties:"a,default=foo"`
-// D time.Duration `properties:"timeout,default=5s"`
-// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"`
-// }
+// type S struct {
+// A string `properties:"a,default=foo"`
+// D time.Duration `properties:"timeout,default=5s"`
+// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"`
+// }
//
// See `Decode()` method for the full documentation.
//
@@ -152,5 +152,4 @@
// http://en.wikipedia.org/wiki/.properties
//
// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29
-//
package properties
diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go
index 74d38dc6..35d0ae97 100644
--- a/vendor/github.com/magiconair/properties/integrate.go
+++ b/vendor/github.com/magiconair/properties/integrate.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -10,8 +10,9 @@ import "flag"
// the respective key for flag.Flag.Name.
//
// It's use is recommended with command line arguments as in:
-// flag.Parse()
-// p.MustFlag(flag.CommandLine)
+//
+// flag.Parse()
+// p.MustFlag(flag.CommandLine)
func (p *Properties) MustFlag(dst *flag.FlagSet) {
m := make(map[string]*flag.Flag)
dst.VisitAll(func(f *flag.Flag) {
diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go
index e1e9dd7b..3d15a1f6 100644
--- a/vendor/github.com/magiconair/properties/lex.go
+++ b/vendor/github.com/magiconair/properties/lex.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go
index c83c2dad..635368dc 100644
--- a/vendor/github.com/magiconair/properties/load.go
+++ b/vendor/github.com/magiconair/properties/load.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go
index 430e4fcd..fccfd39f 100644
--- a/vendor/github.com/magiconair/properties/parser.go
+++ b/vendor/github.com/magiconair/properties/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go
index 62ae2d67..fb2f7b40 100644
--- a/vendor/github.com/magiconair/properties/properties.go
+++ b/vendor/github.com/magiconair/properties/properties.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -700,22 +700,17 @@ func (p *Properties) Delete(key string) {
// Merge merges properties, comments and keys from other *Properties into p
func (p *Properties) Merge(other *Properties) {
+ for _, k := range other.k {
+ if _, ok := p.m[k]; !ok {
+ p.k = append(p.k, k)
+ }
+ }
for k, v := range other.m {
p.m[k] = v
}
for k, v := range other.c {
p.c[k] = v
}
-
-outer:
- for _, otherKey := range other.k {
- for _, key := range p.k {
- if otherKey == key {
- continue outer
- }
- }
- p.k = append(p.k, otherKey)
- }
}
// ----------------------------------------------------------------------------
diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go
index b013a2e5..dbd60b36 100644
--- a/vendor/github.com/magiconair/properties/rangecheck.go
+++ b/vendor/github.com/magiconair/properties/rangecheck.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/vendor/github.com/pelletier/go-toml/v2/README.md b/vendor/github.com/pelletier/go-toml/v2/README.md
index a63c3a79..9f8439cc 100644
--- a/vendor/github.com/pelletier/go-toml/v2/README.md
+++ b/vendor/github.com/pelletier/go-toml/v2/README.md
@@ -140,6 +140,17 @@ fmt.Println(string(b))
[marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal
+## Unstable API
+
+This API does not yet follow the backward compatibility guarantees of this
+library. They provide early access to features that may have rough edges or an
+API subject to change.
+
+### Parser
+
+Parser is the unstable API that allows iterative parsing of a TOML document at
+the AST level. See https://pkg.go.dev/github.com/pelletier/go-toml/v2/unstable.
+
## Benchmarks
Execution time speedup compared to other Go TOML libraries:
diff --git a/vendor/github.com/pelletier/go-toml/v2/decode.go b/vendor/github.com/pelletier/go-toml/v2/decode.go
index 4af96536..3a860d0f 100644
--- a/vendor/github.com/pelletier/go-toml/v2/decode.go
+++ b/vendor/github.com/pelletier/go-toml/v2/decode.go
@@ -5,6 +5,8 @@ import (
"math"
"strconv"
"time"
+
+ "github.com/pelletier/go-toml/v2/unstable"
)
func parseInteger(b []byte) (int64, error) {
@@ -32,7 +34,7 @@ func parseLocalDate(b []byte) (LocalDate, error) {
var date LocalDate
if len(b) != 10 || b[4] != '-' || b[7] != '-' {
- return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD")
+ return date, unstable.NewParserError(b, "dates are expected to have the format YYYY-MM-DD")
}
var err error
@@ -53,7 +55,7 @@ func parseLocalDate(b []byte) (LocalDate, error) {
}
if !isValidDate(date.Year, date.Month, date.Day) {
- return LocalDate{}, newDecodeError(b, "impossible date")
+ return LocalDate{}, unstable.NewParserError(b, "impossible date")
}
return date, nil
@@ -64,7 +66,7 @@ func parseDecimalDigits(b []byte) (int, error) {
for i, c := range b {
if c < '0' || c > '9' {
- return 0, newDecodeError(b[i:i+1], "expected digit (0-9)")
+ return 0, unstable.NewParserError(b[i:i+1], "expected digit (0-9)")
}
v *= 10
v += int(c - '0')
@@ -97,7 +99,7 @@ func parseDateTime(b []byte) (time.Time, error) {
} else {
const dateTimeByteLen = 6
if len(b) != dateTimeByteLen {
- return time.Time{}, newDecodeError(b, "invalid date-time timezone")
+ return time.Time{}, unstable.NewParserError(b, "invalid date-time timezone")
}
var direction int
switch b[0] {
@@ -106,11 +108,11 @@ func parseDateTime(b []byte) (time.Time, error) {
case '+':
direction = +1
default:
- return time.Time{}, newDecodeError(b[:1], "invalid timezone offset character")
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset character")
}
if b[3] != ':' {
- return time.Time{}, newDecodeError(b[3:4], "expected a : separator")
+ return time.Time{}, unstable.NewParserError(b[3:4], "expected a : separator")
}
hours, err := parseDecimalDigits(b[1:3])
@@ -118,7 +120,7 @@ func parseDateTime(b []byte) (time.Time, error) {
return time.Time{}, err
}
if hours > 23 {
- return time.Time{}, newDecodeError(b[:1], "invalid timezone offset hours")
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset hours")
}
minutes, err := parseDecimalDigits(b[4:6])
@@ -126,7 +128,7 @@ func parseDateTime(b []byte) (time.Time, error) {
return time.Time{}, err
}
if minutes > 59 {
- return time.Time{}, newDecodeError(b[:1], "invalid timezone offset minutes")
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset minutes")
}
seconds := direction * (hours*3600 + minutes*60)
@@ -139,7 +141,7 @@ func parseDateTime(b []byte) (time.Time, error) {
}
if len(b) > 0 {
- return time.Time{}, newDecodeError(b, "extra bytes at the end of the timezone")
+ return time.Time{}, unstable.NewParserError(b, "extra bytes at the end of the timezone")
}
t := time.Date(
@@ -160,7 +162,7 @@ func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
const localDateTimeByteMinLen = 11
if len(b) < localDateTimeByteMinLen {
- return dt, nil, newDecodeError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
+ return dt, nil, unstable.NewParserError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
}
date, err := parseLocalDate(b[:10])
@@ -171,7 +173,7 @@ func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
sep := b[10]
if sep != 'T' && sep != ' ' && sep != 't' {
- return dt, nil, newDecodeError(b[10:11], "datetime separator is expected to be T or a space")
+ return dt, nil, unstable.NewParserError(b[10:11], "datetime separator is expected to be T or a space")
}
t, rest, err := parseLocalTime(b[11:])
@@ -195,7 +197,7 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
// check if b matches to have expected format HH:MM:SS[.NNNNNN]
const localTimeByteLen = 8
if len(b) < localTimeByteLen {
- return t, nil, newDecodeError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
+ return t, nil, unstable.NewParserError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
}
var err error
@@ -206,10 +208,10 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
}
if t.Hour > 23 {
- return t, nil, newDecodeError(b[0:2], "hour cannot be greater 23")
+ return t, nil, unstable.NewParserError(b[0:2], "hour cannot be greater 23")
}
if b[2] != ':' {
- return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes")
+ return t, nil, unstable.NewParserError(b[2:3], "expecting colon between hours and minutes")
}
t.Minute, err = parseDecimalDigits(b[3:5])
@@ -217,10 +219,10 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
return t, nil, err
}
if t.Minute > 59 {
- return t, nil, newDecodeError(b[3:5], "minutes cannot be greater 59")
+ return t, nil, unstable.NewParserError(b[3:5], "minutes cannot be greater 59")
}
if b[5] != ':' {
- return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds")
+ return t, nil, unstable.NewParserError(b[5:6], "expecting colon between minutes and seconds")
}
t.Second, err = parseDecimalDigits(b[6:8])
@@ -229,7 +231,7 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
}
if t.Second > 60 {
- return t, nil, newDecodeError(b[6:8], "seconds cannot be greater 60")
+ return t, nil, unstable.NewParserError(b[6:8], "seconds cannot be greater 60")
}
b = b[8:]
@@ -242,7 +244,7 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
for i, c := range b[1:] {
if !isDigit(c) {
if i == 0 {
- return t, nil, newDecodeError(b[0:1], "need at least one digit after fraction point")
+ return t, nil, unstable.NewParserError(b[0:1], "need at least one digit after fraction point")
}
break
}
@@ -266,7 +268,7 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) {
}
if precision == 0 {
- return t, nil, newDecodeError(b[:1], "nanoseconds need at least one digit")
+ return t, nil, unstable.NewParserError(b[:1], "nanoseconds need at least one digit")
}
t.Nanosecond = frac * nspow[precision]
@@ -289,24 +291,24 @@ func parseFloat(b []byte) (float64, error) {
}
if cleaned[0] == '.' {
- return 0, newDecodeError(b, "float cannot start with a dot")
+ return 0, unstable.NewParserError(b, "float cannot start with a dot")
}
if cleaned[len(cleaned)-1] == '.' {
- return 0, newDecodeError(b, "float cannot end with a dot")
+ return 0, unstable.NewParserError(b, "float cannot end with a dot")
}
dotAlreadySeen := false
for i, c := range cleaned {
if c == '.' {
if dotAlreadySeen {
- return 0, newDecodeError(b[i:i+1], "float can have at most one decimal point")
+ return 0, unstable.NewParserError(b[i:i+1], "float can have at most one decimal point")
}
if !isDigit(cleaned[i-1]) {
- return 0, newDecodeError(b[i-1:i+1], "float decimal point must be preceded by a digit")
+ return 0, unstable.NewParserError(b[i-1:i+1], "float decimal point must be preceded by a digit")
}
if !isDigit(cleaned[i+1]) {
- return 0, newDecodeError(b[i:i+2], "float decimal point must be followed by a digit")
+ return 0, unstable.NewParserError(b[i:i+2], "float decimal point must be followed by a digit")
}
dotAlreadySeen = true
}
@@ -317,12 +319,12 @@ func parseFloat(b []byte) (float64, error) {
start = 1
}
if cleaned[start] == '0' && isDigit(cleaned[start+1]) {
- return 0, newDecodeError(b, "float integer part cannot have leading zeroes")
+ return 0, unstable.NewParserError(b, "float integer part cannot have leading zeroes")
}
f, err := strconv.ParseFloat(string(cleaned), 64)
if err != nil {
- return 0, newDecodeError(b, "unable to parse float: %w", err)
+ return 0, unstable.NewParserError(b, "unable to parse float: %w", err)
}
return f, nil
@@ -336,7 +338,7 @@ func parseIntHex(b []byte) (int64, error) {
i, err := strconv.ParseInt(string(cleaned), 16, 64)
if err != nil {
- return 0, newDecodeError(b, "couldn't parse hexadecimal number: %w", err)
+ return 0, unstable.NewParserError(b, "couldn't parse hexadecimal number: %w", err)
}
return i, nil
@@ -350,7 +352,7 @@ func parseIntOct(b []byte) (int64, error) {
i, err := strconv.ParseInt(string(cleaned), 8, 64)
if err != nil {
- return 0, newDecodeError(b, "couldn't parse octal number: %w", err)
+ return 0, unstable.NewParserError(b, "couldn't parse octal number: %w", err)
}
return i, nil
@@ -364,7 +366,7 @@ func parseIntBin(b []byte) (int64, error) {
i, err := strconv.ParseInt(string(cleaned), 2, 64)
if err != nil {
- return 0, newDecodeError(b, "couldn't parse binary number: %w", err)
+ return 0, unstable.NewParserError(b, "couldn't parse binary number: %w", err)
}
return i, nil
@@ -387,12 +389,12 @@ func parseIntDec(b []byte) (int64, error) {
}
if len(cleaned) > startIdx+1 && cleaned[startIdx] == '0' {
- return 0, newDecodeError(b, "leading zero not allowed on decimal number")
+ return 0, unstable.NewParserError(b, "leading zero not allowed on decimal number")
}
i, err := strconv.ParseInt(string(cleaned), 10, 64)
if err != nil {
- return 0, newDecodeError(b, "couldn't parse decimal number: %w", err)
+ return 0, unstable.NewParserError(b, "couldn't parse decimal number: %w", err)
}
return i, nil
@@ -409,11 +411,11 @@ func checkAndRemoveUnderscoresIntegers(b []byte) ([]byte, error) {
}
if b[start] == '_' {
- return nil, newDecodeError(b[start:start+1], "number cannot start with underscore")
+ return nil, unstable.NewParserError(b[start:start+1], "number cannot start with underscore")
}
if b[len(b)-1] == '_' {
- return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
+ return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
}
// fast path
@@ -435,7 +437,7 @@ func checkAndRemoveUnderscoresIntegers(b []byte) ([]byte, error) {
c := b[i]
if c == '_' {
if !before {
- return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
+ return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
}
before = false
} else {
@@ -449,11 +451,11 @@ func checkAndRemoveUnderscoresIntegers(b []byte) ([]byte, error) {
func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
if b[0] == '_' {
- return nil, newDecodeError(b[0:1], "number cannot start with underscore")
+ return nil, unstable.NewParserError(b[0:1], "number cannot start with underscore")
}
if b[len(b)-1] == '_' {
- return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
+ return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
}
// fast path
@@ -476,10 +478,10 @@ func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
switch c {
case '_':
if !before {
- return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
+ return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
}
if i < len(b)-1 && (b[i+1] == 'e' || b[i+1] == 'E') {
- return nil, newDecodeError(b[i+1:i+2], "cannot have underscore before exponent")
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore before exponent")
}
before = false
case '+', '-':
@@ -488,15 +490,15 @@ func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
before = false
case 'e', 'E':
if i < len(b)-1 && b[i+1] == '_' {
- return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after exponent")
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after exponent")
}
cleaned = append(cleaned, c)
case '.':
if i < len(b)-1 && b[i+1] == '_' {
- return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after decimal point")
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after decimal point")
}
if i > 0 && b[i-1] == '_' {
- return nil, newDecodeError(b[i-1:i], "cannot have underscore before decimal point")
+ return nil, unstable.NewParserError(b[i-1:i], "cannot have underscore before decimal point")
}
cleaned = append(cleaned, c)
default:
@@ -542,3 +544,7 @@ func daysIn(m int, year int) int {
func isLeap(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
+
+func isDigit(r byte) bool {
+ return r >= '0' && r <= '9'
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/errors.go b/vendor/github.com/pelletier/go-toml/v2/errors.go
index 2e7f0ffd..309733f1 100644
--- a/vendor/github.com/pelletier/go-toml/v2/errors.go
+++ b/vendor/github.com/pelletier/go-toml/v2/errors.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/pelletier/go-toml/v2/internal/danger"
+ "github.com/pelletier/go-toml/v2/unstable"
)
// DecodeError represents an error encountered during the parsing or decoding
@@ -55,25 +56,6 @@ func (s *StrictMissingError) String() string {
type Key []string
-// internal version of DecodeError that is used as the base to create a
-// DecodeError with full context.
-type decodeError struct {
- highlight []byte
- message string
- key Key // optional
-}
-
-func (de *decodeError) Error() string {
- return de.message
-}
-
-func newDecodeError(highlight []byte, format string, args ...interface{}) error {
- return &decodeError{
- highlight: highlight,
- message: fmt.Errorf(format, args...).Error(),
- }
-}
-
// Error returns the error message contained in the DecodeError.
func (e *DecodeError) Error() string {
return "toml: " + e.message
@@ -105,12 +87,12 @@ func (e *DecodeError) Key() Key {
// highlight can be freely deallocated.
//
//nolint:funlen
-func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
- offset := danger.SubsliceOffset(document, de.highlight)
+func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
+ offset := danger.SubsliceOffset(document, de.Highlight)
errMessage := de.Error()
errLine, errColumn := positionAtEnd(document[:offset])
- before, after := linesOfContext(document, de.highlight, offset, 3)
+ before, after := linesOfContext(document, de.Highlight, offset, 3)
var buf strings.Builder
@@ -140,7 +122,7 @@ func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
buf.Write(before[0])
}
- buf.Write(de.highlight)
+ buf.Write(de.Highlight)
if len(after) > 0 {
buf.Write(after[0])
@@ -158,7 +140,7 @@ func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
buf.WriteString(strings.Repeat(" ", len(before[0])))
}
- buf.WriteString(strings.Repeat("~", len(de.highlight)))
+ buf.WriteString(strings.Repeat("~", len(de.Highlight)))
if len(errMessage) > 0 {
buf.WriteString(" ")
@@ -183,7 +165,7 @@ func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
message: errMessage,
line: errLine,
column: errColumn,
- key: de.key,
+ key: de.Key,
human: buf.String(),
}
}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go b/vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go
deleted file mode 100644
index 120f16e5..00000000
--- a/vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package ast
-
-type Reference int
-
-const InvalidReference Reference = -1
-
-func (r Reference) Valid() bool {
- return r != InvalidReference
-}
-
-type Builder struct {
- tree Root
- lastIdx int
-}
-
-func (b *Builder) Tree() *Root {
- return &b.tree
-}
-
-func (b *Builder) NodeAt(ref Reference) *Node {
- return b.tree.at(ref)
-}
-
-func (b *Builder) Reset() {
- b.tree.nodes = b.tree.nodes[:0]
- b.lastIdx = 0
-}
-
-func (b *Builder) Push(n Node) Reference {
- b.lastIdx = len(b.tree.nodes)
- b.tree.nodes = append(b.tree.nodes, n)
- return Reference(b.lastIdx)
-}
-
-func (b *Builder) PushAndChain(n Node) Reference {
- newIdx := len(b.tree.nodes)
- b.tree.nodes = append(b.tree.nodes, n)
- if b.lastIdx >= 0 {
- b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
- }
- b.lastIdx = newIdx
- return Reference(b.lastIdx)
-}
-
-func (b *Builder) AttachChild(parent Reference, child Reference) {
- b.tree.nodes[parent].child = int(child) - int(parent)
-}
-
-func (b *Builder) Chain(from Reference, to Reference) {
- b.tree.nodes[from].next = int(to) - int(from)
-}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go b/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
new file mode 100644
index 00000000..80f698db
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
@@ -0,0 +1,42 @@
+package characters
+
+var invalidAsciiTable = [256]bool{
+ 0x00: true,
+ 0x01: true,
+ 0x02: true,
+ 0x03: true,
+ 0x04: true,
+ 0x05: true,
+ 0x06: true,
+ 0x07: true,
+ 0x08: true,
+ // 0x09 TAB
+ // 0x0A LF
+ 0x0B: true,
+ 0x0C: true,
+ // 0x0D CR
+ 0x0E: true,
+ 0x0F: true,
+ 0x10: true,
+ 0x11: true,
+ 0x12: true,
+ 0x13: true,
+ 0x14: true,
+ 0x15: true,
+ 0x16: true,
+ 0x17: true,
+ 0x18: true,
+ 0x19: true,
+ 0x1A: true,
+ 0x1B: true,
+ 0x1C: true,
+ 0x1D: true,
+ 0x1E: true,
+ 0x1F: true,
+ // 0x20 - 0x7E Printable ASCII characters
+ 0x7F: true,
+}
+
+func InvalidAscii(b byte) bool {
+ return invalidAsciiTable[b]
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/utf8.go b/vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
similarity index 87%
rename from vendor/github.com/pelletier/go-toml/v2/utf8.go
rename to vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
index d47a4f20..db4f45ac 100644
--- a/vendor/github.com/pelletier/go-toml/v2/utf8.go
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
@@ -1,4 +1,4 @@
-package toml
+package characters
import (
"unicode/utf8"
@@ -32,7 +32,7 @@ func (u utf8Err) Zero() bool {
// 0x9 => tab, ok
// 0xA - 0x1F => invalid
// 0x7F => invalid
-func utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
+func Utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
// Fast path. Check for and skip 8 bytes of ASCII characters per iteration.
offset := 0
for len(p) >= 8 {
@@ -48,7 +48,7 @@ func utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
}
for i, b := range p[:8] {
- if invalidAscii(b) {
+ if InvalidAscii(b) {
err.Index = offset + i
err.Size = 1
return
@@ -62,7 +62,7 @@ func utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
for i := 0; i < n; {
pi := p[i]
if pi < utf8.RuneSelf {
- if invalidAscii(pi) {
+ if InvalidAscii(pi) {
err.Index = offset + i
err.Size = 1
return
@@ -106,11 +106,11 @@ func utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
}
// Return the size of the next rune if valid, 0 otherwise.
-func utf8ValidNext(p []byte) int {
+func Utf8ValidNext(p []byte) int {
c := p[0]
if c < utf8.RuneSelf {
- if invalidAscii(c) {
+ if InvalidAscii(c) {
return 0
}
return 1
@@ -140,47 +140,6 @@ func utf8ValidNext(p []byte) int {
return size
}
-var invalidAsciiTable = [256]bool{
- 0x00: true,
- 0x01: true,
- 0x02: true,
- 0x03: true,
- 0x04: true,
- 0x05: true,
- 0x06: true,
- 0x07: true,
- 0x08: true,
- // 0x09 TAB
- // 0x0A LF
- 0x0B: true,
- 0x0C: true,
- // 0x0D CR
- 0x0E: true,
- 0x0F: true,
- 0x10: true,
- 0x11: true,
- 0x12: true,
- 0x13: true,
- 0x14: true,
- 0x15: true,
- 0x16: true,
- 0x17: true,
- 0x18: true,
- 0x19: true,
- 0x1A: true,
- 0x1B: true,
- 0x1C: true,
- 0x1D: true,
- 0x1E: true,
- 0x1F: true,
- // 0x20 - 0x7E Printable ASCII characters
- 0x7F: true,
-}
-
-func invalidAscii(b byte) bool {
- return invalidAsciiTable[b]
-}
-
// acceptRange gives the range of valid values for the second byte in a UTF-8
// sequence.
type acceptRange struct {
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
index 7c148f48..149b17f5 100644
--- a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
@@ -1,8 +1,6 @@
package tracker
-import (
- "github.com/pelletier/go-toml/v2/internal/ast"
-)
+import "github.com/pelletier/go-toml/v2/unstable"
// KeyTracker is a tracker that keeps track of the current Key as the AST is
// walked.
@@ -11,19 +9,19 @@ type KeyTracker struct {
}
// UpdateTable sets the state of the tracker with the AST table node.
-func (t *KeyTracker) UpdateTable(node *ast.Node) {
+func (t *KeyTracker) UpdateTable(node *unstable.Node) {
t.reset()
t.Push(node)
}
// UpdateArrayTable sets the state of the tracker with the AST array table node.
-func (t *KeyTracker) UpdateArrayTable(node *ast.Node) {
+func (t *KeyTracker) UpdateArrayTable(node *unstable.Node) {
t.reset()
t.Push(node)
}
// Push the given key on the stack.
-func (t *KeyTracker) Push(node *ast.Node) {
+func (t *KeyTracker) Push(node *unstable.Node) {
it := node.Key()
for it.Next() {
t.k = append(t.k, string(it.Node().Data))
@@ -31,7 +29,7 @@ func (t *KeyTracker) Push(node *ast.Node) {
}
// Pop key from stack.
-func (t *KeyTracker) Pop(node *ast.Node) {
+func (t *KeyTracker) Pop(node *unstable.Node) {
it := node.Key()
for it.Next() {
t.k = t.k[:len(t.k)-1]
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
index a7ee05ba..40e23f83 100644
--- a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
@@ -5,7 +5,7 @@ import (
"fmt"
"sync"
- "github.com/pelletier/go-toml/v2/internal/ast"
+ "github.com/pelletier/go-toml/v2/unstable"
)
type keyKind uint8
@@ -150,23 +150,23 @@ func (s *SeenTracker) setExplicitFlag(parentIdx int) {
// CheckExpression takes a top-level node and checks that it does not contain
// keys that have been seen in previous calls, and validates that types are
// consistent.
-func (s *SeenTracker) CheckExpression(node *ast.Node) error {
+func (s *SeenTracker) CheckExpression(node *unstable.Node) error {
if s.entries == nil {
s.reset()
}
switch node.Kind {
- case ast.KeyValue:
+ case unstable.KeyValue:
return s.checkKeyValue(node)
- case ast.Table:
+ case unstable.Table:
return s.checkTable(node)
- case ast.ArrayTable:
+ case unstable.ArrayTable:
return s.checkArrayTable(node)
default:
panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
}
}
-func (s *SeenTracker) checkTable(node *ast.Node) error {
+func (s *SeenTracker) checkTable(node *unstable.Node) error {
if s.currentIdx >= 0 {
s.setExplicitFlag(s.currentIdx)
}
@@ -219,7 +219,7 @@ func (s *SeenTracker) checkTable(node *ast.Node) error {
return nil
}
-func (s *SeenTracker) checkArrayTable(node *ast.Node) error {
+func (s *SeenTracker) checkArrayTable(node *unstable.Node) error {
if s.currentIdx >= 0 {
s.setExplicitFlag(s.currentIdx)
}
@@ -267,7 +267,7 @@ func (s *SeenTracker) checkArrayTable(node *ast.Node) error {
return nil
}
-func (s *SeenTracker) checkKeyValue(node *ast.Node) error {
+func (s *SeenTracker) checkKeyValue(node *unstable.Node) error {
parentIdx := s.currentIdx
it := node.Key()
@@ -297,26 +297,26 @@ func (s *SeenTracker) checkKeyValue(node *ast.Node) error {
value := node.Value()
switch value.Kind {
- case ast.InlineTable:
+ case unstable.InlineTable:
return s.checkInlineTable(value)
- case ast.Array:
+ case unstable.Array:
return s.checkArray(value)
}
return nil
}
-func (s *SeenTracker) checkArray(node *ast.Node) error {
+func (s *SeenTracker) checkArray(node *unstable.Node) error {
it := node.Children()
for it.Next() {
n := it.Node()
switch n.Kind {
- case ast.InlineTable:
+ case unstable.InlineTable:
err := s.checkInlineTable(n)
if err != nil {
return err
}
- case ast.Array:
+ case unstable.Array:
err := s.checkArray(n)
if err != nil {
return err
@@ -326,7 +326,7 @@ func (s *SeenTracker) checkArray(node *ast.Node) error {
return nil
}
-func (s *SeenTracker) checkInlineTable(node *ast.Node) error {
+func (s *SeenTracker) checkInlineTable(node *unstable.Node) error {
if pool.New == nil {
pool.New = func() interface{} {
return &SeenTracker{}
diff --git a/vendor/github.com/pelletier/go-toml/v2/localtime.go b/vendor/github.com/pelletier/go-toml/v2/localtime.go
index 30a31dcb..a856bfdb 100644
--- a/vendor/github.com/pelletier/go-toml/v2/localtime.go
+++ b/vendor/github.com/pelletier/go-toml/v2/localtime.go
@@ -4,6 +4,8 @@ import (
"fmt"
"strings"
"time"
+
+ "github.com/pelletier/go-toml/v2/unstable"
)
// LocalDate represents a calendar day in no specific timezone.
@@ -75,7 +77,7 @@ func (d LocalTime) MarshalText() ([]byte, error) {
func (d *LocalTime) UnmarshalText(b []byte) error {
res, left, err := parseLocalTime(b)
if err == nil && len(left) != 0 {
- err = newDecodeError(left, "extra characters")
+ err = unstable.NewParserError(left, "extra characters")
}
if err != nil {
return err
@@ -109,7 +111,7 @@ func (d LocalDateTime) MarshalText() ([]byte, error) {
func (d *LocalDateTime) UnmarshalText(data []byte) error {
res, left, err := parseLocalDateTime(data)
if err == nil && len(left) != 0 {
- err = newDecodeError(left, "extra characters")
+ err = unstable.NewParserError(left, "extra characters")
}
if err != nil {
return err
diff --git a/vendor/github.com/pelletier/go-toml/v2/marshaler.go b/vendor/github.com/pelletier/go-toml/v2/marshaler.go
index acb28831..07aceb90 100644
--- a/vendor/github.com/pelletier/go-toml/v2/marshaler.go
+++ b/vendor/github.com/pelletier/go-toml/v2/marshaler.go
@@ -12,6 +12,8 @@ import (
"strings"
"time"
"unicode"
+
+ "github.com/pelletier/go-toml/v2/internal/characters"
)
// Marshal serializes a Go value as a TOML document.
@@ -437,7 +439,7 @@ func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byt
func needsQuoting(v string) bool {
// TODO: vectorize
for _, b := range []byte(v) {
- if b == '\'' || b == '\r' || b == '\n' || invalidAscii(b) {
+ if b == '\'' || b == '\r' || b == '\n' || characters.InvalidAscii(b) {
return true
}
}
diff --git a/vendor/github.com/pelletier/go-toml/v2/strict.go b/vendor/github.com/pelletier/go-toml/v2/strict.go
index b7830d13..802e7e4d 100644
--- a/vendor/github.com/pelletier/go-toml/v2/strict.go
+++ b/vendor/github.com/pelletier/go-toml/v2/strict.go
@@ -1,9 +1,9 @@
package toml
import (
- "github.com/pelletier/go-toml/v2/internal/ast"
"github.com/pelletier/go-toml/v2/internal/danger"
"github.com/pelletier/go-toml/v2/internal/tracker"
+ "github.com/pelletier/go-toml/v2/unstable"
)
type strict struct {
@@ -12,10 +12,10 @@ type strict struct {
// Tracks the current key being processed.
key tracker.KeyTracker
- missing []decodeError
+ missing []unstable.ParserError
}
-func (s *strict) EnterTable(node *ast.Node) {
+func (s *strict) EnterTable(node *unstable.Node) {
if !s.Enabled {
return
}
@@ -23,7 +23,7 @@ func (s *strict) EnterTable(node *ast.Node) {
s.key.UpdateTable(node)
}
-func (s *strict) EnterArrayTable(node *ast.Node) {
+func (s *strict) EnterArrayTable(node *unstable.Node) {
if !s.Enabled {
return
}
@@ -31,7 +31,7 @@ func (s *strict) EnterArrayTable(node *ast.Node) {
s.key.UpdateArrayTable(node)
}
-func (s *strict) EnterKeyValue(node *ast.Node) {
+func (s *strict) EnterKeyValue(node *unstable.Node) {
if !s.Enabled {
return
}
@@ -39,7 +39,7 @@ func (s *strict) EnterKeyValue(node *ast.Node) {
s.key.Push(node)
}
-func (s *strict) ExitKeyValue(node *ast.Node) {
+func (s *strict) ExitKeyValue(node *unstable.Node) {
if !s.Enabled {
return
}
@@ -47,27 +47,27 @@ func (s *strict) ExitKeyValue(node *ast.Node) {
s.key.Pop(node)
}
-func (s *strict) MissingTable(node *ast.Node) {
+func (s *strict) MissingTable(node *unstable.Node) {
if !s.Enabled {
return
}
- s.missing = append(s.missing, decodeError{
- highlight: keyLocation(node),
- message: "missing table",
- key: s.key.Key(),
+ s.missing = append(s.missing, unstable.ParserError{
+ Highlight: keyLocation(node),
+ Message: "missing table",
+ Key: s.key.Key(),
})
}
-func (s *strict) MissingField(node *ast.Node) {
+func (s *strict) MissingField(node *unstable.Node) {
if !s.Enabled {
return
}
- s.missing = append(s.missing, decodeError{
- highlight: keyLocation(node),
- message: "missing field",
- key: s.key.Key(),
+ s.missing = append(s.missing, unstable.ParserError{
+ Highlight: keyLocation(node),
+ Message: "missing field",
+ Key: s.key.Key(),
})
}
@@ -88,7 +88,7 @@ func (s *strict) Error(doc []byte) error {
return err
}
-func keyLocation(node *ast.Node) []byte {
+func keyLocation(node *unstable.Node) []byte {
k := node.Key()
hasOne := k.Next()
diff --git a/vendor/github.com/pelletier/go-toml/v2/types.go b/vendor/github.com/pelletier/go-toml/v2/types.go
index 630a4546..3c6b8fe5 100644
--- a/vendor/github.com/pelletier/go-toml/v2/types.go
+++ b/vendor/github.com/pelletier/go-toml/v2/types.go
@@ -6,9 +6,9 @@ import (
"time"
)
-var timeType = reflect.TypeOf(time.Time{})
-var textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
-var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
-var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
-var sliceInterfaceType = reflect.TypeOf([]interface{}{})
+var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}(nil))
+var sliceInterfaceType = reflect.TypeOf([]interface{}(nil))
var stringType = reflect.TypeOf("")
diff --git a/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
index d0d7a72d..70f6ec57 100644
--- a/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
+++ b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
@@ -12,16 +12,16 @@ import (
"sync/atomic"
"time"
- "github.com/pelletier/go-toml/v2/internal/ast"
"github.com/pelletier/go-toml/v2/internal/danger"
"github.com/pelletier/go-toml/v2/internal/tracker"
+ "github.com/pelletier/go-toml/v2/unstable"
)
// Unmarshal deserializes a TOML document into a Go value.
//
// It is a shortcut for Decoder.Decode() with the default options.
func Unmarshal(data []byte, v interface{}) error {
- p := parser{}
+ p := unstable.Parser{}
p.Reset(data)
d := decoder{p: &p}
@@ -101,7 +101,7 @@ func (d *Decoder) Decode(v interface{}) error {
return fmt.Errorf("toml: %w", err)
}
- p := parser{}
+ p := unstable.Parser{}
p.Reset(b)
dec := decoder{
p: &p,
@@ -115,7 +115,7 @@ func (d *Decoder) Decode(v interface{}) error {
type decoder struct {
// Which parser instance in use for this decoding session.
- p *parser
+ p *unstable.Parser
// Flag indicating that the current expression is stashed.
// If set to true, calling nextExpr will not actually pull a new expression
@@ -157,7 +157,7 @@ func (d *decoder) typeMismatchError(toml string, target reflect.Type) error {
return fmt.Errorf("toml: cannot decode TOML %s into a Go value of type %s", toml, target)
}
-func (d *decoder) expr() *ast.Node {
+func (d *decoder) expr() *unstable.Node {
return d.p.Expression()
}
@@ -208,12 +208,12 @@ func (d *decoder) FromParser(v interface{}) error {
err := d.fromParser(r)
if err == nil {
- return d.strict.Error(d.p.data)
+ return d.strict.Error(d.p.Data())
}
- var e *decodeError
+ var e *unstable.ParserError
if errors.As(err, &e) {
- return wrapDecodeError(d.p.data, e)
+ return wrapDecodeError(d.p.Data(), e)
}
return err
@@ -234,16 +234,16 @@ func (d *decoder) fromParser(root reflect.Value) error {
Rules for the unmarshal code:
- The stack is used to keep track of which values need to be set where.
-- handle* functions <=> switch on a given ast.Kind.
+- handle* functions <=> switch on a given unstable.Kind.
- unmarshalX* functions need to unmarshal a node of kind X.
- An "object" is either a struct or a map.
*/
-func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
+func (d *decoder) handleRootExpression(expr *unstable.Node, v reflect.Value) error {
var x reflect.Value
var err error
- if !(d.skipUntilTable && expr.Kind == ast.KeyValue) {
+ if !(d.skipUntilTable && expr.Kind == unstable.KeyValue) {
err = d.seen.CheckExpression(expr)
if err != nil {
return err
@@ -251,16 +251,16 @@ func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
}
switch expr.Kind {
- case ast.KeyValue:
+ case unstable.KeyValue:
if d.skipUntilTable {
return nil
}
x, err = d.handleKeyValue(expr, v)
- case ast.Table:
+ case unstable.Table:
d.skipUntilTable = false
d.strict.EnterTable(expr)
x, err = d.handleTable(expr.Key(), v)
- case ast.ArrayTable:
+ case unstable.ArrayTable:
d.skipUntilTable = false
d.strict.EnterArrayTable(expr)
x, err = d.handleArrayTable(expr.Key(), v)
@@ -269,7 +269,7 @@ func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
}
if d.skipUntilTable {
- if expr.Kind == ast.Table || expr.Kind == ast.ArrayTable {
+ if expr.Kind == unstable.Table || expr.Kind == unstable.ArrayTable {
d.strict.MissingTable(expr)
}
} else if err == nil && x.IsValid() {
@@ -279,14 +279,14 @@ func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
return err
}
-func (d *decoder) handleArrayTable(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleArrayTable(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
if key.Next() {
return d.handleArrayTablePart(key, v)
}
return d.handleKeyValues(v)
}
-func (d *decoder) handleArrayTableCollectionLast(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleArrayTableCollectionLast(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
switch v.Kind() {
case reflect.Interface:
elem := v.Elem()
@@ -339,13 +339,13 @@ func (d *decoder) handleArrayTableCollectionLast(key ast.Iterator, v reflect.Val
case reflect.Array:
idx := d.arrayIndex(true, v)
if idx >= v.Len() {
- return v, fmt.Errorf("toml: cannot decode array table into %s at position %d", v.Type(), idx)
+ return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
}
elem := v.Index(idx)
_, err := d.handleArrayTable(key, elem)
return v, err
default:
- return reflect.Value{}, fmt.Errorf("toml: cannot decode array table into a %s", v.Type())
+ return reflect.Value{}, d.typeMismatchError("array table", v.Type())
}
}
@@ -353,7 +353,7 @@ func (d *decoder) handleArrayTableCollectionLast(key ast.Iterator, v reflect.Val
// evaluated like a normal key, but if it returns a collection, it also needs to
// point to the last element of the collection. Unless it is the last part of
// the key, then it needs to create a new element at the end.
-func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleArrayTableCollection(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
if key.IsLast() {
return d.handleArrayTableCollectionLast(key, v)
}
@@ -390,7 +390,7 @@ func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value)
case reflect.Array:
idx := d.arrayIndex(false, v)
if idx >= v.Len() {
- return v, fmt.Errorf("toml: cannot decode array table into %s at position %d", v.Type(), idx)
+ return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
}
elem := v.Index(idx)
_, err := d.handleArrayTable(key, elem)
@@ -400,7 +400,7 @@ func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value)
return d.handleArrayTable(key, v)
}
-func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
+func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
var rv reflect.Value
// First, dispatch over v to make sure it is a valid object.
@@ -518,7 +518,7 @@ func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handle
// HandleArrayTablePart navigates the Go structure v using the key v. It is
// only used for the prefix (non-last) parts of an array-table. When
// encountering a collection, it should go to the last element.
-func (d *decoder) handleArrayTablePart(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleArrayTablePart(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
var makeFn valueMakerFn
if key.IsLast() {
makeFn = makeSliceInterface
@@ -530,10 +530,10 @@ func (d *decoder) handleArrayTablePart(key ast.Iterator, v reflect.Value) (refle
// HandleTable returns a reference when it has checked the next expression but
// cannot handle it.
-func (d *decoder) handleTable(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleTable(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
if v.Kind() == reflect.Slice {
if v.Len() == 0 {
- return reflect.Value{}, newDecodeError(key.Node().Data, "cannot store a table in a slice")
+ return reflect.Value{}, unstable.NewParserError(key.Node().Data, "cannot store a table in a slice")
}
elem := v.Index(v.Len() - 1)
x, err := d.handleTable(key, elem)
@@ -560,7 +560,7 @@ func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
var rv reflect.Value
for d.nextExpr() {
expr := d.expr()
- if expr.Kind != ast.KeyValue {
+ if expr.Kind != unstable.KeyValue {
// Stash the expression so that fromParser can just loop and use
// the right handler.
// We could just recurse ourselves here, but at least this gives a
@@ -587,7 +587,7 @@ func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
}
type (
- handlerFn func(key ast.Iterator, v reflect.Value) (reflect.Value, error)
+ handlerFn func(key unstable.Iterator, v reflect.Value) (reflect.Value, error)
valueMakerFn func() reflect.Value
)
@@ -599,11 +599,11 @@ func makeSliceInterface() reflect.Value {
return reflect.MakeSlice(sliceInterfaceType, 0, 16)
}
-func (d *decoder) handleTablePart(key ast.Iterator, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleTablePart(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
return d.handleKeyPart(key, v, d.handleTable, makeMapStringInterface)
}
-func (d *decoder) tryTextUnmarshaler(node *ast.Node, v reflect.Value) (bool, error) {
+func (d *decoder) tryTextUnmarshaler(node *unstable.Node, v reflect.Value) (bool, error) {
// Special case for time, because we allow to unmarshal to it from
// different kind of AST nodes.
if v.Type() == timeType {
@@ -613,7 +613,7 @@ func (d *decoder) tryTextUnmarshaler(node *ast.Node, v reflect.Value) (bool, err
if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
err := v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
if err != nil {
- return false, newDecodeError(d.p.Raw(node.Raw), "%w", err)
+ return false, unstable.NewParserError(d.p.Raw(node.Raw), "%w", err)
}
return true, nil
@@ -622,7 +622,7 @@ func (d *decoder) tryTextUnmarshaler(node *ast.Node, v reflect.Value) (bool, err
return false, nil
}
-func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
+func (d *decoder) handleValue(value *unstable.Node, v reflect.Value) error {
for v.Kind() == reflect.Ptr {
v = initAndDereferencePointer(v)
}
@@ -633,32 +633,32 @@ func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
}
switch value.Kind {
- case ast.String:
+ case unstable.String:
return d.unmarshalString(value, v)
- case ast.Integer:
+ case unstable.Integer:
return d.unmarshalInteger(value, v)
- case ast.Float:
+ case unstable.Float:
return d.unmarshalFloat(value, v)
- case ast.Bool:
+ case unstable.Bool:
return d.unmarshalBool(value, v)
- case ast.DateTime:
+ case unstable.DateTime:
return d.unmarshalDateTime(value, v)
- case ast.LocalDate:
+ case unstable.LocalDate:
return d.unmarshalLocalDate(value, v)
- case ast.LocalTime:
+ case unstable.LocalTime:
return d.unmarshalLocalTime(value, v)
- case ast.LocalDateTime:
+ case unstable.LocalDateTime:
return d.unmarshalLocalDateTime(value, v)
- case ast.InlineTable:
+ case unstable.InlineTable:
return d.unmarshalInlineTable(value, v)
- case ast.Array:
+ case unstable.Array:
return d.unmarshalArray(value, v)
default:
panic(fmt.Errorf("handleValue not implemented for %s", value.Kind))
}
}
-func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalArray(array *unstable.Node, v reflect.Value) error {
switch v.Kind() {
case reflect.Slice:
if v.IsNil() {
@@ -729,7 +729,7 @@ func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
return nil
}
-func (d *decoder) unmarshalInlineTable(itable *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalInlineTable(itable *unstable.Node, v reflect.Value) error {
// Make sure v is an initialized object.
switch v.Kind() {
case reflect.Map:
@@ -746,7 +746,7 @@ func (d *decoder) unmarshalInlineTable(itable *ast.Node, v reflect.Value) error
}
return d.unmarshalInlineTable(itable, elem)
default:
- return newDecodeError(itable.Data, "cannot store inline table in Go type %s", v.Kind())
+ return unstable.NewParserError(itable.Data, "cannot store inline table in Go type %s", v.Kind())
}
it := itable.Children()
@@ -765,7 +765,7 @@ func (d *decoder) unmarshalInlineTable(itable *ast.Node, v reflect.Value) error
return nil
}
-func (d *decoder) unmarshalDateTime(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalDateTime(value *unstable.Node, v reflect.Value) error {
dt, err := parseDateTime(value.Data)
if err != nil {
return err
@@ -775,7 +775,7 @@ func (d *decoder) unmarshalDateTime(value *ast.Node, v reflect.Value) error {
return nil
}
-func (d *decoder) unmarshalLocalDate(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalLocalDate(value *unstable.Node, v reflect.Value) error {
ld, err := parseLocalDate(value.Data)
if err != nil {
return err
@@ -792,28 +792,28 @@ func (d *decoder) unmarshalLocalDate(value *ast.Node, v reflect.Value) error {
return nil
}
-func (d *decoder) unmarshalLocalTime(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalLocalTime(value *unstable.Node, v reflect.Value) error {
lt, rest, err := parseLocalTime(value.Data)
if err != nil {
return err
}
if len(rest) > 0 {
- return newDecodeError(rest, "extra characters at the end of a local time")
+ return unstable.NewParserError(rest, "extra characters at the end of a local time")
}
v.Set(reflect.ValueOf(lt))
return nil
}
-func (d *decoder) unmarshalLocalDateTime(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalLocalDateTime(value *unstable.Node, v reflect.Value) error {
ldt, rest, err := parseLocalDateTime(value.Data)
if err != nil {
return err
}
if len(rest) > 0 {
- return newDecodeError(rest, "extra characters at the end of a local date time")
+ return unstable.NewParserError(rest, "extra characters at the end of a local date time")
}
if v.Type() == timeType {
@@ -828,7 +828,7 @@ func (d *decoder) unmarshalLocalDateTime(value *ast.Node, v reflect.Value) error
return nil
}
-func (d *decoder) unmarshalBool(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalBool(value *unstable.Node, v reflect.Value) error {
b := value.Data[0] == 't'
switch v.Kind() {
@@ -837,13 +837,13 @@ func (d *decoder) unmarshalBool(value *ast.Node, v reflect.Value) error {
case reflect.Interface:
v.Set(reflect.ValueOf(b))
default:
- return newDecodeError(value.Data, "cannot assign boolean to a %t", b)
+ return unstable.NewParserError(value.Data, "cannot assign boolean to a %t", b)
}
return nil
}
-func (d *decoder) unmarshalFloat(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalFloat(value *unstable.Node, v reflect.Value) error {
f, err := parseFloat(value.Data)
if err != nil {
return err
@@ -854,13 +854,13 @@ func (d *decoder) unmarshalFloat(value *ast.Node, v reflect.Value) error {
v.SetFloat(f)
case reflect.Float32:
if f > math.MaxFloat32 {
- return newDecodeError(value.Data, "number %f does not fit in a float32", f)
+ return unstable.NewParserError(value.Data, "number %f does not fit in a float32", f)
}
v.SetFloat(f)
case reflect.Interface:
v.Set(reflect.ValueOf(f))
default:
- return newDecodeError(value.Data, "float cannot be assigned to %s", v.Kind())
+ return unstable.NewParserError(value.Data, "float cannot be assigned to %s", v.Kind())
}
return nil
@@ -886,7 +886,7 @@ func init() {
}
}
-func (d *decoder) unmarshalInteger(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error {
i, err := parseInteger(value.Data)
if err != nil {
return err
@@ -967,20 +967,20 @@ func (d *decoder) unmarshalInteger(value *ast.Node, v reflect.Value) error {
return nil
}
-func (d *decoder) unmarshalString(value *ast.Node, v reflect.Value) error {
+func (d *decoder) unmarshalString(value *unstable.Node, v reflect.Value) error {
switch v.Kind() {
case reflect.String:
v.SetString(string(value.Data))
case reflect.Interface:
v.Set(reflect.ValueOf(string(value.Data)))
default:
- return newDecodeError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
+ return unstable.NewParserError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
}
return nil
}
-func (d *decoder) handleKeyValue(expr *ast.Node, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleKeyValue(expr *unstable.Node, v reflect.Value) (reflect.Value, error) {
d.strict.EnterKeyValue(expr)
v, err := d.handleKeyValueInner(expr.Key(), expr.Value(), v)
@@ -994,7 +994,7 @@ func (d *decoder) handleKeyValue(expr *ast.Node, v reflect.Value) (reflect.Value
return v, err
}
-func (d *decoder) handleKeyValueInner(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleKeyValueInner(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) {
if key.Next() {
// Still scoping the key
return d.handleKeyValuePart(key, value, v)
@@ -1004,7 +1004,7 @@ func (d *decoder) handleKeyValueInner(key ast.Iterator, value *ast.Node, v refle
return reflect.Value{}, d.handleValue(value, v)
}
-func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
+func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) {
// contains the replacement for v
var rv reflect.Value
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
similarity index 60%
rename from vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go
rename to vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
index 9dec2e00..b60d9bfd 100644
--- a/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
@@ -1,4 +1,4 @@
-package ast
+package unstable
import (
"fmt"
@@ -7,13 +7,16 @@ import (
"github.com/pelletier/go-toml/v2/internal/danger"
)
-// Iterator starts uninitialized, you need to call Next() first.
+// Iterator over a sequence of nodes.
+//
+// Starts uninitialized, you need to call Next() first.
//
// For example:
//
// it := n.Children()
// for it.Next() {
-// it.Node()
+// n := it.Node()
+// // do something with n
// }
type Iterator struct {
started bool
@@ -32,42 +35,31 @@ func (c *Iterator) Next() bool {
}
// IsLast returns true if the current node of the iterator is the last
-// one. Subsequent call to Next() will return false.
+// one. Subsequent calls to Next() will return false.
func (c *Iterator) IsLast() bool {
return c.node.next == 0
}
-// Node returns a copy of the node pointed at by the iterator.
+// Node returns a pointer to the node pointed at by the iterator.
func (c *Iterator) Node() *Node {
return c.node
}
-// Root contains a full AST.
+// Node in a TOML expression AST.
//
-// It is immutable once constructed with Builder.
-type Root struct {
- nodes []Node
-}
-
-// Iterator over the top level nodes.
-func (r *Root) Iterator() Iterator {
- it := Iterator{}
- if len(r.nodes) > 0 {
- it.node = &r.nodes[0]
- }
- return it
-}
-
-func (r *Root) at(idx Reference) *Node {
- return &r.nodes[idx]
-}
-
-// Arrays have one child per element in the array. InlineTables have
-// one child per key-value pair in the table. KeyValues have at least
-// two children. The first one is the value. The rest make a
-// potentially dotted key. Table and Array table have one child per
-// element of the key they represent (same as KeyValue, but without
-// the last node being the value).
+// Depending on Kind, its sequence of children should be interpreted
+// differently.
+//
+// - Array have one child per element in the array.
+// - InlineTable have one child per key-value in the table (each of kind
+// InlineTable).
+// - KeyValue have at least two children. The first one is the value. The rest
+// make a potentially dotted key.
+// - Table and ArrayTable's children represent a dotted key (same as
+// KeyValue, but without the first node being the value).
+//
+// When relevant, Raw describes the range of bytes this node is refering to in
+// the input document. Use Parser.Raw() to retrieve the actual bytes.
type Node struct {
Kind Kind
Raw Range // Raw bytes from the input.
@@ -80,13 +72,13 @@ type Node struct {
child int // 0 if no child
}
+// Range of bytes in the document.
type Range struct {
Offset uint32
Length uint32
}
-// Next returns a copy of the next node, or an invalid Node if there
-// is no next node.
+// Next returns a pointer to the next node, or nil if there is no next node.
func (n *Node) Next() *Node {
if n.next == 0 {
return nil
@@ -96,9 +88,9 @@ func (n *Node) Next() *Node {
return (*Node)(danger.Stride(ptr, size, n.next))
}
-// Child returns a copy of the first child node of this node. Other
-// children can be accessed calling Next on the first child. Returns
-// an invalid Node if there is none.
+// Child returns a pointer to the first child node of this node. Other children
+// can be accessed calling Next on the first child. Returns an nil if this Node
+// has no child.
func (n *Node) Child() *Node {
if n.child == 0 {
return nil
@@ -113,9 +105,9 @@ func (n *Node) Valid() bool {
return n != nil
}
-// Key returns the child nodes making the Key on a supported
-// node. Panics otherwise. They are guaranteed to be all be of the
-// Kind Key. A simple key would return just one element.
+// Key returns the children nodes making the Key on a supported node. Panics
+// otherwise. They are guaranteed to be all be of the Kind Key. A simple key
+// would return just one element.
func (n *Node) Key() Iterator {
switch n.Kind {
case KeyValue:
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go b/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
new file mode 100644
index 00000000..9538e30d
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
@@ -0,0 +1,71 @@
+package unstable
+
+// root contains a full AST.
+//
+// It is immutable once constructed with Builder.
+type root struct {
+ nodes []Node
+}
+
+// Iterator over the top level nodes.
+func (r *root) Iterator() Iterator {
+ it := Iterator{}
+ if len(r.nodes) > 0 {
+ it.node = &r.nodes[0]
+ }
+ return it
+}
+
+func (r *root) at(idx reference) *Node {
+ return &r.nodes[idx]
+}
+
+type reference int
+
+const invalidReference reference = -1
+
+func (r reference) Valid() bool {
+ return r != invalidReference
+}
+
+type builder struct {
+ tree root
+ lastIdx int
+}
+
+func (b *builder) Tree() *root {
+ return &b.tree
+}
+
+func (b *builder) NodeAt(ref reference) *Node {
+ return b.tree.at(ref)
+}
+
+func (b *builder) Reset() {
+ b.tree.nodes = b.tree.nodes[:0]
+ b.lastIdx = 0
+}
+
+func (b *builder) Push(n Node) reference {
+ b.lastIdx = len(b.tree.nodes)
+ b.tree.nodes = append(b.tree.nodes, n)
+ return reference(b.lastIdx)
+}
+
+func (b *builder) PushAndChain(n Node) reference {
+ newIdx := len(b.tree.nodes)
+ b.tree.nodes = append(b.tree.nodes, n)
+ if b.lastIdx >= 0 {
+ b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
+ }
+ b.lastIdx = newIdx
+ return reference(b.lastIdx)
+}
+
+func (b *builder) AttachChild(parent reference, child reference) {
+ b.tree.nodes[parent].child = int(child) - int(parent)
+}
+
+func (b *builder) Chain(from reference, to reference) {
+ b.tree.nodes[from].next = int(to) - int(from)
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go b/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go
new file mode 100644
index 00000000..7ff26c53
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go
@@ -0,0 +1,3 @@
+// Package unstable provides APIs that do not meet the backward compatibility
+// guarantees yet.
+package unstable
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go b/vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
similarity index 81%
rename from vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go
rename to vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
index 2b50c67f..ff9df1be 100644
--- a/vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
@@ -1,25 +1,26 @@
-package ast
+package unstable
import "fmt"
+// Kind represents the type of TOML structure contained in a given Node.
type Kind int
const (
- // meta
+ // Meta
Invalid Kind = iota
Comment
Key
- // top level structures
+ // Top level structures
Table
ArrayTable
KeyValue
- // containers values
+ // Containers values
Array
InlineTable
- // values
+ // Values
String
Bool
Float
@@ -30,6 +31,7 @@ const (
DateTime
)
+// String implementation of fmt.Stringer.
func (k Kind) String() string {
switch k {
case Invalid:
diff --git a/vendor/github.com/pelletier/go-toml/v2/parser.go b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
similarity index 70%
rename from vendor/github.com/pelletier/go-toml/v2/parser.go
rename to vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
index 9859a795..52db88e7 100644
--- a/vendor/github.com/pelletier/go-toml/v2/parser.go
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
@@ -1,50 +1,108 @@
-package toml
+package unstable
import (
"bytes"
+ "fmt"
"unicode"
- "github.com/pelletier/go-toml/v2/internal/ast"
+ "github.com/pelletier/go-toml/v2/internal/characters"
"github.com/pelletier/go-toml/v2/internal/danger"
)
-type parser struct {
- builder ast.Builder
- ref ast.Reference
+// ParserError describes an error relative to the content of the document.
+//
+// It cannot outlive the instance of Parser it refers to, and may cause panics
+// if the parser is reset.
+type ParserError struct {
+ Highlight []byte
+ Message string
+ Key []string // optional
+}
+
+// Error is the implementation of the error interface.
+func (e *ParserError) Error() string {
+ return e.Message
+}
+
+// NewParserError is a convenience function to create a ParserError
+//
+// Warning: Highlight needs to be a subslice of Parser.data, so only slices
+// returned by Parser.Raw are valid candidates.
+func NewParserError(highlight []byte, format string, args ...interface{}) error {
+ return &ParserError{
+ Highlight: highlight,
+ Message: fmt.Errorf(format, args...).Error(),
+ }
+}
+
+// Parser scans over a TOML-encoded document and generates an iterative AST.
+//
+// To prime the Parser, first reset it with the contents of a TOML document.
+// Then, process all top-level expressions sequentially. See Example.
+//
+// Don't forget to check Error() after you're done parsing.
+//
+// Each top-level expression needs to be fully processed before calling
+// NextExpression() again. Otherwise, calls to various Node methods may panic if
+// the parser has moved on the next expression.
+//
+// For performance reasons, go-toml doesn't make a copy of the input bytes to
+// the parser. Make sure to copy all the bytes you need to outlive the slice
+// given to the parser.
+//
+// The parser doesn't provide nodes for comments yet, nor for whitespace.
+type Parser struct {
data []byte
+ builder builder
+ ref reference
left []byte
err error
first bool
}
-func (p *parser) Range(b []byte) ast.Range {
- return ast.Range{
+// Data returns the slice provided to the last call to Reset.
+func (p *Parser) Data() []byte {
+ return p.data
+}
+
+// Range returns a range description that corresponds to a given slice of the
+// input. If the argument is not a subslice of the parser input, this function
+// panics.
+func (p *Parser) Range(b []byte) Range {
+ return Range{
Offset: uint32(danger.SubsliceOffset(p.data, b)),
Length: uint32(len(b)),
}
}
-func (p *parser) Raw(raw ast.Range) []byte {
+// Raw returns the slice corresponding to the bytes in the given range.
+func (p *Parser) Raw(raw Range) []byte {
return p.data[raw.Offset : raw.Offset+raw.Length]
}
-func (p *parser) Reset(b []byte) {
+// Reset brings the parser to its initial state for a given input. It wipes an
+// reuses internal storage to reduce allocation.
+func (p *Parser) Reset(b []byte) {
p.builder.Reset()
- p.ref = ast.InvalidReference
+ p.ref = invalidReference
p.data = b
p.left = b
p.err = nil
p.first = true
}
-//nolint:cyclop
-func (p *parser) NextExpression() bool {
+// NextExpression parses the next top-level expression. If an expression was
+// successfully parsed, it returns true. If the parser is at the end of the
+// document or an error occurred, it returns false.
+//
+// Retrieve the parsed expression with Expression().
+func (p *Parser) NextExpression() bool {
if len(p.left) == 0 || p.err != nil {
return false
}
p.builder.Reset()
- p.ref = ast.InvalidReference
+ p.ref = invalidReference
for {
if len(p.left) == 0 || p.err != nil {
@@ -73,15 +131,18 @@ func (p *parser) NextExpression() bool {
}
}
-func (p *parser) Expression() *ast.Node {
+// Expression returns a pointer to the node representing the last successfully
+// parsed expresion.
+func (p *Parser) Expression() *Node {
return p.builder.NodeAt(p.ref)
}
-func (p *parser) Error() error {
+// Error returns any error that has occured during parsing.
+func (p *Parser) Error() error {
return p.err
}
-func (p *parser) parseNewline(b []byte) ([]byte, error) {
+func (p *Parser) parseNewline(b []byte) ([]byte, error) {
if b[0] == '\n' {
return b[1:], nil
}
@@ -91,14 +152,14 @@ func (p *parser) parseNewline(b []byte) ([]byte, error) {
return rest, err
}
- return nil, newDecodeError(b[0:1], "expected newline but got %#U", b[0])
+ return nil, NewParserError(b[0:1], "expected newline but got %#U", b[0])
}
-func (p *parser) parseExpression(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseExpression(b []byte) (reference, []byte, error) {
// expression = ws [ comment ]
// expression =/ ws keyval ws [ comment ]
// expression =/ ws table ws [ comment ]
- ref := ast.InvalidReference
+ ref := invalidReference
b = p.parseWhitespace(b)
@@ -136,7 +197,7 @@ func (p *parser) parseExpression(b []byte) (ast.Reference, []byte, error) {
return ref, b, nil
}
-func (p *parser) parseTable(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseTable(b []byte) (reference, []byte, error) {
// table = std-table / array-table
if len(b) > 1 && b[1] == '[' {
return p.parseArrayTable(b)
@@ -145,12 +206,12 @@ func (p *parser) parseTable(b []byte) (ast.Reference, []byte, error) {
return p.parseStdTable(b)
}
-func (p *parser) parseArrayTable(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseArrayTable(b []byte) (reference, []byte, error) {
// array-table = array-table-open key array-table-close
// array-table-open = %x5B.5B ws ; [[ Double left square bracket
// array-table-close = ws %x5D.5D ; ]] Double right square bracket
- ref := p.builder.Push(ast.Node{
- Kind: ast.ArrayTable,
+ ref := p.builder.Push(Node{
+ Kind: ArrayTable,
})
b = b[2:]
@@ -174,12 +235,12 @@ func (p *parser) parseArrayTable(b []byte) (ast.Reference, []byte, error) {
return ref, b, err
}
-func (p *parser) parseStdTable(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseStdTable(b []byte) (reference, []byte, error) {
// std-table = std-table-open key std-table-close
// std-table-open = %x5B ws ; [ Left square bracket
// std-table-close = ws %x5D ; ] Right square bracket
- ref := p.builder.Push(ast.Node{
- Kind: ast.Table,
+ ref := p.builder.Push(Node{
+ Kind: Table,
})
b = b[1:]
@@ -199,15 +260,15 @@ func (p *parser) parseStdTable(b []byte) (ast.Reference, []byte, error) {
return ref, b, err
}
-func (p *parser) parseKeyval(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
// keyval = key keyval-sep val
- ref := p.builder.Push(ast.Node{
- Kind: ast.KeyValue,
+ ref := p.builder.Push(Node{
+ Kind: KeyValue,
})
key, b, err := p.parseKey(b)
if err != nil {
- return ast.InvalidReference, nil, err
+ return invalidReference, nil, err
}
// keyval-sep = ws %x3D ws ; =
@@ -215,12 +276,12 @@ func (p *parser) parseKeyval(b []byte) (ast.Reference, []byte, error) {
b = p.parseWhitespace(b)
if len(b) == 0 {
- return ast.InvalidReference, nil, newDecodeError(b, "expected = after a key, but the document ends there")
+ return invalidReference, nil, NewParserError(b, "expected = after a key, but the document ends there")
}
b, err = expect('=', b)
if err != nil {
- return ast.InvalidReference, nil, err
+ return invalidReference, nil, err
}
b = p.parseWhitespace(b)
@@ -237,12 +298,12 @@ func (p *parser) parseKeyval(b []byte) (ast.Reference, []byte, error) {
}
//nolint:cyclop,funlen
-func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseVal(b []byte) (reference, []byte, error) {
// val = string / boolean / array / inline-table / date-time / float / integer
- ref := ast.InvalidReference
+ ref := invalidReference
if len(b) == 0 {
- return ref, nil, newDecodeError(b, "expected value, not eof")
+ return ref, nil, NewParserError(b, "expected value, not eof")
}
var err error
@@ -259,8 +320,8 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
}
if err == nil {
- ref = p.builder.Push(ast.Node{
- Kind: ast.String,
+ ref = p.builder.Push(Node{
+ Kind: String,
Raw: p.Range(raw),
Data: v,
})
@@ -277,8 +338,8 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
}
if err == nil {
- ref = p.builder.Push(ast.Node{
- Kind: ast.String,
+ ref = p.builder.Push(Node{
+ Kind: String,
Raw: p.Range(raw),
Data: v,
})
@@ -287,22 +348,22 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
return ref, b, err
case 't':
if !scanFollowsTrue(b) {
- return ref, nil, newDecodeError(atmost(b, 4), "expected 'true'")
+ return ref, nil, NewParserError(atmost(b, 4), "expected 'true'")
}
- ref = p.builder.Push(ast.Node{
- Kind: ast.Bool,
+ ref = p.builder.Push(Node{
+ Kind: Bool,
Data: b[:4],
})
return ref, b[4:], nil
case 'f':
if !scanFollowsFalse(b) {
- return ref, nil, newDecodeError(atmost(b, 5), "expected 'false'")
+ return ref, nil, NewParserError(atmost(b, 5), "expected 'false'")
}
- ref = p.builder.Push(ast.Node{
- Kind: ast.Bool,
+ ref = p.builder.Push(Node{
+ Kind: Bool,
Data: b[:5],
})
@@ -324,7 +385,7 @@ func atmost(b []byte, n int) []byte {
return b[:n]
}
-func (p *parser) parseLiteralString(b []byte) ([]byte, []byte, []byte, error) {
+func (p *Parser) parseLiteralString(b []byte) ([]byte, []byte, []byte, error) {
v, rest, err := scanLiteralString(b)
if err != nil {
return nil, nil, nil, err
@@ -333,19 +394,19 @@ func (p *parser) parseLiteralString(b []byte) ([]byte, []byte, []byte, error) {
return v, v[1 : len(v)-1], rest, nil
}
-func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseInlineTable(b []byte) (reference, []byte, error) {
// inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
// inline-table-open = %x7B ws ; {
// inline-table-close = ws %x7D ; }
// inline-table-sep = ws %x2C ws ; , Comma
// inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
- parent := p.builder.Push(ast.Node{
- Kind: ast.InlineTable,
+ parent := p.builder.Push(Node{
+ Kind: InlineTable,
})
first := true
- var child ast.Reference
+ var child reference
b = b[1:]
@@ -356,7 +417,7 @@ func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
b = p.parseWhitespace(b)
if len(b) == 0 {
- return parent, nil, newDecodeError(previousB[:1], "inline table is incomplete")
+ return parent, nil, NewParserError(previousB[:1], "inline table is incomplete")
}
if b[0] == '}' {
@@ -371,7 +432,7 @@ func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
b = p.parseWhitespace(b)
}
- var kv ast.Reference
+ var kv reference
kv, b, err = p.parseKeyval(b)
if err != nil {
@@ -394,7 +455,7 @@ func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
}
//nolint:funlen,cyclop
-func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseValArray(b []byte) (reference, []byte, error) {
// array = array-open [ array-values ] ws-comment-newline array-close
// array-open = %x5B ; [
// array-close = %x5D ; ]
@@ -405,13 +466,13 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
arrayStart := b
b = b[1:]
- parent := p.builder.Push(ast.Node{
- Kind: ast.Array,
+ parent := p.builder.Push(Node{
+ Kind: Array,
})
first := true
- var lastChild ast.Reference
+ var lastChild reference
var err error
for len(b) > 0 {
@@ -421,7 +482,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
}
if len(b) == 0 {
- return parent, nil, newDecodeError(arrayStart[:1], "array is incomplete")
+ return parent, nil, NewParserError(arrayStart[:1], "array is incomplete")
}
if b[0] == ']' {
@@ -430,7 +491,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
if b[0] == ',' {
if first {
- return parent, nil, newDecodeError(b[0:1], "array cannot start with comma")
+ return parent, nil, NewParserError(b[0:1], "array cannot start with comma")
}
b = b[1:]
@@ -439,7 +500,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
return parent, nil, err
}
} else if !first {
- return parent, nil, newDecodeError(b[0:1], "array elements must be separated by commas")
+ return parent, nil, NewParserError(b[0:1], "array elements must be separated by commas")
}
// TOML allows trailing commas in arrays.
@@ -447,7 +508,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
break
}
- var valueRef ast.Reference
+ var valueRef reference
valueRef, b, err = p.parseVal(b)
if err != nil {
return parent, nil, err
@@ -472,7 +533,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
return parent, rest, err
}
-func (p *parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error) {
+func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error) {
for len(b) > 0 {
var err error
b = p.parseWhitespace(b)
@@ -501,7 +562,7 @@ func (p *parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error)
return b, nil
}
-func (p *parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, []byte, error) {
+func (p *Parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, []byte, error) {
token, rest, err := scanMultilineLiteralString(b)
if err != nil {
return nil, nil, nil, err
@@ -520,7 +581,7 @@ func (p *parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, []byte,
}
//nolint:funlen,gocognit,cyclop
-func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, error) {
+func (p *Parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, error) {
// ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
// ml-basic-string-delim
// ml-basic-string-delim = 3quotation-mark
@@ -551,11 +612,11 @@ func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, er
if !escaped {
str := token[startIdx:endIdx]
- verr := utf8TomlValidAlreadyEscaped(str)
+ verr := characters.Utf8TomlValidAlreadyEscaped(str)
if verr.Zero() {
return token, str, rest, nil
}
- return nil, nil, nil, newDecodeError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
+ return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
}
var builder bytes.Buffer
@@ -635,13 +696,13 @@ func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, er
builder.WriteRune(x)
i += 8
default:
- return nil, nil, nil, newDecodeError(token[i:i+1], "invalid escaped character %#U", c)
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid escaped character %#U", c)
}
i++
} else {
- size := utf8ValidNext(token[i:])
+ size := characters.Utf8ValidNext(token[i:])
if size == 0 {
- return nil, nil, nil, newDecodeError(token[i:i+1], "invalid character %#U", c)
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid character %#U", c)
}
builder.Write(token[i : i+size])
i += size
@@ -651,7 +712,7 @@ func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, er
return token, builder.Bytes(), rest, nil
}
-func (p *parser) parseKey(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseKey(b []byte) (reference, []byte, error) {
// key = simple-key / dotted-key
// simple-key = quoted-key / unquoted-key
//
@@ -662,11 +723,11 @@ func (p *parser) parseKey(b []byte) (ast.Reference, []byte, error) {
// dot-sep = ws %x2E ws ; . Period
raw, key, b, err := p.parseSimpleKey(b)
if err != nil {
- return ast.InvalidReference, nil, err
+ return invalidReference, nil, err
}
- ref := p.builder.Push(ast.Node{
- Kind: ast.Key,
+ ref := p.builder.Push(Node{
+ Kind: Key,
Raw: p.Range(raw),
Data: key,
})
@@ -681,8 +742,8 @@ func (p *parser) parseKey(b []byte) (ast.Reference, []byte, error) {
return ref, nil, err
}
- p.builder.PushAndChain(ast.Node{
- Kind: ast.Key,
+ p.builder.PushAndChain(Node{
+ Kind: Key,
Raw: p.Range(raw),
Data: key,
})
@@ -694,9 +755,9 @@ func (p *parser) parseKey(b []byte) (ast.Reference, []byte, error) {
return ref, b, nil
}
-func (p *parser) parseSimpleKey(b []byte) (raw, key, rest []byte, err error) {
+func (p *Parser) parseSimpleKey(b []byte) (raw, key, rest []byte, err error) {
if len(b) == 0 {
- return nil, nil, nil, newDecodeError(b, "expected key but found none")
+ return nil, nil, nil, NewParserError(b, "expected key but found none")
}
// simple-key = quoted-key / unquoted-key
@@ -711,12 +772,12 @@ func (p *parser) parseSimpleKey(b []byte) (raw, key, rest []byte, err error) {
key, rest = scanUnquotedKey(b)
return key, key, rest, nil
default:
- return nil, nil, nil, newDecodeError(b[0:1], "invalid character at start of key: %c", b[0])
+ return nil, nil, nil, NewParserError(b[0:1], "invalid character at start of key: %c", b[0])
}
}
//nolint:funlen,cyclop
-func (p *parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
+func (p *Parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
// basic-string = quotation-mark *basic-char quotation-mark
// quotation-mark = %x22 ; "
// basic-char = basic-unescaped / escaped
@@ -744,11 +805,11 @@ func (p *parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
// validate the string and return a direct reference to the buffer.
if !escaped {
str := token[startIdx:endIdx]
- verr := utf8TomlValidAlreadyEscaped(str)
+ verr := characters.Utf8TomlValidAlreadyEscaped(str)
if verr.Zero() {
return token, str, rest, nil
}
- return nil, nil, nil, newDecodeError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
+ return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
}
i := startIdx
@@ -795,13 +856,13 @@ func (p *parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
builder.WriteRune(x)
i += 8
default:
- return nil, nil, nil, newDecodeError(token[i:i+1], "invalid escaped character %#U", c)
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid escaped character %#U", c)
}
i++
} else {
- size := utf8ValidNext(token[i:])
+ size := characters.Utf8ValidNext(token[i:])
if size == 0 {
- return nil, nil, nil, newDecodeError(token[i:i+1], "invalid character %#U", c)
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid character %#U", c)
}
builder.Write(token[i : i+size])
i += size
@@ -813,7 +874,7 @@ func (p *parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
func hexToRune(b []byte, length int) (rune, error) {
if len(b) < length {
- return -1, newDecodeError(b, "unicode point needs %d character, not %d", length, len(b))
+ return -1, NewParserError(b, "unicode point needs %d character, not %d", length, len(b))
}
b = b[:length]
@@ -828,19 +889,19 @@ func hexToRune(b []byte, length int) (rune, error) {
case 'A' <= c && c <= 'F':
d = uint32(c - 'A' + 10)
default:
- return -1, newDecodeError(b[i:i+1], "non-hex character")
+ return -1, NewParserError(b[i:i+1], "non-hex character")
}
r = r*16 + d
}
if r > unicode.MaxRune || 0xD800 <= r && r < 0xE000 {
- return -1, newDecodeError(b, "escape sequence is invalid Unicode code point")
+ return -1, NewParserError(b, "escape sequence is invalid Unicode code point")
}
return rune(r), nil
}
-func (p *parser) parseWhitespace(b []byte) []byte {
+func (p *Parser) parseWhitespace(b []byte) []byte {
// ws = *wschar
// wschar = %x20 ; Space
// wschar =/ %x09 ; Horizontal tab
@@ -850,24 +911,24 @@ func (p *parser) parseWhitespace(b []byte) []byte {
}
//nolint:cyclop
-func (p *parser) parseIntOrFloatOrDateTime(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) parseIntOrFloatOrDateTime(b []byte) (reference, []byte, error) {
switch b[0] {
case 'i':
if !scanFollowsInf(b) {
- return ast.InvalidReference, nil, newDecodeError(atmost(b, 3), "expected 'inf'")
+ return invalidReference, nil, NewParserError(atmost(b, 3), "expected 'inf'")
}
- return p.builder.Push(ast.Node{
- Kind: ast.Float,
+ return p.builder.Push(Node{
+ Kind: Float,
Data: b[:3],
}), b[3:], nil
case 'n':
if !scanFollowsNan(b) {
- return ast.InvalidReference, nil, newDecodeError(atmost(b, 3), "expected 'nan'")
+ return invalidReference, nil, NewParserError(atmost(b, 3), "expected 'nan'")
}
- return p.builder.Push(ast.Node{
- Kind: ast.Float,
+ return p.builder.Push(Node{
+ Kind: Float,
Data: b[:3],
}), b[3:], nil
case '+', '-':
@@ -898,7 +959,7 @@ func (p *parser) parseIntOrFloatOrDateTime(b []byte) (ast.Reference, []byte, err
return p.scanIntOrFloat(b)
}
-func (p *parser) scanDateTime(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) scanDateTime(b []byte) (reference, []byte, error) {
// scans for contiguous characters in [0-9T:Z.+-], and up to one space if
// followed by a digit.
hasDate := false
@@ -941,30 +1002,30 @@ byteLoop:
}
}
- var kind ast.Kind
+ var kind Kind
if hasTime {
if hasDate {
if hasTz {
- kind = ast.DateTime
+ kind = DateTime
} else {
- kind = ast.LocalDateTime
+ kind = LocalDateTime
}
} else {
- kind = ast.LocalTime
+ kind = LocalTime
}
} else {
- kind = ast.LocalDate
+ kind = LocalDate
}
- return p.builder.Push(ast.Node{
+ return p.builder.Push(Node{
Kind: kind,
Data: b[:i],
}), b[i:], nil
}
//nolint:funlen,gocognit,cyclop
-func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
+func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
i := 0
if len(b) > 2 && b[0] == '0' && b[1] != '.' && b[1] != 'e' && b[1] != 'E' {
@@ -990,8 +1051,8 @@ func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
}
}
- return p.builder.Push(ast.Node{
- Kind: ast.Integer,
+ return p.builder.Push(Node{
+ Kind: Integer,
Data: b[:i],
}), b[i:], nil
}
@@ -1013,40 +1074,40 @@ func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
if c == 'i' {
if scanFollowsInf(b[i:]) {
- return p.builder.Push(ast.Node{
- Kind: ast.Float,
+ return p.builder.Push(Node{
+ Kind: Float,
Data: b[:i+3],
}), b[i+3:], nil
}
- return ast.InvalidReference, nil, newDecodeError(b[i:i+1], "unexpected character 'i' while scanning for a number")
+ return invalidReference, nil, NewParserError(b[i:i+1], "unexpected character 'i' while scanning for a number")
}
if c == 'n' {
if scanFollowsNan(b[i:]) {
- return p.builder.Push(ast.Node{
- Kind: ast.Float,
+ return p.builder.Push(Node{
+ Kind: Float,
Data: b[:i+3],
}), b[i+3:], nil
}
- return ast.InvalidReference, nil, newDecodeError(b[i:i+1], "unexpected character 'n' while scanning for a number")
+ return invalidReference, nil, NewParserError(b[i:i+1], "unexpected character 'n' while scanning for a number")
}
break
}
if i == 0 {
- return ast.InvalidReference, b, newDecodeError(b, "incomplete number")
+ return invalidReference, b, NewParserError(b, "incomplete number")
}
- kind := ast.Integer
+ kind := Integer
if isFloat {
- kind = ast.Float
+ kind = Float
}
- return p.builder.Push(ast.Node{
+ return p.builder.Push(Node{
Kind: kind,
Data: b[:i],
}), b[i:], nil
@@ -1075,11 +1136,11 @@ func isValidBinaryRune(r byte) bool {
func expect(x byte, b []byte) ([]byte, error) {
if len(b) == 0 {
- return nil, newDecodeError(b, "expected character %c but the document ended here", x)
+ return nil, NewParserError(b, "expected character %c but the document ended here", x)
}
if b[0] != x {
- return nil, newDecodeError(b[0:1], "expected character %c", x)
+ return nil, NewParserError(b[0:1], "expected character %c", x)
}
return b[1:], nil
diff --git a/vendor/github.com/pelletier/go-toml/v2/scanner.go b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go
similarity index 79%
rename from vendor/github.com/pelletier/go-toml/v2/scanner.go
rename to vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go
index bb445fab..af22ebbe 100644
--- a/vendor/github.com/pelletier/go-toml/v2/scanner.go
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go
@@ -1,4 +1,6 @@
-package toml
+package unstable
+
+import "github.com/pelletier/go-toml/v2/internal/characters"
func scanFollows(b []byte, pattern string) bool {
n := len(pattern)
@@ -54,16 +56,16 @@ func scanLiteralString(b []byte) ([]byte, []byte, error) {
case '\'':
return b[:i+1], b[i+1:], nil
case '\n', '\r':
- return nil, nil, newDecodeError(b[i:i+1], "literal strings cannot have new lines")
+ return nil, nil, NewParserError(b[i:i+1], "literal strings cannot have new lines")
}
- size := utf8ValidNext(b[i:])
+ size := characters.Utf8ValidNext(b[i:])
if size == 0 {
- return nil, nil, newDecodeError(b[i:i+1], "invalid character")
+ return nil, nil, NewParserError(b[i:i+1], "invalid character")
}
i += size
}
- return nil, nil, newDecodeError(b[len(b):], "unterminated literal string")
+ return nil, nil, NewParserError(b[len(b):], "unterminated literal string")
}
func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
@@ -98,39 +100,39 @@ func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
i++
if i < len(b) && b[i] == '\'' {
- return nil, nil, newDecodeError(b[i-3:i+1], "''' not allowed in multiline literal string")
+ return nil, nil, NewParserError(b[i-3:i+1], "''' not allowed in multiline literal string")
}
return b[:i], b[i:], nil
}
case '\r':
if len(b) < i+2 {
- return nil, nil, newDecodeError(b[len(b):], `need a \n after \r`)
+ return nil, nil, NewParserError(b[len(b):], `need a \n after \r`)
}
if b[i+1] != '\n' {
- return nil, nil, newDecodeError(b[i:i+2], `need a \n after \r`)
+ return nil, nil, NewParserError(b[i:i+2], `need a \n after \r`)
}
i += 2 // skip the \n
continue
}
- size := utf8ValidNext(b[i:])
+ size := characters.Utf8ValidNext(b[i:])
if size == 0 {
- return nil, nil, newDecodeError(b[i:i+1], "invalid character")
+ return nil, nil, NewParserError(b[i:i+1], "invalid character")
}
i += size
}
- return nil, nil, newDecodeError(b[len(b):], `multiline literal string not terminated by '''`)
+ return nil, nil, NewParserError(b[len(b):], `multiline literal string not terminated by '''`)
}
func scanWindowsNewline(b []byte) ([]byte, []byte, error) {
const lenCRLF = 2
if len(b) < lenCRLF {
- return nil, nil, newDecodeError(b, "windows new line expected")
+ return nil, nil, NewParserError(b, "windows new line expected")
}
if b[1] != '\n' {
- return nil, nil, newDecodeError(b, `windows new line should be \r\n`)
+ return nil, nil, NewParserError(b, `windows new line should be \r\n`)
}
return b[:lenCRLF], b[lenCRLF:], nil
@@ -165,11 +167,11 @@ func scanComment(b []byte) ([]byte, []byte, error) {
if i+1 < len(b) && b[i+1] == '\n' {
return b[:i+1], b[i+1:], nil
}
- return nil, nil, newDecodeError(b[i:i+1], "invalid character in comment")
+ return nil, nil, NewParserError(b[i:i+1], "invalid character in comment")
}
- size := utf8ValidNext(b[i:])
+ size := characters.Utf8ValidNext(b[i:])
if size == 0 {
- return nil, nil, newDecodeError(b[i:i+1], "invalid character in comment")
+ return nil, nil, NewParserError(b[i:i+1], "invalid character in comment")
}
i += size
@@ -192,17 +194,17 @@ func scanBasicString(b []byte) ([]byte, bool, []byte, error) {
case '"':
return b[:i+1], escaped, b[i+1:], nil
case '\n', '\r':
- return nil, escaped, nil, newDecodeError(b[i:i+1], "basic strings cannot have new lines")
+ return nil, escaped, nil, NewParserError(b[i:i+1], "basic strings cannot have new lines")
case '\\':
if len(b) < i+2 {
- return nil, escaped, nil, newDecodeError(b[i:i+1], "need a character after \\")
+ return nil, escaped, nil, NewParserError(b[i:i+1], "need a character after \\")
}
escaped = true
i++ // skip the next character
}
}
- return nil, escaped, nil, newDecodeError(b[len(b):], `basic string not terminated by "`)
+ return nil, escaped, nil, NewParserError(b[len(b):], `basic string not terminated by "`)
}
func scanMultilineBasicString(b []byte) ([]byte, bool, []byte, error) {
@@ -243,27 +245,27 @@ func scanMultilineBasicString(b []byte) ([]byte, bool, []byte, error) {
i++
if i < len(b) && b[i] == '"' {
- return nil, escaped, nil, newDecodeError(b[i-3:i+1], `""" not allowed in multiline basic string`)
+ return nil, escaped, nil, NewParserError(b[i-3:i+1], `""" not allowed in multiline basic string`)
}
return b[:i], escaped, b[i:], nil
}
case '\\':
if len(b) < i+2 {
- return nil, escaped, nil, newDecodeError(b[len(b):], "need a character after \\")
+ return nil, escaped, nil, NewParserError(b[len(b):], "need a character after \\")
}
escaped = true
i++ // skip the next character
case '\r':
if len(b) < i+2 {
- return nil, escaped, nil, newDecodeError(b[len(b):], `need a \n after \r`)
+ return nil, escaped, nil, NewParserError(b[len(b):], `need a \n after \r`)
}
if b[i+1] != '\n' {
- return nil, escaped, nil, newDecodeError(b[i:i+2], `need a \n after \r`)
+ return nil, escaped, nil, NewParserError(b[i:i+2], `need a \n after \r`)
}
i++ // skip the \n
}
}
- return nil, escaped, nil, newDecodeError(b[len(b):], `multiline basic string not terminated by """`)
+ return nil, escaped, nil, NewParserError(b[len(b):], `multiline basic string not terminated by """`)
}
diff --git a/vendor/github.com/rivo/uniseg/README.md b/vendor/github.com/rivo/uniseg/README.md
index 7e3d12e7..25e93468 100644
--- a/vendor/github.com/rivo/uniseg/README.md
+++ b/vendor/github.com/rivo/uniseg/README.md
@@ -133,6 +133,13 @@ Similarly, use
- [`FirstSentence`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentence) or [`FirstSentenceInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentenceInString) for sentence segmentation only, and
- [`FirstLineSegment`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegment) or [`FirstLineSegmentInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegmentInString) for line breaking / word wrapping (although using [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) or [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) is preferred as it will observe grapheme cluster boundaries).
+Finally, if you need to reverse a string while preserving grapheme clusters, use [`ReverseString`](https://pkg.go.dev/github.com/rivo/uniseg#ReverseString):
+
+```go
+fmt.Println(uniseg.ReverseString("🇩🇪🏳️🌈"))
+// 🏳️🌈🇩🇪
+```
+
## Documentation
Refer to https://pkg.go.dev/github.com/rivo/uniseg for the package's documentation.
diff --git a/vendor/github.com/rivo/uniseg/doc.go b/vendor/github.com/rivo/uniseg/doc.go
index 0fc2d8b4..11224ae2 100644
--- a/vendor/github.com/rivo/uniseg/doc.go
+++ b/vendor/github.com/rivo/uniseg/doc.go
@@ -70,10 +70,10 @@ broken.
Monospace width, as referred to in this package, is the width of a string in a
monospace font. This is commonly used in terminal user interfaces or text
displays or editors that don't support proportional fonts. A width of 1
-corresponds to a single character cell. The C function [wcwidth()] and its
+corresponds to a single character cell. The C function [wcswidth()] and its
implementation in other programming languages is in widespread use for the same
purpose. However, there is no standard for the calculation of such widths, and
-this package differs from wcwidth() in a number of ways, presumably to generate
+this package differs from wcswidth() in a number of ways, presumably to generate
more visually pleasing results.
To start, we assume that every code point has a width of 1, with the following
@@ -103,6 +103,6 @@ Note that whether these widths appear correct depends on your application's
render engine, to which extent it conforms to the Unicode Standard, and its
choice of font.
-[wcwidth()]: https://man7.org/linux/man-pages/man3/wcwidth.3.html
+[wcswidth()]: https://man7.org/linux/man-pages/man3/wcswidth.3.html
*/
package uniseg
diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go
index 997abbef..d5d4c09e 100644
--- a/vendor/github.com/rivo/uniseg/grapheme.go
+++ b/vendor/github.com/rivo/uniseg/grapheme.go
@@ -163,6 +163,25 @@ func GraphemeClusterCount(s string) (n int) {
return
}
+// ReverseString reverses the given string while observing grapheme cluster
+// boundaries.
+func ReverseString(s string) string {
+ str := []byte(s)
+ reversed := make([]byte, len(str))
+ state := -1
+ index := len(str)
+ for len(str) > 0 {
+ var cluster []byte
+ cluster, str, _, state = FirstGraphemeCluster(str, state)
+ index -= len(cluster)
+ copy(reversed[index:], cluster)
+ if index <= len(str)/2 {
+ break
+ }
+ }
+ return string(reversed)
+}
+
// The number of bits the grapheme property must be shifted to make place for
// grapheme states.
const shiftGraphemePropState = 4
diff --git a/vendor/github.com/samber/lo/CHANGELOG.md b/vendor/github.com/samber/lo/CHANGELOG.md
index 5665cc8a..ea3ef7a5 100644
--- a/vendor/github.com/samber/lo/CHANGELOG.md
+++ b/vendor/github.com/samber/lo/CHANGELOG.md
@@ -2,6 +2,50 @@
@samber: I sometimes forget to update this file. Ping me on [Twitter](https://twitter.com/samuelberthe) or open an issue in case of error. We need to keep a clear changelog for easier lib upgrade.
+## 1.37.0 (2022-12-15)
+
+Adding:
+- lo.PartialX
+- lo.Transaction
+
+Improvement:
+- lo.Associate / lo.SliceToMap: faster memory allocation
+
+Chore:
+- Remove *_test.go files from releases, in order to cleanup dev dependencies
+
+## 1.36.0 (2022-11-28)
+
+Adding:
+- lo.AttemptWhile
+- lo.AttemptWhileWithDelay
+
+## 1.35.0 (2022-11-15)
+
+Adding:
+- lo.RandomString
+- lo.BufferWithTimeout (alias to lo.BatchWithTimeout)
+- lo.Buffer (alias to lo.Batch)
+
+Change:
+- lo.Slice: avoid panic caused by out-of-bounds
+
+Deprecation:
+- lo.BatchWithTimeout
+- lo.Batch
+
+## 1.34.0 (2022-11-12)
+
+Improving:
+- lo.Union: faster and can receive more than 2 lists
+
+Adding:
+- lo.FanIn (alias to lo.ChannelMerge)
+- lo.FanOut
+
+Deprecation:
+- lo.ChannelMerge
+
## 1.33.0 (2022-10-14)
Adding:
diff --git a/vendor/github.com/samber/lo/README.md b/vendor/github.com/samber/lo/README.md
index 06803933..ffb7c438 100644
--- a/vendor/github.com/samber/lo/README.md
+++ b/vendor/github.com/samber/lo/README.md
@@ -1,16 +1,19 @@
# lo
[![tag](https://img.shields.io/github/tag/samber/lo.svg)](https://github.com/samber/lo/releases)
+![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.18-%23007d9c)
[![GoDoc](https://godoc.org/github.com/samber/lo?status.svg)](https://pkg.go.dev/github.com/samber/lo)
![Build Status](https://github.com/samber/lo/actions/workflows/go.yml/badge.svg)
[![Go report](https://goreportcard.com/badge/github.com/samber/lo)](https://goreportcard.com/report/github.com/samber/lo)
-[![codecov](https://codecov.io/gh/samber/lo/branch/master/graph/badge.svg)](https://codecov.io/gh/samber/lo)
+[![Coverage](https://img.shields.io/codecov/c/github/samber/lo)](https://codecov.io/gh/samber/lo)
+[![Contributors](https://img.shields.io/github/contributors/samber/lo)](https://github.com/samber/lo/graphs/contributors)
+[![License](https://img.shields.io/github/license/samber/lo)](./LICENSE)
✨ **`samber/lo` is a Lodash-style Go library based on Go 1.18+ Generics.**
This project started as an experiment with the new generics implementation. It may look like [Lodash](https://github.com/lodash/lodash) in some aspects. I used to code with the fantastic ["go-funk"](https://github.com/thoas/go-funk) package, but "go-funk" uses reflection and therefore is not typesafe.
-As expected, benchmarks demonstrate that generics will be much faster than implementations based on the "reflect" package. Benchmarks also show similar performance gains compared to pure `for` loops. [See below](#-benchmark).
+As expected, benchmarks demonstrate that generics are much faster than implementations based on the "reflect" package. Benchmarks also show similar performance gains compared to pure `for` loops. [See below](#-benchmark).
In the future, 5 to 10 helpers will overlap with those coming into the Go standard library (under package names `slices` and `maps`). I feel this library is legitimate and offers many more valuable abstractions.
@@ -23,6 +26,8 @@ In the future, 5 to 10 helpers will overlap with those coming into the Go standa
I wanted a **short name**, similar to "Lodash" and no Go package currently uses this name.
+![](img/logo-full.png)
+
## 🚀 Install
```sh
@@ -138,6 +143,7 @@ Supported math helpers:
Supported helpers for strings:
+- [RandomString](#randomstring)
- [Substring](#substring)
- [ChunkString](#chunkstring)
- [RuneLength](#runelength)
@@ -154,9 +160,10 @@ Supported helpers for channels:
- [ChannelDispatcher](#channeldispatcher)
- [SliceToChannel](#slicetochannel)
- [Generator](#generator)
-- [Batch](#batch)
-- [BatchWithTimeout](#batchwithtimeout)
-- [ChannelMerge](#channelmerge)
+- [Buffer](#buffer)
+- [BufferWithTimeout](#bufferwithtimeout)
+- [FanIn](#fanin)
+- [FanOut](#fanout)
Supported intersection helpers:
@@ -219,14 +226,18 @@ Type manipulation helpers:
Function helpers:
- [Partial](#partial)
+- [Partial2 -> Partial5](#partial2---partial5)
Concurrency helpers:
- [Attempt](#attempt)
+- [AttemptWhile](#attemptwhile)
- [AttemptWithDelay](#attemptwithdelay)
+- [AttemptWhileWithDelay](#attemptwhilewithdelay)
- [Debounce](#debounce)
- [Synchronize](#synchronize)
- [Async](#async)
+- [Transaction](#transaction)
Error handling:
@@ -515,7 +526,7 @@ flat := lo.Flatten[int]([][]int{{0, 1}, {2, 3, 4, 5}})
### Interleave
-Round-robbin alternating input slices and sequentially appending value at index into result.
+Round-robin alternating input slices and sequentially appending value at index into result.
```go
interleaved := lo.Interleave[int]([]int{1, 4, 7}, []int{2, 5, 8}, []int{3, 6, 9})
@@ -1201,6 +1212,17 @@ sum := lo.SumBy(strings, func(item string) int {
[[play](https://go.dev/play/p/Dz_a_7jN_ca)]
+### RandomString
+
+Returns a random string of the specified length and made of the specified charset.
+
+```go
+str := lo.RandomString(5, lo.LettersCharset)
+// example: "eIGbt"
+```
+
+[[play](https://go.dev/play/p/rRseOQVVum4)]
+
### Substring
Return part of a string.
@@ -1432,16 +1454,16 @@ for v := range lo.Generator(2, generator) {
// prints 1, then 2, then 3
```
-### Batch
+### Buffer
Creates a slice of n elements from a channel. Returns the slice, the slice length, the read time and the channel status (opened/closed).
```go
ch := lo.SliceToChannel(2, []int{1, 2, 3, 4, 5})
-items1, length1, duration1, ok1 := lo.Batch(ch, 3)
+items1, length1, duration1, ok1 := lo.Buffer(ch, 3)
// []int{1, 2, 3}, 3, 0s, true
-items2, length2, duration2, ok2 := lo.Batch(ch, 3)
+items2, length2, duration2, ok2 := lo.Buffer(ch, 3)
// []int{4, 5}, 2, 0s, false
```
@@ -1452,7 +1474,7 @@ ch := readFromQueue()
for {
// read 1k items
- items, length, _, ok := lo.Batch(ch, 1000)
+ items, length, _, ok := lo.Buffer(ch, 1000)
// do batching stuff
@@ -1462,7 +1484,7 @@ for {
}
```
-### BatchWithTimeout
+### BufferWithTimeout
Creates a slice of n elements from a channel, with timeout. Returns the slice, the slice length, the read time and the channel status (opened/closed).
@@ -1476,11 +1498,11 @@ generator := func(yield func(int)) {
ch := lo.Generator(0, generator)
-items1, length1, duration1, ok1 := lo.BatchWithTimeout(ch, 3, 100*time.Millisecond)
+items1, length1, duration1, ok1 := lo.BufferWithTimeout(ch, 3, 100*time.Millisecond)
// []int{1, 2}, 2, 100ms, true
-items2, length2, duration2, ok2 := lo.BatchWithTimeout(ch, 3, 100*time.Millisecond)
+items2, length2, duration2, ok2 := lo.BufferWithTimeout(ch, 3, 100*time.Millisecond)
// []int{3, 4, 5}, 3, 75ms, true
-items3, length3, duration2, ok3 := lo.BatchWithTimeout(ch, 3, 100*time.Millisecond)
+items3, length3, duration2, ok3 := lo.BufferWithTimeout(ch, 3, 100*time.Millisecond)
// []int{}, 0, 10ms, false
```
@@ -1492,7 +1514,7 @@ ch := readFromQueue()
for {
// read 1k items
// wait up to 1 second
- items, length, _, ok := lo.BatchWithTimeout(ch, 1000, 1*time.Second)
+ items, length, _, ok := lo.BufferWithTimeout(ch, 1000, 1*time.Second)
// do batching stuff
@@ -1515,7 +1537,7 @@ consumer := func(c <-chan int) {
for {
// read 1k items
// wait up to 1 second
- items, length, _, ok := lo.BatchWithTimeout(ch, 1000, 1*time.Second)
+ items, length, _, ok := lo.BufferWithTimeout(ch, 1000, 1*time.Second)
// do batching stuff
@@ -1530,16 +1552,28 @@ for i := range children {
}
```
-### ChannelMerge
+### FanIn
-Collects messages from multiple input channels into a single buffered channel. Output messages has no priority.
+Merge messages from multiple input channels into a single buffered channel. Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
```go
stream1 := make(chan int, 42)
stream2 := make(chan int, 42)
stream3 := make(chan int, 42)
-all := lo.ChannelMerge(100, stream1, stream2, stream3)
+all := lo.FanIn(100, stream1, stream2, stream3)
+// <-chan int
+```
+
+### FanOut
+
+Broadcasts all the upstream messages to multiple downstream channels. When upstream channel reach EOF, downstream channels close. If any downstream channels is full, broadcasting is paused.
+
+```go
+stream := make(chan int, 42)
+
+all := lo.FanOut(5, 100, stream)
+// [5]<-chan int
```
### Contains
@@ -1664,10 +1698,10 @@ left, right := lo.Difference[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4,
### Union
-Returns all distinct elements from both collections. Result will not change the order of elements relatively.
+Returns all distinct elements from given collections. Result will not change the order of elements relatively.
```go
-union := lo.Union[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 10})
+union := lo.Union[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}, []int{0, 10})
// []int{0, 1, 2, 3, 4, 5, 10}
```
@@ -2242,6 +2276,21 @@ f(42)
// 47
```
+### Partial2 -> Partial5
+
+Returns new function that, when called, has its first argument set to the provided value.
+
+```go
+add := func(x, y, z int) int { return x + y + z }
+f := lo.Partial2(add, 42)
+
+f(10, 5)
+// 57
+
+f(42, -4)
+// 80
+```
+
### Attempt
Invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a successful response is returned.
@@ -2305,6 +2354,56 @@ For more advanced retry strategies (delay, exponential backoff...), please take
[[play](https://go.dev/play/p/tVs6CygC7m1)]
+### AttemptWhile
+
+Invokes a function N times until it returns valid output. Returning either the caught error or nil, and along with a bool value to identifying whether it needs invoke function continuously. It will terminate the invoke immediately if second bool value is returned with falsy value.
+
+When first argument is less than `1`, the function runs until a successful response is returned.
+
+```go
+count1, err1 := lo.AttemptWhile(5, func(i int) (error, bool) {
+ err := doMockedHTTPRequest(i)
+ if err != nil {
+ if errors.Is(err, ErrBadRequest) { // lets assume ErrBadRequest is a critical error that needs to terminate the invoke
+ return err, false // flag the second return value as false to terminate the invoke
+ }
+
+ return err, true
+ }
+
+ return nil, false
+})
+```
+
+For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
+
+[[play](https://go.dev/play/p/M2wVq24PaZM)]
+
+### AttemptWhileWithDelay
+
+Invokes a function N times until it returns valid output, with a pause between each call. Returning either the caught error or nil, and along with a bool value to identifying whether it needs to invoke function continuously. It will terminate the invoke immediately if second bool value is returned with falsy value.
+
+When first argument is less than `1`, the function runs until a successful response is returned.
+
+```go
+count1, time1, err1 := lo.AttemptWhileWithDelay(5, time.Millisecond, func(i int, d time.Duration) (error, bool) {
+ err := doMockedHTTPRequest(i)
+ if err != nil {
+ if errors.Is(err, ErrBadRequest) { // lets assume ErrBadRequest is a critical error that needs to terminate the invoke
+ return err, false // flag the second return value as false to terminate the invoke
+ }
+
+ return err, true
+ }
+
+ return nil, false
+})
+```
+
+For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
+
+[[play](https://go.dev/play/p/cfcmhvLO-nv)]
+
### Debounce
`NewDebounce` creates a debounced instance that delays invoking functions given until after wait milliseconds have elapsed, until `cancel` is called.
@@ -2384,6 +2483,58 @@ ch := lo.Async2(func() (int, string) {
// chan lo.Tuple2[int, string] ({42, "Hello"})
```
+### Transaction
+
+Implements a Saga pattern.
+
+```go
+transaction := NewTransaction[int]().
+ Then(
+ func(state int) (int, error) {
+ fmt.Println("step 1")
+ return state + 10, nil
+ },
+ func(state int) int {
+ fmt.Println("rollback 1")
+ return state - 10
+ },
+ ).
+ Then(
+ func(state int) (int, error) {
+ fmt.Println("step 2")
+ return state + 15, nil
+ },
+ func(state int) int {
+ fmt.Println("rollback 2")
+ return state - 15
+ },
+ ).
+ Then(
+ func(state int) (int, error) {
+ fmt.Println("step 3")
+
+ if true {
+ return state, fmt.Errorf("error")
+ }
+
+ return state + 42, nil
+ },
+ func(state int) int {
+ fmt.Println("rollback 3")
+ return state - 42
+ },
+ )
+
+_, _ = transaction.Process(-5)
+
+// Output:
+// step 1
+// step 2
+// step 3
+// rollback 2
+// rollback 1
+```
+
### Validate
Helper function that creates an error when a condition is not met.
@@ -2683,9 +2834,9 @@ make test
make watch-test
```
-## 👤 Authors
+## 👤 Contributors
-- Samuel Berthe
+![Contributors](https://contrib.rocks/image?repo=samber/lo)
## 💫 Show your support
diff --git a/vendor/github.com/samber/lo/channel.go b/vendor/github.com/samber/lo/channel.go
index 41c5bfa8..e5af2504 100644
--- a/vendor/github.com/samber/lo/channel.go
+++ b/vendor/github.com/samber/lo/channel.go
@@ -193,9 +193,9 @@ func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T {
return ch
}
-// Batch creates a slice of n elements from a channel. Returns the slice and the slice length.
+// Buffer creates a slice of n elements from a channel. Returns the slice and the slice length.
// @TODO: we should probably provide an helper that reuse the same buffer.
-func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
+func Buffer[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
buffer := make([]T, 0, size)
index := 0
now := time.Now()
@@ -212,9 +212,15 @@ func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime t
return buffer, index, time.Since(now), true
}
-// BatchWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
+// Buffer creates a slice of n elements from a channel. Returns the slice and the slice length.
+// Deprecated: Use lo.Buffer instead.
+func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
+ return Buffer(ch, size)
+}
+
+// BufferWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
// @TODO: we should probably provide an helper that reuse the same buffer.
-func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
+func BufferWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
expire := time.NewTimer(timeout)
defer expire.Stop()
@@ -239,9 +245,15 @@ func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (coll
return buffer, index, time.Since(now), true
}
-// ChannelMerge collects messages from multiple input channels into a single buffered channel.
-// Output messages has no priority.
-func ChannelMerge[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
+// BufferWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
+// Deprecated: Use lo.BufferWithTimeout instead.
+func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
+ return BufferWithTimeout(ch, size, timeout)
+}
+
+// FanIn collects messages from multiple input channels into a single buffered channel.
+// Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
+func FanIn[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
out := make(chan T, channelBufferCap)
var wg sync.WaitGroup
@@ -263,3 +275,32 @@ func ChannelMerge[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
}()
return out
}
+
+// ChannelMerge collects messages from multiple input channels into a single buffered channel.
+// Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
+// Deprecated: Use lo.FanIn instead.
+func ChannelMerge[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
+ return FanIn(channelBufferCap, upstreams...)
+}
+
+// FanOut broadcasts all the upstream messages to multiple downstream channels.
+// When upstream channel reach EOF, downstream channels close. If any downstream
+// channels is full, broadcasting is paused.
+func FanOut[T any](count int, channelsBufferCap int, upstream <-chan T) []<-chan T {
+ downstreams := createChannels[T](count, channelsBufferCap)
+
+ go func() {
+ for msg := range upstream {
+ for i := range downstreams {
+ downstreams[i] <- msg
+ }
+ }
+
+ // Close out once all the output goroutines are done.
+ for i := range downstreams {
+ close(downstreams[i])
+ }
+ }()
+
+ return channelsToReadOnly(downstreams)
+}
diff --git a/vendor/github.com/samber/lo/docker-compose.yml b/vendor/github.com/samber/lo/docker-compose.yml
deleted file mode 100644
index 511e85fd..00000000
--- a/vendor/github.com/samber/lo/docker-compose.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3'
-
-services:
- dev:
- image: golang:1.18-bullseye
- volumes:
- - ./:/go/src/github.com/samber/lo
- working_dir: /go/src/github.com/samber/lo
- command: make watch-test
diff --git a/vendor/github.com/samber/lo/find.go b/vendor/github.com/samber/lo/find.go
index 751410a0..f8caeb89 100644
--- a/vendor/github.com/samber/lo/find.go
+++ b/vendor/github.com/samber/lo/find.go
@@ -352,7 +352,7 @@ func Sample[T any](collection []T) T {
func Samples[T any](collection []T, count int) []T {
size := len(collection)
- cOpy := append([]T{}, collection...)
+ copy := append([]T{}, collection...)
results := []T{}
@@ -360,12 +360,12 @@ func Samples[T any](collection []T, count int) []T {
copyLength := size - i
index := rand.Intn(size - i)
- results = append(results, cOpy[index])
+ results = append(results, copy[index])
// Removes element.
// It is faster to swap with last element and remove it.
- cOpy[index] = cOpy[copyLength-1]
- cOpy = cOpy[:copyLength-1]
+ copy[index] = copy[copyLength-1]
+ copy = copy[:copyLength-1]
}
return results
diff --git a/vendor/github.com/samber/lo/func.go b/vendor/github.com/samber/lo/func.go
index 5a51f2d6..5fa1cbc8 100644
--- a/vendor/github.com/samber/lo/func.go
+++ b/vendor/github.com/samber/lo/func.go
@@ -6,3 +6,36 @@ func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R {
return f(arg1, t2)
}
}
+
+// Partial1 returns new function that, when called, has its first argument set to the provided value.
+func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R {
+ return Partial(f, arg1)
+}
+
+// Partial2 returns new function that, when called, has its first argument set to the provided value.
+func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R {
+ return func(t2 T2, t3 T3) R {
+ return f(arg1, t2, t3)
+ }
+}
+
+// Partial3 returns new function that, when called, has its first argument set to the provided value.
+func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2, T3, T4) R {
+ return func(t2 T2, t3 T3, t4 T4) R {
+ return f(arg1, t2, t3, t4)
+ }
+}
+
+// Partial4 returns new function that, when called, has its first argument set to the provided value.
+func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1) func(T2, T3, T4, T5) R {
+ return func(t2 T2, t3 T3, t4 T4, t5 T5) R {
+ return f(arg1, t2, t3, t4, t5)
+ }
+}
+
+// Partial5 returns new function that, when called, has its first argument set to the provided value
+func Partial5[T1, T2, T3, T4, T5, T6, R any](f func(T1, T2, T3, T4, T5, T6) R, arg1 T1) func(T2, T3, T4, T5, T6) R {
+ return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R {
+ return f(arg1, t2, t3, t4, t5, t6)
+ }
+}
diff --git a/vendor/github.com/samber/lo/intersect.go b/vendor/github.com/samber/lo/intersect.go
index 38a0052b..cf6cab3d 100644
--- a/vendor/github.com/samber/lo/intersect.go
+++ b/vendor/github.com/samber/lo/intersect.go
@@ -141,35 +141,18 @@ func Difference[T comparable](list1 []T, list2 []T) ([]T, []T) {
return left, right
}
-// Union returns all distinct elements from both collections.
+// Union returns all distinct elements from given collections.
// result returns will not change the order of elements relatively.
-func Union[T comparable](list1 []T, list2 []T) []T {
+func Union[T comparable](lists ...[]T) []T {
result := []T{}
-
seen := map[T]struct{}{}
- hasAdd := map[T]struct{}{}
-
- for _, e := range list1 {
- seen[e] = struct{}{}
- }
- for _, e := range list2 {
- seen[e] = struct{}{}
- }
-
- for _, e := range list1 {
- if _, ok := seen[e]; ok {
- result = append(result, e)
- hasAdd[e] = struct{}{}
- }
- }
-
- for _, e := range list2 {
- if _, ok := hasAdd[e]; ok {
- continue
- }
- if _, ok := seen[e]; ok {
- result = append(result, e)
+ for _, list := range lists {
+ for _, e := range list {
+ if _, ok := seen[e]; !ok {
+ seen[e] = struct{}{}
+ result = append(result, e)
+ }
}
}
diff --git a/vendor/github.com/samber/lo/retry.go b/vendor/github.com/samber/lo/retry.go
index 0303f84a..0d46f265 100644
--- a/vendor/github.com/samber/lo/retry.go
+++ b/vendor/github.com/samber/lo/retry.go
@@ -101,4 +101,110 @@ func AttemptWithDelay(maxIteration int, delay time.Duration, f func(index int, d
return maxIteration, time.Since(start), err
}
+// AttemptWhile invokes a function N times until it returns valid output.
+// Returning either the caught error or nil, and along with a bool value to identify
+// whether it needs invoke function continuously. It will terminate the invoke
+// immediately if second bool value is returned with falsy value. When first
+// argument is less than `1`, the function runs until a successful response is
+// returned.
+func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) {
+ var err error
+ var shouldContinueInvoke bool
+
+ for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
+ // for retries >= 0 {
+ err, shouldContinueInvoke = f(i)
+ if !shouldContinueInvoke { // if shouldContinueInvoke is false, then return immediately
+ return i + 1, err
+ }
+ if err == nil {
+ return i + 1, nil
+ }
+ }
+
+ return maxIteration, err
+}
+
+// AttemptWhileWithDelay invokes a function N times until it returns valid output,
+// with a pause between each call. Returning either the caught error or nil, and along
+// with a bool value to identify whether it needs to invoke function continuously.
+// It will terminate the invoke immediately if second bool value is returned with falsy
+// value. When first argument is less than `1`, the function runs until a successful
+// response is returned.
+func AttemptWhileWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) (error, bool)) (int, time.Duration, error) {
+ var err error
+ var shouldContinueInvoke bool
+
+ start := time.Now()
+
+ for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
+ err, shouldContinueInvoke = f(i, time.Since(start))
+ if !shouldContinueInvoke { // if shouldContinueInvoke is false, then return immediately
+ return i + 1, time.Since(start), err
+ }
+ if err == nil {
+ return i + 1, time.Since(start), nil
+ }
+
+ if maxIteration <= 0 || i+1 < maxIteration {
+ time.Sleep(delay)
+ }
+ }
+
+ return maxIteration, time.Since(start), err
+}
+
+type transactionStep[T any] struct {
+ exec func(T) (T, error)
+ onRollback func(T) T
+}
+
+// NewTransaction instanciate a new transaction.
+func NewTransaction[T any]() *Transaction[T] {
+ return &Transaction[T]{
+ steps: []transactionStep[T]{},
+ }
+}
+
+// Transaction implements a Saga pattern
+type Transaction[T any] struct {
+ steps []transactionStep[T]
+}
+
+// Then adds a step to the chain of callbacks. It returns the same Transaction.
+func (t *Transaction[T]) Then(exec func(T) (T, error), onRollback func(T) T) *Transaction[T] {
+ t.steps = append(t.steps, transactionStep[T]{
+ exec: exec,
+ onRollback: onRollback,
+ })
+
+ return t
+}
+
+// Process runs the Transaction steps and rollbacks in case of errors.
+func (t *Transaction[T]) Process(state T) (T, error) {
+ var i int
+ var err error
+
+ for i < len(t.steps) {
+ state, err = t.steps[i].exec(state)
+ if err != nil {
+ break
+ }
+
+ i++
+ }
+
+ if err == nil {
+ return state, nil
+ }
+
+ for i > 0 {
+ i--
+ state = t.steps[i].onRollback(state)
+ }
+
+ return state, err
+}
+
// throttle ?
diff --git a/vendor/github.com/samber/lo/slice.go b/vendor/github.com/samber/lo/slice.go
index 8ef4addc..b2e92ad2 100644
--- a/vendor/github.com/samber/lo/slice.go
+++ b/vendor/github.com/samber/lo/slice.go
@@ -229,7 +229,7 @@ func Flatten[T any](collection [][]T) []T {
return result
}
-// Interleave round-robbin alternating input slices and sequentially appending value at index into result
+// Interleave round-robin alternating input slices and sequentially appending value at index into result
// Play: https://go.dev/play/p/DDhlwrShbwe
func Interleave[T any](collections ...[]T) []T {
if len(collections) == 0 {
@@ -345,7 +345,7 @@ func KeyBy[K comparable, V any](collection []V, iteratee func(item V) K) map[K]V
// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array.
// Play: https://go.dev/play/p/WHa2CfMO3Lr
func Associate[T any, K comparable, V any](collection []T, transform func(item T) (K, V)) map[K]V {
- result := make(map[K]V)
+ result := make(map[K]V, len(collection))
for _, t := range collection {
k, v := transform(t)
@@ -513,10 +513,16 @@ func Slice[T any](collection []T, start int, end int) []T {
if start > size {
start = size
}
+ if start < 0 {
+ start = 0
+ }
if end > size {
end = size
}
+ if end < 0 {
+ end = 0
+ }
return collection[start:end]
}
diff --git a/vendor/github.com/samber/lo/string.go b/vendor/github.com/samber/lo/string.go
index a63167cb..dfe1050b 100644
--- a/vendor/github.com/samber/lo/string.go
+++ b/vendor/github.com/samber/lo/string.go
@@ -1,9 +1,38 @@
package lo
import (
+ "math/rand"
"unicode/utf8"
)
+var (
+ LowerCaseLettersCharset = []rune("abcdefghijklmnopqrstuvwxyz")
+ UpperCaseLettersCharset = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ LettersCharset = append(LowerCaseLettersCharset, UpperCaseLettersCharset...)
+ NumbersCharset = []rune("0123456789")
+ AlphanumericCharset = append(LettersCharset, NumbersCharset...)
+ SpecialCharset = []rune("!@#$%^&*()_+-=[]{}|;':\",./<>?")
+ AllCharset = append(AlphanumericCharset, SpecialCharset...)
+)
+
+// RandomString return a random string.
+// Play: https://go.dev/play/p/rRseOQVVum4
+func RandomString(size int, charset []rune) string {
+ if size <= 0 {
+ panic("lo.RandomString: Size parameter must be greater than 0")
+ }
+ if len(charset) <= 0 {
+ panic("lo.RandomString: Charset parameter must not be empty")
+ }
+
+ b := make([]rune, size)
+ possibleCharactersCount := len(charset)
+ for i := range b {
+ b[i] = charset[rand.Intn(possibleCharactersCount)]
+ }
+ return string(b)
+}
+
// Substring return part of a string.
// Play: https://go.dev/play/p/TQlxQi82Lu1
func Substring[T ~string](str T, offset int, length uint) T {
diff --git a/vendor/github.com/samber/lo/test.go b/vendor/github.com/samber/lo/test.go
deleted file mode 100644
index 26db4c25..00000000
--- a/vendor/github.com/samber/lo/test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package lo
-
-import (
- "os"
- "testing"
- "time"
-)
-
-// https://github.com/stretchr/testify/issues/1101
-func testWithTimeout(t *testing.T, timeout time.Duration) {
- t.Helper()
-
- testFinished := make(chan struct{})
- t.Cleanup(func() { close(testFinished) })
-
- go func() {
- select {
- case <-testFinished:
- case <-time.After(timeout):
- t.Errorf("test timed out after %s", timeout)
- os.Exit(1)
- }
- }()
-}
-
-type foo struct {
- bar string
-}
-
-func (f foo) Clone() foo {
- return foo{f.bar}
-}
diff --git a/vendor/github.com/samber/mo/README.md b/vendor/github.com/samber/mo/README.md
index b8e2e162..6875ca28 100644
--- a/vendor/github.com/samber/mo/README.md
+++ b/vendor/github.com/samber/mo/README.md
@@ -1,10 +1,12 @@
# mo - Monads
[![tag](https://img.shields.io/github/tag/samber/mo.svg)](https://github.com/samber/mo/releases)
+![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.18-%23007d9c)
[![GoDoc](https://godoc.org/github.com/samber/mo?status.svg)](https://pkg.go.dev/github.com/samber/mo)
![Build Status](https://github.com/samber/mo/actions/workflows/go.yml/badge.svg)
[![Go report](https://goreportcard.com/badge/github.com/samber/mo)](https://goreportcard.com/report/github.com/samber/mo)
-[![codecov](https://codecov.io/gh/samber/mo/branch/master/graph/badge.svg)](https://codecov.io/gh/samber/mo)
+[![Coverage](https://img.shields.io/codecov/c/github/samber/do)](https://codecov.io/gh/samber/mo)
+[![License](https://img.shields.io/github/license/samber/mo)](./LICENSE)
🦄 **`samber/mo` brings monads and popular FP abstractions to Go projects. `samber/mo` uses the recent Go 1.18+ Generics.**
@@ -30,7 +32,7 @@ We currently support the following data types:
- `Option[T]` (Maybe)
- `Result[T]`
- `Either[A, B]`
-- `EitherX[T1, ..., TX]` (With X between 3 and 5)
+- `EitherX[T1, ..., TX]` (With X between 3 and 5)
- `Future[T]`
- `IO[T]`
- `IOEither[T]`
@@ -98,6 +100,18 @@ option3 := option1.Match(
More examples in [documentation](https://godoc.org/github.com/samber/mo).
+### Tips for lazy developers
+
+I cannot recommend it, but in case you are too lazy for repeating `mo.` everywhere, you can import the entire library into the namespace.
+
+```go
+import (
+ . "github.com/samber/mo"
+)
+```
+
+I take no responsibility on this junk. 😁 💩
+
## 🤠 Documentation and examples
[GoDoc: https://godoc.org/github.com/samber/mo](https://godoc.org/github.com/samber/mo)
@@ -182,6 +196,7 @@ Methods:
- `.Right()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.Right)
- `.MustLeft()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.MustLeft)
- `.MustRight()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.MustRight)
+- `.Unpack()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.Unpack)
- `.LeftOrElse()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.LeftOrElse)
- `.RightOrElse()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.RightOrElse)
- `.LeftOrEmpty()` [doc](https://pkg.go.dev/github.com/samber/mo#Either.LeftOrEmpty)
@@ -211,6 +226,7 @@ Methods:
- `.IsArgX()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.IsArg1)
- `.ArgX()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.Arg1)
- `.MustArgX()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.MustArg1)
+- `.Unpack()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.Unpack)
- `.ArgXOrElse()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.Arg1OrElse)
- `.ArgXOrEmpty()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.Arg1OrEmpty)
- `.ForEach()` [doc](https://pkg.go.dev/github.com/samber/mo#Either5.ForEach)
@@ -357,9 +373,9 @@ make test
make watch-test
```
-## 👤 Authors
+## 👤 Contributors
-- Samuel Berthe
+![Contributors](https://contrib.rocks/image?repo=samber/mo)
## 💫 Show your support
diff --git a/vendor/github.com/samber/mo/docker-compose.yml b/vendor/github.com/samber/mo/docker-compose.yml
deleted file mode 100644
index 51393361..00000000
--- a/vendor/github.com/samber/mo/docker-compose.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-version: '3'
-
-services:
- dev:
- build: .
- volumes:
- - ./:/go/src/github.com/samber/mo
- working_dir: /go/src/github.com/samber/mo
- command: bash -c 'make tools ; make watch-test'
diff --git a/vendor/github.com/samber/mo/either.go b/vendor/github.com/samber/mo/either.go
index f3aadeb8..8fa69874 100644
--- a/vendor/github.com/samber/mo/either.go
+++ b/vendor/github.com/samber/mo/either.go
@@ -75,6 +75,11 @@ func (e Either[L, R]) MustRight() R {
return e.right
}
+// Unpack returns all values
+func (e Either[L, R]) Unpack() (L, R) {
+ return e.left, e.right
+}
+
// LeftOrElse returns left value of a Either struct or fallback.
func (e Either[L, R]) LeftOrElse(fallback L) L {
if e.IsLeft() {
diff --git a/vendor/github.com/samber/mo/either3.go b/vendor/github.com/samber/mo/either3.go
index 6660a964..131b8bab 100644
--- a/vendor/github.com/samber/mo/either3.go
+++ b/vendor/github.com/samber/mo/either3.go
@@ -112,6 +112,11 @@ func (e Either3[T1, T2, T3]) MustArg3() T3 {
return e.arg3
}
+// Unpack returns all values
+func (e Either3[T1, T2, T3]) Unpack() (T1, T2, T3) {
+ return e.arg1, e.arg2, e.arg3
+}
+
// Arg1OrElse returns the first argument of a Either3 struct or fallback.
func (e Either3[T1, T2, T3]) Arg1OrElse(fallback T1) T1 {
if e.IsArg1() {
diff --git a/vendor/github.com/samber/mo/either4.go b/vendor/github.com/samber/mo/either4.go
index fb4cf812..16e207a8 100644
--- a/vendor/github.com/samber/mo/either4.go
+++ b/vendor/github.com/samber/mo/either4.go
@@ -144,6 +144,11 @@ func (e Either4[T1, T2, T3, T4]) MustArg4() T4 {
return e.arg4
}
+// Unpack returns all values
+func (e Either4[T1, T2, T3, T4]) Unpack() (T1, T2, T3, T4) {
+ return e.arg1, e.arg2, e.arg3, e.arg4
+}
+
// Arg1OrElse returns the first argument of a Either4 struct or fallback.
func (e Either4[T1, T2, T3, T4]) Arg1OrElse(fallback T1) T1 {
if e.IsArg1() {
diff --git a/vendor/github.com/samber/mo/either5.go b/vendor/github.com/samber/mo/either5.go
index 1eadc073..bc8e3c5c 100644
--- a/vendor/github.com/samber/mo/either5.go
+++ b/vendor/github.com/samber/mo/either5.go
@@ -176,6 +176,11 @@ func (e Either5[T1, T2, T3, T4, T5]) MustArg5() T5 {
return e.arg5
}
+// Unpack returns all values
+func (e Either5[T1, T2, T3, T4, T5]) Unpack() (T1, T2, T3, T4, T5) {
+ return e.arg1, e.arg2, e.arg3, e.arg4, e.arg5
+}
+
// Arg1OrElse returns the first argument of a Either5 struct or fallback.
func (e Either5[T1, T2, T3, T4, T5]) Arg1OrElse(fallback T1) T1 {
if e.IsArg1() {
diff --git a/vendor/github.com/samber/mo/future.go b/vendor/github.com/samber/mo/future.go
index faf2345d..f8e14071 100644
--- a/vendor/github.com/samber/mo/future.go
+++ b/vendor/github.com/samber/mo/future.go
@@ -7,14 +7,12 @@ import (
// NewFuture instanciate a new future.
func NewFuture[T any](cb func(resolve func(T), reject func(error))) *Future[T] {
future := Future[T]{
- mu: sync.RWMutex{},
- next: nil,
+ cb: cb,
cancelCb: func() {},
+ done: make(chan struct{}),
}
- go func() {
- cb(future.resolve, future.reject)
- }()
+ future.active()
return &future
}
@@ -22,28 +20,43 @@ func NewFuture[T any](cb func(resolve func(T), reject func(error))) *Future[T] {
// Future represents a value which may or may not currently be available, but will be
// available at some point, or an exception if that value could not be made available.
type Future[T any] struct {
- mu sync.RWMutex
+ mu sync.Mutex
- next func(T, error)
+ cb func(func(T), func(error))
cancelCb func()
+ next *Future[T]
+ done chan struct{}
+ result Result[T]
+}
+
+func (f *Future[T]) active() {
+ go f.cb(f.resolve, f.reject)
+}
+
+func (f *Future[T]) activeSync() {
+ f.cb(f.resolve, f.reject)
}
func (f *Future[T]) resolve(value T) {
- f.mu.RLock()
- defer f.mu.RUnlock()
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ f.result = Ok(value)
if f.next != nil {
- f.next(value, nil)
+ f.next.activeSync()
}
+ close(f.done)
}
func (f *Future[T]) reject(err error) {
- f.mu.RLock()
- defer f.mu.RUnlock()
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ f.result = Err[T](err)
if f.next != nil {
- f.next(empty[T](), err)
+ f.next.activeSync()
}
+ close(f.done)
}
// Then is called when Future is resolved. It returns a new Future.
@@ -51,30 +64,31 @@ func (f *Future[T]) Then(cb func(T) (T, error)) *Future[T] {
f.mu.Lock()
defer f.mu.Unlock()
- future := &Future[T]{
- mu: sync.RWMutex{},
- next: nil,
+ f.next = &Future[T]{
+ cb: func(resolve func(T), reject func(error)) {
+ if f.result.IsError() {
+ reject(f.result.Error())
+ return
+ }
+ newValue, err := cb(f.result.MustGet())
+ if err != nil {
+ reject(err)
+ return
+ }
+ resolve(newValue)
+ },
cancelCb: func() {
f.Cancel()
},
+ done: make(chan struct{}),
}
- f.next = func(value T, err error) {
- if err != nil {
- future.reject(err)
- return
- }
-
- newValue, err := cb(value)
- if err != nil {
- future.reject(err)
- return
- }
-
- future.resolve(newValue)
+ select {
+ case <-f.done:
+ f.next.active()
+ default:
}
-
- return future
+ return f.next
}
// Catch is called when Future is rejected. It returns a new Future.
@@ -82,30 +96,31 @@ func (f *Future[T]) Catch(cb func(error) (T, error)) *Future[T] {
f.mu.Lock()
defer f.mu.Unlock()
- future := &Future[T]{
- mu: sync.RWMutex{},
- next: nil,
+ f.next = &Future[T]{
+ cb: func(resolve func(T), reject func(error)) {
+ if f.result.IsOk() {
+ resolve(f.result.MustGet())
+ return
+ }
+ newValue, err := cb(f.result.Error())
+ if err != nil {
+ reject(err)
+ return
+ }
+ resolve(newValue)
+ },
cancelCb: func() {
f.Cancel()
},
+ done: make(chan struct{}),
}
- f.next = func(value T, err error) {
- if err == nil {
- future.resolve(value)
- return
- }
-
- newValue, err := cb(err)
- if err != nil {
- future.reject(err)
- return
- }
-
- future.resolve(newValue)
+ select {
+ case <-f.done:
+ f.next.active()
+ default:
}
-
- return future
+ return f.next
}
// Finally is called when Future is processed either resolved or rejected. It returns a new Future.
@@ -113,25 +128,27 @@ func (f *Future[T]) Finally(cb func(T, error) (T, error)) *Future[T] {
f.mu.Lock()
defer f.mu.Unlock()
- future := &Future[T]{
- mu: sync.RWMutex{},
- next: nil,
+ f.next = &Future[T]{
+ cb: func(resolve func(T), reject func(error)) {
+ newValue, err := cb(f.result.Get())
+ if err != nil {
+ reject(err)
+ return
+ }
+ resolve(newValue)
+ },
cancelCb: func() {
f.Cancel()
},
+ done: make(chan struct{}),
}
- f.next = func(value T, err error) {
- newValue, err := cb(value, err)
- if err != nil {
- future.reject(err)
- return
- }
-
- future.resolve(newValue)
+ select {
+ case <-f.done:
+ f.next.active()
+ default:
}
-
- return future
+ return f.next
}
// Cancel cancels the Future chain.
@@ -147,23 +164,8 @@ func (f *Future[T]) Cancel() {
// Collect awaits and return result of the Future.
func (f *Future[T]) Collect() (T, error) {
- done := make(chan struct{})
-
- var a T
- var b error
-
- f.mu.Lock()
- f.next = func(value T, err error) {
- a = value
- b = err
-
- done <- struct{}{}
- }
- f.mu.Unlock()
-
- <-done
-
- return a, b
+ <-f.done
+ return f.result.Get()
}
// Result wraps Collect and returns a Result.
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go
index ea0798d8..d06975e7 100644
--- a/vendor/github.com/spf13/afero/memmap.go
+++ b/vendor/github.com/spf13/afero/memmap.go
@@ -142,6 +142,11 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
}
m.mu.Lock()
+ // Dobule check that it doesn't exist.
+ if _, ok := m.getData()[name]; ok {
+ m.mu.Unlock()
+ return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
+ }
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
m.getData()[name] = item
diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md
index 5701422c..63413a7d 100644
--- a/vendor/github.com/spf13/viper/README.md
+++ b/vendor/github.com/spf13/viper/README.md
@@ -11,7 +11,7 @@
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spf13/viper/CI?style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
[![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper)
-![Go Version](https://img.shields.io/badge/go%20version-%3E=1.15-61CFDD.svg?style=flat-square)
+![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square)
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper)
**Go configuration with fangs!**
diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go
index 5f76cc09..5c12529b 100644
--- a/vendor/github.com/spf13/viper/viper.go
+++ b/vendor/github.com/spf13/viper/viper.go
@@ -463,9 +463,8 @@ func (v *Viper) WatchConfig() {
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
- const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if (filepath.Clean(event.Name) == configFile &&
- event.Op&writeOrCreateMask != 0) ||
+ (event.Has(fsnotify.Write) || event.Has(fsnotify.Create))) ||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
realConfigFile = currentConfigFile
err := v.ReadInConfig()
@@ -475,8 +474,7 @@ func (v *Viper) WatchConfig() {
if v.onConfigChange != nil {
v.onConfigChange(event)
}
- } else if filepath.Clean(event.Name) == configFile &&
- event.Op&fsnotify.Remove != 0 {
+ } else if filepath.Clean(event.Name) == configFile && event.Has(fsnotify.Remove) {
eventsWG.Done()
return
}
diff --git a/vendor/github.com/spf13/viper/watch.go b/vendor/github.com/spf13/viper/watch.go
index b5523b8f..1ce84eaf 100644
--- a/vendor/github.com/spf13/viper/watch.go
+++ b/vendor/github.com/spf13/viper/watch.go
@@ -1,5 +1,5 @@
-//go:build !js
-// +build !js
+//go:build darwin || dragonfly || freebsd || openbsd || linux || netbsd || solaris || windows
+// +build darwin dragonfly freebsd openbsd linux netbsd solaris windows
package viper
diff --git a/vendor/github.com/spf13/viper/watch_wasm.go b/vendor/github.com/spf13/viper/watch_unsupported.go
similarity index 52%
rename from vendor/github.com/spf13/viper/watch_wasm.go
rename to vendor/github.com/spf13/viper/watch_unsupported.go
index 8e47e6a9..7e271537 100644
--- a/vendor/github.com/spf13/viper/watch_wasm.go
+++ b/vendor/github.com/spf13/viper/watch_unsupported.go
@@ -1,13 +1,19 @@
-// +build js,wasm
+//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
+// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
package viper
import (
- "errors"
+ "fmt"
+ "runtime"
"github.com/fsnotify/fsnotify"
)
+func newWatcher() (*watcher, error) {
+ return &watcher{}, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
+}
+
type watcher struct {
Events chan fsnotify.Event
Errors chan error
@@ -24,7 +30,3 @@ func (*watcher) Add(name string) error {
func (*watcher) Remove(name string) error {
return nil
}
-
-func newWatcher() (*watcher, error) {
- return &watcher{}, errors.New("fsnotify is not supported on WASM")
-}
diff --git a/vendor/github.com/ysmood/gson/read.go b/vendor/github.com/ysmood/gson/read.go
index f1e6ae2c..8843d95e 100644
--- a/vendor/github.com/ysmood/gson/read.go
+++ b/vendor/github.com/ysmood/gson/read.go
@@ -1,3 +1,4 @@
+// Package gson A tiny JSON lib to read and alter a JSON value.
package gson
import (
@@ -22,6 +23,24 @@ func (j JSON) MarshalJSON() ([]byte, error) {
return json.Marshal(j.Val())
}
+// Unmarshal is the same as [json.Unmarshal] for the underlying raw value.
+// It should be called before other operations.
+func (j JSON) Unmarshal(v interface{}) error {
+ if j.value == nil {
+ return fmt.Errorf("gson: no value to unmarshal")
+ }
+
+ j.lock.Lock()
+ defer j.lock.Unlock()
+
+ b, ok := (*j.value).([]byte)
+ if !ok {
+ return fmt.Errorf("gson: value has been parsed")
+ }
+
+ return json.Unmarshal(b, v)
+}
+
// JSON string
func (j JSON) JSON(prefix, indent string) string {
buf := bytes.NewBuffer(nil)
@@ -33,7 +52,7 @@ func (j JSON) JSON(prefix, indent string) string {
return s[:len(s)-1]
}
-// Raw underlaying value
+// Raw underlying value
func (j JSON) Raw() interface{} {
if j.value == nil {
return nil
@@ -41,7 +60,7 @@ func (j JSON) Raw() interface{} {
return *j.value
}
-// String implements fmt.Stringer interface
+// String implements [fmt.Stringer] interface
func (j JSON) String() string {
return fmt.Sprintf("%v", j.Val())
}
diff --git a/vendor/github.com/ysmood/gson/write.go b/vendor/github.com/ysmood/gson/write.go
index 8c9dc629..9237e729 100644
--- a/vendor/github.com/ysmood/gson/write.go
+++ b/vendor/github.com/ysmood/gson/write.go
@@ -7,7 +7,7 @@ import (
"sync"
)
-// New JSON from []byte, io.Reader, or raw value.
+// New JSON from []byte, [io.Reader], or raw value.
func New(v interface{}) JSON {
return JSON{&sync.Mutex{}, &v}
}
@@ -23,7 +23,7 @@ func (j *JSON) UnmarshalJSON(b []byte) error {
return nil
}
-// Val of the underlaying json value.
+// Val of the underlying json value.
// The first time it's called, it will try to parse the underlying data.
func (j JSON) Val() interface{} {
if j.value == nil {
diff --git a/vendor/github.com/yuin/gopher-lua/_vm.go b/vendor/github.com/yuin/gopher-lua/_vm.go
index 049107e1..687fe797 100644
--- a/vendor/github.com/yuin/gopher-lua/_vm.go
+++ b/vendor/github.com/yuin/gopher-lua/_vm.go
@@ -840,7 +840,7 @@ func luaModulo(lhs, rhs LNumber) LNumber {
flhs := float64(lhs)
frhs := float64(rhs)
v := math.Mod(flhs, frhs)
- if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
+ if frhs > 0 && v < 0 || frhs < 0 && v > 0 {
v += frhs
}
return LNumber(v)
diff --git a/vendor/github.com/yuin/gopher-lua/vm.go b/vendor/github.com/yuin/gopher-lua/vm.go
index aaa04dc9..470855f2 100644
--- a/vendor/github.com/yuin/gopher-lua/vm.go
+++ b/vendor/github.com/yuin/gopher-lua/vm.go
@@ -1533,7 +1533,7 @@ func luaModulo(lhs, rhs LNumber) LNumber {
flhs := float64(lhs)
frhs := float64(rhs)
v := math.Mod(flhs, frhs)
- if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) {
+ if frhs > 0 && v < 0 || frhs < 0 && v > 0 {
v += frhs
}
return LNumber(v)
diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go
index 0c756c46..cff0cd49 100644
--- a/vendor/golang.org/x/exp/slices/slices.go
+++ b/vendor/golang.org/x/exp/slices/slices.go
@@ -128,6 +128,12 @@ func Contains[E comparable](s []E, v E) bool {
return Index(s, v) >= 0
}
+// ContainsFunc reports whether at least one
+// element e of s satisfies f(e).
+func ContainsFunc[E any](s []E, f func(E) bool) bool {
+ return IndexFunc(s, f) >= 0
+}
+
// Insert inserts the values v... into s at index i,
// returning the modified slice.
// In the returned slice r, r[i] == v[0].
@@ -165,6 +171,7 @@ func Delete[S ~[]E, E any](s S, i, j int) S {
// Replace replaces the elements s[i:j] by the given v, and returns the
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
+ _ = s[i:j] // verify that i:j is a valid subslice
tot := len(s[:i]) + len(v) + len(s[j:])
if tot <= cap(s) {
s2 := s[:tot]
@@ -192,8 +199,11 @@ func Clone[S ~[]E, E any](s S) S {
// Compact replaces consecutive runs of equal elements with a single copy.
// This is like the uniq command found on Unix.
// Compact modifies the contents of the slice s; it does not create a new slice.
+// When Compact discards m elements in total, it might not modify the elements
+// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
+// zeroing those elements so that objects they reference can be garbage collected.
func Compact[S ~[]E, E comparable](s S) S {
- if len(s) == 0 {
+ if len(s) < 2 {
return s
}
i := 1
@@ -210,7 +220,7 @@ func Compact[S ~[]E, E comparable](s S) S {
// CompactFunc is like Compact but uses a comparison function.
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
- if len(s) == 0 {
+ if len(s) < 2 {
return s
}
i := 1
diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go
index c22e74bd..35a5d8f0 100644
--- a/vendor/golang.org/x/exp/slices/sort.go
+++ b/vendor/golang.org/x/exp/slices/sort.go
@@ -30,7 +30,7 @@ func SortFunc[E any](x []E, less func(a, b E) bool) {
pdqsortLessFunc(x, 0, n, bits.Len(uint(n)), less)
}
-// SortStable sorts the slice x while keeping the original order of equal
+// SortStableFunc sorts the slice x while keeping the original order of equal
// elements, using less to compare elements.
func SortStableFunc[E any](x []E, less func(a, b E) bool) {
stableLessFunc(x, len(x), less)
diff --git a/vendor/golang.org/x/net/html/token.go b/vendor/golang.org/x/net/html/token.go
index be3c7541..ae24a6fd 100644
--- a/vendor/golang.org/x/net/html/token.go
+++ b/vendor/golang.org/x/net/html/token.go
@@ -605,7 +605,10 @@ func (z *Tokenizer) readComment() {
z.data.end = z.data.start
}
}()
- for dashCount := 2; ; {
+
+ var dashCount int
+ beginning := true
+ for {
c := z.readByte()
if z.err != nil {
// Ignore up to two dashes at EOF.
@@ -620,7 +623,7 @@ func (z *Tokenizer) readComment() {
dashCount++
continue
case '>':
- if dashCount >= 2 {
+ if dashCount >= 2 || beginning {
z.data.end = z.raw.end - len("-->")
return
}
@@ -638,6 +641,7 @@ func (z *Tokenizer) readComment() {
}
}
dashCount = 0
+ beginning = false
}
}
diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
index 453a942c..3865943f 100644
--- a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
+++ b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
@@ -52,6 +52,20 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
return msgs, nil
}
+// ParseOneSocketControlMessage parses a single socket control message from b, returning the message header,
+// message data (a slice of b), and the remainder of b after that single message.
+// When there are no remaining messages, len(remainder) == 0.
+func ParseOneSocketControlMessage(b []byte) (hdr Cmsghdr, data []byte, remainder []byte, err error) {
+ h, dbuf, err := socketControlMessageHeaderAndData(b)
+ if err != nil {
+ return Cmsghdr{}, nil, nil, err
+ }
+ if i := cmsgAlignOf(int(h.Len)); i < len(b) {
+ remainder = b[i:]
+ }
+ return *h, dbuf, remainder, nil
+}
+
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index e044d5b5..c5a98440 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1554,6 +1554,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
var iova [1]Iovec
iova[0].Base = &dummy
iova[0].SetLen(1)
+ iov = iova[:]
}
}
msg.Control = &oob[0]
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 7a6ba43a..a49853e9 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -367,6 +367,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys IsWindowUnicode(hwnd HWND) (isUnicode bool) = user32.IsWindowUnicode
//sys IsWindowVisible(hwnd HWND) (isVisible bool) = user32.IsWindowVisible
//sys GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) = user32.GetGUIThreadInfo
+//sys GetLargePageMinimum() (size uintptr)
// Volume Management Functions
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 96ba8559..ac60052e 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -252,6 +252,7 @@ var (
procGetFileType = modkernel32.NewProc("GetFileType")
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLargePageMinimum = modkernel32.NewProc("GetLargePageMinimum")
procGetLastError = modkernel32.NewProc("GetLastError")
procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW")
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
@@ -2180,6 +2181,12 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
return
}
+func GetLargePageMinimum() (size uintptr) {
+ r0, _, _ := syscall.Syscall(procGetLargePageMinimum.Addr(), 0, 0, 0, 0)
+ size = uintptr(r0)
+ return
+}
+
func GetLastError() (lasterr error) {
r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
if r0 != 0 {
diff --git a/vendor/golang.org/x/term/terminal.go b/vendor/golang.org/x/term/terminal.go
index 4b48a589..f636667f 100644
--- a/vendor/golang.org/x/term/terminal.go
+++ b/vendor/golang.org/x/term/terminal.go
@@ -233,7 +233,6 @@ func (t *Terminal) queue(data []rune) {
t.outBuf = append(t.outBuf, []byte(string(data))...)
}
-var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
var space = []rune{' '}
func isPrintable(key rune) bool {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b9ebfd6d..df9c26f3 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -15,7 +15,7 @@ github.com/andybalholm/cascadia
# github.com/antchfx/htmlquery v1.2.5
## explicit; go 1.14
github.com/antchfx/htmlquery
-# github.com/antchfx/xmlquery v1.3.12
+# github.com/antchfx/xmlquery v1.3.13
## explicit; go 1.14
github.com/antchfx/xmlquery
# github.com/antchfx/xpath v1.2.1
@@ -39,8 +39,8 @@ github.com/charmbracelet/bubbles/paginator
github.com/charmbracelet/bubbles/progress
github.com/charmbracelet/bubbles/spinner
github.com/charmbracelet/bubbles/textinput
-# github.com/charmbracelet/bubbletea v0.22.1
-## explicit; go 1.13
+# github.com/charmbracelet/bubbletea v0.23.1
+## explicit; go 1.16
github.com/charmbracelet/bubbletea
# github.com/charmbracelet/harmonica v0.2.0
## explicit; go 1.16
@@ -63,7 +63,7 @@ github.com/fatih/color
# github.com/fsnotify/fsnotify v1.6.0
## explicit; go 1.16
github.com/fsnotify/fsnotify
-# github.com/go-rod/rod v0.112.0
+# github.com/go-rod/rod v0.112.2
## explicit; go 1.16
github.com/go-rod/rod
github.com/go-rod/rod/lib/assets
@@ -121,10 +121,10 @@ github.com/hhrutter/tiff
# github.com/iancoleman/orderedmap v0.2.0
## explicit
github.com/iancoleman/orderedmap
-# github.com/inconshreveable/mousetrap v1.0.1
+# github.com/inconshreveable/mousetrap v1.1.0
## explicit; go 1.18
github.com/inconshreveable/mousetrap
-# github.com/invopop/jsonschema v0.6.0
+# github.com/invopop/jsonschema v0.7.0
## explicit; go 1.16
github.com/invopop/jsonschema
# github.com/ivanpirog/coloredcobra v1.0.1
@@ -148,8 +148,8 @@ github.com/lithammer/fuzzysearch/fuzzy
# github.com/lucasb-eyer/go-colorful v1.2.0
## explicit; go 1.12
github.com/lucasb-eyer/go-colorful
-# github.com/magiconair/properties v1.8.6
-## explicit; go 1.13
+# github.com/magiconair/properties v1.8.7
+## explicit; go 1.19
github.com/magiconair/properties
# github.com/mattn/go-colorable v0.1.13
## explicit; go 1.15
@@ -206,7 +206,7 @@ github.com/mitchellh/mapstructure
# github.com/montanaflynn/stats v0.6.6
## explicit; go 1.13
github.com/montanaflynn/stats
-# github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70
+# github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a
## explicit; go 1.17
github.com/muesli/ansi
github.com/muesli/ansi/compressor
@@ -237,16 +237,17 @@ github.com/pdfcpu/pdfcpu/pkg/types
# github.com/pelletier/go-toml v1.9.5
## explicit; go 1.12
github.com/pelletier/go-toml
-# github.com/pelletier/go-toml/v2 v2.0.5
+# github.com/pelletier/go-toml/v2 v2.0.6
## explicit; go 1.16
github.com/pelletier/go-toml/v2
-github.com/pelletier/go-toml/v2/internal/ast
+github.com/pelletier/go-toml/v2/internal/characters
github.com/pelletier/go-toml/v2/internal/danger
github.com/pelletier/go-toml/v2/internal/tracker
+github.com/pelletier/go-toml/v2/unstable
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
-# github.com/rivo/uniseg v0.4.2
+# github.com/rivo/uniseg v0.4.3
## explicit; go 1.18
github.com/rivo/uniseg
# github.com/sahilm/fuzzy v0.1.0
@@ -255,10 +256,10 @@ github.com/sahilm/fuzzy
# github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
## explicit
github.com/saintfish/chardet
-# github.com/samber/lo v1.33.0
+# github.com/samber/lo v1.37.0
## explicit; go 1.18
github.com/samber/lo
-# github.com/samber/mo v1.5.1
+# github.com/samber/mo v1.7.0
## explicit; go 1.18
github.com/samber/mo
# github.com/sirupsen/logrus v1.9.0
@@ -275,7 +276,7 @@ github.com/smartystreets/assertions/internal/oglematchers
github.com/smartystreets/goconvey/convey
github.com/smartystreets/goconvey/convey/gotest
github.com/smartystreets/goconvey/convey/reporting
-# github.com/spf13/afero v1.9.2
+# github.com/spf13/afero v1.9.3
## explicit; go 1.16
github.com/spf13/afero
github.com/spf13/afero/internal/common
@@ -292,7 +293,7 @@ github.com/spf13/jwalterweatherman
# github.com/spf13/pflag v1.0.5
## explicit; go 1.12
github.com/spf13/pflag
-# github.com/spf13/viper v1.13.0
+# github.com/spf13/viper v1.14.0
## explicit; go 1.17
github.com/spf13/viper
github.com/spf13/viper/internal/encoding
@@ -312,7 +313,7 @@ github.com/temoto/robotstxt
# github.com/ysmood/goob v0.4.0
## explicit; go 1.15
github.com/ysmood/goob
-# github.com/ysmood/gson v0.7.2
+# github.com/ysmood/gson v0.7.3
## explicit; go 1.15
github.com/ysmood/gson
# github.com/ysmood/leakless v0.8.0
@@ -323,39 +324,39 @@ github.com/ysmood/leakless/pkg/utils
# github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7
## explicit
github.com/yuin/gluamapper
-# github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
+# github.com/yuin/gopher-lua v0.0.0-20221210110428-332342483e3f
## explicit; go 1.17
github.com/yuin/gopher-lua
github.com/yuin/gopher-lua/ast
github.com/yuin/gopher-lua/parse
github.com/yuin/gopher-lua/pm
-# golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
+# golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15
## explicit; go 1.18
golang.org/x/exp/constraints
golang.org/x/exp/slices
-# golang.org/x/image v0.1.0
+# golang.org/x/image v0.2.0
## explicit; go 1.12
golang.org/x/image/ccitt
golang.org/x/image/riff
golang.org/x/image/vp8
golang.org/x/image/vp8l
golang.org/x/image/webp
-# golang.org/x/net v0.1.0
+# golang.org/x/net v0.4.0
## explicit; go 1.17
golang.org/x/net/context
golang.org/x/net/html
golang.org/x/net/html/atom
golang.org/x/net/html/charset
-# golang.org/x/sys v0.1.0
+# golang.org/x/sys v0.3.0
## explicit; go 1.17
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/term v0.1.0
+# golang.org/x/term v0.3.0
## explicit; go 1.17
golang.org/x/term
-# golang.org/x/text v0.4.0
+# golang.org/x/text v0.5.0
## explicit; go 1.17
golang.org/x/text/encoding
golang.org/x/text/encoding/charmap
diff --git a/version/version.go b/version/version.go
index 4983c304..b33551fd 100644
--- a/version/version.go
+++ b/version/version.go
@@ -14,7 +14,7 @@ import (
var versionCacher = gache.New[string](&gache.Options{
Path: filepath.Join(where.Cache(), "version.json"),
- Lifetime: time.Hour * 24,
+ Lifetime: time.Hour * 24 * 2,
FileSystem: &filesystem.GacheFs{},
})
diff --git a/where/where.go b/where/where.go
index 75da21fc..def252a4 100644
--- a/where/where.go
+++ b/where/where.go
@@ -3,6 +3,7 @@ package where
import (
"github.com/metafates/mangal/constant"
"github.com/metafates/mangal/filesystem"
+ "github.com/metafates/mangal/key"
"github.com/samber/lo"
"github.com/spf13/viper"
"os"
@@ -63,7 +64,7 @@ func History() string {
// Downloads path
// Will create the directory if it doesn't exist
func Downloads() string {
- path, err := filepath.Abs(viper.GetString(constant.DownloaderPath))
+ path, err := filepath.Abs(viper.GetString(key.DownloaderPath))
if err != nil {
path, err = os.Getwd()