internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: qutebrowser/qutebrowser

Issue:
Allow hint --rapid with normal
Right now rapid hinting is disabled in `normal` hint mode.
Recently I had to delete a bunch of items from my Amazon shopping cart.
There are no checkboxes to perform a multi-select, just a `delete` link on each item.

I removed the limitation on using `--rapid` with `normal`, and to my suprise, it worked!
It was a little disorienting as the link positions shifted each time I deleted an item, but it saved me from pressing `f` each time.

Should we remove this limitation?



Discussion:
Hmm, good point. When I added the limitation I didn't think about clicking links which do something other than following a new link.

I bet it's nice when having to tick a lot of checkboxes for some reason too. Let's get rid of it!


Resolving patch:
diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py
--- a/qutebrowser/browser/hints.py
+++ b/qutebrowser/browser/hints.py
@@ -846,7 +846,7 @@ def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
         if rapid:
             if target in [Target.tab_bg, Target.window, Target.run,
                           Target.hover, Target.userscript, Target.spawn,
-                          Target.download]:
+                          Target.download, Target.normal, Target.current]:
                 pass
             elif (target == Target.tab and
                   config.get('tabs', 'background-tabs')):


Test patch:
diff --git a/tests/end2end/data/hints/buttons.html b/tests/end2end/data/hints/buttons.html
new file mode 100644
--- /dev/null
+++ b/tests/end2end/data/hints/buttons.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Rapid hinting with buttons</title>
+    </head>
+    <body>
+        <input type="text" id="number" value="0"/>
+        <button onclick="console.log('beep!')">beep!</button>
+        <button onclick="console.log('bop!')">bop!</button>
+        <button onclick="console.log('boop!')">boop!</button>
+    </body>
+</html>
diff --git a/tests/end2end/features/hints.feature b/tests/end2end/features/hints.feature
--- a/tests/end2end/features/hints.feature
+++ b/tests/end2end/features/hints.feature
@@ -97,6 +97,16 @@ Feature: Using hints
         And I run :follow-hint a
         Then the clipboard should contain "http://localhost:(port)/data/hello.txt"
 
+    Scenario: Using hint --rapid to hit multiple buttons
+        When I open data/hints/buttons.html
+        And I run :hint --rapid
+        And I run :follow-hint s
+        And I run :follow-hint d
+        And I run :follow-hint f
+        Then the javascript message "beep!" should be logged
+        And the javascript message "bop!" should be logged
+        And the javascript message "boop!" should be logged
+
     ### iframes
     ### FIXME currenly skipped, see https://github.com/The-Compiler/qutebrowser/issues/1525
Repository: qutebrowser/qutebrowser

Issue:
Make C-w behave like in readline
Hi, I'm used to `C-w` deleting up to the next whitespace.

For example, if your command is : `:open -t http://google.com`, Hitting `C-w` should remove the whole http://google.com part, however it only removes up to the first `.`.

Usually the readline binding to remove up to the next word is bound to `C-Backspace`



Discussion:
The associated command (`:rl-unix-word-rubout`) simply uses Qt's [`QLineEdit::cursorWordBackward`](http://doc.qt.io/qt-5/qlineedit.html#cursorWordBackward) currently which has that behaviour. It should probably do the word matching manually to match words like readline.

It seems that there isn't any standard component for readline keybindings in Qt, maybe I will find the time to create such a library :-)

I won't be able to use an external library which isn't commonly packaged in distributions, but a pullrequest to fix this in qutebrowser's [`readline.py`](https://github.com/The-Compiler/qutebrowser/blob/master/qutebrowser/misc/readline.py#L151-L163) would certainly be most welcome!


Resolving patch:
diff --git a/qutebrowser/misc/readline.py b/qutebrowser/misc/readline.py
--- a/qutebrowser/misc/readline.py
+++ b/qutebrowser/misc/readline.py
@@ -158,7 +158,23 @@ def rl_unix_word_rubout(self):
         widget = self._widget()
         if widget is None:
             return
-        widget.cursorWordBackward(True)
+        cursor_position = widget.cursorPosition()
+        text = widget.text()
+
+        target_position = cursor_position
+
+        is_word_boundary = True
+        while is_word_boundary and target_position > 0:
+            is_word_boundary = text[target_position - 1] == " "
+            target_position -= 1
+
+        is_word_boundary = False
+        while not is_word_boundary and target_position > 0:
+            is_word_boundary = text[target_position - 1] == " "
+            target_position -= 1
+
+        moveby = cursor_position - target_position - 1
+        widget.cursorBackward(True, moveby)
         self._deleted[widget] = widget.selectedText()
         widget.del_()
 


