From 7a149db6cfe00e77aa2c8037dfd1b63358b98e9b Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Fri, 29 Apr 2016 19:16:29 -0500 Subject: [PATCH] Show potential completions When entering multi-key commands, display potential completions in the status bar as a reminder to the user. Change-Id: I498781576a60789b0f810f08cbc9c8c74d52784f --- gertty/app.py | 32 ++++++++++++++++++----- gertty/keymap.py | 19 ++++++++++++++ gertty/view/change.py | 52 +++++++++++++++++++------------------ gertty/view/change_list.py | 42 ++++++++++++++++-------------- gertty/view/diff.py | 14 ++++++---- gertty/view/project_list.py | 30 +++++++++++---------- 6 files changed, 120 insertions(+), 69 deletions(-) diff --git a/gertty/app.py b/gertty/app.py index 645c427..447399e 100644 --- a/gertty/app.py +++ b/gertty/app.py @@ -465,18 +465,24 @@ class App(object): self.screens.append(self.frame.body) self.frame.body = overlay + def getGlobalCommands(self): + return list(mywid.GLOBAL_HELP) + + def getGlobalHelp(self): + keys = [(k, self.config.keymap.formatKeys(k), t) for (k, t) in self.getGlobalCommands()] + for d in self.config.dashboards.values(): + keys.append(('', d['key'], d['name'])) + return keys + def help(self): if not hasattr(self.frame.body, 'help'): return - global_help = [(self.config.keymap.formatKeys(k), t) - for (k, t) in mywid.GLOBAL_HELP] - for d in self.config.dashboards.values(): - global_help.append((keymap.formatKey(d['key']), d['name'])) + global_help = self.getGlobalHelp() parts = [('Global Keys', global_help), ('This Screen', self.frame.body.help())] keylen = 0 for title, items in parts: - for keys, text in items: + for cmd, keys, text in items: keylen = max(len(keys), keylen) text = '' for title, items in parts: @@ -484,7 +490,7 @@ class App(object): text += '\n' text += title+'\n' text += '%s\n' % ('='*len(title),) - for keys, cmdtext in items: + for cmd, keys, cmdtext in items: text += '{keys:{width}} {text}\n'.format( keys=keys, width=keylen, text=cmdtext) dialog = mywid.MessageDialog('Help for %s' % version(), text) @@ -675,7 +681,19 @@ class App(object): self.changeScreen(view) elif keymap.FURTHER_INPUT in commands: self.input_buffer.append(key) - self.status.update(message=''.join(self.input_buffer)) + msg = ''.join(self.input_buffer) + commands = dict(self.getGlobalCommands()) + if hasattr(self.frame.body, 'getCommands'): + commands.update(dict(self.frame.body.getCommands())) + further_commands = self.config.keymap.getFurtherCommands(keys) + completions = [] + for (key, cmds) in further_commands: + for cmd in cmds: + if cmd in commands: + completions.append(key) + completions = ' '.join(completions) + msg = '%s: %s' % (msg, completions) + self.status.update(message=msg) return self.clearInputBuffer() diff --git a/gertty/keymap.py b/gertty/keymap.py index c0fe4cb..56c380f 100644 --- a/gertty/keymap.py +++ b/gertty/keymap.py @@ -250,6 +250,25 @@ class KeyMap(object): ret.append(FURTHER_INPUT) return ret + def getFurtherCommands(self, keys): + if not keys: + return [] + tree = self.keytree + for key in keys: + tree = tree.keys.get(key) + if not tree: + return [] + return self._getFurtherCommands('', tree) + + def _getFurtherCommands(self, keys, tree): + if keys: + ret = [(formatKey(keys), tree.commands[:])] + else: + ret = [] + for subtree in tree.keys.values(): + ret.extend(self._getFurtherCommands(keys + subtree.key, subtree)) + return ret + def getKeys(self, command): return self.commandmap.get(command, []) diff --git a/gertty/view/change.py b/gertty/view/change.py index c4bfb2a..c0a62ee 100644 --- a/gertty/view/change.py +++ b/gertty/view/change.py @@ -385,55 +385,57 @@ class CommitMessageBox(mywid.HyperText): @mouse_scroll_decorator.ScrollByWheel class ChangeView(urwid.WidgetWrap): - def help(self): - key = self.app.config.keymap.formatKeys - ret = [ - (key(keymap.LOCAL_CHECKOUT), + def getCommands(self): + return [ + (keymap.LOCAL_CHECKOUT, "Checkout the most recent revision into the local repo"), - (key(keymap.DIFF), + (keymap.DIFF, "Show the diff of the most recent revision"), - (key(keymap.TOGGLE_HIDDEN), + (keymap.TOGGLE_HIDDEN, "Toggle the hidden flag for the current change"), - (key(keymap.NEXT_CHANGE), + (keymap.NEXT_CHANGE, "Go to the next change in the list"), - (key(keymap.PREV_CHANGE), + (keymap.PREV_CHANGE, "Go to the previous change in the list"), - (key(keymap.REVIEW), + (keymap.REVIEW, "Leave a review for the most recent revision"), - (key(keymap.TOGGLE_HELD), + (keymap.TOGGLE_HELD, "Toggle the held flag for the current change"), - (key(keymap.TOGGLE_HIDDEN_COMMENTS), + (keymap.TOGGLE_HIDDEN_COMMENTS, "Toggle display of hidden comments"), - (key(keymap.SEARCH_RESULTS), + (keymap.SEARCH_RESULTS, "Back to the list of changes"), - (key(keymap.TOGGLE_REVIEWED), + (keymap.TOGGLE_REVIEWED, "Toggle the reviewed flag for the current change"), - (key(keymap.TOGGLE_STARRED), + (keymap.TOGGLE_STARRED, "Toggle the starred flag for the current change"), - (key(keymap.LOCAL_CHERRY_PICK), + (keymap.LOCAL_CHERRY_PICK, "Cherry-pick the most recent revision onto the local repo"), - (key(keymap.ABANDON_CHANGE), + (keymap.ABANDON_CHANGE, "Abandon this change"), - (key(keymap.EDIT_COMMIT_MESSAGE), + (keymap.EDIT_COMMIT_MESSAGE, "Edit the commit message of this change"), - (key(keymap.REBASE_CHANGE), + (keymap.REBASE_CHANGE, "Rebase this change (remotely)"), - (key(keymap.RESTORE_CHANGE), + (keymap.RESTORE_CHANGE, "Restore this change"), - (key(keymap.REFRESH), + (keymap.REFRESH, "Refresh this change"), - (key(keymap.EDIT_TOPIC), + (keymap.EDIT_TOPIC, "Edit the topic of this change"), - (key(keymap.SUBMIT_CHANGE), + (keymap.SUBMIT_CHANGE, "Submit this change"), - (key(keymap.CHERRY_PICK_CHANGE), + (keymap.CHERRY_PICK_CHANGE, "Propose this change to another branch"), ] + def help(self): + key = self.app.config.keymap.formatKeys + commands = self.getCommands() + ret = [(c[0], key(c[0]), c[1]) for c in commands] for k in self.app.config.reviewkeys.values(): action = ', '.join(['{category}:{value}'.format(**a) for a in k['approvals']]) - ret.append((keymap.formatKey(k['key']), action)) - + ret.append(('', keymap.formatKey(k['key']), action)) return ret def __init__(self, app, change_key): diff --git a/gertty/view/change_list.py b/gertty/view/change_list.py index e229133..19868cf 100644 --- a/gertty/view/change_list.py +++ b/gertty/view/change_list.py @@ -209,49 +209,53 @@ class ChangeListView(urwid.WidgetWrap): required_columns = set(['Number', 'Subject', 'Updated']) optional_columns = set(['Topic', 'Branch']) - def help(self): - key = self.app.config.keymap.formatKeys + def getCommands(self): if self.project_key: refresh_help = "Sync current project" else: refresh_help = "Sync subscribed projects" return [ - (key(keymap.TOGGLE_HELD), + (keymap.TOGGLE_HELD, "Toggle the held flag for the currently selected change"), - (key(keymap.LOCAL_CHECKOUT), + (keymap.LOCAL_CHECKOUT, "Checkout the most recent revision of the selected change into the local repo"), - (key(keymap.TOGGLE_HIDDEN), + (keymap.TOGGLE_HIDDEN, "Toggle the hidden flag for the currently selected change"), - (key(keymap.TOGGLE_LIST_REVIEWED), + (keymap.TOGGLE_LIST_REVIEWED, "Toggle whether only unreviewed or all changes are displayed"), - (key(keymap.TOGGLE_REVIEWED), + (keymap.TOGGLE_REVIEWED, "Toggle the reviewed flag for the currently selected change"), - (key(keymap.TOGGLE_STARRED), + (keymap.TOGGLE_STARRED, "Toggle the starred flag for the currently selected change"), - (key(keymap.TOGGLE_MARK), + (keymap.TOGGLE_MARK, "Toggle the process mark for the currently selected change"), - (key(keymap.REFINE_CHANGE_SEARCH), + (keymap.REFINE_CHANGE_SEARCH, "Refine the current search query"), - (key(keymap.ABANDON_CHANGE), + (keymap.ABANDON_CHANGE, "Abandon the marked changes"), - (key(keymap.EDIT_TOPIC), + (keymap.EDIT_TOPIC, "Set the topic of the marked changes"), - (key(keymap.RESTORE_CHANGE), + (keymap.RESTORE_CHANGE, "Restore the marked changes"), - (key(keymap.REFRESH), + (keymap.REFRESH, refresh_help), - (key(keymap.REVIEW), + (keymap.REVIEW, "Leave reviews for the marked changes"), - (key(keymap.SORT_BY_NUMBER), + (keymap.SORT_BY_NUMBER, "Sort changes by number"), - (key(keymap.SORT_BY_UPDATED), + (keymap.SORT_BY_UPDATED, "Sort changes by how recently the change was updated"), - (key(keymap.SORT_BY_REVERSE), + (keymap.SORT_BY_REVERSE, "Reverse the sort"), - (key(keymap.LOCAL_CHERRY_PICK), + (keymap.LOCAL_CHERRY_PICK, "Cherry-pick the most recent revision of the selected change onto the local repo"), ] + def help(self): + key = self.app.config.keymap.formatKeys + commands = self.getCommands() + return [(c[0], key(c[0]), c[1]) for c in commands] + def __init__(self, app, query, query_desc=None, project_key=None, unreviewed=False, sort_by=None, reverse=None): super(ChangeListView, self).__init__(urwid.Pile([])) diff --git a/gertty/view/diff.py b/gertty/view/diff.py index 483f06d..1bb7cde 100644 --- a/gertty/view/diff.py +++ b/gertty/view/diff.py @@ -157,17 +157,21 @@ class DiffContextButton(urwid.WidgetWrap): @mouse_scroll_decorator.ScrollByWheel class BaseDiffView(urwid.WidgetWrap): - def help(self): - key = self.app.config.keymap.formatKeys + def getCommands(self): return [ - (key(keymap.ACTIVATE), + (keymap.ACTIVATE, "Add an inline comment"), - (key(keymap.SELECT_PATCHSETS), + (keymap.SELECT_PATCHSETS, "Select old/new patchsets to diff"), - (key(keymap.INTERACTIVE_SEARCH), + (keymap.INTERACTIVE_SEARCH, "Interactive search"), ] + def help(self): + key = self.app.config.keymap.formatKeys + commands = self.getCommands() + return [(c[0], key(c[0]), c[1]) for c in commands] + def __init__(self, app, new_revision_key): super(BaseDiffView, self).__init__(urwid.Pile([])) self.log = logging.getLogger('gertty.view.diff') diff --git a/gertty/view/project_list.py b/gertty/view/project_list.py index d102fa3..1a80277 100644 --- a/gertty/view/project_list.py +++ b/gertty/view/project_list.py @@ -199,33 +199,37 @@ class ProjectListHeader(urwid.WidgetWrap): @mouse_scroll_decorator.ScrollByWheel class ProjectListView(urwid.WidgetWrap): - def help(self): - key = self.app.config.keymap.formatKeys + def getCommands(self): return [ - (key(keymap.TOGGLE_LIST_SUBSCRIBED), + (keymap.TOGGLE_LIST_SUBSCRIBED, "Toggle whether only subscribed projects or all projects are listed"), - (key(keymap.TOGGLE_LIST_REVIEWED), + (keymap.TOGGLE_LIST_REVIEWED, "Toggle listing of projects with unreviewed changes"), - (key(keymap.TOGGLE_SUBSCRIBED), + (keymap.TOGGLE_SUBSCRIBED, "Toggle the subscription flag for the selected project"), - (key(keymap.REFRESH), + (keymap.REFRESH, "Sync subscribed projects"), - (key(keymap.TOGGLE_MARK), + (keymap.TOGGLE_MARK, "Toggle the process mark for the selected project"), - (key(keymap.NEW_PROJECT_TOPIC), + (keymap.NEW_PROJECT_TOPIC, "Create project topic"), - (key(keymap.DELETE_PROJECT_TOPIC), + (keymap.DELETE_PROJECT_TOPIC, "Delete selected project topic"), - (key(keymap.MOVE_PROJECT_TOPIC), + (keymap.MOVE_PROJECT_TOPIC, "Move selected project to topic"), - (key(keymap.COPY_PROJECT_TOPIC), + (keymap.COPY_PROJECT_TOPIC, "Copy selected project to topic"), - (key(keymap.REMOVE_PROJECT_TOPIC), + (keymap.REMOVE_PROJECT_TOPIC, "Remove selected project from topic"), - (key(keymap.RENAME_PROJECT_TOPIC), + (keymap.RENAME_PROJECT_TOPIC, "Rename selected project topic"), ] + def help(self): + key = self.app.config.keymap.formatKeys + commands = self.getCommands() + return [(c[0], key(c[0]), c[1]) for c in commands] + def __init__(self, app): super(ProjectListView, self).__init__(urwid.Pile([])) self.log = logging.getLogger('gertty.view.project_list')