1package survey
2
3import (
4	"strings"
5
6	"github.com/AlecAivazis/survey/v2/terminal"
7)
8
9type Multiline struct {
10	Renderer
11	Message string
12	Default string
13	Help    string
14}
15
16// data available to the templates when processing
17type MultilineTemplateData struct {
18	Multiline
19	Answer     string
20	ShowAnswer bool
21	ShowHelp   bool
22	Config     *PromptConfig
23}
24
25// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
26var MultilineQuestionTemplate = `
27{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
28{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
29{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
30{{- if .ShowAnswer}}
31  {{- "\n"}}{{color "cyan"}}{{.Answer}}{{color "reset"}}
32  {{- if .Answer }}{{ "\n" }}{{ end }}
33{{- else }}
34  {{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
35  {{- color "cyan"}}[Enter 2 empty lines to finish]{{color "reset"}}
36{{- end}}`
37
38func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) {
39	// render the template
40	err := i.Render(
41		MultilineQuestionTemplate,
42		MultilineTemplateData{
43			Multiline: *i,
44			Config:    config,
45		},
46	)
47	if err != nil {
48		return "", err
49	}
50
51	// start reading runes from the standard in
52	rr := i.NewRuneReader()
53	rr.SetTermMode()
54	defer rr.RestoreTermMode()
55
56	cursor := i.NewCursor()
57
58	multiline := make([]string, 0)
59
60	emptyOnce := false
61	// get the next line
62	for {
63		line := []rune{}
64		line, err = rr.ReadLine(0)
65		if err != nil {
66			return string(line), err
67		}
68
69		if string(line) == "" {
70			if emptyOnce {
71				numLines := len(multiline) + 2
72				cursor.PreviousLine(numLines)
73				for j := 0; j < numLines; j++ {
74					terminal.EraseLine(i.Stdio().Out, terminal.ERASE_LINE_ALL)
75					cursor.NextLine(1)
76				}
77				cursor.PreviousLine(numLines)
78				break
79			}
80			emptyOnce = true
81		} else {
82			emptyOnce = false
83		}
84		multiline = append(multiline, string(line))
85	}
86
87	val := strings.Join(multiline, "\n")
88	val = strings.TrimSpace(val)
89
90	// if the line is empty
91	if len(val) == 0 {
92		// use the default value
93		return i.Default, err
94	}
95
96	i.AppendRenderedText(val)
97	return val, err
98}
99
100func (i *Multiline) Cleanup(config *PromptConfig, val interface{}) error {
101	return i.Render(
102		MultilineQuestionTemplate,
103		MultilineTemplateData{
104			Multiline:  *i,
105			Answer:     val.(string),
106			ShowAnswer: true,
107			Config:     config,
108		},
109	)
110}
111