Test patch:
diff --git a/tests/unit/misc/test_readline.py b/tests/unit/misc/test_readline.py
--- a/tests/unit/misc/test_readline.py
+++ b/tests/unit/misc/test_readline.py
@@ -234,6 +234,8 @@ def test_rl_kill_line(lineedit, bridge, text, deleted, rest):
 @pytest.mark.parametrize('text, deleted, rest', [
     ('test delete|foobar', 'delete', 'test |foobar'),
     ('test delete |foobar', 'delete ', 'test |foobar'),
+    ('open -t github.com/foo/bar  |', 'github.com/foo/bar  ', 'open -t |'),
+    ('open -t |github.com/foo/bar', '-t ', 'open |github.com/foo/bar'),
     fixme(('test del<ete>foobar', 'delete', 'test |foobar')),
     ('test del<ete >foobar', 'del', 'test |ete foobar'),  # wrong
 ])
Repository: qutebrowser/qutebrowser

Issue:
AssertionError when canceling a download with :prompt-open-download
When downloading something, hitting `ctrl-x` and then doing `:download-cancel`:

```
23:35:32 DEBUG    commands   command:run:523 Calling qutebrowser.browser.webkit.downloads.DownloadManager.download_cancel(<qutebrowser.browser.webkit.downloads.DownloadManager downloads=1>, False, 0)
23:35:32 DEBUG    downloads  downloads:cancel:493 cancelled
23:35:32 ERROR    misc       crashsignal:exception_hook:211 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/browser/webkit/downloads.py", line 533, in open_file
    assert self.successful
AssertionError
```

Another one for @Kingdread I guess :laughing: 

Thanks @ultrasabreman for the report!



Discussion:

Resolving patch:
diff --git a/qutebrowser/browser/webkit/downloads.py b/qutebrowser/browser/webkit/downloads.py
--- a/qutebrowser/browser/webkit/downloads.py
+++ b/qutebrowser/browser/webkit/downloads.py
@@ -947,13 +947,28 @@ def _set_download_target(self, download, suggested_filename, target):
             download.set_filename(target.filename)
         elif isinstance(target, usertypes.OpenFileDownloadTarget):
             tmp_manager = objreg.get('temporary-downloads')
-            fobj = tmp_manager.get_tmpfile(suggested_filename)
-            download.finished.connect(download.open_file)
+            try:
+                fobj = tmp_manager.get_tmpfile(suggested_filename)
+            except OSError as exc:
+                msg = "Download error: {}".format(exc)
+                message.error(self._win_id, msg)
+                download.cancel()
+                return
+            download.finished.connect(
+                functools.partial(self._open_download, download))
             download.autoclose = True
             download.set_fileobj(fobj)
         else:
             log.downloads.error("Unknown download target: {}".format(target))
 
+    def _open_download(self, download):
+        """Open the given download but only if it was successful."""
+        if download.successful:
+            download.open_file()
+        else:
+            log.downloads.debug("{} finished but not successful, not opening!"
+                                .format(download))
+
     def raise_no_download(self, count):
         """Raise an exception that the download doesn't exist.
 
@@ -1316,6 +1331,11 @@ def get_tmpfile(self, suggested_name):
             A tempfile.NamedTemporaryFile that should be used to save the file.
         """
         tmpdir = self._get_tmpdir()
+        encoding = sys.getfilesystemencoding()
+        suggested_name = utils.force_encoding(suggested_name, encoding)
+        # Make sure that the filename is not too long
+        if len(suggested_name) > 20:
+            suggested_name = suggested_name[:10] + '...' + suggested_name[-10:]
         fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False,
                                            suffix=suggested_name)
         self.files.append(fobj)


Test patch:
Repository: qutebrowser/qutebrowser

Issue:
Buffer command does not complete on id
When the `:buffer` completions are shown, typing in the numbers for the tab indices does not get completed.



Discussion:
Hmm, do you think it should? Not sure if it's very useful.

As a result of completions always being filtered as you type, because there are no completions on the tab indices, it makes it confusing typing a tab index, because if there are no completions on the tab indices then the tab index you were just typing might disappear as you were typing it.


Resolving patch:
diff --git a/qutebrowser/completion/models/miscmodels.py b/qutebrowser/completion/models/miscmodels.py
--- a/qutebrowser/completion/models/miscmodels.py
+++ b/qutebrowser/completion/models/miscmodels.py
@@ -148,7 +148,8 @@ class TabCompletionModel(base.BaseCompletionModel):
     def __init__(self, parent=None):
         super().__init__(parent)
 
