Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

""" 

:py:mod:`sysdirs.interfaces` 

 

Copyright (C) 2018 Mathias Stelzer 

 

sysdirs is free software: you can redistribute it and/or modify 

it under the terms of the GNU General Public License as published by 

the Free Software Foundation, either version 3 of the License, or 

(at your option) any later version. 

 

sysdirs is distributed in the hope that it will be useful, 

but WITHOUT ANY WARRANTY; without even the implied warranty of 

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

GNU General Public License for more details. 

 

You should have received a copy of the GNU General Public License 

along with this program. If not, see <http://www.gnu.org/licenses/>. 

""" 

from __future__ import absolute_import, unicode_literals, print_function 

 

import io 

import sys 

 

from select import select as pyselect 

 

 

def clean_choice_answer(choices, answer): 

value = answer.strip() 

if not value: 

return 

 

try: 

index = int(value) 

except ValueError: 

sys.stdout.write('"{}" is not a valid number!'.format(value)) 

sys.stdout.flush() 

return 

 

try: 

return choices[index] 

except IndexError: 

sys.stdout.write('"{}" is not a valid choice!'.format(index)) 

sys.stdout.flush() 

 

 

class BaseInterface(object): 

def __init__(self, installer): 

self.installer = installer 

 

def ask_choices(self, prompt, choices, default=None, timeout_default=None, format_callback=None): 

raise NotImplementedError 

 

def ask_text(self, prompt, default=None, timeout_default=None, clean_callback=None): 

raise NotImplementedError 

 

def ask_yesno(self, prompt, default=None, timeout_default=None): 

raise NotImplementedError 

 

 

class TerminalInterface(BaseInterface): 

def ask_choices(self, prompt, choices, default=None, timeout_default=None, format_callback=None): 

""" 

Show selection, wait for user input and return it. 

 

Blocks until valid answer given. 

 

Returns ``None`` if the timeout is reached. 

""" 

print(prompt) 

 

for index, choice in enumerate(choices): 

if callable(format_callback): 

formatted = format_callback(choice) 

else: 

formatted = choice 

print('[{}] {}'.format(index, formatted)) 

 

def clean_callback(answer): 

if answer == default: 

return default 

return clean_choice_answer(choices, answer) 

 

return self.select(default=default, timeout_default=timeout_default, clean_callback=clean_callback) 

 

def _format_default(self, default, space=True): 

formatted = '' 

if default: 

formatted = '{}[{}]'.format(' ' if space else '', default) 

return formatted 

 

def ask_text(self, prompt, default=None, timeout_default=None, clean_callback=None): 

return self.select(prompt=prompt, default=default, timeout_default=timeout_default, 

clean_callback=clean_callback) 

 

def ask_yesno(self, prompt, default=None, timeout_default=None): 

def clean(answer): 

if answer == default: 

return default 

if answer.lower().startswith('y'): 

return True 

if answer.lower().startswith('n'): 

return False 

return self.select(prompt=prompt, default=default, timeout_default=timeout_default, 

clean_callback=clean) 

 

def select(self, prompt='', default=None, timeout_default=None, clean_callback=None): 

answer = None 

timeout = self.installer.input_timeout 

 

# Wrap stdin with an encoding-aware reader in py2 

stdin = sys.stdin 

if sys.version_info[0] < 3: 

stdin = io.TextIOWrapper(sys.stdin, line_buffering=True) 

 

while not answer: 

if timeout: 

sys.stdout.write('({}s timeout{}) '.format(timeout, self._format_default(timeout_default))) 

sys.stdout.write('{}{}: '.format(prompt, self._format_default(default, space=bool(prompt)))) 

sys.stdout.flush() 

 

i, o, e = pyselect([stdin], [], [], timeout) 

 

if not i: 

return timeout_default 

 

timeout = None # received something, disable timeout 

 

answer = i[0].readline().strip() 

 

if not answer and default: 

answer = default 

if callable(clean_callback): 

answer = clean_callback(answer) 

return answer