This is an automated email from the ASF dual-hosted git repository. rohit pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
commit a96aad88988b6203f57bef71ee0c9af95cbb7e84 Author: Rohit Yadav <[email protected]> AuthorDate: Sat Oct 20 09:49:27 2018 +0530 vendor: update dependencies Signed-off-by: Rohit Yadav <[email protected]> --- .../briandowns/spinner/character_sets.go | 2 + vendor/github.com/briandowns/spinner/spinner.go | 66 +- vendor/github.com/chzyer/readline/complete.go | 2 +- vendor/github.com/lunixbochs/vtclean/vtclean.go | 13 +- .../lunixbochs/vtclean/vtclean/vtclean.go | 17 - vendor/github.com/manifoldco/promptui/codes.go | 26 +- vendor/github.com/manifoldco/promptui/keycodes.go | 26 +- .../manifoldco/promptui/keycodes_windows.go | 24 +- vendor/github.com/manifoldco/promptui/list/list.go | 13 +- vendor/github.com/manifoldco/promptui/prompt.go | 71 +- vendor/github.com/manifoldco/promptui/promptui.go | 21 +- .../manifoldco/promptui/screenbuf/screenbuf.go | 4 +- vendor/github.com/manifoldco/promptui/select.go | 171 +++- vendor/github.com/manifoldco/promptui/styles.go | 21 +- .../manifoldco/promptui/styles_windows.go | 21 +- .../mattn/go-colorable/cmd/colorable/colorable.go | 12 - .../mattn/go-colorable/colorable_windows.go | 208 ++-- .../mattn/go-runewidth/runewidth_posix_test.go | 78 -- .../mattn/go-runewidth/runewidth_test.go | 297 ------ .../github.com/mattn/go-shellwords/shellwords.go | 47 +- vendor/github.com/mattn/go-shellwords/util_go15.go | 24 - .../github.com/mattn/go-shellwords/util_posix.go | 5 +- .../github.com/mattn/go-shellwords/util_windows.go | 5 - vendor/github.com/mitchellh/go-homedir/homedir.go | 56 +- vendor/github.com/olekukonko/tablewriter/README.md | 2 +- .../olekukonko/tablewriter/csv2table/README.md | 43 - .../olekukonko/tablewriter/csv2table/csv2table.go | 85 -- .../olekukonko/tablewriter/table_test.go | 1055 -------------------- vendor/github.com/olekukonko/tablewriter/util.go | 19 +- .../github.com/olekukonko/tablewriter/wrap_test.go | 58 -- vendor/gopkg.in/ini.v1/file.go | 47 +- vendor/gopkg.in/ini.v1/ini.go | 26 +- vendor/gopkg.in/ini.v1/parser.go | 143 ++- vendor/gopkg.in/ini.v1/section.go | 1 + 34 files changed, 648 insertions(+), 2061 deletions(-) diff --git a/vendor/github.com/briandowns/spinner/character_sets.go b/vendor/github.com/briandowns/spinner/character_sets.go index 1efe6e6..600ba37 100644 --- a/vendor/github.com/briandowns/spinner/character_sets.go +++ b/vendor/github.com/briandowns/spinner/character_sets.go @@ -49,6 +49,8 @@ var CharSets = map[int][]string{ 41: {"⬒", "⬔", "⬓", "⬕"}, 42: {"⬖", "⬘", "⬗", "⬙"}, 43: {"[>>> >]", "[]>>>> []", "[] >>>> []", "[] >>>> []", "[] >>>> []", "[] >>>>[]", "[>> >>]"}, + 44: {"♠", "♣", "♥", "♦"}, + 45: {"➞", "➟", "➠", "➡", "➠", "➟"}, } func init() { diff --git a/vendor/github.com/briandowns/spinner/spinner.go b/vendor/github.com/briandowns/spinner/spinner.go index 2cd0414..3f1ffdb 100644 --- a/vendor/github.com/briandowns/spinner/spinner.go +++ b/vendor/github.com/briandowns/spinner/spinner.go @@ -14,9 +14,12 @@ package spinner import ( + "encoding/hex" "errors" "fmt" "io" + "os" + "runtime" "strconv" "sync" "time" @@ -183,8 +186,8 @@ type Spinner struct { } // New provides a pointer to an instance of Spinner with the supplied options -func New(cs []string, d time.Duration) *Spinner { - return &Spinner{ +func New(cs []string, d time.Duration, options ...Option) *Spinner { + s:= &Spinner{ Delay: d, chars: cs, color: color.New(color.FgWhite).SprintFunc(), @@ -193,6 +196,38 @@ func New(cs []string, d time.Duration) *Spinner { active: false, stopChan: make(chan struct{}, 1), } + + for _, option := range options { + option(s) + } + + return s +} + +type Option func(*Spinner) + +type Options struct { + Color string + Suffix string + FinalMSG string +} + +func WithColor(color string) Option { + return func(s *Spinner) { + s.Color(color) + } +} + +func WithSuffix(suffix string) Option { + return func(s *Spinner) { + s.Suffix = suffix + } +} + +func WithFinalMSG(finalMsg string) Option { + return func(s *Spinner) { + s.FinalMSG = finalMsg + } } // Active will return whether or not the spinner is currently active @@ -216,7 +251,16 @@ func (s *Spinner) Start() { default: s.lock.Lock() s.erase() - outColor := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix) + var outColor string + if runtime.GOOS == "windows" { + if s.Writer == os.Stderr { + outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.chars[i], s.Suffix) + } else { + outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix) + } + } else { + outColor = fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix) + } outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix) fmt.Fprint(s.Writer, outColor) s.lastOutput = outPlain @@ -297,7 +341,21 @@ func (s *Spinner) UpdateCharSet(cs []string) { // Caller must already hold s.lock. func (s *Spinner) erase() { n := utf8.RuneCountInString(s.lastOutput) - for _, c := range []string{"\b", " ", "\b"} { + if runtime.GOOS == "windows" { + clearString := "\r" + for i := 0; i < n; i++ { + clearString += " " + } + fmt.Fprintf(s.Writer, clearString) + return + } + del, _ := hex.DecodeString("7f") + for _, c := range []string{ + "\b", + string(del), + "\b", + "\033[K", // for macOS Terminal + } { for i := 0; i < n; i++ { fmt.Fprintf(s.Writer, c) } diff --git a/vendor/github.com/chzyer/readline/complete.go b/vendor/github.com/chzyer/readline/complete.go index d1351f7..c08c994 100644 --- a/vendor/github.com/chzyer/readline/complete.go +++ b/vendor/github.com/chzyer/readline/complete.go @@ -221,7 +221,7 @@ func (o *opCompleter) CompleteRefresh() { } buf.WriteString(string(same)) buf.WriteString(string(c)) - buf.Write(bytes.Repeat([]byte(" "), colWidth-len(c)-len(same))) + buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same))) if inSelect { buf.WriteString("\033[0m") diff --git a/vendor/github.com/lunixbochs/vtclean/vtclean.go b/vendor/github.com/lunixbochs/vtclean/vtclean.go index fec492c..64fe01f 100644 --- a/vendor/github.com/lunixbochs/vtclean/vtclean.go +++ b/vendor/github.com/lunixbochs/vtclean/vtclean.go @@ -6,8 +6,13 @@ import ( "strconv" ) -// see regex.txt for a slightly separated version of this regex -var vt100re = regexp.MustCompile(`^\033([\[\]]([\d\?]+)?(;[\d\?]+)*)?(.)`) +// regex based on ECMA-48: +// 1. optional: +// one of [ or ] +// any amount of 0x30-0x3f +// any amount of 0x20-0x2f +// 3. exactly one 0x40-0x7e +var vt100re = regexp.MustCompile(`^\033([\[\]]([0-9:;<=>\?]*)([!"#$%&'()*+,\-./]*))?([@A-Z\[\]^_\x60a-z{|}~])`) var vt100exc = regexp.MustCompile(`^\033(\[[^a-zA-Z0-9@\?]+|[\(\)]).`) // this is to handle the RGB escape generated by `tput initc 1 500 500 500` @@ -21,6 +26,8 @@ func Clean(line string, color bool) string { for i := 0; i < len(lineb); { c := lineb[i] switch c { + case '\r': + edit.MoveAbs(0) case '\b': edit.Move(-1) case '\033': @@ -74,7 +81,7 @@ func Clean(line string, color bool) string { } continue default: - if c == '\n' || c >= ' ' { + if c == '\n' || c == '\t' || c >= ' ' { edit.Write([]byte{c}) } } diff --git a/vendor/github.com/lunixbochs/vtclean/vtclean/vtclean.go b/vendor/github.com/lunixbochs/vtclean/vtclean/vtclean.go deleted file mode 100644 index 2c4f177..0000000 --- a/vendor/github.com/lunixbochs/vtclean/vtclean/vtclean.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "flag" - "github.com/lunixbochs/vtclean" - "io" - "os" -) - -func main() { - color := flag.Bool("color", false, "enable color") - flag.Parse() - - stdout := vtclean.NewWriter(os.Stdout, *color) - defer stdout.Close() - io.Copy(stdout, os.Stdin) -} diff --git a/vendor/github.com/manifoldco/promptui/codes.go b/vendor/github.com/manifoldco/promptui/codes.go index de3f086..8138c40 100644 --- a/vendor/github.com/manifoldco/promptui/codes.go +++ b/vendor/github.com/manifoldco/promptui/codes.go @@ -11,7 +11,9 @@ const esc = "\033[" type attribute int -// Foreground weight/decoration attributes. +// The possible state of text inside the application, either Bold, faint, italic or underline. +// +// These constants are called through the use of the Styler function. const ( reset attribute = iota @@ -21,7 +23,9 @@ const ( FGUnderline ) -// Foreground color attributes +// The possible colors of text inside the application. +// +// These constants are called through the use of the Styler function. const ( FGBlack attribute = iota + 30 FGRed @@ -33,7 +37,9 @@ const ( FGWhite ) -// Background color attributes +// The possible background colors of text inside the application. +// +// These constants are called through the use of the Styler function. const ( BGBlack attribute = iota + 40 BGRed @@ -54,8 +60,10 @@ const ( clearLine = esc + "2K" ) -// FuncMap defines template helpers for the output. It can be extended as a -// regular map. +// FuncMap defines template helpers for the output. It can be extended as a regular map. +// +// The functions inside the map link the state, color and background colors strings detected in templates to a Styler +// function that applies the given style using the corresponding constant. var FuncMap = template.FuncMap{ "black": Styler(FGBlack), "red": Styler(FGRed), @@ -87,8 +95,12 @@ func movementCode(n uint, code rune) string { return esc + strconv.FormatUint(uint64(n), 10) + string(code) } -// Styler returns a func that applies the attributes given in the Styler call -// to the provided string. +// Styler is a function that accepts multiple possible styling transforms from the state, +// color and background colors constants and transforms them into a templated string +// to apply those styles in the CLI. +// +// The returned styling function accepts a string that will be extended with +// the wrapping function's styling attributes. func Styler(attrs ...attribute) func(interface{}) string { attrstrs := make([]string, len(attrs)) for i, v := range attrs { diff --git a/vendor/github.com/manifoldco/promptui/keycodes.go b/vendor/github.com/manifoldco/promptui/keycodes.go index c1f8491..2b22e24 100644 --- a/vendor/github.com/manifoldco/promptui/keycodes.go +++ b/vendor/github.com/manifoldco/promptui/keycodes.go @@ -4,22 +4,28 @@ package promptui import "github.com/chzyer/readline" +// These runes are used to identity the commands entered by the user in the command prompt. They map +// to specific actions of promptui in prompt mode and can be remapped if necessary. var ( - // KeyEnter is the default key for submission/selection + // KeyEnter is the default key for submission/selection. KeyEnter rune = readline.CharEnter - // KeyBackspace is the default key for deleting input text + // KeyBackspace is the default key for deleting input text. KeyBackspace rune = readline.CharBackspace - // KeyPrev is the default key to go up during selection - KeyPrev rune = readline.CharPrev + // KeyPrev is the default key to go up during selection. + KeyPrev rune = readline.CharPrev + KeyPrevDisplay = "↑" - // KeyNext is the default key to go down during selection - KeyNext rune = readline.CharNext + // KeyNext is the default key to go down during selection. + KeyNext rune = readline.CharNext + KeyNextDisplay = "↓" - // KeyBackward is the default key to page up during selection - KeyBackward rune = readline.CharBackward + // KeyBackward is the default key to page up during selection. + KeyBackward rune = readline.CharBackward + KeyBackwardDisplay = "←" - // KeyForward is the default key to page down during selection - KeyForward rune = readline.CharForward + // KeyForward is the default key to page down during selection. + KeyForward rune = readline.CharForward + KeyForwardDisplay = "→" ) diff --git a/vendor/github.com/manifoldco/promptui/keycodes_windows.go b/vendor/github.com/manifoldco/promptui/keycodes_windows.go index fa4709c..fc29d39 100644 --- a/vendor/github.com/manifoldco/promptui/keycodes_windows.go +++ b/vendor/github.com/manifoldco/promptui/keycodes_windows.go @@ -3,23 +3,27 @@ package promptui // source: https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx var ( - // KeyEnter is the default key for submission/selection + // KeyEnter is the default key for submission/selection inside a command line prompt. KeyEnter rune = 13 - // KeyBackspace is the default key for deleting input text + // KeyBackspace is the default key for deleting input text inside a command line prompt. KeyBackspace rune = 8 // FIXME: keys below are not triggered by readline, not working on Windows - // KeyPrev is the default key to go up during selection - KeyPrev rune = 38 + // KeyPrev is the default key to go up during selection inside a command line prompt. + KeyPrev rune = 38 + KeyPrevDisplay = "k" - // KeyNext is the default key to go down during selection - KeyNext rune = 40 + // KeyNext is the default key to go down during selection inside a command line prompt. + KeyNext rune = 40 + KeyNextDisplay = "j" - // KeyBackward is the default key to page up during selection - KeyBackward rune = 37 + // KeyBackward is the default key to page up during selection inside a command line prompt. + KeyBackward rune = 37 + KeyBackwardDisplay = "h" - // KeyForward is the default key to page down during selection - KeyForward rune = 39 + // KeyForward is the default key to page down during selection inside a command line prompt. + KeyForward rune = 39 + KeyForwardDisplay = "l" ) diff --git a/vendor/github.com/manifoldco/promptui/list/list.go b/vendor/github.com/manifoldco/promptui/list/list.go index b1cc8be..0765da9 100644 --- a/vendor/github.com/manifoldco/promptui/list/list.go +++ b/vendor/github.com/manifoldco/promptui/list/list.go @@ -6,7 +6,9 @@ import ( "strings" ) -// Searcher can be implemented to allow the list to search for results. +// Searcher is a base function signature that is used inside select when activating the search mode. +// If defined, it is called on each items of the select and should return a boolean for whether or not +// the item fits the searched term. type Searcher func(input string, index int) bool // NotFound is an index returned when no item was selected. This could @@ -25,8 +27,8 @@ type List struct { Searcher Searcher } -// New creates and initializes a list. Items must be a slice type and size must -// be greater than 0. +// New creates and initializes a list of searchable items. The items attribute must be a slice type with a +// size greater than 0. Error will be returned if those two conditions are not met. func New(items interface{}, size int) (*List, error) { if size < 1 { return nil, fmt.Errorf("list size %d must be greater than 0", size) @@ -61,7 +63,7 @@ func (l *List) Prev() { } // Search allows the list to be filtered by a given term. The list must -// implement the searcher method for that. +// implement the searcher function signature for this functionality to work. func (l *List) Search(term string) { term = strings.Trim(term, " ") l.cursor = 0 @@ -159,7 +161,8 @@ func (l *List) CanPageUp() bool { return l.start > 0 } -// Index returns the index of the item currently selected. +// Index returns the index of the item currently selected inside the searched list. If no item is selected, +// the NotFound (-1) index is returned. func (l *List) Index() int { selected := l.scope[l.cursor] diff --git a/vendor/github.com/manifoldco/promptui/prompt.go b/vendor/github.com/manifoldco/promptui/prompt.go index 9fdfcb6..402befc 100644 --- a/vendor/github.com/manifoldco/promptui/prompt.go +++ b/vendor/github.com/manifoldco/promptui/prompt.go @@ -12,31 +12,35 @@ import ( const cursor = "\u2588" -// Prompt represents a single line text field input. +// Prompt represents a single line text field input with options for validation and input masks. type Prompt struct { - // Label is the value displayed on the command line prompt. It can be any - // value one would pass to a text/template Execute(), including just a string. + // Label is the value displayed on the command line prompt. + // + // The value for Label can be a simple string or a struct that will need to be accessed by dot notation + // inside the templates. For example, `{{ .Name }}` will display the name property of a struct. Label interface{} - Default string // Default is the initial value to populate in the prompt + // Default is the initial value for the prompt. This value will be displayed next to the prompt's label + // and the user will be able to view or change it depending on the options. + Default string // AllowEdit lets the user edit the default value. If false, any key press // other than <Enter> automatically clears the default value. AllowEdit bool - // Validate is optional. If set, this function is used to validate the input - // after each character entry. + // Validate is an optional function that fill be used against the entered value in the prompt to validate it. Validate ValidateFunc - // If mask is set, this value is displayed instead of the actual input - // characters. + // Mask is an optional rune that sets which character to display instead of the entered characters. This + // allows hiding private information like passwords. Mask rune // Templates can be used to customize the prompt output. If nil is passed, the - // default templates are used. + // default templates are used. See the PromptTemplates docs for more info. Templates *PromptTemplates - // IsConfirm sets the prompt to be a [y/N] question. + // IsConfirm makes the prompt ask for a yes or no ([Y/N]) question rather than request an input. When set, + // most properties related to input will be ignored. IsConfirm bool // IsVimMode enables vi-like movements (hjkl) and editing. @@ -47,28 +51,51 @@ type Prompt struct { } // PromptTemplates allow a prompt to be customized following stdlib -// text/template syntax. If any field is blank a default template is used. +// text/template syntax. Custom state, colors and background color are available for use inside +// the templates and are documented inside the Variable section of the docs. +// +// Examples +// +// text/templates use a special notation to display programmable content. Using the double bracket notation, +// the value can be printed with specific helper functions. For example +// +// This displays the value given to the template as pure, unstylized text. +// '{{ . }}' +// +// This displays the value colored in cyan +// '{{ . | cyan }}' +// +// This displays the value colored in red with a cyan background-color +// '{{ . | red | cyan }}' +// +// See the doc of text/template for more info: https://golang.org/pkg/text/template/ type PromptTemplates struct { - // Prompt is a text/template for the initial prompt question. + // Prompt is a text/template for the prompt label displayed on the left side of the prompt. Prompt string - // Prompt is a text/template if the prompt is a confirmation. + // Prompt is a text/template for the prompt label when IsConfirm is set as true. Confirm string - // Valid is a text/template for when the current input is valid. + // Valid is a text/template for the prompt label when the value entered is valid. Valid string - // Invalid is a text/template for when the current input is invalid. + // Invalid is a text/template for the prompt label when the value entered is invalid. Invalid string - // Success is a text/template for the successful result. + // Success is a text/template for the prompt label when the user has pressed entered and the value has been + // deemed valid by the validation function. The label will keep using this template even when the prompt ends + // inside the console. Success string - // Prompt is a text/template when there is a validation error. + // Prompt is a text/template for the prompt label when the value is invalid dur to an error triggered from + // the prompt's validation function. ValidationError string - // FuncMap is a map of helpers for the templates. If nil, the default helpers - // are used. + // FuncMap is a map of helper functions that can be used inside of templates according to the text/template + // documentation. + // + // By default, FuncMap contains the color functions used to color the text in templates. If FuncMap + // is overridden, the colors functions must be added in the override from promptui.FuncMap to work. FuncMap template.FuncMap prompt *template.Template @@ -78,7 +105,9 @@ type PromptTemplates struct { success *template.Template } -// Run runs the prompt, returning the validated input. +// Run executes the prompt. Its displays the label and default value if any, asking the user to enter a value. +// Run will keep the prompt alive until it has been canceled from the command prompt or it has received a valid +// value. It will return the value and an error if any occurred during the prompt's execution. func (p *Prompt) Run() (string, error) { c := &readline.Config{} err := c.Init() @@ -228,7 +257,7 @@ func (p *Prompt) Run() (string, error) { echo = strings.Repeat(string(p.Mask), len(echo)) } - prompt := render(p.Templates.valid, p.Label) + prompt := render(p.Templates.success, p.Label) prompt = append(prompt, []byte(echo)...) if p.IsConfirm { diff --git a/vendor/github.com/manifoldco/promptui/promptui.go b/vendor/github.com/manifoldco/promptui/promptui.go index 4faa68d..6248e58 100644 --- a/vendor/github.com/manifoldco/promptui/promptui.go +++ b/vendor/github.com/manifoldco/promptui/promptui.go @@ -1,18 +1,27 @@ -// Package promptui provides ui elements for the command line prompt. +// Package promptui is a library providing a simple interface to create command-line prompts for go. +// It can be easily integrated into spf13/cobra, urfave/cli or any cli go application. +// +// promptui has two main input modes: +// +// Prompt provides a single line for user input. It supports optional live validation, +// confirmation and masking the input. +// +// Select provides a list of options to choose from. It supports pagination, search, +// detailed view and custom templates. package promptui import "errors" -// ErrEOF is returned from prompts when EOF is encountered. +// ErrEOF is the error returned from prompts when EOF is encountered. var ErrEOF = errors.New("^D") -// ErrInterrupt is returned from prompts when an interrupt (ctrl-c) is +// ErrInterrupt is the error returned from prompts when an interrupt (ctrl-c) is // encountered. var ErrInterrupt = errors.New("^C") -// ErrAbort is returned when confirm prompts are supplied "n" +// ErrAbort is the error returned when confirm prompts are supplied "n" var ErrAbort = errors.New("") -// ValidateFunc validates the given input. It should return a ValidationError -// if the input is not valid. +// ValidateFunc is a placeholder type for any validation functions that validates a given input. It should return +// a ValidationError if the input is not valid. type ValidateFunc func(string) error diff --git a/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go b/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go index f9dd24c..e4f87ee 100644 --- a/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go +++ b/vendor/github.com/manifoldco/promptui/screenbuf/screenbuf.go @@ -40,7 +40,7 @@ func (s *ScreenBuf) Reset() { // Write writes a single line to the underlining buffer. If the ScreenBuf was // previously reset, all previous lines are cleared and the output starts from -// the top. Lines with \r or \n will fail since they can interfere with the +// the top. Lines with \r or \n will cause an error since they can interfere with the // terminal ability to move between lines. func (s *ScreenBuf) Write(b []byte) (int, error) { if bytes.ContainsAny(b, "\r\n") { @@ -97,7 +97,7 @@ func (s *ScreenBuf) Write(b []byte) (int, error) { } } -// Flush writes any buffered data to the underlying io.Writer. +// Flush writes any buffered data to the underlying io.Writer, ensuring that any pending data is displayed. func (s *ScreenBuf) Flush() error { for i := s.cursor; i < s.height; i++ { if i < s.height { diff --git a/vendor/github.com/manifoldco/promptui/select.go b/vendor/github.com/manifoldco/promptui/select.go index 165b969..afa6f67 100644 --- a/vendor/github.com/manifoldco/promptui/select.go +++ b/vendor/github.com/manifoldco/promptui/select.go @@ -13,37 +13,55 @@ import ( "github.com/manifoldco/promptui/screenbuf" ) -// SelectedAdd is returned from SelectWithAdd when add is selected. +// SelectedAdd is used internally inside SelectWithAdd when the add option is selected in select mode. +// Since -1 is not a possible selected index, this ensure that add mode is always unique inside +// SelectWithAdd's logic. const SelectedAdd = -1 -// Select represents a list for selecting a single item +// Select represents a list of items used to enable selections, they can be used as search engines, menus +// or as a list of items in a cli based prompt. type Select struct { - // Label is the value displayed on the command line prompt. It can be any - // value one would pass to a text/template Execute(), including just a string. + // Label is the text displayed on top of the list to direct input. The IconInitial value "?" will be + // appended automatically to the label so it does not need to be added. + // + // The value for Label can be a simple string or a struct that will need to be accessed by dot notation + // inside the templates. For example, `{{ .Name }}` will display the name property of a struct. Label interface{} - // Items are the items to use in the list. It can be any slice type one would - // pass to a text/template execute, including a string slice. + // Items are the items to display inside the list. It expect a slice of any kind of values, including strings. + // + // If using a slice a strings, promptui will use those strings directly into its base templates or the + // provided templates. If using any other type in the slice, it will attempt to transform it into a string + // before giving it to its templates. Custom templates will override this behavior if using the dot notation + // inside the templates. + // + // For example, `{{ .Name }}` will display the name property of a struct. Items interface{} - // Size is the number of items that should appear on the select before - // scrolling. If it is 0, defaults to 5. + // Size is the number of items that should appear on the select before scrolling is necessary. Defaults to 5. Size int - // IsVimMode sets whether readline is using Vim mode. + // IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at + // https://godoc.org/github.com/chzyer/readline#Config for more information on readline. IsVimMode bool // Templates can be used to customize the select output. If nil is passed, the - // default templates are used. + // default templates are used. See the SelectTemplates docs for more info. Templates *SelectTemplates - // Keys can be used to change movement and search keys. + // Keys is the set of keys used in select mode to control the command line interface. See the SelectKeys docs for + // more info. Keys *SelectKeys - // Searcher can be implemented to teach the select how to search for items. + // Searcher is a function that can be implemented to refine the base searching algorithm in selects. + // + // Search is a function that will receive the searched term and the item's index and should return a boolean + // for whether or not the terms are alike. It is unimplemented by default and search will not work unless + // it is implemented. Searcher list.Searcher - // Starts the prompt in search mode. + // StartInSearchMode sets whether or not the select mdoe should start in search mode or selection mode. + // For search mode to work, the Search property must be implemented. StartInSearchMode bool label string @@ -51,32 +69,71 @@ type Select struct { list *list.List } -// SelectKeys defines which keys can be used for movement and search. +// SelectKeys defines the available keys used by select mode to enable the user to move around the list +// and trigger search mode. See the Key struct docs for more information on keys. type SelectKeys struct { - Next Key // Next defaults to down arrow key - Prev Key // Prev defaults to up arrow key - PageUp Key // PageUp defaults to left arrow key - PageDown Key // PageDown defaults to right arrow key - Search Key // Search defaults to '/' key + // Next is the key used to move to the next element inside the list. Defaults to down arrow key. + Next Key + + // Prev is the key used to move to the previous element inside the list. Defaults to up arrow key. + Prev Key + + // PageUp is the key used to jump back to the first element inside the list. Defaults to left arrow key. + PageUp Key + + // PageUp is the key used to jump forward to the last element inside the list. Defaults to right arrow key. + PageDown Key + + // Search is the key used to trigger the search mode for the list. Default to the "/" key. + Search Key } -// Key defines a keyboard code and a display representation for the help -// Check https://github.com/chzyer/readline for a list of codes +// Key defines a keyboard code and a display representation for the help menu. type Key struct { - Code rune + // Code is a rune that will be used to compare against typed keys with readline. + // Check https://github.com/chzyer/readline for a list of codes + Code rune + + // Display is the string that will be displayed inside the help menu to help inform the user + // of which key to use on his keyboard for various functions. Display string } -// SelectTemplates allow a select prompt to be customized following stdlib -// text/template syntax. If any field is blank a default template is used. +// SelectTemplates allow a select list to be customized following stdlib +// text/template syntax. Custom state, colors and background color are available for use inside +// the templates and are documented inside the Variable section of the docs. +// +// Examples +// +// text/templates use a special notation to display programmable content. Using the double bracket notation, +// the value can be printed with specific helper functions. For example +// +// This displays the value given to the template as pure, unstylized text. Structs are transformed to string +// with this notation. +// '{{ . }}' +// +// This displays the name property of the value colored in cyan +// '{{ .Name | cyan }}' +// +// This displays the label property of value colored in red with a cyan background-color +// '{{ .Label | red | cyan }}' +// +// See the doc of text/template for more info: https://golang.org/pkg/text/template/ +// +// Notes +// +// Setting any of these templates will remove the icons from the default templates. They must +// be added back in each of their specific templates. The styles.go constants contains the default icons. type SelectTemplates struct { - // Active is a text/template for the label. + // Label is a text/template for the main command line label. Defaults to printing the label as it with + // the IconInitial. Label string - // Active is a text/template for when an item is current active. + // Active is a text/template for when an item is currently active within the list. Active string - // Inactive is a text/template for when an item is not current active. + // Inactive is a text/template for when an item is not currently active inside the list. This + // template is used for all items unless they are active or selected. Inactive string // Selected is a text/template for when an item was successfully selected. @@ -84,14 +141,22 @@ type SelectTemplates struct { // Details is a text/template for when an item current active to show // additional information. It can have multiple lines. + // + // Detail will always be displayed for the active element and thus can be used to display additional + // information on the element beyond its label. + // + // promptui will not trim spaces and tabs will be displayed if the template is indented. Details string // Help is a text/template for displaying instructions at the top. By default // it shows keys for movement and search. Help string - // FuncMap is a map of helpers for the templates. If nil, the default helpers - // are used. + // FuncMap is a map of helper functions that can be used inside of templates according to the text/template + // documentation. + // + // By default, FuncMap contains the color functions used to color the text in templates. If FuncMap + // is overridden, the colors functions must be added in the override from promptui.FuncMap to work. FuncMap template.FuncMap label *template.Template @@ -102,8 +167,10 @@ type SelectTemplates struct { help *template.Template } -// Run runs the Select list. It returns the index of the selected element, -// and its value. +// Run executes the select list. Its displays the label and the list of items, asking the user to chose any +// value within to list. Run will keep the prompt alive until it has been canceled from +// the command prompt or it has received a valid value. It will return the value and an error if any +// occurred during the select's execution. func (s *Select) Run() (int, string, error) { if s.Size == 0 { s.Size = 5 @@ -382,23 +449,37 @@ func (s *Select) prepareTemplates() error { return nil } -// SelectWithAdd represents a list for selecting a single item, or selecting -// a newly created item. +// SelectWithAdd represents a list for selecting a single item inside a list of items with the possibility to +// add new items to the list. type SelectWithAdd struct { - Label string // Label is the value displayed on the command line prompt. - Items []string // Items are the items to use in the list. + // Label is the text displayed on top of the list to direct input. The IconInitial value "?" will be + // appended automatically to the label so it does not need to be added. + Label string - AddLabel string // The label used in the item list for creating a new item. + // Items are the items to display inside the list. Each item will be listed individually with the + // AddLabel as the first item of the list. + Items []string - // Validate is optional. If set, this function is used to validate the input - // after each character entry. + // AddLabel is the label used for the first item of the list that enables adding a new item. + // Selecting this item in the list displays the add item prompt using promptui/prompt. + AddLabel string + + // Validate is an optional function that fill be used against the entered value in the prompt to validate it. + // If the value is valid, it is returned to the callee to be added in the list. Validate ValidateFunc - IsVimMode bool // Whether readline is using Vim mode. + // IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at + // https://godoc.org/github.com/chzyer/readline#Config for more information on readline. + IsVimMode bool } -// Run runs the Select list. It returns the index of the selected element, -// and its value. If a new element is created, -1 is returned as the index. +// Run executes the select list. Its displays the label and the list of items, asking the user to chose any +// value within to list or add his own. Run will keep the prompt alive until it has been canceled from +// the command prompt or it has received a valid value. +// +// If the addLabel is selected in the list, this function will return a -1 index with the added label and no error. +// Otherwise, it will return the index and the value of the selected item. In any case, if an error is triggered, it +// will also return the error as its third return value. func (sa *SelectWithAdd) Run() (int, string, error) { if len(sa.Items) > 0 { newItems := append([]string{sa.AddLabel}, sa.Items...) @@ -445,10 +526,10 @@ func (s *Select) setKeys() { return } s.Keys = &SelectKeys{ - Prev: Key{Code: KeyPrev, Display: "↑"}, - Next: Key{Code: KeyNext, Display: "↓"}, - PageUp: Key{Code: KeyBackward, Display: "←"}, - PageDown: Key{Code: KeyForward, Display: "→"}, + Prev: Key{Code: KeyPrev, Display: KeyPrevDisplay}, + Next: Key{Code: KeyNext, Display: KeyNextDisplay}, + PageUp: Key{Code: KeyBackward, Display: KeyBackwardDisplay}, + PageDown: Key{Code: KeyForward, Display: KeyForwardDisplay}, Search: Key{Code: '/', Display: "/"}, } } diff --git a/vendor/github.com/manifoldco/promptui/styles.go b/vendor/github.com/manifoldco/promptui/styles.go index 7decdd8..d7698c9 100644 --- a/vendor/github.com/manifoldco/promptui/styles.go +++ b/vendor/github.com/manifoldco/promptui/styles.go @@ -2,11 +2,22 @@ package promptui -// Icons used for displaying prompts or status +// These are the default icons used by promptui for select and prompts. These should not be overridden and instead +// customized through the use of custom templates var ( + // IconInitial is the icon used when starting in prompt mode and the icon next to the label when + // starting in select mode. IconInitial = Styler(FGBlue)("?") - IconGood = Styler(FGGreen)("✔") - IconWarn = Styler(FGYellow)("⚠") - IconBad = Styler(FGRed)("✗") - IconSelect = Styler(FGBold)("▸") + + // IconGood is the icon used when a good answer is entered in prompt mode. + IconGood = Styler(FGGreen)("✔") + + // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode. + IconWarn = Styler(FGYellow)("⚠") + + // IconBad is the icon used when a bad answer is entered in prompt mode. + IconBad = Styler(FGRed)("✗") + + // IconSelect is the icon used to identify the currently selected item in select mode. + IconSelect = Styler(FGBold)("▸") ) diff --git a/vendor/github.com/manifoldco/promptui/styles_windows.go b/vendor/github.com/manifoldco/promptui/styles_windows.go index d48dfdd..36de268 100644 --- a/vendor/github.com/manifoldco/promptui/styles_windows.go +++ b/vendor/github.com/manifoldco/promptui/styles_windows.go @@ -1,10 +1,21 @@ package promptui -// Icons used for displaying prompts or status +// These are the default icons used bu promptui for select and prompts. They can either be overridden directly +// from these variable or customized through the use of custom templates var ( + // IconInitial is the icon used when starting in prompt mode and the icon next to the label when + // starting in select mode. IconInitial = Styler(FGBlue)("?") - IconGood = Styler(FGGreen)("v") - IconWarn = Styler(FGYellow)("!") - IconBad = Styler(FGRed)("x") - IconSelect = Styler(FGBold)(">") + + // IconGood is the icon used when a good answer is entered in prompt mode. + IconGood = Styler(FGGreen)("v") + + // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode. + IconWarn = Styler(FGYellow)("!") + + // IconBad is the icon used when a bad answer is entered in prompt mode. + IconBad = Styler(FGRed)("x") + + // IconSelect is the icon used to identify the currently selected item in select mode. + IconSelect = Styler(FGBold)(">") ) diff --git a/vendor/github.com/mattn/go-colorable/cmd/colorable/colorable.go b/vendor/github.com/mattn/go-colorable/cmd/colorable/colorable.go deleted file mode 100644 index 8790477..0000000 --- a/vendor/github.com/mattn/go-colorable/cmd/colorable/colorable.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "io" - "os" - - "github.com/mattn/go-colorable" -) - -func main() { - io.Copy(colorable.NewColorableStdout(), os.Stdin) -} diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 404e10c..e17a547 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -29,15 +29,6 @@ const ( backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) ) -const ( - genericRead = 0x80000000 - genericWrite = 0x40000000 -) - -const ( - consoleTextmodeBuffer = 0x1 -) - type wchar uint16 type short int16 type dword uint32 @@ -78,17 +69,14 @@ var ( procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW") - procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer") ) // Writer provide colorable Writer to the console type Writer struct { - out io.Writer - handle syscall.Handle - althandle syscall.Handle - oldattr word - oldpos coord - rest bytes.Buffer + out io.Writer + handle syscall.Handle + oldattr word + oldpos coord } // NewColorable return new instance of Writer which handle escape sequence from File. @@ -419,18 +407,7 @@ func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - handle := w.handle - - var er *bytes.Reader - if w.rest.Len() > 0 { - var rest bytes.Buffer - w.rest.WriteTo(&rest) - w.rest.Reset() - rest.Write(data) - er = bytes.NewReader(rest.Bytes()) - } else { - er = bytes.NewReader(data) - } + er := bytes.NewReader(data) var bw [1]byte loop: for { @@ -448,55 +425,29 @@ loop: break loop } - switch c2 { - case '>': - continue - case ']': - w.rest.WriteByte(c1) - w.rest.WriteByte(c2) - er.WriteTo(&w.rest) - if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 { + if c2 == ']' { + if err := doTitleSequence(er); err != nil { break loop } - er = bytes.NewReader(w.rest.Bytes()[2:]) - err := doTitleSequence(er) - if err != nil { - break loop - } - w.rest.Reset() continue - // https://github.com/mattn/go-colorable/issues/27 - case '7': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - w.oldpos = csbi.cursorPosition - continue - case '8': - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) - continue - case 0x5b: - // execute part after switch - default: + } + if c2 != 0x5b { continue } - w.rest.WriteByte(c1) - w.rest.WriteByte(c2) - er.WriteTo(&w.rest) - var buf bytes.Buffer var m byte - for i, c := range w.rest.Bytes()[2:] { + for { + c, err := er.ReadByte() + if err != nil { + break loop + } if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { m = c - er = bytes.NewReader(w.rest.Bytes()[2+i+1:]) - w.rest.Reset() break } buf.Write([]byte(string(c))) } - if m == 0 { - break loop - } switch m { case 'A': @@ -504,64 +455,61 @@ loop: if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'B': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'C': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'D': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x -= short(n) - if csbi.cursorPosition.x < 0 { - csbi.cursorPosition.x = 0 - } - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'E': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'F': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'G': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = short(n - 1) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'H', 'f': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) if buf.Len() > 0 { token := strings.Split(buf.String(), ";") switch len(token) { @@ -586,7 +534,7 @@ loop: } else { csbi.cursorPosition.y = 0 } - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'J': n := 0 if buf.Len() > 0 { @@ -597,20 +545,20 @@ loop: } var count, written dword var cursor coord - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x) + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x) case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top} - count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'K': n := 0 if buf.Len() > 0 { @@ -619,28 +567,28 @@ loop: continue } } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord var count, written dword switch n { case 0: - cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - count = dword(csbi.size.x - csbi.cursorPosition.x) + cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x - 1) case 1: - cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} count = dword(csbi.size.x - csbi.cursorPosition.x) case 2: - cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} count = dword(csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'm': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) attr := csbi.attributes cs := buf.String() if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr)) + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) continue } token := strings.Split(cs, ";") @@ -679,21 +627,6 @@ loop: attr |= n256foreAttr[n256] i += 2 } - } else if len(token) == 5 && token[i+1] == "2" { - var r, g, b int - r, _ = strconv.Atoi(token[i+2]) - g, _ = strconv.Atoi(token[i+3]) - b, _ = strconv.Atoi(token[i+4]) - i += 4 - if r > 127 { - attr |= foregroundRed - } - if g > 127 { - attr |= foregroundGreen - } - if b > 127 { - attr |= foregroundBlue - } } else { attr = attr & (w.oldattr & backgroundMask) } @@ -721,21 +654,6 @@ loop: attr |= n256backAttr[n256] i += 2 } - } else if len(token) == 5 && token[i+1] == "2" { - var r, g, b int - r, _ = strconv.Atoi(token[i+2]) - g, _ = strconv.Atoi(token[i+3]) - b, _ = strconv.Atoi(token[i+4]) - i += 4 - if r > 127 { - attr |= backgroundRed - } - if g > 127 { - attr |= backgroundGreen - } - if b > 127 { - attr |= backgroundBlue - } } else { attr = attr & (w.oldattr & foregroundMask) } @@ -767,52 +685,38 @@ loop: attr |= backgroundBlue } } - procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr)) + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) } } case 'h': var ci consoleCursorInfo cs := buf.String() if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) - } else if cs == "?1049" { - if w.althandle == 0 { - h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) - w.althandle = syscall.Handle(h) - if w.althandle != 0 { - handle = w.althandle - } - } + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) } case 'l': var ci consoleCursorInfo cs := buf.String() if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) - } else if cs == "?1049" { - if w.althandle != 0 { - syscall.CloseHandle(w.althandle) - w.althandle = 0 - handle = w.handle - } + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) } case 's': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) w.oldpos = csbi.cursorPosition case 'u': - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) } } diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix_test.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix_test.go deleted file mode 100644 index 4bf7c25..0000000 --- a/vendor/github.com/mattn/go-runewidth/runewidth_posix_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// +build !windows,!js - -package runewidth - -import ( - "os" - "testing" -) - -func TestIsEastAsian(t *testing.T) { - testcases := []struct { - locale string - want bool - }{ - {"foo@cjk_narrow", false}, - {"foo@cjk", false}, - {"utf-8@cjk", false}, - {"ja_JP.CP932", true}, - } - - for _, tt := range testcases { - got := isEastAsian(tt.locale) - if got != tt.want { - t.Fatalf("isEastAsian(%q) should be %v", tt.locale, tt.want) - } - } -} - -func TestIsEastAsianLCCTYPE(t *testing.T) { - lcctype := os.Getenv("LC_CTYPE") - defer os.Setenv("LC_CTYPE", lcctype) - - testcases := []struct { - lcctype string - want bool - }{ - {"ja_JP.UTF-8", true}, - {"C", false}, - {"POSIX", false}, - {"en_US.UTF-8", false}, - } - - for _, tt := range testcases { - os.Setenv("LC_CTYPE", tt.lcctype) - got := IsEastAsian() - if got != tt.want { - t.Fatalf("IsEastAsian() for LC_CTYPE=%v should be %v", tt.lcctype, tt.want) - } - } -} - -func TestIsEastAsianLANG(t *testing.T) { - lcctype := os.Getenv("LC_CTYPE") - defer os.Setenv("LC_CTYPE", lcctype) - lang := os.Getenv("LANG") - defer os.Setenv("LANG", lang) - - os.Setenv("LC_CTYPE", "") - - testcases := []struct { - lcctype string - want bool - }{ - {"ja_JP.UTF-8", true}, - {"C", false}, - {"POSIX", false}, - {"en_US.UTF-8", false}, - {"C.UTF-8", false}, - } - - for _, tt := range testcases { - os.Setenv("LANG", tt.lcctype) - got := IsEastAsian() - if got != tt.want { - t.Fatalf("IsEastAsian() for LANG=%v should be %v", tt.lcctype, tt.want) - } - } -} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_test.go b/vendor/github.com/mattn/go-runewidth/runewidth_test.go deleted file mode 100644 index e9edf6a..0000000 --- a/vendor/github.com/mattn/go-runewidth/runewidth_test.go +++ /dev/null @@ -1,297 +0,0 @@ -// +build !windows,!js - -package runewidth - -import ( - "os" - "sort" - "testing" -) - -var _ sort.Interface = (*table)(nil) - -func init() { - os.Setenv("RUNEWIDTH_EASTASIAN", "") -} - -func (t table) Len() int { - return len(t) -} - -func (t table) Less(i, j int) bool { - return t[i].first < t[j].first -} - -func (t *table) Swap(i, j int) { - (*t)[i], (*t)[j] = (*t)[j], (*t)[i] -} - -var tables = []table{ - private, - nonprint, - combining, - doublewidth, - ambiguous, - emoji, - notassigned, - neutral, -} - -func TestSorted(t *testing.T) { - for _, tbl := range tables { - if !sort.IsSorted(&tbl) { - t.Errorf("not sorted") - } - } -} - -var runewidthtests = []struct { - in rune - out int - eaout int -}{ - {'世', 2, 2}, - {'界', 2, 2}, - {'セ', 1, 1}, - {'カ', 1, 1}, - {'イ', 1, 1}, - {'☆', 1, 2}, // double width in ambiguous - {'\x00', 0, 0}, - {'\x01', 0, 0}, - {'\u0300', 0, 0}, - {'\u2028', 0, 0}, - {'\u2029', 0, 0}, -} - -func TestRuneWidth(t *testing.T) { - c := NewCondition() - c.EastAsianWidth = false - for _, tt := range runewidthtests { - if out := c.RuneWidth(tt.in); out != tt.out { - t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.out) - } - } - c.EastAsianWidth = true - for _, tt := range runewidthtests { - if out := c.RuneWidth(tt.in); out != tt.eaout { - t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.eaout) - } - } -} - -var isambiguouswidthtests = []struct { - in rune - out bool -}{ - {'世', false}, - {'■', true}, - {'界', false}, - {'○', true}, - {'㈱', false}, - {'①', true}, - {'②', true}, - {'③', true}, - {'④', true}, - {'⑤', true}, - {'⑥', true}, - {'⑦', true}, - {'⑧', true}, - {'⑨', true}, - {'⑩', true}, - {'⑪', true}, - {'⑫', true}, - {'⑬', true}, - {'⑭', true}, - {'⑮', true}, - {'⑯', true}, - {'⑰', true}, - {'⑱', true}, - {'⑲', true}, - {'⑳', true}, - {'☆', true}, -} - -func TestIsAmbiguousWidth(t *testing.T) { - for _, tt := range isambiguouswidthtests { - if out := IsAmbiguousWidth(tt.in); out != tt.out { - t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out) - } - } -} - -var stringwidthtests = []struct { - in string - out int - eaout int -}{ - {"■㈱の世界①", 10, 12}, - {"スター☆", 7, 8}, - {"つのだ☆HIRO", 11, 12}, -} - -func TestStringWidth(t *testing.T) { - c := NewCondition() - c.EastAsianWidth = false - for _, tt := range stringwidthtests { - if out := c.StringWidth(tt.in); out != tt.out { - t.Errorf("StringWidth(%q) = %d, want %d", tt.in, out, tt.out) - } - } - c.EastAsianWidth = true - for _, tt := range stringwidthtests { - if out := c.StringWidth(tt.in); out != tt.eaout { - t.Errorf("StringWidth(%q) = %d, want %d", tt.in, out, tt.eaout) - } - } -} - -func TestStringWidthInvalid(t *testing.T) { - s := "こんにちわ\x00世界" - if out := StringWidth(s); out != 14 { - t.Errorf("StringWidth(%q) = %d, want %d", s, out, 14) - } -} - -func TestTruncateSmaller(t *testing.T) { - s := "あいうえお" - expected := "あいうえお" - - if out := Truncate(s, 10, "..."); out != expected { - t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) - } -} - -func TestTruncate(t *testing.T) { - s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" - expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." - out := Truncate(s, 80, "...") - if out != expected { - t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) - } - width := StringWidth(out) - if width != 79 { - t.Errorf("width of Truncate(%q) should be %d, but %d", s, 79, width) - } -} - -func TestTruncateFit(t *testing.T) { - s := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" - expected := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." - - out := Truncate(s, 80, "...") - if out != expected { - t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) - } - width := StringWidth(out) - if width != 80 { - t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) - } -} - -func TestTruncateJustFit(t *testing.T) { - s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" - expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" - - out := Truncate(s, 80, "...") - if out != expected { - t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) - } - width := StringWidth(out) - if width != 80 { - t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) - } -} - -func TestWrap(t *testing.T) { - s := `東京特許許可局局長はよく柿喰う客だ/東京特許許可局局長はよく柿喰う客だ -123456789012345678901234567890 - -END` - expected := `東京特許許可局局長はよく柿喰う -客だ/東京特許許可局局長はよく -柿喰う客だ -123456789012345678901234567890 - -END` - - if out := Wrap(s, 30); out != expected { - t.Errorf("Wrap(%q) = %q, want %q", s, out, expected) - } -} - -func TestTruncateNoNeeded(t *testing.T) { - s := "あいうえおあい" - expected := "あいうえおあい" - - if out := Truncate(s, 80, "..."); out != expected { - t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) - } -} - -var isneutralwidthtests = []struct { - in rune - out bool -}{ - {'→', false}, - {'┊', false}, - {'┈', false}, - {'~', false}, - {'└', false}, - {'⣀', true}, - {'⣀', true}, -} - -func TestIsNeutralWidth(t *testing.T) { - for _, tt := range isneutralwidthtests { - if out := IsNeutralWidth(tt.in); out != tt.out { - t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out) - } - } -} - -func TestFillLeft(t *testing.T) { - s := "あxいうえお" - expected := " あxいうえお" - - if out := FillLeft(s, 15); out != expected { - t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) - } -} - -func TestFillLeftFit(t *testing.T) { - s := "あいうえお" - expected := "あいうえお" - - if out := FillLeft(s, 10); out != expected { - t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) - } -} - -func TestFillRight(t *testing.T) { - s := "あxいうえお" - expected := "あxいうえお " - - if out := FillRight(s, 15); out != expected { - t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) - } -} - -func TestFillRightFit(t *testing.T) { - s := "あいうえお" - expected := "あいうえお" - - if out := FillRight(s, 10); out != expected { - t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) - } -} - -func TestEnv(t *testing.T) { - old := os.Getenv("RUNEWIDTH_EASTASIAN") - defer os.Setenv("RUNEWIDTH_EASTASIAN", old) - - os.Setenv("RUNEWIDTH_EASTASIAN", "1") - - if w := RuneWidth('│'); w != 1 { - t.Errorf("RuneWidth('│') = %d, want %d", w, 1) - } -} diff --git a/vendor/github.com/mattn/go-shellwords/shellwords.go b/vendor/github.com/mattn/go-shellwords/shellwords.go index 96feca7..1078039 100644 --- a/vendor/github.com/mattn/go-shellwords/shellwords.go +++ b/vendor/github.com/mattn/go-shellwords/shellwords.go @@ -44,7 +44,7 @@ func NewParser() *Parser { func (p *Parser) Parse(line string) ([]string, error) { args := []string{} buf := "" - var escaped, doubleQuoted, singleQuoted, backQuote, dollarQuote bool + var escaped, doubleQuoted, singleQuoted, backQuote bool backtick := "" pos := -1 @@ -68,7 +68,7 @@ loop: } if isSpace(r) { - if singleQuoted || doubleQuoted || backQuote || dollarQuote { + if singleQuoted || doubleQuoted || backQuote { buf += string(r) backtick += string(r) } else if got { @@ -84,7 +84,7 @@ loop: switch r { case '`': - if !singleQuoted && !doubleQuoted && !dollarQuote { + if !singleQuoted && !doubleQuoted { if p.ParseBacktick { if backQuote { out, err := shellRun(backtick) @@ -100,51 +100,18 @@ loop: backtick = "" backQuote = !backQuote } - case ')': - if !singleQuoted && !doubleQuoted && !backQuote { - if p.ParseBacktick { - if dollarQuote { - out, err := shellRun(backtick) - if err != nil { - return nil, err - } - buf = out - } - backtick = "" - dollarQuote = !dollarQuote - continue - } - backtick = "" - dollarQuote = !dollarQuote - } - case '(': - if !singleQuoted && !doubleQuoted && !backQuote { - if !dollarQuote && len(buf) > 0 && buf == "$" { - dollarQuote = true - buf += "(" - continue - } else { - return nil, errors.New("invalid command line string") - } - } case '"': - if !singleQuoted && !dollarQuote { + if !singleQuoted { doubleQuoted = !doubleQuoted continue } case '\'': - if !doubleQuoted && !dollarQuote { + if !doubleQuoted { singleQuoted = !singleQuoted continue } case ';', '&', '|', '<', '>': if !(escaped || singleQuoted || doubleQuoted || backQuote) { - if r == '>' { - if c := buf[0]; '0' <= c && c <= '9' { - i -= 1 - got = false - } - } pos = i break loop } @@ -152,7 +119,7 @@ loop: got = true buf += string(r) - if backQuote || dollarQuote { + if backQuote { backtick += string(r) } } @@ -164,7 +131,7 @@ loop: args = append(args, buf) } - if escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote { + if escaped || singleQuoted || doubleQuoted || backQuote { return nil, errors.New("invalid command line string") } diff --git a/vendor/github.com/mattn/go-shellwords/util_go15.go b/vendor/github.com/mattn/go-shellwords/util_go15.go deleted file mode 100644 index 180f00f..0000000 --- a/vendor/github.com/mattn/go-shellwords/util_go15.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build !go1.6 - -package shellwords - -import ( - "os" - "os/exec" - "runtime" - "strings" -) - -func shellRun(line string) (string, error) { - var b []byte - var err error - if runtime.GOOS == "windows" { - b, err = exec.Command(os.Getenv("COMSPEC"), "/c", line).Output() - } else { - b, err = exec.Command(os.Getenv("SHELL"), "-c", line).Output() - } - if err != nil { - return "", err - } - return strings.TrimSpace(string(b)), nil -} diff --git a/vendor/github.com/mattn/go-shellwords/util_posix.go b/vendor/github.com/mattn/go-shellwords/util_posix.go index eaf1011..4f8ac55 100644 --- a/vendor/github.com/mattn/go-shellwords/util_posix.go +++ b/vendor/github.com/mattn/go-shellwords/util_posix.go @@ -1,4 +1,4 @@ -// +build !windows,go1.6 +// +build !windows package shellwords @@ -13,9 +13,6 @@ func shellRun(line string) (string, error) { shell := os.Getenv("SHELL") b, err := exec.Command(shell, "-c", line).Output() if err != nil { - if eerr, ok := err.(*exec.ExitError); ok { - b = eerr.Stderr - } return "", errors.New(err.Error() + ":" + string(b)) } return strings.TrimSpace(string(b)), nil diff --git a/vendor/github.com/mattn/go-shellwords/util_windows.go b/vendor/github.com/mattn/go-shellwords/util_windows.go index e46f89a..7cad4cf 100644 --- a/vendor/github.com/mattn/go-shellwords/util_windows.go +++ b/vendor/github.com/mattn/go-shellwords/util_windows.go @@ -1,5 +1,3 @@ -// +build windows,go1.6 - package shellwords import ( @@ -13,9 +11,6 @@ func shellRun(line string) (string, error) { shell := os.Getenv("COMSPEC") b, err := exec.Command(shell, "/c", line).Output() if err != nil { - if eerr, ok := err.(*exec.ExitError); ok { - b = eerr.Stderr - } return "", errors.New(err.Error() + ":" + string(b)) } return strings.TrimSpace(string(b)), nil diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go index 47e1f9e..fb87bef 100644 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -77,33 +77,51 @@ func Expand(path string) (string, error) { } func dirUnix() (string, error) { + homeEnv := "HOME" + if runtime.GOOS == "plan9" { + // On plan9, env vars are lowercase. + homeEnv = "home" + } + // First prefer the HOME environmental variable - if home := os.Getenv("HOME"); home != "" { + if home := os.Getenv(homeEnv); home != "" { return home, nil } - // If that fails, try getent var stdout bytes.Buffer - cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - // If the error is ErrNotFound, we ignore it. Otherwise, return it. - if err != exec.ErrNotFound { - return "", err + + // If that fails, try OS specific commands + if runtime.GOOS == "darwin" { + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + result := strings.TrimSpace(stdout.String()) + if result != "" { + return result, nil + } } } else { - if passwd := strings.TrimSpace(stdout.String()); passwd != "" { - // username:password:uid:gid:gecos:home:shell - passwdParts := strings.SplitN(passwd, ":", 7) - if len(passwdParts) > 5 { - return passwdParts[5], nil + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + // If the error is ErrNotFound, we ignore it. Otherwise, return it. + if err != exec.ErrNotFound { + return "", err + } + } else { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + return passwdParts[5], nil + } } } } // If all else fails, try the shell stdout.Reset() - cmd = exec.Command("sh", "-c", "cd && pwd") + cmd := exec.Command("sh", "-c", "cd && pwd") cmd.Stdout = &stdout if err := cmd.Run(); err != nil { return "", err @@ -123,14 +141,16 @@ func dirWindows() (string, error) { return home, nil } + // Prefer standard environment variable USERPROFILE + if home := os.Getenv("USERPROFILE"); home != "" { + return home, nil + } + drive := os.Getenv("HOMEDRIVE") path := os.Getenv("HOMEPATH") home := drive + path if drive == "" || path == "" { - home = os.Getenv("USERPROFILE") - } - if home == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") + return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") } return home, nil diff --git a/vendor/github.com/olekukonko/tablewriter/README.md b/vendor/github.com/olekukonko/tablewriter/README.md index 59cb86c..d44d31a 100644 --- a/vendor/github.com/olekukonko/tablewriter/README.md +++ b/vendor/github.com/olekukonko/tablewriter/README.md @@ -115,7 +115,7 @@ table.SetRowLine(true) // Enable row line // Change table lines table.SetCenterSeparator("*") -table.SetColumnSeparator("‡") +table.SetColumnSeparator("╪") table.SetRowSeparator("-") table.SetAlignment(tablewriter.ALIGN_LEFT) diff --git a/vendor/github.com/olekukonko/tablewriter/csv2table/README.md b/vendor/github.com/olekukonko/tablewriter/csv2table/README.md deleted file mode 100644 index 6cf5628..0000000 --- a/vendor/github.com/olekukonko/tablewriter/csv2table/README.md +++ /dev/null @@ -1,43 +0,0 @@ -ASCII Table Writer Tool -========= - -Generate ASCII table on the fly via command line ... Installation is simple as - -#### Get Tool - - go get github.com/olekukonko/tablewriter/csv2table - -#### Install Tool - - go install github.com/olekukonko/tablewriter/csv2table - - -#### Usage - - csv2table -f test.csv - -#### Support for Piping - - cat test.csv | csv2table -p=true - -#### Output - -``` -+------------+-----------+---------+ -| FIRST NAME | LAST NAME | SSN | -+------------+-----------+---------+ -| John | Barry | 123456 | -| Kathy | Smith | 687987 | -| Bob | McCornick | 3979870 | -+------------+-----------+---------+ -``` - -#### Another Piping with Header set to `false` - - echo dance,with,me | csv2table -p=true -h=false - -#### Output - - +-------+------+-----+ - | dance | with | me | - +-------+------+-----+ diff --git a/vendor/github.com/olekukonko/tablewriter/csv2table/csv2table.go b/vendor/github.com/olekukonko/tablewriter/csv2table/csv2table.go deleted file mode 100644 index 5e1d7f2..0000000 --- a/vendor/github.com/olekukonko/tablewriter/csv2table/csv2table.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "encoding/csv" - "flag" - "fmt" - "io" - "os" - "unicode/utf8" - - "github.com/olekukonko/tablewriter" -) - -var ( - fileName = flag.String("f", "", "Set file with eg. sample.csv") - delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ") - header = flag.Bool("h", true, "Set header options eg. true|false ") - align = flag.String("a", "none", "Set aligmement with eg. none|left|right|center") - pipe = flag.Bool("p", false, "Suport for Piping from STDIN") - border = flag.Bool("b", true, "Enable / disable table border") -) - -func main() { - flag.Parse() - fmt.Println() - if *pipe || hasArg("-p") { - process(os.Stdin) - } else { - if *fileName == "" { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - flag.PrintDefaults() - fmt.Println() - os.Exit(1) - } - processFile() - } - fmt.Println() -} - -func hasArg(name string) bool { - for _, v := range os.Args { - if name == v { - return true - } - } - return false -} -func processFile() { - r, err := os.Open(*fileName) - if err != nil { - exit(err) - } - defer r.Close() - process(r) -} -func process(r io.Reader) { - csvReader := csv.NewReader(r) - rune, size := utf8.DecodeRuneInString(*delimiter) - if size == 0 { - rune = ',' - } - csvReader.Comma = rune - - table, err := tablewriter.NewCSVReader(os.Stdout, csvReader, *header) - - if err != nil { - exit(err) - } - - switch *align { - case "left": - table.SetAlignment(tablewriter.ALIGN_LEFT) - case "right": - table.SetAlignment(tablewriter.ALIGN_RIGHT) - case "center": - table.SetAlignment(tablewriter.ALIGN_CENTER) - } - table.SetBorder(*border) - table.Render() -} - -func exit(err error) { - fmt.Fprintf(os.Stderr, "#Error : %s", err) - os.Exit(1) -} diff --git a/vendor/github.com/olekukonko/tablewriter/table_test.go b/vendor/github.com/olekukonko/tablewriter/table_test.go deleted file mode 100644 index 39fdb3c..0000000 --- a/vendor/github.com/olekukonko/tablewriter/table_test.go +++ /dev/null @@ -1,1055 +0,0 @@ -// Copyright 2014 Oleku Konko All rights reserved. -// Use of this source code is governed by a MIT -// license that can be found in the LICENSE file. - -// This module is a Table Writer API for the Go Programming Language. -// The protocols were written in pure Go and works on windows and unix systems - -package tablewriter - -import ( - "bytes" - "fmt" - "io" - "os" - "reflect" - "strings" - "testing" -) - -func checkEqual(t *testing.T, got, want interface{}, msgs ...interface{}) { - if !reflect.DeepEqual(got, want) { - buf := bytes.Buffer{} - buf.WriteString("got:\n[%v]\nwant:\n[%v]\n") - for _, v := range msgs { - buf.WriteString(v.(string)) - } - t.Errorf(buf.String(), got, want) - } -} - -func ExampleShort() { - data := [][]string{ - {"A", "The Good", "500"}, - {"B", "The Very very Bad Man", "288"}, - {"C", "The Ugly", "120"}, - {"D", "The Gopher", "800"}, - } - - table := NewWriter(os.Stdout) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - for _, v := range data { - table.Append(v) - } - table.Render() - - // Output: +------+-----------------------+--------+ - // | NAME | SIGN | RATING | - // +------+-----------------------+--------+ - // | A | The Good | 500 | - // | B | The Very very Bad Man | 288 | - // | C | The Ugly | 120 | - // | D | The Gopher | 800 | - // +------+-----------------------+--------+ -} - -func ExampleLong() { - data := [][]string{ - {"Learn East has computers with adapted keyboards with enlarged print etc", " Some Data ", " Another Data"}, - {"Instead of lining up the letters all ", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards", "See Data"}, - } - - table := NewWriter(os.Stdout) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - table.SetCenterSeparator("*") - table.SetRowSeparator("=") - - for _, v := range data { - table.Append(v) - } - table.Render() - - // Output: *================================*================================*===============================*==========* - // | NAME | SIGN | RATING | | - // *================================*================================*===============================*==========* - // | Learn East has computers | Some Data | Another Data | - // | with adapted keyboards with | | | - // | enlarged print etc | | | - // | Instead of lining up the | the way across, he splits the | Like most ergonomic keyboards | See Data | - // | letters all | keyboard in two | | | - // *================================*================================*===============================*==========* -} - -func ExampleCSV() { - table, _ := NewCSV(os.Stdout, "testdata/test.csv", true) - table.SetCenterSeparator("*") - table.SetRowSeparator("=") - - table.Render() - - // Output: *============*===========*=========* - // | FIRST NAME | LAST NAME | SSN | - // *============*===========*=========* - // | John | Barry | 123456 | - // | Kathy | Smith | 687987 | - // | Bob | McCornick | 3979870 | - // *============*===========*=========* -} - -// TestNumLines to test the numbers of lines -func TestNumLines(t *testing.T) { - data := [][]string{ - {"A", "The Good", "500"}, - {"B", "The Very very Bad Man", "288"}, - {"C", "The Ugly", "120"}, - {"D", "The Gopher", "800"}, - } - - buf := &bytes.Buffer{} - table := NewWriter(buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - for i, v := range data { - table.Append(v) - checkEqual(t, table.NumLines(), i+1, "Number of lines failed") - } - - checkEqual(t, table.NumLines(), len(data), "Number of lines failed") -} - -func TestCSVInfo(t *testing.T) { - buf := &bytes.Buffer{} - table, err := NewCSV(buf, "testdata/test_info.csv", true) - if err != nil { - t.Error(err) - return - } - table.SetAlignment(ALIGN_LEFT) - table.SetBorder(false) - table.Render() - - got := buf.String() - want := ` FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA -+----------+--------------+------+-----+---------+----------------+ - user_id | smallint(5) | NO | PRI | NULL | auto_increment - username | varchar(10) | NO | | NULL | - password | varchar(100) | NO | | NULL | -` - checkEqual(t, got, want, "CSV info failed") -} - -func TestCSVSeparator(t *testing.T) { - buf := &bytes.Buffer{} - table, err := NewCSV(buf, "testdata/test.csv", true) - if err != nil { - t.Error(err) - return - } - table.SetRowLine(true) - table.SetCenterSeparator("+") - table.SetColumnSeparator("|") - table.SetRowSeparator("-") - table.SetAlignment(ALIGN_LEFT) - table.Render() - - want := `+------------+-----------+---------+ -| FIRST NAME | LAST NAME | SSN | -+------------+-----------+---------+ -| John | Barry | 123456 | -+------------+-----------+---------+ -| Kathy | Smith | 687987 | -+------------+-----------+---------+ -| Bob | McCornick | 3979870 | -+------------+-----------+---------+ -` - - checkEqual(t, buf.String(), want, "CSV info failed") -} - -func TestNoBorder(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - {"1/1/2014", "January Hosting", "2233", "$54.95"}, - {"", " (empty)\n (empty)", "", ""}, - {"1/4/2014", "February Hosting", "2233", "$51.00"}, - {"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, - {"1/4/2014", " (Discount)", "2233", "-$1.00"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetAutoWrapText(false) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer - table.SetBorder(false) // Set Border to false - table.AppendBulk(data) // Add Bulk Data - table.Render() - - want := ` DATE | DESCRIPTION | CV2 | AMOUNT -+----------+--------------------------+-------+---------+ - 1/1/2014 | Domain name | 2233 | $10.98 - 1/1/2014 | January Hosting | 2233 | $54.95 - | (empty) | | - | (empty) | | - 1/4/2014 | February Hosting | 2233 | $51.00 - 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 - 1/4/2014 | (Discount) | 2233 | -$1.00 -+----------+--------------------------+-------+---------+ - TOTAL | $145 93 - +-------+---------+ -` - - checkEqual(t, buf.String(), want, "border table rendering failed") -} - -func TestWithBorder(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - {"1/1/2014", "January Hosting", "2233", "$54.95"}, - {"", " (empty)\n (empty)", "", ""}, - {"1/4/2014", "February Hosting", "2233", "$51.00"}, - {"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, - {"1/4/2014", " (Discount)", "2233", "-$1.00"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetAutoWrapText(false) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer - table.AppendBulk(data) // Add Bulk Data - table.Render() - - want := `+----------+--------------------------+-------+---------+ -| DATE | DESCRIPTION | CV2 | AMOUNT | -+----------+--------------------------+-------+---------+ -| 1/1/2014 | Domain name | 2233 | $10.98 | -| 1/1/2014 | January Hosting | 2233 | $54.95 | -| | (empty) | | | -| | (empty) | | | -| 1/4/2014 | February Hosting | 2233 | $51.00 | -| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 | -| 1/4/2014 | (Discount) | 2233 | -$1.00 | -+----------+--------------------------+-------+---------+ -| TOTAL | $145 93 | -+----------+--------------------------+-------+---------+ -` - - checkEqual(t, buf.String(), want, "border table rendering failed") -} - -func TestPrintingInMarkdown(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - {"1/1/2014", "January Hosting", "2233", "$54.95"}, - {"1/4/2014", "February Hosting", "2233", "$51.00"}, - {"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.AppendBulk(data) // Add Bulk Data - table.SetBorders(Border{Left: true, Top: false, Right: true, Bottom: false}) - table.SetCenterSeparator("|") - table.Render() - - want := `| DATE | DESCRIPTION | CV2 | AMOUNT | -|----------|--------------------------|------|--------| -| 1/1/2014 | Domain name | 2233 | $10.98 | -| 1/1/2014 | January Hosting | 2233 | $54.95 | -| 1/4/2014 | February Hosting | 2233 | $51.00 | -| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 | -` - checkEqual(t, buf.String(), want, "border table rendering failed") -} - -func TestPrintHeading(t *testing.T) { - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.printHeading() - want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | -+---+---+---+---+---+---+---+---+---+---+---+---+ -` - checkEqual(t, buf.String(), want, "header rendering failed") -} - -func TestPrintHeadingWithoutAutoFormat(t *testing.T) { - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.SetAutoFormatHeaders(false) - table.printHeading() - want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | -+---+---+---+---+---+---+---+---+---+---+---+---+ -` - checkEqual(t, buf.String(), want, "header rendering failed") -} - -func TestPrintFooter(t *testing.T) { - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.printFooter() - want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | -+---+---+---+---+---+---+---+---+---+---+---+---+ -` - checkEqual(t, buf.String(), want, "footer rendering failed") -} - -func TestPrintFooterWithoutAutoFormat(t *testing.T) { - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetAutoFormatHeaders(false) - table.SetHeader([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.SetFooter([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c"}) - table.printFooter() - want := `| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | -+---+---+---+---+---+---+---+---+---+---+---+---+ -` - checkEqual(t, buf.String(), want, "footer rendering failed") -} - -func TestPrintShortCaption(t *testing.T) { - var buf bytes.Buffer - data := [][]string{ - {"A", "The Good", "500"}, - {"B", "The Very very Bad Man", "288"}, - {"C", "The Ugly", "120"}, - {"D", "The Gopher", "800"}, - } - - table := NewWriter(&buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - table.SetCaption(true, "Short caption.") - - for _, v := range data { - table.Append(v) - } - table.Render() - - want := `+------+-----------------------+--------+ -| NAME | SIGN | RATING | -+------+-----------------------+--------+ -| A | The Good | 500 | -| B | The Very very Bad Man | 288 | -| C | The Ugly | 120 | -| D | The Gopher | 800 | -+------+-----------------------+--------+ -Short caption. -` - checkEqual(t, buf.String(), want, "long caption for short example rendering failed") -} - -func TestPrintLongCaptionWithShortExample(t *testing.T) { - var buf bytes.Buffer - data := [][]string{ - {"A", "The Good", "500"}, - {"B", "The Very very Bad Man", "288"}, - {"C", "The Ugly", "120"}, - {"D", "The Gopher", "800"}, - } - - table := NewWriter(&buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.") - - for _, v := range data { - table.Append(v) - } - table.Render() - - want := `+------+-----------------------+--------+ -| NAME | SIGN | RATING | -+------+-----------------------+--------+ -| A | The Good | 500 | -| B | The Very very Bad Man | 288 | -| C | The Ugly | 120 | -| D | The Gopher | 800 | -+------+-----------------------+--------+ -This is a very long caption. The text -should wrap. If not, we have a problem -that needs to be solved. -` - checkEqual(t, buf.String(), want, "long caption for short example rendering failed") -} - -func TestPrintCaptionWithFooter(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - {"1/1/2014", "January Hosting", "2233", "$54.95"}, - {"1/4/2014", "February Hosting", "2233", "$51.00"}, - {"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer - table.SetCaption(true, "This is a very long caption. The text should wrap to the width of the table.") // Add caption - table.SetBorder(false) // Set Border to false - table.AppendBulk(data) // Add Bulk Data - table.Render() - - want := ` DATE | DESCRIPTION | CV2 | AMOUNT -+----------+--------------------------+-------+---------+ - 1/1/2014 | Domain name | 2233 | $10.98 - 1/1/2014 | January Hosting | 2233 | $54.95 - 1/4/2014 | February Hosting | 2233 | $51.00 - 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 -+----------+--------------------------+-------+---------+ - TOTAL | $146 93 - +-------+---------+ -This is a very long caption. The text should wrap to the -width of the table. -` - checkEqual(t, buf.String(), want, "border table rendering failed") -} - -func TestPrintLongCaptionWithLongExample(t *testing.T) { - var buf bytes.Buffer - data := [][]string{ - {"Learn East has computers with adapted keyboards with enlarged print etc", "Some Data", "Another Data"}, - {"Instead of lining up the letters all", "the way across, he splits the keyboard in two", "Like most ergonomic keyboards"}, - } - - table := NewWriter(&buf) - table.SetCaption(true, "This is a very long caption. The text should wrap. If not, we have a problem that needs to be solved.") - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - for _, v := range data { - table.Append(v) - } - table.Render() - - want := `+--------------------------------+--------------------------------+-------------------------------+ -| NAME | SIGN | RATING | -+--------------------------------+--------------------------------+-------------------------------+ -| Learn East has computers | Some Data | Another Data | -| with adapted keyboards with | | | -| enlarged print etc | | | -| Instead of lining up the | the way across, he splits the | Like most ergonomic keyboards | -| letters all | keyboard in two | | -+--------------------------------+--------------------------------+-------------------------------+ -This is a very long caption. The text should wrap. If not, we have a problem that needs to be -solved. -` - checkEqual(t, buf.String(), want, "long caption for long example rendering failed") -} - -func Example_autowrap() { - var multiline = `A multiline -string with some lines being really long.` - - const ( - testRow = iota - testHeader - testFooter - testFooter2 - ) - for mode := testRow; mode <= testFooter2; mode++ { - for _, autoFmt := range []bool{false, true} { - if mode == testRow && autoFmt { - // Nothing special to test, skip - continue - } - for _, autoWrap := range []bool{false, true} { - for _, reflow := range []bool{false, true} { - if !autoWrap && reflow { - // Invalid configuration, skip - continue - } - fmt.Println("mode", mode, "autoFmt", autoFmt, "autoWrap", autoWrap, "reflow", reflow) - t := NewWriter(os.Stdout) - t.SetAutoFormatHeaders(autoFmt) - t.SetAutoWrapText(autoWrap) - t.SetReflowDuringAutoWrap(reflow) - if mode == testHeader { - t.SetHeader([]string{"woo", multiline}) - } else { - t.SetHeader([]string{"woo", "waa"}) - } - if mode == testRow { - t.Append([]string{"woo", multiline}) - } else { - t.Append([]string{"woo", "waa"}) - } - if mode == testFooter { - t.SetFooter([]string{"woo", multiline}) - } else if mode == testFooter2 { - t.SetFooter([]string{"", multiline}) - } else { - t.SetFooter([]string{"woo", "waa"}) - } - t.Render() - } - } - } - fmt.Println() - } - - // Output: - // mode 0 autoFmt false autoWrap false reflow false - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | woo | A multiline | - // | | string with some lines being really long. | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // mode 0 autoFmt false autoWrap true reflow false - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | A multiline | - // | | | - // | | string with some lines being | - // | | really long. | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // mode 0 autoFmt false autoWrap true reflow true - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | A multiline string with some | - // | | lines being really long. | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // - // mode 1 autoFmt false autoWrap false reflow false - // +-----+-------------------------------------------+ - // | woo | A multiline | - // | | string with some lines being really long. | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // mode 1 autoFmt false autoWrap true reflow false - // +-----+--------------------------------+ - // | woo | A multiline | - // | | | - // | | string with some lines being | - // | | really long. | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // mode 1 autoFmt false autoWrap true reflow true - // +-----+--------------------------------+ - // | woo | A multiline string with some | - // | | lines being really long. | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // mode 1 autoFmt true autoWrap false reflow false - // +-----+-------------------------------------------+ - // | WOO | A MULTILINE | - // | | STRING WITH SOME LINES BEING REALLY LONG | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | WOO | WAA | - // +-----+-------------------------------------------+ - // mode 1 autoFmt true autoWrap true reflow false - // +-----+--------------------------------+ - // | WOO | A MULTILINE | - // | | | - // | | STRING WITH SOME LINES BEING | - // | | REALLY LONG | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // mode 1 autoFmt true autoWrap true reflow true - // +-----+--------------------------------+ - // | WOO | A MULTILINE STRING WITH SOME | - // | | LINES BEING REALLY LONG | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // - // mode 2 autoFmt false autoWrap false reflow false - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | woo | A multiline | - // | | string with some lines being really long. | - // +-----+-------------------------------------------+ - // mode 2 autoFmt false autoWrap true reflow false - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | A multiline | - // | | | - // | | string with some lines being | - // | | really long. | - // +-----+--------------------------------+ - // mode 2 autoFmt false autoWrap true reflow true - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | A multiline string with some | - // | | lines being really long. | - // +-----+--------------------------------+ - // mode 2 autoFmt true autoWrap false reflow false - // +-----+-------------------------------------------+ - // | WOO | WAA | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | WOO | A MULTILINE | - // | | STRING WITH SOME LINES BEING REALLY LONG | - // +-----+-------------------------------------------+ - // mode 2 autoFmt true autoWrap true reflow false - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | WOO | A MULTILINE | - // | | | - // | | STRING WITH SOME LINES BEING | - // | | REALLY LONG | - // +-----+--------------------------------+ - // mode 2 autoFmt true autoWrap true reflow true - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | WOO | A MULTILINE STRING WITH SOME | - // | | LINES BEING REALLY LONG | - // +-----+--------------------------------+ - // - // mode 3 autoFmt false autoWrap false reflow false - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | A multiline | - // | string with some lines being really long. | - // +-----+-------------------------------------------+ - // mode 3 autoFmt false autoWrap true reflow false - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | A multiline | - // | | - // | string with some lines being | - // | really long. | - // +-----+--------------------------------+ - // mode 3 autoFmt false autoWrap true reflow true - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | A multiline string with some | - // | lines being really long. | - // +-----+--------------------------------+ - // mode 3 autoFmt true autoWrap false reflow false - // +-----+-------------------------------------------+ - // | WOO | WAA | - // +-----+-------------------------------------------+ - // | woo | waa | - // +-----+-------------------------------------------+ - // | A MULTILINE | - // | STRING WITH SOME LINES BEING REALLY LONG | - // +-----+-------------------------------------------+ - // mode 3 autoFmt true autoWrap true reflow false - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | A MULTILINE | - // | | - // | STRING WITH SOME LINES BEING | - // | REALLY LONG | - // +-----+--------------------------------+ - // mode 3 autoFmt true autoWrap true reflow true - // +-----+--------------------------------+ - // | WOO | WAA | - // +-----+--------------------------------+ - // | woo | waa | - // +-----+--------------------------------+ - // | A MULTILINE STRING WITH SOME | - // | LINES BEING REALLY LONG | - // +-----+--------------------------------+ -} - -func TestPrintLine(t *testing.T) { - header := make([]string, 12) - val := " " - want := "" - for i := range header { - header[i] = val - want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1)) - val = val + " " - } - want = want + "+" - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader(header) - table.printLine(false) - checkEqual(t, buf.String(), want, "line rendering failed") -} - -func TestAnsiStrip(t *testing.T) { - header := make([]string, 12) - val := " " - want := "" - for i := range header { - header[i] = "\033[43;30m" + val + "\033[00m" - want = fmt.Sprintf("%s+-%s-", want, strings.Replace(val, " ", "-", -1)) - val = val + " " - } - want = want + "+" - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader(header) - table.printLine(false) - checkEqual(t, buf.String(), want, "line rendering failed") -} - -func NewCustomizedTable(out io.Writer) *Table { - table := NewWriter(out) - table.SetCenterSeparator("") - table.SetColumnSeparator("") - table.SetRowSeparator("") - table.SetBorder(false) - table.SetAlignment(ALIGN_LEFT) - table.SetHeader([]string{}) - return table -} - -func TestSubclass(t *testing.T) { - buf := new(bytes.Buffer) - table := NewCustomizedTable(buf) - - data := [][]string{ - {"A", "The Good", "500"}, - {"B", "The Very very Bad Man", "288"}, - {"C", "The Ugly", "120"}, - {"D", "The Gopher", "800"}, - } - - for _, v := range data { - table.Append(v) - } - table.Render() - - want := ` A The Good 500 - B The Very very Bad Man 288 - C The Ugly 120 - D The Gopher 800 -` - checkEqual(t, buf.String(), want, "test subclass failed") -} - -func TestAutoMergeRows(t *testing.T) { - data := [][]string{ - {"A", "The Good", "500"}, - {"A", "The Very very Bad Man", "288"}, - {"B", "The Very very Bad Man", "120"}, - {"B", "The Very very Bad Man", "200"}, - } - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - for _, v := range data { - table.Append(v) - } - table.SetAutoMergeCells(true) - table.Render() - want := `+------+-----------------------+--------+ -| NAME | SIGN | RATING | -+------+-----------------------+--------+ -| A | The Good | 500 | -| | The Very very Bad Man | 288 | -| B | | 120 | -| | | 200 | -+------+-----------------------+--------+ -` - got := buf.String() - if got != want { - t.Errorf("\ngot:\n%s\nwant:\n%s\n", got, want) - } - - buf.Reset() - table = NewWriter(&buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - for _, v := range data { - table.Append(v) - } - table.SetAutoMergeCells(true) - table.SetRowLine(true) - table.Render() - want = `+------+-----------------------+--------+ -| NAME | SIGN | RATING | -+------+-----------------------+--------+ -| A | The Good | 500 | -+ +-----------------------+--------+ -| | The Very very Bad Man | 288 | -+------+ +--------+ -| B | | 120 | -+ + +--------+ -| | | 200 | -+------+-----------------------+--------+ -` - checkEqual(t, buf.String(), want) - - buf.Reset() - table = NewWriter(&buf) - table.SetHeader([]string{"Name", "Sign", "Rating"}) - - dataWithlongText := [][]string{ - {"A", "The Good", "500"}, - {"A", "The Very very very very very Bad Man", "288"}, - {"B", "The Very very very very very Bad Man", "120"}, - {"C", "The Very very Bad Man", "200"}, - } - table.AppendBulk(dataWithlongText) - table.SetAutoMergeCells(true) - table.SetRowLine(true) - table.Render() - want = `+------+--------------------------------+--------+ -| NAME | SIGN | RATING | -+------+--------------------------------+--------+ -| A | The Good | 500 | -+------+--------------------------------+--------+ -| A | The Very very very very very | 288 | -| | Bad Man | | -+------+ +--------+ -| B | | 120 | -| | | | -+------+--------------------------------+--------+ -| C | The Very very Bad Man | 200 | -+------+--------------------------------+--------+ -` - checkEqual(t, buf.String(), want) -} - -func TestClearRows(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetAutoWrapText(false) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer - table.AppendBulk(data) // Add Bulk Data - table.Render() - - originalWant := `+----------+-------------+-------+---------+ -| DATE | DESCRIPTION | CV2 | AMOUNT | -+----------+-------------+-------+---------+ -| 1/1/2014 | Domain name | 2233 | $10.98 | -+----------+-------------+-------+---------+ -| TOTAL | $145 93 | -+----------+-------------+-------+---------+ -` - want := originalWant - - checkEqual(t, buf.String(), want, "table clear rows failed") - - buf.Reset() - table.ClearRows() - table.Render() - - want = `+----------+-------------+-------+---------+ -| DATE | DESCRIPTION | CV2 | AMOUNT | -+----------+-------------+-------+---------+ -+----------+-------------+-------+---------+ -| TOTAL | $145 93 | -+----------+-------------+-------+---------+ -` - - checkEqual(t, buf.String(), want, "table clear rows failed") - - buf.Reset() - table.AppendBulk(data) // Add Bulk Data - table.Render() - - want = `+----------+-------------+-------+---------+ -| DATE | DESCRIPTION | CV2 | AMOUNT | -+----------+-------------+-------+---------+ -| 1/1/2014 | Domain name | 2233 | $10.98 | -+----------+-------------+-------+---------+ -| TOTAL | $145 93 | -+----------+-------------+-------+---------+ -` - - checkEqual(t, buf.String(), want, "table clear rows failed") -} - -func TestClearFooters(t *testing.T) { - data := [][]string{ - {"1/1/2014", "Domain name", "2233", "$10.98"}, - } - - var buf bytes.Buffer - table := NewWriter(&buf) - table.SetAutoWrapText(false) - table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) - table.SetFooter([]string{"", "", "Total", "$145.93"}) // Add Footer - table.AppendBulk(data) // Add Bulk Data - table.Render() - - buf.Reset() - table.ClearFooter() - table.Render() - - want := `+----------+-------------+-------+---------+ -| DATE | DESCRIPTION | CV2 | AMOUNT | -+----------+-------------+-------+---------+ -| 1/1/2014 | Domain name | 2233 | $10.98 | -+----------+-------------+-------+---------+ -` - - checkEqual(t, buf.String(), want) -} - -func TestMoreDataColumnsThanHeaders(t *testing.T) { - var ( - buf = &bytes.Buffer{} - table = NewWriter(buf) - header = []string{"A", "B", "C"} - data = [][]string{ - {"a", "b", "c", "d"}, - {"1", "2", "3", "4"}, - } - want = `+---+---+---+---+ -| A | B | C | | -+---+---+---+---+ -| a | b | c | d | -| 1 | 2 | 3 | 4 | -+---+---+---+---+ -` - ) - table.SetHeader(header) - // table.SetFooter(ctx.tableCtx.footer) - table.AppendBulk(data) - table.Render() - - checkEqual(t, buf.String(), want) -} - -func TestMoreFooterColumnsThanHeaders(t *testing.T) { - var ( - buf = &bytes.Buffer{} - table = NewWriter(buf) - header = []string{"A", "B", "C"} - data = [][]string{ - {"a", "b", "c", "d"}, - {"1", "2", "3", "4"}, - } - footer = []string{"a", "b", "c", "d", "e"} - want = `+---+---+---+---+---+ -| A | B | C | | | -+---+---+---+---+---+ -| a | b | c | d | -| 1 | 2 | 3 | 4 | -+---+---+---+---+---+ -| A | B | C | D | E | -+---+---+---+---+---+ -` - ) - table.SetHeader(header) - table.SetFooter(footer) - table.AppendBulk(data) - table.Render() - - checkEqual(t, buf.String(), want) -} - -func TestSetColMinWidth(t *testing.T) { - var ( - buf = &bytes.Buffer{} - table = NewWriter(buf) - header = []string{"AAA", "BBB", "CCC"} - data = [][]string{ - {"a", "b", "c"}, - {"1", "2", "3"}, - } - footer = []string{"a", "b", "cccc"} - want = `+-----+-----+-------+ -| AAA | BBB | CCC | -+-----+-----+-------+ -| a | b | c | -| 1 | 2 | 3 | -+-----+-----+-------+ -| A | B | CCCC | -+-----+-----+-------+ -` - ) - table.SetHeader(header) - table.SetFooter(footer) - table.AppendBulk(data) - table.SetColMinWidth(2, 5) - table.Render() - - checkEqual(t, buf.String(), want) -} - -func TestWrapString(t *testing.T) { - want := []string{"ああああああああああああああああああああああああ", "あああああああ"} - got, _ := WrapString("ああああああああああああああああああああああああ あああああああ", 55) - checkEqual(t, got, want) -} - -func TestCustomAlign(t *testing.T) { - var ( - buf = &bytes.Buffer{} - table = NewWriter(buf) - header = []string{"AAA", "BBB", "CCC"} - data = [][]string{ - {"a", "b", "c"}, - {"1", "2", "3"}, - } - footer = []string{"a", "b", "cccc"} - want = `+-----+-----+-------+ -| AAA | BBB | CCC | -+-----+-----+-------+ -| a | b | c | -| 1 | 2 | 3 | -+-----+-----+-------+ -| A | B | CCCC | -+-----+-----+-------+ -` - ) - table.SetHeader(header) - table.SetFooter(footer) - table.AppendBulk(data) - table.SetColMinWidth(2, 5) - table.SetColumnAlignment([]int{ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}) - table.Render() - - checkEqual(t, buf.String(), want) -} diff --git a/vendor/github.com/olekukonko/tablewriter/util.go b/vendor/github.com/olekukonko/tablewriter/util.go index dea3c7a..9e8f0cb 100644 --- a/vendor/github.com/olekukonko/tablewriter/util.go +++ b/vendor/github.com/olekukonko/tablewriter/util.go @@ -30,12 +30,27 @@ func ConditionString(cond bool, valid, inValid string) string { return inValid } +func isNumOrSpace(r rune) bool { + return ('0' <= r && r <= '9') || r == ' ' +} + // Format Table Header // Replace _ , . and spaces func Title(name string) string { origLen := len(name) - name = strings.Replace(name, "_", " ", -1) - name = strings.Replace(name, ".", " ", -1) + rs := []rune(name) + for i, r := range rs { + switch r { + case '_': + rs[i] = ' ' + case '.': + // ignore floating number 0.0 + if (i != 0 && !isNumOrSpace(rs[i-1])) || (i != len(rs)-1 && !isNumOrSpace(rs[i+1])) { + rs[i] = ' ' + } + } + } + name = string(rs) name = strings.TrimSpace(name) if len(name) == 0 && origLen > 0 { // Keep at least one character. This is important to preserve diff --git a/vendor/github.com/olekukonko/tablewriter/wrap_test.go b/vendor/github.com/olekukonko/tablewriter/wrap_test.go deleted file mode 100644 index a03f9fc..0000000 --- a/vendor/github.com/olekukonko/tablewriter/wrap_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 Oleku Konko All rights reserved. -// Use of this source code is governed by a MIT -// license that can be found in the LICENSE file. - -// This module is a Table Writer API for the Go Programming Language. -// The protocols were written in pure Go and works on windows and unix systems - -package tablewriter - -import ( - "strings" - "testing" - - "github.com/mattn/go-runewidth" -) - -var text = "The quick brown fox jumps over the lazy dog." - -func TestWrap(t *testing.T) { - exp := []string{ - "The", "quick", "brown", "fox", - "jumps", "over", "the", "lazy", "dog."} - - got, _ := WrapString(text, 6) - checkEqual(t, len(got), len(exp)) -} - -func TestWrapOneLine(t *testing.T) { - exp := "The quick brown fox jumps over the lazy dog." - words, _ := WrapString(text, 500) - checkEqual(t, strings.Join(words, string(sp)), exp) - -} - -func TestUnicode(t *testing.T) { - input := "Česká řeřicha" - var wordsUnicode []string - if runewidth.IsEastAsian() { - wordsUnicode, _ = WrapString(input, 14) - } else { - wordsUnicode, _ = WrapString(input, 13) - } - // input contains 13 (or 14 for CJK) runes, so it fits on one line. - checkEqual(t, len(wordsUnicode), 1) -} - -func TestDisplayWidth(t *testing.T) { - input := "Česká řeřicha" - want := 13 - if runewidth.IsEastAsian() { - want = 14 - } - if n := DisplayWidth(input); n != want { - t.Errorf("Wants: %d Got: %d", want, n) - } - input = "\033[43;30m" + input + "\033[00m" - checkEqual(t, DisplayWidth(input), want) -} diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go index d7982c3..61ef963 100644 --- a/vendor/gopkg.in/ini.v1/file.go +++ b/vendor/gopkg.in/ini.v1/file.go @@ -45,6 +45,9 @@ type File struct { // newFile initializes File object with given data sources. func newFile(dataSources []dataSource, opts LoadOptions) *File { + if len(opts.KeyValueDelimiters) == 0 { + opts.KeyValueDelimiters = "=:" + } return &File{ BlockMode: true, dataSources: dataSources, @@ -227,7 +230,8 @@ func (f *File) Append(source interface{}, others ...interface{}) error { } func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { - equalSign := "=" + equalSign := DefaultFormatLeft + "=" + DefaultFormatRight + if PrettyFormat || PrettyEqual { equalSign = " = " } @@ -237,13 +241,18 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { for i, sname := range f.sectionList { sec := f.Section(sname) if len(sec.Comment) > 0 { - if sec.Comment[0] != '#' && sec.Comment[0] != ';' { - sec.Comment = "; " + sec.Comment - } else { - sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:]) - } - if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil { - return nil, err + // Support multiline comments + lines := strings.Split(sec.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + lines[i] + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } + + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } } } @@ -280,7 +289,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { for _, kname := range sec.keyList { keyLength := len(kname) // First case will surround key by ` and second by """ - if strings.ContainsAny(kname, "\"=:") { + if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) { keyLength += 2 } else if strings.Contains(kname, "`") { keyLength += 6 @@ -300,17 +309,19 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } - if key.Comment[0] != '#' && key.Comment[0] != ';' { - key.Comment = "; " + key.Comment - } else { - key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:]) - } // Support multiline comments - key.Comment = strings.Replace(key.Comment, "\n", "\n; ", -1) + lines := strings.Split(key.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + lines[i] + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } - if _, err := buf.WriteString(key.Comment + LineBreak); err != nil { - return nil, err + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } } } @@ -321,7 +332,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { switch { case key.isAutoIncrement: kname = "-" - case strings.ContainsAny(kname, "\"=:"): + case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters): kname = "`" + kname + "`" case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index ccba1ee..b6505a9 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -1,3 +1,5 @@ +// +build go1.6 + // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may @@ -32,7 +34,7 @@ const ( // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 - _VERSION = "1.35.0" + _VERSION = "1.39.0" ) // Version returns current package version literal. @@ -46,6 +48,10 @@ var ( // at package init time. LineBreak = "\n" + // Place custom spaces when PrettyFormat and PrettyEqual are both disabled + DefaultFormatLeft = "" + DefaultFormatRight = "" + // Variable regexp pattern: %(variable)s varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) @@ -132,6 +138,8 @@ type LoadOptions struct { IgnoreContinuation bool // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. IgnoreInlineComment bool + // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. + SkipUnrecognizableLines bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool @@ -140,6 +148,16 @@ type LoadOptions struct { // AllowNestedValues indicates whether to allow AWS-like nested values. // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values AllowNestedValues bool + // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. + // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure + // Relevant quote: Values can also span multiple lines, as long as they are indented deeper + // than the first line of the value. + AllowPythonMultilineValues bool + // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. + // Docs: https://docs.python.org/2/library/configparser.html + // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. + // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. + SpaceBeforeInlineComment bool // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" UnescapeValueDoubleQuotes bool @@ -147,9 +165,11 @@ type LoadOptions struct { // when value is NOT surrounded by any quotes. // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. UnescapeValueCommentSymbols bool - // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise + // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise // conform to key/value pairs. Specify the names of those blocks here. UnparseableSections []string + // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". + KeyValueDelimiters string } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { @@ -190,7 +210,7 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } -// InsensitiveLoad has exactly same functionality as Load function +// ShadowLoad has exactly same functionality as Load function // except it allows have shadow keys. func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{AllowShadows: true}, source, others...) diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index db3af8f..36cb3da 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -19,11 +19,14 @@ import ( "bytes" "fmt" "io" + "regexp" "strconv" "strings" "unicode" ) +var pythonMultiline = regexp.MustCompile("^(\\s+)([^\n]+)") + type tokenType int const ( @@ -97,7 +100,7 @@ func cleanComment(in []byte) ([]byte, bool) { return in[i:], true } -func readKeyName(in []byte) (string, int, error) { +func readKeyName(delimiters string, in []byte) (string, int, error) { line := string(in) // Check if key name surrounded by quotes. @@ -124,7 +127,7 @@ func readKeyName(in []byte) (string, int, error) { pos += startIdx // Find key-value delimiter - i := strings.IndexAny(line[pos+startIdx:], "=:") + i := strings.IndexAny(line[pos+startIdx:], delimiters) if i < 0 { return "", -1, ErrDelimiterNotFound{line} } @@ -132,7 +135,7 @@ func readKeyName(in []byte) (string, int, error) { return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil } - endIdx = strings.IndexAny(line, "=:") + endIdx = strings.IndexAny(line, delimiters) if endIdx < 0 { return "", -1, ErrDelimiterNotFound{line} } @@ -194,7 +197,8 @@ func hasSurroundedQuote(in string, quote byte) bool { } func (p *parser) readValue(in []byte, - ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols bool) (string, error) { + parserBufferSize int, + ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols, allowPythonMultilines, spaceBeforeInlineComment bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { @@ -224,21 +228,34 @@ func (p *parser) readValue(in []byte, return line[startIdx : pos+startIdx], nil } + lastChar := line[len(line)-1] // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) + trimmedLastChar := line[len(line)-1] // Check continuation lines when desired - if !ignoreContinuation && line[len(line)-1] == '\\' { + if !ignoreContinuation && trimmedLastChar == '\\' { return p.readContinuationLines(line[:len(line)-1]) } // Check if ignore inline comment if !ignoreInlineComment { - i := strings.IndexAny(line, "#;") + var i int + if spaceBeforeInlineComment { + i = strings.Index(line, " #") + if i == -1 { + i = strings.Index(line, " ;") + } + + } else { + i = strings.IndexAny(line, "#;") + } + if i > -1 { p.comment.WriteString(line[i:]) line = strings.TrimSpace(line[:i]) } + } // Trim single and double quotes @@ -252,7 +269,50 @@ func (p *parser) readValue(in []byte, if strings.Contains(line, `\#`) { line = strings.Replace(line, `\#`, "#", -1) } + } else if allowPythonMultilines && lastChar == '\n' { + parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + + identSize := -1 + val := line + + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { + return val, nil + } + return "", peekErr + } + + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + if len(peekMatches) != 3 { + return val, nil + } + + currentIdentSize := len(peekMatches[1]) + // NOTE: Return if not a python-ini multi-line value. + if currentIdentSize < 0 { + return val, nil + } + identSize = currentIdentSize + + // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.readUntil('\n') + if err != nil { + return "", err + } + + val += fmt.Sprintf("\n%s", peekMatches[2]) + } + + // NOTE: If it was a Python multi-line value, + // return the appended value. + if identSize > 0 { + return val, nil + } } + return line, nil } @@ -276,6 +336,28 @@ func (f *File) parse(reader io.Reader) (err error) { var line []byte var inUnparseableSection bool + + // NOTE: Iterate and increase `currentPeekSize` until + // the size of the parser buffer is found. + // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`. + parserBufferSize := 0 + // NOTE: Peek 1kb at a time. + currentPeekSize := 1024 + + if f.options.AllowPythonMultilineValues { + for { + peekBytes, _ := p.buf.Peek(currentPeekSize) + peekBytesLength := len(peekBytes) + + if parserBufferSize >= peekBytesLength { + break + } + + currentPeekSize *= 2 + parserBufferSize = peekBytesLength + } + } + for !p.isEOF { line, err = p.readUntil('\n') if err != nil { @@ -307,8 +389,7 @@ func (f *File) parse(reader io.Reader) (err error) { // Section if line[0] == '[' { // Read to the next ']' (TODO: support quoted strings) - // TODO(unknwon): use LastIndexByte when stop supporting Go1.4 - closeIdx := bytes.LastIndex(line, []byte("]")) + closeIdx := bytes.LastIndexByte(line, ']') if closeIdx == -1 { return fmt.Errorf("unclosed section: %s", line) } @@ -347,25 +428,34 @@ func (f *File) parse(reader io.Reader) (err error) { continue } - kname, offset, err := readKeyName(line) + kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line) if err != nil { // Treat as boolean key when desired, and whole line is key name. - if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { - kname, err := p.readValue(line, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols) - if err != nil { - return err - } - key, err := section.NewBooleanKey(kname) - if err != nil { - return err + if IsErrDelimiterNotFound(err) { + switch { + case f.options.AllowBooleanKeys: + kname, err := p.readValue(line, + parserBufferSize, + f.options.IgnoreContinuation, + f.options.IgnoreInlineComment, + f.options.UnescapeValueDoubleQuotes, + f.options.UnescapeValueCommentSymbols, + f.options.AllowPythonMultilineValues, + f.options.SpaceBeforeInlineComment) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) + if err != nil { + return err + } + key.Comment = strings.TrimSpace(p.comment.String()) + p.comment.Reset() + continue + + case f.options.SkipUnrecognizableLines: + continue } - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - continue } return err } @@ -379,10 +469,13 @@ func (f *File) parse(reader io.Reader) (err error) { } value, err := p.readValue(line[offset:], + parserBufferSize, f.options.IgnoreContinuation, f.options.IgnoreInlineComment, f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols) + f.options.UnescapeValueCommentSymbols, + f.options.AllowPythonMultilineValues, + f.options.SpaceBeforeInlineComment) if err != nil { return err } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index d8a4026..340a1ef 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -82,6 +82,7 @@ func (s *Section) NewKey(name, val string) (*Key, error) { } } else { s.keys[name].value = val + s.keysHash[name] = val } return s.keys[name], nil }
