Merge remote-tracking branch 'origin/pr/3348'

This commit is contained in:
Florian Bruhin 2018-01-20 18:28:14 +01:00
commit 1f5cbf21a3
9 changed files with 1461 additions and 47 deletions

2
.github/CODEOWNERS vendored
View File

@ -8,3 +8,5 @@ tests/unit/completion/* @rcorre
tests/unit/misc/test_sql.py @rcorre
qutebrowser/config/configdata.yml @mschilli87
qutebrowser/javascript/caret.js @artur-shaik

View File

@ -393,7 +393,7 @@ class AbstractCaret(QObject):
def has_selection(self):
raise NotImplementedError
def selection(self, html=False):
def selection(self, html=False, callback=None):
raise NotImplementedError
def follow_selected(self, *, tab=False):

View File

@ -849,14 +849,21 @@ class CommandDispatcher:
s = self._yank_url(what)
what = 'URL' # For printing
elif what == 'selection':
def _selection_callback(s):
if not self._current_widget().caret.has_selection() or not s:
message.info("Nothing to yank")
return
self._yank_to_target(s, sel, what, keep)
caret = self._current_widget().caret
s = caret.selection()
if not caret.has_selection() or not s:
message.info("Nothing to yank")
return
caret.selection(callback=_selection_callback)
return
else: # pragma: no cover
raise ValueError("Invalid value {!r} for `what'.".format(what))
self._yank_to_target(s, sel, what, keep)
def _yank_to_target(self, s, sel, what, keep):
if sel and utils.supports_selection():
target = "primary selection"
else:
@ -1208,8 +1215,19 @@ class CommandDispatcher:
log.procs.debug("Executing {} with args {}, userscript={}".format(
cmd, args, userscript))
if userscript:
def _selection_callback(s):
try:
self._run_userscript(s, cmd, args, verbose)
except cmdexc.CommandError as e:
message.error(str(e))
# ~ expansion is handled by the userscript module.
self._run_userscript(cmd, *args, verbose=verbose)
# dirty hack for async call because of:
# https://bugreports.qt.io/browse/QTBUG-53134
# until it fixed or blocked async call implemented:
# https://github.com/qutebrowser/qutebrowser/issues/3327
caret = self._current_widget().caret
caret.selection(callback=_selection_callback)
else:
cmd = os.path.expanduser(cmd)
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
@ -1229,7 +1247,7 @@ class CommandDispatcher:
"""Open main startpage in current tab."""
self.openurl(config.val.url.start_pages[0])
def _run_userscript(self, cmd, *args, verbose=False):
def _run_userscript(self, selection, cmd, args, verbose):
"""Run a userscript given as argument.
Args:
@ -1247,7 +1265,7 @@ class CommandDispatcher:
tab = self._tabbed_browser.currentWidget()
if tab is not None and tab.caret.has_selection():
env['QUTE_SELECTED_TEXT'] = tab.caret.selection()
env['QUTE_SELECTED_TEXT'] = selection
try:
env['QUTE_SELECTED_HTML'] = tab.caret.selection(html=True)
except browsertab.UnsupportedOperationError:

View File

@ -21,6 +21,7 @@
import math
import functools
import sys
import html as html_utils
import sip
@ -201,70 +202,98 @@ class WebEngineCaret(browsertab.AbstractCaret):
@pyqtSlot(usertypes.KeyMode)
def _on_mode_entered(self, mode):
pass
if mode != usertypes.KeyMode.caret:
return
self._tab.run_js_async(
javascript.assemble('caret', 'setPlatform', sys.platform))
self._js_call('setInitialCursor')
@pyqtSlot(usertypes.KeyMode)
def _on_mode_left(self):
pass
self.drop_selection()
self._js_call('disableCaret')
def move_to_next_line(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveDown')
def move_to_prev_line(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveUp')
def move_to_next_char(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveRight')
def move_to_prev_char(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveLeft')
def move_to_end_of_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfWord')
def move_to_next_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToNextWord')
def move_to_prev_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToPreviousWord')
def move_to_start_of_line(self):
log.stub()
self._js_call('moveToStartOfLine')
def move_to_end_of_line(self):
log.stub()
self._js_call('moveToEndOfLine')
def move_to_start_of_next_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToStartOfNextBlock')
def move_to_start_of_prev_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToStartOfPrevBlock')
def move_to_end_of_next_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfNextBlock')
def move_to_end_of_prev_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfPrevBlock')
def move_to_start_of_document(self):
log.stub()
self._js_call('moveToStartOfDocument')
def move_to_end_of_document(self):
log.stub()
self._js_call('moveToEndOfDocument')
def toggle_selection(self):
log.stub()
self._js_call('toggleSelection')
def drop_selection(self):
log.stub()
self._js_call('dropSelection')
def has_selection(self):
return self._widget.hasSelection()
if qtutils.version_check('5.10'):
return self._widget.hasSelection()
else:
# WORKAROUND for
# https://bugreports.qt.io/browse/QTBUG-53134
return True
def selection(self, html=False):
def selection(self, html=False, callback=None):
if html:
raise browsertab.UnsupportedOperationError
return self._widget.selectedText()
if qtutils.version_check('5.10'):
callback(self._widget.selectedText())
else:
# WORKAROUND for
# https://bugreports.qt.io/browse/QTBUG-53134
self._tab.run_js_async(
javascript.assemble('caret', 'getSelection'), callback)
def _follow_selected_cb(self, js_elem, tab=False):
"""Callback for javascript which clicks the selected element.
@ -308,6 +337,10 @@ class WebEngineCaret(browsertab.AbstractCaret):
self._tab.run_js_async(js_code, lambda jsret:
self._follow_selected_cb(jsret, tab))
def _js_call(self, command):
self._tab.run_js_async(
javascript.assemble('caret', command))
class WebEngineScroller(browsertab.AbstractScroller):
@ -577,6 +610,7 @@ class WebEngineTab(browsertab.AbstractTab):
'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/scroll.js'),
utils.read_file('javascript/webelem.js'),
utils.read_file('javascript/caret.js'),
])
script = QWebEngineScript()
script.setInjectionPoint(QWebEngineScript.DocumentCreation)

View File

@ -161,7 +161,7 @@ class WebKitCaret(browsertab.AbstractCaret):
settings = self._widget.settings()
settings.setAttribute(QWebSettings.CaretBrowsingEnabled, True)
self.selection_enabled = bool(self.selection())
self.selection_enabled = bool(self._selection())
if self._widget.isVisible():
# Sometimes the caret isn't immediately visible, but unfocusing
@ -174,7 +174,7 @@ class WebKitCaret(browsertab.AbstractCaret):
#
# Note: We can't use hasSelection() here, as that's always
# true in caret mode.
if not self.selection():
if not self.selection_enabled:
self._widget.page().currentFrame().evaluateJavaScript(
utils.read_file('javascript/position_caret.js'))
@ -336,10 +336,14 @@ class WebKitCaret(browsertab.AbstractCaret):
def has_selection(self):
return self._widget.hasSelection()
def selection(self, html=False):
def selection(self, html=False, callback=False):
callback(self._selection(html))
def _selection(self, html=False):
if html:
return self._widget.selectedHtml()
return self._widget.selectedText()
else:
return self._widget.selectedText()
def follow_selected(self, *, tab=False):
if not self.has_selection():
@ -351,7 +355,7 @@ class WebKitCaret(browsertab.AbstractCaret):
self._tab.run_js_async(
'window.getSelection().anchorNode.parentNode.click()')
else:
selection = self.selection(html=True)
selection = self._selection(html=True)
try:
selected_element = xml.etree.ElementTree.fromstring(
'<html>{}</html>'.format(selection)).find('a')

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,6 @@ from qutebrowser.keyinput import modeparsers, keyparser
from qutebrowser.config import config
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.misc import objects
@attr.s(frozen=True)
@ -267,10 +266,6 @@ class ModeManager(QObject):
usertypes.KeyMode.yesno, usertypes.KeyMode.prompt]:
raise cmdexc.CommandError(
"Mode {} can't be entered manually!".format(mode))
elif (m == usertypes.KeyMode.caret and
objects.backend == usertypes.Backend.QtWebEngine):
raise cmdexc.CommandError("Caret mode is not supported with "
"QtWebEngine yet.")
self.enter(m, 'command')

View File

@ -129,7 +129,6 @@ Feature: Opening external editors
And I kill the waiting editor
Then the error "Edited element vanished" should be shown
@qtwebengine_todo: Caret mode is not implemented yet
Scenario: Spawning an editor in caret mode
When I set up a fake editor returning "foobar"
And I open data/editor.html

View File

@ -17,15 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
import pytest
import pytest_bdd as bdd
# pylint: disable=unused-import
from end2end.features.test_yankpaste_bdd import init_fake_clipboard
pytestmark = pytest.mark.qtwebengine_todo("Caret mode is not implemented",
run=False)
bdd.scenarios('caret.feature')