| // 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 number |
| |
| import ( |
| "fmt" |
| |
| "golang.org/x/text/internal/number" |
| "golang.org/x/text/language" |
| ) |
| |
| // An Option configures a Formatter. |
| type Option option |
| |
| type option func(tag language.Tag, f *number.Formatter) |
| |
| // TODO: SpellOut requires support of the ICU RBNF format. |
| // func SpellOut() Option |
| |
| // NoSeparator causes a number to be displayed without grouping separators. |
| func NoSeparator() Option { |
| return func(t language.Tag, f *number.Formatter) { |
| f.GroupingSize = [2]uint8{} |
| } |
| } |
| |
| // MaxIntegerDigits limits the number of integer digits, eliminating the |
| // most significant digits. |
| func MaxIntegerDigits(max int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| if max >= 1<<8 { |
| max = (1 << 8) - 1 |
| } |
| f.MaxIntegerDigits = uint8(max) |
| } |
| } |
| |
| // MinIntegerDigits specifies the minimum number of integer digits, adding |
| // leading zeros when needed. |
| func MinIntegerDigits(min int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| if min >= 1<<8 { |
| min = (1 << 8) - 1 |
| } |
| f.MinIntegerDigits = uint8(min) |
| } |
| } |
| |
| // MaxFractionDigits specifies the maximum number of fractional digits. |
| func MaxFractionDigits(max int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| if max >= 1<<15 { |
| max = (1 << 15) - 1 |
| } |
| f.MaxFractionDigits = int16(max) |
| } |
| } |
| |
| // MinFractionDigits specifies the minimum number of fractional digits. |
| func MinFractionDigits(min int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| if min >= 1<<8 { |
| min = (1 << 8) - 1 |
| } |
| f.MinFractionDigits = uint8(min) |
| } |
| } |
| |
| // Precision sets the maximum number of significant digits. A negative value |
| // means exact. |
| func Precision(prec int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| f.SetPrecision(prec) |
| } |
| } |
| |
| // Scale simultaneously sets MinFractionDigits and MaxFractionDigits to the |
| // given value. |
| func Scale(decimals int) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| f.SetScale(decimals) |
| } |
| } |
| |
| // IncrementString sets the incremental value to which numbers should be |
| // rounded. For instance: Increment("0.05") will cause 1.44 to round to 1.45. |
| // IncrementString also sets scale to the scale of the increment. |
| func IncrementString(decimal string) Option { |
| increment := 0 |
| scale := 0 |
| d := decimal |
| p := 0 |
| for ; p < len(d) && '0' <= d[p] && d[p] <= '9'; p++ { |
| increment *= 10 |
| increment += int(d[p]) - '0' |
| } |
| if p < len(d) && d[p] == '.' { |
| for p++; p < len(d) && '0' <= d[p] && d[p] <= '9'; p++ { |
| increment *= 10 |
| increment += int(d[p]) - '0' |
| scale++ |
| } |
| } |
| if p < len(d) { |
| increment = 0 |
| scale = 0 |
| } |
| return func(t language.Tag, f *number.Formatter) { |
| f.Increment = uint32(increment) |
| f.IncrementScale = uint8(scale) |
| f.SetScale(scale) |
| } |
| } |
| |
| func noop(language.Tag, *number.Formatter) {} |
| |
| // PatternOverrides allows users to specify alternative patterns for specific |
| // languages. The Pattern will be overridden for all languages in a subgroup as |
| // well. The function will panic for invalid input. It is best to create this |
| // option at startup time. |
| // PatternOverrides must be the first Option passed to a formatter. |
| func PatternOverrides(patterns map[string]string) Option { |
| // TODO: make it so that it does not have to be the first option. |
| // TODO: use -x-nochild to indicate it does not override child tags. |
| m := map[language.Tag]*number.Pattern{} |
| for k, v := range patterns { |
| tag := language.MustParse(k) |
| p, err := number.ParsePattern(v) |
| if err != nil { |
| panic(fmt.Errorf("number: PatternOverrides: %v", err)) |
| } |
| m[tag] = p |
| } |
| return func(t language.Tag, f *number.Formatter) { |
| // TODO: Use language grouping relation instead of parent relation. |
| // TODO: Should parent implement the grouping relation? |
| for lang := t; ; lang = t.Parent() { |
| if p, ok := m[lang]; ok { |
| f.Pattern = *p |
| break |
| } |
| if lang == language.Und { |
| break |
| } |
| } |
| } |
| } |
| |
| // FormatWidth sets the total format width. |
| func FormatWidth(n int) Option { |
| if n <= 0 { |
| return noop |
| } |
| return func(t language.Tag, f *number.Formatter) { |
| f.FormatWidth = uint16(n) |
| if f.PadRune == 0 { |
| f.PadRune = ' ' |
| } |
| } |
| } |
| |
| // Pad sets the rune to be used for filling up to the format width. |
| func Pad(r rune) Option { |
| return func(t language.Tag, f *number.Formatter) { |
| f.PadRune = r |
| } |
| } |
| |
| // TODO: |
| // - FormatPosition (using type aliasing?) |
| // - Multiplier: find a better way to represent and figure out what to do |
| // with clashes with percent/permille. |
| // - NumberingSystem(nu string): not accessible in number.Info now. Also, should |
| // this be keyed by language or generic? |
| // - SymbolOverrides(symbols map[string]map[number.SymbolType]string) Option |