62
60
self.stderr = stderr
63
61
# paints progress, network activity, etc
64
62
self._progress_view = self.make_progress_view()
65
# hook up the signals to watch for terminal size changes
66
""" Helper class for choose implementation.
69
class InputEOF(StandardError):
72
def __init__(self, ui, msg, choices, default):
75
self._build_alternatives(msg, choices, default)
77
def _setup_mode(self):
78
"""Setup input mode (line-based, char-based) and echo-back.
80
Line-based input is used if the BZR_TEXTUI_INPUT environment
81
variable is set to 'line-based', or if there is no controlling
84
if os.environ.get('BZR_TEXTUI_INPUT') != 'line-based' and \
85
self.ui.stdin == sys.stdin and self.ui.stdin.isatty():
86
self.line_based = False
89
self.line_based = True
90
self.echo_back = not self.ui.stdin.isatty()
92
def _build_alternatives(self, msg, choices, default):
93
"""Parse choices string.
95
Setup final prompt and the lists of choices and associated
100
self.alternatives = {}
101
choices = choices.split('\n')
102
if default is not None and default not in range(0, len(choices)):
103
raise ValueError("invalid default index")
105
name = c.replace('&', '').lower()
106
choice = (name, index)
107
if name in self.alternatives:
108
raise ValueError("duplicated choice: %s" % name)
109
self.alternatives[name] = choice
110
shortcut = c.find('&')
111
if -1 != shortcut and (shortcut + 1) < len(c):
113
help += '[' + c[shortcut + 1] + ']'
114
help += c[(shortcut + 2):]
115
shortcut = c[shortcut + 1]
117
c = c.replace('&', '')
119
help = '[%s]%s' % (shortcut, c[1:])
120
shortcut = shortcut.lower()
121
if shortcut in self.alternatives:
122
raise ValueError("duplicated shortcut: %s" % shortcut)
123
self.alternatives[shortcut] = choice
124
# Add redirections for default.
126
self.alternatives[''] = choice
127
self.alternatives['\r'] = choice
128
self.alternatives['\n'] = choice
129
help_list.append(help)
132
self.prompt = u'%s (%s): ' % (msg, ', '.join(help_list))
135
line = self.ui.stdin.readline()
141
char = osutils.getchar()
142
if char == chr(3): # INTR
143
raise KeyboardInterrupt
144
if char == chr(4): # EOF (^d, C-d)
149
"""Keep asking the user until a valid choice is made.
152
getchoice = self._getline
154
getchoice = self._getchar
158
if 1 == iter or self.line_based:
159
self.ui.prompt(self.prompt)
162
except self.InputEOF:
163
self.ui.stderr.write('\n')
165
except KeyboardInterrupt:
166
self.ui.stderr.write('\n')
167
raise KeyboardInterrupt
168
choice = choice.lower()
169
if choice not in self.alternatives:
170
# Not a valid choice, keep on asking.
172
name, index = self.alternatives[choice]
174
self.ui.stderr.write(name + '\n')
177
def choose(self, msg, choices, default=None):
178
"""Prompt the user for a list of alternatives.
180
Support both line-based and char-based editing.
182
In line-based mode, both the shortcut and full choice name are valid
183
answers, e.g. for choose('prompt', '&yes\n&no'): 'y', ' Y ', ' yes',
184
'YES ' are all valid input lines for choosing 'yes'.
186
An empty line, when in line-based mode, or pressing enter in char-based
187
mode will select the default choice (if any).
189
Choice is echoed back if:
190
- input is char-based; which means a controlling terminal is available,
191
and osutils.getchar is used
192
- input is line-based, and no controlling terminal is available
195
choose_ui = self.ChooseUI(self, msg, choices, default)
196
return choose_ui.interact()
68
198
def be_quiet(self, state):
69
199
if state and not self._quiet:
364
498
t = t._parent_task
366
500
m = t.msg + ':' + m
369
503
def _render_line(self):
370
504
bar_string = self._render_bar()
371
505
if self._last_task:
372
task_msg = self._format_task(self._last_task)
506
task_part, counter_part = self._format_task(self._last_task)
508
task_part = counter_part = ''
375
509
if self._last_task and not self._last_task.show_transport_activity:
378
512
trans = self._last_transport_msg
381
return (bar_string + trans + task_msg)
513
# the bar separates the transport activity from the message, so even
514
# if there's no bar or spinner, we must show something if both those
516
if (task_part or trans) and not bar_string:
518
# preferentially truncate the task message if we don't have enough
520
avail_width = self._avail_width()
521
if avail_width is not None:
522
# if terminal avail_width is unknown, don't truncate
523
current_len = len(bar_string) + len(trans) + len(task_part) + len(counter_part)
524
gap = current_len - avail_width
526
task_part = task_part[:-gap-2] + '..'
527
s = trans + bar_string + task_part + counter_part
528
if avail_width is not None:
529
if len(s) < avail_width:
530
s = s.ljust(avail_width)
531
elif len(s) > avail_width:
383
535
def _repaint(self):
384
536
s = self._render_line()