Merge branch 'master' of ssh://lupin/qutebrowser
This commit is contained in:
commit
df98318e6b
@ -18,9 +18,10 @@ It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl.
|
|||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
In addition to the topics mentioned in that README, the following documents are
|
In addition to the topics mentioned in this README, the following documents are
|
||||||
available:
|
available:
|
||||||
|
|
||||||
|
* link:doc/quickstart.asciidoc[Quick start guide]
|
||||||
* link:doc/FAQ.asciidoc[Frequently asked questions]
|
* link:doc/FAQ.asciidoc[Frequently asked questions]
|
||||||
* link:doc/HACKING.asciidoc[HACKING]
|
* link:doc/HACKING.asciidoc[HACKING]
|
||||||
* link:doc/readme.asciidoc[Reporting segfaults]
|
* link:doc/readme.asciidoc[Reporting segfaults]
|
||||||
@ -165,6 +166,22 @@ As soon as v0.1 is out, a standalone .exe (built with
|
|||||||
http://cx-freeze.sourceforge.net/[cx_Freeze]) will be provided. In the
|
http://cx-freeze.sourceforge.net/[cx_Freeze]) will be provided. In the
|
||||||
meantime, you can simply ask in IRC if you need one.
|
meantime, you can simply ask in IRC if you need one.
|
||||||
|
|
||||||
|
Donating
|
||||||
|
--------
|
||||||
|
|
||||||
|
Working on qutebrowser is a very rewarding hobby, but like (nearly) all hobbies
|
||||||
|
it also costs some money. Namely I have to pay for the server and domain, and
|
||||||
|
do occasional hardware upgrades footnote:[It turned out a 160 GB SSD is rather
|
||||||
|
small - the VMs and custom Qt builds I use for testing/developing qutebrowser
|
||||||
|
need about 100 GB of space].
|
||||||
|
|
||||||
|
If you want to give me a beer or a pizza back, I'm trying to make it as easy as
|
||||||
|
possible for you to do so. If some other way would be easier for you, please
|
||||||
|
get in touch!
|
||||||
|
|
||||||
|
* PayPal: me@the-compiler.org
|
||||||
|
* Bitcoin: link:bitcoin:1PMzbcetAHfpxoXww8Bj5XqquHtVvMjJtE[1PMzbcetAHfpxoXww8Bj5XqquHtVvMjJtE]
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -421,7 +421,8 @@ displaying it to the user.
|
|||||||
* Mention in the docstring whether your function needs a URL string or a
|
* Mention in the docstring whether your function needs a URL string or a
|
||||||
`QUrl`.
|
`QUrl`.
|
||||||
* Call `ensure_valid` from `utils.qtutils` whenever getting or creating a
|
* Call `ensure_valid` from `utils.qtutils` whenever getting or creating a
|
||||||
`QUrl` and take appropriate action if not.
|
`QUrl` and take appropriate action if not. Note the URL of the current page
|
||||||
|
always could be an invalid QUrl (if nothing is loaded yet).
|
||||||
|
|
||||||
|
|
||||||
Style conventions
|
Style conventions
|
||||||
|
@ -6,6 +6,7 @@ Documentation
|
|||||||
|
|
||||||
The following help pages are currently available:
|
The following help pages are currently available:
|
||||||
|
|
||||||
|
* link:quickstart.html[Quick start guide]
|
||||||
* link:FAQ.html[Frequently asked questions]
|
* link:FAQ.html[Frequently asked questions]
|
||||||
* link:commands.html[Documentation of commands]
|
* link:commands.html[Documentation of commands]
|
||||||
* link:settings.html[Documentation of settings]
|
* link:settings.html[Documentation of settings]
|
||||||
|
@ -40,7 +40,7 @@ What to do now
|
|||||||
* Press `:` to get the commandline. Press `o`/`O` to open a new page (with `O`
|
* Press `:` to get the commandline. Press `o`/`O` to open a new page (with `O`
|
||||||
in a new tab). Use `H` and `L` to go back/forward and `J`/`K` to focus the
|
in a new tab). Use `H` and `L` to go back/forward and `J`/`K` to focus the
|
||||||
next/previous tab. See `~/.config/qutebrowser/keys.conf` for all mapped keys.
|
next/previous tab. See `~/.config/qutebrowser/keys.conf` for all mapped keys.
|
||||||
* Subscribe to
|
* Subscribe to
|
||||||
https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[the mailinglist]
|
https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[the mailinglist]
|
||||||
where there are weekly "what's new in qutebrowser" posts.
|
where there are weekly "what's new in qutebrowser" posts.
|
||||||
* Let me know what features you are missing or things that need (even small!)
|
* Let me know what features you are missing or things that need (even small!)
|
||||||
|
@ -263,6 +263,21 @@ class Application(QApplication):
|
|||||||
else:
|
else:
|
||||||
tabbed_browser.tabopen(url)
|
tabbed_browser.tabopen(url)
|
||||||
|
|
||||||
|
# Open quickstart if it's the first start
|
||||||
|
state_config = objreg.get('state-config')
|
||||||
|
try:
|
||||||
|
quickstart_done = state_config['general']['quickstart-done'] == '1'
|
||||||
|
except KeyError:
|
||||||
|
quickstart_done = False
|
||||||
|
if not quickstart_done:
|
||||||
|
tabbed_browser.tabopen(
|
||||||
|
QUrl('http://www.qutebrowser.org/quickstart.html'))
|
||||||
|
try:
|
||||||
|
state_config.add_section('general')
|
||||||
|
except configparser.DuplicateSectionError:
|
||||||
|
pass
|
||||||
|
state_config['general']['quickstart-done'] = '1'
|
||||||
|
|
||||||
def _python_hacks(self):
|
def _python_hacks(self):
|
||||||
"""Get around some PyQt-oddities by evil hacks.
|
"""Get around some PyQt-oddities by evil hacks.
|
||||||
|
|
||||||
|
@ -92,6 +92,11 @@ class CommandDispatcher:
|
|||||||
tab: Whether to open in a new tab.
|
tab: Whether to open in a new tab.
|
||||||
background: Whether to open in the background.
|
background: Whether to open in the background.
|
||||||
"""
|
"""
|
||||||
|
if not url.isValid():
|
||||||
|
errstr = "Invalid URL {}"
|
||||||
|
if url.errorString():
|
||||||
|
errstr += " - {}".format(url.errorString())
|
||||||
|
raise cmdexc.CommandError(errstr)
|
||||||
tabbed_browser = objreg.get('tabbed-browser')
|
tabbed_browser = objreg.get('tabbed-browser')
|
||||||
if tab and background:
|
if tab and background:
|
||||||
raise cmdexc.CommandError("Only one of -t/-b can be given!")
|
raise cmdexc.CommandError("Only one of -t/-b can be given!")
|
||||||
@ -715,9 +720,6 @@ class CommandDispatcher:
|
|||||||
"""
|
"""
|
||||||
urlstr = quickmarks.get(name)
|
urlstr = quickmarks.get(name)
|
||||||
url = QUrl(urlstr)
|
url = QUrl(urlstr)
|
||||||
if not url.isValid():
|
|
||||||
raise cmdexc.CommandError("Invalid URL {} ({})".format(
|
|
||||||
urlstr, url.errorString()))
|
|
||||||
self._open(url, tab, bg)
|
self._open(url, tab, bg)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', name='inspector')
|
@cmdutils.register(instance='command-dispatcher', name='inspector')
|
||||||
|
@ -359,7 +359,9 @@ class DownloadManager(QObject):
|
|||||||
url: The URL to get, as QUrl
|
url: The URL to get, as QUrl
|
||||||
page: The QWebPage to get the download from.
|
page: The QWebPage to get the download from.
|
||||||
"""
|
"""
|
||||||
qtutils.ensure_valid(url)
|
if not url.isValid():
|
||||||
|
urlutils.invalid_url_error(url, "start download")
|
||||||
|
return
|
||||||
req = QNetworkRequest(url)
|
req = QNetworkRequest(url)
|
||||||
reply = page.networkAccessManager().get(req)
|
reply = page.networkAccessManager().get(req)
|
||||||
self.fetch(reply)
|
self.fetch(reply)
|
||||||
|
@ -327,7 +327,6 @@ class HintManager(QObject):
|
|||||||
Args:
|
Args:
|
||||||
url: The URL to open as a QURL.
|
url: The URL to open as a QURL.
|
||||||
"""
|
"""
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
sel = self._context.target == Target.yank_primary
|
sel = self._context.target == Target.yank_primary
|
||||||
mode = QClipboard.Selection if sel else QClipboard.Clipboard
|
mode = QClipboard.Selection if sel else QClipboard.Clipboard
|
||||||
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
|
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||||
@ -341,7 +340,6 @@ class HintManager(QObject):
|
|||||||
Args:
|
Args:
|
||||||
url: The URL to open as a QUrl.
|
url: The URL to open as a QUrl.
|
||||||
"""
|
"""
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
urlstr = url.toDisplayString(QUrl.FullyEncoded)
|
urlstr = url.toDisplayString(QUrl.FullyEncoded)
|
||||||
args = self._context.get_args(urlstr)
|
args = self._context.get_args(urlstr)
|
||||||
message.set_cmd_text(' '.join(args))
|
message.set_cmd_text(' '.join(args))
|
||||||
@ -357,19 +355,16 @@ class HintManager(QObject):
|
|||||||
message.error("No suitable link found for this element.",
|
message.error("No suitable link found for this element.",
|
||||||
immediately=True)
|
immediately=True)
|
||||||
return
|
return
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
objreg.get('download-manager').get(url, elem.webFrame().page())
|
objreg.get('download-manager').get(url, elem.webFrame().page())
|
||||||
|
|
||||||
def _call_userscript(self, url):
|
def _call_userscript(self, url):
|
||||||
"""Call an userscript from a hint."""
|
"""Call an userscript from a hint."""
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
cmd = self._context.args[0]
|
cmd = self._context.args[0]
|
||||||
args = self._context.args[1:]
|
args = self._context.args[1:]
|
||||||
userscripts.run(cmd, *args, url=url)
|
userscripts.run(cmd, *args, url=url)
|
||||||
|
|
||||||
def _spawn(self, url):
|
def _spawn(self, url):
|
||||||
"""Spawn a simple command from a hint."""
|
"""Spawn a simple command from a hint."""
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
|
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
|
||||||
args = self._context.get_args(urlstr)
|
args = self._context.get_args(urlstr)
|
||||||
subprocess.Popen(args)
|
subprocess.Popen(args)
|
||||||
@ -396,6 +391,7 @@ class HintManager(QObject):
|
|||||||
if baseurl is None:
|
if baseurl is None:
|
||||||
baseurl = self._context.baseurl
|
baseurl = self._context.baseurl
|
||||||
url = baseurl.resolved(url)
|
url = baseurl.resolved(url)
|
||||||
|
qtutils.ensure_valid(url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def _find_prevnext(self, frame, prev=False):
|
def _find_prevnext(self, frame, prev=False):
|
||||||
@ -511,7 +507,6 @@ class HintManager(QObject):
|
|||||||
if url is None:
|
if url is None:
|
||||||
raise cmdexc.CommandError("No {} links found!".format(
|
raise cmdexc.CommandError("No {} links found!".format(
|
||||||
"prev" if prev else "forward"))
|
"prev" if prev else "forward"))
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
if newtab:
|
if newtab:
|
||||||
objreg.get('tabbed-browser').tabopen(url, background=False)
|
objreg.get('tabbed-browser').tabopen(url, background=False)
|
||||||
else:
|
else:
|
||||||
|
@ -64,7 +64,9 @@ def prompt_save(url):
|
|||||||
Args:
|
Args:
|
||||||
url: The quickmark url as a QUrl.
|
url: The quickmark url as a QUrl.
|
||||||
"""
|
"""
|
||||||
qtutils.ensure_valid(url)
|
if not url.isValid():
|
||||||
|
urlutils.invalid_url_error(url, "save quickmark")
|
||||||
|
return
|
||||||
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
|
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
|
||||||
message.ask_async("Add quickmark:", usertypes.PromptMode.text,
|
message.ask_async("Add quickmark:", usertypes.PromptMode.text,
|
||||||
functools.partial(quickmark_add, urlstr))
|
functools.partial(quickmark_add, urlstr))
|
||||||
|
@ -28,7 +28,7 @@ from PyQt5.QtCore import QUrl
|
|||||||
from PyQt5.QtNetwork import QHostInfo
|
from PyQt5.QtNetwork import QHostInfo
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import log, qtutils
|
from qutebrowser.utils import log, qtutils, message
|
||||||
|
|
||||||
|
|
||||||
# FIXME: we probably could raise some exceptions on invalid URLs
|
# FIXME: we probably could raise some exceptions on invalid URLs
|
||||||
@ -262,6 +262,17 @@ def qurl_from_user_input(urlstr):
|
|||||||
return QUrl('http://[{}]{}'.format(ipstr, rest))
|
return QUrl('http://[{}]{}'.format(ipstr, rest))
|
||||||
|
|
||||||
|
|
||||||
|
def invalid_url_error(url, action):
|
||||||
|
"""Display an error message for an URL."""
|
||||||
|
if url.isValid():
|
||||||
|
raise ValueError("Calling invalid_url_error with valid URL {}".format(
|
||||||
|
url.toDisplayString()))
|
||||||
|
errstring = "Trying to {} with invalid URL".format(action)
|
||||||
|
if url.errorString():
|
||||||
|
errstring += " - {}".format(url.errorString())
|
||||||
|
message.error(errstring)
|
||||||
|
|
||||||
|
|
||||||
class FuzzyUrlError(Exception):
|
class FuzzyUrlError(Exception):
|
||||||
|
|
||||||
"""Exception raised by fuzzy_url on problems."""
|
"""Exception raised by fuzzy_url on problems."""
|
||||||
|
@ -86,7 +86,7 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
|||||||
"""Push a line to the interpreter."""
|
"""Push a line to the interpreter."""
|
||||||
self._buffer.append(line)
|
self._buffer.append(line)
|
||||||
source = '\n'.join(self._buffer)
|
source = '\n'.join(self._buffer)
|
||||||
self.write.emit(self._curprompt() + line)
|
self.write.emit(self._curprompt() + line + '\n')
|
||||||
# We do two special things with the contextmanagers here:
|
# We do two special things with the contextmanagers here:
|
||||||
# - We replace stdout/stderr to capture output. Even if we could
|
# - We replace stdout/stderr to capture output. Even if we could
|
||||||
# override InteractiveInterpreter's write method, most things are
|
# override InteractiveInterpreter's write method, most things are
|
||||||
@ -152,11 +152,12 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
|||||||
|
|
||||||
class ConsoleTextEdit(QTextEdit):
|
class ConsoleTextEdit(QTextEdit):
|
||||||
|
|
||||||
"""Custom QTextEdit for console input."""
|
"""Custom QTextEdit for console output."""
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setAcceptRichText(False)
|
self.setAcceptRichText(False)
|
||||||
|
self.setLineWrapMode(QTextEdit.NoWrap)
|
||||||
self.setReadOnly(True)
|
self.setReadOnly(True)
|
||||||
config.on_change(self.update_font, 'fonts', 'debug-console')
|
config.on_change(self.update_font, 'fonts', 'debug-console')
|
||||||
self.update_font()
|
self.update_font()
|
||||||
@ -184,7 +185,7 @@ class ConsoleWidget(QWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._lineedit = ConsoleLineEdit(self)
|
self._lineedit = ConsoleLineEdit(self)
|
||||||
self._output = ConsoleTextEdit()
|
self._output = ConsoleTextEdit()
|
||||||
self._lineedit.write.connect(self._output.append)
|
self._lineedit.write.connect(self._output.insertPlainText)
|
||||||
self._vbox = QVBoxLayout()
|
self._vbox = QVBoxLayout()
|
||||||
self._vbox.setSpacing(0)
|
self._vbox.setSpacing(0)
|
||||||
self._vbox.addWidget(self._output)
|
self._vbox.addWidget(self._output)
|
||||||
|
@ -247,11 +247,13 @@ class TabbedBrowser(tabwidget.TabWidget):
|
|||||||
self._now_focused = None
|
self._now_focused = None
|
||||||
if tab is objreg.get('last-focused-tab', None):
|
if tab is objreg.get('last-focused-tab', None):
|
||||||
objreg.delete('last-focused-tab')
|
objreg.delete('last-focused-tab')
|
||||||
if not tab.cur_url.isEmpty():
|
if tab.cur_url.isValid():
|
||||||
qtutils.ensure_valid(tab.cur_url)
|
|
||||||
history_data = qtutils.serialize(tab.history())
|
history_data = qtutils.serialize(tab.history())
|
||||||
entry = UndoEntry(tab.cur_url, history_data)
|
entry = UndoEntry(tab.cur_url, history_data)
|
||||||
self._undo_stack.append(entry)
|
self._undo_stack.append(entry)
|
||||||
|
else:
|
||||||
|
urlutils.invalid_url_error(url, "saving tab")
|
||||||
|
return
|
||||||
tab.shutdown()
|
tab.shutdown()
|
||||||
self._tabs.remove(tab)
|
self._tabs.remove(tab)
|
||||||
self.removeTab(idx)
|
self.removeTab(idx)
|
||||||
|
@ -335,10 +335,13 @@ class WebView(QWebView):
|
|||||||
|
|
||||||
@pyqtSlot('QUrl')
|
@pyqtSlot('QUrl')
|
||||||
def on_url_changed(self, url):
|
def on_url_changed(self, url):
|
||||||
"""Update cur_url when URL has changed."""
|
"""Update cur_url when URL has changed.
|
||||||
qtutils.ensure_valid(url)
|
|
||||||
self.cur_url = url
|
If the URL is invalid, we just ignore it here.
|
||||||
self.url_text_changed.emit(url.toDisplayString())
|
"""
|
||||||
|
if url.isValid():
|
||||||
|
self.cur_url = url
|
||||||
|
self.url_text_changed.emit(url.toDisplayString())
|
||||||
|
|
||||||
@pyqtSlot('QMouseEvent')
|
@pyqtSlot('QMouseEvent')
|
||||||
def on_mouse_event(self, evt):
|
def on_mouse_event(self, evt):
|
||||||
|
@ -65,6 +65,7 @@ def main(colors=False):
|
|||||||
utils.use_color = colors
|
utils.use_color = colors
|
||||||
asciidoc_files = [
|
asciidoc_files = [
|
||||||
('doc/FAQ.asciidoc', 'qutebrowser/html/doc/FAQ.html'),
|
('doc/FAQ.asciidoc', 'qutebrowser/html/doc/FAQ.html'),
|
||||||
|
('doc/quickstart.asciidoc', 'qutebrowser/html/doc/quickstart.html'),
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
os.mkdir('qutebrowser/html/doc')
|
os.mkdir('qutebrowser/html/doc')
|
||||||
|
Loading…
Reference in New Issue
Block a user