-        self.columns_to_filter = [self.URL_COLUMN, self.TEXT_COLUMN]
+        self.columns_to_filter = [self.IDX_COLUMN, self.URL_COLUMN,
+                                  self.TEXT_COLUMN]
 
         for win_id in objreg.window_registry:
             tabbed_browser = objreg.get('tabbed-browser', scope='window',


Test patch:
Repository: qutebrowser/qutebrowser

Issue:
tab-detach does not fail on a single tab
When `:tab-detach` is run on a window with one tab, it still runs, which can result in cloning your tab (depending on your settings potentially).



Discussion:

Resolving patch:
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -424,6 +424,8 @@ def tab_clone(self, bg=False, window=False):
     @cmdutils.register(instance='command-dispatcher', scope='window')
     def tab_detach(self):
         """Detach the current tab to its own window."""
+        if self._count() < 2:
+            raise cmdexc.CommandError("Cannot detach one tab.")
         url = self._current_url()
         self._open(url, window=True)
         cur_widget = self._current_widget()


Test patch:
diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature
--- a/tests/end2end/features/tabs.feature
+++ b/tests/end2end/features/tabs.feature
@@ -620,6 +620,11 @@ Feature: Tab management
               - history:
                 - url: http://localhost:*/data/numbers/2.txt
 
+    Scenario: Detach tab from window with only one tab
+        When I open data/hello.txt
+        And I run :tab-detach
+        Then the error "Cannot detach one tab." should be shown
+
     # :undo
 
     Scenario: Undo without any closed tabs
Repository: qutebrowser/qutebrowser

Issue:
open-editor should work outside of insert mode
`open-editor` should open the editor on whatever input field my cursor is in,
same as if I had done `enter-mode insert ;; open-editor ;; leave-mode`
instead.

It's not a big deal because you can currently just create precisely that
binding on your own, but there's still no technical reason to restrict it.



Discussion:
This should probably be a matter of writing a test and removing the respective constraint.


Resolving patch:
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -1472,8 +1472,8 @@ def _open_editor_cb(self, elem):
             self.on_editing_finished, elem))
         ed.edit(text)
 
