Make yes/no questions work

This commit is contained in:
Florian Bruhin 2014-05-20 12:05:14 +02:00
parent f43549d452
commit cfd70e7821
4 changed files with 62 additions and 20 deletions

View File

@ -55,7 +55,8 @@ from qutebrowser.config.config import ConfigManager
from qutebrowser.keyinput.modeman import ModeManager
from qutebrowser.widgets.mainwindow import MainWindow
from qutebrowser.widgets.crash import ExceptionCrashDialog, FatalCrashDialog
from qutebrowser.keyinput.modeparsers import NormalKeyParser, HintKeyParser
from qutebrowser.keyinput.modeparsers import (NormalKeyParser, HintKeyParser,
PromptKeyParser)
from qutebrowser.keyinput.keyparser import PassthroughKeyParser
from qutebrowser.commands.managers import CommandManager, SearchManager
from qutebrowser.commands.exceptions import CommandError
@ -212,6 +213,7 @@ class QuteBrowser(QApplication):
'passthrough': PassthroughKeyParser('keybind.passthrough', self),
'command': PassthroughKeyParser('keybind.command', self),
'prompt': PassthroughKeyParser('keybind.prompt', self),
'yesno': PromptKeyParser(self),
}
self.modeman = ModeManager()
self.modeman.register('normal', self._keyparsers['normal'].handle)
@ -225,6 +227,7 @@ class QuteBrowser(QApplication):
passthrough=True)
self.modeman.register('prompt', self._keyparsers['prompt'].handle,
passthrough=True)
self.modeman.register('yesno', self._keyparsers['yesno'].handle)
def _init_log(self):
"""Initialisation of the logging output.

View File

@ -121,8 +121,13 @@ SECTION_DESC = {
" leave-mode: Leave the command mode."),
'keybind.prompt': (
"Keybindings for prompts in the status line.\n"
"You can bind normal keys in this mode, but they will be only active "
"when a yes/no-prompt is asked. For other prompt modes, you can only "
"bind special keys.\n"
"Useful hidden commands to map in this section:\n"
" prompt-accept: Confirm the entered value\n"
" prompt-accept: Confirm the entered value.\n"
" prompt-yes: Answer yes to a yes/no question.\n"
" prompt-no: Answer no to a yes/no question.\n"
" leave-mode: Leave the prompt mode."),
'aliases': (
"Aliases for commands.\n"
@ -701,6 +706,8 @@ DATA = OrderedDict([
('<Escape>', 'leave-mode'),
('<Ctrl-N>', 'leave-mode'),
('<Return>', 'prompt-accept'),
('y', 'prompt-yes'),
('n', 'prompt-no'),
)),
('aliases', sect.ValueList(

View File

@ -59,6 +59,17 @@ class NormalKeyParser(CommandKeyParser):
return super()._handle_single_key(e)
class PromptKeyParser(CommandKeyParser):
"""KeyParser for yes/no prompts."""
def __init__(self, parent=None):
super().__init__(parent, supports_count=False, supports_chains=True)
# We don't want an extra section for this in the config, so we just
# abuse the keybind.prompt section.
self.read_config('keybind.prompt')
class HintKeyParser(CommandKeyParser):
"""KeyChainParser for hints.

View File

@ -22,6 +22,7 @@ from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit
import qutebrowser.keyinput.modeman as modeman
import qutebrowser.commands.utils as cmdutils
import qutebrowser.config.config as config
from qutebrowser.widgets.statusbar._textbase import TextBase
from qutebrowser.widgets.misc import MinimalLineEdit
from qutebrowser.utils.usertypes import PromptMode, Question
@ -36,7 +37,7 @@ class Prompt(QWidget):
loop: A local QEventLoop to spin in exec_.
_hbox: The QHBoxLayout used to display the text and prompt.
_txt: The TextBase instance (QLabel) used to display the prompt text.
_input: The QueryInput instance (QLineEdit) used for the input.
_input: The MinimalLineEdit instance (QLineEdit) used for the input.
Signals:
show_prompt: Emitted when the prompt widget wants to be shown.
@ -61,7 +62,7 @@ class Prompt(QWidget):
self._txt = TextBase()
self._hbox.addWidget(self._txt)
self._input = _QueryInput()
self._input = MinimalLineEdit()
self._hbox.addWidget(self._input)
def on_mode_left(self, mode):
@ -71,7 +72,7 @@ class Prompt(QWidget):
cancelled: Emitted when the mode was forcibly left by the user
without answering the question.
"""
if mode == 'prompt':
if mode in ['prompt', 'yesno']:
self._txt.setText('')
self._input.clear()
self._input.setEchoMode(QLineEdit.Normal)
@ -100,10 +101,36 @@ class Prompt(QWidget):
self.question.answer = (self.question.user, password)
modeman.leave('prompt', 'prompt accept')
self.hide_prompt.emit()
else:
# User just entered all information needed in some other mode.
elif self.question.mode == PromptMode.text:
# User just entered text.
self.question.answer = self._input.text()
modeman.leave('prompt', 'prompt accept')
elif self.question.mode == PromptMode.yesno:
# User wants to accept the default of a yes/no question.
self.question.answer = self.question.default
modeman.leave('yesno', 'yesno accept')
else:
raise ValueError("Invalid question mode!")
@cmdutils.register(instance='mainwindow.status.prompt', hide=True,
modes=['yesno'])
def prompt_yes(self):
"""Answer yes to a yes/no prompt."""
if self.question.mode != PromptMode.yesno:
# We just ignore this if we don't have a yes/no question.
return
self.question.answer = True
modeman.leave('yesno', 'yesno accept')
@cmdutils.register(instance='mainwindow.status.prompt', hide=True,
modes=['yesno'])
def prompt_no(self):
"""Answer no to a yes/no prompt."""
if self.question.mode != PromptMode.yesno:
# We just ignore this if we don't have a yes/no question.
return
self.question.answer = False
modeman.leave('yesno', 'prompt accept')
def display(self):
"""Display the question in self.question in the widget.
@ -114,27 +141,31 @@ class Prompt(QWidget):
q = self.question
if q.mode == PromptMode.yesno:
if q.default is None:
suffix = " [y/n]"
suffix = ""
elif q.default:
suffix = " [Y/n]"
suffix = " (yes)"
else:
suffix = " [y/N]"
suffix = " (no)"
self._txt.setText(q.text + suffix)
self._input.hide()
mode = 'yesno'
elif q.mode == PromptMode.text:
self._txt.setText(q.text)
if q.default:
self._input.setText(q.default)
self._input.show()
mode = 'prompt'
elif q.mode == PromptMode.user_pwd:
self._txt.setText(q.text)
if q.default:
self._input.setText(q.default)
self._input.show()
mode = 'prompt'
else:
raise ValueError("Invalid prompt mode!")
self._input.setFocus()
self.show_prompt.emit()
modeman.enter(mode, 'question asked')
@pyqtSlot(Question, bool)
def ask_question(self, question, blocking):
@ -163,13 +194,3 @@ class Prompt(QWidget):
self.cancelled.connect(self.loop.quit)
self.loop.exec_()
return self.question.answer
class _QueryInput(MinimalLineEdit):
"""QLineEdit used for input."""
def focusInEvent(self, e):
"""Extend focusInEvent to enter command mode."""
modeman.enter('prompt', 'auth focus')
super().focusInEvent(e)