diff options
author | Patrick Totzke <patricktotzke@gmail.com> | 2011-09-10 21:36:22 +0100 |
---|---|---|
committer | Patrick Totzke <patricktotzke@gmail.com> | 2011-09-10 21:36:22 +0100 |
commit | 2ad71567def4409aef2d5f2145f879f41834cf44 (patch) | |
tree | 3e447d2a13aa387ac55536f0d8b1ffd1e17b0d88 | |
parent | 4b77957e590cdb16e34e734a80ad7faad153b8d6 (diff) | |
parent | d9cc7c847c6a50bdd0e51ad50a9dead4805688e6 (diff) |
Merge branch 'prompt' into develop
-rw-r--r-- | alot/command.py | 15 | ||||
-rw-r--r-- | alot/ui.py | 93 | ||||
-rw-r--r-- | alot/widgets.py | 25 |
3 files changed, 70 insertions, 63 deletions
diff --git a/alot/command.py b/alot/command.py index 3111f2cd..407634e6 100644 --- a/alot/command.py +++ b/alot/command.py @@ -34,6 +34,7 @@ from email.message import Message from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import urwid +from twisted.internet import defer import buffer import settings @@ -354,6 +355,7 @@ class ComposeCommand(Command): for key, value in headers.items(): self.mail[key] = encode_header(key, value) + @defer.inlineCallbacks def apply(self, ui): # TODO: fill with default header (per account) # get From header @@ -366,11 +368,11 @@ class ComposeCommand(Command): a = accounts[0] else: cmpl = AccountCompleter(ui.accountman) - fromaddress = ui.prompt(prefix='From>', completer=cmpl, tab=1) + fromaddress = yield ui.prompt(prefix='From>', completer=cmpl, tab=1) validaddresses = [a.address for a in accounts] + [None] while fromaddress not in validaddresses: # TODO: not cool ui.notify('no account for this address. (<esc> cancels)') - fromaddress = ui.prompt(prefix='From>', completer=cmpl) + fromaddress = yield ui.prompt(prefix='From>', completer=cmpl) if not fromaddress: ui.notify('canceled') return @@ -379,7 +381,7 @@ class ComposeCommand(Command): #get To header if 'To' not in self.mail: - to = ui.prompt(prefix='To>', + to = yield ui.prompt(prefix='To>', completer=ContactsCompleter(ui.accountman)) if to == None: ui.notify('canceled') @@ -387,7 +389,7 @@ class ComposeCommand(Command): self.mail['To'] = encode_header('to', to) if settings.config.getboolean('general', 'ask_subject') and \ not 'Subject' in self.mail: - subject = ui.prompt(prefix='Subject>') + subject = yield ui.prompt(prefix='Subject>') if subject == None: ui.notify('canceled') return @@ -728,12 +730,13 @@ class SaveAttachmentCommand(Command): self.all = all self.path = path + @defer.inlineCallbacks def apply(self, ui): pcomplete = completion.PathCompleter() if self.all: msg = ui.current_buffer.get_selected_message() if not self.path: - self.path = ui.prompt(prefix='save attachments to:', + self.path = yield ui.prompt(prefix='save attachments to:', text=os.path.join('~', ''), completer=pcomplete) if self.path: @@ -752,7 +755,7 @@ class SaveAttachmentCommand(Command): attachment = focus.get_attachment() filename = attachment.get_filename() if not self.path: - self.path = ui.prompt(prefix='save attachment as:', + self.path = yield ui.prompt(prefix='save attachment as:', text=os.path.join('~', filename), completer=pcomplete) if self.path: @@ -19,6 +19,7 @@ Copyright (C) 2011 Patrick Totzke <patricktotzke@gmail.com> import urwid import os from urwid.command_map import command_map +from twisted.internet import defer from settings import config from buffer import BufferlistBuffer @@ -30,7 +31,7 @@ from completion import CommandLineCompleter class MainWidget(urwid.Frame): def __init__(self, ui, *args, **kwargs): - urwid.Frame.__init__(self, urwid.SolidFill(' '), *args, **kwargs) + urwid.Frame.__init__(self, urwid.SolidFill(), *args, **kwargs) self.ui = ui def keypress(self, size, key): @@ -61,6 +62,7 @@ class UI: self.mainloop = urwid.MainLoop(self.mainframe, config.get_palette(), handle_mouse=False, + event_loop=urwid.TwistedEventLoop(), unhandled_input=self.keypress) self.mainloop.screen.set_terminal_properties(colors=colourmode) @@ -91,59 +93,41 @@ class UI: :type tab: int :param history: history to be used for up/down keys :type history: list of str + :returns: a `twisted.defer.Deferred` """ - self.logger.info('open prompt') - history = list(history) # make a local copy - historypos = None + d = defer.Deferred() # create return deferred + main = self.mainloop.widget # save main widget + + def select_or_cancel(text): + self.mainloop.widget = main # restore main screen + d.callback(text) + + #set up widgets leftpart = urwid.Text(prefix, align='left') - if completer: - editpart = CompleteEdit(completer, edit_text=text) - for i in range(tab): - editpart.keypress((0,), 'tab') - else: - editpart = urwid.Edit(edit_text=text) + editpart = CompleteEdit(completer, on_exit=select_or_cancel, + edit_text=text, history=history) + + for i in range(tab): # hit some tabs + editpart.keypress((0,), 'tab') + + # build promptwidget both = urwid.Columns( [ ('fixed', len(prefix), leftpart), ('weight', 1, editpart), ]) prompt_widget = urwid.AttrMap(both, 'prompt', 'prompt') - footer = self.mainframe.get_footer() - self.mainframe.set_footer(prompt_widget) - self.mainframe.set_focus('footer') - self.mainloop.draw_screen() - while True: - keys = None - while not keys: - keys = self.mainloop.screen.get_input() - for key in keys: - self.logger.debug('prompt got key: %s' % key) - if command_map[key] == 'select': - self.mainframe.set_footer(footer) - self.mainframe.set_focus('body') - return editpart.get_edit_text() - elif command_map[key] == 'cancel': - self.mainframe.set_footer(footer) - self.mainframe.set_focus('body') - return None - elif key in ['up', 'down']: - if history: - if historypos == None: - history.append(editpart.get_edit_text()) - historypos = len(history) - 1 - if key == 'cursor up': - historypos = (historypos - 1) % len(history) - else: - historypos = (historypos + 1) % len(history) - editpart.set_edit_text(history[historypos]) - self.mainloop.draw_screen() - - else: - size = (20,) # don't know why they want a size here - editpart.keypress(size, key) - self.mainloop.draw_screen() + # put promptwidget as overlay on main widget + overlay = urwid.Overlay(both, main, + ('fixed left', 0), + ('fixed right', 0), + ('fixed bottom', 1), + None) + self.mainloop.widget = overlay + return d # return deferred + @defer.inlineCallbacks def commandprompt(self, startstring): """prompt for a commandline and interpret/apply it upon enter @@ -152,15 +136,15 @@ class UI: """ self.logger.info('open command shell') mode = self.current_buffer.typename - cmdline = self.prompt(prefix=':', + cmdline = yield self.prompt(prefix=':', text=startstring, completer=CommandLineCompleter(self.dbman, self.accountman, mode), history=self.commandprompthistory, ) - if cmdline: - self.interpret_commandline(cmdline) + self.logger.debug('CMDLINE: %s' % cmdline) + self.interpret_commandline(cmdline) def interpret_commandline(self, cmdline): """interpret and apply a commandstring @@ -168,13 +152,14 @@ class UI: :param cmdline: command string to apply :type cmdline: str """ - mode = self.current_buffer.typename - self.commandprompthistory.append(cmdline) - cmd = interpret_commandline(cmdline, mode) - if cmd: - self.apply_command(cmd) - else: - self.notify('invalid command') + if cmdline: + mode = self.current_buffer.typename + self.commandprompthistory.append(cmdline) + cmd = interpret_commandline(cmdline, mode) + if cmd: + self.apply_command(cmd) + else: + self.notify('invalid command') def buffer_open(self, b): """ diff --git a/alot/widgets.py b/alot/widgets.py index 4fe7439b..a5b08673 100644 --- a/alot/widgets.py +++ b/alot/widgets.py @@ -63,7 +63,7 @@ class ThreadlineWidget(urwid.AttrMap): authors = self.thread.get_authors() or '(None)' maxlength = config.getint('general', 'authors_maxlength') - authorsstring = shorten(authors, maxlength).strip() + authorsstring = shorten(authors, maxlength) self.authors_w = urwid.AttrMap(urwid.Text(authorsstring), 'threadline_authors') cols.append(('fixed', len(authorsstring), self.authors_w)) @@ -167,8 +167,13 @@ class TagWidget(urwid.AttrMap): class CompleteEdit(urwid.Edit): - def __init__(self, completer, edit_text=u'', **kwargs): + def __init__(self, completer, on_exit, edit_text=u'', + history=None, **kwargs): self.completer = completer + self.on_exit = on_exit + self.history = list(history) # we temporarily add stuff here + self.historypos = None + if not isinstance(edit_text, unicode): edit_text = unicode(edit_text, errors='replace') self.start_completion_pos = len(edit_text) @@ -178,7 +183,7 @@ class CompleteEdit(urwid.Edit): def keypress(self, size, key): cmd = command_map[key] # if we tabcomplete - if cmd in ['next selectable', 'prev selectable']: + if cmd in ['next selectable', 'prev selectable'] and self.completer: # if not already in completion mode if not self.completions: self.completions = [(self.edit_text, self.edit_pos)] + \ @@ -199,6 +204,20 @@ class CompleteEdit(urwid.Edit): if self.edit_pos >= len(self.edit_text): self.edit_text += ' ' self.completions = None + elif key in ['up', 'down']: + if self.history: + if self.historypos == None: + self.history.append(self.edit_text) + self.historypos = len(self.history) - 1 + if key == 'cursor up': + self.historypos = (self.historypos + 1) % len(self.history) + else: + self.historypos = (self.historypos - 1) % len(self.history) + self.set_edit_text(self.history[self.historypos]) + elif cmd == 'select': + self.on_exit(self.edit_text) + elif cmd == 'cancel': + self.on_exit(None) else: result = urwid.Edit.keypress(self, size, key) self.completions = None |