-    @cmdutils.register(instance='command-dispatcher',
-                       modes=[KeyMode.insert], hide=True, scope='window')
+    @cmdutils.register(instance='command-dispatcher', hide=True,
+                       scope='window')
     def open_editor(self):
         """Open an external editor with the currently selected form field.
 


Test patch:
diff --git a/tests/end2end/features/editor.feature b/tests/end2end/features/editor.feature
--- a/tests/end2end/features/editor.feature
+++ b/tests/end2end/features/editor.feature
@@ -67,3 +67,29 @@ Feature: Opening external editors
         And I wait for "Read back: foobar" in the log
         And I run :click-element id qute-button
         Then the javascript message "text: foobar" should be logged
+
+    Scenario: Spawning an editor in normal mode
+        When I set up a fake editor returning "foobar"
+        And I open data/editor.html
+        And I run :click-element id qute-textarea
+        And I wait for "Clicked editable element!" in the log
+        And I run :leave-mode
+        And I wait for "Leaving mode KeyMode.insert (reason: leave current)" in the log
+        And I run :open-editor
+        And I wait for "Read back: foobar" in the log
+        And I run :click-element id qute-button
+        Then the javascript message "text: foobar" should be logged
+
+    Scenario: Spawning an editor in caret mode
+        When I set up a fake editor returning "foobar"
+        And I open data/editor.html
+        And I run :click-element id qute-textarea
+        And I wait for "Clicked editable element!" in the log
+        And I run :leave-mode
+        And I wait for "Leaving mode KeyMode.insert (reason: leave current)" in the log
+        And I run :enter-mode caret
+        And I wait for "Entering mode KeyMode.caret (reason: command)" in the log
+        And I run :open-editor
+        And I wait for "Read back: foobar" in the log
+        And I run :click-element id qute-button
+        Then the javascript message "text: foobar" should be logged
Repository: qutebrowser/qutebrowser

Issue:
QtWebKit: Handle visibility API
See https://github.com/OtterBrowser/otter-browser/commit/6500972092a562e23271ccf9aff4fdeed21d8290



Discussion:

Resolving patch:
diff --git a/qutebrowser/browser/webkit/webview.py b/qutebrowser/browser/webkit/webview.py
--- a/qutebrowser/browser/webkit/webview.py
+++ b/qutebrowser/browser/webkit/webview.py
@@ -72,6 +72,14 @@ def __init__(self, win_id, tab_id, tab, parent=None):
 
         page = webpage.BrowserPage(self.win_id, self._tab_id, tab.data,
                                    parent=self)
+
+        try:
+            page.setVisibilityState(
+                QWebPage.VisibilityStateVisible if self.isVisible()
+                else QWebPage.VisibilityStateHidden)
+        except AttributeError:
+            pass
+
         self.setPage(page)
 
         mode_manager = objreg.get('mode-manager', scope='window',
@@ -240,3 +248,35 @@ def contextMenuEvent(self, e):
         self.shutting_down.connect(menu.close)
         modeman.instance(self.win_id).entered.connect(menu.close)
         menu.exec_(e.globalPos())
+
+    def showEvent(self, e):
+        """Extend showEvent to set the page visibility state to visible.
+
+        Args:
+            e: The QShowEvent.
+
+        Return:
+            The superclass event return value.
+        """
+        try:
+            self.page().setVisibilityState(QWebPage.VisibilityStateVisible)
+        except AttributeError:
+            pass
+
+        super().showEvent(e)
+
+    def hideEvent(self, e):
+        """Extend hideEvent to set the page visibility state to hidden.
+
+        Args:
+            e: The QHideEvent.
+
+        Return:
+            The superclass event return value.
+        """
+        try:
+            self.page().setVisibilityState(QWebPage.VisibilityStateHidden)
+        except AttributeError:
+            pass
+
+        super().hideEvent(e)


Test patch:
Repository: qutebrowser/qutebrowser

Issue:
No default is enforced for keyword-only arguments
With this:

``` python
    @cmdutils.register(instance='command-dispatcher', scope='window',
                       hide=True)
    @cmdutils.argument('filter_', choices=['id'])
    def click_element(self, filter_: str, value, *,
                      target: usertypes.ClickTarget):
        # ...
```

We can do `:click-element` without giving `--target`, and the function will get called with `inspect._empty` as argument.



Discussion:
Working on it :wink:


Resolving patch:
diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py
--- a/qutebrowser/commands/command.py
+++ b/qutebrowser/commands/command.py
@@ -246,6 +246,11 @@ def _inspect_func(self):
                     continue
                 if self._inspect_special_param(param):
                     continue
+                if (param.kind == inspect.Parameter.KEYWORD_ONLY and
+                        param.default is inspect.Parameter.empty):
+                    raise TypeError("{}: handler has keyword only argument "
+                                    "{!r} without default!".format(self.name,
+                                                                   param.name))
                 typ = self._get_type(param)
                 is_bool = typ is bool
                 kwargs = self._param_to_argparse_kwargs(param, is_bool)


Test patch:
diff --git a/tests/unit/commands/test_cmdutils.py b/tests/unit/commands/test_cmdutils.py
--- a/tests/unit/commands/test_cmdutils.py
+++ b/tests/unit/commands/test_cmdutils.py
@@ -324,7 +324,7 @@ def test_choices_no_annotation_kwonly(self):
         # https://github.com/The-Compiler/qutebrowser/issues/1871
         @cmdutils.register()
         @cmdutils.argument('arg', choices=['foo', 'bar'])
-        def fun(*, arg):
+        def fun(*, arg='foo'):
             """Blah."""
             pass
 
@@ -349,6 +349,33 @@ def fun(foo, bar, opt=False):
         with pytest.raises(IndexError):
             cmd.get_pos_arg_info(2)
 
+    def test_keyword_only_without_default(self):
+        # https://github.com/The-Compiler/qutebrowser/issues/1872
+        def fun(*, target):
+            """Blah."""
+            pass
+
+        with pytest.raises(TypeError) as excinfo:
+            fun = cmdutils.register()(fun)
+
+        expected = ("fun: handler has keyword only argument 'target' without "
+                    "default!")
+        assert str(excinfo.value) == expected
+
+
+    def test_typed_keyword_only_without_default(self):
+        # https://github.com/The-Compiler/qutebrowser/issues/1872
+        def fun(*, target: int):
+            """Blah."""
+            pass
+
+        with pytest.raises(TypeError) as excinfo:
+            fun = cmdutils.register()(fun)
+
+        expected = ("fun: handler has keyword only argument 'target' without "
+                    "default!")
+        assert str(excinfo.value) == expected
+
 
 class TestArgument:
Repository: qutebrowser/qutebrowser

Issue:
Always reserve space for favicon with vertical tabs
Having a tab without a favicon with `tabs -> position` set to `left` looks kind of ugly:

![tabs](https://cloud.githubusercontent.com/assets/625793/18687260/8a450008-7f7f-11e6-93a8-14f3fe80c655.png)

We should always reserve the space for the favicon with vertical tabs IMHO.



Discussion:

Resolving patch:
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -703,13 +703,10 @@ def _tab_layout(self, opt):
             text_rect.adjust(indicator_width + indicator_padding.left +
                              indicator_padding.right, 0, 0, 0)
 
-        if opt.icon.isNull():
-            icon_rect = QRect()
-        else:
+        icon_rect = self._get_icon_rect(opt, text_rect)
+        if icon_rect.isValid():
             icon_padding = self.pixelMetric(PixelMetrics.icon_padding, opt)
-            icon_rect = self._get_icon_rect(opt, text_rect)
-            if icon_rect.isValid():
-                text_rect.adjust(icon_rect.width() + icon_padding, 0, 0, 0)
+            text_rect.adjust(icon_rect.width() + icon_padding, 0, 0, 0)
 
         text_rect = self._style.visualRect(opt.direction, opt.rect, text_rect)
         return Layouts(text=text_rect, icon=icon_rect,
@@ -733,9 +730,17 @@ def _get_icon_rect(self, opt, text_rect):
                      else QIcon.Disabled)
         icon_state = (QIcon.On if opt.state & QStyle.State_Selected
                       else QIcon.Off)
-        tab_icon_size = opt.icon.actualSize(icon_size, icon_mode, icon_state)
-        tab_icon_size = QSize(min(tab_icon_size.width(), icon_size.width()),
-                              min(tab_icon_size.height(), icon_size.height()))
+        # reserve space for favicon when tab bar is vertical (issue #1968)
+        position = config.get('tabs', 'position')
+        if (opt.icon.isNull() and
+                position in [QTabWidget.East, QTabWidget.West] and
+                config.get('tabs', 'show-favicons')):
+            tab_icon_size = icon_size
+        else:
+            actual_size = opt.icon.actualSize(icon_size, icon_mode, icon_state)
+            tab_icon_size = QSize(
+                min(actual_size.width(), icon_size.width()),
+                min(actual_size.height(), icon_size.height()))
         icon_rect = QRect(text_rect.left(), text_rect.top() + 1,
                           tab_icon_size.width(), tab_icon_size.height())
         icon_rect = self._style.visualRect(opt.direction, opt.rect, icon_rect)


Test patch:
diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py
--- a/tests/unit/mainwindow/test_tabwidget.py
+++ b/tests/unit/mainwindow/test_tabwidget.py
@@ -41,6 +41,7 @@ class TestTabWidget:
             'position': 0,
             'select-on-remove': 1,
             'show': 'always',
+            'show-favicons': True,
             'padding': configtypes.PaddingValues(0, 0, 5, 5),
             'indicator-width': 3,
             'indicator-padding': configtypes.PaddingValues(2, 2, 0, 4),
Repository: qutebrowser/qutebrowser

Issue:
Document how to use .netrc
This seems to be an undocumented feature of qutebrowser, and I also can't figure out how to make it work (without looking at the code).



Discussion:

Resolving patch:
diff --git a/qutebrowser/browser/webkit/network/networkmanager.py b/qutebrowser/browser/webkit/network/networkmanager.py
--- a/qutebrowser/browser/webkit/network/networkmanager.py
+++ b/qutebrowser/browser/webkit/network/networkmanager.py
@@ -330,7 +330,7 @@ def on_authentication_required(self, reply, authenticator):
             # altogether.
             reply.netrc_used = True
             try:
-                net = netrc.netrc()
+                net = netrc.netrc(config.get('network', 'netrc-file'))
                 authenticators = net.authenticators(reply.url().host())
                 if authenticators is not None:
                     (user, _account, password) = authenticators
diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py
--- a/qutebrowser/config/configdata.py
+++ b/qutebrowser/config/configdata.py
@@ -438,6 +438,10 @@ def data(readonly=False):
              SettingValue(typ.HeaderDict(none_ok=True), ''),
              "Set custom headers for qutebrowser HTTP requests."),
 
+            ('netrc-file',
+             SettingValue(typ.File(none_ok=True), ''),
+             "Set location of netrc-file for HTTP authentication."),
+
             readonly=readonly
         )),
 


Test patch: