File: tui.go

package info (click to toggle)
age 1.3.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 984 kB
  • sloc: makefile: 11
file content (78 lines) | stat: -rw-r--r-- 2,056 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package plugin

import (
	"errors"
	"fmt"

	"filippo.io/age/internal/term"
)

// NewTerminalUI returns a [ClientUI] that uses the terminal to request inputs,
// and the provided functions to display messages and errors.
//
// The terminal is reached directly through /dev/tty or CONIN$/CONOUT$,
// bypassing standard input and output, so this UI can be used even when
// standard input or output are redirected.
func NewTerminalUI(printf, warningf func(format string, v ...any)) *ClientUI {
	return &ClientUI{
		DisplayMessage: func(name, message string) error {
			printf("%s plugin: %s", name, message)
			return nil
		},
		RequestValue: func(name, message string, isSecret bool) (s string, err error) {
			defer func() {
				if err != nil {
					warningf("could not read value for age-plugin-%s: %v", name, err)
				}
			}()
			if isSecret {
				secret, err := term.ReadSecret(message)
				if err != nil {
					return "", err
				}
				return string(secret), nil
			} else {
				public, err := term.ReadPublic(message)
				if err != nil {
					return "", err
				}
				return string(public), nil
			}
		},
		Confirm: func(name, message, yes, no string) (choseYes bool, err error) {
			defer func() {
				if err != nil {
					warningf("could not read value for age-plugin-%s: %v", name, err)
				}
			}()
			if no == "" {
				message += fmt.Sprintf(" (press enter for %q)", yes)
				_, err := term.ReadSecret(message)
				if err != nil {
					return false, err
				}
				return true, nil
			}
			message += fmt.Sprintf(" (press [1] for %q or [2] for %q)", yes, no)
			for {
				selection, err := term.ReadCharacter(message)
				if err != nil {
					return false, err
				}
				switch selection {
				case '1':
					return true, nil
				case '2':
					return false, nil
				case '\x03': // CTRL-C
					return false, errors.New("user cancelled prompt")
				default:
					warningf("reading value for age-plugin-%s: invalid selection %q", name, selection)
				}
			}
		},
		WaitTimer: func(name string) {
			printf("waiting on %s plugin...", name)
		},
	}
}