mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 09:15:26 +01:00 
			
		
		
		
	Update Dependencies (#390)
Co-authored-by: Norwin Roosen <git@nroo.de> Co-authored-by: Norwin <git@nroo.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/390 Reviewed-by: 6543 <6543@obermui.de> Reviewed-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Norwin <noerw@noreply.gitea.io> Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
		
							
								
								
									
										22
									
								
								vendor/github.com/AlecAivazis/survey/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/AlecAivazis/survey/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
| [](https://travis-ci.org/AlecAivazis/survey) | ||||
| [](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) | ||||
|  | ||||
| A library for building interactive prompts. | ||||
| A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences. | ||||
|  | ||||
| <img width="550" src="https://thumbs.gfycat.com/VillainousGraciousKouprey-size_restricted.gif"/> | ||||
|  | ||||
| @@ -295,7 +295,7 @@ survey.AskOne(prompt, &color, survey.WithFilter(myFilter)) | ||||
|  | ||||
| ## Keeping the filter active | ||||
|  | ||||
| By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone.  | ||||
| By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone. | ||||
|  | ||||
| However the user can prevent this from happening and keep the filter active for multiple selections in a e.g. MultiSelect: | ||||
|  | ||||
| @@ -342,11 +342,13 @@ survey.AskOne(prompt, &color, survey.WithValidator(survey.Required)) | ||||
| `survey` comes prepackaged with a few validators to fit common situations. Currently these | ||||
| validators include: | ||||
|  | ||||
| | name         | valid types | description                                                 | notes                                                                                 | | ||||
| | ------------ | ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- | | ||||
| | Required     | any         | Rejects zero values of the response type                    | Boolean values pass straight through since the zero value (false) is a valid response | | ||||
| | MinLength(n) | string      | Enforces that a response is at least the given length       |                                                                                       | | ||||
| | MaxLength(n) | string      | Enforces that a response is no longer than the given length |                                                                                       | | ||||
| | name         | valid types    | description                                                      | notes                                                                                 | | ||||
| | ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | ||||
| | Required     | any            | Rejects zero values of the response type                         | Boolean values pass straight through since the zero value (false) is a valid response | | ||||
| | MinLength(n) | string         | Enforces that a response is at least the given length            |                                                                                       | | ||||
| | MaxLength(n) | string         | Enforces that a response is no longer than the given length      |                                                                                       | | ||||
| | MaxItems(n)  | []OptionAnswer | Enforces that a response has no more selections of the indicated |                                                                                       | | ||||
| | MinItems(n)  | []OptionAnswer | Enforces that a response has no less selections of the indicated |                                                                                       | | ||||
|  | ||||
| ## Help Text | ||||
|  | ||||
| @@ -456,6 +458,12 @@ For some examples, you can see any of the tests in this repo. | ||||
|  | ||||
| ## FAQ | ||||
|  | ||||
| ### What kinds of IO are supported by `survey`? | ||||
|  | ||||
| survey aims to support most terminal emulators; it expects support for ANSI escape sequences. | ||||
| This means that reading from piped stdin or writing to piped stdout is **not supported**, | ||||
| and likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617) | ||||
|  | ||||
| ### Why isn't sending a SIGINT (aka. CTRL-C) signal working? | ||||
|  | ||||
| When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code: | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +1,19 @@ | ||||
| task "install-deps" { | ||||
|     description = "Install all of package dependencies" | ||||
|     pipeline = [ | ||||
|         "go get {{.files}}", | ||||
|         "go get -v {{.files}}", | ||||
|     ] | ||||
| } | ||||
|  | ||||
| task "tests" { | ||||
|     description = "Run the test suite" | ||||
|     command = "go test {{.files}}" | ||||
|     environment { | ||||
|     command = "go test -v {{.files}}" | ||||
|     environment = { | ||||
|         GOFLAGS = "-mod=vendor" | ||||
|     } | ||||
| } | ||||
|  | ||||
| variables { | ||||
| variables = { | ||||
|     files = "$(go list -v ./... | grep -iEv \"tests|examples\")" | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,7 +29,7 @@ var TemplateFuncsNoColor = map[string]interface{}{ | ||||
| //for colored output. The second string does not contain escape codes | ||||
| //and can be used by the renderer for layout purposes. | ||||
| func RunTemplate(tmpl string, data interface{}) (string, string, error) { | ||||
| 	tPair, err := getTemplatePair(tmpl) | ||||
| 	tPair, err := GetTemplatePair(tmpl) | ||||
| 	if err != nil { | ||||
| 		return "", "", err | ||||
| 	} | ||||
| @@ -52,12 +52,12 @@ var ( | ||||
| 	memoMutex = &sync.RWMutex{} | ||||
| ) | ||||
|  | ||||
| //getTemplatePair returns a pair of compiled templates where the | ||||
| //GetTemplatePair returns a pair of compiled templates where the | ||||
| //first template is generated for user-facing output and the | ||||
| //second is generated for use by the renderer. The second | ||||
| //template does not contain any color escape codes, whereas | ||||
| //the first template may or may not depending on DisableColor. | ||||
| func getTemplatePair(tmpl string) ([2]*template.Template, error) { | ||||
| func GetTemplatePair(tmpl string) ([2]*template.Template, error) { | ||||
| 	memoMutex.RLock() | ||||
| 	if t, ok := memoizedGetTemplate[tmpl]; ok { | ||||
| 		memoMutex.RUnlock() | ||||
|   | ||||
							
								
								
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/core/write.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -24,6 +24,11 @@ type OptionAnswer struct { | ||||
| 	Index int | ||||
| } | ||||
|  | ||||
| type reflectField struct { | ||||
| 	value     reflect.Value | ||||
| 	fieldType reflect.StructField | ||||
| } | ||||
|  | ||||
| func OptionAnswerList(incoming []string) []OptionAnswer { | ||||
| 	list := []OptionAnswer{} | ||||
| 	for i, opt := range incoming { | ||||
| @@ -63,13 +68,12 @@ func WriteAnswer(t interface{}, name string, v interface{}) (err error) { | ||||
| 		} | ||||
|  | ||||
| 		// get the name of the field that matches the string we  were given | ||||
| 		fieldIndex, err := findFieldIndex(elem, name) | ||||
| 		field, _, err := findField(elem, name) | ||||
| 		// if something went wrong | ||||
| 		if err != nil { | ||||
| 			// bubble up | ||||
| 			return err | ||||
| 		} | ||||
| 		field := elem.Field(fieldIndex) | ||||
| 		// handle references to the Settable interface aswell | ||||
| 		if s, ok := field.Interface().(Settable); ok { | ||||
| 			// use the interface method | ||||
| @@ -156,37 +160,51 @@ func IsFieldNotMatch(err error) (string, bool) { | ||||
|  | ||||
| // BUG(AlecAivazis): the current implementation might cause weird conflicts if there are | ||||
| // two fields with same name that only differ by casing. | ||||
| func findFieldIndex(s reflect.Value, name string) (int, error) { | ||||
| 	// the type of the value | ||||
| 	sType := s.Type() | ||||
| func findField(s reflect.Value, name string) (reflect.Value, reflect.StructField, error) { | ||||
|  | ||||
| 	fields := flattenFields(s) | ||||
|  | ||||
| 	// first look for matching tags so we can overwrite matching field names | ||||
| 	for i := 0; i < sType.NumField(); i++ { | ||||
| 		// the field we are current scanning | ||||
| 		field := sType.Field(i) | ||||
|  | ||||
| 	for _, f := range fields { | ||||
| 		// the value of the survey tag | ||||
| 		tag := field.Tag.Get(tagName) | ||||
| 		tag := f.fieldType.Tag.Get(tagName) | ||||
| 		// if the tag matches the name we are looking for | ||||
| 		if tag != "" && tag == name { | ||||
| 			// then we found our index | ||||
| 			return i, nil | ||||
| 			return f.value, f.fieldType, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// then look for matching names | ||||
| 	for i := 0; i < sType.NumField(); i++ { | ||||
| 		// the field we are current scanning | ||||
| 		field := sType.Field(i) | ||||
|  | ||||
| 	for _, f := range fields { | ||||
| 		// if the name of the field matches what we're looking for | ||||
| 		if strings.ToLower(field.Name) == strings.ToLower(name) { | ||||
| 			return i, nil | ||||
| 		if strings.ToLower(f.fieldType.Name) == strings.ToLower(name) { | ||||
| 			return f.value, f.fieldType, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// we didn't find the field | ||||
| 	return -1, errFieldNotMatch{name} | ||||
| 	return reflect.Value{}, reflect.StructField{}, errFieldNotMatch{name} | ||||
| } | ||||
|  | ||||
| func flattenFields(s reflect.Value) []reflectField { | ||||
| 	sType := s.Type() | ||||
| 	numField := sType.NumField() | ||||
| 	fields := make([]reflectField, 0, numField) | ||||
| 	for i := 0; i < numField; i++ { | ||||
| 		fieldType := sType.Field(i) | ||||
| 		field := s.Field(i) | ||||
|  | ||||
| 		if field.Kind() == reflect.Struct && fieldType.Anonymous { | ||||
| 			// field is a promoted structure | ||||
| 			for _, f := range flattenFields(field) { | ||||
| 				fields = append(fields, f) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		fields = append(fields, reflectField{field, fieldType}) | ||||
| 	} | ||||
| 	return fields | ||||
| } | ||||
|  | ||||
| // isList returns true if the element is something we can Len() | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,9 +11,9 @@ require ( | ||||
| 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/stretchr/testify v1.2.1 | ||||
| 	golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 | ||||
| 	golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect | ||||
| 	golang.org/x/text v0.3.0 | ||||
| 	golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 // indirect | ||||
| 	golang.org/x/term v0.0.0-20210503060354-a79de5458b56 | ||||
| 	golang.org/x/text v0.3.3 | ||||
| ) | ||||
|  | ||||
| go 1.13 | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -25,7 +25,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 h1:R4dVlxdmKenVdMRS/tTspEpSTRWINYrHD8ySIU9yCIU= | ||||
| golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= | ||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= | ||||
| golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
|   | ||||
							
								
								
									
										171
									
								
								vendor/github.com/AlecAivazis/survey/v2/input.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										171
									
								
								vendor/github.com/AlecAivazis/survey/v2/input.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,8 @@ | ||||
| package survey | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
|  | ||||
| 	"github.com/AlecAivazis/survey/v2/core" | ||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | ||||
| ) | ||||
| @@ -19,8 +21,8 @@ type Input struct { | ||||
| 	Default       string | ||||
| 	Help          string | ||||
| 	Suggest       func(toComplete string) []string | ||||
| 	typedAnswer   string | ||||
| 	answer        string | ||||
| 	typedAnswer   string | ||||
| 	options       []core.OptionAnswer | ||||
| 	selectedIndex int | ||||
| 	showingHelp   bool | ||||
| @@ -58,86 +60,90 @@ var InputQuestionTemplate = ` | ||||
|     {{- if and .Suggest }}{{color "cyan"}}{{ print .Config.SuggestInput }} for suggestions{{end -}} | ||||
|   ]{{color "reset"}} {{end}} | ||||
|   {{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}} | ||||
|   {{- .Answer -}} | ||||
| {{- end}}` | ||||
|  | ||||
| func (i *Input) OnChange(key rune, config *PromptConfig) (bool, error) { | ||||
| 	if key == terminal.KeyEnter || key == '\n' { | ||||
| 		if i.answer != config.HelpInput || i.Help == "" { | ||||
| 			// we're done | ||||
| 			return true, nil | ||||
| 		} else { | ||||
| 			i.answer = "" | ||||
| 			i.showingHelp = true | ||||
| 		} | ||||
| 	} else if key == terminal.KeyDeleteWord || key == terminal.KeyDeleteLine { | ||||
| 		i.answer = "" | ||||
| 	} else if key == terminal.KeyEscape && i.Suggest != nil { | ||||
| 		if len(i.options) > 0 { | ||||
| func (i *Input) onRune(config *PromptConfig) terminal.OnRuneFn { | ||||
| 	return terminal.OnRuneFn(func(key rune, line []rune) ([]rune, bool, error) { | ||||
| 		if i.options != nil && (key == terminal.KeyEnter || key == '\n') { | ||||
| 			return []rune(i.answer), true, nil | ||||
| 		} else if i.options != nil && key == terminal.KeyEscape { | ||||
| 			i.answer = i.typedAnswer | ||||
| 		} | ||||
| 		i.options = nil | ||||
| 	} else if key == terminal.KeyArrowUp && len(i.options) > 0 { | ||||
| 		if i.selectedIndex == 0 { | ||||
| 			i.selectedIndex = len(i.options) - 1 | ||||
| 		} else { | ||||
| 			i.selectedIndex-- | ||||
| 		} | ||||
| 		i.answer = i.options[i.selectedIndex].Value | ||||
| 	} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 { | ||||
| 		if i.selectedIndex == len(i.options)-1 { | ||||
| 			i.options = nil | ||||
| 		} else if key == terminal.KeyArrowUp && len(i.options) > 0 { | ||||
| 			if i.selectedIndex == 0 { | ||||
| 				i.selectedIndex = len(i.options) - 1 | ||||
| 			} else { | ||||
| 				i.selectedIndex-- | ||||
| 			} | ||||
| 			i.answer = i.options[i.selectedIndex].Value | ||||
| 		} else if (key == terminal.KeyArrowDown || key == terminal.KeyTab) && len(i.options) > 0 { | ||||
| 			if i.selectedIndex == len(i.options)-1 { | ||||
| 				i.selectedIndex = 0 | ||||
| 			} else { | ||||
| 				i.selectedIndex++ | ||||
| 			} | ||||
| 			i.answer = i.options[i.selectedIndex].Value | ||||
| 		} else if key == terminal.KeyTab && i.Suggest != nil { | ||||
| 			i.answer = string(line) | ||||
| 			i.typedAnswer = i.answer | ||||
| 			options := i.Suggest(i.answer) | ||||
| 			i.selectedIndex = 0 | ||||
| 		} else { | ||||
| 			i.selectedIndex++ | ||||
| 		} | ||||
| 		i.answer = i.options[i.selectedIndex].Value | ||||
| 	} else if key == terminal.KeyTab && i.Suggest != nil { | ||||
| 		options := i.Suggest(i.answer) | ||||
| 		i.selectedIndex = 0 | ||||
| 		i.typedAnswer = i.answer | ||||
| 		if len(options) > 0 { | ||||
| 			if len(options) == 0 { | ||||
| 				return line, false, nil | ||||
| 			} | ||||
|  | ||||
| 			i.answer = options[0] | ||||
| 			if len(options) == 1 { | ||||
| 				i.typedAnswer = i.answer | ||||
| 				i.options = nil | ||||
| 			} else { | ||||
| 				i.options = core.OptionAnswerList(options) | ||||
| 			} | ||||
| 		} | ||||
| 	} else if key == terminal.KeyDelete || key == terminal.KeyBackspace { | ||||
| 		if i.answer != "" { | ||||
| 			runeAnswer := []rune(i.answer) | ||||
| 			i.answer = string(runeAnswer[0 : len(runeAnswer)-1]) | ||||
| 		} | ||||
| 	} else if key >= terminal.KeySpace { | ||||
| 		i.answer += string(key) | ||||
| 		i.typedAnswer = i.answer | ||||
| 		i.options = nil | ||||
| 	} | ||||
| 		} else { | ||||
| 			if i.options == nil { | ||||
| 				return line, false, nil | ||||
| 			} | ||||
|  | ||||
| 	pageSize := config.PageSize | ||||
| 	opts, idx := paginate(pageSize, i.options, i.selectedIndex) | ||||
| 	err := i.Render( | ||||
| 		InputQuestionTemplate, | ||||
| 		InputTemplateData{ | ||||
| 			Input:         *i, | ||||
| 			Answer:        i.answer, | ||||
| 			ShowHelp:      i.showingHelp, | ||||
| 			SelectedIndex: idx, | ||||
| 			PageEntries:   opts, | ||||
| 			Config:        config, | ||||
| 		}, | ||||
| 	) | ||||
| 			if key >= terminal.KeySpace { | ||||
| 				i.answer += string(key) | ||||
| 			} | ||||
| 			i.typedAnswer = i.answer | ||||
|  | ||||
| 	return err != nil, err | ||||
| 			i.options = nil | ||||
| 		} | ||||
|  | ||||
| 		pageSize := config.PageSize | ||||
| 		opts, idx := paginate(pageSize, i.options, i.selectedIndex) | ||||
| 		err := i.Render( | ||||
| 			InputQuestionTemplate, | ||||
| 			InputTemplateData{ | ||||
| 				Input:         *i, | ||||
| 				Answer:        i.answer, | ||||
| 				ShowHelp:      i.showingHelp, | ||||
| 				SelectedIndex: idx, | ||||
| 				PageEntries:   opts, | ||||
| 				Config:        config, | ||||
| 			}, | ||||
| 		) | ||||
|  | ||||
| 		if err == nil { | ||||
| 			err = readLineAgain | ||||
| 		} | ||||
|  | ||||
| 		return []rune(i.typedAnswer), true, err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var readLineAgain = errors.New("read line again") | ||||
|  | ||||
| func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| 	// render the template | ||||
| 	err := i.Render( | ||||
| 		InputQuestionTemplate, | ||||
| 		InputTemplateData{ | ||||
| 			Input:  *i, | ||||
| 			Config: config, | ||||
| 			Input:    *i, | ||||
| 			Config:   config, | ||||
| 			ShowHelp: i.showingHelp, | ||||
| 		}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| @@ -150,30 +156,39 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| 	defer rr.RestoreTermMode() | ||||
|  | ||||
| 	cursor := i.NewCursor() | ||||
| 	cursor.Hide()       // hide the cursor | ||||
| 	defer cursor.Show() // show the cursor when we're done | ||||
| 	if !config.ShowCursor { | ||||
| 		cursor.Hide()       // hide the cursor | ||||
| 		defer cursor.Show() // show the cursor when we're done | ||||
| 	} | ||||
|  | ||||
| 	var line []rune | ||||
|  | ||||
| 	// start waiting for input | ||||
| 	for { | ||||
| 		r, _, err := rr.ReadRune() | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if r == terminal.KeyInterrupt { | ||||
| 			return "", terminal.InterruptErr | ||||
| 		} | ||||
| 		if r == terminal.KeyEndTransmission { | ||||
| 			break | ||||
| 		if i.options != nil { | ||||
| 			line = []rune{} | ||||
| 		} | ||||
|  | ||||
| 		line, err = rr.ReadLineWithDefault(0, line, i.onRune(config)) | ||||
| 		if err == readLineAgain { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		b, err := i.OnChange(r, config) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
|  | ||||
| 		if b { | ||||
| 			break | ||||
| 		} | ||||
| 		break | ||||
| 	} | ||||
|  | ||||
| 	i.answer = string(line) | ||||
| 	// readline print an empty line, go up before we render the follow up | ||||
| 	cursor.Up(1) | ||||
|  | ||||
| 	// if we ran into the help string | ||||
| 	if i.answer == config.HelpInput && i.Help != "" { | ||||
| 		// show the help and prompt again | ||||
| 		i.showingHelp = true | ||||
| 		return i.Prompt(config) | ||||
| 	} | ||||
|  | ||||
| 	// if the line is empty | ||||
|   | ||||
							
								
								
									
										69
									
								
								vendor/github.com/AlecAivazis/survey/v2/multiselect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/AlecAivazis/survey/v2/multiselect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -45,9 +45,27 @@ type MultiSelectTemplateData struct { | ||||
| 	ShowHelp      bool | ||||
| 	PageEntries   []core.OptionAnswer | ||||
| 	Config        *PromptConfig | ||||
|  | ||||
| 	// These fields are used when rendering an individual option | ||||
| 	CurrentOpt   core.OptionAnswer | ||||
| 	CurrentIndex int | ||||
| } | ||||
|  | ||||
| // IterateOption sets CurrentOpt and CurrentIndex appropriately so a multiselect option can be rendered individually | ||||
| func (m MultiSelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { | ||||
| 	copy := m | ||||
| 	copy.CurrentIndex = ix | ||||
| 	copy.CurrentOpt = opt | ||||
| 	return copy | ||||
| } | ||||
|  | ||||
| var MultiSelectQuestionTemplate = ` | ||||
| {{- define "option"}} | ||||
|     {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} | ||||
|     {{- if index .Checked .CurrentOpt.Index }}{{color .Config.Icons.MarkedOption.Format }} {{ .Config.Icons.MarkedOption.Text }} {{else}}{{color .Config.Icons.UnmarkedOption.Format }} {{ .Config.Icons.UnmarkedOption.Text }} {{end}} | ||||
|     {{- color "reset"}} | ||||
|     {{- " "}}{{- .CurrentOpt.Value}} | ||||
| {{end}} | ||||
| {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | ||||
| {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | ||||
| {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | ||||
| @@ -56,10 +74,7 @@ var MultiSelectQuestionTemplate = ` | ||||
| 	{{- "  "}}{{- color "cyan"}}[Use arrows to move, space to select, <right> to all, <left> to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} | ||||
|   {{- "\n"}} | ||||
|   {{- range $ix, $option := .PageEntries}} | ||||
|     {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} | ||||
|     {{- if index $.Checked $option.Index }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}} | ||||
|     {{- color "reset"}} | ||||
|     {{- " "}}{{$option.Value}}{{"\n"}} | ||||
|     {{- template "option" $.IterateOption $ix $option}} | ||||
|   {{- end}} | ||||
| {{- end}}` | ||||
|  | ||||
| @@ -159,18 +174,17 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) { | ||||
| 	// and we have modified the filter then we should move the page back! | ||||
| 	opts, idx := paginate(pageSize, options, m.selectedIndex) | ||||
|  | ||||
| 	tmplData := MultiSelectTemplateData{ | ||||
| 		MultiSelect:   *m, | ||||
| 		SelectedIndex: idx, | ||||
| 		Checked:       m.checked, | ||||
| 		ShowHelp:      m.showingHelp, | ||||
| 		PageEntries:   opts, | ||||
| 		Config:        config, | ||||
| 	} | ||||
|  | ||||
| 	// render the options | ||||
| 	m.Render( | ||||
| 		MultiSelectQuestionTemplate, | ||||
| 		MultiSelectTemplateData{ | ||||
| 			MultiSelect:   *m, | ||||
| 			SelectedIndex: idx, | ||||
| 			Checked:       m.checked, | ||||
| 			ShowHelp:      m.showingHelp, | ||||
| 			PageEntries:   opts, | ||||
| 			Config:        config, | ||||
| 		}, | ||||
| 	) | ||||
| 	m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) | ||||
| } | ||||
|  | ||||
| func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer { | ||||
| @@ -250,20 +264,21 @@ func (m *MultiSelect) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| 	opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex) | ||||
|  | ||||
| 	cursor := m.NewCursor() | ||||
| 	cursor.Hide()       // hide the cursor | ||||
| 	defer cursor.Show() // show the cursor when we're done | ||||
| 	cursor.Save()          // for proper cursor placement during selection | ||||
| 	cursor.Hide()          // hide the cursor | ||||
| 	defer cursor.Show()    // show the cursor when we're done | ||||
| 	defer cursor.Restore() // clear any accessibility offsetting on exit | ||||
|  | ||||
| 	tmplData := MultiSelectTemplateData{ | ||||
| 		MultiSelect:   *m, | ||||
| 		SelectedIndex: idx, | ||||
| 		Checked:       m.checked, | ||||
| 		PageEntries:   opts, | ||||
| 		Config:        config, | ||||
| 	} | ||||
|  | ||||
| 	// ask the question | ||||
| 	err := m.Render( | ||||
| 		MultiSelectQuestionTemplate, | ||||
| 		MultiSelectTemplateData{ | ||||
| 			MultiSelect:   *m, | ||||
| 			SelectedIndex: idx, | ||||
| 			Checked:       m.checked, | ||||
| 			PageEntries:   opts, | ||||
| 			Config:        config, | ||||
| 		}, | ||||
| 	) | ||||
| 	err := m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										38
									
								
								vendor/github.com/AlecAivazis/survey/v2/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/AlecAivazis/survey/v2/renderer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,7 +7,7 @@ import ( | ||||
|  | ||||
| 	"github.com/AlecAivazis/survey/v2/core" | ||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | ||||
| 	goterm "golang.org/x/crypto/ssh/terminal" | ||||
| 	"golang.org/x/term" | ||||
| ) | ||||
|  | ||||
| type Renderer struct { | ||||
| @@ -69,6 +69,14 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *Renderer) OffsetCursor(offset int) { | ||||
| 	cursor := r.NewCursor() | ||||
| 	for offset > 0 { | ||||
| 		cursor.PreviousLine(1) | ||||
| 		offset-- | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *Renderer) Render(tmpl string, data interface{}) error { | ||||
| 	// cleanup the currently rendered text | ||||
| 	lineCount := r.countLines(r.renderedText) | ||||
| @@ -91,6 +99,21 @@ func (r *Renderer) Render(tmpl string, data interface{}) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *Renderer) RenderWithCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx int) error { | ||||
| 	cursor := r.NewCursor() | ||||
| 	cursor.Restore() // clear any accessibility offsetting | ||||
|  | ||||
| 	if err := r.Render(tmpl, data); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	cursor.Save() | ||||
|  | ||||
| 	offset := computeCursorOffset(MultiSelectQuestionTemplate, data, opts, idx, r.termWidthSafe()) | ||||
| 	r.OffsetCursor(offset) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // appendRenderedError appends text to the renderer's error buffer | ||||
| // which is used to track what has been printed. It is not exported | ||||
| // as errors should only be displayed via Error(config, error). | ||||
| @@ -119,19 +142,24 @@ func (r *Renderer) resetPrompt(lines int) { | ||||
|  | ||||
| func (r *Renderer) termWidth() (int, error) { | ||||
| 	fd := int(r.stdio.Out.Fd()) | ||||
| 	termWidth, _, err := goterm.GetSize(fd) | ||||
| 	termWidth, _, err := term.GetSize(fd) | ||||
| 	return termWidth, err | ||||
| } | ||||
|  | ||||
| // countLines will return the count of `\n` with the addition of any | ||||
| // lines that have wrapped due to narrow terminal width | ||||
| func (r *Renderer) countLines(buf bytes.Buffer) int { | ||||
| func (r *Renderer) termWidthSafe() int { | ||||
| 	w, err := r.termWidth() | ||||
| 	if err != nil || w == 0 { | ||||
| 		// if we got an error due to terminal.GetSize not being supported | ||||
| 		// on current platform then just assume a very wide terminal | ||||
| 		w = 10000 | ||||
| 	} | ||||
| 	return w | ||||
| } | ||||
|  | ||||
| // countLines will return the count of `\n` with the addition of any | ||||
| // lines that have wrapped due to narrow terminal width | ||||
| func (r *Renderer) countLines(buf bytes.Buffer) int { | ||||
| 	w := r.termWidthSafe() | ||||
|  | ||||
| 	bufBytes := buf.Bytes() | ||||
|  | ||||
|   | ||||
							
								
								
									
										72
									
								
								vendor/github.com/AlecAivazis/survey/v2/select.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/AlecAivazis/survey/v2/select.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,9 +43,26 @@ type SelectTemplateData struct { | ||||
| 	ShowAnswer    bool | ||||
| 	ShowHelp      bool | ||||
| 	Config        *PromptConfig | ||||
|  | ||||
| 	// These fields are used when rendering an individual option | ||||
| 	CurrentOpt   core.OptionAnswer | ||||
| 	CurrentIndex int | ||||
| } | ||||
|  | ||||
| // IterateOption sets CurrentOpt and CurrentIndex appropriately so a select option can be rendered individually | ||||
| func (s SelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { | ||||
| 	copy := s | ||||
| 	copy.CurrentIndex = ix | ||||
| 	copy.CurrentOpt = opt | ||||
| 	return copy | ||||
| } | ||||
|  | ||||
| var SelectQuestionTemplate = ` | ||||
| {{- define "option"}} | ||||
|     {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}}  {{end}} | ||||
|     {{- .CurrentOpt.Value}} | ||||
|     {{- color "reset"}} | ||||
| {{end}} | ||||
| {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} | ||||
| {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} | ||||
| {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} | ||||
| @@ -53,10 +70,8 @@ var SelectQuestionTemplate = ` | ||||
| {{- else}} | ||||
|   {{- "  "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} | ||||
|   {{- "\n"}} | ||||
|   {{- range $ix, $choice := .PageEntries}} | ||||
|     {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}}  {{end}} | ||||
|     {{- $choice.Value}} | ||||
|     {{- color "reset"}}{{"\n"}} | ||||
|   {{- range $ix, $option := .PageEntries}} | ||||
|     {{- template "option" $.IterateOption $ix $option}} | ||||
|   {{- end}} | ||||
| {{- end}}` | ||||
|  | ||||
| @@ -152,17 +167,16 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { | ||||
| 	// and we have modified the filter then we should move the page back! | ||||
| 	opts, idx := paginate(pageSize, options, s.selectedIndex) | ||||
|  | ||||
| 	tmplData := SelectTemplateData{ | ||||
| 		Select:        *s, | ||||
| 		SelectedIndex: idx, | ||||
| 		ShowHelp:      s.showingHelp, | ||||
| 		PageEntries:   opts, | ||||
| 		Config:        config, | ||||
| 	} | ||||
|  | ||||
| 	// render the options | ||||
| 	s.Render( | ||||
| 		SelectQuestionTemplate, | ||||
| 		SelectTemplateData{ | ||||
| 			Select:        *s, | ||||
| 			SelectedIndex: idx, | ||||
| 			ShowHelp:      s.showingHelp, | ||||
| 			PageEntries:   opts, | ||||
| 			Config:        config, | ||||
| 		}, | ||||
| 	) | ||||
| 	s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) | ||||
|  | ||||
| 	// keep prompting | ||||
| 	return false | ||||
| @@ -234,16 +248,22 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| 	// figure out the options and index to render | ||||
| 	opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel) | ||||
|  | ||||
| 	cursor := s.NewCursor() | ||||
| 	cursor.Save()          // for proper cursor placement during selection | ||||
| 	cursor.Hide()          // hide the cursor | ||||
| 	defer cursor.Show()    // show the cursor when we're done | ||||
| 	defer cursor.Restore() // clear any accessibility offsetting on exit | ||||
|  | ||||
| 	tmplData := SelectTemplateData{ | ||||
| 		Select:        *s, | ||||
| 		SelectedIndex: idx, | ||||
| 		ShowHelp:      s.showingHelp, | ||||
| 		PageEntries:   opts, | ||||
| 		Config:        config, | ||||
| 	} | ||||
|  | ||||
| 	// ask the question | ||||
| 	err := s.Render( | ||||
| 		SelectQuestionTemplate, | ||||
| 		SelectTemplateData{ | ||||
| 			Select:        *s, | ||||
| 			PageEntries:   opts, | ||||
| 			SelectedIndex: idx, | ||||
| 			Config:        config, | ||||
| 		}, | ||||
| 	) | ||||
| 	err := s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| @@ -255,10 +275,6 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| 	rr.SetTermMode() | ||||
| 	defer rr.RestoreTermMode() | ||||
|  | ||||
| 	cursor := s.NewCursor() | ||||
| 	cursor.Hide()       // hide the cursor | ||||
| 	defer cursor.Show() // show the cursor when we're done | ||||
|  | ||||
| 	// start waiting for input | ||||
| 	for { | ||||
| 		r, _, err := rr.ReadRune() | ||||
| @@ -317,6 +333,8 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { | ||||
| } | ||||
|  | ||||
| func (s *Select) Cleanup(config *PromptConfig, val interface{}) error { | ||||
| 	cursor := s.NewCursor() | ||||
| 	cursor.Restore() | ||||
| 	return s.Render( | ||||
| 		SelectQuestionTemplate, | ||||
| 		SelectTemplateData{ | ||||
|   | ||||
							
								
								
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/survey.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/AlecAivazis/survey/v2/survey.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,10 +1,12 @@ | ||||
| package survey | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/AlecAivazis/survey/v2/core" | ||||
| 	"github.com/AlecAivazis/survey/v2/terminal" | ||||
| @@ -55,6 +57,7 @@ func defaultAskOptions() *AskOptions { | ||||
| 				return strings.Contains(strings.ToLower(value), filter) | ||||
| 			}, | ||||
| 			KeepFilter: false, | ||||
| 			ShowCursor: false, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| @@ -114,6 +117,7 @@ type PromptConfig struct { | ||||
| 	SuggestInput string | ||||
| 	Filter       func(filter string, option string, index int) bool | ||||
| 	KeepFilter   bool | ||||
| 	ShowCursor   bool | ||||
| } | ||||
|  | ||||
| // Prompt is the primary interface for the objects that can take user input | ||||
| @@ -219,6 +223,17 @@ func WithIcons(setIcons func(*IconSet)) AskOpt { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithShowCursor sets the show cursor behavior when prompting the user | ||||
| func WithShowCursor(ShowCursor bool) AskOpt { | ||||
| 	return func(options *AskOptions) error { | ||||
| 		// set the page size | ||||
| 		options.PromptConfig.ShowCursor = ShowCursor | ||||
|  | ||||
| 		// nothing went wrong | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
| AskOne performs the prompt for a single prompt and asks for validation if required. | ||||
| Response types should be something that can be casted from the response type designated | ||||
| @@ -398,3 +413,42 @@ func paginate(pageSize int, choices []core.OptionAnswer, sel int) ([]core.Option | ||||
| 	// return the subset we care about and the index | ||||
| 	return choices[start:end], cursor | ||||
| } | ||||
|  | ||||
| type IterableOpts interface { | ||||
| 	IterateOption(int, core.OptionAnswer) interface{} | ||||
| } | ||||
|  | ||||
| func computeCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx, tWidth int) int { | ||||
| 	tmpls, err := core.GetTemplatePair(tmpl) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return 0 | ||||
| 	} | ||||
|  | ||||
| 	t := tmpls[0] | ||||
|  | ||||
| 	renderOpt := func(ix int, opt core.OptionAnswer) string { | ||||
| 		buf := bytes.NewBufferString("") | ||||
| 		t.ExecuteTemplate(buf, "option", data.IterateOption(ix, opt)) | ||||
| 		return buf.String() | ||||
| 	} | ||||
|  | ||||
| 	offset := len(opts) - idx | ||||
|  | ||||
| 	for i, o := range opts { | ||||
| 		if i < idx { | ||||
| 			continue | ||||
| 		} | ||||
| 		renderedOpt := renderOpt(i, o) | ||||
| 		valWidth := utf8.RuneCount([]byte(renderedOpt)) | ||||
| 		if valWidth > tWidth { | ||||
| 			splitCount := valWidth / tWidth | ||||
| 			if valWidth%tWidth == 0 { | ||||
| 				splitCount -= 1 | ||||
| 			} | ||||
| 			offset += splitCount | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return offset | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -43,11 +43,13 @@ func (c *Cursor) Back(n int) { | ||||
| // NextLine moves cursor to beginning of the line n lines down. | ||||
| func (c *Cursor) NextLine(n int) { | ||||
| 	c.Down(1) | ||||
| 	c.HorizontalAbsolute(0) | ||||
| } | ||||
|  | ||||
| // PreviousLine moves cursor to beginning of the line n lines up. | ||||
| func (c *Cursor) PreviousLine(n int) { | ||||
| 	c.Up(1) | ||||
| 	c.HorizontalAbsolute(0) | ||||
| } | ||||
|  | ||||
| // HorizontalAbsolute moves cursor horizontally to x. | ||||
| @@ -167,8 +169,11 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { | ||||
|  | ||||
| 	// hide the cursor (so it doesn't blink when getting the size of the terminal) | ||||
| 	c.Hide() | ||||
| 	defer c.Show() | ||||
|  | ||||
| 	// save the current location of the cursor | ||||
| 	c.Save() | ||||
| 	defer c.Restore() | ||||
|  | ||||
| 	// move the cursor to the very bottom of the terminal | ||||
| 	c.Move(999, 999) | ||||
| @@ -179,11 +184,6 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// move back where we began | ||||
| 	c.Restore() | ||||
|  | ||||
| 	// show the cursor | ||||
| 	c.Show() | ||||
| 	// since the bottom was calculated in the lower right corner, it | ||||
| 	// is the dimensions we are looking for | ||||
| 	return bottom, nil | ||||
|   | ||||
							
								
								
									
										71
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -31,7 +31,13 @@ func (rr *RuneReader) printChar(char rune, mask rune) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| type OnRuneFn func(rune, []rune) ([]rune, bool, error) | ||||
|  | ||||
| func (rr *RuneReader) ReadLine(mask rune, onRunes ...OnRuneFn) ([]rune, error) { | ||||
| 	return rr.ReadLineWithDefault(mask, []rune{}, onRunes...) | ||||
| } | ||||
|  | ||||
| func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRuneFn) ([]rune, error) { | ||||
| 	line := []rune{} | ||||
| 	// we only care about horizontal displacements from the origin so start counting at 0 | ||||
| 	index := 0 | ||||
| @@ -41,19 +47,56 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 		Out: rr.stdio.Out, | ||||
| 	} | ||||
|  | ||||
| 	onRune := func(r rune, line []rune) ([]rune, bool, error) { | ||||
| 		return line, false, nil | ||||
| 	} | ||||
|  | ||||
| 	// if the user pressed a key the caller was interested in capturing | ||||
| 	if len(onRunes) > 0 { | ||||
| 		onRune = onRunes[0] | ||||
| 	} | ||||
|  | ||||
| 	// we get the terminal width and height (if resized after this point the property might become invalid) | ||||
| 	terminalSize, _ := cursor.Size(rr.Buffer()) | ||||
| 	// we set the current location of the cursor once | ||||
| 	cursorCurrent, _ := cursor.Location(rr.Buffer()) | ||||
|  | ||||
| 	increment := func() { | ||||
| 		if cursorCurrent.CursorIsAtLineEnd(terminalSize) { | ||||
| 			cursorCurrent.X = COORDINATE_SYSTEM_BEGIN | ||||
| 			cursorCurrent.Y++ | ||||
| 		} else { | ||||
| 			cursorCurrent.X++ | ||||
| 		} | ||||
| 	} | ||||
| 	decrement := func() { | ||||
| 		if cursorCurrent.CursorIsAtLineBegin() { | ||||
| 			cursorCurrent.X = terminalSize.X | ||||
| 			cursorCurrent.Y-- | ||||
| 		} else { | ||||
| 			cursorCurrent.X-- | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(d) > 0 { | ||||
| 		index = len(d) | ||||
| 		fmt.Fprint(rr.stdio.Out, string(d)) | ||||
| 		line = d | ||||
| 		for range d { | ||||
| 			increment() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		// wait for some input | ||||
| 		r, _, err := rr.ReadRune() | ||||
| 		if err != nil { | ||||
| 			return line, err | ||||
| 		} | ||||
| 		// increment cursor location | ||||
| 		cursorCurrent.X++ | ||||
|  | ||||
| 		if l, stop, err := onRune(r, line); stop || err != nil { | ||||
| 			return l, err | ||||
| 		} | ||||
|  | ||||
| 		// if the user pressed enter or some other newline/termination like ctrl+d | ||||
| 		if r == '\r' || r == '\n' || r == KeyEndTransmission { | ||||
| @@ -63,13 +106,10 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 					EraseLine(rr.stdio.Out, ERASE_LINE_END) | ||||
| 					cursor.PreviousLine(1) | ||||
| 					cursor.Forward(int(terminalSize.X)) | ||||
| 					cursorCurrent.X = terminalSize.X | ||||
| 					cursorCurrent.Y-- | ||||
|  | ||||
| 				} else { | ||||
| 					cursor.Back(1) | ||||
| 					cursorCurrent.X-- | ||||
| 				} | ||||
| 				decrement() | ||||
| 				index-- | ||||
| 			} | ||||
| 			// move the cursor the a new line | ||||
| @@ -148,6 +188,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
|  | ||||
| 				// decrement the index | ||||
| 				index-- | ||||
| 				decrement() | ||||
| 			} else { | ||||
| 				// otherwise the user pressed backspace while at the beginning of the line | ||||
| 				soundBell(rr.stdio.Out) | ||||
| @@ -170,6 +211,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 				} | ||||
| 				//decrement the index | ||||
| 				index-- | ||||
| 				decrement() | ||||
|  | ||||
| 			} else { | ||||
| 				// otherwise we are at the beginning of where we started reading lines | ||||
| @@ -192,6 +234,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 					cursor.Forward(runeWidth(line[index])) | ||||
| 				} | ||||
| 				index++ | ||||
| 				increment() | ||||
|  | ||||
| 			} else { | ||||
| 				// otherwise we are at the end of the word and can't go past | ||||
| @@ -208,12 +251,11 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 				if cursorCurrent.CursorIsAtLineBegin() { | ||||
| 					cursor.PreviousLine(1) | ||||
| 					cursor.Forward(int(terminalSize.X)) | ||||
| 					cursorCurrent.X = terminalSize.X | ||||
| 					cursorCurrent.Y-- | ||||
|  | ||||
| 					cursorCurrent.X = terminalSize.X | ||||
| 				} else { | ||||
| 					cursor.Back(runeWidth(line[index-1])) | ||||
| 					cursorCurrent.X-- | ||||
| 					cursorCurrent.X -= Short(runeWidth(line[index-1])) | ||||
| 				} | ||||
| 				index-- | ||||
| 			} | ||||
| @@ -223,12 +265,11 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 			for index != len(line) { | ||||
| 				if cursorCurrent.CursorIsAtLineEnd(terminalSize) { | ||||
| 					cursor.NextLine(1) | ||||
| 					cursorCurrent.X = COORDINATE_SYSTEM_BEGIN | ||||
| 					cursorCurrent.Y++ | ||||
|  | ||||
| 					cursorCurrent.X = COORDINATE_SYSTEM_BEGIN | ||||
| 				} else { | ||||
| 					cursor.Forward(runeWidth(line[index])) | ||||
| 					cursorCurrent.X++ | ||||
| 					cursorCurrent.X += Short(runeWidth(line[index])) | ||||
| 				} | ||||
| 				index++ | ||||
| 			} | ||||
| @@ -277,6 +318,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 			line = append(line, r) | ||||
| 			// save the location of the cursor | ||||
| 			index++ | ||||
| 			increment() | ||||
| 			// print out the character | ||||
| 			rr.printChar(r, mask) | ||||
| 		} else { | ||||
| @@ -293,7 +335,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 				EraseLine(rr.stdio.Out, ERASE_LINE_END) | ||||
| 				// print out the character | ||||
| 				rr.printChar(char, mask) | ||||
| 				cursorCurrent.X++ | ||||
| 				increment() | ||||
| 			} | ||||
| 			// if we are at the last line, we want to visually insert a new line and append to it. | ||||
| 			if cursorCurrent.CursorIsAtLineEnd(terminalSize) && cursorCurrent.Y == terminalSize.Y { | ||||
| @@ -316,6 +358,7 @@ func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) { | ||||
| 			} | ||||
| 			// increment the index | ||||
| 			index++ | ||||
| 			increment() | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										40
									
								
								vendor/github.com/AlecAivazis/survey/v2/validate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/AlecAivazis/survey/v2/validate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,8 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/AlecAivazis/survey/v2/core" | ||||
| ) | ||||
|  | ||||
| // Required does not allow an empty value | ||||
| @@ -58,6 +60,44 @@ func MinLength(length int) Validator { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MaxItems requires that the list is no longer than the specified value | ||||
| func MaxItems(numberItems int) Validator { | ||||
| 	// return a validator that checks the length of the list | ||||
| 	return func(val interface{}) error { | ||||
| 		if list, ok := val.([]core.OptionAnswer); ok { | ||||
| 			// if the list is longer than the given value | ||||
| 			if len(list) > numberItems { | ||||
| 				// yell loudly | ||||
| 				return fmt.Errorf("value is too long. Max items is %v", numberItems) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// otherwise we cannot convert the value into a list of answer and cannot enforce length | ||||
| 			return fmt.Errorf("cannot impose the length on something other than a list of answers") | ||||
| 		} | ||||
| 		// the input is fine | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MinItems requires that the list is longer or equal in length to the specified value | ||||
| func MinItems(numberItems int) Validator { | ||||
| 	// return a validator that checks the length of the list | ||||
| 	return func(val interface{}) error { | ||||
| 		if list, ok := val.([]core.OptionAnswer); ok { | ||||
| 			// if the list is shorter than the given value | ||||
| 			if len(list) < numberItems { | ||||
| 				// yell loudly | ||||
| 				return fmt.Errorf("value is too long. Min items is %v", numberItems) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// otherwise we cannot convert the value into a list of answer and cannot enforce length | ||||
| 			return fmt.Errorf("cannot impose the length on something other than a list of answers") | ||||
| 		} | ||||
| 		// the input is fine | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ComposeValidators is a variadic function used to create one validator from many. | ||||
| func ComposeValidators(validators ...Validator) Validator { | ||||
| 	// return a validator that calls each one sequentially | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin