From 6e2cb00008cbf09e556b00f87603797fcaa47e09 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 16 Apr 2018 05:37:14 -0700 Subject: Depenancy upgrades and movign to dep. (#8630) --- vendor/golang.org/x/text/message/catalog.go | 36 - .../golang.org/x/text/message/catalog/catalog.go | 369 ---- .../x/text/message/catalog/catalog_test.go | 296 ---- vendor/golang.org/x/text/message/catalog/dict.go | 129 -- vendor/golang.org/x/text/message/catalog/go19.go | 15 - .../golang.org/x/text/message/catalog/gopre19.go | 23 - vendor/golang.org/x/text/message/catalog_test.go | 43 - vendor/golang.org/x/text/message/doc.go | 100 -- vendor/golang.org/x/text/message/examples_test.go | 42 - vendor/golang.org/x/text/message/fmt_test.go | 1871 -------------------- vendor/golang.org/x/text/message/format.go | 510 ------ vendor/golang.org/x/text/message/message.go | 186 -- vendor/golang.org/x/text/message/message_test.go | 181 -- .../golang.org/x/text/message/pipeline/extract.go | 314 ---- .../golang.org/x/text/message/pipeline/generate.go | 314 ---- .../x/text/message/pipeline/go19_test.go | 13 - .../golang.org/x/text/message/pipeline/message.go | 241 --- .../golang.org/x/text/message/pipeline/pipeline.go | 422 ----- .../x/text/message/pipeline/pipeline_test.go | 126 -- .../golang.org/x/text/message/pipeline/rewrite.go | 268 --- .../message/pipeline/testdata/test1/catalog_gen.go | 85 - .../pipeline/testdata/test1/catalog_gen.go.want | 85 - .../pipeline/testdata/test1/catalog_test.go | 49 - .../pipeline/testdata/test1/extracted.gotext.json | 188 -- .../testdata/test1/extracted.gotext.json.want | 188 -- .../testdata/test1/locales/de/messages.gotext.json | 123 -- .../testdata/test1/locales/de/out.gotext.json | 137 -- .../testdata/test1/locales/de/out.gotext.json.want | 137 -- .../test1/locales/en-US/messages.gotext.json | 91 - .../testdata/test1/locales/en-US/out.gotext.json | 154 -- .../test1/locales/en-US/out.gotext.json.want | 154 -- .../testdata/test1/locales/zh/messages.gotext.json | 135 -- .../testdata/test1/locales/zh/out.gotext.json | 137 -- .../testdata/test1/locales/zh/out.gotext.json.want | 137 -- .../text/message/pipeline/testdata/test1/test1.go | 75 - vendor/golang.org/x/text/message/print.go | 979 ---------- 36 files changed, 8353 deletions(-) delete mode 100644 vendor/golang.org/x/text/message/catalog.go delete mode 100644 vendor/golang.org/x/text/message/catalog/catalog.go delete mode 100644 vendor/golang.org/x/text/message/catalog/catalog_test.go delete mode 100644 vendor/golang.org/x/text/message/catalog/dict.go delete mode 100644 vendor/golang.org/x/text/message/catalog/go19.go delete mode 100644 vendor/golang.org/x/text/message/catalog/gopre19.go delete mode 100644 vendor/golang.org/x/text/message/catalog_test.go delete mode 100644 vendor/golang.org/x/text/message/doc.go delete mode 100644 vendor/golang.org/x/text/message/examples_test.go delete mode 100644 vendor/golang.org/x/text/message/fmt_test.go delete mode 100644 vendor/golang.org/x/text/message/format.go delete mode 100644 vendor/golang.org/x/text/message/message.go delete mode 100644 vendor/golang.org/x/text/message/message_test.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/extract.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/generate.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/go19_test.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/message.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/pipeline.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/pipeline_test.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/rewrite.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go.want delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_test.go delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json.want delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/messages.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json.want delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/messages.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json.want delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/messages.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json delete mode 100755 vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json.want delete mode 100644 vendor/golang.org/x/text/message/pipeline/testdata/test1/test1.go delete mode 100644 vendor/golang.org/x/text/message/print.go (limited to 'vendor/golang.org/x/text/message') diff --git a/vendor/golang.org/x/text/message/catalog.go b/vendor/golang.org/x/text/message/catalog.go deleted file mode 100644 index 068271def..000000000 --- a/vendor/golang.org/x/text/message/catalog.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -// TODO: some types in this file will need to be made public at some time. -// Documentation and method names will reflect this by using the exported name. - -import ( - "golang.org/x/text/language" - "golang.org/x/text/message/catalog" -) - -// MatchLanguage reports the matched tag obtained from language.MatchStrings for -// the Matcher of the DefaultCatalog. -func MatchLanguage(preferred ...string) language.Tag { - c := DefaultCatalog - tag, _ := language.MatchStrings(c.Matcher(), preferred...) - return tag -} - -// DefaultCatalog is used by SetString. -var DefaultCatalog catalog.Catalog = defaultCatalog - -var defaultCatalog = catalog.NewBuilder() - -// SetString calls SetString on the initial default Catalog. -func SetString(tag language.Tag, key string, msg string) error { - return defaultCatalog.SetString(tag, key, msg) -} - -// Set calls Set on the initial default Catalog. -func Set(tag language.Tag, key string, msg ...catalog.Message) error { - return defaultCatalog.Set(tag, key, msg...) -} diff --git a/vendor/golang.org/x/text/message/catalog/catalog.go b/vendor/golang.org/x/text/message/catalog/catalog.go deleted file mode 100644 index 34a30d3c8..000000000 --- a/vendor/golang.org/x/text/message/catalog/catalog.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package catalog defines collections of translated format strings. -// -// This package mostly defines types for populating catalogs with messages. The -// catmsg package contains further definitions for creating custom message and -// dictionary types as well as packages that use Catalogs. -// -// Package catalog defines various interfaces: Dictionary, Loader, and Message. -// A Dictionary maintains a set of translations of format strings for a single -// language. The Loader interface defines a source of dictionaries. A -// translation of a format string is represented by a Message. -// -// -// Catalogs -// -// A Catalog defines a programmatic interface for setting message translations. -// It maintains a set of per-language dictionaries with translations for a set -// of keys. For message translation to function properly, a translation should -// be defined for each key for each supported language. A dictionary may be -// underspecified, though, if there is a parent language that already defines -// the key. For example, a Dictionary for "en-GB" could leave out entries that -// are identical to those in a dictionary for "en". -// -// -// Messages -// -// A Message is a format string which varies on the value of substitution -// variables. For instance, to indicate the number of results one could want "no -// results" if there are none, "1 result" if there is 1, and "%d results" for -// any other number. Catalog is agnostic to the kind of format strings that are -// used: for instance, messages can follow either the printf-style substitution -// from package fmt or use templates. -// -// A Message does not substitute arguments in the format string. This job is -// reserved for packages that render strings, such as message, that use Catalogs -// to selected string. This separation of concerns allows Catalog to be used to -// store any kind of formatting strings. -// -// -// Selecting messages based on linguistic features of substitution arguments -// -// Messages may vary based on any linguistic features of the argument values. -// The most common one is plural form, but others exist. -// -// Selection messages are provided in packages that provide support for a -// specific linguistic feature. The following snippet uses plural.Select: -// -// catalog.Set(language.English, "You are %d minute(s) late.", -// plural.Select(1, -// "one", "You are 1 minute late.", -// "other", "You are %d minutes late.")) -// -// In this example, a message is stored in the Catalog where one of two messages -// is selected based on the first argument, a number. The first message is -// selected if the argument is singular (identified by the selector "one") and -// the second message is selected in all other cases. The selectors are defined -// by the plural rules defined in CLDR. The selector "other" is special and will -// always match. Each language always defines one of the linguistic categories -// to be "other." For English, singular is "one" and plural is "other". -// -// Selects can be nested. This allows selecting sentences based on features of -// multiple arguments or multiple linguistic properties of a single argument. -// -// -// String interpolation -// -// There is often a lot of commonality between the possible variants of a -// message. For instance, in the example above the word "minute" varies based on -// the plural catogory of the argument, but the rest of the sentence is -// identical. Using interpolation the above message can be rewritten as: -// -// catalog.Set(language.English, "You are %d minute(s) late.", -// catalog.Var("minutes", -// plural.Select(1, "one", "minute", "other", "minutes")), -// catalog.String("You are %[1]d ${minutes} late.")) -// -// Var is defined to return the variable name if the message does not yield a -// match. This allows us to further simplify this snippet to -// -// catalog.Set(language.English, "You are %d minute(s) late.", -// catalog.Var("minutes", plural.Select(1, "one", "minute")), -// catalog.String("You are %d ${minutes} late.")) -// -// Overall this is still only a minor improvement, but things can get a lot more -// unwieldy if more than one linguistic feature is used to determine a message -// variant. Consider the following example: -// -// // argument 1: list of hosts, argument 2: list of guests -// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.", -// catalog.Var("their", -// plural.Select(1, -// "one", gender.Select(1, "female", "her", "other", "his"))), -// catalog.Var("invites", plural.Select(1, "one", "invite")) -// catalog.String("%[1]v ${invites} %[2]v to ${their} party.")), -// -// Without variable substitution, this would have to be written as -// -// // argument 1: list of hosts, argument 2: list of guests -// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.", -// plural.Select(1, -// "one", gender.Select(1, -// "female", "%[1]v invites %[2]v to her party." -// "other", "%[1]v invites %[2]v to his party."), -// "other", "%[1]v invites %[2]v to their party.") -// -// Not necessarily shorter, but using variables there is less duplication and -// the messages are more maintenance friendly. Moreover, languages may have up -// to six plural forms. This makes the use of variables more welcome. -// -// Different messages using the same inflections can reuse variables by moving -// them to macros. Using macros we can rewrite the message as: -// -// // argument 1: list of hosts, argument 2: list of guests -// catalog.SetString(language.English, "%[1]v invite(s) %[2]v to their party.", -// "%[1]v ${invites(1)} %[2]v to ${their(1)} party.") -// -// Where the following macros were defined separately. -// -// catalog.SetMacro(language.English, "invites", plural.Select(1, "one", "invite")) -// catalog.SetMacro(language.English, "their", plural.Select(1, -// "one", gender.Select(1, "female", "her", "other", "his"))), -// -// Placeholders use parentheses and the arguments to invoke a macro. -// -// -// Looking up messages -// -// Message lookup using Catalogs is typically only done by specialized packages -// and is not something the user should be concerned with. For instance, to -// express the tardiness of a user using the related message we defined earlier, -// the user may use the package message like so: -// -// p := message.NewPrinter(language.English) -// p.Printf("You are %d minute(s) late.", 5) -// -// Which would print: -// You are 5 minutes late. -// -// -// This package is UNDER CONSTRUCTION and its API may change. -package catalog // import "golang.org/x/text/message/catalog" - -// TODO: -// Some way to freeze a catalog. -// - Locking on each lockup turns out to be about 50% of the total running time -// for some of the benchmarks in the message package. -// Consider these: -// - Sequence type to support sequences in user-defined messages. -// - Garbage collection: Remove dictionaries that can no longer be reached -// as other dictionaries have been added that cover all possible keys. - -import ( - "errors" - "fmt" - - "golang.org/x/text/internal" - - "golang.org/x/text/internal/catmsg" - "golang.org/x/text/language" -) - -// A Catalog allows lookup of translated messages. -type Catalog interface { - // Languages returns all languages for which the Catalog contains variants. - Languages() []language.Tag - - // Matcher returns a Matcher for languages from this Catalog. - Matcher() language.Matcher - - // A Context is used for evaluating Messages. - Context(tag language.Tag, r catmsg.Renderer) *Context - - // This method also makes Catalog a private interface. - lookup(tag language.Tag, key string) (data string, ok bool) -} - -// NewFromMap creates a Catalog from the given map. If a Dictionary is -// underspecified the entry is retrieved from a parent language. -func NewFromMap(dictionaries map[string]Dictionary, opts ...Option) (Catalog, error) { - options := options{} - for _, o := range opts { - o(&options) - } - c := &catalog{ - dicts: map[language.Tag]Dictionary{}, - } - _, hasFallback := dictionaries[options.fallback.String()] - if hasFallback { - // TODO: Should it be okay to not have a fallback language? - // Catalog generators could enforce there is always a fallback. - c.langs = append(c.langs, options.fallback) - } - for lang, dict := range dictionaries { - tag, err := language.Parse(lang) - if err != nil { - return nil, fmt.Errorf("catalog: invalid language tag %q", lang) - } - if _, ok := c.dicts[tag]; ok { - return nil, fmt.Errorf("catalog: duplicate entry for tag %q after normalization", tag) - } - c.dicts[tag] = dict - if !hasFallback || tag != options.fallback { - c.langs = append(c.langs, tag) - } - } - if hasFallback { - internal.SortTags(c.langs[1:]) - } else { - internal.SortTags(c.langs) - } - c.matcher = language.NewMatcher(c.langs) - return c, nil -} - -// A Dictionary is a source of translations for a single language. -type Dictionary interface { - // Lookup returns a message compiled with catmsg.Compile for the given key. - // It returns false for ok if such a message could not be found. - Lookup(key string) (data string, ok bool) -} - -type catalog struct { - langs []language.Tag - dicts map[language.Tag]Dictionary - macros store - matcher language.Matcher -} - -func (c *catalog) Languages() []language.Tag { return c.langs } -func (c *catalog) Matcher() language.Matcher { return c.matcher } - -func (c *catalog) lookup(tag language.Tag, key string) (data string, ok bool) { - for ; ; tag = tag.Parent() { - if dict, ok := c.dicts[tag]; ok { - if data, ok := dict.Lookup(key); ok { - return data, true - } - } - if tag == language.Und { - break - } - } - return "", false -} - -// Context returns a Context for formatting messages. -// Only one Message may be formatted per context at any given time. -func (c *catalog) Context(tag language.Tag, r catmsg.Renderer) *Context { - return &Context{ - cat: c, - tag: tag, - dec: catmsg.NewDecoder(tag, r, &dict{&c.macros, tag}), - } -} - -// A Builder allows building a Catalog programmatically. -type Builder struct { - options - matcher language.Matcher - - index store - macros store -} - -type options struct { - fallback language.Tag -} - -// An Option configures Catalog behavior. -type Option func(*options) - -// Fallback specifies the default fallback language. The default is Und. -func Fallback(tag language.Tag) Option { - return func(o *options) { o.fallback = tag } -} - -// TODO: -// // Catalogs specifies one or more sources for a Catalog. -// // Lookups are in order. -// // This can be changed inserting a Catalog used for setting, which implements -// // Loader, used for setting in the chain. -// func Catalogs(d ...Loader) Option { -// return nil -// } -// -// func Delims(start, end string) Option {} -// -// func Dict(tag language.Tag, d ...Dictionary) Option - -// NewBuilder returns an empty mutable Catalog. -func NewBuilder(opts ...Option) *Builder { - c := &Builder{} - for _, o := range opts { - o(&c.options) - } - return c -} - -// SetString is shorthand for Set(tag, key, String(msg)). -func (c *Builder) SetString(tag language.Tag, key string, msg string) error { - return c.set(tag, key, &c.index, String(msg)) -} - -// Set sets the translation for the given language and key. -// -// When evaluation this message, the first Message in the sequence to msgs to -// evaluate to a string will be the message returned. -func (c *Builder) Set(tag language.Tag, key string, msg ...Message) error { - return c.set(tag, key, &c.index, msg...) -} - -// SetMacro defines a Message that may be substituted in another message. -// The arguments to a macro Message are passed as arguments in the -// placeholder the form "${foo(arg1, arg2)}". -func (c *Builder) SetMacro(tag language.Tag, name string, msg ...Message) error { - return c.set(tag, name, &c.macros, msg...) -} - -// ErrNotFound indicates there was no message for the given key. -var ErrNotFound = errors.New("catalog: message not found") - -// String specifies a plain message string. It can be used as fallback if no -// other strings match or as a simple standalone message. -// -// It is an error to pass more than one String in a message sequence. -func String(name string) Message { - return catmsg.String(name) -} - -// Var sets a variable that may be substituted in formatting patterns using -// named substitution of the form "${name}". The name argument is used as a -// fallback if the statements do not produce a match. The statement sequence may -// not contain any Var calls. -// -// The name passed to a Var must be unique within message sequence. -func Var(name string, msg ...Message) Message { - return &catmsg.Var{Name: name, Message: firstInSequence(msg)} -} - -// Context returns a Context for formatting messages. -// Only one Message may be formatted per context at any given time. -func (b *Builder) Context(tag language.Tag, r catmsg.Renderer) *Context { - return &Context{ - cat: b, - tag: tag, - dec: catmsg.NewDecoder(tag, r, &dict{&b.macros, tag}), - } -} - -// A Context is used for evaluating Messages. -// Only one Message may be formatted per context at any given time. -type Context struct { - cat Catalog - tag language.Tag // TODO: use compact index. - dec *catmsg.Decoder -} - -// Execute looks up and executes the message with the given key. -// It returns ErrNotFound if no message could be found in the index. -func (c *Context) Execute(key string) error { - data, ok := c.cat.lookup(c.tag, key) - if !ok { - return ErrNotFound - } - return c.dec.Execute(data) -} diff --git a/vendor/golang.org/x/text/message/catalog/catalog_test.go b/vendor/golang.org/x/text/message/catalog/catalog_test.go deleted file mode 100644 index 08bfdc7ce..000000000 --- a/vendor/golang.org/x/text/message/catalog/catalog_test.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package catalog - -import ( - "bytes" - "path" - "reflect" - "strings" - "testing" - - "golang.org/x/text/internal/catmsg" - "golang.org/x/text/language" -) - -type entry struct { - tag, key string - msg interface{} -} - -func langs(s string) []language.Tag { - t, _, _ := language.ParseAcceptLanguage(s) - return t -} - -type testCase struct { - desc string - cat []entry - lookup []entry - fallback string - match []string - tags []language.Tag -} - -var testCases = []testCase{{ - desc: "empty catalog", - lookup: []entry{ - {"en", "key", ""}, - {"en", "", ""}, - {"nl", "", ""}, - }, - match: []string{ - "gr -> und", - "en-US -> und", - "af -> und", - }, - tags: nil, // not an empty list. -}, { - desc: "one entry", - cat: []entry{ - {"en", "hello", "Hello!"}, - }, - lookup: []entry{ - {"und", "hello", ""}, - {"nl", "hello", ""}, - {"en", "hello", "Hello!"}, - {"en-US", "hello", "Hello!"}, - {"en-GB", "hello", "Hello!"}, - {"en-oxendict", "hello", "Hello!"}, - {"en-oxendict-u-ms-metric", "hello", "Hello!"}, - }, - match: []string{ - "gr -> en", - "en-US -> en", - }, - tags: langs("en"), -}, { - desc: "hierarchical languages", - cat: []entry{ - {"en", "hello", "Hello!"}, - {"en-GB", "hello", "Hellø!"}, - {"en-US", "hello", "Howdy!"}, - {"en", "greetings", "Greetings!"}, - {"gsw", "hello", "Grüetzi!"}, - }, - lookup: []entry{ - {"und", "hello", ""}, - {"nl", "hello", ""}, - {"en", "hello", "Hello!"}, - {"en-US", "hello", "Howdy!"}, - {"en-GB", "hello", "Hellø!"}, - {"en-oxendict", "hello", "Hello!"}, - {"en-US-oxendict-u-ms-metric", "hello", "Howdy!"}, - - {"und", "greetings", ""}, - {"nl", "greetings", ""}, - {"en", "greetings", "Greetings!"}, - {"en-US", "greetings", "Greetings!"}, - {"en-GB", "greetings", "Greetings!"}, - {"en-oxendict", "greetings", "Greetings!"}, - {"en-US-oxendict-u-ms-metric", "greetings", "Greetings!"}, - }, - fallback: "gsw", - match: []string{ - "gr -> gsw", - "en-US -> en-US", - }, - tags: langs("gsw, en, en-GB, en-US"), -}, { - desc: "variables", - cat: []entry{ - {"en", "hello %s", []Message{ - Var("person", String("Jane")), - String("Hello ${person}!"), - }}, - {"en", "hello error", []Message{ - Var("person", String("Jane")), - noMatchMessage{}, // trigger sequence path. - String("Hello ${person."), - }}, - {"en", "fallback to var value", []Message{ - Var("you", noMatchMessage{}, noMatchMessage{}), - String("Hello ${you}."), - }}, - {"en", "scopes", []Message{ - Var("person1", String("Mark")), - Var("person2", String("Jane")), - Var("couple", - Var("person1", String("Joe")), - String("${person1} and ${person2}")), - String("Hello ${couple}."), - }}, - {"en", "missing var", String("Hello ${missing}.")}, - }, - lookup: []entry{ - {"en", "hello %s", "Hello Jane!"}, - {"en", "hello error", "Hello $!(MISSINGBRACE)"}, - {"en", "fallback to var value", "Hello you."}, - {"en", "scopes", "Hello Joe and Jane."}, - {"en", "missing var", "Hello missing."}, - }, - tags: langs("en"), -}, { - desc: "macros", - cat: []entry{ - {"en", "macro1", String("Hello ${macro1(1)}.")}, - {"en", "macro2", String("Hello ${ macro1(2) }!")}, - {"en", "macroWS", String("Hello ${ macro1( 2 ) }!")}, - {"en", "missing", String("Hello ${ missing(1 }.")}, - {"en", "badnum", String("Hello ${ badnum(1b) }.")}, - {"en", "undefined", String("Hello ${ undefined(1) }.")}, - {"en", "macroU", String("Hello ${ macroU(2) }!")}, - }, - lookup: []entry{ - {"en", "macro1", "Hello Joe."}, - {"en", "macro2", "Hello Joe!"}, - {"en-US", "macroWS", "Hello Joe!"}, - {"en-NL", "missing", "Hello $!(MISSINGPAREN)."}, - {"en", "badnum", "Hello $!(BADNUM)."}, - {"en", "undefined", "Hello undefined."}, - {"en", "macroU", "Hello macroU!"}, - }, - tags: langs("en"), -}} - -func setMacros(b *Builder) { - b.SetMacro(language.English, "macro1", String("Joe")) - b.SetMacro(language.Und, "macro2", String("${macro1(1)}")) - b.SetMacro(language.English, "macroU", noMatchMessage{}) -} - -type buildFunc func(t *testing.T, tc testCase) Catalog - -func initBuilder(t *testing.T, tc testCase) Catalog { - options := []Option{} - if tc.fallback != "" { - options = append(options, Fallback(language.MustParse(tc.fallback))) - } - cat := NewBuilder(options...) - for _, e := range tc.cat { - tag := language.MustParse(e.tag) - switch msg := e.msg.(type) { - case string: - - cat.SetString(tag, e.key, msg) - case Message: - cat.Set(tag, e.key, msg) - case []Message: - cat.Set(tag, e.key, msg...) - } - } - setMacros(cat) - return cat -} - -type dictionary map[string]string - -func (d dictionary) Lookup(key string) (data string, ok bool) { - data, ok = d[key] - return data, ok -} - -func initCatalog(t *testing.T, tc testCase) Catalog { - m := map[string]Dictionary{} - for _, e := range tc.cat { - m[e.tag] = dictionary{} - } - for _, e := range tc.cat { - var msg Message - switch x := e.msg.(type) { - case string: - msg = String(x) - case Message: - msg = x - case []Message: - msg = firstInSequence(x) - } - data, _ := catmsg.Compile(language.MustParse(e.tag), nil, msg) - m[e.tag].(dictionary)[e.key] = data - } - options := []Option{} - if tc.fallback != "" { - options = append(options, Fallback(language.MustParse(tc.fallback))) - } - c, err := NewFromMap(m, options...) - if err != nil { - t.Fatal(err) - } - // TODO: implement macros for fixed catalogs. - b := NewBuilder() - setMacros(b) - c.(*catalog).macros.index = b.macros.index - return c -} - -func TestMatcher(t *testing.T) { - test := func(t *testing.T, init buildFunc) { - for _, tc := range testCases { - for _, s := range tc.match { - a := strings.Split(s, "->") - t.Run(path.Join(tc.desc, a[0]), func(t *testing.T) { - cat := init(t, tc) - got, _ := language.MatchStrings(cat.Matcher(), a[0]) - want := language.MustParse(strings.TrimSpace(a[1])) - if got != want { - t.Errorf("got %q; want %q", got, want) - } - }) - } - } - } - t.Run("Builder", func(t *testing.T) { test(t, initBuilder) }) - t.Run("Catalog", func(t *testing.T) { test(t, initCatalog) }) -} - -func TestCatalog(t *testing.T) { - test := func(t *testing.T, init buildFunc) { - for _, tc := range testCases { - cat := init(t, tc) - wantTags := tc.tags - if got := cat.Languages(); !reflect.DeepEqual(got, wantTags) { - t.Errorf("%s:Languages: got %v; want %v", tc.desc, got, wantTags) - } - - for _, e := range tc.lookup { - t.Run(path.Join(tc.desc, e.tag, e.key), func(t *testing.T) { - tag := language.MustParse(e.tag) - buf := testRenderer{} - ctx := cat.Context(tag, &buf) - want := e.msg.(string) - err := ctx.Execute(e.key) - gotFound := err != ErrNotFound - wantFound := want != "" - if gotFound != wantFound { - t.Fatalf("err: got %v (%v); want %v", gotFound, err, wantFound) - } - if got := buf.buf.String(); got != want { - t.Errorf("Lookup:\ngot %q\nwant %q", got, want) - } - }) - } - } - } - t.Run("Builder", func(t *testing.T) { test(t, initBuilder) }) - t.Run("Catalog", func(t *testing.T) { test(t, initCatalog) }) -} - -type testRenderer struct { - buf bytes.Buffer -} - -func (f *testRenderer) Arg(i int) interface{} { return nil } -func (f *testRenderer) Render(s string) { f.buf.WriteString(s) } - -var msgNoMatch = catmsg.Register("no match", func(d *catmsg.Decoder) bool { - return false // no match -}) - -type noMatchMessage struct{} - -func (noMatchMessage) Compile(e *catmsg.Encoder) error { - e.EncodeMessageType(msgNoMatch) - return catmsg.ErrIncomplete -} diff --git a/vendor/golang.org/x/text/message/catalog/dict.go b/vendor/golang.org/x/text/message/catalog/dict.go deleted file mode 100644 index a0eb81810..000000000 --- a/vendor/golang.org/x/text/message/catalog/dict.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package catalog - -import ( - "sync" - - "golang.org/x/text/internal" - "golang.org/x/text/internal/catmsg" - "golang.org/x/text/language" -) - -// TODO: -// Dictionary returns a Dictionary that returns the first Message, using the -// given language tag, that matches: -// 1. the last one registered by one of the Set methods -// 2. returned by one of the Loaders -// 3. repeat from 1. using the parent language -// This approach allows messages to be underspecified. -// func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) { -// // TODO: verify dictionary exists. -// return &dict{&c.index, tag}, nil -// } - -type dict struct { - s *store - tag language.Tag // TODO: make compact tag. -} - -func (d *dict) Lookup(key string) (data string, ok bool) { - return d.s.lookup(d.tag, key) -} - -func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) { - return b.index.lookup(tag, key) -} - -func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error { - data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg)) - - s.mutex.Lock() - defer s.mutex.Unlock() - - m := s.index[tag] - if m == nil { - m = msgMap{} - if s.index == nil { - s.index = map[language.Tag]msgMap{} - } - c.matcher = nil - s.index[tag] = m - } - - m[key] = data - return err -} - -func (c *Builder) Matcher() language.Matcher { - c.index.mutex.RLock() - m := c.matcher - c.index.mutex.RUnlock() - if m != nil { - return m - } - - c.index.mutex.Lock() - if c.matcher == nil { - c.matcher = language.NewMatcher(c.unlockedLanguages()) - } - m = c.matcher - c.index.mutex.Unlock() - return m -} - -type store struct { - mutex sync.RWMutex - index map[language.Tag]msgMap -} - -type msgMap map[string]string - -func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) { - s.mutex.RLock() - defer s.mutex.RUnlock() - - for ; ; tag = tag.Parent() { - if msgs, ok := s.index[tag]; ok { - if msg, ok := msgs[key]; ok { - return msg, true - } - } - if tag == language.Und { - break - } - } - return "", false -} - -// Languages returns all languages for which the Catalog contains variants. -func (b *Builder) Languages() []language.Tag { - s := &b.index - s.mutex.RLock() - defer s.mutex.RUnlock() - - return b.unlockedLanguages() -} - -func (b *Builder) unlockedLanguages() []language.Tag { - s := &b.index - if len(s.index) == 0 { - return nil - } - tags := make([]language.Tag, 0, len(s.index)) - _, hasFallback := s.index[b.options.fallback] - offset := 0 - if hasFallback { - tags = append(tags, b.options.fallback) - offset = 1 - } - for t := range s.index { - if t != b.options.fallback { - tags = append(tags, t) - } - } - internal.SortTags(tags[offset:]) - return tags -} diff --git a/vendor/golang.org/x/text/message/catalog/go19.go b/vendor/golang.org/x/text/message/catalog/go19.go deleted file mode 100644 index 147fc7cf5..000000000 --- a/vendor/golang.org/x/text/message/catalog/go19.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.9 - -package catalog - -import "golang.org/x/text/internal/catmsg" - -// A Message holds a collection of translations for the same phrase that may -// vary based on the values of substitution arguments. -type Message = catmsg.Message - -type firstInSequence = catmsg.FirstOf diff --git a/vendor/golang.org/x/text/message/catalog/gopre19.go b/vendor/golang.org/x/text/message/catalog/gopre19.go deleted file mode 100644 index a9753b905..000000000 --- a/vendor/golang.org/x/text/message/catalog/gopre19.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.9 - -package catalog - -import "golang.org/x/text/internal/catmsg" - -// A Message holds a collection of translations for the same phrase that may -// vary based on the values of substitution arguments. -type Message interface { - catmsg.Message -} - -func firstInSequence(m []Message) catmsg.Message { - a := []catmsg.Message{} - for _, m := range m { - a = append(a, m) - } - return catmsg.FirstOf(a) -} diff --git a/vendor/golang.org/x/text/message/catalog_test.go b/vendor/golang.org/x/text/message/catalog_test.go deleted file mode 100644 index 7a2301c0e..000000000 --- a/vendor/golang.org/x/text/message/catalog_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -import ( - "strings" - "testing" - - "golang.org/x/text/language" - "golang.org/x/text/message/catalog" -) - -func TestMatchLanguage(t *testing.T) { - c := catalog.NewBuilder(catalog.Fallback(language.English)) - c.SetString(language.Bengali, "", "") - c.SetString(language.English, "", "") - c.SetString(language.German, "", "") - - testCases := []struct { - args string // '|'-separated list - want string - }{{ - args: "de-CH", - want: "de", - }, { - args: "bn-u-nu-latn|en-US,en;q=0.9,de;q=0.8,nl;q=0.7", - want: "bn-u-nu-latn", - }, { - args: "gr", - want: "en", - }} - for _, tc := range testCases { - DefaultCatalog = c - t.Run(tc.args, func(t *testing.T) { - got := MatchLanguage(strings.Split(tc.args, "|")...) - if got != language.Make(tc.want) { - t.Errorf("got %q; want %q", got, tc.want) - } - }) - } -} diff --git a/vendor/golang.org/x/text/message/doc.go b/vendor/golang.org/x/text/message/doc.go deleted file mode 100644 index 2f7effd25..000000000 --- a/vendor/golang.org/x/text/message/doc.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package message implements formatted I/O for localized strings with functions -// analogous to the fmt's print functions. It is a drop-in replacement for fmt. -// -// -// Localized Formatting -// -// A format string can be localized by replacing any of the print functions of -// fmt with an equivalent call to a Printer. -// -// p := message.NewPrinter(message.MatchLanguage("en")) -// p.Println(123456.78) // Prints 123,456.78 -// -// p.Printf("%d ducks in a row", 4331) // Prints 4,331 ducks in a row -// -// p := message.NewPrinter(message.MatchLanguage("nl")) -// p.Println("Hoogte: %f meter", 1244.9) // Prints Hoogte: 1.244,9 meter -// -// p := message.NewPrinter(message.MatchLanguage("bn")) -// p.Println(123456.78) // Prints ১,২৩,৪৫৬.৭৮ -// -// Printer currently supports numbers and specialized types for which packages -// exist in x/text. Other builtin types such as time.Time and slices are -// planned. -// -// Format strings largely have the same meaning as with fmt with the following -// notable exceptions: -// - flag # always resorts to fmt for printing -// - verb 'f', 'e', 'g', 'd' use localized formatting unless the '#' flag is -// specified. -// -// See package fmt for more options. -// -// -// Translation -// -// The format strings that are passed to Printf, Sprintf, Fprintf, or Errorf -// are used as keys to look up translations for the specified languages. -// More on how these need to be specified below. -// -// One can use arbitrary keys to distinguish between otherwise ambiguous -// strings: -// p := message.NewPrinter(language.English) -// p.Printf("archive(noun)") // Prints "archive" -// p.Printf("archive(verb)") // Prints "archive" -// -// p := message.NewPrinter(language.German) -// p.Printf("archive(noun)") // Prints "Archiv" -// p.Printf("archive(verb)") // Prints "archivieren" -// -// To retain the fallback functionality, use Key: -// p.Printf(message.Key("archive(noun)", "archive")) -// p.Printf(message.Key("archive(verb)", "archive")) -// -// -// Translation Pipeline -// -// Format strings that contain text need to be translated to support different -// locales. The first step is to extract strings that need to be translated. -// -// 1. Install gotext -// go get -u golang.org/x/text/cmd/gotext -// gotext -help -// -// 2. Mark strings in your source to be translated by using message.Printer, -// instead of the functions of the fmt package. -// -// 3. Extract the strings from your source -// -// gotext extract -// -// The output will be written to the textdata directory. -// -// 4. Send the files for translation -// -// It is planned to support multiple formats, but for now one will have to -// rewrite the JSON output to the desired format. -// -// 5. Inject translations into program -// -// 6. Repeat from 2 -// -// Right now this has to be done programmatically with calls to Set or -// SetString. These functions as well as the methods defined in -// see also package golang.org/x/text/message/catalog can be used to implement -// either dynamic or static loading of messages. -// -// -// Plural and Gender Forms -// -// Translated messages can vary based on the plural and gender forms of -// substitution values. In general, it is up to the translators to provide -// alternative translations for such forms. See the packages in -// golang.org/x/text/feature and golang.org/x/text/message/catalog for more -// information. -// -package message diff --git a/vendor/golang.org/x/text/message/examples_test.go b/vendor/golang.org/x/text/message/examples_test.go deleted file mode 100644 index c73eaf90b..000000000 --- a/vendor/golang.org/x/text/message/examples_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message_test - -import ( - "net/http" - - "golang.org/x/text/language" - "golang.org/x/text/message" -) - -func Example_http() { - // languages supported by this service: - matcher := language.NewMatcher(message.DefaultCatalog.Languages()) - - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - lang, _ := r.Cookie("lang") - accept := r.Header.Get("Accept-Language") - fallback := "en" - tag, _ := language.MatchStrings(matcher, lang.String(), accept, fallback) - - p := message.NewPrinter(tag) - - p.Fprintln(w, "User language is", tag) - }) -} - -func ExamplePrinter_numbers() { - for _, lang := range []string{"en", "de", "de-CH", "fr", "bn"} { - p := message.NewPrinter(language.Make(lang)) - p.Printf("%-6s %g\n", lang, 123456.78) - } - - // Output: - // en 123,456.78 - // de 123.456,78 - // de-CH 123’456.78 - // fr 123 456,78 - // bn ১,২৩,৪৫৬.৭৮ -} diff --git a/vendor/golang.org/x/text/message/fmt_test.go b/vendor/golang.org/x/text/message/fmt_test.go deleted file mode 100644 index 2d6872bf8..000000000 --- a/vendor/golang.org/x/text/message/fmt_test.go +++ /dev/null @@ -1,1871 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -import ( - "bytes" - "fmt" - "io" - "math" - "reflect" - "runtime" - "strings" - "testing" - "time" - - "golang.org/x/text/language" -) - -type ( - renamedBool bool - renamedInt int - renamedInt8 int8 - renamedInt16 int16 - renamedInt32 int32 - renamedInt64 int64 - renamedUint uint - renamedUint8 uint8 - renamedUint16 uint16 - renamedUint32 uint32 - renamedUint64 uint64 - renamedUintptr uintptr - renamedString string - renamedBytes []byte - renamedFloat32 float32 - renamedFloat64 float64 - renamedComplex64 complex64 - renamedComplex128 complex128 -) - -func TestFmtInterface(t *testing.T) { - p := NewPrinter(language.Und) - var i1 interface{} - i1 = "abc" - s := p.Sprintf("%s", i1) - if s != "abc" { - t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc") - } -} - -var ( - NaN = math.NaN() - posInf = math.Inf(1) - negInf = math.Inf(-1) - - intVar = 0 - - array = [5]int{1, 2, 3, 4, 5} - iarray = [4]interface{}{1, "hello", 2.5, nil} - slice = array[:] - islice = iarray[:] -) - -type A struct { - i int - j uint - s string - x []int -} - -type I int - -func (i I) String() string { - p := NewPrinter(language.Und) - return p.Sprintf("<%d>", int(i)) -} - -type B struct { - I I - j int -} - -type C struct { - i int - B -} - -type F int - -func (f F) Format(s fmt.State, c rune) { - p := NewPrinter(language.Und) - p.Fprintf(s, "<%c=F(%d)>", c, int(f)) -} - -type G int - -func (g G) GoString() string { - p := NewPrinter(language.Und) - return p.Sprintf("GoString(%d)", int(g)) -} - -type S struct { - F F // a struct field that Formats - G G // a struct field that GoStrings -} - -type SI struct { - I interface{} -} - -// P is a type with a String method with pointer receiver for testing %p. -type P int - -var pValue P - -func (p *P) String() string { - return "String(p)" -} - -var barray = [5]renamedUint8{1, 2, 3, 4, 5} -var bslice = barray[:] - -type byteStringer byte - -func (byteStringer) String() string { - return "X" -} - -var byteStringerSlice = []byteStringer{'h', 'e', 'l', 'l', 'o'} - -type byteFormatter byte - -func (byteFormatter) Format(f fmt.State, _ rune) { - p := NewPrinter(language.Und) - p.Fprint(f, "X") -} - -var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'} - -var fmtTests = []struct { - fmt string - val interface{} - out string -}{ - // The behavior of the following tests differs from that of the fmt package. - - // Unlike with the fmt package, it is okay to have extra arguments for - // strings without format parameters. This is because it is impossible to - // distinguish between reordered or ordered format strings in this case. - // (For reordered format strings it is okay to not use arguments.) - {"", nil, ""}, - {"", 2, ""}, - {"no args", "hello", "no args"}, - - {"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)"}, - {"%184467440737095516170v", 0, "%!(NOVERB)"}, - // Extra argument errors should format without flags set. - {"%010.2", "12345", "%!(NOVERB)"}, - - // Some key other differences, asides from localized values: - // - NaN values should not use affixes; so no signs (CLDR requirement) - // - Infinity uses patterns, so signs may be different (CLDR requirement) - // - The # flag is used to disable localization. - - // All following tests are analogous to those of the fmt package, but with - // localized numbers when appropriate. - {"%d", 12345, "12,345"}, - {"%v", 12345, "12,345"}, - {"%t", true, "true"}, - - // basic string - {"%s", "abc", "abc"}, - {"%q", "abc", `"abc"`}, - {"%x", "abc", "616263"}, - {"%x", "\xff\xf0\x0f\xff", "fff00fff"}, - {"%X", "\xff\xf0\x0f\xff", "FFF00FFF"}, - {"%x", "", ""}, - {"% x", "", ""}, - {"%#x", "", ""}, - {"%# x", "", ""}, - {"%x", "xyz", "78797a"}, - {"%X", "xyz", "78797A"}, - {"% x", "xyz", "78 79 7a"}, - {"% X", "xyz", "78 79 7A"}, - {"%#x", "xyz", "0x78797a"}, - {"%#X", "xyz", "0X78797A"}, - {"%# x", "xyz", "0x78 0x79 0x7a"}, - {"%# X", "xyz", "0X78 0X79 0X7A"}, - - // basic bytes - {"%s", []byte("abc"), "abc"}, - {"%s", [3]byte{'a', 'b', 'c'}, "abc"}, - {"%s", &[3]byte{'a', 'b', 'c'}, "&abc"}, - {"%q", []byte("abc"), `"abc"`}, - {"%x", []byte("abc"), "616263"}, - {"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"}, - {"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"}, - {"%x", []byte(""), ""}, - {"% x", []byte(""), ""}, - {"%#x", []byte(""), ""}, - {"%# x", []byte(""), ""}, - {"%x", []byte("xyz"), "78797a"}, - {"%X", []byte("xyz"), "78797A"}, - {"% x", []byte("xyz"), "78 79 7a"}, - {"% X", []byte("xyz"), "78 79 7A"}, - {"%#x", []byte("xyz"), "0x78797a"}, - {"%#X", []byte("xyz"), "0X78797A"}, - {"%# x", []byte("xyz"), "0x78 0x79 0x7a"}, - {"%# X", []byte("xyz"), "0X78 0X79 0X7A"}, - - // escaped strings - {"%q", "", `""`}, - {"%#q", "", "``"}, - {"%q", "\"", `"\""`}, - {"%#q", "\"", "`\"`"}, - {"%q", "`", `"` + "`" + `"`}, - {"%#q", "`", `"` + "`" + `"`}, - {"%q", "\n", `"\n"`}, - {"%#q", "\n", `"\n"`}, - {"%q", `\n`, `"\\n"`}, - {"%#q", `\n`, "`\\n`"}, - {"%q", "abc", `"abc"`}, - {"%#q", "abc", "`abc`"}, - {"%q", "日本語", `"日本語"`}, - {"%+q", "日本語", `"\u65e5\u672c\u8a9e"`}, - {"%#q", "日本語", "`日本語`"}, - {"%#+q", "日本語", "`日本語`"}, - {"%q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, - {"%+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, - {"%#q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, - {"%#+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, - {"%q", "☺", `"☺"`}, - {"% q", "☺", `"☺"`}, // The space modifier should have no effect. - {"%+q", "☺", `"\u263a"`}, - {"%#q", "☺", "`☺`"}, - {"%#+q", "☺", "`☺`"}, - {"%10q", "⌘", ` "⌘"`}, - {"%+10q", "⌘", ` "\u2318"`}, - {"%-10q", "⌘", `"⌘" `}, - {"%+-10q", "⌘", `"\u2318" `}, - {"%010q", "⌘", `0000000"⌘"`}, - {"%+010q", "⌘", `00"\u2318"`}, - {"%-010q", "⌘", `"⌘" `}, // 0 has no effect when - is present. - {"%+-010q", "⌘", `"\u2318" `}, - {"%#8q", "\n", ` "\n"`}, - {"%#+8q", "\r", ` "\r"`}, - {"%#-8q", "\t", "` ` "}, - {"%#+-8q", "\b", `"\b" `}, - {"%q", "abc\xffdef", `"abc\xffdef"`}, - {"%+q", "abc\xffdef", `"abc\xffdef"`}, - {"%#q", "abc\xffdef", `"abc\xffdef"`}, - {"%#+q", "abc\xffdef", `"abc\xffdef"`}, - // Runes that are not printable. - {"%q", "\U0010ffff", `"\U0010ffff"`}, - {"%+q", "\U0010ffff", `"\U0010ffff"`}, - {"%#q", "\U0010ffff", "`􏿿`"}, - {"%#+q", "\U0010ffff", "`􏿿`"}, - // Runes that are not valid. - {"%q", string(0x110000), `"�"`}, - {"%+q", string(0x110000), `"\ufffd"`}, - {"%#q", string(0x110000), "`�`"}, - {"%#+q", string(0x110000), "`�`"}, - - // characters - {"%c", uint('x'), "x"}, - {"%c", 0xe4, "ä"}, - {"%c", 0x672c, "本"}, - {"%c", '日', "日"}, - {"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect. - {"%3c", '⌘', " ⌘"}, - {"%-3c", '⌘', "⌘ "}, - // Runes that are not printable. - {"%c", '\U00000e00', "\u0e00"}, - {"%c", '\U0010ffff', "\U0010ffff"}, - // Runes that are not valid. - {"%c", -1, "�"}, - {"%c", 0xDC80, "�"}, - {"%c", rune(0x110000), "�"}, - {"%c", int64(0xFFFFFFFFF), "�"}, - {"%c", uint64(0xFFFFFFFFF), "�"}, - - // escaped characters - {"%q", uint(0), `'\x00'`}, - {"%+q", uint(0), `'\x00'`}, - {"%q", '"', `'"'`}, - {"%+q", '"', `'"'`}, - {"%q", '\'', `'\''`}, - {"%+q", '\'', `'\''`}, - {"%q", '`', "'`'"}, - {"%+q", '`', "'`'"}, - {"%q", 'x', `'x'`}, - {"%+q", 'x', `'x'`}, - {"%q", 'ÿ', `'ÿ'`}, - {"%+q", 'ÿ', `'\u00ff'`}, - {"%q", '\n', `'\n'`}, - {"%+q", '\n', `'\n'`}, - {"%q", '☺', `'☺'`}, - {"%+q", '☺', `'\u263a'`}, - {"% q", '☺', `'☺'`}, // The space modifier should have no effect. - {"%.0q", '☺', `'☺'`}, // Specifying precision should have no effect. - {"%10q", '⌘', ` '⌘'`}, - {"%+10q", '⌘', ` '\u2318'`}, - {"%-10q", '⌘', `'⌘' `}, - {"%+-10q", '⌘', `'\u2318' `}, - {"%010q", '⌘', `0000000'⌘'`}, - {"%+010q", '⌘', `00'\u2318'`}, - {"%-010q", '⌘', `'⌘' `}, // 0 has no effect when - is present. - {"%+-010q", '⌘', `'\u2318' `}, - // Runes that are not printable. - {"%q", '\U00000e00', `'\u0e00'`}, - {"%q", '\U0010ffff', `'\U0010ffff'`}, - // Runes that are not valid. - {"%q", int32(-1), "%!q(int32=-1)"}, - {"%q", 0xDC80, `'�'`}, - {"%q", rune(0x110000), "%!q(int32=1,114,112)"}, - {"%q", int64(0xFFFFFFFFF), "%!q(int64=68,719,476,735)"}, - {"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68,719,476,735)"}, - - // width - {"%5s", "abc", " abc"}, - {"%2s", "\u263a", " ☺"}, - {"%-5s", "abc", "abc "}, - {"%-8q", "abc", `"abc" `}, - {"%05s", "abc", "00abc"}, - {"%08q", "abc", `000"abc"`}, - {"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"}, - {"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"}, - {"%.0s", "日本語日本語", ""}, - {"%.5s", "日本語日本語", "日本語日本"}, - {"%.10s", "日本語日本語", "日本語日本語"}, - {"%.5s", []byte("日本語日本語"), "日本語日本"}, - {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`}, - {"%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"}, - {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`}, - {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), "6162636465"}, - {"%.3q", "日本語日本語", `"日本語"`}, - {"%.3q", []byte("日本語日本語"), `"日本語"`}, - {"%.1q", "日本語", `"日"`}, - {"%.1q", []byte("日本語"), `"日"`}, - {"%.1x", "日本語", "e6"}, - {"%.1X", []byte("日本語"), "E6"}, - {"%10.1q", "日本語日本語", ` "日"`}, - {"%10v", nil, " "}, - {"%-10v", nil, " "}, - - // integers - {"%d", uint(12345), "12,345"}, - {"%d", int(-12345), "-12,345"}, - {"%d", ^uint8(0), "255"}, - {"%d", ^uint16(0), "65,535"}, - {"%d", ^uint32(0), "4,294,967,295"}, - {"%d", ^uint64(0), "18,446,744,073,709,551,615"}, - {"%d", int8(-1 << 7), "-128"}, - {"%d", int16(-1 << 15), "-32,768"}, - {"%d", int32(-1 << 31), "-2,147,483,648"}, - {"%d", int64(-1 << 63), "-9,223,372,036,854,775,808"}, - {"%.d", 0, ""}, - {"%.0d", 0, ""}, - {"%6.0d", 0, " "}, - {"%06.0d", 0, " "}, - {"% d", 12345, " 12,345"}, - {"%+d", 12345, "+12,345"}, - {"%+d", -12345, "-12,345"}, - {"%b", 7, "111"}, - {"%b", -6, "-110"}, - {"%b", ^uint32(0), "11111111111111111111111111111111"}, - {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"}, - {"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, - {"%o", 01234, "1234"}, - {"%#o", 01234, "01234"}, - {"%o", ^uint32(0), "37777777777"}, - {"%o", ^uint64(0), "1777777777777777777777"}, - {"%#X", 0, "0X0"}, - {"%x", 0x12abcdef, "12abcdef"}, - {"%X", 0x12abcdef, "12ABCDEF"}, - {"%x", ^uint32(0), "ffffffff"}, - {"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"}, - {"%.20b", 7, "00000000000000000111"}, - {"%10d", 12345, " 12,345"}, - {"%10d", -12345, " -12,345"}, - {"%+10d", 12345, " +12,345"}, - {"%010d", 12345, "0,000,012,345"}, - {"%010d", -12345, "-0,000,012,345"}, - {"%20.8d", 1234, " 00,001,234"}, - {"%20.8d", -1234, " -00,001,234"}, - {"%020.8d", 1234, " 00,001,234"}, - {"%020.8d", -1234, " -00,001,234"}, - {"%-20.8d", 1234, "00,001,234 "}, - {"%-20.8d", -1234, "-00,001,234 "}, - {"%-#20.8x", 0x1234abc, "0x01234abc "}, - {"%-#20.8X", 0x1234abc, "0X01234ABC "}, - {"%-#20.8o", 01234, "00001234 "}, - - // Test correct f.intbuf overflow checks. - {"%068d", 1, "00," + strings.Repeat("000,", 21) + "001"}, - {"%068d", -1, "-00," + strings.Repeat("000,", 21) + "001"}, - {"%#.68x", 42, zeroFill("0x", 68, "2a")}, - {"%.68d", -42, "-00," + strings.Repeat("000,", 21) + "042"}, - {"%+.68d", 42, "+00," + strings.Repeat("000,", 21) + "042"}, - {"% .68d", 42, " 00," + strings.Repeat("000,", 21) + "042"}, - {"% +.68d", 42, "+00," + strings.Repeat("000,", 21) + "042"}, - - // unicode format - {"%U", 0, "U+0000"}, - {"%U", -1, "U+FFFFFFFFFFFFFFFF"}, - {"%U", '\n', `U+000A`}, - {"%#U", '\n', `U+000A`}, - {"%+U", 'x', `U+0078`}, // Plus flag should have no effect. - {"%# U", 'x', `U+0078 'x'`}, // Space flag should have no effect. - {"%#.2U", 'x', `U+0078 'x'`}, // Precisions below 4 should print 4 digits. - {"%U", '\u263a', `U+263A`}, - {"%#U", '\u263a', `U+263A '☺'`}, - {"%U", '\U0001D6C2', `U+1D6C2`}, - {"%#U", '\U0001D6C2', `U+1D6C2 '𝛂'`}, - {"%#14.6U", '⌘', " U+002318 '⌘'"}, - {"%#-14.6U", '⌘', "U+002318 '⌘' "}, - {"%#014.6U", '⌘', " U+002318 '⌘'"}, - {"%#-014.6U", '⌘', "U+002318 '⌘' "}, - {"%.68U", uint(42), zeroFill("U+", 68, "2A")}, - {"%#.68U", '日', zeroFill("U+", 68, "65E5") + " '日'"}, - - // floats - {"%+.3e", 0.0, "+0.000\u202f×\u202f10⁰⁰"}, - {"%+.3e", 1.0, "+1.000\u202f×\u202f10⁰⁰"}, - {"%+.3f", -1.0, "-1.000"}, - {"%+.3F", -1.0, "-1.000"}, - {"%+.3F", float32(-1.0), "-1.000"}, - {"%+07.2f", 1.0, "+001.00"}, - {"%+07.2f", -1.0, "-001.00"}, - {"%-07.2f", 1.0, "1.00 "}, - {"%-07.2f", -1.0, "-1.00 "}, - {"%+-07.2f", 1.0, "+1.00 "}, - {"%+-07.2f", -1.0, "-1.00 "}, - {"%-+07.2f", 1.0, "+1.00 "}, - {"%-+07.2f", -1.0, "-1.00 "}, - {"%+10.2f", +1.0, " +1.00"}, - {"%+10.2f", -1.0, " -1.00"}, - {"% .3E", -1.0, "-1.000\u202f×\u202f10⁰⁰"}, - {"% .3e", 1.0, " 1.000\u202f×\u202f10⁰⁰"}, - {"%+.3g", 0.0, "+0"}, - {"%+.3g", 1.0, "+1"}, - {"%+.3g", -1.0, "-1"}, - {"% .3g", -1.0, "-1"}, - {"% .3g", 1.0, " 1"}, - {"%b", float32(1.0), "8388608p-23"}, - {"%b", 1.0, "4503599627370496p-52"}, - // Test sharp flag used with floats. - {"%#g", 1e-323, "1.00000e-323"}, - {"%#g", -1.0, "-1.00000"}, - {"%#g", 1.1, "1.10000"}, - {"%#g", 123456.0, "123456."}, - {"%#g", 1234567.0, "1.234567e+06"}, - {"%#g", 1230000.0, "1.23000e+06"}, - {"%#g", 1000000.0, "1.00000e+06"}, - {"%#.0f", 1.0, "1."}, - {"%#.0e", 1.0, "1.e+00"}, - {"%#.0g", 1.0, "1."}, - {"%#.0g", 1100000.0, "1.e+06"}, - {"%#.4f", 1.0, "1.0000"}, - {"%#.4e", 1.0, "1.0000e+00"}, - {"%#.4g", 1.0, "1.000"}, - {"%#.4g", 100000.0, "1.000e+05"}, - {"%#.0f", 123.0, "123."}, - {"%#.0e", 123.0, "1.e+02"}, - {"%#.0g", 123.0, "1.e+02"}, - {"%#.4f", 123.0, "123.0000"}, - {"%#.4e", 123.0, "1.2300e+02"}, - {"%#.4g", 123.0, "123.0"}, - {"%#.4g", 123000.0, "1.230e+05"}, - {"%#9.4g", 1.0, " 1.000"}, - // The sharp flag has no effect for binary float format. - {"%#b", 1.0, "4503599627370496p-52"}, - // Precision has no effect for binary float format. - {"%.4b", float32(1.0), "8388608p-23"}, - {"%.4b", -1.0, "-4503599627370496p-52"}, - // Test correct f.intbuf boundary checks. - {"%.68f", 1.0, zeroFill("1.", 68, "")}, - {"%.68f", -1.0, zeroFill("-1.", 68, "")}, - // float infinites and NaNs - {"%f", posInf, "∞"}, - {"%.1f", negInf, "-∞"}, - {"% f", NaN, "NaN"}, - {"%20f", posInf, " ∞"}, - {"% 20F", posInf, " ∞"}, - {"% 20e", negInf, " -∞"}, - {"%+20E", negInf, " -∞"}, - {"% +20g", negInf, " -∞"}, - {"%+-20G", posInf, "+∞ "}, - {"%20e", NaN, " NaN"}, - {"% +20E", NaN, " NaN"}, - {"% -20g", NaN, "NaN "}, - {"%+-20G", NaN, "NaN "}, - // Zero padding does not apply to infinities and NaN. - {"%+020e", posInf, " +∞"}, - {"%-020f", negInf, "-∞ "}, - {"%-020E", NaN, "NaN "}, - - // complex values - {"%.f", 0i, "(0+0i)"}, - {"% .f", 0i, "( 0+0i)"}, - {"%+.f", 0i, "(+0+0i)"}, - {"% +.f", 0i, "(+0+0i)"}, - {"%+.3e", 0i, "(+0.000\u202f×\u202f10⁰⁰+0.000\u202f×\u202f10⁰⁰i)"}, - {"%+.3f", 0i, "(+0.000+0.000i)"}, - {"%+.3g", 0i, "(+0+0i)"}, - {"%+.3e", 1 + 2i, "(+1.000\u202f×\u202f10⁰⁰+2.000\u202f×\u202f10⁰⁰i)"}, - {"%+.3f", 1 + 2i, "(+1.000+2.000i)"}, - {"%+.3g", 1 + 2i, "(+1+2i)"}, - {"%.3e", 0i, "(0.000\u202f×\u202f10⁰⁰+0.000\u202f×\u202f10⁰⁰i)"}, - {"%.3f", 0i, "(0.000+0.000i)"}, - {"%.3F", 0i, "(0.000+0.000i)"}, - {"%.3F", complex64(0i), "(0.000+0.000i)"}, - {"%.3g", 0i, "(0+0i)"}, - {"%.3e", 1 + 2i, "(1.000\u202f×\u202f10⁰⁰+2.000\u202f×\u202f10⁰⁰i)"}, - {"%.3f", 1 + 2i, "(1.000+2.000i)"}, - {"%.3g", 1 + 2i, "(1+2i)"}, - {"%.3e", -1 - 2i, "(-1.000\u202f×\u202f10⁰⁰-2.000\u202f×\u202f10⁰⁰i)"}, - {"%.3f", -1 - 2i, "(-1.000-2.000i)"}, - {"%.3g", -1 - 2i, "(-1-2i)"}, - {"% .3E", -1 - 2i, "(-1.000\u202f×\u202f10⁰⁰-2.000\u202f×\u202f10⁰⁰i)"}, - {"%+.3g", 1 + 2i, "(+1+2i)"}, - {"%+.3g", complex64(1 + 2i), "(+1+2i)"}, - {"%#g", 1 + 2i, "(1.00000+2.00000i)"}, - {"%#g", 123456 + 789012i, "(123456.+789012.i)"}, - {"%#g", 1e-10i, "(0.00000+1.00000e-10i)"}, - {"%#g", -1e10 - 1.11e100i, "(-1.00000e+10-1.11000e+100i)"}, - {"%#.0f", 1.23 + 1.0i, "(1.+1.i)"}, - {"%#.0e", 1.23 + 1.0i, "(1.e+00+1.e+00i)"}, - {"%#.0g", 1.23 + 1.0i, "(1.+1.i)"}, - {"%#.0g", 0 + 100000i, "(0.+1.e+05i)"}, - {"%#.0g", 1230000 + 0i, "(1.e+06+0.i)"}, - {"%#.4f", 1 + 1.23i, "(1.0000+1.2300i)"}, - {"%#.4e", 123 + 1i, "(1.2300e+02+1.0000e+00i)"}, - {"%#.4g", 123 + 1.23i, "(123.0+1.230i)"}, - {"%#12.5g", 0 + 100000i, "( 0.0000 +1.0000e+05i)"}, - {"%#12.5g", 1230000 - 0i, "( 1.2300e+06 +0.0000i)"}, - {"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, - {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, - // The sharp flag has no effect for binary complex format. - {"%#b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, - // Precision has no effect for binary complex format. - {"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, - {"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, - // complex infinites and NaNs - {"%f", complex(posInf, posInf), "(∞+∞i)"}, - {"%f", complex(negInf, negInf), "(-∞-∞i)"}, - {"%f", complex(NaN, NaN), "(NaN+NaNi)"}, - {"%.1f", complex(posInf, posInf), "(∞+∞i)"}, - {"% f", complex(posInf, posInf), "( ∞+∞i)"}, - {"% f", complex(negInf, negInf), "(-∞-∞i)"}, - {"% f", complex(NaN, NaN), "(NaN+NaNi)"}, - {"%8e", complex(posInf, posInf), "( ∞ +∞i)"}, - {"% 8E", complex(posInf, posInf), "( ∞ +∞i)"}, - {"%+8f", complex(negInf, negInf), "( -∞ -∞i)"}, - {"% +8g", complex(negInf, negInf), "( -∞ -∞i)"}, // TODO(g) - {"% -8G", complex(NaN, NaN), "(NaN +NaN i)"}, - {"%+-8b", complex(NaN, NaN), "(+NaN +NaN i)"}, - // Zero padding does not apply to infinities and NaN. - {"%08f", complex(posInf, posInf), "( ∞ +∞i)"}, - {"%-08g", complex(negInf, negInf), "(-∞ -∞ i)"}, - {"%-08G", complex(NaN, NaN), "(NaN +NaN i)"}, - - // old test/fmt_test.go - {"%e", 1.0, "1.000000\u202f×\u202f10⁰⁰"}, - {"%e", 1234.5678e3, "1.234568\u202f×\u202f10⁰⁶"}, - {"%e", 1234.5678e-8, "1.234568\u202f×\u202f10⁻⁰⁵"}, - {"%e", -7.0, "-7.000000\u202f×\u202f10⁰⁰"}, - {"%e", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"}, - {"%f", 1234.5678e3, "1,234,567.800000"}, - {"%f", 1234.5678e-8, "0.000012"}, - {"%f", -7.0, "-7.000000"}, - {"%f", -1e-9, "-0.000000"}, - {"%g", 1234.5678e3, "1.2345678\u202f×\u202f10⁰⁶"}, - {"%g", float32(1234.5678e3), "1.2345678\u202f×\u202f10⁰⁶"}, - {"%g", 1234.5678e-8, "1.2345678\u202f×\u202f10⁻⁰⁵"}, - {"%g", -7.0, "-7"}, - {"%g", -1e-9, "-1\u202f×\u202f10⁻⁰⁹"}, - {"%g", float32(-1e-9), "-1\u202f×\u202f10⁻⁰⁹"}, - {"%E", 1.0, "1.000000\u202f×\u202f10⁰⁰"}, - {"%E", 1234.5678e3, "1.234568\u202f×\u202f10⁰⁶"}, - {"%E", 1234.5678e-8, "1.234568\u202f×\u202f10⁻⁰⁵"}, - {"%E", -7.0, "-7.000000\u202f×\u202f10⁰⁰"}, - {"%E", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"}, - {"%G", 1234.5678e3, "1.2345678\u202f×\u202f10⁰⁶"}, - {"%G", float32(1234.5678e3), "1.2345678\u202f×\u202f10⁰⁶"}, - {"%G", 1234.5678e-8, "1.2345678\u202f×\u202f10⁻⁰⁵"}, - {"%G", -7.0, "-7"}, - {"%G", -1e-9, "-1\u202f×\u202f10⁻⁰⁹"}, - {"%G", float32(-1e-9), "-1\u202f×\u202f10⁻⁰⁹"}, - {"%20.5s", "qwertyuiop", " qwert"}, - {"%.5s", "qwertyuiop", "qwert"}, - {"%-20.5s", "qwertyuiop", "qwert "}, - {"%20c", 'x', " x"}, - {"%-20c", 'x', "x "}, - {"%20.6e", 1.2345e3, " 1.234500\u202f×\u202f10⁰³"}, - {"%20.6e", 1.2345e-3, " 1.234500\u202f×\u202f10⁻⁰³"}, - {"%20e", 1.2345e3, " 1.234500\u202f×\u202f10⁰³"}, - {"%20e", 1.2345e-3, " 1.234500\u202f×\u202f10⁻⁰³"}, - {"%20.8e", 1.2345e3, " 1.23450000\u202f×\u202f10⁰³"}, - {"%20f", 1.23456789e3, " 1,234.567890"}, - {"%20f", 1.23456789e-3, " 0.001235"}, - {"%20f", 12345678901.23456789, "12,345,678,901.234568"}, - {"%-20f", 1.23456789e3, "1,234.567890 "}, - {"%20.8f", 1.23456789e3, " 1,234.56789000"}, - {"%20.8f", 1.23456789e-3, " 0.00123457"}, - {"%g", 1.23456789e3, "1,234.56789"}, - {"%g", 1.23456789e-3, "0.00123456789"}, - {"%g", 1.23456789e20, "1.23456789\u202f×\u202f10²⁰"}, - - // arrays - {"%v", array, "[1 2 3 4 5]"}, - {"%v", iarray, "[1 hello 2.5 ]"}, - {"%v", barray, "[1 2 3 4 5]"}, - {"%v", &array, "&[1 2 3 4 5]"}, - {"%v", &iarray, "&[1 hello 2.5 ]"}, - {"%v", &barray, "&[1 2 3 4 5]"}, - - // slices - {"%v", slice, "[1 2 3 4 5]"}, - {"%v", islice, "[1 hello 2.5 ]"}, - {"%v", bslice, "[1 2 3 4 5]"}, - {"%v", &slice, "&[1 2 3 4 5]"}, - {"%v", &islice, "&[1 hello 2.5 ]"}, - {"%v", &bslice, "&[1 2 3 4 5]"}, - - // byte arrays and slices with %b,%c,%d,%o,%U and %v - {"%b", [3]byte{65, 66, 67}, "[1000001 1000010 1000011]"}, - {"%c", [3]byte{65, 66, 67}, "[A B C]"}, - {"%d", [3]byte{65, 66, 67}, "[65 66 67]"}, - {"%o", [3]byte{65, 66, 67}, "[101 102 103]"}, - {"%U", [3]byte{65, 66, 67}, "[U+0041 U+0042 U+0043]"}, - {"%v", [3]byte{65, 66, 67}, "[65 66 67]"}, - {"%v", [1]byte{123}, "[123]"}, - {"%012v", []byte{}, "[]"}, - {"%#012v", []byte{}, "[]byte{}"}, - {"%6v", []byte{1, 11, 111}, "[ 1 11 111]"}, - {"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"}, - {"%-6v", []byte{1, 11, 111}, "[1 11 111 ]"}, - {"%-06v", []byte{1, 11, 111}, "[1 11 111 ]"}, - {"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"}, - {"%#6v", []byte{1, 11, 111}, "[]byte{ 0x1, 0xb, 0x6f}"}, - {"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"}, - {"%#-6v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"}, - {"%#-06v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"}, - // f.space should and f.plus should not have an effect with %v. - {"% v", []byte{1, 11, 111}, "[ 1 11 111]"}, - {"%+v", [3]byte{1, 11, 111}, "[1 11 111]"}, - {"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1 , 0xb , 0x6f }"}, - {"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"}, - // f.space and f.plus should have an effect with %d. - {"% d", []byte{1, 11, 111}, "[ 1 11 111]"}, - {"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"}, - {"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"}, - {"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"}, - - // floates with %v - {"%v", 1.2345678, "1.2345678"}, - {"%v", float32(1.2345678), "1.2345678"}, - - // complexes with %v - {"%v", 1 + 2i, "(1+2i)"}, - {"%v", complex64(1 + 2i), "(1+2i)"}, - - // structs - {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`}, - {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`}, - - // +v on structs with Stringable items - {"%+v", B{1, 2}, `{I:<1> j:2}`}, - {"%+v", C{1, B{2, 3}}, `{i:1 B:{I:<2> j:3}}`}, - - // other formats on Stringable items - {"%s", I(23), `<23>`}, - {"%q", I(23), `"<23>"`}, - {"%x", I(23), `3c32333e`}, - {"%#x", I(23), `0x3c32333e`}, - {"%# x", I(23), `0x3c 0x32 0x33 0x3e`}, - // Stringer applies only to string formats. - {"%d", I(23), `23`}, - // Stringer applies to the extracted value. - {"%s", reflect.ValueOf(I(23)), `<23>`}, - - // go syntax - {"%#v", A{1, 2, "a", []int{1, 2}}, `message.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`}, - {"%#v", new(byte), "(*uint8)(0xPTR)"}, - {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"}, - {"%#v", make(chan int), "(chan int)(0xPTR)"}, - {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"}, - {"%#v", 1000000000, "1000000000"}, - {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`}, - {"%#v", map[string]B{"a": {1, 2}}, `map[string]message.B{"a":message.B{I:1, j:2}}`}, - {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`}, - {"%#v", SI{}, `message.SI{I:interface {}(nil)}`}, - {"%#v", []int(nil), `[]int(nil)`}, - {"%#v", []int{}, `[]int{}`}, - {"%#v", array, `[5]int{1, 2, 3, 4, 5}`}, - {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`}, - {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, - {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, - {"%#v", map[int]byte(nil), `map[int]uint8(nil)`}, - {"%#v", map[int]byte{}, `map[int]uint8{}`}, - {"%#v", "foo", `"foo"`}, - {"%#v", barray, `[5]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, - {"%#v", bslice, `[]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, - {"%#v", []int32(nil), "[]int32(nil)"}, - {"%#v", 1.2345678, "1.2345678"}, - {"%#v", float32(1.2345678), "1.2345678"}, - // Only print []byte and []uint8 as type []byte if they appear at the top level. - {"%#v", []byte(nil), "[]byte(nil)"}, - {"%#v", []uint8(nil), "[]byte(nil)"}, - {"%#v", []byte{}, "[]byte{}"}, - {"%#v", []uint8{}, "[]byte{}"}, - {"%#v", reflect.ValueOf([]byte{}), "[]uint8{}"}, - {"%#v", reflect.ValueOf([]uint8{}), "[]uint8{}"}, - {"%#v", &[]byte{}, "&[]uint8{}"}, - {"%#v", &[]byte{}, "&[]uint8{}"}, - {"%#v", [3]byte{}, "[3]uint8{0x0, 0x0, 0x0}"}, - {"%#v", [3]uint8{}, "[3]uint8{0x0, 0x0, 0x0}"}, - - // slices with other formats - {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, - {"%x", []int{1, 2, 15}, `[1 2 f]`}, - {"%d", []int{1, 2, 15}, `[1 2 15]`}, - {"%d", []byte{1, 2, 15}, `[1 2 15]`}, - {"%q", []string{"a", "b"}, `["a" "b"]`}, - {"% 02x", []byte{1}, "01"}, - {"% 02x", []byte{1, 2, 3}, "01 02 03"}, - - // Padding with byte slices. - {"%2x", []byte{}, " "}, - {"%#2x", []byte{}, " "}, - {"% 02x", []byte{}, "00"}, - {"%# 02x", []byte{}, "00"}, - {"%-2x", []byte{}, " "}, - {"%-02x", []byte{}, " "}, - {"%8x", []byte{0xab}, " ab"}, - {"% 8x", []byte{0xab}, " ab"}, - {"%#8x", []byte{0xab}, " 0xab"}, - {"%# 8x", []byte{0xab}, " 0xab"}, - {"%08x", []byte{0xab}, "000000ab"}, - {"% 08x", []byte{0xab}, "000000ab"}, - {"%#08x", []byte{0xab}, "00000xab"}, - {"%# 08x", []byte{0xab}, "00000xab"}, - {"%10x", []byte{0xab, 0xcd}, " abcd"}, - {"% 10x", []byte{0xab, 0xcd}, " ab cd"}, - {"%#10x", []byte{0xab, 0xcd}, " 0xabcd"}, - {"%# 10x", []byte{0xab, 0xcd}, " 0xab 0xcd"}, - {"%010x", []byte{0xab, 0xcd}, "000000abcd"}, - {"% 010x", []byte{0xab, 0xcd}, "00000ab cd"}, - {"%#010x", []byte{0xab, 0xcd}, "00000xabcd"}, - {"%# 010x", []byte{0xab, 0xcd}, "00xab 0xcd"}, - {"%-10X", []byte{0xab}, "AB "}, - {"% -010X", []byte{0xab}, "AB "}, - {"%#-10X", []byte{0xab, 0xcd}, "0XABCD "}, - {"%# -010X", []byte{0xab, 0xcd}, "0XAB 0XCD "}, - // Same for strings - {"%2x", "", " "}, - {"%#2x", "", " "}, - {"% 02x", "", "00"}, - {"%# 02x", "", "00"}, - {"%-2x", "", " "}, - {"%-02x", "", " "}, - {"%8x", "\xab", " ab"}, - {"% 8x", "\xab", " ab"}, - {"%#8x", "\xab", " 0xab"}, - {"%# 8x", "\xab", " 0xab"}, - {"%08x", "\xab", "000000ab"}, - {"% 08x", "\xab", "000000ab"}, - {"%#08x", "\xab", "00000xab"}, - {"%# 08x", "\xab", "00000xab"}, - {"%10x", "\xab\xcd", " abcd"}, - {"% 10x", "\xab\xcd", " ab cd"}, - {"%#10x", "\xab\xcd", " 0xabcd"}, - {"%# 10x", "\xab\xcd", " 0xab 0xcd"}, - {"%010x", "\xab\xcd", "000000abcd"}, - {"% 010x", "\xab\xcd", "00000ab cd"}, - {"%#010x", "\xab\xcd", "00000xabcd"}, - {"%# 010x", "\xab\xcd", "00xab 0xcd"}, - {"%-10X", "\xab", "AB "}, - {"% -010X", "\xab", "AB "}, - {"%#-10X", "\xab\xcd", "0XABCD "}, - {"%# -010X", "\xab\xcd", "0XAB 0XCD "}, - - // renamings - {"%v", renamedBool(true), "true"}, - {"%d", renamedBool(true), "%!d(message.renamedBool=true)"}, - {"%o", renamedInt(8), "10"}, - {"%d", renamedInt8(-9), "-9"}, - {"%v", renamedInt16(10), "10"}, - {"%v", renamedInt32(-11), "-11"}, - {"%X", renamedInt64(255), "FF"}, - {"%v", renamedUint(13), "13"}, - {"%o", renamedUint8(14), "16"}, - {"%X", renamedUint16(15), "F"}, - {"%d", renamedUint32(16), "16"}, - {"%X", renamedUint64(17), "11"}, - {"%o", renamedUintptr(18), "22"}, - {"%x", renamedString("thing"), "7468696e67"}, - {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`}, - {"%q", renamedBytes([]byte("hello")), `"hello"`}, - {"%x", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656c6c6f"}, - {"%X", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656C6C6F"}, - {"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"}, - {"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`}, - {"%v", renamedFloat32(22), "22"}, - {"%v", renamedFloat64(33), "33"}, - {"%v", renamedComplex64(3 + 4i), "(3+4i)"}, - {"%v", renamedComplex128(4 - 3i), "(4-3i)"}, - - // Formatter - {"%x", F(1), ""}, - {"%x", G(2), "2"}, - {"%+v", S{F(4), G(5)}, "{F: G:5}"}, - - // GoStringer - {"%#v", G(6), "GoString(6)"}, - {"%#v", S{F(7), G(8)}, "message.S{F:, G:GoString(8)}"}, - - // %T - {"%T", byte(0), "uint8"}, - {"%T", reflect.ValueOf(nil), "reflect.Value"}, - {"%T", (4 - 3i), "complex128"}, - {"%T", renamedComplex128(4 - 3i), "message.renamedComplex128"}, - {"%T", intVar, "int"}, - {"%6T", &intVar, " *int"}, - {"%10T", nil, " "}, - {"%-10T", nil, " "}, - - // %p with pointers - {"%p", (*int)(nil), "0x0"}, - {"%#p", (*int)(nil), "0"}, - {"%p", &intVar, "0xPTR"}, - {"%#p", &intVar, "PTR"}, - {"%p", &array, "0xPTR"}, - {"%p", &slice, "0xPTR"}, - {"%8.2p", (*int)(nil), " 0x00"}, - {"%-20.16p", &intVar, "0xPTR "}, - // %p on non-pointers - {"%p", make(chan int), "0xPTR"}, - {"%p", make(map[int]int), "0xPTR"}, - {"%p", func() {}, "0xPTR"}, - {"%p", 27, "%!p(int=27)"}, // not a pointer at all - {"%p", nil, "%!p()"}, // nil on its own has no type ... - {"%#p", nil, "%!p()"}, // ... and hence is not a pointer type. - // pointers with specified base - {"%b", &intVar, "PTR_b"}, - {"%d", &intVar, "PTR_d"}, - {"%o", &intVar, "PTR_o"}, - {"%x", &intVar, "PTR_x"}, - {"%X", &intVar, "PTR_X"}, - // %v on pointers - {"%v", nil, ""}, - {"%#v", nil, ""}, - {"%v", (*int)(nil), ""}, - {"%#v", (*int)(nil), "(*int)(nil)"}, - {"%v", &intVar, "0xPTR"}, - {"%#v", &intVar, "(*int)(0xPTR)"}, - {"%8.2v", (*int)(nil), " "}, - {"%-20.16v", &intVar, "0xPTR "}, - // string method on pointer - {"%s", &pValue, "String(p)"}, // String method... - {"%p", &pValue, "0xPTR"}, // ... is not called with %p. - - // %d on Stringer should give integer if possible - {"%s", time.Time{}.Month(), "January"}, - {"%d", time.Time{}.Month(), "1"}, - - // erroneous things - {"%s %", "hello", "hello %!(NOVERB)"}, - {"%s %.2", "hello", "hello %!(NOVERB)"}, - - // The "" show up because maps are printed by - // first obtaining a list of keys and then looking up - // each key. Since NaNs can be map keys but cannot - // be fetched directly, the lookup fails and returns a - // zero reflect.Value, which formats as . - // This test is just to check that it shows the two NaNs at all. - {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN: NaN:]"}, - - // Comparison of padding rules with C printf. - /* - C program: - #include - - char *format[] = { - "[%.2f]", - "[% .2f]", - "[%+.2f]", - "[%7.2f]", - "[% 7.2f]", - "[%+7.2f]", - "[% +7.2f]", - "[%07.2f]", - "[% 07.2f]", - "[%+07.2f]", - "[% +07.2f]" - }; - - int main(void) { - int i; - for(i = 0; i < 11; i++) { - printf("%s: ", format[i]); - printf(format[i], 1.0); - printf(" "); - printf(format[i], -1.0); - printf("\n"); - } - } - - Output: - [%.2f]: [1.00] [-1.00] - [% .2f]: [ 1.00] [-1.00] - [%+.2f]: [+1.00] [-1.00] - [%7.2f]: [ 1.00] [ -1.00] - [% 7.2f]: [ 1.00] [ -1.00] - [%+7.2f]: [ +1.00] [ -1.00] - [% +7.2f]: [ +1.00] [ -1.00] - [%07.2f]: [0001.00] [-001.00] - [% 07.2f]: [ 001.00] [-001.00] - [%+07.2f]: [+001.00] [-001.00] - [% +07.2f]: [+001.00] [-001.00] - - */ - {"%.2f", 1.0, "1.00"}, - {"%.2f", -1.0, "-1.00"}, - {"% .2f", 1.0, " 1.00"}, - {"% .2f", -1.0, "-1.00"}, - {"%+.2f", 1.0, "+1.00"}, - {"%+.2f", -1.0, "-1.00"}, - {"%7.2f", 1.0, " 1.00"}, - {"%7.2f", -1.0, " -1.00"}, - {"% 7.2f", 1.0, " 1.00"}, - {"% 7.2f", -1.0, " -1.00"}, - {"%+7.2f", 1.0, " +1.00"}, - {"%+7.2f", -1.0, " -1.00"}, - {"% +7.2f", 1.0, " +1.00"}, - {"% +7.2f", -1.0, " -1.00"}, - // Padding with 0's indicates minimum number of integer digits minus the - // period, if present, and minus the sign if it is fixed. - // TODO: consider making this number the number of significant digits. - {"%07.2f", 1.0, "0,001.00"}, - {"%07.2f", -1.0, "-0,001.00"}, - {"% 07.2f", 1.0, " 001.00"}, - {"% 07.2f", -1.0, "-001.00"}, - {"%+07.2f", 1.0, "+001.00"}, - {"%+07.2f", -1.0, "-001.00"}, - {"% +07.2f", 1.0, "+001.00"}, - {"% +07.2f", -1.0, "-001.00"}, - - // Complex numbers: exhaustively tested in TestComplexFormatting. - {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"}, - {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"}, - - // Use spaces instead of zero if padding to the right. - {"%0-5s", "abc", "abc "}, - {"%-05.1f", 1.0, "1.0 "}, - - // float and complex formatting should not change the padding width - // for other elements. See issue 14642. - {"%06v", []interface{}{+10.0, 10}, "[000,010 000,010]"}, - {"%06v", []interface{}{-10.0, 10}, "[-000,010 000,010]"}, - {"%06v", []interface{}{+10.0 + 10i, 10}, "[(000,010+00,010i) 000,010]"}, - {"%06v", []interface{}{-10.0 + 10i, 10}, "[(-000,010+00,010i) 000,010]"}, - - // integer formatting should not alter padding for other elements. - {"%03.6v", []interface{}{1, 2.0, "x"}, "[000,001 002 00x]"}, - {"%03.0v", []interface{}{0, 2.0, "x"}, "[ 002 000]"}, - - // Complex fmt used to leave the plus flag set for future entries in the array - // causing +2+0i and +3+0i instead of 2+0i and 3+0i. - {"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"}, - {"%v", []complex128{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"}, - - // Incomplete format specification caused crash. - {"%.", 3, "%!.(int=3)"}, - - // Padding for complex numbers. Has been bad, then fixed, then bad again. - {"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"}, - {"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"}, - {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"}, - {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"}, - {"%010.2f", +104.66 + 440.51i, "(0,000,104.66+000,440.51i)"}, - {"%+010.2f", +104.66 + 440.51i, "(+000,104.66+000,440.51i)"}, - {"%+010.2f", -104.66 + 440.51i, "(-000,104.66+000,440.51i)"}, - {"%+010.2f", +104.66 - 440.51i, "(+000,104.66-000,440.51i)"}, - {"%+010.2f", -104.66 - 440.51i, "(-000,104.66-000,440.51i)"}, - - // []T where type T is a byte with a Stringer method. - {"%v", byteStringerSlice, "[X X X X X]"}, - {"%s", byteStringerSlice, "hello"}, - {"%q", byteStringerSlice, "\"hello\""}, - {"%x", byteStringerSlice, "68656c6c6f"}, - {"%X", byteStringerSlice, "68656C6C6F"}, - {"%#v", byteStringerSlice, "[]message.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"}, - - // And the same for Formatter. - {"%v", byteFormatterSlice, "[X X X X X]"}, - {"%s", byteFormatterSlice, "hello"}, - {"%q", byteFormatterSlice, "\"hello\""}, - {"%x", byteFormatterSlice, "68656c6c6f"}, - {"%X", byteFormatterSlice, "68656C6C6F"}, - // This next case seems wrong, but the docs say the Formatter wins here. - {"%#v", byteFormatterSlice, "[]message.byteFormatter{X, X, X, X, X}"}, - - // reflect.Value handled specially in Go 1.5, making it possible to - // see inside non-exported fields (which cannot be accessed with Interface()). - // Issue 8965. - {"%v", reflect.ValueOf(A{}).Field(0).String(), ""}, // Equivalent to the old way. - {"%v", reflect.ValueOf(A{}).Field(0), "0"}, // Sees inside the field. - - // verbs apply to the extracted value too. - {"%s", reflect.ValueOf("hello"), "hello"}, - {"%q", reflect.ValueOf("hello"), `"hello"`}, - {"%#04x", reflect.ValueOf(256), "0x0100"}, - - // invalid reflect.Value doesn't crash. - {"%v", reflect.Value{}, ""}, - {"%v", &reflect.Value{}, ""}, - {"%v", SI{reflect.Value{}}, "{}"}, - - // Tests to check that not supported verbs generate an error string. - {"%☠", nil, "%!☠()"}, - {"%☠", interface{}(nil), "%!☠()"}, - {"%☠", int(0), "%!☠(int=0)"}, - {"%☠", uint(0), "%!☠(uint=0)"}, - {"%☠", []byte{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"}, - {"%☠", []uint8{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"}, - {"%☠", [1]byte{0}, "[%!☠(uint8=0)]"}, - {"%☠", [1]uint8{0}, "[%!☠(uint8=0)]"}, - {"%☠", "hello", "%!☠(string=hello)"}, - {"%☠", 1.2345678, "%!☠(float64=1.2345678)"}, - {"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"}, - {"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"}, - {"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"}, - {"%☠", &intVar, "%!☠(*int=0xPTR)"}, - {"%☠", make(chan int), "%!☠(chan int=0xPTR)"}, - {"%☠", func() {}, "%!☠(func()=0xPTR)"}, - {"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(message.renamedInt=0)"}, - {"%☠", SI{renamedInt(0)}, "{%!☠(message.renamedInt=0)}"}, - {"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(message.I=1) %!☠(message.G=2)]"}, - {"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"}, - {"%☠", reflect.Value{}, ""}, - {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠()]"}, -} - -// zeroFill generates zero-filled strings of the specified width. The length -// of the suffix (but not the prefix) is compensated for in the width calculation. -func zeroFill(prefix string, width int, suffix string) string { - return prefix + strings.Repeat("0", width-len(suffix)) + suffix -} - -func TestSprintf(t *testing.T) { - p := NewPrinter(language.Und) - for _, tt := range fmtTests { - t.Run(fmt.Sprint(tt.fmt, "/", tt.val), func(t *testing.T) { - s := p.Sprintf(tt.fmt, tt.val) - i := strings.Index(tt.out, "PTR") - if i >= 0 && i < len(s) { - var pattern, chars string - switch { - case strings.HasPrefix(tt.out[i:], "PTR_b"): - pattern = "PTR_b" - chars = "01" - case strings.HasPrefix(tt.out[i:], "PTR_o"): - pattern = "PTR_o" - chars = "01234567" - case strings.HasPrefix(tt.out[i:], "PTR_d"): - pattern = "PTR_d" - chars = "0123456789" - case strings.HasPrefix(tt.out[i:], "PTR_x"): - pattern = "PTR_x" - chars = "0123456789abcdef" - case strings.HasPrefix(tt.out[i:], "PTR_X"): - pattern = "PTR_X" - chars = "0123456789ABCDEF" - default: - pattern = "PTR" - chars = "0123456789abcdefABCDEF" - } - p := s[:i] + pattern - for j := i; j < len(s); j++ { - if !strings.ContainsRune(chars, rune(s[j])) { - p += s[j:] - break - } - } - s = p - } - if s != tt.out { - if _, ok := tt.val.(string); ok { - // Don't requote the already-quoted strings. - // It's too confusing to read the errors. - t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out) - } else { - t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out) - } - } - }) - } -} - -var f float64 - -// TestComplexFormatting checks that a complex always formats to the same -// thing as if done by hand with two singleton prints. -func TestComplexFormatting(t *testing.T) { - var yesNo = []bool{true, false} - var values = []float64{1, 0, -1, posInf, negInf, NaN} - p := NewPrinter(language.Und) - for _, plus := range yesNo { - for _, zero := range yesNo { - for _, space := range yesNo { - for _, char := range "fFeEgG" { - realFmt := "%" - if zero { - realFmt += "0" - } - if space { - realFmt += " " - } - if plus { - realFmt += "+" - } - realFmt += "10.2" - realFmt += string(char) - // Imaginary part always has a sign, so force + and ignore space. - imagFmt := "%" - if zero { - imagFmt += "0" - } - imagFmt += "+" - imagFmt += "10.2" - imagFmt += string(char) - for _, realValue := range values { - for _, imagValue := range values { - one := p.Sprintf(realFmt, complex(realValue, imagValue)) - two := p.Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue) - if math.IsNaN(imagValue) { - p := len(two) - len("NaNi)") - 1 - if two[p] == ' ' { - two = two[:p] + "+" + two[p+1:] - } else { - two = two[:p+1] + "+" + two[p+1:] - } - } - if one != two { - t.Error(f, one, two) - } - } - } - } - } - } - } -} - -type SE []interface{} // slice of empty; notational compactness. - -var reorderTests = []struct { - format string - args SE - out string -}{ - {"%[1]d", SE{1}, "1"}, - {"%[2]d", SE{2, 1}, "1"}, - {"%[2]d %[1]d", SE{1, 2}, "2 1"}, - {"%[2]*[1]d", SE{2, 5}, " 2"}, - {"%6.2f", SE{12.0}, " 12.00"}, // Explicit version of next line. - {"%[3]*.[2]*[1]f", SE{12.0, 2, 6}, " 12.00"}, - {"%[1]*.[2]*[3]f", SE{6, 2, 12.0}, " 12.00"}, - {"%10f", SE{12.0}, " 12.000000"}, - {"%[1]*[3]f", SE{10, 99, 12.0}, " 12.000000"}, - {"%.6f", SE{12.0}, "12.000000"}, // Explicit version of next line. - {"%.[1]*[3]f", SE{6, 99, 12.0}, "12.000000"}, - {"%6.f", SE{12.0}, " 12"}, // // Explicit version of next line; empty precision means zero. - {"%[1]*.[3]f", SE{6, 3, 12.0}, " 12"}, - // An actual use! Print the same arguments twice. - {"%d %d %d %#[1]o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015"}, - - // Erroneous cases. - {"%[d", SE{2, 1}, "%!d(BADINDEX)"}, - {"%]d", SE{2, 1}, "%!](int=2)d%!(EXTRA int=1)"}, - {"%[]d", SE{2, 1}, "%!d(BADINDEX)"}, - {"%[-3]d", SE{2, 1}, "%!d(BADINDEX)"}, - {"%[99]d", SE{2, 1}, "%!d(BADINDEX)"}, - {"%[3]", SE{2, 1}, "%!(NOVERB)"}, - {"%[1].2d", SE{5, 6}, "%!d(BADINDEX)"}, - {"%[1]2d", SE{2, 1}, "%!d(BADINDEX)"}, - {"%3.[2]d", SE{7}, "%!d(BADINDEX)"}, - {"%.[2]d", SE{7}, "%!d(BADINDEX)"}, - {"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"}, - {"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"}, - {"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence. - {"%.[]", SE{}, "%!](BADINDEX)"}, // Issue 10675 - {"%.-3d", SE{42}, "%!-(int=42)3d"}, // TODO: Should this set return better error messages? - // The following messages are interpreted as if there is no substitution, - // in which case it is okay to have extra arguments. This is different - // semantics from the fmt package. - {"%2147483648d", SE{42}, "%!(NOVERB)"}, - {"%-2147483648d", SE{42}, "%!(NOVERB)"}, - {"%.2147483648d", SE{42}, "%!(NOVERB)"}, -} - -func TestReorder(t *testing.T) { - p := NewPrinter(language.Und) - for _, tc := range reorderTests { - t.Run(fmt.Sprint(tc.format, "/", tc.args), func(t *testing.T) { - s := p.Sprintf(tc.format, tc.args...) - if s != tc.out { - t.Errorf("Sprintf(%q, %v) = %q want %q", tc.format, tc.args, s, tc.out) - } - }) - } -} - -func BenchmarkSprintfPadding(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%16f", 1.0) - } - }) -} - -func BenchmarkSprintfEmpty(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("") - } - }) -} - -func BenchmarkSprintfString(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%s", "hello") - } - }) -} - -func BenchmarkSprintfTruncateString(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%.3s", "日本語日本語日本語") - } - }) -} - -func BenchmarkSprintfQuoteString(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%q", "日本語日本語日本語") - } - }) -} - -func BenchmarkSprintfInt(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%d", 5) - } - }) -} - -func BenchmarkSprintfIntInt(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%d %d", 5, 6) - } - }) -} - -func BenchmarkSprintfPrefixedInt(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) - } - }) -} - -func BenchmarkSprintfFloat(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%g", 5.23184) - } - }) -} - -func BenchmarkSprintfComplex(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%f", 5.23184+5.23184i) - } - }) -} - -func BenchmarkSprintfBoolean(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%t", true) - } - }) -} - -func BenchmarkSprintfHexString(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("% #x", "0123456789abcdef") - } - }) -} - -func BenchmarkSprintfHexBytes(b *testing.B) { - data := []byte("0123456789abcdef") - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("% #x", data) - } - }) -} - -func BenchmarkSprintfBytes(b *testing.B) { - data := []byte("0123456789abcdef") - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%v", data) - } - }) -} - -func BenchmarkSprintfStringer(b *testing.B) { - stringer := I(12345) - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%v", stringer) - } - }) -} - -func BenchmarkSprintfStructure(b *testing.B) { - s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}} - b.RunParallel(func(pb *testing.PB) { - p := NewPrinter(language.English) - for pb.Next() { - p.Sprintf("%#v", s) - } - }) -} - -func BenchmarkManyArgs(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - var buf bytes.Buffer - p := NewPrinter(language.English) - for pb.Next() { - buf.Reset() - p.Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") - } - }) -} - -func BenchmarkFprintInt(b *testing.B) { - var buf bytes.Buffer - p := NewPrinter(language.English) - for i := 0; i < b.N; i++ { - buf.Reset() - p.Fprint(&buf, 123456) - } -} - -func BenchmarkFprintfBytes(b *testing.B) { - data := []byte(string("0123456789")) - var buf bytes.Buffer - p := NewPrinter(language.English) - for i := 0; i < b.N; i++ { - buf.Reset() - p.Fprintf(&buf, "%s", data) - } -} - -func BenchmarkFprintIntNoAlloc(b *testing.B) { - var x interface{} = 123456 - var buf bytes.Buffer - p := NewPrinter(language.English) - for i := 0; i < b.N; i++ { - buf.Reset() - p.Fprint(&buf, x) - } -} - -var mallocBuf bytes.Buffer -var mallocPointer *int // A pointer so we know the interface value won't allocate. - -var mallocTest = []struct { - count int - desc string - fn func(p *Printer) -}{ - {0, `Sprintf("")`, func(p *Printer) { p.Sprintf("") }}, - {1, `Sprintf("xxx")`, func(p *Printer) { p.Sprintf("xxx") }}, - {2, `Sprintf("%x")`, func(p *Printer) { p.Sprintf("%x", 7) }}, - {2, `Sprintf("%s")`, func(p *Printer) { p.Sprintf("%s", "hello") }}, - {3, `Sprintf("%x %x")`, func(p *Printer) { p.Sprintf("%x %x", 7, 112) }}, - {2, `Sprintf("%g")`, func(p *Printer) { p.Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1? - {1, `Fprintf(buf, "%s")`, func(p *Printer) { mallocBuf.Reset(); p.Fprintf(&mallocBuf, "%s", "hello") }}, - // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. - {0, `Fprintf(buf, "%x %x %x")`, func(p *Printer) { - mallocBuf.Reset() - p.Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer) - }}, -} - -var _ bytes.Buffer - -func TestCountMallocs(t *testing.T) { - switch { - case testing.Short(): - t.Skip("skipping malloc count in short mode") - case runtime.GOMAXPROCS(0) > 1: - t.Skip("skipping; GOMAXPROCS>1") - // TODO: detect race detecter enabled. - // case race.Enabled: - // t.Skip("skipping malloc count under race detector") - } - p := NewPrinter(language.English) - for _, mt := range mallocTest { - mallocs := testing.AllocsPerRun(100, func() { mt.fn(p) }) - if got, max := mallocs, float64(mt.count); got > max { - t.Errorf("%s: got %v allocs, want <=%v", mt.desc, got, max) - } - } -} - -type flagPrinter struct{} - -func (flagPrinter) Format(f fmt.State, c rune) { - s := "%" - for i := 0; i < 128; i++ { - if f.Flag(i) { - s += string(i) - } - } - if w, ok := f.Width(); ok { - s += fmt.Sprintf("%d", w) - } - if p, ok := f.Precision(); ok { - s += fmt.Sprintf(".%d", p) - } - s += string(c) - io.WriteString(f, "["+s+"]") -} - -var flagtests = []struct { - in string - out string -}{ - {"%a", "[%a]"}, - {"%-a", "[%-a]"}, - {"%+a", "[%+a]"}, - {"%#a", "[%#a]"}, - {"% a", "[% a]"}, - {"%0a", "[%0a]"}, - {"%1.2a", "[%1.2a]"}, - {"%-1.2a", "[%-1.2a]"}, - {"%+1.2a", "[%+1.2a]"}, - {"%-+1.2a", "[%+-1.2a]"}, - {"%-+1.2abc", "[%+-1.2a]bc"}, - {"%-1.2abc", "[%-1.2a]bc"}, -} - -func TestFlagParser(t *testing.T) { - var flagprinter flagPrinter - for _, tt := range flagtests { - s := NewPrinter(language.Und).Sprintf(tt.in, &flagprinter) - if s != tt.out { - t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out) - } - } -} - -func TestStructPrinter(t *testing.T) { - type T struct { - a string - b string - c int - } - var s T - s.a = "abc" - s.b = "def" - s.c = 123 - var tests = []struct { - fmt string - out string - }{ - {"%v", "{abc def 123}"}, - {"%+v", "{a:abc b:def c:123}"}, - {"%#v", `message.T{a:"abc", b:"def", c:123}`}, - } - p := NewPrinter(language.Und) - for _, tt := range tests { - out := p.Sprintf(tt.fmt, s) - if out != tt.out { - t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out) - } - // The same but with a pointer. - out = p.Sprintf(tt.fmt, &s) - if out != "&"+tt.out { - t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out) - } - } -} - -func TestSlicePrinter(t *testing.T) { - p := NewPrinter(language.Und) - slice := []int{} - s := p.Sprint(slice) - if s != "[]" { - t.Errorf("empty slice printed as %q not %q", s, "[]") - } - slice = []int{1, 2, 3} - s = p.Sprint(slice) - if s != "[1 2 3]" { - t.Errorf("slice: got %q expected %q", s, "[1 2 3]") - } - s = p.Sprint(&slice) - if s != "&[1 2 3]" { - t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]") - } -} - -// presentInMap checks map printing using substrings so we don't depend on the -// print order. -func presentInMap(s string, a []string, t *testing.T) { - for i := 0; i < len(a); i++ { - loc := strings.Index(s, a[i]) - if loc < 0 { - t.Errorf("map print: expected to find %q in %q", a[i], s) - } - // make sure the match ends here - loc += len(a[i]) - if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') { - t.Errorf("map print: %q not properly terminated in %q", a[i], s) - } - } -} - -func TestMapPrinter(t *testing.T) { - p := NewPrinter(language.Und) - m0 := make(map[int]string) - s := p.Sprint(m0) - if s != "map[]" { - t.Errorf("empty map printed as %q not %q", s, "map[]") - } - m1 := map[int]string{1: "one", 2: "two", 3: "three"} - a := []string{"1:one", "2:two", "3:three"} - presentInMap(p.Sprintf("%v", m1), a, t) - presentInMap(p.Sprint(m1), a, t) - // Pointer to map prints the same but with initial &. - if !strings.HasPrefix(p.Sprint(&m1), "&") { - t.Errorf("no initial & for address of map") - } - presentInMap(p.Sprintf("%v", &m1), a, t) - presentInMap(p.Sprint(&m1), a, t) -} - -func TestEmptyMap(t *testing.T) { - const emptyMapStr = "map[]" - var m map[string]int - p := NewPrinter(language.Und) - s := p.Sprint(m) - if s != emptyMapStr { - t.Errorf("nil map printed as %q not %q", s, emptyMapStr) - } - m = make(map[string]int) - s = p.Sprint(m) - if s != emptyMapStr { - t.Errorf("empty map printed as %q not %q", s, emptyMapStr) - } -} - -// TestBlank checks that Sprint (and hence Print, Fprint) puts spaces in the -// right places, that is, between arg pairs in which neither is a string. -func TestBlank(t *testing.T) { - p := NewPrinter(language.Und) - got := p.Sprint("<", 1, ">:", 1, 2, 3, "!") - expect := "<1>:1 2 3!" - if got != expect { - t.Errorf("got %q expected %q", got, expect) - } -} - -// TestBlankln checks that Sprintln (and hence Println, Fprintln) puts spaces in -// the right places, that is, between all arg pairs. -func TestBlankln(t *testing.T) { - p := NewPrinter(language.Und) - got := p.Sprintln("<", 1, ">:", 1, 2, 3, "!") - expect := "< 1 >: 1 2 3 !\n" - if got != expect { - t.Errorf("got %q expected %q", got, expect) - } -} - -// TestFormatterPrintln checks Formatter with Sprint, Sprintln, Sprintf. -func TestFormatterPrintln(t *testing.T) { - p := NewPrinter(language.Und) - f := F(1) - expect := "\n" - s := p.Sprint(f, "\n") - if s != expect { - t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s) - } - s = p.Sprintln(f) - if s != expect { - t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s) - } - s = p.Sprintf("%v\n", f) - if s != expect { - t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s) - } -} - -func args(a ...interface{}) []interface{} { return a } - -var startests = []struct { - fmt string - in []interface{} - out string -}{ - {"%*d", args(4, 42), " 42"}, - {"%-*d", args(4, 42), "42 "}, - {"%*d", args(-4, 42), "42 "}, - {"%-*d", args(-4, 42), "42 "}, - {"%.*d", args(4, 42), "0,042"}, - {"%*.*d", args(8, 4, 42), " 0,042"}, - {"%0*d", args(4, 42), "0,042"}, - // Some non-int types for width. (Issue 10732). - {"%0*d", args(uint(4), 42), "0,042"}, - {"%0*d", args(uint64(4), 42), "0,042"}, - {"%0*d", args('\x04', 42), "0,042"}, - {"%0*d", args(uintptr(4), 42), "0,042"}, - - // erroneous - {"%*d", args(nil, 42), "%!(BADWIDTH)42"}, - {"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"}, - {"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"}, - {"%.*d", args(nil, 42), "%!(BADPREC)42"}, - {"%.*d", args(-1, 42), "%!(BADPREC)42"}, - {"%.*d", args(int(1e7), 42), "%!(BADPREC)42"}, - {"%.*d", args(uint(1e7), 42), "%!(BADPREC)42"}, - {"%.*d", args(uint64(1<<63), 42), "%!(BADPREC)42"}, // Huge negative (-inf). - {"%.*d", args(uint64(1<<64-1), 42), "%!(BADPREC)42"}, // Small negative (-1). - {"%*d", args(5, "foo"), "%!d(string= foo)"}, - {"%*% %d", args(20, 5), "% 5"}, - {"%*", args(4), "%!(NOVERB)"}, -} - -func TestWidthAndPrecision(t *testing.T) { - p := NewPrinter(language.Und) - for i, tt := range startests { - t.Run(fmt.Sprint(tt.fmt, tt.in), func(t *testing.T) { - s := p.Sprintf(tt.fmt, tt.in...) - if s != tt.out { - t.Errorf("#%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) - } - }) - } -} - -// PanicS is a type that panics in String. -type PanicS struct { - message interface{} -} - -// Value receiver. -func (p PanicS) String() string { - panic(p.message) -} - -// PanicGo is a type that panics in GoString. -type PanicGo struct { - message interface{} -} - -// Value receiver. -func (p PanicGo) GoString() string { - panic(p.message) -} - -// PanicF is a type that panics in Format. -type PanicF struct { - message interface{} -} - -// Value receiver. -func (p PanicF) Format(f fmt.State, c rune) { - panic(p.message) -} - -var panictests = []struct { - desc string - fmt string - in interface{} - out string -}{ - // String - {"String", "%s", (*PanicS)(nil), ""}, // nil pointer special case - {"String", "%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"}, - {"String", "%s", PanicS{3}, "%!s(PANIC=3)"}, - // GoString - {"GoString", "%#v", (*PanicGo)(nil), ""}, // nil pointer special case - {"GoString", "%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"}, - {"GoString", "%#v", PanicGo{3}, "%!v(PANIC=3)"}, - // Issue 18282. catchPanic should not clear fmtFlags permanently. - {"Issue 18282", "%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!v(PANIC=3), %!v(PANIC=3)}"}, - // Format - {"Format", "%s", (*PanicF)(nil), ""}, // nil pointer special case - {"Format", "%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"}, - {"Format", "%s", PanicF{3}, "%!s(PANIC=3)"}, -} - -func TestPanics(t *testing.T) { - p := NewPrinter(language.Und) - for i, tt := range panictests { - t.Run(fmt.Sprint(tt.desc, "/", tt.fmt, "/", tt.in), func(t *testing.T) { - s := p.Sprintf(tt.fmt, tt.in) - if s != tt.out { - t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) - } - }) - } -} - -// recurCount tests that erroneous String routine doesn't cause fatal recursion. -var recurCount = 0 - -type Recur struct { - i int - failed *bool -} - -func (r *Recur) String() string { - p := NewPrinter(language.Und) - if recurCount++; recurCount > 10 { - *r.failed = true - return "FAIL" - } - // This will call badVerb. Before the fix, that would cause us to recur into - // this routine to print %!p(value). Now we don't call the user's method - // during an error. - return p.Sprintf("recur@%p value: %d", r, r.i) -} - -func TestBadVerbRecursion(t *testing.T) { - p := NewPrinter(language.Und) - failed := false - r := &Recur{3, &failed} - p.Sprintf("recur@%p value: %d\n", &r, r.i) - if failed { - t.Error("fail with pointer") - } - failed = false - r = &Recur{4, &failed} - p.Sprintf("recur@%p, value: %d\n", r, r.i) - if failed { - t.Error("fail with value") - } -} - -func TestNilDoesNotBecomeTyped(t *testing.T) { - p := NewPrinter(language.Und) - type A struct{} - type B struct{} - var a *A = nil - var b B = B{} - - // indirect the Sprintf call through this noVetWarn variable to avoid - // "go test" failing vet checks in Go 1.10+. - noVetWarn := p.Sprintf - got := noVetWarn("%s %s %s %s %s", nil, a, nil, b, nil) - - const expect = "%!s() %!s(*message.A=) %!s() {} %!s()" - if got != expect { - t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) - } -} - -var formatterFlagTests = []struct { - in string - val interface{} - out string -}{ - // scalar values with the (unused by fmt) 'a' verb. - {"%a", flagPrinter{}, "[%a]"}, - {"%-a", flagPrinter{}, "[%-a]"}, - {"%+a", flagPrinter{}, "[%+a]"}, - {"%#a", flagPrinter{}, "[%#a]"}, - {"% a", flagPrinter{}, "[% a]"}, - {"%0a", flagPrinter{}, "[%0a]"}, - {"%1.2a", flagPrinter{}, "[%1.2a]"}, - {"%-1.2a", flagPrinter{}, "[%-1.2a]"}, - {"%+1.2a", flagPrinter{}, "[%+1.2a]"}, - {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"}, - {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"}, - {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"}, - - // composite values with the 'a' verb - {"%a", [1]flagPrinter{}, "[[%a]]"}, - {"%-a", [1]flagPrinter{}, "[[%-a]]"}, - {"%+a", [1]flagPrinter{}, "[[%+a]]"}, - {"%#a", [1]flagPrinter{}, "[[%#a]]"}, - {"% a", [1]flagPrinter{}, "[[% a]]"}, - {"%0a", [1]flagPrinter{}, "[[%0a]]"}, - {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"}, - {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"}, - {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"}, - {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"}, - {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"}, - {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"}, - - // simple values with the 'v' verb - {"%v", flagPrinter{}, "[%v]"}, - {"%-v", flagPrinter{}, "[%-v]"}, - {"%+v", flagPrinter{}, "[%+v]"}, - {"%#v", flagPrinter{}, "[%#v]"}, - {"% v", flagPrinter{}, "[% v]"}, - {"%0v", flagPrinter{}, "[%0v]"}, - {"%1.2v", flagPrinter{}, "[%1.2v]"}, - {"%-1.2v", flagPrinter{}, "[%-1.2v]"}, - {"%+1.2v", flagPrinter{}, "[%+1.2v]"}, - {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"}, - {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"}, - {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"}, - - // composite values with the 'v' verb. - {"%v", [1]flagPrinter{}, "[[%v]]"}, - {"%-v", [1]flagPrinter{}, "[[%-v]]"}, - {"%+v", [1]flagPrinter{}, "[[%+v]]"}, - {"%#v", [1]flagPrinter{}, "[1]message.flagPrinter{[%#v]}"}, - {"% v", [1]flagPrinter{}, "[[% v]]"}, - {"%0v", [1]flagPrinter{}, "[[%0v]]"}, - {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"}, - {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"}, - {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"}, - {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"}, - {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"}, - {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"}, -} - -func TestFormatterFlags(t *testing.T) { - p := NewPrinter(language.Und) - for _, tt := range formatterFlagTests { - s := p.Sprintf(tt.in, tt.val) - if s != tt.out { - t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out) - } - } -} diff --git a/vendor/golang.org/x/text/message/format.go b/vendor/golang.org/x/text/message/format.go deleted file mode 100644 index a47d17dd4..000000000 --- a/vendor/golang.org/x/text/message/format.go +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -import ( - "bytes" - "strconv" - "unicode/utf8" - - "golang.org/x/text/internal/format" -) - -const ( - ldigits = "0123456789abcdefx" - udigits = "0123456789ABCDEFX" -) - -const ( - signed = true - unsigned = false -) - -// A formatInfo is the raw formatter used by Printf etc. -// It prints into a buffer that must be set up separately. -type formatInfo struct { - buf *bytes.Buffer - - format.Parser - - // intbuf is large enough to store %b of an int64 with a sign and - // avoids padding at the end of the struct on 32 bit architectures. - intbuf [68]byte -} - -func (f *formatInfo) init(buf *bytes.Buffer) { - f.ClearFlags() - f.buf = buf -} - -// writePadding generates n bytes of padding. -func (f *formatInfo) writePadding(n int) { - if n <= 0 { // No padding bytes needed. - return - } - f.buf.Grow(n) - // Decide which byte the padding should be filled with. - padByte := byte(' ') - if f.Zero { - padByte = byte('0') - } - // Fill padding with padByte. - for i := 0; i < n; i++ { - f.buf.WriteByte(padByte) // TODO: make more efficient. - } -} - -// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus). -func (f *formatInfo) pad(b []byte) { - if !f.WidthPresent || f.Width == 0 { - f.buf.Write(b) - return - } - width := f.Width - utf8.RuneCount(b) - if !f.Minus { - // left padding - f.writePadding(width) - f.buf.Write(b) - } else { - // right padding - f.buf.Write(b) - f.writePadding(width) - } -} - -// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus). -func (f *formatInfo) padString(s string) { - if !f.WidthPresent || f.Width == 0 { - f.buf.WriteString(s) - return - } - width := f.Width - utf8.RuneCountInString(s) - if !f.Minus { - // left padding - f.writePadding(width) - f.buf.WriteString(s) - } else { - // right padding - f.buf.WriteString(s) - f.writePadding(width) - } -} - -// fmt_boolean formats a boolean. -func (f *formatInfo) fmt_boolean(v bool) { - if v { - f.padString("true") - } else { - f.padString("false") - } -} - -// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'". -func (f *formatInfo) fmt_unicode(u uint64) { - buf := f.intbuf[0:] - - // With default precision set the maximum needed buf length is 18 - // for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits - // into the already allocated intbuf with a capacity of 68 bytes. - prec := 4 - if f.PrecPresent && f.Prec > 4 { - prec = f.Prec - // Compute space needed for "U+" , number, " '", character, "'". - width := 2 + prec + 2 + utf8.UTFMax + 1 - if width > len(buf) { - buf = make([]byte, width) - } - } - - // Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left. - i := len(buf) - - // For %#U we want to add a space and a quoted character at the end of the buffer. - if f.Sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) { - i-- - buf[i] = '\'' - i -= utf8.RuneLen(rune(u)) - utf8.EncodeRune(buf[i:], rune(u)) - i-- - buf[i] = '\'' - i-- - buf[i] = ' ' - } - // Format the Unicode code point u as a hexadecimal number. - for u >= 16 { - i-- - buf[i] = udigits[u&0xF] - prec-- - u >>= 4 - } - i-- - buf[i] = udigits[u] - prec-- - // Add zeros in front of the number until requested precision is reached. - for prec > 0 { - i-- - buf[i] = '0' - prec-- - } - // Add a leading "U+". - i-- - buf[i] = '+' - i-- - buf[i] = 'U' - - oldZero := f.Zero - f.Zero = false - f.pad(buf[i:]) - f.Zero = oldZero -} - -// fmt_integer formats signed and unsigned integers. -func (f *formatInfo) fmt_integer(u uint64, base int, isSigned bool, digits string) { - negative := isSigned && int64(u) < 0 - if negative { - u = -u - } - - buf := f.intbuf[0:] - // The already allocated f.intbuf with a capacity of 68 bytes - // is large enough for integer formatting when no precision or width is set. - if f.WidthPresent || f.PrecPresent { - // Account 3 extra bytes for possible addition of a sign and "0x". - width := 3 + f.Width + f.Prec // wid and prec are always positive. - if width > len(buf) { - // We're going to need a bigger boat. - buf = make([]byte, width) - } - } - - // Two ways to ask for extra leading zero digits: %.3d or %03d. - // If both are specified the f.zero flag is ignored and - // padding with spaces is used instead. - prec := 0 - if f.PrecPresent { - prec = f.Prec - // Precision of 0 and value of 0 means "print nothing" but padding. - if prec == 0 && u == 0 { - oldZero := f.Zero - f.Zero = false - f.writePadding(f.Width) - f.Zero = oldZero - return - } - } else if f.Zero && f.WidthPresent { - prec = f.Width - if negative || f.Plus || f.Space { - prec-- // leave room for sign - } - } - - // Because printing is easier right-to-left: format u into buf, ending at buf[i]. - // We could make things marginally faster by splitting the 32-bit case out - // into a separate block but it's not worth the duplication, so u has 64 bits. - i := len(buf) - // Use constants for the division and modulo for more efficient code. - // Switch cases ordered by popularity. - switch base { - case 10: - for u >= 10 { - i-- - next := u / 10 - buf[i] = byte('0' + u - next*10) - u = next - } - case 16: - for u >= 16 { - i-- - buf[i] = digits[u&0xF] - u >>= 4 - } - case 8: - for u >= 8 { - i-- - buf[i] = byte('0' + u&7) - u >>= 3 - } - case 2: - for u >= 2 { - i-- - buf[i] = byte('0' + u&1) - u >>= 1 - } - default: - panic("fmt: unknown base; can't happen") - } - i-- - buf[i] = digits[u] - for i > 0 && prec > len(buf)-i { - i-- - buf[i] = '0' - } - - // Various prefixes: 0x, -, etc. - if f.Sharp { - switch base { - case 8: - if buf[i] != '0' { - i-- - buf[i] = '0' - } - case 16: - // Add a leading 0x or 0X. - i-- - buf[i] = digits[16] - i-- - buf[i] = '0' - } - } - - if negative { - i-- - buf[i] = '-' - } else if f.Plus { - i-- - buf[i] = '+' - } else if f.Space { - i-- - buf[i] = ' ' - } - - // Left padding with zeros has already been handled like precision earlier - // or the f.zero flag is ignored due to an explicitly set precision. - oldZero := f.Zero - f.Zero = false - f.pad(buf[i:]) - f.Zero = oldZero -} - -// truncate truncates the string to the specified precision, if present. -func (f *formatInfo) truncate(s string) string { - if f.PrecPresent { - n := f.Prec - for i := range s { - n-- - if n < 0 { - return s[:i] - } - } - } - return s -} - -// fmt_s formats a string. -func (f *formatInfo) fmt_s(s string) { - s = f.truncate(s) - f.padString(s) -} - -// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes. -func (f *formatInfo) fmt_sbx(s string, b []byte, digits string) { - length := len(b) - if b == nil { - // No byte slice present. Assume string s should be encoded. - length = len(s) - } - // Set length to not process more bytes than the precision demands. - if f.PrecPresent && f.Prec < length { - length = f.Prec - } - // Compute width of the encoding taking into account the f.sharp and f.space flag. - width := 2 * length - if width > 0 { - if f.Space { - // Each element encoded by two hexadecimals will get a leading 0x or 0X. - if f.Sharp { - width *= 2 - } - // Elements will be separated by a space. - width += length - 1 - } else if f.Sharp { - // Only a leading 0x or 0X will be added for the whole string. - width += 2 - } - } else { // The byte slice or string that should be encoded is empty. - if f.WidthPresent { - f.writePadding(f.Width) - } - return - } - // Handle padding to the left. - if f.WidthPresent && f.Width > width && !f.Minus { - f.writePadding(f.Width - width) - } - // Write the encoding directly into the output buffer. - buf := f.buf - if f.Sharp { - // Add leading 0x or 0X. - buf.WriteByte('0') - buf.WriteByte(digits[16]) - } - var c byte - for i := 0; i < length; i++ { - if f.Space && i > 0 { - // Separate elements with a space. - buf.WriteByte(' ') - if f.Sharp { - // Add leading 0x or 0X for each element. - buf.WriteByte('0') - buf.WriteByte(digits[16]) - } - } - if b != nil { - c = b[i] // Take a byte from the input byte slice. - } else { - c = s[i] // Take a byte from the input string. - } - // Encode each byte as two hexadecimal digits. - buf.WriteByte(digits[c>>4]) - buf.WriteByte(digits[c&0xF]) - } - // Handle padding to the right. - if f.WidthPresent && f.Width > width && f.Minus { - f.writePadding(f.Width - width) - } -} - -// fmt_sx formats a string as a hexadecimal encoding of its bytes. -func (f *formatInfo) fmt_sx(s, digits string) { - f.fmt_sbx(s, nil, digits) -} - -// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes. -func (f *formatInfo) fmt_bx(b []byte, digits string) { - f.fmt_sbx("", b, digits) -} - -// fmt_q formats a string as a double-quoted, escaped Go string constant. -// If f.sharp is set a raw (backquoted) string may be returned instead -// if the string does not contain any control characters other than tab. -func (f *formatInfo) fmt_q(s string) { - s = f.truncate(s) - if f.Sharp && strconv.CanBackquote(s) { - f.padString("`" + s + "`") - return - } - buf := f.intbuf[:0] - if f.Plus { - f.pad(strconv.AppendQuoteToASCII(buf, s)) - } else { - f.pad(strconv.AppendQuote(buf, s)) - } -} - -// fmt_c formats an integer as a Unicode character. -// If the character is not valid Unicode, it will print '\ufffd'. -func (f *formatInfo) fmt_c(c uint64) { - r := rune(c) - if c > utf8.MaxRune { - r = utf8.RuneError - } - buf := f.intbuf[:0] - w := utf8.EncodeRune(buf[:utf8.UTFMax], r) - f.pad(buf[:w]) -} - -// fmt_qc formats an integer as a single-quoted, escaped Go character constant. -// If the character is not valid Unicode, it will print '\ufffd'. -func (f *formatInfo) fmt_qc(c uint64) { - r := rune(c) - if c > utf8.MaxRune { - r = utf8.RuneError - } - buf := f.intbuf[:0] - if f.Plus { - f.pad(strconv.AppendQuoteRuneToASCII(buf, r)) - } else { - f.pad(strconv.AppendQuoteRune(buf, r)) - } -} - -// fmt_float formats a float64. It assumes that verb is a valid format specifier -// for strconv.AppendFloat and therefore fits into a byte. -func (f *formatInfo) fmt_float(v float64, size int, verb rune, prec int) { - // Explicit precision in format specifier overrules default precision. - if f.PrecPresent { - prec = f.Prec - } - // Format number, reserving space for leading + sign if needed. - num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size) - if num[1] == '-' || num[1] == '+' { - num = num[1:] - } else { - num[0] = '+' - } - // f.space means to add a leading space instead of a "+" sign unless - // the sign is explicitly asked for by f.plus. - if f.Space && num[0] == '+' && !f.Plus { - num[0] = ' ' - } - // Special handling for infinities and NaN, - // which don't look like a number so shouldn't be padded with zeros. - if num[1] == 'I' || num[1] == 'N' { - oldZero := f.Zero - f.Zero = false - // Remove sign before NaN if not asked for. - if num[1] == 'N' && !f.Space && !f.Plus { - num = num[1:] - } - f.pad(num) - f.Zero = oldZero - return - } - // The sharp flag forces printing a decimal point for non-binary formats - // and retains trailing zeros, which we may need to restore. - if f.Sharp && verb != 'b' { - digits := 0 - switch verb { - case 'v', 'g', 'G': - digits = prec - // If no precision is set explicitly use a precision of 6. - if digits == -1 { - digits = 6 - } - } - - // Buffer pre-allocated with enough room for - // exponent notations of the form "e+123". - var tailBuf [5]byte - tail := tailBuf[:0] - - hasDecimalPoint := false - // Starting from i = 1 to skip sign at num[0]. - for i := 1; i < len(num); i++ { - switch num[i] { - case '.': - hasDecimalPoint = true - case 'e', 'E': - tail = append(tail, num[i:]...) - num = num[:i] - default: - digits-- - } - } - if !hasDecimalPoint { - num = append(num, '.') - } - for digits > 0 { - num = append(num, '0') - digits-- - } - num = append(num, tail...) - } - // We want a sign if asked for and if the sign is not positive. - if f.Plus || num[0] != '+' { - // If we're zero padding to the left we want the sign before the leading zeros. - // Achieve this by writing the sign out and then padding the unsigned number. - if f.Zero && f.WidthPresent && f.Width > len(num) { - f.buf.WriteByte(num[0]) - f.writePadding(f.Width - len(num)) - f.buf.Write(num[1:]) - return - } - f.pad(num) - return - } - // No sign to show and the number is positive; just print the unsigned number. - f.pad(num[1:]) -} diff --git a/vendor/golang.org/x/text/message/message.go b/vendor/golang.org/x/text/message/message.go deleted file mode 100644 index a3473bffd..000000000 --- a/vendor/golang.org/x/text/message/message.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message // import "golang.org/x/text/message" - -import ( - "io" - "os" - - // Include features to facilitate generated catalogs. - _ "golang.org/x/text/feature/plural" - - "golang.org/x/text/internal/number" - "golang.org/x/text/language" - "golang.org/x/text/message/catalog" -) - -// A Printer implements language-specific formatted I/O analogous to the fmt -// package. -type Printer struct { - // the language - tag language.Tag - - toDecimal number.Formatter - toScientific number.Formatter - - cat catalog.Catalog -} - -type options struct { - cat catalog.Catalog - // TODO: - // - allow %s to print integers in written form (tables are likely too large - // to enable this by default). - // - list behavior - // -} - -// An Option defines an option of a Printer. -type Option func(o *options) - -// Catalog defines the catalog to be used. -func Catalog(c catalog.Catalog) Option { - return func(o *options) { o.cat = c } -} - -// NewPrinter returns a Printer that formats messages tailored to language t. -func NewPrinter(t language.Tag, opts ...Option) *Printer { - options := &options{ - cat: DefaultCatalog, - } - for _, o := range opts { - o(options) - } - p := &Printer{ - tag: t, - cat: options.cat, - } - p.toDecimal.InitDecimal(t) - p.toScientific.InitScientific(t) - return p -} - -// Sprint is like fmt.Sprint, but using language-specific formatting. -func (p *Printer) Sprint(a ...interface{}) string { - pp := newPrinter(p) - pp.doPrint(a) - s := pp.String() - pp.free() - return s -} - -// Fprint is like fmt.Fprint, but using language-specific formatting. -func (p *Printer) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - pp := newPrinter(p) - pp.doPrint(a) - n64, err := io.Copy(w, &pp.Buffer) - pp.free() - return int(n64), err -} - -// Print is like fmt.Print, but using language-specific formatting. -func (p *Printer) Print(a ...interface{}) (n int, err error) { - return p.Fprint(os.Stdout, a...) -} - -// Sprintln is like fmt.Sprintln, but using language-specific formatting. -func (p *Printer) Sprintln(a ...interface{}) string { - pp := newPrinter(p) - pp.doPrintln(a) - s := pp.String() - pp.free() - return s -} - -// Fprintln is like fmt.Fprintln, but using language-specific formatting. -func (p *Printer) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - pp := newPrinter(p) - pp.doPrintln(a) - n64, err := io.Copy(w, &pp.Buffer) - pp.free() - return int(n64), err -} - -// Println is like fmt.Println, but using language-specific formatting. -func (p *Printer) Println(a ...interface{}) (n int, err error) { - return p.Fprintln(os.Stdout, a...) -} - -// Sprintf is like fmt.Sprintf, but using language-specific formatting. -func (p *Printer) Sprintf(key Reference, a ...interface{}) string { - pp := newPrinter(p) - lookupAndFormat(pp, key, a) - s := pp.String() - pp.free() - return s -} - -// Fprintf is like fmt.Fprintf, but using language-specific formatting. -func (p *Printer) Fprintf(w io.Writer, key Reference, a ...interface{}) (n int, err error) { - pp := newPrinter(p) - lookupAndFormat(pp, key, a) - n, err = w.Write(pp.Bytes()) - pp.free() - return n, err - -} - -// Printf is like fmt.Printf, but using language-specific formatting. -func (p *Printer) Printf(key Reference, a ...interface{}) (n int, err error) { - pp := newPrinter(p) - lookupAndFormat(pp, key, a) - n, err = os.Stdout.Write(pp.Bytes()) - pp.free() - return n, err -} - -func lookupAndFormat(p *printer, r Reference, a []interface{}) { - p.fmt.Reset(a) - var id, msg string - switch v := r.(type) { - case string: - id, msg = v, v - case key: - id, msg = v.id, v.fallback - default: - panic("key argument is not a Reference") - } - - if p.catContext.Execute(id) == catalog.ErrNotFound { - if p.catContext.Execute(msg) == catalog.ErrNotFound { - p.Render(msg) - return - } - } -} - -// Arg implements catmsg.Renderer. -func (p *printer) Arg(i int) interface{} { // TODO, also return "ok" bool - i-- - if uint(i) < uint(len(p.fmt.Args)) { - return p.fmt.Args[i] - } - return nil -} - -// Render implements catmsg.Renderer. -func (p *printer) Render(msg string) { - p.doPrintf(msg) -} - -// A Reference is a string or a message reference. -type Reference interface { - // TODO: also allow []string -} - -// Key creates a message Reference for a message where the given id is used for -// message lookup and the fallback is returned when no matches are found. -func Key(id string, fallback string) Reference { - return key{id, fallback} -} - -type key struct { - id, fallback string -} diff --git a/vendor/golang.org/x/text/message/message_test.go b/vendor/golang.org/x/text/message/message_test.go deleted file mode 100644 index 326f716fb..000000000 --- a/vendor/golang.org/x/text/message/message_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -import ( - "bytes" - "fmt" - "io" - "testing" - - "golang.org/x/text/internal" - "golang.org/x/text/internal/format" - "golang.org/x/text/language" - "golang.org/x/text/message/catalog" -) - -type formatFunc func(s fmt.State, v rune) - -func (f formatFunc) Format(s fmt.State, v rune) { f(s, v) } - -func TestBinding(t *testing.T) { - testCases := []struct { - tag string - value interface{} - want string - }{ - {"en", 1, "1"}, - {"en", "2", "2"}, - { // Language is passed. - "en", - formatFunc(func(fs fmt.State, v rune) { - s := fs.(format.State) - io.WriteString(s, s.Language().String()) - }), - "en", - }, - } - for i, tc := range testCases { - p := NewPrinter(language.MustParse(tc.tag)) - if got := p.Sprint(tc.value); got != tc.want { - t.Errorf("%d:%s:Sprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want) - } - var buf bytes.Buffer - p.Fprint(&buf, tc.value) - if got := buf.String(); got != tc.want { - t.Errorf("%d:%s:Fprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want) - } - } -} - -func TestLocalization(t *testing.T) { - type test struct { - tag string - key Reference - args []interface{} - want string - } - args := func(x ...interface{}) []interface{} { return x } - empty := []interface{}{} - joe := []interface{}{"Joe"} - joeAndMary := []interface{}{"Joe", "Mary"} - - testCases := []struct { - desc string - cat []entry - test []test - }{{ - desc: "empty", - test: []test{ - {"en", "key", empty, "key"}, - {"en", "", empty, ""}, - {"nl", "", empty, ""}, - }, - }, { - desc: "hierarchical languages", - cat: []entry{ - {"en", "hello %s", "Hello %s!"}, - {"en-GB", "hello %s", "Hellø %s!"}, - {"en-US", "hello %s", "Howdy %s!"}, - {"en", "greetings %s and %s", "Greetings %s and %s!"}, - }, - test: []test{ - {"und", "hello %s", joe, "hello Joe"}, - {"nl", "hello %s", joe, "hello Joe"}, - {"en", "hello %s", joe, "Hello Joe!"}, - {"en-US", "hello %s", joe, "Howdy Joe!"}, - {"en-GB", "hello %s", joe, "Hellø Joe!"}, - {"en-oxendict", "hello %s", joe, "Hello Joe!"}, - {"en-US-oxendict-u-ms-metric", "hello %s", joe, "Howdy Joe!"}, - - {"und", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"}, - {"nl", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"}, - {"en", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"}, - {"en-US", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"}, - {"en-GB", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"}, - {"en-oxendict", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"}, - {"en-US-oxendict-u-ms-metric", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"}, - }, - }, { - desc: "references", - cat: []entry{ - {"en", "hello", "Hello!"}, - }, - test: []test{ - {"en", "hello", empty, "Hello!"}, - {"en", Key("hello", "fallback"), empty, "Hello!"}, - {"en", Key("xxx", "fallback"), empty, "fallback"}, - {"und", Key("hello", "fallback"), empty, "fallback"}, - }, - }, { - desc: "zero substitution", // work around limitation of fmt - cat: []entry{ - {"en", "hello %s", "Hello!"}, - {"en", "hi %s and %s", "Hello %[2]s!"}, - }, - test: []test{ - {"en", "hello %s", joe, "Hello!"}, - {"en", "hello %s", joeAndMary, "Hello!"}, - {"en", "hi %s and %s", joeAndMary, "Hello Mary!"}, - // The following tests resolve to the fallback string. - {"und", "hello", joeAndMary, "hello"}, - {"und", "hello %%%%", joeAndMary, "hello %%"}, - {"und", "hello %#%%4.2% ", joeAndMary, "hello %% "}, - {"und", "hello %s", joeAndMary, "hello Joe%!(EXTRA string=Mary)"}, - {"und", "hello %+%%s", joeAndMary, "hello %Joe%!(EXTRA string=Mary)"}, - {"und", "hello %-42%%s ", joeAndMary, "hello %Joe %!(EXTRA string=Mary)"}, - }, - }, { - desc: "number formatting", // work around limitation of fmt - cat: []entry{ - {"und", "files", "%d files left"}, - {"und", "meters", "%.2f meters"}, - {"de", "files", "%d Dateien übrig"}, - }, - test: []test{ - {"en", "meters", args(3000.2), "3,000.20 meters"}, - {"en-u-nu-gujr", "files", args(123456), "૧૨૩,૪૫૬ files left"}, - {"de", "files", args(1234), "1.234 Dateien übrig"}, - {"de-CH", "files", args(1234), "1’234 Dateien übrig"}, - {"de-CH-u-nu-mong", "files", args(1234), "᠑’᠒᠓᠔ Dateien übrig"}, - }, - }} - - for _, tc := range testCases { - cat, _ := initCat(tc.cat) - - for i, pt := range tc.test { - t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) { - p := NewPrinter(language.MustParse(pt.tag), Catalog(cat)) - - if got := p.Sprintf(pt.key, pt.args...); got != pt.want { - t.Errorf("Sprintf(%q, %v) = %s; want %s", - pt.key, pt.args, got, pt.want) - return // Next error will likely be the same. - } - - w := &bytes.Buffer{} - p.Fprintf(w, pt.key, pt.args...) - if got := w.String(); got != pt.want { - t.Errorf("Fprintf(%q, %v) = %s; want %s", - pt.key, pt.args, got, pt.want) - } - }) - } - } -} - -type entry struct{ tag, key, msg string } - -func initCat(entries []entry) (*catalog.Builder, []language.Tag) { - tags := []language.Tag{} - cat := catalog.NewBuilder() - for _, e := range entries { - tag := language.MustParse(e.tag) - tags = append(tags, tag) - cat.SetString(tag, e.key, e.msg) - } - return cat, internal.UniqueTags(tags) -} diff --git a/vendor/golang.org/x/text/message/pipeline/extract.go b/vendor/golang.org/x/text/message/pipeline/extract.go deleted file mode 100644 index 379cc6d86..000000000 --- a/vendor/golang.org/x/text/message/pipeline/extract.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pipeline - -import ( - "bytes" - "fmt" - "go/ast" - "go/constant" - "go/format" - "go/token" - "go/types" - "path" - "path/filepath" - "strings" - "unicode" - "unicode/utf8" - - fmtparser "golang.org/x/text/internal/format" - "golang.org/x/tools/go/loader" -) - -// TODO: -// - merge information into existing files -// - handle different file formats (PO, XLIFF) -// - handle features (gender, plural) -// - message rewriting - -// - %m substitutions -// - `msg:"etc"` tags -// - msg/Msg top-level vars and strings. - -// Extract extracts all strings form the package defined in Config. -func Extract(c *Config) (*State, error) { - conf := loader.Config{} - prog, err := loadPackages(&conf, c.Packages) - if err != nil { - return nil, wrap(err, "") - } - - // print returns Go syntax for the specified node. - print := func(n ast.Node) string { - var buf bytes.Buffer - format.Node(&buf, conf.Fset, n) - return buf.String() - } - - var messages []Message - - for _, info := range prog.AllPackages { - for _, f := range info.Files { - // Associate comments with nodes. - cmap := ast.NewCommentMap(prog.Fset, f, f.Comments) - getComment := func(n ast.Node) string { - cs := cmap.Filter(n).Comments() - if len(cs) > 0 { - return strings.TrimSpace(cs[0].Text()) - } - return "" - } - - // Find function calls. - ast.Inspect(f, func(n ast.Node) bool { - call, ok := n.(*ast.CallExpr) - if !ok { - return true - } - - // Skip calls of functions other than - // (*message.Printer).{Sp,Fp,P}rintf. - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return true - } - meth := info.Selections[sel] - if meth == nil || meth.Kind() != types.MethodVal { - return true - } - // TODO: remove cheap hack and check if the type either - // implements some interface or is specifically of type - // "golang.org/x/text/message".Printer. - m, ok := extractFuncs[path.Base(meth.Recv().String())] - if !ok { - return true - } - - fmtType, ok := m[meth.Obj().Name()] - if !ok { - return true - } - // argn is the index of the format string. - argn := fmtType.arg - if argn >= len(call.Args) { - return true - } - - args := call.Args[fmtType.arg:] - - fmtMsg, ok := msgStr(info, args[0]) - if !ok { - // TODO: identify the type of the format argument. If it - // is not a string, multiple keys may be defined. - return true - } - comment := "" - key := []string{} - if ident, ok := args[0].(*ast.Ident); ok { - key = append(key, ident.Name) - if v, ok := ident.Obj.Decl.(*ast.ValueSpec); ok && v.Comment != nil { - // TODO: get comment above ValueSpec as well - comment = v.Comment.Text() - } - } - - arguments := []argument{} - args = args[1:] - simArgs := make([]interface{}, len(args)) - for i, arg := range args { - expr := print(arg) - val := "" - if v := info.Types[arg].Value; v != nil { - val = v.ExactString() - simArgs[i] = val - switch arg.(type) { - case *ast.BinaryExpr, *ast.UnaryExpr: - expr = val - } - } - arguments = append(arguments, argument{ - ArgNum: i + 1, - Type: info.Types[arg].Type.String(), - UnderlyingType: info.Types[arg].Type.Underlying().String(), - Expr: expr, - Value: val, - Comment: getComment(arg), - Position: posString(conf, info, arg.Pos()), - // TODO report whether it implements - // interfaces plural.Interface, - // gender.Interface. - }) - } - msg := "" - - ph := placeholders{index: map[string]string{}} - - trimmed, _, _ := trimWS(fmtMsg) - - p := fmtparser.Parser{} - p.Reset(simArgs) - for p.SetFormat(trimmed); p.Scan(); { - switch p.Status { - case fmtparser.StatusText: - msg += p.Text() - case fmtparser.StatusSubstitution, - fmtparser.StatusBadWidthSubstitution, - fmtparser.StatusBadPrecSubstitution: - arguments[p.ArgNum-1].used = true - arg := arguments[p.ArgNum-1] - sub := p.Text() - if !p.HasIndex { - r, sz := utf8.DecodeLastRuneInString(sub) - sub = fmt.Sprintf("%s[%d]%c", sub[:len(sub)-sz], p.ArgNum, r) - } - msg += fmt.Sprintf("{%s}", ph.addArg(&arg, sub)) - } - } - key = append(key, msg) - - // Add additional Placeholders that can be used in translations - // that are not present in the string. - for _, arg := range arguments { - if arg.used { - continue - } - ph.addArg(&arg, fmt.Sprintf("%%[%d]v", arg.ArgNum)) - } - - if c := getComment(call.Args[0]); c != "" { - comment = c - } - - messages = append(messages, Message{ - ID: key, - Key: fmtMsg, - Message: Text{Msg: msg}, - // TODO(fix): this doesn't get the before comment. - Comment: comment, - Placeholders: ph.slice, - Position: posString(conf, info, call.Lparen), - }) - return true - }) - } - } - - return &State{ - Config: *c, - program: prog, - Extracted: Messages{ - Language: c.SourceLanguage, - Messages: messages, - }, - }, nil -} - -func posString(conf loader.Config, info *loader.PackageInfo, pos token.Pos) string { - p := conf.Fset.Position(pos) - file := fmt.Sprintf("%s:%d:%d", filepath.Base(p.Filename), p.Line, p.Column) - return filepath.Join(info.Pkg.Path(), file) -} - -// extractFuncs indicates the types and methods for which to extract strings, -// and which argument to extract. -// TODO: use the types in conf.Import("golang.org/x/text/message") to extract -// the correct instances. -var extractFuncs = map[string]map[string]extractType{ - // TODO: Printer -> *golang.org/x/text/message.Printer - "message.Printer": { - "Printf": extractType{arg: 0, format: true}, - "Sprintf": extractType{arg: 0, format: true}, - "Fprintf": extractType{arg: 1, format: true}, - - "Lookup": extractType{arg: 0}, - }, -} - -type extractType struct { - // format indicates if the next arg is a formatted string or whether to - // concatenate all arguments - format bool - // arg indicates the position of the argument to extract. - arg int -} - -func getID(arg *argument) string { - s := getLastComponent(arg.Expr) - s = strip(s) - s = strings.Replace(s, " ", "", -1) - // For small variable names, use user-defined types for more info. - if len(s) <= 2 && arg.UnderlyingType != arg.Type { - s = getLastComponent(arg.Type) - } - return strings.Title(s) -} - -// strip is a dirty hack to convert function calls to placeholder IDs. -func strip(s string) string { - s = strings.Map(func(r rune) rune { - if unicode.IsSpace(r) || r == '-' { - return '_' - } - if !unicode.In(r, unicode.Letter, unicode.Mark, unicode.Number) { - return -1 - } - return r - }, s) - // Strip "Get" from getter functions. - if strings.HasPrefix(s, "Get") || strings.HasPrefix(s, "get") { - if len(s) > len("get") { - r, _ := utf8.DecodeRuneInString(s) - if !unicode.In(r, unicode.Ll, unicode.M) { // not lower or mark - s = s[len("get"):] - } - } - } - return s -} - -type placeholders struct { - index map[string]string - slice []Placeholder -} - -func (p *placeholders) addArg(arg *argument, sub string) (id string) { - id = getID(arg) - id1 := id - alt, ok := p.index[id1] - for i := 1; ok && alt != sub; i++ { - id1 = fmt.Sprintf("%s_%d", id, i) - alt, ok = p.index[id1] - } - p.index[id1] = sub - p.slice = append(p.slice, Placeholder{ - ID: id1, - String: sub, - Type: arg.Type, - UnderlyingType: arg.UnderlyingType, - ArgNum: arg.ArgNum, - Expr: arg.Expr, - Comment: arg.Comment, - }) - return id1 -} - -func getLastComponent(s string) string { - return s[1+strings.LastIndexByte(s, '.'):] -} - -func msgStr(info *loader.PackageInfo, e ast.Expr) (s string, ok bool) { - v := info.Types[e].Value - if v == nil || v.Kind() != constant.String { - return "", false - } - s = constant.StringVal(v) - // Only record strings with letters. - for _, r := range s { - if unicode.In(r, unicode.L) { - return s, true - } - } - return "", false -} diff --git a/vendor/golang.org/x/text/message/pipeline/generate.go b/vendor/golang.org/x/text/message/pipeline/generate.go deleted file mode 100644 index 5d329b2f4..000000000 --- a/vendor/golang.org/x/text/message/pipeline/generate.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pipeline - -import ( - "fmt" - "go/build" - "io" - "path/filepath" - "regexp" - "sort" - "strings" - "text/template" - - "golang.org/x/text/collate" - "golang.org/x/text/feature/plural" - "golang.org/x/text/internal" - "golang.org/x/text/internal/catmsg" - "golang.org/x/text/internal/gen" - "golang.org/x/text/language" - "golang.org/x/tools/go/loader" -) - -var transRe = regexp.MustCompile(`messages\.(.*)\.json`) - -// Generate writes a Go file that defines a Catalog with translated messages. -// Translations are retrieved from s.Messages, not s.Translations, so it -// is assumed Merge has been called. -func (s *State) Generate() error { - path := s.Config.GenPackage - if path == "" { - path = "." - } - isDir := path[0] == '.' - prog, err := loadPackages(&loader.Config{}, []string{path}) - if err != nil { - return wrap(err, "could not load package") - } - pkgs := prog.InitialPackages() - if len(pkgs) != 1 { - return errorf("more than one package selected: %v", pkgs) - } - pkg := pkgs[0].Pkg.Name() - - cw, err := s.generate() - if err != nil { - return err - } - if !isDir { - gopath := build.Default.GOPATH - path = filepath.Join(gopath, filepath.FromSlash(pkgs[0].Pkg.Path())) - } - path = filepath.Join(path, s.Config.GenFile) - cw.WriteGoFile(path, pkg) // TODO: WriteGoFile should return error. - return err -} - -// WriteGen writes a Go file with the given package name to w that defines a -// Catalog with translated messages. Translations are retrieved from s.Messages, -// not s.Translations, so it is assumed Merge has been called. -func (s *State) WriteGen(w io.Writer, pkg string) error { - cw, err := s.generate() - if err != nil { - return err - } - _, err = cw.WriteGo(w, pkg, "") - return err -} - -// Generate is deprecated; use (*State).Generate(). -func Generate(w io.Writer, pkg string, extracted *Messages, trans ...Messages) (n int, err error) { - s := State{ - Extracted: *extracted, - Translations: trans, - } - cw, err := s.generate() - if err != nil { - return 0, err - } - return cw.WriteGo(w, pkg, "") -} - -func (s *State) generate() (*gen.CodeWriter, error) { - // Build up index of translations and original messages. - translations := map[language.Tag]map[string]Message{} - languages := []language.Tag{} - usedKeys := map[string]int{} - - for _, loc := range s.Messages { - tag := loc.Language - if _, ok := translations[tag]; !ok { - translations[tag] = map[string]Message{} - languages = append(languages, tag) - } - for _, m := range loc.Messages { - if !m.Translation.IsEmpty() { - for _, id := range m.ID { - if _, ok := translations[tag][id]; ok { - warnf("Duplicate translation in locale %q for message %q", tag, id) - } - translations[tag][id] = m - } - } - } - } - - // Verify completeness and register keys. - internal.SortTags(languages) - - langVars := []string{} - for _, tag := range languages { - langVars = append(langVars, strings.Replace(tag.String(), "-", "_", -1)) - dict := translations[tag] - for _, msg := range s.Extracted.Messages { - for _, id := range msg.ID { - if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() { - if _, ok := usedKeys[msg.Key]; !ok { - usedKeys[msg.Key] = len(usedKeys) - } - break - } - // TODO: log missing entry. - warnf("%s: Missing entry for %q.", tag, id) - } - } - } - - cw := gen.NewCodeWriter() - - x := &struct { - Fallback language.Tag - Languages []string - }{ - Fallback: s.Extracted.Language, - Languages: langVars, - } - - if err := lookup.Execute(cw, x); err != nil { - return nil, wrap(err, "error") - } - - keyToIndex := []string{} - for k := range usedKeys { - keyToIndex = append(keyToIndex, k) - } - sort.Strings(keyToIndex) - fmt.Fprint(cw, "var messageKeyToIndex = map[string]int{\n") - for _, k := range keyToIndex { - fmt.Fprintf(cw, "%q: %d,\n", k, usedKeys[k]) - } - fmt.Fprint(cw, "}\n\n") - - for i, tag := range languages { - dict := translations[tag] - a := make([]string, len(usedKeys)) - for _, msg := range s.Extracted.Messages { - for _, id := range msg.ID { - if trans, ok := dict[id]; ok && !trans.Translation.IsEmpty() { - m, err := assemble(&msg, &trans.Translation) - if err != nil { - return nil, wrap(err, "error") - } - _, leadWS, trailWS := trimWS(msg.Key) - if leadWS != "" || trailWS != "" { - m = catmsg.Affix{ - Message: m, - Prefix: leadWS, - Suffix: trailWS, - } - } - // TODO: support macros. - data, err := catmsg.Compile(tag, nil, m) - if err != nil { - return nil, wrap(err, "error") - } - key := usedKeys[msg.Key] - if d := a[key]; d != "" && d != data { - warnf("Duplicate non-consistent translation for key %q, picking the one for message %q", msg.Key, id) - } - a[key] = string(data) - break - } - } - } - index := []uint32{0} - p := 0 - for _, s := range a { - p += len(s) - index = append(index, uint32(p)) - } - - cw.WriteVar(langVars[i]+"Index", index) - cw.WriteConst(langVars[i]+"Data", strings.Join(a, "")) - } - return cw, nil -} - -func assemble(m *Message, t *Text) (msg catmsg.Message, err error) { - keys := []string{} - for k := range t.Var { - keys = append(keys, k) - } - sort.Strings(keys) - var a []catmsg.Message - for _, k := range keys { - t := t.Var[k] - m, err := assemble(m, &t) - if err != nil { - return nil, err - } - a = append(a, &catmsg.Var{Name: k, Message: m}) - } - if t.Select != nil { - s, err := assembleSelect(m, t.Select) - if err != nil { - return nil, err - } - a = append(a, s) - } - if t.Msg != "" { - sub, err := m.Substitute(t.Msg) - if err != nil { - return nil, err - } - a = append(a, catmsg.String(sub)) - } - switch len(a) { - case 0: - return nil, errorf("generate: empty message") - case 1: - return a[0], nil - default: - return catmsg.FirstOf(a), nil - - } -} - -func assembleSelect(m *Message, s *Select) (msg catmsg.Message, err error) { - cases := []string{} - for c := range s.Cases { - cases = append(cases, c) - } - sortCases(cases) - - caseMsg := []interface{}{} - for _, c := range cases { - cm := s.Cases[c] - m, err := assemble(m, &cm) - if err != nil { - return nil, err - } - caseMsg = append(caseMsg, c, m) - } - - ph := m.Placeholder(s.Arg) - - switch s.Feature { - case "plural": - // TODO: only printf-style selects are supported as of yet. - return plural.Selectf(ph.ArgNum, ph.String, caseMsg...), nil - } - return nil, errorf("unknown feature type %q", s.Feature) -} - -func sortCases(cases []string) { - // TODO: implement full interface. - sort.Slice(cases, func(i, j int) bool { - if cases[j] == "other" && cases[i] != "other" { - return true - } - // the following code relies on '<' < '=' < any letter. - return cmpNumeric(cases[i], cases[j]) == -1 - }) -} - -var cmpNumeric = collate.New(language.Und, collate.Numeric).CompareString - -var lookup = template.Must(template.New("gen").Parse(` -import ( - "golang.org/x/text/language" - "golang.org/x/text/message" - "golang.org/x/text/message/catalog" -) - -type dictionary struct { - index []uint32 - data string -} - -func (d *dictionary) Lookup(key string) (data string, ok bool) { - p := messageKeyToIndex[key] - start, end := d.index[p], d.index[p+1] - if start == end { - return "", false - } - return d.data[start:end], true -} - -func init() { - dict := map[string]catalog.Dictionary{ - {{range .Languages}}"{{.}}": &dictionary{index: {{.}}Index, data: {{.}}Data }, - {{end}} - } - fallback := language.MustParse("{{.Fallback}}") - cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback)) - if err != nil { - panic(err) - } - message.DefaultCatalog = cat -} - -`)) diff --git a/vendor/golang.org/x/text/message/pipeline/go19_test.go b/vendor/golang.org/x/text/message/pipeline/go19_test.go deleted file mode 100644 index c9517c130..000000000 --- a/vendor/golang.org/x/text/message/pipeline/go19_test.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.9 - -package pipeline - -import "testing" - -func init() { - setHelper = (*testing.T).Helper -} diff --git a/vendor/golang.org/x/text/message/pipeline/message.go b/vendor/golang.org/x/text/message/pipeline/message.go deleted file mode 100644 index c83a8fd87..000000000 --- a/vendor/golang.org/x/text/message/pipeline/message.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pipeline - -import ( - "encoding/json" - "errors" - "strings" - - "golang.org/x/text/language" -) - -// TODO: these definitions should be moved to a package so that the can be used -// by other tools. - -// The file contains the structures used to define translations of a certain -// messages. -// -// A translation may have multiple translations strings, or messages, depending -// on the feature values of the various arguments. For instance, consider -// a hypothetical translation from English to English, where the source defines -// the format string "%d file(s) remaining". -// See the examples directory for examples of extracted messages. - -// Messages is used to store translations for a single language. -type Messages struct { - Language language.Tag `json:"language"` - Messages []Message `json:"messages"` - Macros map[string]Text `json:"macros,omitempty"` -} - -// A Message describes a message to be translated. -type Message struct { - // ID contains a list of identifiers for the message. - ID IDList `json:"id"` - // Key is the string that is used to look up the message at runtime. - Key string `json:"key,omitempty"` - Meaning string `json:"meaning,omitempty"` - Message Text `json:"message"` - Translation Text `json:"translation"` - - Comment string `json:"comment,omitempty"` - TranslatorComment string `json:"translatorComment,omitempty"` - - Placeholders []Placeholder `json:"placeholders,omitempty"` - - // Fuzzy indicates that the provide translation needs review by a - // translator, for instance because it was derived from automated - // translation. - Fuzzy bool `json:"fuzzy,omitempty"` - - // TODO: default placeholder syntax is {foo}. Allow alternative escaping - // like `foo`. - - // Extraction information. - Position string `json:"position,omitempty"` // filePosition:line -} - -// Placeholder reports the placeholder for the given ID if it is defined or nil -// otherwise. -func (m *Message) Placeholder(id string) *Placeholder { - for _, p := range m.Placeholders { - if p.ID == id { - return &p - } - } - return nil -} - -// Substitute replaces placeholders in msg with their original value. -func (m *Message) Substitute(msg string) (sub string, err error) { - last := 0 - for i := 0; i < len(msg); { - pLeft := strings.IndexByte(msg[i:], '{') - if pLeft == -1 { - break - } - pLeft += i - pRight := strings.IndexByte(msg[pLeft:], '}') - if pRight == -1 { - return "", errorf("unmatched '}'") - } - pRight += pLeft - id := strings.TrimSpace(msg[pLeft+1 : pRight]) - i = pRight + 1 - if id != "" && id[0] == '$' { - continue - } - sub += msg[last:pLeft] - last = i - ph := m.Placeholder(id) - if ph == nil { - return "", errorf("unknown placeholder %q in message %q", id, msg) - } - sub += ph.String - } - sub += msg[last:] - return sub, err -} - -var errIncompatibleMessage = errors.New("messages incompatible") - -func checkEquivalence(a, b *Message) error { - for _, v := range a.ID { - for _, w := range b.ID { - if v == w { - return nil - } - } - } - // TODO: canonicalize placeholders and check for type equivalence. - return errIncompatibleMessage -} - -// A Placeholder is a part of the message that should not be changed by a -// translator. It can be used to hide or prettify format strings (e.g. %d or -// {{.Count}}), hide HTML, or mark common names that should not be translated. -type Placeholder struct { - // ID is the placeholder identifier without the curly braces. - ID string `json:"id"` - - // String is the string with which to replace the placeholder. This may be a - // formatting string (for instance "%d" or "{{.Count}}") or a literal string - // (
). - String string `json:"string"` - - Type string `json:"type"` - UnderlyingType string `json:"underlyingType"` - // ArgNum and Expr are set if the placeholder is a substitution of an - // argument. - ArgNum int `json:"argNum,omitempty"` - Expr string `json:"expr,omitempty"` - - Comment string `json:"comment,omitempty"` - Example string `json:"example,omitempty"` - - // Features contains the features that are available for the implementation - // of this argument. - Features []Feature `json:"features,omitempty"` -} - -// An argument contains information about the arguments passed to a message. -type argument struct { - // ArgNum corresponds to the number that should be used for explicit argument indexes (e.g. - // "%[1]d"). - ArgNum int `json:"argNum,omitempty"` - - used bool // Used by Placeholder - Type string `json:"type"` - UnderlyingType string `json:"underlyingType"` - Expr string `json:"expr"` - Value string `json:"value,omitempty"` - Comment string `json:"comment,omitempty"` - Position string `json:"position,omitempty"` -} - -// Feature holds information about a feature that can be implemented by -// an Argument. -type Feature struct { - Type string `json:"type"` // Right now this is only gender and plural. - - // TODO: possible values and examples for the language under consideration. - -} - -// Text defines a message to be displayed. -type Text struct { - // Msg and Select contains the message to be displayed. Msg may be used as - // a fallback value if none of the select cases match. - Msg string `json:"msg,omitempty"` - Select *Select `json:"select,omitempty"` - - // Var defines a map of variables that may be substituted in the selected - // message. - Var map[string]Text `json:"var,omitempty"` - - // Example contains an example message formatted with default values. - Example string `json:"example,omitempty"` -} - -// IsEmpty reports whether this Text can generate anything. -func (t *Text) IsEmpty() bool { - return t.Msg == "" && t.Select == nil && t.Var == nil -} - -// rawText erases the UnmarshalJSON method. -type rawText Text - -// UnmarshalJSON implements json.Unmarshaler. -func (t *Text) UnmarshalJSON(b []byte) error { - if b[0] == '"' { - return json.Unmarshal(b, &t.Msg) - } - return json.Unmarshal(b, (*rawText)(t)) -} - -// MarshalJSON implements json.Marshaler. -func (t *Text) MarshalJSON() ([]byte, error) { - if t.Select == nil && t.Var == nil && t.Example == "" { - return json.Marshal(t.Msg) - } - return json.Marshal((*rawText)(t)) -} - -// IDList is a set identifiers that each may refer to possibly different -// versions of the same message. When looking up a messages, the first -// identifier in the list takes precedence. -type IDList []string - -// UnmarshalJSON implements json.Unmarshaler. -func (id *IDList) UnmarshalJSON(b []byte) error { - if b[0] == '"' { - *id = []string{""} - return json.Unmarshal(b, &((*id)[0])) - } - return json.Unmarshal(b, (*[]string)(id)) -} - -// MarshalJSON implements json.Marshaler. -func (id *IDList) MarshalJSON() ([]byte, error) { - if len(*id) == 1 { - return json.Marshal((*id)[0]) - } - return json.Marshal((*[]string)(id)) -} - -// Select selects a Text based on the feature value associated with a feature of -// a certain argument. -type Select struct { - Feature string `json:"feature"` // Name of Feature type (e.g plural) - Arg string `json:"arg"` // The placeholder ID - Cases map[string]Text `json:"cases"` -} - -// TODO: order matters, but can we derive the ordering from the case keys? -// type Case struct { -// Key string `json:"key"` -// Value Text `json:"value"` -// } diff --git a/vendor/golang.org/x/text/message/pipeline/pipeline.go b/vendor/golang.org/x/text/message/pipeline/pipeline.go deleted file mode 100644 index cafd6f29b..000000000 --- a/vendor/golang.org/x/text/message/pipeline/pipeline.go +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package pipeline provides tools for creating translation pipelines. -// -// NOTE: UNDER DEVELOPMENT. API MAY CHANGE. -package pipeline - -import ( - "bytes" - "encoding/json" - "fmt" - "go/build" - "go/parser" - "io/ioutil" - "log" - "os" - "path/filepath" - "regexp" - "strings" - "text/template" - "unicode" - - "golang.org/x/text/internal" - "golang.org/x/text/language" - "golang.org/x/text/runes" - "golang.org/x/tools/go/loader" -) - -const ( - extractFile = "extracted.gotext.json" - outFile = "out.gotext.json" - gotextSuffix = "gotext.json" -) - -// Config contains configuration for the translation pipeline. -type Config struct { - // Supported indicates the languages for which data should be generated. - // The default is to support all locales for which there are matching - // translation files. - Supported []language.Tag - - // --- Extraction - - SourceLanguage language.Tag - - Packages []string - - // --- File structure - - // Dir is the root dir for all operations. - Dir string - - // TranslationsPattern is a regular expression to match incoming translation - // files. These files may appear in any directory rooted at Dir. - // language for the translation files is determined as follows: - // 1. From the Language field in the file. - // 2. If not present, from a valid language tag in the filename, separated - // by dots (e.g. "en-US.json" or "incoming.pt_PT.xmb"). - // 3. If not present, from a the closest subdirectory in which the file - // is contained that parses as a valid language tag. - TranslationsPattern string - - // OutPattern defines the location for translation files for a certain - // language. The default is "{{.Dir}}/{{.Language}}/out.{{.Ext}}" - OutPattern string - - // Format defines the file format for generated translation files. - // The default is XMB. Alternatives are GetText, XLIFF, L20n, GoText. - Format string - - Ext string - - // TODO: - // Actions are additional actions to be performed after the initial extract - // and merge. - // Actions []struct { - // Name string - // Options map[string]string - // } - - // --- Generation - - // GenFile may be in a different package. It is not defined, it will - // be written to stdout. - GenFile string - - // GenPackage is the package or relative path into which to generate the - // file. If not specified it is relative to the current directory. - GenPackage string - - // DeclareVar defines a variable to which to assing the generated Catalog. - DeclareVar string - - // SetDefault determines whether to assign the generated Catalog to - // message.DefaultCatalog. The default for this is true if DeclareVar is - // not defined, false otherwise. - SetDefault bool - - // TODO: - // - Printf-style configuration - // - Template-style configuration - // - Extraction options - // - Rewrite options - // - Generation options -} - -// Operations: -// - extract: get the strings -// - disambiguate: find messages with the same key, but possible different meaning. -// - create out: create a list of messages that need translations -// - load trans: load the list of current translations -// - merge: assign list of translations as done -// - (action)expand: analyze features and create example sentences for each version. -// - (action)googletrans: pre-populate messages with automatic translations. -// - (action)export: send out messages somewhere non-standard -// - (action)import: load messages from somewhere non-standard -// - vet program: don't pass "foo" + var + "bar" strings. Not using funcs for translated strings. -// - vet trans: coverage: all translations/ all features. -// - generate: generate Go code - -// State holds all accumulated information on translations during processing. -type State struct { - Config Config - - Package string - program *loader.Program - - Extracted Messages `json:"messages"` - - // Messages includes all messages for which there need to be translations. - // Duplicates may be eliminated. Generation will be done from these messages - // (usually after merging). - Messages []Messages - - // Translations are incoming translations for the application messages. - Translations []Messages -} - -func (s *State) dir() string { - if d := s.Config.Dir; d != "" { - return d - } - return "./locales" -} - -func outPattern(s *State) (string, error) { - c := s.Config - pat := c.OutPattern - if pat == "" { - pat = "{{.Dir}}/{{.Language}}/out.{{.Ext}}" - } - - ext := c.Ext - if ext == "" { - ext = c.Format - } - if ext == "" { - ext = gotextSuffix - } - t, err := template.New("").Parse(pat) - if err != nil { - return "", wrap(err, "error parsing template") - } - buf := bytes.Buffer{} - err = t.Execute(&buf, map[string]string{ - "Dir": s.dir(), - "Language": "%s", - "Ext": ext, - }) - return filepath.FromSlash(buf.String()), wrap(err, "incorrect OutPattern") -} - -var transRE = regexp.MustCompile(`.*\.` + gotextSuffix) - -// Import loads existing translation files. -func (s *State) Import() error { - outPattern, err := outPattern(s) - if err != nil { - return err - } - re := transRE - if pat := s.Config.TranslationsPattern; pat != "" { - if re, err = regexp.Compile(pat); err != nil { - return wrapf(err, "error parsing regexp %q", s.Config.TranslationsPattern) - } - } - x := importer{s, outPattern, re} - return x.walkImport(s.dir(), s.Config.SourceLanguage) -} - -type importer struct { - state *State - outPattern string - transFile *regexp.Regexp -} - -func (i *importer) walkImport(path string, tag language.Tag) error { - files, err := ioutil.ReadDir(path) - if err != nil { - return nil - } - for _, f := range files { - name := f.Name() - tag := tag - if f.IsDir() { - if t, err := language.Parse(name); err == nil { - tag = t - } - // We ignore errors - if err := i.walkImport(filepath.Join(path, name), tag); err != nil { - return err - } - continue - } - for _, l := range strings.Split(name, ".") { - if t, err := language.Parse(l); err == nil { - tag = t - } - } - file := filepath.Join(path, name) - // TODO: Should we skip files that match output files? - if fmt.Sprintf(i.outPattern, tag) == file { - continue - } - // TODO: handle different file formats. - if !i.transFile.MatchString(name) { - continue - } - b, err := ioutil.ReadFile(file) - if err != nil { - return wrap(err, "read file failed") - } - var translations Messages - if err := json.Unmarshal(b, &translations); err != nil { - return wrap(err, "parsing translation file failed") - } - i.state.Translations = append(i.state.Translations, translations) - } - return nil -} - -// Merge merges the extracted messages with the existing translations. -func (s *State) Merge() error { - if s.Messages != nil { - panic("already merged") - } - // Create an index for each unique message. - // Duplicates are okay as long as the substitution arguments are okay as - // well. - // Top-level messages are okay to appear in multiple substitution points. - - // Collect key equivalence. - msgs := []*Message{} - keyToIDs := map[string]*Message{} - for _, m := range s.Extracted.Messages { - m := m - if prev, ok := keyToIDs[m.Key]; ok { - if err := checkEquivalence(&m, prev); err != nil { - warnf("Key %q matches conflicting messages: %v and %v", m.Key, prev.ID, m.ID) - // TODO: track enough information so that the rewriter can - // suggest/disambiguate messages. - } - // TODO: add position to message. - continue - } - i := len(msgs) - msgs = append(msgs, &m) - keyToIDs[m.Key] = msgs[i] - } - - // Messages with different keys may still refer to the same translated - // message (e.g. different whitespace). Filter these. - idMap := map[string]bool{} - filtered := []*Message{} - for _, m := range msgs { - found := false - for _, id := range m.ID { - found = found || idMap[id] - } - if !found { - filtered = append(filtered, m) - } - for _, id := range m.ID { - idMap[id] = true - } - } - - // Build index of translations. - translations := map[language.Tag]map[string]Message{} - languages := append([]language.Tag{}, s.Config.Supported...) - - for _, t := range s.Translations { - tag := t.Language - if _, ok := translations[tag]; !ok { - translations[tag] = map[string]Message{} - languages = append(languages, tag) - } - for _, m := range t.Messages { - if !m.Translation.IsEmpty() { - for _, id := range m.ID { - if _, ok := translations[tag][id]; ok { - warnf("Duplicate translation in locale %q for message %q", tag, id) - } - translations[tag][id] = m - } - } - } - } - languages = internal.UniqueTags(languages) - - for _, tag := range languages { - ms := Messages{Language: tag} - for _, orig := range filtered { - m := *orig - m.Key = "" - m.Position = "" - - for _, id := range m.ID { - if t, ok := translations[tag][id]; ok { - m.Translation = t.Translation - if t.TranslatorComment != "" { - m.TranslatorComment = t.TranslatorComment - m.Fuzzy = t.Fuzzy - } - break - } - } - if tag == s.Config.SourceLanguage && m.Translation.IsEmpty() { - m.Translation = m.Message - if m.TranslatorComment == "" { - m.TranslatorComment = "Copied from source." - m.Fuzzy = true - } - } - // TODO: if translation is empty: pre-expand based on available - // linguistic features. This may also be done as a plugin. - ms.Messages = append(ms.Messages, m) - } - s.Messages = append(s.Messages, ms) - } - return nil -} - -// Export writes out the messages to translation out files. -func (s *State) Export() error { - path, err := outPattern(s) - if err != nil { - return wrap(err, "export failed") - } - for _, out := range s.Messages { - // TODO: inject translations from existing files to avoid retranslation. - data, err := json.MarshalIndent(out, "", " ") - if err != nil { - return wrap(err, "JSON marshal failed") - } - file := fmt.Sprintf(path, out.Language) - if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil { - return wrap(err, "dir create failed") - } - if err := ioutil.WriteFile(file, data, 0644); err != nil { - return wrap(err, "write failed") - } - } - return nil -} - -var ( - ws = runes.In(unicode.White_Space).Contains - notWS = runes.NotIn(unicode.White_Space).Contains -) - -func trimWS(s string) (trimmed, leadWS, trailWS string) { - trimmed = strings.TrimRightFunc(s, ws) - trailWS = s[len(trimmed):] - if i := strings.IndexFunc(trimmed, notWS); i > 0 { - leadWS = trimmed[:i] - trimmed = trimmed[i:] - } - return trimmed, leadWS, trailWS -} - -// NOTE: The command line tool already prefixes with "gotext:". -var ( - wrap = func(err error, msg string) error { - if err == nil { - return nil - } - return fmt.Errorf("%s: %v", msg, err) - } - wrapf = func(err error, msg string, args ...interface{}) error { - if err == nil { - return nil - } - return wrap(err, fmt.Sprintf(msg, args...)) - } - errorf = fmt.Errorf -) - -func warnf(format string, args ...interface{}) { - // TODO: don't log. - log.Printf(format, args...) -} - -func loadPackages(conf *loader.Config, args []string) (*loader.Program, error) { - if len(args) == 0 { - args = []string{"."} - } - - conf.Build = &build.Default - conf.ParserMode = parser.ParseComments - - // Use the initial packages from the command line. - args, err := conf.FromArgs(args, false) - if err != nil { - return nil, wrap(err, "loading packages failed") - } - - // Load, parse and type-check the whole program. - return conf.Load() -} diff --git a/vendor/golang.org/x/text/message/pipeline/pipeline_test.go b/vendor/golang.org/x/text/message/pipeline/pipeline_test.go deleted file mode 100644 index 293101b25..000000000 --- a/vendor/golang.org/x/text/message/pipeline/pipeline_test.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pipeline - -import ( - "bufio" - "bytes" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" - "testing" - - "golang.org/x/text/language" -) - -var genFiles = flag.Bool("gen", false, "generate output files instead of comparing") - -// setHelper is testing.T.Helper on Go 1.9+, overridden by go19_test.go. -var setHelper = func(t *testing.T) {} - -func TestFullCycle(t *testing.T) { - const path = "./testdata" - dirs, err := ioutil.ReadDir(path) - if err != nil { - t.Fatal(err) - } - for _, f := range dirs { - t.Run(f.Name(), func(t *testing.T) { - chk := func(t *testing.T, err error) { - setHelper(t) - if err != nil { - t.Fatal(err) - } - } - dir := filepath.Join(path, f.Name()) - pkgPath := fmt.Sprintf("%s/%s", path, f.Name()) - config := Config{ - SourceLanguage: language.AmericanEnglish, - Packages: []string{pkgPath}, - Dir: filepath.Join(dir, "locales"), - GenFile: "catalog_gen.go", - GenPackage: pkgPath, - } - // TODO: load config if available. - s, err := Extract(&config) - chk(t, err) - chk(t, s.Import()) - chk(t, s.Merge()) - // TODO: - // for range s.Config.Actions { - // // TODO: do the actions. - // } - chk(t, s.Export()) - chk(t, s.Generate()) - - writeJSON(t, filepath.Join(dir, "extracted.gotext.json"), s.Extracted) - checkOutput(t, dir) - }) - } -} - -func checkOutput(t *testing.T, p string) { - filepath.Walk(p, func(p string, f os.FileInfo, err error) error { - if f.IsDir() { - return nil - } - if filepath.Ext(p) != ".want" { - return nil - } - gotFile := p[:len(p)-len(".want")] - got, err := ioutil.ReadFile(gotFile) - if err != nil { - t.Errorf("failed to read %q", p) - return nil - } - if *genFiles { - if err := ioutil.WriteFile(p, got, 0644); err != nil { - t.Fatal(err) - } - } - want, err := ioutil.ReadFile(p) - if err != nil { - t.Errorf("failed to read %q", p) - } else { - scanGot := bufio.NewScanner(bytes.NewReader(got)) - scanWant := bufio.NewScanner(bytes.NewReader(want)) - line := 0 - clean := func(s string) string { - if i := strings.LastIndex(s, "//"); i != -1 { - s = s[:i] - } - return path.Clean(filepath.ToSlash(s)) - } - for scanGot.Scan() && scanWant.Scan() { - got := clean(scanGot.Text()) - want := clean(scanWant.Text()) - if got != want { - t.Errorf("file %q differs from .want file at line %d:\n\t%s\n\t%s", gotFile, line, got, want) - break - } - line++ - } - if scanGot.Scan() || scanWant.Scan() { - t.Errorf("file %q differs from .want file at line %d.", gotFile, line) - } - } - return nil - }) -} - -func writeJSON(t *testing.T, path string, x interface{}) { - data, err := json.MarshalIndent(x, "", " ") - if err != nil { - t.Fatal(err) - } - if err := ioutil.WriteFile(path, data, 0644); err != nil { - t.Fatal(err) - } -} diff --git a/vendor/golang.org/x/text/message/pipeline/rewrite.go b/vendor/golang.org/x/text/message/pipeline/rewrite.go deleted file mode 100644 index cf1511f56..000000000 --- a/vendor/golang.org/x/text/message/pipeline/rewrite.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pipeline - -import ( - "bytes" - "fmt" - "go/ast" - "go/constant" - "go/format" - "go/token" - "io" - "os" - "strings" - - "golang.org/x/tools/go/loader" -) - -const printerType = "golang.org/x/text/message.Printer" - -// Rewrite rewrites the Go files in a single package to use the localization -// machinery and rewrites strings to adopt best practices when possible. -// If w is not nil the generated files are written to it, each files with a -// "--- " header. Otherwise the files are overwritten. -func Rewrite(w io.Writer, args ...string) error { - conf := &loader.Config{ - AllowErrors: true, // Allow unused instances of message.Printer. - } - prog, err := loadPackages(conf, args) - if err != nil { - return wrap(err, "") - } - - for _, info := range prog.InitialPackages() { - for _, f := range info.Files { - // Associate comments with nodes. - - // Pick up initialized Printers at the package level. - r := rewriter{info: info, conf: conf} - for _, n := range info.InitOrder { - if t := r.info.Types[n.Rhs].Type.String(); strings.HasSuffix(t, printerType) { - r.printerVar = n.Lhs[0].Name() - } - } - - ast.Walk(&r, f) - - w := w - if w == nil { - var err error - if w, err = os.Create(conf.Fset.File(f.Pos()).Name()); err != nil { - return wrap(err, "open failed") - } - } else { - fmt.Fprintln(w, "---", conf.Fset.File(f.Pos()).Name()) - } - - if err := format.Node(w, conf.Fset, f); err != nil { - return wrap(err, "go format failed") - } - } - } - - return nil -} - -type rewriter struct { - info *loader.PackageInfo - conf *loader.Config - printerVar string -} - -// print returns Go syntax for the specified node. -func (r *rewriter) print(n ast.Node) string { - var buf bytes.Buffer - format.Node(&buf, r.conf.Fset, n) - return buf.String() -} - -func (r *rewriter) Visit(n ast.Node) ast.Visitor { - // Save the state by scope. - if _, ok := n.(*ast.BlockStmt); ok { - r := *r - return &r - } - // Find Printers created by assignment. - stmt, ok := n.(*ast.AssignStmt) - if ok { - for _, v := range stmt.Lhs { - if r.printerVar == r.print(v) { - r.printerVar = "" - } - } - for i, v := range stmt.Rhs { - if t := r.info.Types[v].Type.String(); strings.HasSuffix(t, printerType) { - r.printerVar = r.print(stmt.Lhs[i]) - return r - } - } - } - // Find Printers created by variable declaration. - spec, ok := n.(*ast.ValueSpec) - if ok { - for _, v := range spec.Names { - if r.printerVar == r.print(v) { - r.printerVar = "" - } - } - for i, v := range spec.Values { - if t := r.info.Types[v].Type.String(); strings.HasSuffix(t, printerType) { - r.printerVar = r.print(spec.Names[i]) - return r - } - } - } - if r.printerVar == "" { - return r - } - call, ok := n.(*ast.CallExpr) - if !ok { - return r - } - - // TODO: Handle literal values? - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return r - } - meth := r.info.Selections[sel] - - source := r.print(sel.X) - fun := r.print(sel.Sel) - if meth != nil { - source = meth.Recv().String() - fun = meth.Obj().Name() - } - - // TODO: remove cheap hack and check if the type either - // implements some interface or is specifically of type - // "golang.org/x/text/message".Printer. - m, ok := rewriteFuncs[source] - if !ok { - return r - } - - rewriteType, ok := m[fun] - if !ok { - return r - } - ident := ast.NewIdent(r.printerVar) - ident.NamePos = sel.X.Pos() - sel.X = ident - if rewriteType.method != "" { - sel.Sel.Name = rewriteType.method - } - - // Analyze arguments. - argn := rewriteType.arg - if rewriteType.format || argn >= len(call.Args) { - return r - } - hasConst := false - for _, a := range call.Args[argn:] { - if v := r.info.Types[a].Value; v != nil && v.Kind() == constant.String { - hasConst = true - break - } - } - if !hasConst { - return r - } - sel.Sel.Name = rewriteType.methodf - - // We are done if there is only a single string that does not need to be - // escaped. - if len(call.Args) == 1 { - s, ok := constStr(r.info, call.Args[0]) - if ok && !strings.Contains(s, "%") && !rewriteType.newLine { - return r - } - } - - // Rewrite arguments as format string. - expr := &ast.BasicLit{ - ValuePos: call.Lparen, - Kind: token.STRING, - } - newArgs := append(call.Args[:argn:argn], expr) - newStr := []string{} - for i, a := range call.Args[argn:] { - if s, ok := constStr(r.info, a); ok { - newStr = append(newStr, strings.Replace(s, "%", "%%", -1)) - } else { - newStr = append(newStr, "%v") - newArgs = append(newArgs, call.Args[argn+i]) - } - } - s := strings.Join(newStr, rewriteType.sep) - if rewriteType.newLine { - s += "\n" - } - expr.Value = fmt.Sprintf("%q", s) - - call.Args = newArgs - - // TODO: consider creating an expression instead of a constant string and - // then wrapping it in an escape function or so: - // call.Args[argn+i] = &ast.CallExpr{ - // Fun: &ast.SelectorExpr{ - // X: ast.NewIdent("message"), - // Sel: ast.NewIdent("Lookup"), - // }, - // Args: []ast.Expr{a}, - // } - // } - - return r -} - -type rewriteType struct { - // method is the name of the equivalent method on a printer, or "" if it is - // the same. - method string - - // methodf is the method to use if the arguments can be rewritten as a - // arguments to a printf-style call. - methodf string - - // format is true if the method takes a formatting string followed by - // substitution arguments. - format bool - - // arg indicates the position of the argument to extract. If all is - // positive, all arguments from this argument onwards needs to be extracted. - arg int - - sep string - newLine bool -} - -// rewriteFuncs list functions that can be directly mapped to the printer -// functions of the message package. -var rewriteFuncs = map[string]map[string]rewriteType{ - // TODO: Printer -> *golang.org/x/text/message.Printer - "fmt": { - "Print": rewriteType{methodf: "Printf"}, - "Sprint": rewriteType{methodf: "Sprintf"}, - "Fprint": rewriteType{methodf: "Fprintf"}, - - "Println": rewriteType{methodf: "Printf", sep: " ", newLine: true}, - "Sprintln": rewriteType{methodf: "Sprintf", sep: " ", newLine: true}, - "Fprintln": rewriteType{methodf: "Fprintf", sep: " ", newLine: true}, - - "Printf": rewriteType{method: "Printf", format: true}, - "Sprintf": rewriteType{method: "Sprintf", format: true}, - "Fprintf": rewriteType{method: "Fprintf", format: true}, - }, -} - -func constStr(info *loader.PackageInfo, e ast.Expr) (s string, ok bool) { - v := info.Types[e].Value - if v == nil || v.Kind() != constant.String { - return "", false - } - return constant.StringVal(v), true -} diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go b/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go deleted file mode 100644 index 7d93f4868..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go +++ /dev/null @@ -1,85 +0,0 @@ -// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. - -package main - -import ( - "golang.org/x/text/language" - "golang.org/x/text/message" - "golang.org/x/text/message/catalog" -) - -type dictionary struct { - index []uint32 - data string -} - -func (d *dictionary) Lookup(key string) (data string, ok bool) { - p := messageKeyToIndex[key] - start, end := d.index[p], d.index[p+1] - if start == end { - return "", false - } - return d.data[start:end], true -} - -func init() { - dict := map[string]catalog.Dictionary{ - "de": &dictionary{index: deIndex, data: deData}, - "en_US": &dictionary{index: en_USIndex, data: en_USData}, - "zh": &dictionary{index: zhIndex, data: zhData}, - } - fallback := language.MustParse("en-US") - cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback)) - if err != nil { - panic(err) - } - message.DefaultCatalog = cat -} - -var messageKeyToIndex = map[string]int{ - "%.2[1]f miles traveled (%[1]f)": 8, - "%[1]s is visiting %[3]s!\n": 3, - "%d files remaining!": 4, - "%d more files remaining!": 5, - "%s is out of order!": 7, - "%s is visiting %s!\n": 2, - "Hello %s!\n": 1, - "Hello world!\n": 0, - "Use the following code for your discount: %d\n": 6, -} - -var deIndex = []uint32{ // 10 elements - 0x00000000, 0x00000011, 0x00000023, 0x0000003d, - 0x00000057, 0x00000075, 0x00000094, 0x00000094, - 0x00000094, 0x00000094, -} // Size: 64 bytes - -const deData string = "" + // Size: 148 bytes - "\x04\x00\x01\x0a\x0c\x02Hallo Welt!\x04\x00\x01\x0a\x0d\x02Hallo %[1]s!" + - "\x04\x00\x01\x0a\x15\x02%[1]s besucht %[2]s!\x04\x00\x01\x0a\x15\x02%[1]" + - "s besucht %[3]s!\x02Noch zwei Bestände zu gehen!\x02Noch %[1]d Bestände " + - "zu gehen!" - -var en_USIndex = []uint32{ // 10 elements - 0x00000000, 0x00000012, 0x00000024, 0x00000042, - 0x00000060, 0x00000077, 0x000000ba, 0x000000ef, - 0x00000106, 0x00000125, -} // Size: 64 bytes - -const en_USData string = "" + // Size: 293 bytes - "\x04\x00\x01\x0a\x0d\x02Hello world!\x04\x00\x01\x0a\x0d\x02Hello %[1]s!" + - "\x04\x00\x01\x0a\x19\x02%[1]s is visiting %[2]s!\x04\x00\x01\x0a\x19\x02" + - "%[1]s is visiting %[3]s!\x02%[1]d files remaining!\x14\x01\x81\x01\x00" + - "\x02\x14\x02One file remaining!\x00&\x02There are %[1]d more files remai" + - "ning!\x04\x00\x01\x0a0\x02Use the following code for your discount: %[1]" + - "d\x02%[1]s is out of order!\x02%.2[1]f miles traveled (%[1]f)" - -var zhIndex = []uint32{ // 10 elements - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, -} // Size: 64 bytes - -const zhData string = "" - -// Total table size 633 bytes (0KiB); checksum: 74B32E70 diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go.want b/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go.want deleted file mode 100644 index 7d93f4868..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_gen.go.want +++ /dev/null @@ -1,85 +0,0 @@ -// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. - -package main - -import ( - "golang.org/x/text/language" - "golang.org/x/text/message" - "golang.org/x/text/message/catalog" -) - -type dictionary struct { - index []uint32 - data string -} - -func (d *dictionary) Lookup(key string) (data string, ok bool) { - p := messageKeyToIndex[key] - start, end := d.index[p], d.index[p+1] - if start == end { - return "", false - } - return d.data[start:end], true -} - -func init() { - dict := map[string]catalog.Dictionary{ - "de": &dictionary{index: deIndex, data: deData}, - "en_US": &dictionary{index: en_USIndex, data: en_USData}, - "zh": &dictionary{index: zhIndex, data: zhData}, - } - fallback := language.MustParse("en-US") - cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback)) - if err != nil { - panic(err) - } - message.DefaultCatalog = cat -} - -var messageKeyToIndex = map[string]int{ - "%.2[1]f miles traveled (%[1]f)": 8, - "%[1]s is visiting %[3]s!\n": 3, - "%d files remaining!": 4, - "%d more files remaining!": 5, - "%s is out of order!": 7, - "%s is visiting %s!\n": 2, - "Hello %s!\n": 1, - "Hello world!\n": 0, - "Use the following code for your discount: %d\n": 6, -} - -var deIndex = []uint32{ // 10 elements - 0x00000000, 0x00000011, 0x00000023, 0x0000003d, - 0x00000057, 0x00000075, 0x00000094, 0x00000094, - 0x00000094, 0x00000094, -} // Size: 64 bytes - -const deData string = "" + // Size: 148 bytes - "\x04\x00\x01\x0a\x0c\x02Hallo Welt!\x04\x00\x01\x0a\x0d\x02Hallo %[1]s!" + - "\x04\x00\x01\x0a\x15\x02%[1]s besucht %[2]s!\x04\x00\x01\x0a\x15\x02%[1]" + - "s besucht %[3]s!\x02Noch zwei Bestände zu gehen!\x02Noch %[1]d Bestände " + - "zu gehen!" - -var en_USIndex = []uint32{ // 10 elements - 0x00000000, 0x00000012, 0x00000024, 0x00000042, - 0x00000060, 0x00000077, 0x000000ba, 0x000000ef, - 0x00000106, 0x00000125, -} // Size: 64 bytes - -const en_USData string = "" + // Size: 293 bytes - "\x04\x00\x01\x0a\x0d\x02Hello world!\x04\x00\x01\x0a\x0d\x02Hello %[1]s!" + - "\x04\x00\x01\x0a\x19\x02%[1]s is visiting %[2]s!\x04\x00\x01\x0a\x19\x02" + - "%[1]s is visiting %[3]s!\x02%[1]d files remaining!\x14\x01\x81\x01\x00" + - "\x02\x14\x02One file remaining!\x00&\x02There are %[1]d more files remai" + - "ning!\x04\x00\x01\x0a0\x02Use the following code for your discount: %[1]" + - "d\x02%[1]s is out of order!\x02%.2[1]f miles traveled (%[1]f)" - -var zhIndex = []uint32{ // 10 elements - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, -} // Size: 64 bytes - -const zhData string = "" - -// Total table size 633 bytes (0KiB); checksum: 74B32E70 diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_test.go b/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_test.go deleted file mode 100644 index eeb7c25f4..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/catalog_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "path" - "testing" - - "golang.org/x/text/message" -) - -func TestCatalog(t *testing.T) { - args := func(a ...interface{}) []interface{} { return a } - testCases := []struct { - lang string - key string - args []interface{} - want string - }{{ - lang: "en", - key: "Hello world!\n", - want: "Hello world!\n", - }, { - lang: "de", - key: "Hello world!\n", - want: "Hallo Welt!\n", - }, { - lang: "en", - key: "%d more files remaining!", - args: args(1), - want: "One file remaining!", - }, { - lang: "en-u-nu-fullwide", - key: "%d more files remaining!", - args: args(5), - want: "There are 5 more files remaining!", - }} - for _, tc := range testCases { - t.Run(path.Join(tc.lang, tc.key), func(t *testing.T) { - p := message.NewPrinter(message.MatchLanguage(tc.lang)) - got := p.Sprintf(tc.key, tc.args...) - if got != tc.want { - t.Errorf("got %q; want %q", got, tc.want) - } - }) - } -} diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json deleted file mode 100644 index 4d317af59..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "language": "en-US", - "messages": [ - { - "id": "Hello world!", - "key": "Hello world!\n", - "message": "Hello world!", - "translation": "", - "position": "testdata/test1/test1.go:19:10" - }, - { - "id": "Hello {City}!", - "key": "Hello %s!\n", - "message": "Hello {City}!", - "translation": "", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ], - "position": "testdata/test1/test1.go:24:10" - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%s is visiting %s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ], - "position": "testdata/test1/test1.go:30:10" - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%[1]s is visiting %[3]s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "comment": "Field names are placeholders.", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "pp.Person" - }, - { - "id": "Place", - "string": "%[3]s", - "type": "string", - "underlyingType": "string", - "argNum": 3, - "expr": "pp.Place", - "comment": "Place the person is visiting." - }, - { - "id": "Extra", - "string": "%[2]v", - "type": "int", - "underlyingType": "int", - "argNum": 2, - "expr": "pp.extra" - } - ], - "position": "testdata/test1/test1.go:44:10" - }, - { - "id": "{2} files remaining!", - "key": "%d files remaining!", - "message": "{2} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ], - "position": "testdata/test1/test1.go:51:10" - }, - { - "id": "{N} more files remaining!", - "key": "%d more files remaining!", - "message": "{N} more files remaining!", - "translation": "", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ], - "position": "testdata/test1/test1.go:56:10" - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "key": "Use the following code for your discount: %d\n", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ], - "position": "testdata/test1/test1.go:64:10" - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "key": "%s is out of order!", - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ], - "position": "testdata/test1/test1.go:70:10" - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "key": "%.2[1]f miles traveled (%[1]f)", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ], - "position": "testdata/test1/test1.go:74:10" - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json.want b/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json.want deleted file mode 100644 index 4d317af59..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/extracted.gotext.json.want +++ /dev/null @@ -1,188 +0,0 @@ -{ - "language": "en-US", - "messages": [ - { - "id": "Hello world!", - "key": "Hello world!\n", - "message": "Hello world!", - "translation": "", - "position": "testdata/test1/test1.go:19:10" - }, - { - "id": "Hello {City}!", - "key": "Hello %s!\n", - "message": "Hello {City}!", - "translation": "", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ], - "position": "testdata/test1/test1.go:24:10" - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%s is visiting %s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ], - "position": "testdata/test1/test1.go:30:10" - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%[1]s is visiting %[3]s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "comment": "Field names are placeholders.", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "pp.Person" - }, - { - "id": "Place", - "string": "%[3]s", - "type": "string", - "underlyingType": "string", - "argNum": 3, - "expr": "pp.Place", - "comment": "Place the person is visiting." - }, - { - "id": "Extra", - "string": "%[2]v", - "type": "int", - "underlyingType": "int", - "argNum": 2, - "expr": "pp.extra" - } - ], - "position": "testdata/test1/test1.go:44:10" - }, - { - "id": "{2} files remaining!", - "key": "%d files remaining!", - "message": "{2} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ], - "position": "testdata/test1/test1.go:51:10" - }, - { - "id": "{N} more files remaining!", - "key": "%d more files remaining!", - "message": "{N} more files remaining!", - "translation": "", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ], - "position": "testdata/test1/test1.go:56:10" - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "key": "Use the following code for your discount: %d\n", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ], - "position": "testdata/test1/test1.go:64:10" - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "key": "%s is out of order!", - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ], - "position": "testdata/test1/test1.go:70:10" - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "key": "%.2[1]f miles traveled (%[1]f)", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ], - "position": "testdata/test1/test1.go:74:10" - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/messages.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/messages.gotext.json deleted file mode 100755 index f92e4a1f5..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/messages.gotext.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "language": "de", - "messages": [ - { - "id": "Hello world!", - "key": "Hello world!\n", - "message": "Hello world!", - "translation": "Hallo Welt!" - }, - { - "id": "Hello {City}!", - "key": "Hello %s!\n", - "message": "Hello {City}!", - "translation": "Hallo {City}!", - "placeholders": [ - { - "id": "City", - "string": "%[1]s" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%s is visiting %s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} besucht {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s" - }, - { - "id": "Place", - "string": "%[2]s" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%[1]s is visiting %[3]s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} besucht {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s" - }, - { - "id": "Place", - "string": "%[3]s" - }, - { - "id": "Extra", - "string": "%[2]v" - } - ] - }, - { - "id": "{2} files remaining!", - "key": "%d files remaining!", - "message": "{N} files remaining!", - "translation": "Noch zwei Bestände zu gehen!", - "placeholders": [ - { - "id": "2", - "string": "%[1]d" - } - ] - }, - { - "id": "{N} more files remaining!", - "key": "%d more files remaining!", - "message": "{N} more files remaining!", - "translation": "Noch {N} Bestände zu gehen!", - "placeholders": [ - { - "id": "N", - "string": "%[1]d" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "key": "Use the following code for your discount: %d\n", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d" - } - ] - }, - { - "id": [ "msgOutOfOrder", "{Device} is out of order!" ], - "key": "%s is out of order!", - "message": "{Device} is out of order!", - "translation": "", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "key": "%.2[1]f miles traveled (%[1]f)", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f" - }, - { - "id": "Miles_1", - "string": "%[1]f" - } - ] - } - ] -} diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json deleted file mode 100755 index f19e21d72..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "language": "de", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "Hallo Welt!" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "Hallo {City}!", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} besucht {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "Noch zwei Bestände zu gehen!", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ] - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": "Noch {N} Bestände zu gehen!", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ] - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json.want b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json.want deleted file mode 100755 index f19e21d72..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/de/out.gotext.json.want +++ /dev/null @@ -1,137 +0,0 @@ -{ - "language": "de", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "Hallo Welt!" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "Hallo {City}!", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} besucht {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "Noch zwei Bestände zu gehen!", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ] - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": "Noch {N} Bestände zu gehen!", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ] - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/messages.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/messages.gotext.json deleted file mode 100755 index b984242f6..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/messages.gotext.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "language": "en-US", - "messages": [ - { - "id": "Hello world!", - "key": "Hello world!\n", - "message": "Hello world!", - "translation": "Hello world!" - }, - { - "id": "Hello {City}!", - "key": "Hello %s!\n", - "message": "Hello {City}!", - "translation": "Hello {City}!" - }, - { - "id": "Hello {Town}!", - "key": "Hello %s!\n", - "message": "Hello {Town}!", - "translation": "Hello {Town}!", - "placeholders": [ - { - "id": "Town", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "town", - "comment": "Town" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%s is visiting %s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} is visiting {Place}!" - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%[1]s is visiting %[3]s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} is visiting {Place}!" - }, - { - "id": "{2} files remaining!", - "key": "%d files remaining!", - "message": "{N} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "2", - "string": "%[1]d" - } - ] - }, - { - "id": "{N} more files remaining!", - "key": "%d more files remaining!", - "message": "{N} more files remaining!", - "translation": { - "select": { - "feature": "plural", - "arg": "N", - "cases": { - "one": "One file remaining!", - "other": "There are {N} more files remaining!" - } - } - } - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "key": "Use the following code for your discount: %d\n", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "" - }, - { - "id": [ "msgOutOfOrder", "{Device} is out of order!" ], - "key": "%s is out of order!", - "message": "{Device} is out of order!", - "translation": "{Device} is out of order!" - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "key": "%.2[1]f miles traveled (%[1]f)", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "{Miles} miles traveled ({Miles_1})" - } - ] -} diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json deleted file mode 100755 index 59f92a5a6..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "language": "en-US", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "Hello world!" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "Hello {City}!", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} is visiting {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "{2} files remaining!", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ], - "fuzzy": true - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": { - "select": { - "feature": "plural", - "arg": "N", - "cases": { - "one": { - "msg": "One file remaining!" - }, - "other": { - "msg": "There are {N} more files remaining!" - } - } - } - }, - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "Use the following code for your discount: {ReferralCode}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ], - "fuzzy": true - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "{Device} is out of order!", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "{Miles} miles traveled ({Miles_1})", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json.want b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json.want deleted file mode 100755 index 59f92a5a6..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/en-US/out.gotext.json.want +++ /dev/null @@ -1,154 +0,0 @@ -{ - "language": "en-US", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "Hello world!" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "Hello {City}!", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "{Person} is visiting {Place}!", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "{2} files remaining!", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ], - "fuzzy": true - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": { - "select": { - "feature": "plural", - "arg": "N", - "cases": { - "one": { - "msg": "One file remaining!" - }, - "other": { - "msg": "There are {N} more files remaining!" - } - } - } - }, - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "Use the following code for your discount: {ReferralCode}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ], - "fuzzy": true - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "{Device} is out of order!", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "{Miles} miles traveled ({Miles_1})", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/messages.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/messages.gotext.json deleted file mode 100755 index c80d1d2a7..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/messages.gotext.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "language": "zh", - "messages": [ - { - "id": "Hello world!", - "key": "Hello world!\n", - "message": "Hello world!", - "translation": "" - }, - { - "id": "Hello {City}!", - "key": "Hello %s!\n", - "message": "Hello {City}!", - "translation": "", - "placeholders": [ - { - "id": "City", - "string": "%[1]s" - } - ] - }, - { - "id": "Hello {Town}!", - "key": "Hello %s!\n", - "message": "Hello {Town}!", - "translation": "", - "placeholders": [ - { - "id": "Town", - "string": "%[1]s" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%s is visiting %s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s" - }, - { - "id": "Place", - "string": "%[2]s" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "key": "%[1]s is visiting %[3]s!\n", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s" - }, - { - "id": "Place", - "string": "%[3]s" - }, - { - "id": "Extra", - "string": "%[2]v" - } - ] - }, - { - "id": "{2} files remaining!", - "key": "%d files remaining!", - "message": "{2} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "", - "string": "%[1]d" - } - ] - }, - { - "id": "{N} more files remaining!", - "key": "%d more files remaining!", - "message": "{N} more files remaining!", - "translation": "", - "placeholders": [ - { - "id": "N", - "string": "%[1]d" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "key": "Use the following code for your discount: %d\n", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d" - } - ] - }, - { - "id": [ "{Device} is out of order!", "msgOutOfOrder" ], - "key": "%s is out of order!", - "message": "{Device} is out of order!", - "translation": "", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "key": "%.2[1]f miles traveled (%[1]f)", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f" - }, - { - "id": "Miles_1", - "string": "%[1]f" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json deleted file mode 100755 index 9bede65ee..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "language": "zh", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ] - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": "", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ] - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json.want b/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json.want deleted file mode 100755 index 9bede65ee..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/locales/zh/out.gotext.json.want +++ /dev/null @@ -1,137 +0,0 @@ -{ - "language": "zh", - "messages": [ - { - "id": "Hello world!", - "message": "Hello world!", - "translation": "" - }, - { - "id": "Hello {City}!", - "message": "Hello {City}!", - "translation": "", - "placeholders": [ - { - "id": "City", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "city" - } - ] - }, - { - "id": "{Person} is visiting {Place}!", - "message": "{Person} is visiting {Place}!", - "translation": "", - "placeholders": [ - { - "id": "Person", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "person", - "comment": "The person of matter." - }, - { - "id": "Place", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "place", - "comment": "Place the person is visiting." - } - ] - }, - { - "id": "{2} files remaining!", - "message": "{2} files remaining!", - "translation": "", - "placeholders": [ - { - "id": "2", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "2" - } - ] - }, - { - "id": "{N} more files remaining!", - "message": "{N} more files remaining!", - "translation": "", - "placeholders": [ - { - "id": "N", - "string": "%[1]d", - "type": "int", - "underlyingType": "int", - "argNum": 1, - "expr": "n" - } - ] - }, - { - "id": "Use the following code for your discount: {ReferralCode}", - "message": "Use the following code for your discount: {ReferralCode}", - "translation": "", - "placeholders": [ - { - "id": "ReferralCode", - "string": "%[1]d", - "type": "./testdata/test1.referralCode", - "underlyingType": "int", - "argNum": 1, - "expr": "c" - } - ] - }, - { - "id": [ - "msgOutOfOrder", - "{Device} is out of order!" - ], - "message": "{Device} is out of order!", - "translation": "", - "comment": "This comment wins.\n", - "placeholders": [ - { - "id": "Device", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "device" - } - ] - }, - { - "id": "{Miles} miles traveled ({Miles_1})", - "message": "{Miles} miles traveled ({Miles_1})", - "translation": "", - "placeholders": [ - { - "id": "Miles", - "string": "%.2[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - }, - { - "id": "Miles_1", - "string": "%[1]f", - "type": "float64", - "underlyingType": "float64", - "argNum": 1, - "expr": "miles" - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/golang.org/x/text/message/pipeline/testdata/test1/test1.go b/vendor/golang.org/x/text/message/pipeline/testdata/test1/test1.go deleted file mode 100644 index 88051f932..000000000 --- a/vendor/golang.org/x/text/message/pipeline/testdata/test1/test1.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "golang.org/x/text/message" - -func main() { - p := message.NewPrinter(message.MatchLanguage("en")) - - // NOT EXTRACTED: strings passed to Println are not extracted. - p.Println("Hello world!") - - // NOT EXTRACTED: strings passed to Print are not extracted. - p.Print("Hello world!\n") - - // Extract and trim whitespace (TODO). - p.Printf("Hello world!\n") - - // NOT EXTRACTED: city is not used as a pattern or passed to %m. - city := "Amsterdam" - // This comment is extracted. - p.Printf("Hello %s!\n", city) - - person := "Sheila" - place := "Zürich" - - // Substitutions replaced by variable names. - p.Printf("%s is visiting %s!\n", - person, // The person of matter. - place, // Place the person is visiting. - ) - - pp := struct { - Person string // The person of matter. // TODO: get this comment. - Place string - extra int - }{ - person, place, 4, - } - - // extract will drop this comment in favor of the one below. - p.Printf("%[1]s is visiting %[3]s!\n", // Field names are placeholders. - pp.Person, - pp.extra, - pp.Place, // Place the person is visiting. - ) - - // Numeric literal becomes placeholder. - p.Printf("%d files remaining!", 2) - - const n = 2 - - // Constant identifier becomes placeholder. - p.Printf("%d more files remaining!", n) - - // Infer better names from type names. - type referralCode int - - const c = referralCode(5) - - // Use type name as placeholder. - p.Printf("Use the following code for your discount: %d\n", c) - - // Use constant name as message ID. - const msgOutOfOrder = "%s is out of order!" // This comment wins. - const device = "Soda machine" - // This message has two IDs. - p.Printf(msgOutOfOrder, device) - - // Multiple substitutions for same argument. - miles := 1.2345 - p.Printf("%.2[1]f miles traveled (%[1]f)", miles) -} diff --git a/vendor/golang.org/x/text/message/print.go b/vendor/golang.org/x/text/message/print.go deleted file mode 100644 index 777e1724a..000000000 --- a/vendor/golang.org/x/text/message/print.go +++ /dev/null @@ -1,979 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package message - -import ( - "bytes" - "fmt" // TODO: consider copying interfaces from package fmt to avoid dependency. - "math" - "reflect" - "sync" - "unicode/utf8" - - "golang.org/x/text/internal/format" - "golang.org/x/text/internal/number" - "golang.org/x/text/language" - "golang.org/x/text/message/catalog" -) - -// Strings for use with buffer.WriteString. -// This is less overhead than using buffer.Write with byte arrays. -const ( - commaSpaceString = ", " - nilAngleString = "" - nilParenString = "(nil)" - nilString = "nil" - mapString = "map[" - percentBangString = "%!" - missingString = "(MISSING)" - badIndexString = "(BADINDEX)" - panicString = "(PANIC=" - extraString = "%!(EXTRA " - badWidthString = "%!(BADWIDTH)" - badPrecString = "%!(BADPREC)" - noVerbString = "%!(NOVERB)" - - invReflectString = "" -) - -var printerPool = sync.Pool{ - New: func() interface{} { return new(printer) }, -} - -// newPrinter allocates a new printer struct or grabs a cached one. -func newPrinter(pp *Printer) *printer { - p := printerPool.Get().(*printer) - p.Printer = *pp - // TODO: cache most of the following call. - p.catContext = pp.cat.Context(pp.tag, p) - - p.panicking = false - p.erroring = false - p.fmt.init(&p.Buffer) - return p -} - -// free saves used printer structs in printerFree; avoids an allocation per invocation. -func (p *printer) free() { - p.Buffer.Reset() - p.arg = nil - p.value = reflect.Value{} - printerPool.Put(p) -} - -// printer is used to store a printer's state. -// It implements "golang.org/x/text/internal/format".State. -type printer struct { - Printer - - // the context for looking up message translations - catContext *catalog.Context - - // buffer for accumulating output. - bytes.Buffer - - // arg holds the current item, as an interface{}. - arg interface{} - // value is used instead of arg for reflect values. - value reflect.Value - - // fmt is used to format basic items such as integers or strings. - fmt formatInfo - - // panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion. - panicking bool - // erroring is set when printing an error string to guard against calling handleMethods. - erroring bool -} - -// Language implements "golang.org/x/text/internal/format".State. -func (p *printer) Language() language.Tag { return p.tag } - -func (p *printer) Width() (wid int, ok bool) { return p.fmt.Width, p.fmt.WidthPresent } - -func (p *printer) Precision() (prec int, ok bool) { return p.fmt.Prec, p.fmt.PrecPresent } - -func (p *printer) Flag(b int) bool { - switch b { - case '-': - return p.fmt.Minus - case '+': - return p.fmt.Plus || p.fmt.PlusV - case '#': - return p.fmt.Sharp || p.fmt.SharpV - case ' ': - return p.fmt.Space - case '0': - return p.fmt.Zero - } - return false -} - -// getField gets the i'th field of the struct value. -// If the field is itself is an interface, return a value for -// the thing inside the interface, not the interface itself. -func getField(v reflect.Value, i int) reflect.Value { - val := v.Field(i) - if val.Kind() == reflect.Interface && !val.IsNil() { - val = val.Elem() - } - return val -} - -func (p *printer) unknownType(v reflect.Value) { - if !v.IsValid() { - p.WriteString(nilAngleString) - return - } - p.WriteByte('?') - p.WriteString(v.Type().String()) - p.WriteByte('?') -} - -func (p *printer) badVerb(verb rune) { - p.erroring = true - p.WriteString(percentBangString) - p.WriteRune(verb) - p.WriteByte('(') - switch { - case p.arg != nil: - p.WriteString(reflect.TypeOf(p.arg).String()) - p.WriteByte('=') - p.printArg(p.arg, 'v') - case p.value.IsValid(): - p.WriteString(p.value.Type().String()) - p.WriteByte('=') - p.printValue(p.value, 'v', 0) - default: - p.WriteString(nilAngleString) - } - p.WriteByte(')') - p.erroring = false -} - -func (p *printer) fmtBool(v bool, verb rune) { - switch verb { - case 't', 'v': - p.fmt.fmt_boolean(v) - default: - p.badVerb(verb) - } -} - -// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or -// not, as requested, by temporarily setting the sharp flag. -func (p *printer) fmt0x64(v uint64, leading0x bool) { - sharp := p.fmt.Sharp - p.fmt.Sharp = leading0x - p.fmt.fmt_integer(v, 16, unsigned, ldigits) - p.fmt.Sharp = sharp -} - -// fmtInteger formats a signed or unsigned integer. -func (p *printer) fmtInteger(v uint64, isSigned bool, verb rune) { - switch verb { - case 'v': - if p.fmt.SharpV && !isSigned { - p.fmt0x64(v, true) - return - } - fallthrough - case 'd': - if p.fmt.Sharp || p.fmt.SharpV { - p.fmt.fmt_integer(v, 10, isSigned, ldigits) - } else { - p.fmtDecimalInt(v, isSigned) - } - case 'b': - p.fmt.fmt_integer(v, 2, isSigned, ldigits) - case 'o': - p.fmt.fmt_integer(v, 8, isSigned, ldigits) - case 'x': - p.fmt.fmt_integer(v, 16, isSigned, ldigits) - case 'X': - p.fmt.fmt_integer(v, 16, isSigned, udigits) - case 'c': - p.fmt.fmt_c(v) - case 'q': - if v <= utf8.MaxRune { - p.fmt.fmt_qc(v) - } else { - p.badVerb(verb) - } - case 'U': - p.fmt.fmt_unicode(v) - default: - p.badVerb(verb) - } -} - -// fmtFloat formats a float. The default precision for each verb -// is specified as last argument in the call to fmt_float. -func (p *printer) fmtFloat(v float64, size int, verb rune) { - switch verb { - case 'b': - p.fmt.fmt_float(v, size, verb, -1) - case 'v': - verb = 'g' - fallthrough - case 'g', 'G': - if p.fmt.Sharp || p.fmt.SharpV { - p.fmt.fmt_float(v, size, verb, -1) - } else { - p.fmtVariableFloat(v, size) - } - case 'e', 'E': - if p.fmt.Sharp || p.fmt.SharpV { - p.fmt.fmt_float(v, size, verb, 6) - } else { - p.fmtScientific(v, size, 6) - } - case 'f', 'F': - if p.fmt.Sharp || p.fmt.SharpV { - p.fmt.fmt_float(v, size, verb, 6) - } else { - p.fmtDecimalFloat(v, size, 6) - } - default: - p.badVerb(verb) - } -} - -func (p *printer) setFlags(f *number.Formatter) { - f.Flags &^= number.ElideSign - if p.fmt.Plus || p.fmt.Space { - f.Flags |= number.AlwaysSign - if !p.fmt.Plus { - f.Flags |= number.ElideSign - } - } else { - f.Flags &^= number.AlwaysSign - } -} - -func (p *printer) updatePadding(f *number.Formatter) { - f.Flags &^= number.PadMask - if p.fmt.Minus { - f.Flags |= number.PadAfterSuffix - } else { - f.Flags |= number.PadBeforePrefix - } - f.PadRune = ' ' - f.FormatWidth = uint16(p.fmt.Width) -} - -func (p *printer) initDecimal(minFrac, maxFrac int) { - f := &p.toDecimal - f.MinIntegerDigits = 1 - f.MaxIntegerDigits = 0 - f.MinFractionDigits = uint8(minFrac) - f.MaxFractionDigits = int16(maxFrac) - p.setFlags(f) - f.PadRune = 0 - if p.fmt.WidthPresent { - if p.fmt.Zero { - wid := p.fmt.Width - // Use significant integers for this. - // TODO: this is not the same as width, but so be it. - if f.MinFractionDigits > 0 { - wid -= 1 + int(f.MinFractionDigits) - } - if p.fmt.Plus || p.fmt.Space { - wid-- - } - if wid > 0 && wid > int(f.MinIntegerDigits) { - f.MinIntegerDigits = uint8(wid) - } - } - p.updatePadding(f) - } -} - -func (p *printer) initScientific(minFrac, maxFrac int) { - f := &p.toScientific - if maxFrac < 0 { - f.SetPrecision(maxFrac) - } else { - f.SetPrecision(maxFrac + 1) - f.MinFractionDigits = uint8(minFrac) - f.MaxFractionDigits = int16(maxFrac) - } - f.MinExponentDigits = 2 - p.setFlags(f) - f.PadRune = 0 - if p.fmt.WidthPresent { - f.Flags &^= number.PadMask - if p.fmt.Zero { - f.PadRune = f.Digit(0) - f.Flags |= number.PadAfterPrefix - } else { - f.PadRune = ' ' - f.Flags |= number.PadBeforePrefix - } - p.updatePadding(f) - } -} - -func (p *printer) fmtDecimalInt(v uint64, isSigned bool) { - var d number.Decimal - - f := &p.toDecimal - if p.fmt.PrecPresent { - p.setFlags(f) - f.MinIntegerDigits = uint8(p.fmt.Prec) - f.MaxIntegerDigits = 0 - f.MinFractionDigits = 0 - f.MaxFractionDigits = 0 - if p.fmt.WidthPresent { - p.updatePadding(f) - } - } else { - p.initDecimal(0, 0) - } - d.ConvertInt(p.toDecimal.RoundingContext, isSigned, v) - - out := p.toDecimal.Format([]byte(nil), &d) - p.Buffer.Write(out) -} - -func (p *printer) fmtDecimalFloat(v float64, size, prec int) { - var d number.Decimal - if p.fmt.PrecPresent { - prec = p.fmt.Prec - } - p.initDecimal(prec, prec) - d.ConvertFloat(p.toDecimal.RoundingContext, v, size) - - out := p.toDecimal.Format([]byte(nil), &d) - p.Buffer.Write(out) -} - -func (p *printer) fmtVariableFloat(v float64, size int) { - prec := -1 - if p.fmt.PrecPresent { - prec = p.fmt.Prec - } - var d number.Decimal - p.initScientific(0, prec) - d.ConvertFloat(p.toScientific.RoundingContext, v, size) - - // Copy logic of 'g' formatting from strconv. It is simplified a bit as - // we don't have to mind having prec > len(d.Digits). - shortest := prec < 0 - ePrec := prec - if shortest { - prec = len(d.Digits) - ePrec = 6 - } else if prec == 0 { - prec = 1 - ePrec = 1 - } - exp := int(d.Exp) - 1 - if exp < -4 || exp >= ePrec { - p.initScientific(0, prec) - - out := p.toScientific.Format([]byte(nil), &d) - p.Buffer.Write(out) - } else { - if prec > int(d.Exp) { - prec = len(d.Digits) - } - if prec -= int(d.Exp); prec < 0 { - prec = 0 - } - p.initDecimal(0, prec) - - out := p.toDecimal.Format([]byte(nil), &d) - p.Buffer.Write(out) - } -} - -func (p *printer) fmtScientific(v float64, size, prec int) { - var d number.Decimal - if p.fmt.PrecPresent { - prec = p.fmt.Prec - } - p.initScientific(prec, prec) - rc := p.toScientific.RoundingContext - d.ConvertFloat(rc, v, size) - - out := p.toScientific.Format([]byte(nil), &d) - p.Buffer.Write(out) - -} - -// fmtComplex formats a complex number v with -// r = real(v) and j = imag(v) as (r+ji) using -// fmtFloat for r and j formatting. -func (p *printer) fmtComplex(v complex128, size int, verb rune) { - // Make sure any unsupported verbs are found before the - // calls to fmtFloat to not generate an incorrect error string. - switch verb { - case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E': - p.WriteByte('(') - p.fmtFloat(real(v), size/2, verb) - // Imaginary part always has a sign. - if math.IsNaN(imag(v)) { - // By CLDR's rules, NaNs do not use patterns or signs. As this code - // relies on AlwaysSign working for imaginary parts, we need to - // manually handle NaNs. - f := &p.toScientific - p.setFlags(f) - p.updatePadding(f) - p.setFlags(f) - nan := f.Symbol(number.SymNan) - extra := 0 - if w, ok := p.Width(); ok { - extra = w - utf8.RuneCountInString(nan) - 1 - } - if f.Flags&number.PadAfterNumber == 0 { - for ; extra > 0; extra-- { - p.WriteRune(f.PadRune) - } - } - p.WriteString(f.Symbol(number.SymPlusSign)) - p.WriteString(nan) - for ; extra > 0; extra-- { - p.WriteRune(f.PadRune) - } - p.WriteString("i)") - return - } - oldPlus := p.fmt.Plus - p.fmt.Plus = true - p.fmtFloat(imag(v), size/2, verb) - p.WriteString("i)") // TODO: use symbol? - p.fmt.Plus = oldPlus - default: - p.badVerb(verb) - } -} - -func (p *printer) fmtString(v string, verb rune) { - switch verb { - case 'v': - if p.fmt.SharpV { - p.fmt.fmt_q(v) - } else { - p.fmt.fmt_s(v) - } - case 's': - p.fmt.fmt_s(v) - case 'x': - p.fmt.fmt_sx(v, ldigits) - case 'X': - p.fmt.fmt_sx(v, udigits) - case 'q': - p.fmt.fmt_q(v) - default: - p.badVerb(verb) - } -} - -func (p *printer) fmtBytes(v []byte, verb rune, typeString string) { - switch verb { - case 'v', 'd': - if p.fmt.SharpV { - p.WriteString(typeString) - if v == nil { - p.WriteString(nilParenString) - return - } - p.WriteByte('{') - for i, c := range v { - if i > 0 { - p.WriteString(commaSpaceString) - } - p.fmt0x64(uint64(c), true) - } - p.WriteByte('}') - } else { - p.WriteByte('[') - for i, c := range v { - if i > 0 { - p.WriteByte(' ') - } - p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits) - } - p.WriteByte(']') - } - case 's': - p.fmt.fmt_s(string(v)) - case 'x': - p.fmt.fmt_bx(v, ldigits) - case 'X': - p.fmt.fmt_bx(v, udigits) - case 'q': - p.fmt.fmt_q(string(v)) - default: - p.printValue(reflect.ValueOf(v), verb, 0) - } -} - -func (p *printer) fmtPointer(value reflect.Value, verb rune) { - var u uintptr - switch value.Kind() { - case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: - u = value.Pointer() - default: - p.badVerb(verb) - return - } - - switch verb { - case 'v': - if p.fmt.SharpV { - p.WriteByte('(') - p.WriteString(value.Type().String()) - p.WriteString(")(") - if u == 0 { - p.WriteString(nilString) - } else { - p.fmt0x64(uint64(u), true) - } - p.WriteByte(')') - } else { - if u == 0 { - p.fmt.padString(nilAngleString) - } else { - p.fmt0x64(uint64(u), !p.fmt.Sharp) - } - } - case 'p': - p.fmt0x64(uint64(u), !p.fmt.Sharp) - case 'b', 'o', 'd', 'x', 'X': - if verb == 'd' { - p.fmt.Sharp = true // Print as standard go. TODO: does this make sense? - } - p.fmtInteger(uint64(u), unsigned, verb) - default: - p.badVerb(verb) - } -} - -func (p *printer) catchPanic(arg interface{}, verb rune) { - if err := recover(); err != nil { - // If it's a nil pointer, just say "". The likeliest causes are a - // Stringer that fails to guard against nil or a nil pointer for a - // value receiver, and in either case, "" is a nice result. - if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() { - p.WriteString(nilAngleString) - return - } - // Otherwise print a concise panic message. Most of the time the panic - // value will print itself nicely. - if p.panicking { - // Nested panics; the recursion in printArg cannot succeed. - panic(err) - } - - oldFlags := p.fmt.Parser - // For this output we want default behavior. - p.fmt.ClearFlags() - - p.WriteString(percentBangString) - p.WriteRune(verb) - p.WriteString(panicString) - p.panicking = true - p.printArg(err, 'v') - p.panicking = false - p.WriteByte(')') - - p.fmt.Parser = oldFlags - } -} - -func (p *printer) handleMethods(verb rune) (handled bool) { - if p.erroring { - return - } - // Is it a Formatter? - if formatter, ok := p.arg.(format.Formatter); ok { - handled = true - defer p.catchPanic(p.arg, verb) - formatter.Format(p, verb) - return - } - if formatter, ok := p.arg.(fmt.Formatter); ok { - handled = true - defer p.catchPanic(p.arg, verb) - formatter.Format(p, verb) - return - } - - // If we're doing Go syntax and the argument knows how to supply it, take care of it now. - if p.fmt.SharpV { - if stringer, ok := p.arg.(fmt.GoStringer); ok { - handled = true - defer p.catchPanic(p.arg, verb) - // Print the result of GoString unadorned. - p.fmt.fmt_s(stringer.GoString()) - return - } - } else { - // If a string is acceptable according to the format, see if - // the value satisfies one of the string-valued interfaces. - // Println etc. set verb to %v, which is "stringable". - switch verb { - case 'v', 's', 'x', 'X', 'q': - // Is it an error or Stringer? - // The duplication in the bodies is necessary: - // setting handled and deferring catchPanic - // must happen before calling the method. - switch v := p.arg.(type) { - case error: - handled = true - defer p.catchPanic(p.arg, verb) - p.fmtString(v.Error(), verb) - return - - case fmt.Stringer: - handled = true - defer p.catchPanic(p.arg, verb) - p.fmtString(v.String(), verb) - return - } - } - } - return false -} - -func (p *printer) printArg(arg interface{}, verb rune) { - p.arg = arg - p.value = reflect.Value{} - - if arg == nil { - switch verb { - case 'T', 'v': - p.fmt.padString(nilAngleString) - default: - p.badVerb(verb) - } - return - } - - // Special processing considerations. - // %T (the value's type) and %p (its address) are special; we always do them first. - switch verb { - case 'T': - p.fmt.fmt_s(reflect.TypeOf(arg).String()) - return - case 'p': - p.fmtPointer(reflect.ValueOf(arg), 'p') - return - } - - // Some types can be done without reflection. - switch f := arg.(type) { - case bool: - p.fmtBool(f, verb) - case float32: - p.fmtFloat(float64(f), 32, verb) - case float64: - p.fmtFloat(f, 64, verb) - case complex64: - p.fmtComplex(complex128(f), 64, verb) - case complex128: - p.fmtComplex(f, 128, verb) - case int: - p.fmtInteger(uint64(f), signed, verb) - case int8: - p.fmtInteger(uint64(f), signed, verb) - case int16: - p.fmtInteger(uint64(f), signed, verb) - case int32: - p.fmtInteger(uint64(f), signed, verb) - case int64: - p.fmtInteger(uint64(f), signed, verb) - case uint: - p.fmtInteger(uint64(f), unsigned, verb) - case uint8: - p.fmtInteger(uint64(f), unsigned, verb) - case uint16: - p.fmtInteger(uint64(f), unsigned, verb) - case uint32: - p.fmtInteger(uint64(f), unsigned, verb) - case uint64: - p.fmtInteger(f, unsigned, verb) - case uintptr: - p.fmtInteger(uint64(f), unsigned, verb) - case string: - p.fmtString(f, verb) - case []byte: - p.fmtBytes(f, verb, "[]byte") - case reflect.Value: - // Handle extractable values with special methods - // since printValue does not handle them at depth 0. - if f.IsValid() && f.CanInterface() { - p.arg = f.Interface() - if p.handleMethods(verb) { - return - } - } - p.printValue(f, verb, 0) - default: - // If the type is not simple, it might have methods. - if !p.handleMethods(verb) { - // Need to use reflection, since the type had no - // interface methods that could be used for formatting. - p.printValue(reflect.ValueOf(f), verb, 0) - } - } -} - -// printValue is similar to printArg but starts with a reflect value, not an interface{} value. -// It does not handle 'p' and 'T' verbs because these should have been already handled by printArg. -func (p *printer) printValue(value reflect.Value, verb rune, depth int) { - // Handle values with special methods if not already handled by printArg (depth == 0). - if depth > 0 && value.IsValid() && value.CanInterface() { - p.arg = value.Interface() - if p.handleMethods(verb) { - return - } - } - p.arg = nil - p.value = value - - switch f := value; value.Kind() { - case reflect.Invalid: - if depth == 0 { - p.WriteString(invReflectString) - } else { - switch verb { - case 'v': - p.WriteString(nilAngleString) - default: - p.badVerb(verb) - } - } - case reflect.Bool: - p.fmtBool(f.Bool(), verb) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p.fmtInteger(uint64(f.Int()), signed, verb) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p.fmtInteger(f.Uint(), unsigned, verb) - case reflect.Float32: - p.fmtFloat(f.Float(), 32, verb) - case reflect.Float64: - p.fmtFloat(f.Float(), 64, verb) - case reflect.Complex64: - p.fmtComplex(f.Complex(), 64, verb) - case reflect.Complex128: - p.fmtComplex(f.Complex(), 128, verb) - case reflect.String: - p.fmtString(f.String(), verb) - case reflect.Map: - if p.fmt.SharpV { - p.WriteString(f.Type().String()) - if f.IsNil() { - p.WriteString(nilParenString) - return - } - p.WriteByte('{') - } else { - p.WriteString(mapString) - } - keys := f.MapKeys() - for i, key := range keys { - if i > 0 { - if p.fmt.SharpV { - p.WriteString(commaSpaceString) - } else { - p.WriteByte(' ') - } - } - p.printValue(key, verb, depth+1) - p.WriteByte(':') - p.printValue(f.MapIndex(key), verb, depth+1) - } - if p.fmt.SharpV { - p.WriteByte('}') - } else { - p.WriteByte(']') - } - case reflect.Struct: - if p.fmt.SharpV { - p.WriteString(f.Type().String()) - } - p.WriteByte('{') - for i := 0; i < f.NumField(); i++ { - if i > 0 { - if p.fmt.SharpV { - p.WriteString(commaSpaceString) - } else { - p.WriteByte(' ') - } - } - if p.fmt.PlusV || p.fmt.SharpV { - if name := f.Type().Field(i).Name; name != "" { - p.WriteString(name) - p.WriteByte(':') - } - } - p.printValue(getField(f, i), verb, depth+1) - } - p.WriteByte('}') - case reflect.Interface: - value := f.Elem() - if !value.IsValid() { - if p.fmt.SharpV { - p.WriteString(f.Type().String()) - p.WriteString(nilParenString) - } else { - p.WriteString(nilAngleString) - } - } else { - p.printValue(value, verb, depth+1) - } - case reflect.Array, reflect.Slice: - switch verb { - case 's', 'q', 'x', 'X': - // Handle byte and uint8 slices and arrays special for the above verbs. - t := f.Type() - if t.Elem().Kind() == reflect.Uint8 { - var bytes []byte - if f.Kind() == reflect.Slice { - bytes = f.Bytes() - } else if f.CanAddr() { - bytes = f.Slice(0, f.Len()).Bytes() - } else { - // We have an array, but we cannot Slice() a non-addressable array, - // so we build a slice by hand. This is a rare case but it would be nice - // if reflection could help a little more. - bytes = make([]byte, f.Len()) - for i := range bytes { - bytes[i] = byte(f.Index(i).Uint()) - } - } - p.fmtBytes(bytes, verb, t.String()) - return - } - } - if p.fmt.SharpV { - p.WriteString(f.Type().String()) - if f.Kind() == reflect.Slice && f.IsNil() { - p.WriteString(nilParenString) - return - } - p.WriteByte('{') - for i := 0; i < f.Len(); i++ { - if i > 0 { - p.WriteString(commaSpaceString) - } - p.printValue(f.Index(i), verb, depth+1) - } - p.WriteByte('}') - } else { - p.WriteByte('[') - for i := 0; i < f.Len(); i++ { - if i > 0 { - p.WriteByte(' ') - } - p.printValue(f.Index(i), verb, depth+1) - } - p.WriteByte(']') - } - case reflect.Ptr: - // pointer to array or slice or struct? ok at top level - // but not embedded (avoid loops) - if depth == 0 && f.Pointer() != 0 { - switch a := f.Elem(); a.Kind() { - case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map: - p.WriteByte('&') - p.printValue(a, verb, depth+1) - return - } - } - fallthrough - case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(f, verb) - default: - p.unknownType(f) - } -} - -func (p *printer) badArgNum(verb rune) { - p.WriteString(percentBangString) - p.WriteRune(verb) - p.WriteString(badIndexString) -} - -func (p *printer) missingArg(verb rune) { - p.WriteString(percentBangString) - p.WriteRune(verb) - p.WriteString(missingString) -} - -func (p *printer) doPrintf(fmt string) { - for p.fmt.Parser.SetFormat(fmt); p.fmt.Scan(); { - switch p.fmt.Status { - case format.StatusText: - p.WriteString(p.fmt.Text()) - case format.StatusSubstitution: - p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb) - case format.StatusBadWidthSubstitution: - p.WriteString(badWidthString) - p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb) - case format.StatusBadPrecSubstitution: - p.WriteString(badPrecString) - p.printArg(p.Arg(p.fmt.ArgNum), p.fmt.Verb) - case format.StatusNoVerb: - p.WriteString(noVerbString) - case format.StatusBadArgNum: - p.badArgNum(p.fmt.Verb) - case format.StatusMissingArg: - p.missingArg(p.fmt.Verb) - default: - panic("unreachable") - } - } - - // Check for extra arguments, but only if there was at least one ordered - // argument. Note that this behavior is necessarily different from fmt: - // different variants of messages may opt to drop some or all of the - // arguments. - if !p.fmt.Reordered && p.fmt.ArgNum < len(p.fmt.Args) && p.fmt.ArgNum != 0 { - p.fmt.ClearFlags() - p.WriteString(extraString) - for i, arg := range p.fmt.Args[p.fmt.ArgNum:] { - if i > 0 { - p.WriteString(commaSpaceString) - } - if arg == nil { - p.WriteString(nilAngleString) - } else { - p.WriteString(reflect.TypeOf(arg).String()) - p.WriteString("=") - p.printArg(arg, 'v') - } - } - p.WriteByte(')') - } -} - -func (p *printer) doPrint(a []interface{}) { - prevString := false - for argNum, arg := range a { - isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String - // Add a space between two non-string arguments. - if argNum > 0 && !isString && !prevString { - p.WriteByte(' ') - } - p.printArg(arg, 'v') - prevString = isString - } -} - -// doPrintln is like doPrint but always adds a space between arguments -// and a newline after the last argument. -func (p *printer) doPrintln(a []interface{}) { - for argNum, arg := range a { - if argNum > 0 { - p.WriteByte(' ') - } - p.printArg(arg, 'v') - } - p.WriteByte('\n') -} -- cgit v1.2.3-1-g7c22