Merge remote-tracking branch 'origin/pr/3348'
This commit is contained in:
commit
1f5cbf21a3
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
1368
qutebrowser/javascript/caret.js
Normal file
1368
qutebrowser/javascript/caret.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -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')
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user