Merge https://github.com/The-Compiler/qutebrowser into clip
Also make it possible to use multiple variables in one argument.
This commit is contained in:
commit
ebfe23c376
@ -44,6 +44,17 @@ Changed
|
|||||||
(i.e. to open it at the position it would be opened if it was a clicked link)
|
(i.e. to open it at the position it would be opened if it was a clicked link)
|
||||||
- `:download-open` and `:prompt-open-download` now have an optional `cmdline`
|
- `:download-open` and `:prompt-open-download` now have an optional `cmdline`
|
||||||
argument to pass a commandline to open the download with.
|
argument to pass a commandline to open the download with.
|
||||||
|
- `:yank` now has a position argument to select what to yank instead of using
|
||||||
|
flags.
|
||||||
|
- Replacements like `{url}` can now also be used in the middle of an argument.
|
||||||
|
Consequently, commands taking another command (`:later`, `:repeat` and
|
||||||
|
`:bind`) now don't immediately evaluate variables.
|
||||||
|
|
||||||
|
Removed
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
- The `:yank-selected` command got merged into `:yank` as `:yank selection`
|
||||||
|
and thus removed.
|
||||||
|
|
||||||
v0.8.3 (unreleased)
|
v0.8.3 (unreleased)
|
||||||
-------------------
|
-------------------
|
||||||
@ -52,6 +63,7 @@ Fixed
|
|||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
- Fixed crash when doing `:<space><enter>`, another corner-case introduced in v0.8.0
|
- Fixed crash when doing `:<space><enter>`, another corner-case introduced in v0.8.0
|
||||||
|
- Fixed `:open-editor` (`<Ctrl-e>`) on Windows
|
||||||
|
|
||||||
v0.8.2
|
v0.8.2
|
||||||
------
|
------
|
||||||
|
@ -146,13 +146,13 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* Lamar Pavel
|
* Lamar Pavel
|
||||||
* Bruno Oliveira
|
* Bruno Oliveira
|
||||||
* Alexander Cogneau
|
* Alexander Cogneau
|
||||||
|
* Marshall Lochbaum
|
||||||
* Felix Van der Jeugt
|
* Felix Van der Jeugt
|
||||||
* Jakub Klinkovský
|
* Jakub Klinkovský
|
||||||
* Martin Tournoij
|
* Martin Tournoij
|
||||||
* Marshall Lochbaum
|
* Jan Verbeek
|
||||||
* Raphael Pierzina
|
* Raphael Pierzina
|
||||||
* Joel Torstensson
|
* Joel Torstensson
|
||||||
* Jan Verbeek
|
|
||||||
* Patric Schmitz
|
* Patric Schmitz
|
||||||
* Tarcisio Fedrizzi
|
* Tarcisio Fedrizzi
|
||||||
* Claude
|
* Claude
|
||||||
|
@ -65,8 +65,7 @@
|
|||||||
|<<undo,undo>>|Re-open a closed tab (optionally skipping [count] closed tabs).
|
|<<undo,undo>>|Re-open a closed tab (optionally skipping [count] closed tabs).
|
||||||
|<<view-source,view-source>>|Show the source of the current page.
|
|<<view-source,view-source>>|Show the source of the current page.
|
||||||
|<<wq,wq>>|Save open pages and quit.
|
|<<wq,wq>>|Save open pages and quit.
|
||||||
|<<yank,yank>>|Yank the current URL/title to the clipboard or primary selection.
|
|<<yank,yank>>|Yank something to the clipboard or primary selection.
|
||||||
|<<yank-selected,yank-selected>>|Yank the selected text to the clipboard or primary selection.
|
|
||||||
|<<zoom,zoom>>|Set the zoom level for the current tab.
|
|<<zoom,zoom>>|Set the zoom level for the current tab.
|
||||||
|<<zoom-in,zoom-in>>|Increase the zoom level for the current tab.
|
|<<zoom-in,zoom-in>>|Increase the zoom level for the current tab.
|
||||||
|<<zoom-out,zoom-out>>|Decrease the zoom level for the current tab.
|
|<<zoom-out,zoom-out>>|Decrease the zoom level for the current tab.
|
||||||
@ -110,6 +109,7 @@ Bind a key to a command.
|
|||||||
==== note
|
==== note
|
||||||
* This command does not split arguments after the last argument and handles quotes literally.
|
* This command does not split arguments after the last argument and handles quotes literally.
|
||||||
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
||||||
|
* This command does not replace variables like +\{url\}+.
|
||||||
|
|
||||||
[[bookmark-add]]
|
[[bookmark-add]]
|
||||||
=== bookmark-add
|
=== bookmark-add
|
||||||
@ -424,6 +424,7 @@ Execute a command after some time.
|
|||||||
==== note
|
==== note
|
||||||
* This command does not split arguments after the last argument and handles quotes literally.
|
* This command does not split arguments after the last argument and handles quotes literally.
|
||||||
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
||||||
|
* This command does not replace variables like +\{url\}+.
|
||||||
|
|
||||||
[[messages]]
|
[[messages]]
|
||||||
=== messages
|
=== messages
|
||||||
@ -579,6 +580,7 @@ Repeat a given command.
|
|||||||
==== note
|
==== note
|
||||||
* This command does not split arguments after the last argument and handles quotes literally.
|
* This command does not split arguments after the last argument and handles quotes literally.
|
||||||
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
|
||||||
|
* This command does not replace variables like +\{url\}+.
|
||||||
|
|
||||||
[[report]]
|
[[report]]
|
||||||
=== report
|
=== report
|
||||||
@ -840,25 +842,25 @@ Save open pages and quit.
|
|||||||
|
|
||||||
[[yank]]
|
[[yank]]
|
||||||
=== yank
|
=== yank
|
||||||
Syntax: +:yank [*--title*] [*--sel*] [*--domain*] [*--pretty*]+
|
Syntax: +:yank [*--sel*] [*--keep*] ['what']+
|
||||||
|
|
||||||
Yank the current URL/title to the clipboard or primary selection.
|
Yank something to the clipboard or primary selection.
|
||||||
|
|
||||||
|
==== positional arguments
|
||||||
|
* +'what'+: What to yank.
|
||||||
|
|
||||||
|
- `url`: The current URL.
|
||||||
|
- `pretty-url`: The URL in pretty decoded form.
|
||||||
|
- `title`: The current page's title.
|
||||||
|
- `domain`: The current scheme, domain, and port number.
|
||||||
|
- `selection`: The selection under the cursor.
|
||||||
|
|
||||||
==== optional arguments
|
|
||||||
* +*-t*+, +*--title*+: Yank the title instead of the URL.
|
|
||||||
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
|
|
||||||
* +*-d*+, +*--domain*+: Yank only the scheme, domain, and port number.
|
|
||||||
* +*-p*+, +*--pretty*+: Yank the URL in pretty decoded form.
|
|
||||||
|
|
||||||
[[yank-selected]]
|
|
||||||
=== yank-selected
|
|
||||||
Syntax: +:yank-selected [*--sel*] [*--keep*]+
|
|
||||||
|
|
||||||
Yank the selected text to the clipboard or primary selection.
|
|
||||||
|
|
||||||
==== optional arguments
|
==== optional arguments
|
||||||
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
|
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
|
||||||
* +*-k*+, +*--keep*+: If given, stay in visual mode after yanking.
|
* +*-k*+, +*--keep*+: Stay in visual mode after yanking the selection.
|
||||||
|
|
||||||
[[zoom]]
|
[[zoom]]
|
||||||
=== zoom
|
=== zoom
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
pip==8.1.2
|
pip==8.1.2
|
||||||
setuptools==25.1.4
|
setuptools==25.1.6
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
pluggy==0.3.1
|
pluggy==0.3.1
|
||||||
py==1.4.31
|
py==1.4.31
|
||||||
tox==2.3.1
|
tox==2.3.1
|
||||||
virtualenv==15.0.2
|
virtualenv==15.0.3
|
||||||
|
@ -645,30 +645,44 @@ class CommandDispatcher:
|
|||||||
"representation.")
|
"representation.")
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
def yank(self, title=False, sel=False, domain=False, pretty=False):
|
@cmdutils.argument('what', choices=['selection', 'url', 'pretty-url',
|
||||||
"""Yank the current URL/title to the clipboard or primary selection.
|
'title', 'domain'])
|
||||||
|
def yank(self, what='url', sel=False, keep=False):
|
||||||
|
"""Yank something to the clipboard or primary selection.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
what: What to yank.
|
||||||
|
|
||||||
|
- `url`: The current URL.
|
||||||
|
- `pretty-url`: The URL in pretty decoded form.
|
||||||
|
- `title`: The current page's title.
|
||||||
|
- `domain`: The current scheme, domain, and port number.
|
||||||
|
- `selection`: The selection under the cursor.
|
||||||
|
|
||||||
sel: Use the primary selection instead of the clipboard.
|
sel: Use the primary selection instead of the clipboard.
|
||||||
title: Yank the title instead of the URL.
|
keep: Stay in visual mode after yanking the selection.
|
||||||
domain: Yank only the scheme, domain, and port number.
|
|
||||||
pretty: Yank the URL in pretty decoded form.
|
|
||||||
"""
|
"""
|
||||||
if title:
|
if what == 'title':
|
||||||
s = self._tabbed_browser.page_title(self._current_index())
|
s = self._tabbed_browser.page_title(self._current_index())
|
||||||
what = 'title'
|
elif what == 'domain':
|
||||||
elif domain:
|
|
||||||
port = self._current_url().port()
|
port = self._current_url().port()
|
||||||
s = '{}://{}{}'.format(self._current_url().scheme(),
|
s = '{}://{}{}'.format(self._current_url().scheme(),
|
||||||
self._current_url().host(),
|
self._current_url().host(),
|
||||||
':' + str(port) if port > -1 else '')
|
':' + str(port) if port > -1 else '')
|
||||||
what = 'domain'
|
elif what in ['url', 'pretty-url']:
|
||||||
else:
|
|
||||||
flags = QUrl.RemovePassword
|
flags = QUrl.RemovePassword
|
||||||
if not pretty:
|
if what != 'pretty-url':
|
||||||
flags |= QUrl.FullyEncoded
|
flags |= QUrl.FullyEncoded
|
||||||
s = self._current_url().toString(flags)
|
s = self._current_url().toString(flags)
|
||||||
what = 'URL'
|
what = 'URL' # For printing
|
||||||
|
elif what == 'selection':
|
||||||
|
caret = self._current_widget().caret
|
||||||
|
s = caret.selection()
|
||||||
|
if not caret.has_selection() or not s:
|
||||||
|
message.info(self._win_id, "Nothing to yank")
|
||||||
|
return
|
||||||
|
else: # pragma: no cover
|
||||||
|
raise ValueError("Invalid value {!r} for `what'.".format(what))
|
||||||
|
|
||||||
if sel and utils.supports_selection():
|
if sel and utils.supports_selection():
|
||||||
target = "primary selection"
|
target = "primary selection"
|
||||||
@ -677,8 +691,15 @@ class CommandDispatcher:
|
|||||||
target = "clipboard"
|
target = "clipboard"
|
||||||
|
|
||||||
utils.set_clipboard(s, selection=sel)
|
utils.set_clipboard(s, selection=sel)
|
||||||
message.info(self._win_id, "Yanked {} to {}: {}".format(
|
if what != 'selection':
|
||||||
what, target, s))
|
message.info(self._win_id, "Yanked {} to {}: {}".format(
|
||||||
|
what, target, s))
|
||||||
|
else:
|
||||||
|
message.info(self._win_id, "{} {} yanked to {}".format(
|
||||||
|
len(s), "char" if len(s) == 1 else "chars", target))
|
||||||
|
if not keep:
|
||||||
|
modeman.maybe_leave(self._win_id, KeyMode.caret,
|
||||||
|
"yank selected")
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
@cmdutils.register(instance='command-dispatcher', scope='window')
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
@ -982,7 +1003,7 @@ class CommandDispatcher:
|
|||||||
self._tabbed_browser.setUpdatesEnabled(True)
|
self._tabbed_browser.setUpdatesEnabled(True)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||||
maxsplit=0)
|
maxsplit=0, no_replace_variables=True)
|
||||||
def spawn(self, cmdline, userscript=False, verbose=False, detach=False):
|
def spawn(self, cmdline, userscript=False, verbose=False, detach=False):
|
||||||
"""Spawn a command in a shell.
|
"""Spawn a command in a shell.
|
||||||
|
|
||||||
@ -1755,31 +1776,6 @@ class CommandDispatcher:
|
|||||||
"""Move the cursor or selection to the end of the document."""
|
"""Move the cursor or selection to the end of the document."""
|
||||||
self._current_widget().caret.move_to_end_of_document()
|
self._current_widget().caret.move_to_end_of_document()
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window')
|
|
||||||
def yank_selected(self, sel=False, keep=False):
|
|
||||||
"""Yank the selected text to the clipboard or primary selection.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sel: Use the primary selection instead of the clipboard.
|
|
||||||
keep: If given, stay in visual mode after yanking.
|
|
||||||
"""
|
|
||||||
caret = self._current_widget().caret
|
|
||||||
s = caret.selection()
|
|
||||||
if not caret.has_selection() or len(s) == 0:
|
|
||||||
message.info(self._win_id, "Nothing to yank")
|
|
||||||
return
|
|
||||||
|
|
||||||
if sel and utils.supports_selection():
|
|
||||||
target = "primary selection"
|
|
||||||
else:
|
|
||||||
sel = False
|
|
||||||
target = "clipboard"
|
|
||||||
utils.set_clipboard(s, sel)
|
|
||||||
message.info(self._win_id, "{} {} yanked to {}".format(
|
|
||||||
len(s), "char" if len(s) == 1 else "chars", target))
|
|
||||||
if not keep:
|
|
||||||
modeman.maybe_leave(self._win_id, KeyMode.caret, "yank selected")
|
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||||
modes=[KeyMode.caret], scope='window')
|
modes=[KeyMode.caret], scope='window')
|
||||||
def toggle_selection(self):
|
def toggle_selection(self):
|
||||||
|
@ -75,13 +75,13 @@ class Command:
|
|||||||
deprecated: False, or a string to describe why a command is deprecated.
|
deprecated: False, or a string to describe why a command is deprecated.
|
||||||
desc: The description of the command.
|
desc: The description of the command.
|
||||||
handler: The handler function to call.
|
handler: The handler function to call.
|
||||||
completion: Completions to use for arguments, as a list of strings.
|
|
||||||
debug: Whether this is a debugging command (only shown with --debug).
|
debug: Whether this is a debugging command (only shown with --debug).
|
||||||
parser: The ArgumentParser to use to parse this command.
|
parser: The ArgumentParser to use to parse this command.
|
||||||
flags_with_args: A list of flags which take an argument.
|
flags_with_args: A list of flags which take an argument.
|
||||||
no_cmd_split: If true, ';;' to split sub-commands is ignored.
|
no_cmd_split: If true, ';;' to split sub-commands is ignored.
|
||||||
backend: Which backend the command works with (or None if it works with
|
backend: Which backend the command works with (or None if it works with
|
||||||
both)
|
both)
|
||||||
|
no_replace_variables: Don't replace variables like {url}
|
||||||
_qute_args: The saved data from @cmdutils.argument
|
_qute_args: The saved data from @cmdutils.argument
|
||||||
_needs_js: Whether the command needs javascript enabled
|
_needs_js: Whether the command needs javascript enabled
|
||||||
_modes: The modes the command can be executed in.
|
_modes: The modes the command can be executed in.
|
||||||
@ -95,7 +95,7 @@ class Command:
|
|||||||
hide=False, modes=None, not_modes=None, needs_js=False,
|
hide=False, modes=None, not_modes=None, needs_js=False,
|
||||||
debug=False, ignore_args=False, deprecated=False,
|
debug=False, ignore_args=False, deprecated=False,
|
||||||
no_cmd_split=False, star_args_optional=False, scope='global',
|
no_cmd_split=False, star_args_optional=False, scope='global',
|
||||||
backend=None):
|
backend=None, no_replace_variables=False):
|
||||||
# I really don't know how to solve this in a better way, I tried.
|
# I really don't know how to solve this in a better way, I tried.
|
||||||
# pylint: disable=too-many-locals
|
# pylint: disable=too-many-locals
|
||||||
if modes is not None and not_modes is not None:
|
if modes is not None and not_modes is not None:
|
||||||
@ -127,6 +127,7 @@ class Command:
|
|||||||
self.handler = handler
|
self.handler = handler
|
||||||
self.no_cmd_split = no_cmd_split
|
self.no_cmd_split = no_cmd_split
|
||||||
self.backend = backend
|
self.backend = backend
|
||||||
|
self.no_replace_variables = no_replace_variables
|
||||||
|
|
||||||
self.docparser = docutils.DocstringParser(handler)
|
self.docparser = docutils.DocstringParser(handler)
|
||||||
self.parser = argparser.ArgumentParser(
|
self.parser = argparser.ArgumentParser(
|
||||||
@ -148,13 +149,7 @@ class Command:
|
|||||||
self._qute_args = getattr(self.handler, 'qute_args', {})
|
self._qute_args = getattr(self.handler, 'qute_args', {})
|
||||||
self.handler.qute_args = None
|
self.handler.qute_args = None
|
||||||
|
|
||||||
args = self._inspect_func()
|
self._inspect_func()
|
||||||
|
|
||||||
self.completion = []
|
|
||||||
for arg in args:
|
|
||||||
arg_completion = self.get_arg_info(arg).completion
|
|
||||||
if arg_completion is not None:
|
|
||||||
self.completion.append(arg_completion)
|
|
||||||
|
|
||||||
def _check_prerequisites(self, win_id):
|
def _check_prerequisites(self, win_id):
|
||||||
"""Check if the command is permitted to run currently.
|
"""Check if the command is permitted to run currently.
|
||||||
@ -208,6 +203,11 @@ class Command:
|
|||||||
"""Get an ArgInfo tuple for the given inspect.Parameter."""
|
"""Get an ArgInfo tuple for the given inspect.Parameter."""
|
||||||
return self._qute_args.get(param.name, ArgInfo())
|
return self._qute_args.get(param.name, ArgInfo())
|
||||||
|
|
||||||
|
def get_pos_arg_info(self, pos):
|
||||||
|
"""Get an ArgInfo tuple for the given positional parameter."""
|
||||||
|
name = self.pos_args[pos][0]
|
||||||
|
return self._qute_args.get(name, ArgInfo())
|
||||||
|
|
||||||
def _inspect_special_param(self, param):
|
def _inspect_special_param(self, param):
|
||||||
"""Check if the given parameter is a special one.
|
"""Check if the given parameter is a special one.
|
||||||
|
|
||||||
|
@ -52,29 +52,28 @@ def replace_variables(win_id, arglist):
|
|||||||
args = []
|
args = []
|
||||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||||
window=win_id)
|
window=win_id)
|
||||||
if '{url}' in arglist:
|
if any('{url}' in arg for arg in arglist):
|
||||||
url = _current_url(tabbed_browser).toString(QUrl.FullyEncoded |
|
url = _current_url(tabbed_browser).toString(QUrl.FullyEncoded |
|
||||||
QUrl.RemovePassword)
|
QUrl.RemovePassword)
|
||||||
if '{url:pretty}' in arglist:
|
if any('{url:pretty}' in arg for arg in arglist):
|
||||||
pretty_url = _current_url(tabbed_browser).toString(QUrl.RemovePassword)
|
pretty_url = _current_url(tabbed_browser).toString(QUrl.RemovePassword)
|
||||||
try:
|
try:
|
||||||
if '{clipboard}' in arglist:
|
if any('{clipboard}' in arg for arg in arglist):
|
||||||
clipboard = utils.get_clipboard()
|
clipboard = utils.get_clipboard()
|
||||||
if '{primary}' in arglist:
|
if any('{primary}' in arg for arg in arglist):
|
||||||
primary = utils.get_clipboard(selection=True)
|
primary = utils.get_clipboard(selection=True)
|
||||||
except utils.ClipboardEmptyError as e:
|
except utils.ClipboardEmptyError as e:
|
||||||
raise cmdexc.CommandError(e)
|
raise cmdexc.CommandError(e)
|
||||||
for arg in arglist:
|
for arg in arglist:
|
||||||
if arg == '{url}':
|
if '{url}' in arg:
|
||||||
args.append(url)
|
arg = arg.replace('{url}', url)
|
||||||
elif arg == '{url:pretty}':
|
if '{url:pretty}' in arg:
|
||||||
args.append(pretty_url)
|
arg = arg.replace('{url:pretty}', pretty_url)
|
||||||
elif arg == '{clipboard}':
|
if '{clipboard}' in arg:
|
||||||
args.append(clipboard)
|
arg = arg.replace('{clipboard}', clipboard)
|
||||||
elif arg == '{primary}':
|
if '{primary}' in arg:
|
||||||
args.append(primary)
|
arg = arg.replace('{primary}', primary)
|
||||||
else:
|
args.append(arg)
|
||||||
args.append(arg)
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -290,7 +289,10 @@ class CommandRunner(QObject):
|
|||||||
window=self._win_id)
|
window=self._win_id)
|
||||||
cur_mode = mode_manager.mode
|
cur_mode = mode_manager.mode
|
||||||
|
|
||||||
args = replace_variables(self._win_id, result.args)
|
if result.cmd.no_replace_variables:
|
||||||
|
args = result.args
|
||||||
|
else:
|
||||||
|
args = replace_variables(self._win_id, result.args)
|
||||||
if count is not None:
|
if count is not None:
|
||||||
if result.count is not None:
|
if result.count is not None:
|
||||||
raise cmdexc.CommandMetaError("Got count via command and "
|
raise cmdexc.CommandMetaError("Got count via command and "
|
||||||
|
@ -204,25 +204,18 @@ class Completer(QObject):
|
|||||||
return sortfilter.CompletionFilterModel(source=model, parent=self)
|
return sortfilter.CompletionFilterModel(source=model, parent=self)
|
||||||
# delegate completion to command
|
# delegate completion to command
|
||||||
try:
|
try:
|
||||||
completions = cmdutils.cmd_dict[parts[0]].completion
|
cmd = cmdutils.cmd_dict[parts[0]]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# entering an unknown command
|
# entering an unknown command
|
||||||
return None
|
return None
|
||||||
if completions is None:
|
|
||||||
# command without any available completions
|
|
||||||
return None
|
|
||||||
dbg_completions = [c.name for c in completions]
|
|
||||||
try:
|
try:
|
||||||
idx = cursor_part - 1
|
idx = cursor_part - 1
|
||||||
completion = completions[idx]
|
completion = cmd.get_pos_arg_info(idx).completion
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# More arguments than completions
|
# user provided more positional arguments than the command takes
|
||||||
log.completion.debug("completions: {}".format(
|
return None
|
||||||
', '.join(dbg_completions)))
|
if completion is None:
|
||||||
return None
|
return None
|
||||||
dbg_completions[idx] = '*' + dbg_completions[idx] + '*'
|
|
||||||
log.completion.debug("completions: {}".format(
|
|
||||||
', '.join(dbg_completions)))
|
|
||||||
model = self._get_completion_model(completion, parts, cursor_part)
|
model = self._get_completion_model(completion, parts, cursor_part)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@ -27,8 +27,7 @@ Module attributes:
|
|||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
from qutebrowser.completion.models import (miscmodels, urlmodel, configmodel,
|
from qutebrowser.completion.models import miscmodels, urlmodel, configmodel
|
||||||
base)
|
|
||||||
from qutebrowser.utils import objreg, usertypes, log, debug
|
from qutebrowser.utils import objreg, usertypes, log, debug
|
||||||
from qutebrowser.config import configdata
|
from qutebrowser.config import configdata
|
||||||
|
|
||||||
@ -115,13 +114,6 @@ def init_session_completion():
|
|||||||
_instances[usertypes.Completion.sessions] = model
|
_instances[usertypes.Completion.sessions] = model
|
||||||
|
|
||||||
|
|
||||||
def _init_empty_completion():
|
|
||||||
"""Initialize empty completion model."""
|
|
||||||
log.completion.debug("Initializing empty completion.")
|
|
||||||
if usertypes.Completion.empty not in _instances:
|
|
||||||
_instances[usertypes.Completion.empty] = base.BaseCompletionModel()
|
|
||||||
|
|
||||||
|
|
||||||
INITIALIZERS = {
|
INITIALIZERS = {
|
||||||
usertypes.Completion.command: _init_command_completion,
|
usertypes.Completion.command: _init_command_completion,
|
||||||
usertypes.Completion.helptopic: _init_helptopic_completion,
|
usertypes.Completion.helptopic: _init_helptopic_completion,
|
||||||
@ -133,7 +125,6 @@ INITIALIZERS = {
|
|||||||
usertypes.Completion.quickmark_by_name: init_quickmark_completions,
|
usertypes.Completion.quickmark_by_name: init_quickmark_completions,
|
||||||
usertypes.Completion.bookmark_by_url: init_bookmark_completions,
|
usertypes.Completion.bookmark_by_url: init_bookmark_completions,
|
||||||
usertypes.Completion.sessions: init_session_completion,
|
usertypes.Completion.sessions: init_session_completion,
|
||||||
usertypes.Completion.empty: _init_empty_completion,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,8 +135,8 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
|||||||
|
|
||||||
for col in self.srcmodel.columns_to_filter:
|
for col in self.srcmodel.columns_to_filter:
|
||||||
idx = self.srcmodel.index(row, col, parent)
|
idx = self.srcmodel.index(row, col, parent)
|
||||||
if not idx.isValid():
|
if not idx.isValid(): # pragma: no cover
|
||||||
# No entries in parent model
|
# this is a sanity check not hit by any test case
|
||||||
continue
|
continue
|
||||||
data = self.srcmodel.data(idx)
|
data = self.srcmodel.data(idx)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -1506,12 +1506,12 @@ KEY_DATA = collections.OrderedDict([
|
|||||||
('enter-mode jump_mark', ["'"]),
|
('enter-mode jump_mark', ["'"]),
|
||||||
('yank', ['yy']),
|
('yank', ['yy']),
|
||||||
('yank -s', ['yY']),
|
('yank -s', ['yY']),
|
||||||
('yank -t', ['yt']),
|
('yank title', ['yt']),
|
||||||
('yank -ts', ['yT']),
|
('yank title -s', ['yT']),
|
||||||
('yank -d', ['yd']),
|
('yank domain', ['yd']),
|
||||||
('yank -ds', ['yD']),
|
('yank domain -s', ['yD']),
|
||||||
('yank -p', ['yp']),
|
('yank pretty-url', ['yp']),
|
||||||
('yank -ps', ['yP']),
|
('yank pretty-url -s', ['yP']),
|
||||||
('open {clipboard}', ['pp']),
|
('open {clipboard}', ['pp']),
|
||||||
('open {primary}', ['pP']),
|
('open {primary}', ['pP']),
|
||||||
('open -t {clipboard}', ['Pp']),
|
('open -t {clipboard}', ['Pp']),
|
||||||
@ -1638,8 +1638,8 @@ KEY_DATA = collections.OrderedDict([
|
|||||||
('move-to-end-of-line', ['$']),
|
('move-to-end-of-line', ['$']),
|
||||||
('move-to-start-of-document', ['gg']),
|
('move-to-start-of-document', ['gg']),
|
||||||
('move-to-end-of-document', ['G']),
|
('move-to-end-of-document', ['G']),
|
||||||
('yank-selected -p', ['Y']),
|
('yank selection -s', ['Y']),
|
||||||
('yank-selected', ['y'] + RETURN_KEYS),
|
('yank selection', ['y'] + RETURN_KEYS),
|
||||||
('scroll left', ['H']),
|
('scroll left', ['H']),
|
||||||
('scroll down', ['J']),
|
('scroll down', ['J']),
|
||||||
('scroll up', ['K']),
|
('scroll up', ['K']),
|
||||||
@ -1678,6 +1678,15 @@ CHANGED_KEY_COMMANDS = [
|
|||||||
|
|
||||||
(re.compile(r'^hint links fill "([^"]*)"$'), r'hint links fill \1'),
|
(re.compile(r'^hint links fill "([^"]*)"$'), r'hint links fill \1'),
|
||||||
|
|
||||||
|
(re.compile(r'^yank -t(\S+)'), r'yank title -\1'),
|
||||||
|
(re.compile(r'^yank -t'), r'yank title'),
|
||||||
|
(re.compile(r'^yank -d(\S+)'), r'yank domain -\1'),
|
||||||
|
(re.compile(r'^yank -d'), r'yank domain'),
|
||||||
|
(re.compile(r'^yank -p(\S+)'), r'yank pretty-url -\1'),
|
||||||
|
(re.compile(r'^yank -p'), r'yank pretty-url'),
|
||||||
|
(re.compile(r'^yank-selected -p'), r'yank selection -s'),
|
||||||
|
(re.compile(r'^yank-selected'), r'yank selection'),
|
||||||
|
|
||||||
(re.compile(r'^paste$'), r'open {clipboard}'),
|
(re.compile(r'^paste$'), r'open {clipboard}'),
|
||||||
(re.compile(r'^paste -([twb])$'), r'open -\1 {clipboard}'),
|
(re.compile(r'^paste -([twb])$'), r'open -\1 {clipboard}'),
|
||||||
(re.compile(r'^paste -([twb])s$'), r'open -\1 {primary}'),
|
(re.compile(r'^paste -([twb])s$'), r'open -\1 {primary}'),
|
||||||
|
@ -150,9 +150,9 @@ class KeyConfigParser(QObject):
|
|||||||
data = str(self)
|
data = str(self)
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
@cmdutils.register(instance='key-config', maxsplit=1, no_cmd_split=True)
|
@cmdutils.register(instance='key-config', maxsplit=1, no_cmd_split=True,
|
||||||
|
no_replace_variables=True)
|
||||||
@cmdutils.argument('win_id', win_id=True)
|
@cmdutils.argument('win_id', win_id=True)
|
||||||
@cmdutils.argument('key', completion=usertypes.Completion.empty)
|
|
||||||
@cmdutils.argument('command', completion=usertypes.Completion.command)
|
@cmdutils.argument('command', completion=usertypes.Completion.command)
|
||||||
def bind(self, key, win_id, command=None, *, mode='normal', force=False):
|
def bind(self, key, win_id, command=None, *, mode='normal', force=False):
|
||||||
"""Bind a key to a command.
|
"""Bind a key to a command.
|
||||||
@ -361,12 +361,12 @@ class KeyConfigParser(QObject):
|
|||||||
raise KeyConfigError("Got command '{}' without getting a "
|
raise KeyConfigError("Got command '{}' without getting a "
|
||||||
"section!".format(line))
|
"section!".format(line))
|
||||||
else:
|
else:
|
||||||
self._validate_command(line)
|
|
||||||
for rgx, repl in configdata.CHANGED_KEY_COMMANDS:
|
for rgx, repl in configdata.CHANGED_KEY_COMMANDS:
|
||||||
if rgx.match(line):
|
if rgx.match(line):
|
||||||
line = rgx.sub(repl, line)
|
line = rgx.sub(repl, line)
|
||||||
self._mark_config_dirty()
|
self._mark_config_dirty()
|
||||||
break
|
break
|
||||||
|
self._validate_command(line)
|
||||||
self._cur_command = line
|
self._cur_command = line
|
||||||
|
|
||||||
def _read_keybinding(self, line):
|
def _read_keybinding(self, line):
|
||||||
|
@ -23,8 +23,8 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize
|
|||||||
from PyQt5.QtWidgets import QSizePolicy
|
from PyQt5.QtWidgets import QSizePolicy
|
||||||
|
|
||||||
from qutebrowser.keyinput import modeman, modeparsers
|
from qutebrowser.keyinput import modeman, modeparsers
|
||||||
from qutebrowser.commands import cmdexc, cmdutils, runners
|
from qutebrowser.commands import cmdexc, cmdutils
|
||||||
from qutebrowser.misc import cmdhistory, split
|
from qutebrowser.misc import cmdhistory
|
||||||
from qutebrowser.misc import miscwidgets as misc
|
from qutebrowser.misc import miscwidgets as misc
|
||||||
from qutebrowser.utils import usertypes, log, objreg
|
from qutebrowser.utils import usertypes, log, objreg
|
||||||
|
|
||||||
@ -108,10 +108,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
|||||||
space: If given, a space is added to the end.
|
space: If given, a space is added to the end.
|
||||||
append: If given, the text is appended to the current text.
|
append: If given, the text is appended to the current text.
|
||||||
"""
|
"""
|
||||||
args = split.simple_split(text)
|
|
||||||
args = runners.replace_variables(self._win_id, args)
|
|
||||||
text = ' '.join(args)
|
|
||||||
|
|
||||||
if space:
|
if space:
|
||||||
text += ' '
|
text += ' '
|
||||||
if append:
|
if append:
|
||||||
|
@ -35,8 +35,8 @@ class ExternalEditor(QObject):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_text: The current text before the editor is opened.
|
_text: The current text before the editor is opened.
|
||||||
_oshandle: The OS level handle to the tmpfile.
|
_file: The file handle as tempfile.NamedTemporaryFile. Note that this
|
||||||
_filehandle: The file handle to the tmpfile.
|
handle will be closed after the initial file has been created.
|
||||||
_proc: The GUIProcess of the editor.
|
_proc: The GUIProcess of the editor.
|
||||||
_win_id: The window ID the ExternalEditor is associated with.
|
_win_id: The window ID the ExternalEditor is associated with.
|
||||||
"""
|
"""
|
||||||
@ -46,20 +46,18 @@ class ExternalEditor(QObject):
|
|||||||
def __init__(self, win_id, parent=None):
|
def __init__(self, win_id, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._text = None
|
self._text = None
|
||||||
self._oshandle = None
|
self._file = None
|
||||||
self._filename = None
|
|
||||||
self._proc = None
|
self._proc = None
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
|
|
||||||
def _cleanup(self):
|
def _cleanup(self):
|
||||||
"""Clean up temporary files after the editor closed."""
|
"""Clean up temporary files after the editor closed."""
|
||||||
if self._oshandle is None or self._filename is None:
|
if self._file is None:
|
||||||
# Could not create initial file.
|
# Could not create initial file.
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
os.close(self._oshandle)
|
|
||||||
if self._proc.exit_status() != QProcess.CrashExit:
|
if self._proc.exit_status() != QProcess.CrashExit:
|
||||||
os.remove(self._filename)
|
os.remove(self._file.name)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
# NOTE: Do not replace this with "raise CommandError" as it's
|
# NOTE: Do not replace this with "raise CommandError" as it's
|
||||||
# executed async.
|
# executed async.
|
||||||
@ -82,7 +80,7 @@ class ExternalEditor(QObject):
|
|||||||
return
|
return
|
||||||
encoding = config.get('general', 'editor-encoding')
|
encoding = config.get('general', 'editor-encoding')
|
||||||
try:
|
try:
|
||||||
with open(self._filename, 'r', encoding=encoding) as f:
|
with open(self._file.name, 'r', encoding=encoding) as f:
|
||||||
text = f.read()
|
text = f.read()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
# NOTE: Do not replace this with "raise CommandError" as it's
|
# NOTE: Do not replace this with "raise CommandError" as it's
|
||||||
@ -108,13 +106,18 @@ class ExternalEditor(QObject):
|
|||||||
if self._text is not None:
|
if self._text is not None:
|
||||||
raise ValueError("Already editing a file!")
|
raise ValueError("Already editing a file!")
|
||||||
self._text = text
|
self._text = text
|
||||||
|
encoding = config.get('general', 'editor-encoding')
|
||||||
try:
|
try:
|
||||||
self._oshandle, self._filename = tempfile.mkstemp(
|
# Close while the external process is running, as otherwise systems
|
||||||
text=True, prefix='qutebrowser-editor-')
|
# with exclusive write access (e.g. Windows) may fail to update
|
||||||
if text:
|
# the file from the external editor, see
|
||||||
encoding = config.get('general', 'editor-encoding')
|
# https://github.com/The-Compiler/qutebrowser/issues/1767
|
||||||
with open(self._filename, 'w', encoding=encoding) as f:
|
with tempfile.NamedTemporaryFile(
|
||||||
f.write(text)
|
mode='w', prefix='qutebrowser-editor-', encoding=encoding,
|
||||||
|
delete=False) as fobj:
|
||||||
|
if text:
|
||||||
|
fobj.write(text)
|
||||||
|
self._file = fobj
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
message.error(self._win_id, "Failed to create initial file: "
|
message.error(self._win_id, "Failed to create initial file: "
|
||||||
"{}".format(e))
|
"{}".format(e))
|
||||||
@ -125,6 +128,6 @@ class ExternalEditor(QObject):
|
|||||||
self._proc.error.connect(self.on_proc_error)
|
self._proc.error.connect(self.on_proc_error)
|
||||||
editor = config.get('general', 'editor')
|
editor = config.get('general', 'editor')
|
||||||
executable = editor[0]
|
executable = editor[0]
|
||||||
args = [arg.replace('{}', self._filename) for arg in editor[1:]]
|
args = [arg.replace('{}', self._file.name) for arg in editor[1:]]
|
||||||
log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
|
log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
|
||||||
self._proc.start(executable, args)
|
self._proc.start(executable, args)
|
||||||
|
@ -39,7 +39,7 @@ from PyQt5.QtCore import QUrl
|
|||||||
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
|
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
|
||||||
|
|
||||||
|
|
||||||
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
@cmdutils.register(maxsplit=1, no_cmd_split=True, no_replace_variables=True)
|
||||||
@cmdutils.argument('win_id', win_id=True)
|
@cmdutils.argument('win_id', win_id=True)
|
||||||
def later(ms: int, command, win_id):
|
def later(ms: int, command, win_id):
|
||||||
"""Execute a command after some time.
|
"""Execute a command after some time.
|
||||||
@ -69,7 +69,7 @@ def later(ms: int, command, win_id):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@cmdutils.register(maxsplit=1, no_cmd_split=True)
|
@cmdutils.register(maxsplit=1, no_cmd_split=True, no_replace_variables=True)
|
||||||
@cmdutils.argument('win_id', win_id=True)
|
@cmdutils.argument('win_id', win_id=True)
|
||||||
def repeat(times: int, command, win_id):
|
def repeat(times: int, command, win_id):
|
||||||
"""Repeat a given command.
|
"""Repeat a given command.
|
||||||
|
@ -238,8 +238,7 @@ KeyMode = enum('KeyMode', ['normal', 'hint', 'command', 'yesno', 'prompt',
|
|||||||
# Available command completions
|
# Available command completions
|
||||||
Completion = enum('Completion', ['command', 'section', 'option', 'value',
|
Completion = enum('Completion', ['command', 'section', 'option', 'value',
|
||||||
'helptopic', 'quickmark_by_name',
|
'helptopic', 'quickmark_by_name',
|
||||||
'bookmark_by_url', 'url', 'tab', 'sessions',
|
'bookmark_by_url', 'url', 'tab', 'sessions'])
|
||||||
'empty'])
|
|
||||||
|
|
||||||
|
|
||||||
# Exit statuses for errors. Needs to be an int for sys.exit.
|
# Exit statuses for errors. Needs to be an int for sys.exit.
|
||||||
|
@ -150,12 +150,14 @@ PERFECT_FILES = [
|
|||||||
|
|
||||||
('tests/unit/completion/test_models.py',
|
('tests/unit/completion/test_models.py',
|
||||||
'qutebrowser/completion/models/base.py'),
|
'qutebrowser/completion/models/base.py'),
|
||||||
|
('tests/unit/completion/test_sortfilter.py',
|
||||||
|
'qutebrowser/completion/models/sortfilter.py'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# 100% coverage because of end2end tests, but no perfect unit tests yet.
|
# 100% coverage because of end2end tests, but no perfect unit tests yet.
|
||||||
WHITELISTED_FILES = []
|
WHITELISTED_FILES = ['qutebrowser/browser/webkit/webkitinspector.py']
|
||||||
|
|
||||||
|
|
||||||
class Skipped(Exception):
|
class Skipped(Exception):
|
||||||
|
@ -239,7 +239,8 @@ def _get_command_doc_notes(cmd):
|
|||||||
Yield:
|
Yield:
|
||||||
Strings which should be added to the docs.
|
Strings which should be added to the docs.
|
||||||
"""
|
"""
|
||||||
if cmd.maxsplit is not None or cmd.no_cmd_split:
|
if (cmd.maxsplit is not None or cmd.no_cmd_split or
|
||||||
|
cmd.no_replace_variables and cmd.name != "spawn"):
|
||||||
yield ""
|
yield ""
|
||||||
yield "==== note"
|
yield "==== note"
|
||||||
if cmd.maxsplit is not None:
|
if cmd.maxsplit is not None:
|
||||||
@ -248,6 +249,8 @@ def _get_command_doc_notes(cmd):
|
|||||||
if cmd.no_cmd_split:
|
if cmd.no_cmd_split:
|
||||||
yield ("* With this command, +;;+ is interpreted literally "
|
yield ("* With this command, +;;+ is interpreted literally "
|
||||||
"instead of splitting off a second command.")
|
"instead of splitting off a second command.")
|
||||||
|
if cmd.no_replace_variables and cmd.name != "spawn":
|
||||||
|
yield r"* This command does not replace variables like +\{url\}+."
|
||||||
|
|
||||||
|
|
||||||
def _get_action_metavar(action, nargs=1):
|
def _get_action_metavar(action, nargs=1):
|
||||||
|
@ -10,7 +10,7 @@ Feature: Caret mode
|
|||||||
Scenario: Selecting the entire document
|
Scenario: Selecting the entire document
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-document
|
And I run :move-to-end-of-document
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain:
|
Then the clipboard should contain:
|
||||||
one two three
|
one two three
|
||||||
eins zwei drei
|
eins zwei drei
|
||||||
@ -23,14 +23,14 @@ Feature: Caret mode
|
|||||||
And I run :move-to-start-of-document
|
And I run :move-to-start-of-document
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one"
|
Then the clipboard should contain "one"
|
||||||
|
|
||||||
Scenario: Moving to end and to start of document (with selection)
|
Scenario: Moving to end and to start of document (with selection)
|
||||||
When I run :move-to-end-of-document
|
When I run :move-to-end-of-document
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-start-of-document
|
And I run :move-to-start-of-document
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain:
|
Then the clipboard should contain:
|
||||||
one two three
|
one two three
|
||||||
eins zwei drei
|
eins zwei drei
|
||||||
@ -43,7 +43,7 @@ Feature: Caret mode
|
|||||||
Scenario: Selecting a block
|
Scenario: Selecting a block
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-next-block
|
And I run :move-to-end-of-next-block
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain:
|
Then the clipboard should contain:
|
||||||
one two three
|
one two three
|
||||||
eins zwei drei
|
eins zwei drei
|
||||||
@ -53,7 +53,7 @@ Feature: Caret mode
|
|||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-prev-block
|
And I run :move-to-end-of-prev-block
|
||||||
And I run :move-to-prev-word
|
And I run :move-to-prev-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain:
|
Then the clipboard should contain:
|
||||||
drei
|
drei
|
||||||
|
|
||||||
@ -64,14 +64,14 @@ Feature: Caret mode
|
|||||||
And I run :move-to-end-of-prev-block
|
And I run :move-to-end-of-prev-block
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-prev-word
|
And I run :move-to-prev-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "drei"
|
Then the clipboard should contain "drei"
|
||||||
|
|
||||||
Scenario: Moving back to the start of previous block (with selection)
|
Scenario: Moving back to the start of previous block (with selection)
|
||||||
When I run :move-to-end-of-next-block with count 2
|
When I run :move-to-end-of-next-block with count 2
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-start-of-prev-block
|
And I run :move-to-start-of-prev-block
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain:
|
Then the clipboard should contain:
|
||||||
eins zwei drei
|
eins zwei drei
|
||||||
|
|
||||||
@ -82,20 +82,20 @@ Feature: Caret mode
|
|||||||
And I run :move-to-start-of-prev-block
|
And I run :move-to-start-of-prev-block
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-next-word
|
And I run :move-to-next-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "eins "
|
Then the clipboard should contain "eins "
|
||||||
|
|
||||||
Scenario: Moving to the start of next block (with selection)
|
Scenario: Moving to the start of next block (with selection)
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-start-of-next-block
|
And I run :move-to-start-of-next-block
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three\n"
|
Then the clipboard should contain "one two three\n"
|
||||||
|
|
||||||
Scenario: Moving to the start of next block
|
Scenario: Moving to the start of next block
|
||||||
When I run :move-to-start-of-next-block
|
When I run :move-to-start-of-next-block
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "eins"
|
Then the clipboard should contain "eins"
|
||||||
|
|
||||||
# line
|
# line
|
||||||
@ -103,20 +103,20 @@ Feature: Caret mode
|
|||||||
Scenario: Selecting a line
|
Scenario: Selecting a line
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-line
|
And I run :move-to-end-of-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three"
|
Then the clipboard should contain "one two three"
|
||||||
|
|
||||||
Scenario: Moving and selecting a line
|
Scenario: Moving and selecting a line
|
||||||
When I run :move-to-next-line
|
When I run :move-to-next-line
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-line
|
And I run :move-to-end-of-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "eins zwei drei"
|
Then the clipboard should contain "eins zwei drei"
|
||||||
|
|
||||||
Scenario: Selecting next line
|
Scenario: Selecting next line
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-next-line
|
And I run :move-to-next-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three\n"
|
Then the clipboard should contain "one two three\n"
|
||||||
|
|
||||||
Scenario: Moving to end and to start of line
|
Scenario: Moving to end and to start of line
|
||||||
@ -124,21 +124,21 @@ Feature: Caret mode
|
|||||||
And I run :move-to-start-of-line
|
And I run :move-to-start-of-line
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one"
|
Then the clipboard should contain "one"
|
||||||
|
|
||||||
Scenario: Selecting a line (backwards)
|
Scenario: Selecting a line (backwards)
|
||||||
When I run :move-to-end-of-line
|
When I run :move-to-end-of-line
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
When I run :move-to-start-of-line
|
When I run :move-to-start-of-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three"
|
Then the clipboard should contain "one two three"
|
||||||
|
|
||||||
Scenario: Selecting previous line
|
Scenario: Selecting previous line
|
||||||
When I run :move-to-next-line
|
When I run :move-to-next-line
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
When I run :move-to-prev-line
|
When I run :move-to-prev-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three\n"
|
Then the clipboard should contain "one two three\n"
|
||||||
|
|
||||||
Scenario: Moving to previous line
|
Scenario: Moving to previous line
|
||||||
@ -146,7 +146,7 @@ Feature: Caret mode
|
|||||||
When I run :move-to-prev-line
|
When I run :move-to-prev-line
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
When I run :move-to-next-line
|
When I run :move-to-next-line
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one two three\n"
|
Then the clipboard should contain "one two three\n"
|
||||||
|
|
||||||
# word
|
# word
|
||||||
@ -154,35 +154,35 @@ Feature: Caret mode
|
|||||||
Scenario: Selecting a word
|
Scenario: Selecting a word
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one"
|
Then the clipboard should contain "one"
|
||||||
|
|
||||||
Scenario: Moving to end and selecting a word
|
Scenario: Moving to end and selecting a word
|
||||||
When I run :move-to-end-of-word
|
When I run :move-to-end-of-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain " two"
|
Then the clipboard should contain " two"
|
||||||
|
|
||||||
Scenario: Moving to next word and selecting a word
|
Scenario: Moving to next word and selecting a word
|
||||||
When I run :move-to-next-word
|
When I run :move-to-next-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "two"
|
Then the clipboard should contain "two"
|
||||||
|
|
||||||
Scenario: Moving to next word and selecting until next word
|
Scenario: Moving to next word and selecting until next word
|
||||||
When I run :move-to-next-word
|
When I run :move-to-next-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-next-word
|
And I run :move-to-next-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "two "
|
Then the clipboard should contain "two "
|
||||||
|
|
||||||
Scenario: Moving to previous word and selecting a word
|
Scenario: Moving to previous word and selecting a word
|
||||||
When I run :move-to-end-of-word
|
When I run :move-to-end-of-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-prev-word
|
And I run :move-to-prev-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one"
|
Then the clipboard should contain "one"
|
||||||
|
|
||||||
Scenario: Moving to previous word
|
Scenario: Moving to previous word
|
||||||
@ -190,7 +190,7 @@ Feature: Caret mode
|
|||||||
And I run :move-to-prev-word
|
And I run :move-to-prev-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "one"
|
Then the clipboard should contain "one"
|
||||||
|
|
||||||
# char
|
# char
|
||||||
@ -198,21 +198,21 @@ Feature: Caret mode
|
|||||||
Scenario: Selecting a char
|
Scenario: Selecting a char
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-next-char
|
And I run :move-to-next-char
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "o"
|
Then the clipboard should contain "o"
|
||||||
|
|
||||||
Scenario: Moving and selecting a char
|
Scenario: Moving and selecting a char
|
||||||
When I run :move-to-next-char
|
When I run :move-to-next-char
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-next-char
|
And I run :move-to-next-char
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "n"
|
Then the clipboard should contain "n"
|
||||||
|
|
||||||
Scenario: Selecting previous char
|
Scenario: Selecting previous char
|
||||||
When I run :move-to-end-of-word
|
When I run :move-to-end-of-word
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-prev-char
|
And I run :move-to-prev-char
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "e"
|
Then the clipboard should contain "e"
|
||||||
|
|
||||||
Scenario: Moving to previous char
|
Scenario: Moving to previous char
|
||||||
@ -220,41 +220,41 @@ Feature: Caret mode
|
|||||||
And I run :move-to-prev-char
|
And I run :move-to-prev-char
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "e"
|
Then the clipboard should contain "e"
|
||||||
|
|
||||||
# :yank-selected
|
# :yank selection
|
||||||
|
|
||||||
Scenario: :yank-selected without selection
|
Scenario: :yank selection without selection
|
||||||
When I run :yank-selected
|
When I run :yank selection
|
||||||
Then the message "Nothing to yank" should be shown.
|
Then the message "Nothing to yank" should be shown.
|
||||||
|
|
||||||
Scenario: :yank-selected message
|
Scenario: :yank selection message
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the message "3 chars yanked to clipboard" should be shown.
|
Then the message "3 chars yanked to clipboard" should be shown.
|
||||||
|
|
||||||
Scenario: :yank-selected message with one char
|
Scenario: :yank selection message with one char
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-next-char
|
And I run :move-to-next-char
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the message "1 char yanked to clipboard" should be shown.
|
Then the message "1 char yanked to clipboard" should be shown.
|
||||||
|
|
||||||
Scenario: :yank-selected with primary selection
|
Scenario: :yank selection with primary selection
|
||||||
When selection is supported
|
When selection is supported
|
||||||
And I run :toggle-selection
|
And I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected --sel
|
And I run :yank selection --sel
|
||||||
Then the message "3 chars yanked to primary selection" should be shown.
|
Then the message "3 chars yanked to primary selection" should be shown.
|
||||||
And the primary selection should contain "one"
|
And the primary selection should contain "one"
|
||||||
|
|
||||||
Scenario: :yank-selected with --keep
|
Scenario: :yank selection with --keep
|
||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected --keep
|
And I run :yank selection --keep
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :yank-selected --keep
|
And I run :yank selection --keep
|
||||||
Then the message "3 chars yanked to clipboard" should be shown.
|
Then the message "3 chars yanked to clipboard" should be shown.
|
||||||
And the message "7 chars yanked to clipboard" should be shown.
|
And the message "7 chars yanked to clipboard" should be shown.
|
||||||
And the clipboard should contain "one two"
|
And the clipboard should contain "one two"
|
||||||
@ -265,7 +265,7 @@ Feature: Caret mode
|
|||||||
When I run :toggle-selection
|
When I run :toggle-selection
|
||||||
And I run :move-to-end-of-word
|
And I run :move-to-end-of-word
|
||||||
And I run :drop-selection
|
And I run :drop-selection
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the message "Nothing to yank" should be shown.
|
Then the message "Nothing to yank" should be shown.
|
||||||
|
|
||||||
# :follow-selected
|
# :follow-selected
|
||||||
|
@ -9,19 +9,19 @@ Feature: Searching on a page
|
|||||||
|
|
||||||
Scenario: Searching text
|
Scenario: Searching text
|
||||||
When I run :search foo
|
When I run :search foo
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "foo"
|
Then the clipboard should contain "foo"
|
||||||
|
|
||||||
Scenario: Searching twice
|
Scenario: Searching twice
|
||||||
When I run :search foo
|
When I run :search foo
|
||||||
And I run :search bar
|
And I run :search bar
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Bar"
|
Then the clipboard should contain "Bar"
|
||||||
|
|
||||||
Scenario: Searching with --reverse
|
Scenario: Searching with --reverse
|
||||||
When I set general -> ignore-case to true
|
When I set general -> ignore-case to true
|
||||||
And I run :search -r foo
|
And I run :search -r foo
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Foo"
|
Then the clipboard should contain "Foo"
|
||||||
|
|
||||||
Scenario: Searching without matches
|
Scenario: Searching without matches
|
||||||
@ -32,13 +32,13 @@ Feature: Searching on a page
|
|||||||
Scenario: Searching with / and spaces at the end (issue 874)
|
Scenario: Searching with / and spaces at the end (issue 874)
|
||||||
When I run :set-cmd-text -s /space
|
When I run :set-cmd-text -s /space
|
||||||
And I run :command-accept
|
And I run :command-accept
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "space "
|
Then the clipboard should contain "space "
|
||||||
|
|
||||||
Scenario: Searching with / and slash in search term (issue 507)
|
Scenario: Searching with / and slash in search term (issue 507)
|
||||||
When I run :set-cmd-text -s //slash
|
When I run :set-cmd-text -s //slash
|
||||||
And I run :command-accept
|
And I run :command-accept
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "/slash"
|
Then the clipboard should contain "/slash"
|
||||||
|
|
||||||
# This doesn't work because this is QtWebKit behavior.
|
# This doesn't work because this is QtWebKit behavior.
|
||||||
@ -52,25 +52,25 @@ Feature: Searching on a page
|
|||||||
Scenario: Searching text with ignore-case = true
|
Scenario: Searching text with ignore-case = true
|
||||||
When I set general -> ignore-case to true
|
When I set general -> ignore-case to true
|
||||||
And I run :search bar
|
And I run :search bar
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Bar"
|
Then the clipboard should contain "Bar"
|
||||||
|
|
||||||
Scenario: Searching text with ignore-case = false
|
Scenario: Searching text with ignore-case = false
|
||||||
When I set general -> ignore-case to false
|
When I set general -> ignore-case to false
|
||||||
And I run :search bar
|
And I run :search bar
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "bar"
|
Then the clipboard should contain "bar"
|
||||||
|
|
||||||
Scenario: Searching text with ignore-case = smart (lower-case)
|
Scenario: Searching text with ignore-case = smart (lower-case)
|
||||||
When I set general -> ignore-case to smart
|
When I set general -> ignore-case to smart
|
||||||
And I run :search bar
|
And I run :search bar
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Bar"
|
Then the clipboard should contain "Bar"
|
||||||
|
|
||||||
Scenario: Searching text with ignore-case = smart (upper-case)
|
Scenario: Searching text with ignore-case = smart (upper-case)
|
||||||
When I set general -> ignore-case to smart
|
When I set general -> ignore-case to smart
|
||||||
And I run :search Foo
|
And I run :search Foo
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Foo" # even though foo was first
|
Then the clipboard should contain "Foo" # even though foo was first
|
||||||
|
|
||||||
## :search-next
|
## :search-next
|
||||||
@ -79,21 +79,21 @@ Feature: Searching on a page
|
|||||||
When I set general -> ignore-case to true
|
When I set general -> ignore-case to true
|
||||||
And I run :search foo
|
And I run :search foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Foo"
|
Then the clipboard should contain "Foo"
|
||||||
|
|
||||||
Scenario: Jumping to next match with count
|
Scenario: Jumping to next match with count
|
||||||
When I set general -> ignore-case to true
|
When I set general -> ignore-case to true
|
||||||
And I run :search baz
|
And I run :search baz
|
||||||
And I run :search-next with count 2
|
And I run :search-next with count 2
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "BAZ"
|
Then the clipboard should contain "BAZ"
|
||||||
|
|
||||||
Scenario: Jumping to next match with --reverse
|
Scenario: Jumping to next match with --reverse
|
||||||
When I set general -> ignore-case to true
|
When I set general -> ignore-case to true
|
||||||
And I run :search --reverse foo
|
And I run :search --reverse foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "foo"
|
Then the clipboard should contain "foo"
|
||||||
|
|
||||||
Scenario: Jumping to next match without search
|
Scenario: Jumping to next match without search
|
||||||
@ -107,7 +107,7 @@ Feature: Searching on a page
|
|||||||
And I run :search foo
|
And I run :search foo
|
||||||
And I run :tab-prev
|
And I run :tab-prev
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "foo"
|
Then the clipboard should contain "foo"
|
||||||
|
|
||||||
## :search-prev
|
## :search-prev
|
||||||
@ -117,7 +117,7 @@ Feature: Searching on a page
|
|||||||
And I run :search foo
|
And I run :search foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-prev
|
And I run :search-prev
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "foo"
|
Then the clipboard should contain "foo"
|
||||||
|
|
||||||
Scenario: Jumping to previous match with count
|
Scenario: Jumping to previous match with count
|
||||||
@ -126,7 +126,7 @@ Feature: Searching on a page
|
|||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-prev with count 2
|
And I run :search-prev with count 2
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "baz"
|
Then the clipboard should contain "baz"
|
||||||
|
|
||||||
Scenario: Jumping to previous match with --reverse
|
Scenario: Jumping to previous match with --reverse
|
||||||
@ -134,7 +134,7 @@ Feature: Searching on a page
|
|||||||
And I run :search --reverse foo
|
And I run :search --reverse foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-prev
|
And I run :search-prev
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Foo"
|
Then the clipboard should contain "Foo"
|
||||||
|
|
||||||
Scenario: Jumping to previous match without search
|
Scenario: Jumping to previous match without search
|
||||||
@ -149,14 +149,14 @@ Feature: Searching on a page
|
|||||||
When I run :search foo
|
When I run :search foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "foo"
|
Then the clipboard should contain "foo"
|
||||||
|
|
||||||
Scenario: Wrapping around page with --reverse
|
Scenario: Wrapping around page with --reverse
|
||||||
When I run :search --reverse foo
|
When I run :search --reverse foo
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :search-next
|
And I run :search-next
|
||||||
And I run :yank-selected
|
And I run :yank selection
|
||||||
Then the clipboard should contain "Foo"
|
Then the clipboard should contain "Foo"
|
||||||
|
|
||||||
# TODO: wrapping message with scrolling
|
# TODO: wrapping message with scrolling
|
||||||
|
@ -23,13 +23,13 @@ Feature: Yanking and pasting.
|
|||||||
Scenario: Yanking title to clipboard
|
Scenario: Yanking title to clipboard
|
||||||
When I open data/title.html
|
When I open data/title.html
|
||||||
And I wait for regex "Changing title for idx \d to 'Test title'" in the log
|
And I wait for regex "Changing title for idx \d to 'Test title'" in the log
|
||||||
And I run :yank --title
|
And I run :yank title
|
||||||
Then the message "Yanked title to clipboard: Test title" should be shown
|
Then the message "Yanked title to clipboard: Test title" should be shown
|
||||||
And the clipboard should contain "Test title"
|
And the clipboard should contain "Test title"
|
||||||
|
|
||||||
Scenario: Yanking domain to clipboard
|
Scenario: Yanking domain to clipboard
|
||||||
When I open data/title.html
|
When I open data/title.html
|
||||||
And I run :yank --domain
|
And I run :yank domain
|
||||||
Then the message "Yanked domain to clipboard: http://localhost:(port)" should be shown
|
Then the message "Yanked domain to clipboard: http://localhost:(port)" should be shown
|
||||||
And the clipboard should contain "http://localhost:(port)"
|
And the clipboard should contain "http://localhost:(port)"
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ Feature: Yanking and pasting.
|
|||||||
|
|
||||||
Scenario: Yanking pretty decoded URL
|
Scenario: Yanking pretty decoded URL
|
||||||
When I open data/title with spaces.html
|
When I open data/title with spaces.html
|
||||||
And I run :yank --pretty
|
And I run :yank pretty-url
|
||||||
Then the message "Yanked URL to clipboard: http://localhost:(port)/data/title with spaces.html" should be shown
|
Then the message "Yanked URL to clipboard: http://localhost:(port)/data/title with spaces.html" should be shown
|
||||||
And the clipboard should contain "http://localhost:(port)/data/title with spaces.html"
|
And the clipboard should contain "http://localhost:(port)/data/title with spaces.html"
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ def test_insert_mode(file_name, source, input_text, auto_insert, quteproc):
|
|||||||
quteproc.send_cmd(':enter-mode caret')
|
quteproc.send_cmd(':enter-mode caret')
|
||||||
quteproc.send_cmd(':toggle-selection')
|
quteproc.send_cmd(':toggle-selection')
|
||||||
quteproc.send_cmd(':move-to-prev-word')
|
quteproc.send_cmd(':move-to-prev-word')
|
||||||
quteproc.send_cmd(':yank-selected')
|
quteproc.send_cmd(':yank selection')
|
||||||
|
|
||||||
expected_message = '{} chars yanked to clipboard'.format(len(input_text))
|
expected_message = '{} chars yanked to clipboard'.format(len(input_text))
|
||||||
quteproc.mark_expected(category='message',
|
quteproc.mark_expected(category='message',
|
||||||
|
@ -291,6 +291,21 @@ class TestRegister:
|
|||||||
else:
|
else:
|
||||||
assert cmd._get_call_args(win_id=0) == ([expected], {})
|
assert cmd._get_call_args(win_id=0) == ([expected], {})
|
||||||
|
|
||||||
|
def test_pos_arg_info(self):
|
||||||
|
@cmdutils.register()
|
||||||
|
@cmdutils.argument('foo', choices=('a', 'b'))
|
||||||
|
@cmdutils.argument('bar', choices=('x', 'y'))
|
||||||
|
@cmdutils.argument('opt')
|
||||||
|
def fun(foo, bar, opt=False):
|
||||||
|
"""Blah."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
cmd = cmdutils.cmd_dict['fun']
|
||||||
|
assert cmd.get_pos_arg_info(0) == command.ArgInfo(choices=('a', 'b'))
|
||||||
|
assert cmd.get_pos_arg_info(1) == command.ArgInfo(choices=('x', 'y'))
|
||||||
|
with pytest.raises(IndexError):
|
||||||
|
cmd.get_pos_arg_info(2)
|
||||||
|
|
||||||
|
|
||||||
class TestArgument:
|
class TestArgument:
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ from PyQt5.QtGui import QStandardItemModel
|
|||||||
|
|
||||||
from qutebrowser.completion import completer
|
from qutebrowser.completion import completer
|
||||||
from qutebrowser.utils import usertypes
|
from qutebrowser.utils import usertypes
|
||||||
|
from qutebrowser.commands import command, cmdutils
|
||||||
|
|
||||||
|
|
||||||
class FakeCompletionModel(QStandardItemModel):
|
class FakeCompletionModel(QStandardItemModel):
|
||||||
@ -91,24 +92,48 @@ def instances(monkeypatch):
|
|||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def cmdutils_patch(monkeypatch, stubs):
|
def cmdutils_patch(monkeypatch, stubs):
|
||||||
"""Patch the cmdutils module to provide fake commands."""
|
"""Patch the cmdutils module to provide fake commands."""
|
||||||
|
@cmdutils.argument('section_', completion=usertypes.Completion.section)
|
||||||
|
@cmdutils.argument('option', completion=usertypes.Completion.option)
|
||||||
|
@cmdutils.argument('value', completion=usertypes.Completion.value)
|
||||||
|
def set_command(section_=None, option=None, value=None):
|
||||||
|
"""docstring!"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@cmdutils.argument('topic', completion=usertypes.Completion.helptopic)
|
||||||
|
def show_help(tab=False, bg=False, window=False, topic=None):
|
||||||
|
"""docstring!"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@cmdutils.argument('url', completion=usertypes.Completion.url)
|
||||||
|
@cmdutils.argument('count', count=True)
|
||||||
|
def openurl(url=None, implicit=False, bg=False, tab=False, window=False,
|
||||||
|
count=None):
|
||||||
|
"""docstring!"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@cmdutils.argument('win_id', win_id=True)
|
||||||
|
@cmdutils.argument('command', completion=usertypes.Completion.command)
|
||||||
|
def bind(key, win_id, command=None, *, mode='normal', force=False):
|
||||||
|
"""docstring!"""
|
||||||
|
# pylint: disable=unused-variable
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tab_detach():
|
||||||
|
"""docstring!"""
|
||||||
|
pass
|
||||||
|
|
||||||
cmds = {
|
cmds = {
|
||||||
'set': [usertypes.Completion.section, usertypes.Completion.option,
|
'set': set_command,
|
||||||
usertypes.Completion.value],
|
'help': show_help,
|
||||||
'help': [usertypes.Completion.helptopic],
|
'open': openurl,
|
||||||
'quickmark-load': [usertypes.Completion.quickmark_by_name],
|
'bind': bind,
|
||||||
'bookmark-load': [usertypes.Completion.bookmark_by_url],
|
'tab-detach': tab_detach,
|
||||||
'open': [usertypes.Completion.url],
|
|
||||||
'buffer': [usertypes.Completion.tab],
|
|
||||||
'session-load': [usertypes.Completion.sessions],
|
|
||||||
'bind': [usertypes.Completion.empty, usertypes.Completion.command],
|
|
||||||
'tab-detach': None,
|
|
||||||
}
|
}
|
||||||
cmd_utils = stubs.FakeCmdUtils({
|
cmd_utils = stubs.FakeCmdUtils({
|
||||||
name: stubs.FakeCommand(completion=compl)
|
name: command.Command(name=name, handler=fn)
|
||||||
for name, compl in cmds.items()
|
for name, fn in cmds.items()
|
||||||
})
|
})
|
||||||
monkeypatch.setattr('qutebrowser.completion.completer.cmdutils',
|
monkeypatch.setattr('qutebrowser.completion.completer.cmdutils', cmd_utils)
|
||||||
cmd_utils)
|
|
||||||
|
|
||||||
|
|
||||||
def _set_cmd_prompt(cmd, txt):
|
def _set_cmd_prompt(cmd, txt):
|
||||||
@ -143,21 +168,17 @@ def _validate_cmd_prompt(cmd, txt):
|
|||||||
(':set general ignore-case |', usertypes.Completion.value),
|
(':set general ignore-case |', usertypes.Completion.value),
|
||||||
(':set general huh |', None),
|
(':set general huh |', None),
|
||||||
(':help |', usertypes.Completion.helptopic),
|
(':help |', usertypes.Completion.helptopic),
|
||||||
(':quickmark-load |', usertypes.Completion.quickmark_by_name),
|
(':help |', usertypes.Completion.helptopic),
|
||||||
(':bookmark-load |', usertypes.Completion.bookmark_by_url),
|
|
||||||
(':open |', usertypes.Completion.url),
|
(':open |', usertypes.Completion.url),
|
||||||
(':buffer |', usertypes.Completion.tab),
|
(':bind |', None),
|
||||||
(':session-load |', usertypes.Completion.sessions),
|
|
||||||
(':bind |', usertypes.Completion.empty),
|
|
||||||
(':bind <c-x> |', usertypes.Completion.command),
|
(':bind <c-x> |', usertypes.Completion.command),
|
||||||
(':bind <c-x> foo|', usertypes.Completion.command),
|
(':bind <c-x> foo|', usertypes.Completion.command),
|
||||||
(':bind <c-x>| foo', usertypes.Completion.empty),
|
(':bind <c-x>| foo', None),
|
||||||
(':set| general ', usertypes.Completion.command),
|
(':set| general ', usertypes.Completion.command),
|
||||||
(':|set general ', usertypes.Completion.command),
|
(':|set general ', usertypes.Completion.command),
|
||||||
(':set gene|ral ignore-case', usertypes.Completion.section),
|
(':set gene|ral ignore-case', usertypes.Completion.section),
|
||||||
(':|', usertypes.Completion.command),
|
(':|', usertypes.Completion.command),
|
||||||
(': |', usertypes.Completion.command),
|
(': |', usertypes.Completion.command),
|
||||||
(':bookmark-load |', usertypes.Completion.bookmark_by_url),
|
|
||||||
('/|', None),
|
('/|', None),
|
||||||
(':open -t|', None),
|
(':open -t|', None),
|
||||||
(':open --tab|', None),
|
(':open --tab|', None),
|
||||||
|
@ -21,9 +21,44 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from qutebrowser.completion.models import base, sortfilter
|
from qutebrowser.completion.models import base, sortfilter
|
||||||
|
|
||||||
|
|
||||||
|
def _create_model(data):
|
||||||
|
"""Create a completion model populated with the given data.
|
||||||
|
|
||||||
|
data: A list of lists, where each sub-list represents a category, each
|
||||||
|
tuple in the sub-list represents an item, and each value in the
|
||||||
|
tuple represents the item data for that column
|
||||||
|
"""
|
||||||
|
model = base.BaseCompletionModel()
|
||||||
|
for catdata in data:
|
||||||
|
cat = model.new_category('')
|
||||||
|
for itemdata in catdata:
|
||||||
|
model.new_item(cat, *itemdata)
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_model_data(model):
|
||||||
|
"""Express a model's data as a list for easier comparison.
|
||||||
|
|
||||||
|
Return: A list of lists, where each sub-list represents a category, each
|
||||||
|
tuple in the sub-list represents an item, and each value in the
|
||||||
|
tuple represents the item data for that column
|
||||||
|
"""
|
||||||
|
data = []
|
||||||
|
for i in range(0, model.rowCount()):
|
||||||
|
cat_idx = model.index(i, 0)
|
||||||
|
row = []
|
||||||
|
for j in range(0, model.rowCount(cat_idx)):
|
||||||
|
row.append((model.data(cat_idx.child(j, 0)),
|
||||||
|
model.data(cat_idx.child(j, 1)),
|
||||||
|
model.data(cat_idx.child(j, 2))))
|
||||||
|
data.append(row)
|
||||||
|
return data
|
||||||
|
|
||||||
@pytest.mark.parametrize('pattern, data, expected', [
|
@pytest.mark.parametrize('pattern, data, expected', [
|
||||||
('foo', 'barfoobar', True),
|
('foo', 'barfoobar', True),
|
||||||
('foo', 'barFOObar', True),
|
('foo', 'barFOObar', True),
|
||||||
@ -46,3 +81,145 @@ def test_filter_accepts_row(pattern, data, expected):
|
|||||||
|
|
||||||
row_count = filter_model.rowCount(idx)
|
row_count = filter_model.rowCount(idx)
|
||||||
assert row_count == (1 if expected else 0)
|
assert row_count == (1 if expected else 0)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('tree, first, last', [
|
||||||
|
([[('Aa',)]], 'Aa', 'Aa'),
|
||||||
|
([[('Aa',)], [('Ba',)]], 'Aa', 'Ba'),
|
||||||
|
([[('Aa',), ('Ab',), ('Ac',)], [('Ba',), ('Bb',)], [('Ca',)]],
|
||||||
|
'Aa', 'Ca'),
|
||||||
|
([[], [('Ba',)]], 'Ba', 'Ba'),
|
||||||
|
([[], [], [('Ca',)]], 'Ca', 'Ca'),
|
||||||
|
([[], [], [('Ca',), ('Cb',)]], 'Ca', 'Cb'),
|
||||||
|
([[('Aa',)], []], 'Aa', 'Aa'),
|
||||||
|
([[('Aa',)], []], 'Aa', 'Aa'),
|
||||||
|
([[('Aa',)], [], []], 'Aa', 'Aa'),
|
||||||
|
([[('Aa',)], [], [('Ca',)]], 'Aa', 'Ca'),
|
||||||
|
([[], []], None, None),
|
||||||
|
])
|
||||||
|
def test_first_last_item(tree, first, last):
|
||||||
|
"""Test that first() and last() return indexes to the first and last items.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tree: Each list represents a completion category, with each string
|
||||||
|
being an item under that category.
|
||||||
|
first: text of the first item
|
||||||
|
last: text of the last item
|
||||||
|
"""
|
||||||
|
model = _create_model(tree)
|
||||||
|
filter_model = sortfilter.CompletionFilterModel(model)
|
||||||
|
assert filter_model.data(filter_model.first_item()) == first
|
||||||
|
assert filter_model.data(filter_model.last_item()) == last
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_source_model():
|
||||||
|
"""Ensure setSourceModel sets source_model and clears the pattern."""
|
||||||
|
model1 = base.BaseCompletionModel()
|
||||||
|
model2 = base.BaseCompletionModel()
|
||||||
|
filter_model = sortfilter.CompletionFilterModel(model1)
|
||||||
|
filter_model.set_pattern('foo')
|
||||||
|
# sourceModel() is cached as srcmodel, so make sure both match
|
||||||
|
assert filter_model.srcmodel is model1
|
||||||
|
assert filter_model.sourceModel() is model1
|
||||||
|
assert filter_model.pattern == 'foo'
|
||||||
|
filter_model.setSourceModel(model2)
|
||||||
|
assert filter_model.srcmodel is model2
|
||||||
|
assert filter_model.sourceModel() is model2
|
||||||
|
assert not filter_model.pattern
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('tree, expected', [
|
||||||
|
([[('Aa',)]], 1),
|
||||||
|
([[('Aa',)], [('Ba',)]], 2),
|
||||||
|
([[('Aa',), ('Ab',), ('Ac',)], [('Ba',), ('Bb',)], [('Ca',)]], 6),
|
||||||
|
([[], [('Ba',)]], 1),
|
||||||
|
([[], [], [('Ca',)]], 1),
|
||||||
|
([[], [], [('Ca',), ('Cb',)]], 2),
|
||||||
|
([[('Aa',)], []], 1),
|
||||||
|
([[('Aa',)], []], 1),
|
||||||
|
([[('Aa',)], [], []], 1),
|
||||||
|
([[('Aa',)], [], [('Ca',)]], 2),
|
||||||
|
])
|
||||||
|
def test_count(tree, expected):
|
||||||
|
model = _create_model(tree)
|
||||||
|
filter_model = sortfilter.CompletionFilterModel(model)
|
||||||
|
assert filter_model.count() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('pattern, dumb_sort, filter_cols, before, after', [
|
||||||
|
('foo', None, [0],
|
||||||
|
[[('foo', '', ''), ('bar', '', '')]],
|
||||||
|
[[('foo', '', '')]]),
|
||||||
|
|
||||||
|
('foo', None, [0],
|
||||||
|
[[('foob', '', ''), ('fooc', '', ''), ('fooa', '', '')]],
|
||||||
|
[[('fooa', '', ''), ('foob', '', ''), ('fooc', '', '')]]),
|
||||||
|
|
||||||
|
('foo', None, [0],
|
||||||
|
[[('foo', '', '')], [('bar', '', '')]],
|
||||||
|
[[('foo', '', '')], []]),
|
||||||
|
|
||||||
|
# prefer foobar as it starts with the pattern
|
||||||
|
('foo', None, [0],
|
||||||
|
[[('barfoo', '', ''), ('foobar', '', '')]],
|
||||||
|
[[('foobar', '', ''), ('barfoo', '', '')]]),
|
||||||
|
|
||||||
|
# however, don't rearrange categories
|
||||||
|
('foo', None, [0],
|
||||||
|
[[('barfoo', '', '')], [('foobar', '', '')]],
|
||||||
|
[[('barfoo', '', '')], [('foobar', '', '')]]),
|
||||||
|
|
||||||
|
('foo', None, [1],
|
||||||
|
[[('foo', 'bar', ''), ('bar', 'foo', '')]],
|
||||||
|
[[('bar', 'foo', '')]]),
|
||||||
|
|
||||||
|
('foo', None, [0, 1],
|
||||||
|
[[('foo', 'bar', ''), ('bar', 'foo', ''), ('bar', 'bar', '')]],
|
||||||
|
[[('foo', 'bar', ''), ('bar', 'foo', '')]]),
|
||||||
|
|
||||||
|
('foo', None, [0, 1, 2],
|
||||||
|
[[('foo', '', ''), ('bar', '')]],
|
||||||
|
[[('foo', '', '')]]),
|
||||||
|
|
||||||
|
# the fourth column is the sort role, which overrides data-based sorting
|
||||||
|
('', None, [0],
|
||||||
|
[[('two', '', '', 2), ('one', '', '', 1), ('three', '', '', 3)]],
|
||||||
|
[[('one', '', ''), ('two', '', ''), ('three', '', '')]]),
|
||||||
|
|
||||||
|
('', Qt.AscendingOrder, [0],
|
||||||
|
[[('two', '', '', 2), ('one', '', '', 1), ('three', '', '', 3)]],
|
||||||
|
[[('one', '', ''), ('two', '', ''), ('three', '', '')]]),
|
||||||
|
|
||||||
|
('', Qt.DescendingOrder, [0],
|
||||||
|
[[('two', '', '', 2), ('one', '', '', 1), ('three', '', '', 3)]],
|
||||||
|
[[('three', '', ''), ('two', '', ''), ('one', '', '')]]),
|
||||||
|
])
|
||||||
|
def test_set_pattern(pattern, dumb_sort, filter_cols, before, after):
|
||||||
|
"""Validate the filtering and sorting results of set_pattern."""
|
||||||
|
model = _create_model(before)
|
||||||
|
model.DUMB_SORT = dumb_sort
|
||||||
|
model.columns_to_filter = filter_cols
|
||||||
|
filter_model = sortfilter.CompletionFilterModel(model)
|
||||||
|
filter_model.set_pattern(pattern)
|
||||||
|
actual = _extract_model_data(filter_model)
|
||||||
|
assert actual == after
|
||||||
|
|
||||||
|
|
||||||
|
def test_sort():
|
||||||
|
"""Ensure that a sort argument passed to sort overrides DUMB_SORT.
|
||||||
|
|
||||||
|
While test_set_pattern above covers most of the sorting logic, this
|
||||||
|
particular case is easier to test separately.
|
||||||
|
"""
|
||||||
|
model = _create_model([[('B', '', '', 1),
|
||||||
|
('C', '', '', 2),
|
||||||
|
('A', '', '', 0)]])
|
||||||
|
filter_model = sortfilter.CompletionFilterModel(model)
|
||||||
|
|
||||||
|
filter_model.sort(0, Qt.AscendingOrder)
|
||||||
|
actual = _extract_model_data(filter_model)
|
||||||
|
assert actual == [[('A', '', ''), ('B', '', ''), ('C', '', '')]]
|
||||||
|
|
||||||
|
filter_model.sort(0, Qt.DescendingOrder)
|
||||||
|
actual = _extract_model_data(filter_model)
|
||||||
|
assert actual == [[('C', '', ''), ('B', '', ''), ('A', '', '')]]
|
||||||
|
@ -287,6 +287,17 @@ class TestKeyConfigParser:
|
|||||||
('hint links fill ":open -t {hint-url}"',
|
('hint links fill ":open -t {hint-url}"',
|
||||||
'hint links fill :open -t {hint-url}'),
|
'hint links fill :open -t {hint-url}'),
|
||||||
|
|
||||||
|
('yank-selected', 'yank selection'),
|
||||||
|
('yank-selected --sel', 'yank selection --sel'),
|
||||||
|
('yank-selected -p', 'yank selection -s'),
|
||||||
|
|
||||||
|
('yank -t', 'yank title'),
|
||||||
|
('yank -ts', 'yank title -s'),
|
||||||
|
('yank -d', 'yank domain'),
|
||||||
|
('yank -ds', 'yank domain -s'),
|
||||||
|
('yank -p', 'yank pretty-url'),
|
||||||
|
('yank -ps', 'yank pretty-url -s'),
|
||||||
|
|
||||||
('paste', 'open {clipboard}'),
|
('paste', 'open {clipboard}'),
|
||||||
('paste -t', 'open -t {clipboard}'),
|
('paste -t', 'open -t {clipboard}'),
|
||||||
('paste -ws', 'open -w {primary}'),
|
('paste -ws', 'open -w {primary}'),
|
||||||
|
@ -69,14 +69,14 @@ class TestArg:
|
|||||||
config_stub.data['general']['editor'] = ['bin', 'foo', '{}', 'bar']
|
config_stub.data['general']['editor'] = ['bin', 'foo', '{}', 'bar']
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
editor._proc._proc.start.assert_called_with(
|
editor._proc._proc.start.assert_called_with(
|
||||||
"bin", ["foo", editor._filename, "bar"])
|
"bin", ["foo", editor._file.name, "bar"])
|
||||||
|
|
||||||
def test_placeholder_inline(self, config_stub, editor):
|
def test_placeholder_inline(self, config_stub, editor):
|
||||||
"""Test starting editor with placeholder arg inside of another arg."""
|
"""Test starting editor with placeholder arg inside of another arg."""
|
||||||
config_stub.data['general']['editor'] = ['bin', 'foo{}', 'bar']
|
config_stub.data['general']['editor'] = ['bin', 'foo{}', 'bar']
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
editor._proc._proc.start.assert_called_with(
|
editor._proc._proc.start.assert_called_with(
|
||||||
"bin", ["foo" + editor._filename, "bar"])
|
"bin", ["foo" + editor._file.name, "bar"])
|
||||||
|
|
||||||
|
|
||||||
class TestFileHandling:
|
class TestFileHandling:
|
||||||
@ -86,7 +86,7 @@ class TestFileHandling:
|
|||||||
def test_ok(self, editor):
|
def test_ok(self, editor):
|
||||||
"""Test file handling when closing with an exit status == 0."""
|
"""Test file handling when closing with an exit status == 0."""
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
filename = editor._filename
|
filename = editor._file.name
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
assert os.path.basename(filename).startswith('qutebrowser-editor-')
|
assert os.path.basename(filename).startswith('qutebrowser-editor-')
|
||||||
editor._proc.finished.emit(0, QProcess.NormalExit)
|
editor._proc.finished.emit(0, QProcess.NormalExit)
|
||||||
@ -95,7 +95,7 @@ class TestFileHandling:
|
|||||||
def test_error(self, editor):
|
def test_error(self, editor):
|
||||||
"""Test file handling when closing with an exit status != 0."""
|
"""Test file handling when closing with an exit status != 0."""
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
filename = editor._filename
|
filename = editor._file.name
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
|
|
||||||
editor._proc._proc.exitStatus = mock.Mock(
|
editor._proc._proc.exitStatus = mock.Mock(
|
||||||
@ -109,7 +109,7 @@ class TestFileHandling:
|
|||||||
def test_crash(self, editor):
|
def test_crash(self, editor):
|
||||||
"""Test file handling when closing with a crash."""
|
"""Test file handling when closing with a crash."""
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
filename = editor._filename
|
filename = editor._file.name
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
|
|
||||||
editor._proc._proc.exitStatus = mock.Mock(
|
editor._proc._proc.exitStatus = mock.Mock(
|
||||||
@ -125,7 +125,7 @@ class TestFileHandling:
|
|||||||
def test_unreadable(self, message_mock, editor):
|
def test_unreadable(self, message_mock, editor):
|
||||||
"""Test file handling when closing with an unreadable file."""
|
"""Test file handling when closing with an unreadable file."""
|
||||||
editor.edit("")
|
editor.edit("")
|
||||||
filename = editor._filename
|
filename = editor._file.name
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
os.chmod(filename, 0o077)
|
os.chmod(filename, 0o077)
|
||||||
editor._proc.finished.emit(0, QProcess.NormalExit)
|
editor._proc.finished.emit(0, QProcess.NormalExit)
|
||||||
@ -160,10 +160,10 @@ def test_modify(editor, initial_text, edited_text):
|
|||||||
"""Test if inputs get modified correctly."""
|
"""Test if inputs get modified correctly."""
|
||||||
editor.edit(initial_text)
|
editor.edit(initial_text)
|
||||||
|
|
||||||
with open(editor._filename, 'r', encoding='utf-8') as f:
|
with open(editor._file.name, 'r', encoding='utf-8') as f:
|
||||||
assert f.read() == initial_text
|
assert f.read() == initial_text
|
||||||
|
|
||||||
with open(editor._filename, 'w', encoding='utf-8') as f:
|
with open(editor._file.name, 'w', encoding='utf-8') as f:
|
||||||
f.write(edited_text)
|
f.write(edited_text)
|
||||||
|
|
||||||
editor._proc.finished.emit(0, QProcess.NormalExit)
|
editor._proc.finished.emit(0, QProcess.NormalExit)
|
||||||
|
Loading…
Reference in New Issue
Block a user