| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 6f6fa93 commit 52d2fd7
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -147,6 +147,28 @@ def wrapper(*args, **kwargs): | |||
| 147 | 147 | TwistedEventLoop = urwid.TwistedEventLoop | |
| 148 | 148 | ||
| 149 | 149 | ||
| 150 | + class StatusbarEdit(urwid.Edit): | ||
| 151 | + """Wrapper around urwid.Edit used for the prompt in Statusbar. | ||
| 152 | + | ||
| 153 | + This class only adds a single signal that is emitted if the user presses | ||
| 154 | + Enter.""" | ||
| 155 | + | ||
| 156 | + signals = urwid.Edit.signals + ['prompt_enter'] | ||
| 157 | + | ||
| 158 | + def __init__(self, *args, **kwargs): | ||
| 159 | + self.single = False | ||
| 160 | + urwid.Edit.__init__(self, *args, **kwargs) | ||
| 161 | + | ||
| 162 | + def keypress(self, size, key): | ||
| 163 | + if self.single: | ||
| 164 | + urwid.emit_signal(self, 'prompt_enter', self, key) | ||
| 165 | + elif key == 'enter': | ||
| 166 | + urwid.emit_signal(self, 'prompt_enter', self, self.get_edit_text()) | ||
| 167 | + else: | ||
| 168 | + return urwid.Edit.keypress(self, size, key) | ||
| 169 | + | ||
| 170 | + urwid.register_signal(StatusbarEdit, 'prompt_enter') | ||
| 171 | + | ||
| 150 | 172 | class Statusbar(object): | |
| 151 | 173 | ||
| 152 | 174 | """Statusbar object, ripped off from bpython.cli. | |
@@ -167,15 +189,22 @@ class Statusbar(object): | |||
| 167 | 189 | The "widget" attribute is an urwid widget. | |
| 168 | 190 | """ | |
| 169 | 191 | ||
| 192 | + signals = ['prompt_result'] | ||
| 193 | + | ||
| 170 | 194 | def __init__(self, config, s=None, main_loop=None): | |
| 171 | 195 | self.config = config | |
| 172 | 196 | self.timer = None | |
| 173 | 197 | self.main_loop = main_loop | |
| 174 | 198 | self.s = s or '' | |
| 175 | 199 | ||
| 176 | - self.widget = urwid.Text(('main', self.s)) | ||
| 200 | + self.text = urwid.Text(('main', self.s)) | ||
| 177 | 201 | # use wrap mode 'clip' to just cut off at the end of line | |
| 178 | - self.widget.set_wrap_mode('clip') | ||
| 202 | + self.text.set_wrap_mode('clip') | ||
| 203 | + | ||
| 204 | + self.edit = StatusbarEdit(('main', '')) | ||
| 205 | + urwid.connect_signal(self.edit, 'prompt_enter', self._on_prompt_enter) | ||
| 206 | + | ||
| 207 | + self.widget = urwid.Columns([self.text, self.edit]) | ||
| 179 | 208 | ||
| 180 | 209 | def _check(self, callback, userdata=None): | |
| 181 | 210 | """This is the method is called from the timer to reset the status bar.""" | |
@@ -189,30 +218,57 @@ def message(self, s, n=3): | |||
| 189 | 218 | self.settext(s) | |
| 190 | 219 | self.timer = self.main_loop.set_alarm_in(n, self._check) | |
| 191 | 220 | ||
| 192 | - def prompt(self, s=''): | ||
| 193 | - """Prompt the user for some input (with the optional prompt 's') and | ||
| 194 | - return the input text, then restore the statusbar to its original | ||
| 195 | - value.""" | ||
| 221 | + def prompt(self, s=None, single=False): | ||
| 222 | + """Prompt the user for some input (with the optional prompt 's'). After | ||
| 223 | + the user hit enter the signal 'prompt_result' will be emited and the | ||
| 224 | + status bar will be reset. If single is True, the first keypress will be | ||
| 225 | + returned.""" | ||
| 196 | 226 | ||
| 197 | - # TODO | ||
| 198 | - return '' | ||
| 227 | + if self.timer is not None: | ||
| 228 | + self.main_loop.remove_alarm(self.timer) | ||
| 229 | + self.timer = None | ||
| 230 | + | ||
| 231 | + self.edit.single = single | ||
| 232 | + self.edit.set_caption(('main', s or '?')) | ||
| 233 | + self.edit.set_edit_text('') | ||
| 234 | + # hide the text and display the edit widget | ||
| 235 | + if not self.edit in self.widget.widget_list: | ||
| 236 | + self.widget.widget_list.append(self.edit) | ||
| 237 | + if self.text in self.widget.widget_list: | ||
| 238 | + self.widget.widget_list.remove(self.text) | ||
| 239 | + self.widget.set_focus_column(0) | ||
| 199 | 240 | ||
| 200 | 241 | def settext(self, s, permanent=False): | |
| 201 | 242 | """Set the text on the status bar to a new value. If permanent is True, | |
| 202 | - the new value will be permanent.""" | ||
| 243 | + the new value will be permanent. If that status bar is in prompt mode, | ||
| 244 | + the prompt will be aborted. """ | ||
| 203 | 245 | ||
| 204 | 246 | if self.timer is not None: | |
| 205 | 247 | self.main_loop.remove_alarm(self.timer) | |
| 206 | 248 | self.timer = None | |
| 207 | 249 | ||
| 208 | - self.widget.set_text(('main', s)) | ||
| 250 | + # hide the edit and display the text widget | ||
| 251 | + if self.edit in self.widget.widget_list: | ||
| 252 | + self.widget.widget_list.remove(self.edit) | ||
| 253 | + if not self.text in self.widget.widget_list: | ||
| 254 | + self.widget.widget_list.append(self.text) | ||
| 255 | + | ||
| 256 | + self.text.set_text(('main', s)) | ||
| 209 | 257 | if permanent: | |
| 210 | 258 | self.s = s | |
| 211 | 259 | ||
| 212 | 260 | def clear(self): | |
| 213 | 261 | """Clear the status bar.""" | |
| 214 | 262 | self.settext('') | |
| 215 | 263 | ||
| 264 | + def _on_prompt_enter(self, edit, new_text): | ||
| 265 | + """Reset the statusbar and pass the input from the prompt to the caller | ||
| 266 | + via 'prompt_result'.""" | ||
| 267 | + self.settext(self.s) | ||
| 268 | + urwid.emit_signal(self, 'prompt_result', new_text) | ||
| 269 | + | ||
| 270 | + urwid.register_signal(Statusbar, 'prompt_result') | ||
| 271 | + | ||
| 216 | 272 | ||
| 217 | 273 | def decoding_input_filter(keys, raw): | |
| 218 | 274 | """Input filter for urwid which decodes each key with the locale's | |
@@ -269,7 +325,7 @@ def __init__(self, config, *args, **kwargs): | |||
| 269 | 325 | self._bpy_selectable = True | |
| 270 | 326 | self._bpy_may_move_cursor = False | |
| 271 | 327 | self.config = config | |
| 272 | - self.tab_length = config.tab_length | ||
| 328 | + self.tab_length = config.tab_length | ||
| 273 | 329 | urwid.Edit.__init__(self, *args, **kwargs) | |
| 274 | 330 | ||
| 275 | 331 | def set_edit_pos(self, pos): | |
@@ -353,9 +409,6 @@ def keypress(self, size, key): | |||
| 353 | 409 | self.set_edit_text(line[:-self.tab_length]) | |
| 354 | 410 | else: | |
| 355 | 411 | return urwid.Edit.keypress(self, size, key) | |
| 356 | - elif key == 'pastebin': | ||
| 357 | - # do pastebin | ||
| 358 | - pass | ||
| 359 | 412 | else: | |
| 360 | 413 | # TODO: Add in specific keypress fetching code here | |
| 361 | 414 | return urwid.Edit.keypress(self, size, key) | |
@@ -461,21 +514,40 @@ def render(self, size, focus=False): | |||
| 461 | 514 | return canvas | |
| 462 | 515 | ||
| 463 | 516 | class URWIDInteraction(repl.Interaction): | |
| 464 | - def __init__(self, config, statusbar=None): | ||
| 517 | + def __init__(self, config, statusbar, frame): | ||
| 465 | 518 | repl.Interaction.__init__(self, config, statusbar) | |
| 519 | + self.frame = frame | ||
| 520 | + urwid.connect_signal(statusbar, 'prompt_result', self._prompt_result) | ||
| 521 | + self.callback = None | ||
| 466 | 522 | ||
| 467 | - def confirm(self, q): | ||
| 468 | - """Ask for yes or no and return boolean""" | ||
| 469 | - try: | ||
| 470 | - reply = self.statusbar.prompt(q) | ||
| 471 | - except ValueError: | ||
| 472 | - return False | ||
| 523 | + def confirm(self, q, callback): | ||
| 524 | + """Ask for yes or no and call callback to return the result""" | ||
| 525 | + | ||
| 526 | + def callback_wrapper(result): | ||
| 527 | + callback(result.lower() in (_('y'), _('yes'))) | ||
| 473 | 528 | ||
| 474 | - return reply.lower() in (_('y'), _('yes')) | ||
| 529 | + self.prompt(q, callback_wrapper, single=True) | ||
| 475 | 530 | ||
| 476 | 531 | def notify(self, s, n=10): | |
| 477 | 532 | return self.statusbar.message(s, n) | |
| 478 | 533 | ||
| 534 | + def prompt(self, s, callback=None, single=False): | ||
| 535 | + """Prompt the user for input. The result will be returned via calling | ||
| 536 | + callback.""" | ||
| 537 | + | ||
| 538 | + if self.callback is not None: | ||
| 539 | + raise Exception('Prompt already in progress') | ||
| 540 | + | ||
| 541 | + self.callback = callback | ||
| 542 | + self.statusbar.prompt(s, single=single) | ||
| 543 | + self.frame.set_focus('footer') | ||
| 544 | + | ||
| 545 | + def _prompt_result(self, text): | ||
| 546 | + self.frame.set_focus('body') | ||
| 547 | + if self.callback is not None: | ||
| 548 | + self.callback(text) | ||
| 549 | + self.callback = None | ||
| 550 | + | ||
| 479 | 551 | ||
| 480 | 552 | class URWIDRepl(repl.Repl): | |
| 481 | 553 | ||
@@ -490,21 +562,12 @@ def __init__(self, event_loop, palette, interpreter, config): | |||
| 490 | 562 | ||
| 491 | 563 | self.listbox = BPythonListBox(urwid.SimpleListWalker([])) | |
| 492 | 564 | ||
| 493 | - # String is straight from bpython.cli | ||
| 494 | - self.statusbar = Statusbar(config, | ||
| 495 | - _(" <%s> Rewind <%s> Save <%s> Pastebin " | ||
| 496 | - " <%s> Pager <%s> Show Source ") % | ||
| 497 | - (config.undo_key, config.save_key, config.pastebin_key, | ||
| 498 | - config.last_output_key, config.show_source_key)) | ||
| 499 | - | ||
| 500 | - self.interact = URWIDInteraction(self.config, self.statusbar) | ||
| 501 | - | ||
| 502 | 565 | self.tooltip = urwid.ListBox(urwid.SimpleListWalker([])) | |
| 503 | 566 | self.tooltip.grid = None | |
| 504 | 567 | self.overlay = Tooltip(self.listbox, self.tooltip) | |
| 505 | 568 | self.stdout_hist = '' | |
| 506 | 569 | ||
| 507 | - self.frame = urwid.Frame(self.overlay, footer=self.statusbar.widget) | ||
| 570 | + self.frame = urwid.Frame(self.overlay) | ||
| 508 | 571 | ||
| 509 | 572 | if urwid.get_encoding_mode() == 'narrow': | |
| 510 | 573 | input_filter = decoding_input_filter | |
@@ -516,7 +579,15 @@ def __init__(self, event_loop, palette, interpreter, config): | |||
| 516 | 579 | self.frame, palette, | |
| 517 | 580 | event_loop=event_loop, unhandled_input=self.handle_input, | |
| 518 | 581 | input_filter=input_filter, handle_mouse=False) | |
| 519 | - self.statusbar.main_loop = self.main_loop | ||
| 582 | + | ||
| 583 | + # String is straight from bpython.cli | ||
| 584 | + self.statusbar = Statusbar(config, | ||
| 585 | + _(" <%s> Rewind <%s> Save <%s> Pastebin " | ||
| 586 | + " <%s> Pager <%s> Show Source ") % | ||
| 587 | + (config.undo_key, config.save_key, config.pastebin_key, | ||
| 588 | + config.last_output_key, config.show_source_key), self.main_loop) | ||
| 589 | + self.frame.set_footer(self.statusbar.widget) | ||
| 590 | + self.interact = URWIDInteraction(self.config, self.statusbar, self.frame) | ||
| 520 | 591 | ||
| 521 | 592 | self.edits = [] | |
| 522 | 593 | self.edit = None | |
@@ -899,6 +970,11 @@ def on_edit_pos_changed(self, edit, position): | |||
| 899 | 970 | edit.set_edit_markup(list(format_tokens(tokens))) | |
| 900 | 971 | ||
| 901 | 972 | def handle_input(self, event): | |
| 973 | + # Since most of the input handling here should be handled in the edit | ||
| 974 | + # instead, we return here early if the edit doesn't have the focus. | ||
| 975 | + if self.frame.get_focus() != 'body': | ||
| 976 | + return | ||
| 977 | + | ||
| 902 | 978 | if event == 'enter': | |
| 903 | 979 | inp = self.edit.get_edit_text() | |
| 904 | 980 | self.history.append(inp) | |
@@ -1189,6 +1265,7 @@ def load_urwid_command_map(config): | |||
| 1189 | 1265 | urwid.command_map[key_dispatch[config.down_one_line_key]] = 'cursor down' | |
| 1190 | 1266 | urwid.command_map[key_dispatch['C-a']] = 'cursor max left' | |
| 1191 | 1267 | urwid.command_map[key_dispatch['C-e']] = 'cursor max right' | |
| 1268 | + urwid.command_map[key_dispatch[config.pastebin_key]] = 'pastebin' | ||
| 1192 | 1269 | """ | |
| 1193 | 1270 | 'clear_line': 'C-u', | |
| 1194 | 1271 | 'clear_screen': 'C-l', | |
| Back | FazBrowse Home | New Git URL |
0 commit comments