Repository: qutebrowser/qutebrowser

Issue:
:yank markdown (and asciidoc and html)
I love the [v.1.6.0](https://github.com/qutebrowser/qutebrowser/releases/tag/v1.6.0) `:yank markdown` feature - thank you for that. For those of us who write in asciidoc and html, it would be great to also be able to yank in those formats, i.e., have this:

* :yank markdown
  * `[DuckDuckGo — Privacy, simplified.](https://start.duckduckgo.com/)`
* :yank asciidoc
  * `https://start.duckduckgo.com/[DuckDuckGo — Privacy, simplified.]`
* :yank html
  * `<a href="https://start.duckduckgo.com/">DuckDuckGo — Privacy, simplified.</a>`

Thank you for considering this!


Discussion:

Resolving patch:
diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py
--- a/qutebrowser/commands/runners.py
+++ b/qutebrowser/commands/runners.py
@@ -61,13 +61,29 @@ def replace_variables(win_id, arglist):
     """Utility function to replace variables like {url} in a list of args."""
     tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                 window=win_id)
+    url = lambda: _current_url(tabbed_browser)
 
     variables = {
-        'url': lambda: _current_url(tabbed_browser).toString(
+        'url': lambda: url().toString(
             QUrl.FullyEncoded | QUrl.RemovePassword),
-        'url:pretty': lambda: _current_url(tabbed_browser).toString(
+        'url:pretty': lambda: url().toString(
             QUrl.DecodeReserved | QUrl.RemovePassword),
-        'url:host': lambda: _current_url(tabbed_browser).host(),
+        'url:domain': lambda: "{}://{}{}".format(
+            url().scheme(),
+            url().host(),
+            ":" + str(url().port()) if url().port() != -1 else ""),
+        'url:auth': lambda: "{}:{}@".format(
+            url().userName(),
+            url().password()) if url().userName() else "",
+        'url:scheme': lambda: url().scheme(),
+        'url:username': lambda: url().userName(),
+        'url:password': lambda: url().password(),
+        'url:host': lambda: url().host(),
+        'url:port': lambda: str(url().port()) if url().port() != -1 else "",
+        'url:path': lambda: url().path(),
+        'url:query': lambda: url().query(),
+        'title': lambda: tabbed_browser.widget.page_title(
+            tabbed_browser.widget.currentIndex()),
         'clipboard': utils.get_clipboard,
         'primary': lambda: utils.get_clipboard(selection=True),
     }


Test patch:
diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature
--- a/tests/end2end/features/misc.feature
+++ b/tests/end2end/features/misc.feature
@@ -415,32 +415,6 @@ Feature: Various utility commands.
                 history:
                 - url: http://localhost:*/data/hello3.txt
 
-    ## Variables
-
-    Scenario: {url} as part of an argument
-        When I open data/hello.txt
-        And I run :message-info foo{url}
-        Then the message "foohttp://localhost:*/hello.txt" should be shown
-
-    Scenario: Multiple variables in an argument
-        When I open data/hello.txt
-        And I put "foo" into the clipboard
-        And I run :message-info {clipboard}bar{url}
-        Then the message "foobarhttp://localhost:*/hello.txt" should be shown
-
-    Scenario: escaping {{url}} variable
-        When I open data/hello.txt
-        And I run :message-info foo{{url}}bar
-        Then the message "foo{url}bar" should be shown
-
-    @xfail_norun
-    Scenario: {url} in clipboard should not be expanded
-        When I open data/hello.txt
-        # FIXME: {url} should be escaped, otherwise it is replaced before it enters clipboard
-        And I put "{url}" into the clipboard
-        And I run :message-info {clipboard}bar{url}
-        Then the message "{url}barhttp://localhost:*/hello.txt" should be shown
-
     ## :click-element
 
     Scenario: Clicking an element with unknown ID
diff --git a/tests/end2end/misc/test_runners_e2e.py b/tests/end2end/misc/test_runners_e2e.py
new file mode 100644
--- /dev/null
+++ b/tests/end2end/misc/test_runners_e2e.py
@@ -0,0 +1,85 @@
+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+
+# Copyright 2019 Jay Kamat <jaygkamat@gmail.com>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# qutebrowser is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Tests for runners."""
+
+import logging
+
+import pytest
+
+
+def command_expansion_base(
+        quteproc, send_msg, recv_msg, url="data/hello.txt"):
+    quteproc.open_path(url)
+    quteproc.send_cmd(':message-info ' + send_msg)
+
+    quteproc.mark_expected(category='message',
+                           loglevel=logging.INFO,
+                           message=recv_msg)
+
+
+@pytest.mark.parametrize('send_msg, recv_msg', [
+    # escaping by double-quoting
+    ('foo{{url}}bar', 'foo{url}bar'),
+
+    ('foo{url}', 'foohttp://localhost:*/hello.txt'),
+    ('foo{url:pretty}', 'foohttp://localhost:*/hello.txt'),
+    ('foo{url:domain}', 'foohttp://localhost:*'),
+    # test {url:auth} on a site with no auth
+    ('foo{url:auth}', 'foo'),
+    ('foo{url:scheme}', 'foohttp'),
+    ('foo{url:host}', 'foolocalhost'),
+    ('foo{url:path}', 'foo*/hello.txt'),
+])
+def test_command_expansion(quteproc, send_msg, recv_msg):
+    command_expansion_base(quteproc, send_msg, recv_msg)
+
+
+@pytest.mark.parametrize('send_msg, recv_msg, url', [
+    ('foo{title}', 'fooTest title', 'data/title.html'),
+    ('foo{url:query}', 'fooq=bar', 'data/hello.txt?q=bar'),
+
+    # multiple variable expansion
+    ('{title}bar{url}', 'Test titlebarhttp://localhost:*/title.html', 'data/title.html'),
+])
+def test_command_expansion_complex(
+        quteproc, send_msg, recv_msg, url):
+    command_expansion_base(quteproc, send_msg, recv_msg, url)
+
+
+def test_command_expansion_basic_auth(quteproc, server):
+    url = 'http://user1:password1@localhost:{port}/basic-auth/user1/password1' \
+        .format(port=server.port)
+    quteproc.open_url(url)
+    quteproc.send_cmd(':message-info foo{url:auth}')
+
+    quteproc.mark_expected(
+        category='message',
+        loglevel=logging.INFO, message='foouser1:password1@')
+
+
+def test_command_expansion_clipboard(quteproc):
+    quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format('foo'))
+    command_expansion_base(
+        quteproc, '{clipboard}bar{url}',
+        "foobarhttp://localhost:*/hello.txt")
+    quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format('{{url}}'))
+    command_expansion_base(
+        quteproc, '{clipboard}bar{url}',
+        "{url}barhttp://localhost:*/hello.txt")