Merge branch 'master' of ssh://lupin/qutebrowser

This commit is contained in:
Florian Bruhin 2014-10-05 17:59:45 +02:00
commit df98318e6b
14 changed files with 77 additions and 24 deletions

View File

@ -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
------- -------

View File

@ -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

View File

@ -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]

View File

@ -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!)

View File

@ -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.

View File

@ -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')

View File

@ -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)

View File

@ -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:

View File

@ -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))

View File

@ -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."""

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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')