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
|
tests/unit/misc/test_sql.py @rcorre
|
||||||
|
|
||||||
qutebrowser/config/configdata.yml @mschilli87
|
qutebrowser/config/configdata.yml @mschilli87
|
||||||
|
|
||||||
|
qutebrowser/javascript/caret.js @artur-shaik
|
||||||
|
@ -393,7 +393,7 @@ class AbstractCaret(QObject):
|
|||||||
def has_selection(self):
|
def has_selection(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def selection(self, html=False):
|
def selection(self, html=False, callback=None):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def follow_selected(self, *, tab=False):
|
def follow_selected(self, *, tab=False):
|
||||||
|
@ -849,14 +849,21 @@ class CommandDispatcher:
|
|||||||
s = self._yank_url(what)
|
s = self._yank_url(what)
|
||||||
what = 'URL' # For printing
|
what = 'URL' # For printing
|
||||||
elif what == 'selection':
|
elif what == 'selection':
|
||||||
caret = self._current_widget().caret
|
def _selection_callback(s):
|
||||||
s = caret.selection()
|
if not self._current_widget().caret.has_selection() or not s:
|
||||||
if not caret.has_selection() or not s:
|
|
||||||
message.info("Nothing to yank")
|
message.info("Nothing to yank")
|
||||||
return
|
return
|
||||||
|
self._yank_to_target(s, sel, what, keep)
|
||||||
|
|
||||||
|
caret = self._current_widget().caret
|
||||||
|
caret.selection(callback=_selection_callback)
|
||||||
|
return
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
raise ValueError("Invalid value {!r} for `what'.".format(what))
|
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():
|
if sel and utils.supports_selection():
|
||||||
target = "primary selection"
|
target = "primary selection"
|
||||||
else:
|
else:
|
||||||
@ -1208,8 +1215,19 @@ class CommandDispatcher:
|
|||||||
log.procs.debug("Executing {} with args {}, userscript={}".format(
|
log.procs.debug("Executing {} with args {}, userscript={}".format(
|
||||||
cmd, args, userscript))
|
cmd, args, userscript))
|
||||||
if 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.
|
# ~ 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:
|
else:
|
||||||
cmd = os.path.expanduser(cmd)
|
cmd = os.path.expanduser(cmd)
|
||||||
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
|
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
|
||||||
@ -1229,7 +1247,7 @@ class CommandDispatcher:
|
|||||||
"""Open main startpage in current tab."""
|
"""Open main startpage in current tab."""
|
||||||
self.openurl(config.val.url.start_pages[0])
|
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.
|
"""Run a userscript given as argument.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -1247,7 +1265,7 @@ class CommandDispatcher:
|
|||||||
|
|
||||||
tab = self._tabbed_browser.currentWidget()
|
tab = self._tabbed_browser.currentWidget()
|
||||||
if tab is not None and tab.caret.has_selection():
|
if tab is not None and tab.caret.has_selection():
|
||||||
env['QUTE_SELECTED_TEXT'] = tab.caret.selection()
|
env['QUTE_SELECTED_TEXT'] = selection
|
||||||
try:
|
try:
|
||||||
env['QUTE_SELECTED_HTML'] = tab.caret.selection(html=True)
|
env['QUTE_SELECTED_HTML'] = tab.caret.selection(html=True)
|
||||||
except browsertab.UnsupportedOperationError:
|
except browsertab.UnsupportedOperationError:
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
import math
|
import math
|
||||||
import functools
|
import functools
|
||||||
|
import sys
|
||||||
import html as html_utils
|
import html as html_utils
|
||||||
|
|
||||||
import sip
|
import sip
|
||||||
@ -201,70 +202,98 @@ class WebEngineCaret(browsertab.AbstractCaret):
|
|||||||
|
|
||||||
@pyqtSlot(usertypes.KeyMode)
|
@pyqtSlot(usertypes.KeyMode)
|
||||||
def _on_mode_entered(self, mode):
|
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)
|
@pyqtSlot(usertypes.KeyMode)
|
||||||
def _on_mode_left(self):
|
def _on_mode_left(self):
|
||||||
pass
|
self.drop_selection()
|
||||||
|
self._js_call('disableCaret')
|
||||||
|
|
||||||
def move_to_next_line(self, count=1):
|
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):
|
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):
|
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):
|
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):
|
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):
|
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):
|
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):
|
def move_to_start_of_line(self):
|
||||||
log.stub()
|
self._js_call('moveToStartOfLine')
|
||||||
|
|
||||||
def move_to_end_of_line(self):
|
def move_to_end_of_line(self):
|
||||||
log.stub()
|
self._js_call('moveToEndOfLine')
|
||||||
|
|
||||||
def move_to_start_of_next_block(self, count=1):
|
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):
|
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):
|
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):
|
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):
|
def move_to_start_of_document(self):
|
||||||
log.stub()
|
self._js_call('moveToStartOfDocument')
|
||||||
|
|
||||||
def move_to_end_of_document(self):
|
def move_to_end_of_document(self):
|
||||||
log.stub()
|
self._js_call('moveToEndOfDocument')
|
||||||
|
|
||||||
def toggle_selection(self):
|
def toggle_selection(self):
|
||||||
log.stub()
|
self._js_call('toggleSelection')
|
||||||
|
|
||||||
def drop_selection(self):
|
def drop_selection(self):
|
||||||
log.stub()
|
self._js_call('dropSelection')
|
||||||
|
|
||||||
def has_selection(self):
|
def has_selection(self):
|
||||||
|
if qtutils.version_check('5.10'):
|
||||||
return self._widget.hasSelection()
|
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:
|
if html:
|
||||||
raise browsertab.UnsupportedOperationError
|
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):
|
def _follow_selected_cb(self, js_elem, tab=False):
|
||||||
"""Callback for javascript which clicks the selected element.
|
"""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._tab.run_js_async(js_code, lambda jsret:
|
||||||
self._follow_selected_cb(jsret, tab))
|
self._follow_selected_cb(jsret, tab))
|
||||||
|
|
||||||
|
def _js_call(self, command):
|
||||||
|
self._tab.run_js_async(
|
||||||
|
javascript.assemble('caret', command))
|
||||||
|
|
||||||
|
|
||||||
class WebEngineScroller(browsertab.AbstractScroller):
|
class WebEngineScroller(browsertab.AbstractScroller):
|
||||||
|
|
||||||
@ -577,6 +610,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
'window._qutebrowser = window._qutebrowser || {};',
|
'window._qutebrowser = window._qutebrowser || {};',
|
||||||
utils.read_file('javascript/scroll.js'),
|
utils.read_file('javascript/scroll.js'),
|
||||||
utils.read_file('javascript/webelem.js'),
|
utils.read_file('javascript/webelem.js'),
|
||||||
|
utils.read_file('javascript/caret.js'),
|
||||||
])
|
])
|
||||||
script = QWebEngineScript()
|
script = QWebEngineScript()
|
||||||
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
||||||
|
@ -161,7 +161,7 @@ class WebKitCaret(browsertab.AbstractCaret):
|
|||||||
|
|
||||||
settings = self._widget.settings()
|
settings = self._widget.settings()
|
||||||
settings.setAttribute(QWebSettings.CaretBrowsingEnabled, True)
|
settings.setAttribute(QWebSettings.CaretBrowsingEnabled, True)
|
||||||
self.selection_enabled = bool(self.selection())
|
self.selection_enabled = bool(self._selection())
|
||||||
|
|
||||||
if self._widget.isVisible():
|
if self._widget.isVisible():
|
||||||
# Sometimes the caret isn't immediately visible, but unfocusing
|
# 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
|
# Note: We can't use hasSelection() here, as that's always
|
||||||
# true in caret mode.
|
# true in caret mode.
|
||||||
if not self.selection():
|
if not self.selection_enabled:
|
||||||
self._widget.page().currentFrame().evaluateJavaScript(
|
self._widget.page().currentFrame().evaluateJavaScript(
|
||||||
utils.read_file('javascript/position_caret.js'))
|
utils.read_file('javascript/position_caret.js'))
|
||||||
|
|
||||||
@ -336,9 +336,13 @@ class WebKitCaret(browsertab.AbstractCaret):
|
|||||||
def has_selection(self):
|
def has_selection(self):
|
||||||
return self._widget.hasSelection()
|
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:
|
if html:
|
||||||
return self._widget.selectedHtml()
|
return self._widget.selectedHtml()
|
||||||
|
else:
|
||||||
return self._widget.selectedText()
|
return self._widget.selectedText()
|
||||||
|
|
||||||
def follow_selected(self, *, tab=False):
|
def follow_selected(self, *, tab=False):
|
||||||
@ -351,7 +355,7 @@ class WebKitCaret(browsertab.AbstractCaret):
|
|||||||
self._tab.run_js_async(
|
self._tab.run_js_async(
|
||||||
'window.getSelection().anchorNode.parentNode.click()')
|
'window.getSelection().anchorNode.parentNode.click()')
|
||||||
else:
|
else:
|
||||||
selection = self.selection(html=True)
|
selection = self._selection(html=True)
|
||||||
try:
|
try:
|
||||||
selected_element = xml.etree.ElementTree.fromstring(
|
selected_element = xml.etree.ElementTree.fromstring(
|
||||||
'<html>{}</html>'.format(selection)).find('a')
|
'<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.config import config
|
||||||
from qutebrowser.commands import cmdexc, cmdutils
|
from qutebrowser.commands import cmdexc, cmdutils
|
||||||
from qutebrowser.utils import usertypes, log, objreg, utils
|
from qutebrowser.utils import usertypes, log, objreg, utils
|
||||||
from qutebrowser.misc import objects
|
|
||||||
|
|
||||||
|
|
||||||
@attr.s(frozen=True)
|
@attr.s(frozen=True)
|
||||||
@ -267,10 +266,6 @@ class ModeManager(QObject):
|
|||||||
usertypes.KeyMode.yesno, usertypes.KeyMode.prompt]:
|
usertypes.KeyMode.yesno, usertypes.KeyMode.prompt]:
|
||||||
raise cmdexc.CommandError(
|
raise cmdexc.CommandError(
|
||||||
"Mode {} can't be entered manually!".format(mode))
|
"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')
|
self.enter(m, 'command')
|
||||||
|
|
||||||
|
@ -129,7 +129,6 @@ Feature: Opening external editors
|
|||||||
And I kill the waiting editor
|
And I kill the waiting editor
|
||||||
Then the error "Edited element vanished" should be shown
|
Then the error "Edited element vanished" should be shown
|
||||||
|
|
||||||
@qtwebengine_todo: Caret mode is not implemented yet
|
|
||||||
Scenario: Spawning an editor in caret mode
|
Scenario: Spawning an editor in caret mode
|
||||||
When I set up a fake editor returning "foobar"
|
When I set up a fake editor returning "foobar"
|
||||||
And I open data/editor.html
|
And I open data/editor.html
|
||||||
|
@ -17,15 +17,9 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pytest
|
|
||||||
import pytest_bdd as bdd
|
import pytest_bdd as bdd
|
||||||
|
|
||||||
# pylint: disable=unused-import
|
# pylint: disable=unused-import
|
||||||
from end2end.features.test_yankpaste_bdd import init_fake_clipboard
|
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')
|
bdd.scenarios('caret.feature')
|
||||||
|
Loading…
Reference in New Issue
Block a user