From 69f729dbe5156330c4a866a78be6003ecb12c4d5 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Sat, 9 May 2015 18:07:40 -0400 Subject: [PATCH 001/226] Added foreground color settings for statusbar messages. --- qutebrowser/config/configdata.py | 16 ++++++++++++++++ qutebrowser/mainwindow/statusbar/bar.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index e0e613892..d5ec8e9bd 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -804,18 +804,34 @@ def data(readonly=False): SettingValue(typ.QssColor(), 'red'), "Background color of the statusbar if there was an error."), + ('statusbar.fg.error', + SettingValue(typ.QssColor(), 'white'), + "Foreground color of the statusbar if there was an error."), + ('statusbar.bg.warning', SettingValue(typ.QssColor(), 'darkorange'), "Background color of the statusbar if there is a warning."), + ('statusbar.fg.warning', + SettingValue(typ.QssColor(), 'white'), + "Foreground color of the statusbar if there is a warning."), + ('statusbar.bg.prompt', SettingValue(typ.QssColor(), 'darkblue'), "Background color of the statusbar if there is a prompt."), + ('statusbar.fg.prompt', + SettingValue(typ.QssColor(), 'white'), + "Foreground color of the statusbar if there is a prompt."), + ('statusbar.bg.insert', SettingValue(typ.QssColor(), 'darkgreen'), "Background color of the statusbar in insert mode."), + ('statusbar.fg.insert', + SettingValue(typ.QssColor(), 'white'), + "Foreground color of the statusbar in insert mode."), + ('statusbar.progress.bg', SettingValue(typ.QssColor(), 'white'), "Background color of the progress bar."), diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index a1c8aabd0..2a034223b 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -97,26 +97,47 @@ class StatusBar(QWidget): {{ color['statusbar.bg'] }} } + QWidget#StatusBar QLabel { + {{ color['statusbar.fg'] }} + } + QWidget#StatusBar[insert_active="true"] { {{ color['statusbar.bg.insert'] }} } + QWidget#StatusBar[insert_active="true"] QLabel { + {{ color['statusbar.fg.insert'] }} + } + QWidget#StatusBar[prompt_active="true"] { {{ color['statusbar.bg.prompt'] }} } + QWidget#StatusBar[prompt_active="true"] QLabel { + {{ color['statusbar.fg.prompt'] }} + } + QWidget#StatusBar[severity="error"] { {{ color['statusbar.bg.error'] }} } + QWidget#StatusBar[severity="error"] QLabel { + {{ color['statusbar.fg.error'] }} + } + QWidget#StatusBar[severity="warning"] { {{ color['statusbar.bg.warning'] }} } + QWidget#StatusBar[severity="warning"] QLabel { + {{ color['statusbar.fg.warning'] }} + } + QLabel, QLineEdit { {{ color['statusbar.fg'] }} {{ font['statusbar'] }} } + """ def __init__(self, win_id, parent=None): From 244d2753df3fd63af468e49d31d591e4a6a16342 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Sun, 10 May 2015 15:33:58 -0400 Subject: [PATCH 002/226] Reordered fg/bg statusbar color options Options are now all fg, bg for each variant. --- qutebrowser/config/configdata.py | 56 ++++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index d5ec8e9bd..98787c284 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -792,46 +792,46 @@ def data(readonly=False): SettingValue(typ.QssColor(), '#ff4444'), "Foreground color of the matched text in the completion."), - ('statusbar.bg', - SettingValue(typ.QssColor(), 'black'), - "Foreground color of the statusbar."), - ('statusbar.fg', SettingValue(typ.QssColor(), 'white'), "Foreground color of the statusbar."), - ('statusbar.bg.error', - SettingValue(typ.QssColor(), 'red'), - "Background color of the statusbar if there was an error."), + ('statusbar.bg', + SettingValue(typ.QssColor(), 'black'), + "Foreground color of the statusbar."), ('statusbar.fg.error', SettingValue(typ.QssColor(), 'white'), "Foreground color of the statusbar if there was an error."), - ('statusbar.bg.warning', - SettingValue(typ.QssColor(), 'darkorange'), - "Background color of the statusbar if there is a warning."), + ('statusbar.bg.error', + SettingValue(typ.QssColor(), 'red'), + "Background color of the statusbar if there was an error."), ('statusbar.fg.warning', SettingValue(typ.QssColor(), 'white'), "Foreground color of the statusbar if there is a warning."), - ('statusbar.bg.prompt', - SettingValue(typ.QssColor(), 'darkblue'), - "Background color of the statusbar if there is a prompt."), + ('statusbar.bg.warning', + SettingValue(typ.QssColor(), 'darkorange'), + "Background color of the statusbar if there is a warning."), ('statusbar.fg.prompt', SettingValue(typ.QssColor(), 'white'), "Foreground color of the statusbar if there is a prompt."), - ('statusbar.bg.insert', - SettingValue(typ.QssColor(), 'darkgreen'), - "Background color of the statusbar in insert mode."), + ('statusbar.bg.prompt', + SettingValue(typ.QssColor(), 'darkblue'), + "Background color of the statusbar if there is a prompt."), ('statusbar.fg.insert', SettingValue(typ.QssColor(), 'white'), "Foreground color of the statusbar in insert mode."), + ('statusbar.bg.insert', + SettingValue(typ.QssColor(), 'darkgreen'), + "Background color of the statusbar in insert mode."), + ('statusbar.progress.bg', SettingValue(typ.QssColor(), 'white'), "Background color of the progress bar."), @@ -863,22 +863,22 @@ def data(readonly=False): SettingValue(typ.QtColor(), 'white'), "Foreground color of unselected odd tabs."), - ('tabs.fg.even', - SettingValue(typ.QtColor(), 'white'), - "Foreground color of unselected even tabs."), - - ('tabs.fg.selected', - SettingValue(typ.QtColor(), 'white'), - "Foreground color of selected tabs."), - ('tabs.bg.odd', SettingValue(typ.QtColor(), 'grey'), "Background color of unselected odd tabs."), + ('tabs.fg.even', + SettingValue(typ.QtColor(), 'white'), + "Foreground color of unselected even tabs."), + ('tabs.bg.even', SettingValue(typ.QtColor(), 'darkgrey'), "Background color of unselected even tabs."), + ('tabs.fg.selected', + SettingValue(typ.QtColor(), 'white'), + "Foreground color of selected tabs."), + ('tabs.bg.selected', SettingValue(typ.QtColor(), 'black'), "Background color of selected tabs."), @@ -907,10 +907,6 @@ def data(readonly=False): SettingValue(typ.CssColor(), 'black'), "Font color for hints."), - ('hints.fg.match', - SettingValue(typ.CssColor(), 'green'), - "Font color for the matched part of hints."), - ('hints.bg', SettingValue( typ.CssColor(), '-webkit-gradient(linear, left top, ' @@ -918,6 +914,10 @@ def data(readonly=False): 'color-stop(100%,#FFC542))'), "Background color for hints."), + ('hints.fg.match', + SettingValue(typ.CssColor(), 'green'), + "Font color for the matched part of hints."), + ('downloads.fg', SettingValue(typ.QtColor(), '#ffffff'), "Foreground color for downloads."), From 1a2a57d59eccee3de70899fdfac6db4c90dd1c61 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 11 May 2015 22:27:21 -0400 Subject: [PATCH 003/226] Added command mode color configuration options. Including necessary tracker variable _command_active. --- qutebrowser/config/configdata.py | 8 ++++ qutebrowser/mainwindow/statusbar/bar.py | 49 +++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 98787c284..9327dd377 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -832,6 +832,14 @@ def data(readonly=False): SettingValue(typ.QssColor(), 'darkgreen'), "Background color of the statusbar in insert mode."), + ('statusbar.fg.command', + SettingValue(typ.QssColor(), '${statusbar.fg}'), + "Foreground color of the statusbar in command mode."), + + ('statusbar.bg.command', + SettingValue(typ.QssColor(), '${statusbar.bg}'), + "Background color of the statusbar in command mode."), + ('statusbar.progress.bg', SettingValue(typ.QssColor(), 'white'), "Background color of the progress bar."), diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index 2a034223b..98d2d05e0 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -77,6 +77,10 @@ class StatusBar(QWidget): For some reason we need to have this as class attribute so pyqtProperty works correctly. + _command_active: If we're currently in command mode. + + For some reason we need to have this as class attribute + so pyqtProperty works correctly. Signals: resized: Emitted when the statusbar has resized, so the completion widget can adjust its size to it. @@ -91,6 +95,7 @@ class StatusBar(QWidget): _severity = None _prompt_active = False _insert_active = False + _command_active = False STYLESHEET = """ QWidget#StatusBar { @@ -101,12 +106,8 @@ class StatusBar(QWidget): {{ color['statusbar.fg'] }} } - QWidget#StatusBar[insert_active="true"] { - {{ color['statusbar.bg.insert'] }} - } - - QWidget#StatusBar[insert_active="true"] QLabel { - {{ color['statusbar.fg.insert'] }} + QWidget#StatusBar QLineEdit { + {{ color['statusbar.fg.command'] }} } QWidget#StatusBar[prompt_active="true"] { @@ -117,6 +118,22 @@ class StatusBar(QWidget): {{ color['statusbar.fg.prompt'] }} } + QWidget#StatusBar[insert_active="true"] { + {{ color['statusbar.bg.insert'] }} + } + + QWidget#StatusBar[insert_active="true"] QLabel { + {{ color['statusbar.fg.insert'] }} + } + + QWidget#StatusBar[command_active="true"] QLabel { + {{ color['statusbar.fg.command'] }} + } + + QWidget#StatusBar[command_active="true"] { + {{ color['statusbar.bg.command'] }} + } + QWidget#StatusBar[severity="error"] { {{ color['statusbar.bg.error'] }} } @@ -134,7 +151,6 @@ class StatusBar(QWidget): } QLabel, QLineEdit { - {{ color['statusbar.fg'] }} {{ font['statusbar'] }} } @@ -269,6 +285,21 @@ class StatusBar(QWidget): self._prompt_active = val self.setStyleSheet(style.get_stylesheet(self.STYLESHEET)) + @pyqtProperty(bool) + def command_active(self): + """Getter for self.command_active, so it can be used as Qt property.""" + return self._command_active + + def _set_command_active(self, val): + """Setter for self._command_active. + + Re-set the stylesheet after setting the value, so everything gets + updated by Qt properly. + """ + log.statusbar.debug("Setting command_active to {}".format(val)) + self._command_active = val + self.setStyleSheet(style.get_stylesheet(self.STYLESHEET)) + @pyqtProperty(bool) def insert_active(self): """Getter for self.insert_active, so it can be used as Qt property.""" @@ -461,6 +492,8 @@ class StatusBar(QWidget): self._set_mode_text(mode.name) if mode == usertypes.KeyMode.insert: self._set_insert_active(True) + if mode == usertypes.KeyMode.command: + self._set_command_active(True) @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode) def on_mode_left(self, old_mode, new_mode): @@ -474,6 +507,8 @@ class StatusBar(QWidget): self.txt.set_text(self.txt.Text.normal, '') if old_mode == usertypes.KeyMode.insert: self._set_insert_active(False) + if old_mode == usertypes.KeyMode.command: + self._set_command_active(False) @config.change_filter('ui', 'message-timeout') def set_pop_timer_interval(self): From 14c1332017f23a01f167b910b140d7291d2aa6dc Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 11 May 2015 22:28:12 -0400 Subject: [PATCH 004/226] Reordered statusbar stylesheet to match configuration ordering. --- qutebrowser/mainwindow/statusbar/bar.py | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index 98d2d05e0..53c991c86 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -110,6 +110,22 @@ class StatusBar(QWidget): {{ color['statusbar.fg.command'] }} } + QWidget#StatusBar[severity="error"] { + {{ color['statusbar.bg.error'] }} + } + + QWidget#StatusBar[severity="error"] QLabel { + {{ color['statusbar.fg.error'] }} + } + + QWidget#StatusBar[severity="warning"] { + {{ color['statusbar.bg.warning'] }} + } + + QWidget#StatusBar[severity="warning"] QLabel { + {{ color['statusbar.fg.warning'] }} + } + QWidget#StatusBar[prompt_active="true"] { {{ color['statusbar.bg.prompt'] }} } @@ -134,22 +150,6 @@ class StatusBar(QWidget): {{ color['statusbar.bg.command'] }} } - QWidget#StatusBar[severity="error"] { - {{ color['statusbar.bg.error'] }} - } - - QWidget#StatusBar[severity="error"] QLabel { - {{ color['statusbar.fg.error'] }} - } - - QWidget#StatusBar[severity="warning"] { - {{ color['statusbar.bg.warning'] }} - } - - QWidget#StatusBar[severity="warning"] QLabel { - {{ color['statusbar.fg.warning'] }} - } - QLabel, QLineEdit { {{ font['statusbar'] }} } From 0d66647918c4d27001752ba8ba08dd1bcd954f0d Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 11 May 2015 22:35:44 -0400 Subject: [PATCH 005/226] Set extra foreground colors to match the default by default. --- qutebrowser/config/configdata.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 9327dd377..b4bfbd900 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -801,7 +801,7 @@ def data(readonly=False): "Foreground color of the statusbar."), ('statusbar.fg.error', - SettingValue(typ.QssColor(), 'white'), + SettingValue(typ.QssColor(), '${statusbar.fg}'), "Foreground color of the statusbar if there was an error."), ('statusbar.bg.error', @@ -809,7 +809,7 @@ def data(readonly=False): "Background color of the statusbar if there was an error."), ('statusbar.fg.warning', - SettingValue(typ.QssColor(), 'white'), + SettingValue(typ.QssColor(), '${statusbar.fg}'), "Foreground color of the statusbar if there is a warning."), ('statusbar.bg.warning', @@ -817,7 +817,7 @@ def data(readonly=False): "Background color of the statusbar if there is a warning."), ('statusbar.fg.prompt', - SettingValue(typ.QssColor(), 'white'), + SettingValue(typ.QssColor(), '${statusbar.fg}'), "Foreground color of the statusbar if there is a prompt."), ('statusbar.bg.prompt', @@ -825,7 +825,7 @@ def data(readonly=False): "Background color of the statusbar if there is a prompt."), ('statusbar.fg.insert', - SettingValue(typ.QssColor(), 'white'), + SettingValue(typ.QssColor(), '${statusbar.fg}'), "Foreground color of the statusbar in insert mode."), ('statusbar.bg.insert', From 229733f1b03079dd2c1ad6c28a7d4fe518ba97e7 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 11 May 2015 22:46:26 -0400 Subject: [PATCH 006/226] Properly distinguish between statusbar modes when styling line input. --- qutebrowser/mainwindow/statusbar/bar.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index 53c991c86..aca145f6a 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -107,7 +107,7 @@ class StatusBar(QWidget): } QWidget#StatusBar QLineEdit { - {{ color['statusbar.fg.command'] }} + {{ color['statusbar.fg'] }} } QWidget#StatusBar[severity="error"] { @@ -134,6 +134,10 @@ class StatusBar(QWidget): {{ color['statusbar.fg.prompt'] }} } + QWidget#StatusBar[prompt_active="true"] QLineEdit { + {{ color['statusbar.fg.prompt'] }} + } + QWidget#StatusBar[insert_active="true"] { {{ color['statusbar.bg.insert'] }} } @@ -142,12 +146,16 @@ class StatusBar(QWidget): {{ color['statusbar.fg.insert'] }} } + QWidget#StatusBar[command_active="true"] { + {{ color['statusbar.bg.command'] }} + } + QWidget#StatusBar[command_active="true"] QLabel { {{ color['statusbar.fg.command'] }} } - QWidget#StatusBar[command_active="true"] { - {{ color['statusbar.bg.command'] }} + QWidget#StatusBar[command_active="true"] QLineEdit { + {{ color['statusbar.fg.command'] }} } QLabel, QLineEdit { From 58f031630c6b04c0178f268bf5ad3803455d0c31 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Fri, 22 May 2015 14:44:04 +0200 Subject: [PATCH 007/226] user-stylesheet can be read from relative paths This ist just a first draft to approach issue622 (https://github.com/The-Compiler/qutebrowser/issues/622) and my very first babysteps with python. With this change it is possible to set a user-stylesheet with a relative path, eg.: :set ui user-stylesheet mystyle.css where mystyle.css is in the ~/.config/qutebrowser/. --- .gitignore | 2 ++ qutebrowser/config/configtypes.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index f3ff3652a..9552dc3c4 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ __pycache__ /htmlcov /.tox /testresults.html +tags +*.swp diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index b9c760116..354c09598 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -34,6 +34,7 @@ from PyQt5.QtWidgets import QTabWidget, QTabBar from qutebrowser.commands import cmdutils from qutebrowser.config import configexc +from qutebrowser.utils import standarddir SYSTEM_PROXY = object() # Return value for Proxy type @@ -792,6 +793,9 @@ class RegexList(List): raise configexc.ValidationError(value, "items may not be empty!") +# TODO(lamar) Issue622, relative paths for some config files and directories +# should be implemented here in the base class for files and below in the base +# class for directories. class File(BaseType): """A file on the local filesystem.""" @@ -806,6 +810,10 @@ class File(BaseType): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expanduser(value) try: + if not os.path.isabs(value): + relpath = os.path.join(standarddir.config(), value) + if os.path.isfile(relpath): + value = relpath if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") if not os.path.isabs(value): @@ -1160,6 +1168,10 @@ class UserStyleSheet(File): value = os.path.expandvars(value) value = os.path.expanduser(value) try: + if not os.path.isabs(value): + relpath = os.path.join(standarddir.config(), value) + if os.path.isfile(relpath): + value = relpath if not os.path.isabs(value): # probably a CSS, so we don't handle it as filename. # FIXME We just try if it is encodable, maybe we should From 29b25206f6341f8747447e451ddda78e9bf925fd Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Fri, 22 May 2015 17:21:00 +0200 Subject: [PATCH 008/226] Fix UserStyleSheet, roll back File The former version of UserStyleSheet never actually loaded the css file, this is now fixed. The changes to class File were rolled back as its functions are overloaded by UserStyleSheet; a general solution in classes File and Directory can be implemented when the changes in UserStyleSheet meet the expectation. --- qutebrowser/config/configtypes.py | 54 ++++++++++++++----------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 354c09598..60bd5ecce 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -793,15 +793,17 @@ class RegexList(List): raise configexc.ValidationError(value, "items may not be empty!") -# TODO(lamar) Issue622, relative paths for some config files and directories -# should be implemented here in the base class for files and below in the base -# class for directories. class File(BaseType): """A file on the local filesystem.""" typestr = 'file' + def transform(self, value): + if not value: + return None + return os.path.expanduser(value) + def validate(self, value): if not value: if self._none_ok: @@ -810,10 +812,6 @@ class File(BaseType): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expanduser(value) try: - if not os.path.isabs(value): - relpath = os.path.join(standarddir.config(), value) - if os.path.isfile(relpath): - value = relpath if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") if not os.path.isabs(value): @@ -822,11 +820,6 @@ class File(BaseType): except UnicodeEncodeError as e: raise configexc.ValidationError(value, e) - def transform(self, value): - if not value: - return None - return os.path.expanduser(value) - class Directory(BaseType): @@ -1159,19 +1152,33 @@ class UserStyleSheet(File): def __init__(self): super().__init__(none_ok=True) + def relapath(self, path): + if not os.path.isabs(path): + abspath = os.path.join(standarddir.config(), path) + if os.path.isfile(abspath): + return abspath + return path + + def transform(self, value): + path = os.path.expandvars(value) + path = os.path.expanduser(path) + path = self.relapath(path) + if not value: + return None + elif os.path.isabs(path): + return QUrl.fromLocalFile(path) + else: + data = base64.b64encode(value.encode('utf-8')).decode('ascii') + return QUrl("data:text/css;charset=utf-8;base64,{}".format(data)) + def validate(self, value): if not value: if self._none_ok: return else: raise configexc.ValidationError(value, "may not be empty!") - value = os.path.expandvars(value) - value = os.path.expanduser(value) + value = self.relapath(value) try: - if not os.path.isabs(value): - relpath = os.path.join(standarddir.config(), value) - if os.path.isfile(relpath): - value = relpath if not os.path.isabs(value): # probably a CSS, so we don't handle it as filename. # FIXME We just try if it is encodable, maybe we should @@ -1187,17 +1194,6 @@ class UserStyleSheet(File): except UnicodeEncodeError as e: raise configexc.ValidationError(value, e) - def transform(self, value): - path = os.path.expandvars(value) - path = os.path.expanduser(path) - if not value: - return None - elif os.path.isabs(path): - return QUrl.fromLocalFile(path) - else: - data = base64.b64encode(value.encode('utf-8')).decode('ascii') - return QUrl("data:text/css;charset=utf-8;base64,{}".format(data)) - class AutoSearch(BaseType): From 14ba20670b8923a480c460e41562561556d114d0 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Fri, 22 May 2015 17:31:37 +0200 Subject: [PATCH 009/226] Fix potential bug with missing path-expansion The last commit removed two lines in function validate of class UserStyleSheet that were expanding the path. As it turns out those two lines are needed by validate as well as transform, so I outsourced them to the function they both call at that point. --- qutebrowser/config/configtypes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 60bd5ecce..a1cf77561 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1153,6 +1153,8 @@ class UserStyleSheet(File): super().__init__(none_ok=True) def relapath(self, path): + path = os.path.expandvars(path) + path = os.path.expanduser(path) if not os.path.isabs(path): abspath = os.path.join(standarddir.config(), path) if os.path.isfile(abspath): @@ -1160,9 +1162,7 @@ class UserStyleSheet(File): return path def transform(self, value): - path = os.path.expandvars(value) - path = os.path.expanduser(path) - path = self.relapath(path) + path = self.relapath(value) if not value: return None elif os.path.isabs(path): From 61f32b3e9b693895f2fad4f44122bcb6bb161dba Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Fri, 22 May 2015 18:40:56 +0200 Subject: [PATCH 010/226] Revert some changes, trying to get rid of the tox failures --- qutebrowser/config/configtypes.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index a1cf77561..a9d73d454 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1152,20 +1152,16 @@ class UserStyleSheet(File): def __init__(self): super().__init__(none_ok=True) - def relapath(self, path): - path = os.path.expandvars(path) + def transform(self, value): + if not value: + return None + path = os.path.expandvars(value) path = os.path.expanduser(path) if not os.path.isabs(path): abspath = os.path.join(standarddir.config(), path) if os.path.isfile(abspath): - return abspath - return path - - def transform(self, value): - path = self.relapath(value) - if not value: - return None - elif os.path.isabs(path): + path = abspath + if os.path.isabs(path): return QUrl.fromLocalFile(path) else: data = base64.b64encode(value.encode('utf-8')).decode('ascii') @@ -1177,7 +1173,12 @@ class UserStyleSheet(File): return else: raise configexc.ValidationError(value, "may not be empty!") - value = self.relapath(value) + value = os.path.expandvars(value) + value = os.path.expanduser(value) + if not os.path.isabs(value): + abspath = os.path.join(standarddir.config(), value) + if os.path.isfile(abspath): + value = abspath try: if not os.path.isabs(value): # probably a CSS, so we don't handle it as filename. From 93b92f4aab777ff14d74980e4d871ad5097ddb54 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Sat, 23 May 2015 16:09:44 +0200 Subject: [PATCH 011/226] Fix tox failure regarding exceptions in transform Function transform is not supposed to raise exceptions, so I wrapped the call to os.path.join in an if-clause to test if standarddir.config returns a valid value. --- qutebrowser/config/configtypes.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index a9d73d454..2941f6c72 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1158,9 +1158,10 @@ class UserStyleSheet(File): path = os.path.expandvars(value) path = os.path.expanduser(path) if not os.path.isabs(path): - abspath = os.path.join(standarddir.config(), path) - if os.path.isfile(abspath): - path = abspath + if standarddir.config(): + abspath = os.path.join(standarddir.config(), path) + if os.path.isfile(abspath): + path = abspath if os.path.isabs(path): return QUrl.fromLocalFile(path) else: From ad7920dda1bb110cda9983fb9ab6b3861caddf45 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Sat, 23 May 2015 16:49:40 +0200 Subject: [PATCH 012/226] Fix bug; all tox tests succeed My logic in the validate function of class UserStyleSheet was faulty and caused the check for encoding to be skipped. This is now fixed and all tests run successfully. --- qutebrowser/config/configtypes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 2941f6c72..fb51a4c2e 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1176,12 +1176,11 @@ class UserStyleSheet(File): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expandvars(value) value = os.path.expanduser(value) - if not os.path.isabs(value): - abspath = os.path.join(standarddir.config(), value) - if os.path.isfile(abspath): - value = abspath try: if not os.path.isabs(value): + abspath = os.path.join(standarddir.config(), value) + if os.path.isfile(abspath): + return # probably a CSS, so we don't handle it as filename. # FIXME We just try if it is encodable, maybe we should # validate CSS? From 05530944944b95e324303d6e0ae02ec5e98b09d5 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 25 May 2015 19:20:33 -0400 Subject: [PATCH 013/226] Added explanation of *.system values to settings page. --- qutebrowser/config/configdata.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index b4bfbd900..ad321b73d 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -103,6 +103,10 @@ SECTION_DESC = { " * A gradient as explained in http://qt-project.org/doc/qt-4.8/" "stylesheet-reference.html#list-of-property-types[the Qt " "documentation] under ``Gradient''.\n\n" + "A *.system value determines the color system to use for color " + "interpolation between similarly-named *.start and *.stop entries, " + "regardless of how they are defined in the options. " + "Valid values are 'rgb', 'hsv', and 'hsl'.\n\n" "The `hints.*` values are a special case as they're real CSS " "colors, not Qt-CSS colors. There, for a gradient, you need to use " "`-webkit-gradient`, see https://www.webkit.org/blog/175/introducing-" From a8d2dbfdfb44d41f7f9c17c38c5251d26379f129 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Mon, 25 May 2015 20:47:16 -0400 Subject: [PATCH 014/226] Added downloads bar fg customization, and refactored the download's color-picking. --- qutebrowser/browser/downloads.py | 20 ++++++++++++-------- qutebrowser/config/configdata.py | 20 ++++++++++++++++---- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 6d12761f6..e30147e10 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -356,12 +356,16 @@ class DownloadItem(QObject): if reply.error() != QNetworkReply.NoError: QTimer.singleShot(0, lambda: self.error.emit(reply.errorString())) - def bg_color(self): - """Background color to be shown.""" - start = config.get('colors', 'downloads.bg.start') - stop = config.get('colors', 'downloads.bg.stop') - system = config.get('colors', 'downloads.bg.system') - error = config.get('colors', 'downloads.bg.error') + def get_status_color(self, position): + """Choose an appropriate color for presenting the download's status. + + Args: + position: The color type requested, can be 'fg' or 'bg'. + """ + start = config.get('colors', 'downloads.{}.start'.format(position)) + stop = config.get('colors', 'downloads.{}.stop'.format(position)) + system = config.get('colors', 'downloads.{}.system'.format(position)) + error = config.get('colors', 'downloads.{}.error'.format(position)) if self.error_msg is not None: assert not self.successful return error @@ -1020,9 +1024,9 @@ class DownloadManager(QAbstractListModel): if role == Qt.DisplayRole: data = str(item) elif role == Qt.ForegroundRole: - data = config.get('colors', 'downloads.fg') + data = item.get_status_color('fg') elif role == Qt.BackgroundRole: - data = item.bg_color() + data = item.get_status_color('bg') elif role == ModelRole.item: data = item elif role == Qt.ToolTipRole: diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index ad321b73d..db16a2bbf 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -930,26 +930,38 @@ def data(readonly=False): SettingValue(typ.CssColor(), 'green'), "Font color for the matched part of hints."), - ('downloads.fg', - SettingValue(typ.QtColor(), '#ffffff'), - "Foreground color for downloads."), - ('downloads.bg.bar', SettingValue(typ.QssColor(), 'black'), "Background color for the download bar."), + ('downloads.fg.start', + SettingValue(typ.QtColor(), '#0000aa'), + "Color gradient start for downloads."), + ('downloads.bg.start', SettingValue(typ.QtColor(), '#0000aa'), "Color gradient start for downloads."), + ('downloads.fg.stop', + SettingValue(typ.QtColor(), '#00aa00'), + "Color gradient end for downloads."), + ('downloads.bg.stop', SettingValue(typ.QtColor(), '#00aa00'), "Color gradient end for downloads."), + ('downloads.fg.system', + SettingValue(typ.ColorSystem(), 'rgb'), + "Color gradient interpolation system for downloads."), + ('downloads.bg.system', SettingValue(typ.ColorSystem(), 'rgb'), "Color gradient interpolation system for downloads."), + ('downloads.fg.error', + SettingValue(typ.QtColor(), 'red'), + "Foreground color for downloads with errors."), + ('downloads.bg.error', SettingValue(typ.QtColor(), 'red'), "Background color for downloads with errors."), From c54c637ccc65f4f114f3c25e960deac47b69ad6d Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Tue, 26 May 2015 12:38:04 +0200 Subject: [PATCH 015/226] Class File not transforms relative paths The code from function transform in class UserStyleSheet is now migrated to class File. --- qutebrowser/config/configtypes.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index fb51a4c2e..d0d822a6f 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -802,7 +802,13 @@ class File(BaseType): def transform(self, value): if not value: return None - return os.path.expanduser(value) + value = os.path.expanduser(value) + if not os.path.isabs(value): + if standarddir.config(): + abspath = os.path.join(standarddir.config(), value) + if os.path.isfile(abspath): + return abspath + return value def validate(self, value): if not value: @@ -1155,13 +1161,8 @@ class UserStyleSheet(File): def transform(self, value): if not value: return None - path = os.path.expandvars(value) - path = os.path.expanduser(path) - if not os.path.isabs(path): - if standarddir.config(): - abspath = os.path.join(standarddir.config(), path) - if os.path.isfile(abspath): - path = abspath + path = super().transform(value) + path = os.path.expandvars(path) if os.path.isabs(path): return QUrl.fromLocalFile(path) else: From f1129460d871d4bca46036085f8d869ff913ad49 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Tue, 26 May 2015 13:54:27 +0200 Subject: [PATCH 016/226] Class File now validates relative paths The code from function validate in class UserStyleSheet has been migrated to class File. One test had to be modified due to different expected behaviour. --- qutebrowser/config/configtypes.py | 34 ++++++++++++++++--------------- tests/config/test_configtypes.py | 3 +-- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index d0d822a6f..4b0b5b70f 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -818,6 +818,10 @@ class File(BaseType): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expanduser(value) try: + if not os.path.isabs(value): + abspath = os.path.join(standarddir.config(), value) + if os.path.isfile(abspath): + return if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") if not os.path.isabs(value): @@ -1178,23 +1182,21 @@ class UserStyleSheet(File): value = os.path.expandvars(value) value = os.path.expanduser(value) try: - if not os.path.isabs(value): - abspath = os.path.join(standarddir.config(), value) - if os.path.isfile(abspath): + super().validate(value) + except configexc.ValidationError: + try: + if not os.path.isabs(value): + # probably a CSS, so we don't handle it as filename. + # FIXME We just try if it is encodable, maybe we should + # validate CSS? + # https://github.com/The-Compiler/qutebrowser/issues/115 + try: + value.encode('utf-8') + except UnicodeEncodeError as e: + raise configexc.ValidationError(value, str(e)) return - # probably a CSS, so we don't handle it as filename. - # FIXME We just try if it is encodable, maybe we should - # validate CSS? - # https://github.com/The-Compiler/qutebrowser/issues/115 - try: - value.encode('utf-8') - except UnicodeEncodeError as e: - raise configexc.ValidationError(value, str(e)) - return - elif not os.path.isfile(value): - raise configexc.ValidationError(value, "must be a valid file!") - except UnicodeEncodeError as e: - raise configexc.ValidationError(value, e) + except UnicodeEncodeError as e: + raise configexc.ValidationError(value, e) class AutoSearch(BaseType): diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index 871b6cf4d..c515c6cef 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -1378,8 +1378,7 @@ class TestFile: os_path.expanduser.side_effect = lambda x: x os_path.isfile.return_value = True os_path.isabs.return_value = False - with pytest.raises(configexc.ValidationError): - self.t.validate('foobar') + self.t.validate('foobar') def test_validate_expanduser(self, os_path): """Test if validate expands the user correctly.""" From 4e61a6123e3bf074c122bba2de9311d14d2290b9 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Wed, 27 May 2015 12:06:51 +0200 Subject: [PATCH 017/226] Probably shouldn't include changes to the gitignore in a PR --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9552dc3c4..f3ff3652a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,3 @@ __pycache__ /htmlcov /.tox /testresults.html -tags -*.swp From cfae36c5c82d7ec95b67f7c8f0a1db76fea1e8f1 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Wed, 27 May 2015 14:05:29 +0200 Subject: [PATCH 018/226] Adjust name and doc of modified test --- tests/config/test_configtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index c515c6cef..d8af6995d 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -1373,8 +1373,8 @@ class TestFile: os_path.isabs.return_value = True self.t.validate('foobar') - def test_validate_exists_not_abs(self, os_path): - """Test validate with a file which does exist but is not absolute.""" + def test_validate_exists_rel(self, os_path): + """Test validate with a relative path to an existing file.""" os_path.expanduser.side_effect = lambda x: x os_path.isfile.return_value = True os_path.isabs.return_value = False From e12dce9d55eb3d1d3aeb56691e1b10fa28c5d506 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Wed, 27 May 2015 14:40:07 +0200 Subject: [PATCH 019/226] Include expandvars in File.transform, adjust test --- qutebrowser/config/configtypes.py | 8 +++----- tests/config/test_configtypes.py | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 4b0b5b70f..626ec43c2 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -803,6 +803,7 @@ class File(BaseType): if not value: return None value = os.path.expanduser(value) + value = os.path.expandvars(value) if not os.path.isabs(value): if standarddir.config(): abspath = os.path.join(standarddir.config(), value) @@ -818,10 +819,8 @@ class File(BaseType): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expanduser(value) try: - if not os.path.isabs(value): - abspath = os.path.join(standarddir.config(), value) - if os.path.isfile(abspath): - return + if os.path.isfile(os.path.join(standarddir.config(), value)): + return if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") if not os.path.isabs(value): @@ -1166,7 +1165,6 @@ class UserStyleSheet(File): if not value: return None path = super().transform(value) - path = os.path.expandvars(path) if os.path.isabs(path): return QUrl.fromLocalFile(path) else: diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index d8af6995d..c7df07f14 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -1398,6 +1398,7 @@ class TestFile: def test_transform(self, os_path): """Test transform.""" os_path.expanduser.side_effect = lambda x: x.replace('~', '/home/foo') + os_path.expandvars.side_effect = lambda x: x assert self.t.transform('~/foobar') == '/home/foo/foobar' os_path.expanduser.assert_called_once_with('~/foobar') From 4851a3d4424e61b01b3035ca69b12cbacde1c808 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Wed, 27 May 2015 15:39:58 +0200 Subject: [PATCH 020/226] Replace isabs with exists in transform In UserStyleSheet.transform os.path.isabs was replaced with os.path.exists, a more fitting condition. Accordingly two test cases needed to include mocks for os.path.exists and QUrl.fromLocalFile. --- qutebrowser/config/configtypes.py | 2 +- tests/config/test_configtypes.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 626ec43c2..c3815cb6d 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1165,7 +1165,7 @@ class UserStyleSheet(File): if not value: return None path = super().transform(value) - if os.path.isabs(path): + if os.path.exists(path): return QUrl.fromLocalFile(path) else: data = base64.b64encode(value.encode('utf-8')).decode('ascii') diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index c7df07f14..345a79d3b 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -1930,13 +1930,21 @@ class TestUserStyleSheet: """Test transform with an empty value.""" assert self.t.transform('') is None - def test_transform_file(self): + def test_transform_file(self, os_path, mocker): """Test transform with a filename.""" + qurl = mocker.patch('qutebrowser.config.configtypes.QUrl', + autospec=True) + qurl.fromLocalFile.return_value = QUrl("file:///foo/bar") + os_path.exists.return_value = True path = os.path.join(os.path.sep, 'foo', 'bar') assert self.t.transform(path) == QUrl("file:///foo/bar") - def test_transform_file_expandvars(self, monkeypatch): + def test_transform_file_expandvars(self, os_path, monkeypatch, mocker): """Test transform with a filename (expandvars).""" + qurl = mocker.patch('qutebrowser.config.configtypes.QUrl', + autospec=True) + qurl.fromLocalFile.return_value = QUrl("file:///foo/bar") + os_path.exists.return_value = True monkeypatch.setenv('FOO', 'foo') path = os.path.join(os.path.sep, '$FOO', 'bar') assert self.t.transform(path) == QUrl("file:///foo/bar") From b5eea81e2ed389487a8cf5cb15043ca6a8094efb Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Thu, 28 May 2015 12:14:12 +0200 Subject: [PATCH 021/226] Fix File.validate and corresponding tests There were no tests regarding the return value of standarddir.config() and thus it wasn't caught that it returned None in some cases. This is now fixed by checking the return of standdarddir.config before calling it and modifying the corresponding test_validate_exists_rel as well as adding a new test_validate_rel_config_none. --- qutebrowser/config/configtypes.py | 12 +++++++----- tests/config/test_configtypes.py | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index c3815cb6d..edc96d89d 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -819,13 +819,15 @@ class File(BaseType): raise configexc.ValidationError(value, "may not be empty!") value = os.path.expanduser(value) try: - if os.path.isfile(os.path.join(standarddir.config(), value)): - return + if not os.path.isabs(value): + if standarddir.config(): + if os.path.isfile( + os.path.join(standarddir.config(), value)): + return + raise configexc.ValidationError(value, + "must be an absolute path!") if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") - if not os.path.isabs(value): - raise configexc.ValidationError( - value, "must be an absolute path!") except UnicodeEncodeError as e: raise configexc.ValidationError(value, e) diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index 345a79d3b..1d52afdc8 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -30,7 +30,7 @@ from PyQt5.QtGui import QColor, QFont from PyQt5.QtNetwork import QNetworkProxy from qutebrowser.config import configtypes, configexc -from qutebrowser.utils import debug, utils +from qutebrowser.utils import debug, utils, standarddir class Font(QFont): @@ -1373,12 +1373,24 @@ class TestFile: os_path.isabs.return_value = True self.t.validate('foobar') - def test_validate_exists_rel(self, os_path): + def test_validate_exists_rel(self, os_path, monkeypatch): """Test validate with a relative path to an existing file.""" + monkeypatch.setattr('qutebrowser.config.configtypes.standarddir.config', + lambda: '/home/foo/.config/') os_path.expanduser.side_effect = lambda x: x os_path.isfile.return_value = True os_path.isabs.return_value = False self.t.validate('foobar') + os_path.join.assert_called_once_with('/home/foo/.config/', + 'foobar') + + def test_validate_rel_config_none(self, os_path, monkeypatch): + """Test with a relative path and standarddir.config returning None.""" + monkeypatch.setattr('qutebrowser.config.configtypes.standarddir.config', + lambda: None) + os_path.isabs.return_value = False + with pytest.raises(configexc.ValidationError): + self.t.validate('foobar') def test_validate_expanduser(self, os_path): """Test if validate expands the user correctly.""" From f5d299d8c7170061406fa89020183a2762a2e1ef Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Thu, 28 May 2015 13:05:12 +0200 Subject: [PATCH 022/226] Fix intents --- qutebrowser/config/configtypes.py | 10 +++++----- tests/config/test_configtypes.py | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index edc96d89d..489dc456d 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -820,12 +820,12 @@ class File(BaseType): value = os.path.expanduser(value) try: if not os.path.isabs(value): - if standarddir.config(): - if os.path.isfile( - os.path.join(standarddir.config(), value)): - return + cfgdir = standarddir.config() + if cfgdir: + if os.path.isfile(os.path.join(cfgdir, value)): + return raise configexc.ValidationError(value, - "must be an absolute path!") + "must be an absolute path!") if not os.path.isfile(value): raise configexc.ValidationError(value, "must be a valid file!") except UnicodeEncodeError as e: diff --git a/tests/config/test_configtypes.py b/tests/config/test_configtypes.py index 1d52afdc8..317acbe5e 100644 --- a/tests/config/test_configtypes.py +++ b/tests/config/test_configtypes.py @@ -30,7 +30,7 @@ from PyQt5.QtGui import QColor, QFont from PyQt5.QtNetwork import QNetworkProxy from qutebrowser.config import configtypes, configexc -from qutebrowser.utils import debug, utils, standarddir +from qutebrowser.utils import debug, utils class Font(QFont): @@ -1375,19 +1375,19 @@ class TestFile: def test_validate_exists_rel(self, os_path, monkeypatch): """Test validate with a relative path to an existing file.""" - monkeypatch.setattr('qutebrowser.config.configtypes.standarddir.config', - lambda: '/home/foo/.config/') + monkeypatch.setattr( + 'qutebrowser.config.configtypes.standarddir.config', + lambda: '/home/foo/.config/') os_path.expanduser.side_effect = lambda x: x os_path.isfile.return_value = True os_path.isabs.return_value = False self.t.validate('foobar') - os_path.join.assert_called_once_with('/home/foo/.config/', - 'foobar') + os_path.join.assert_called_once_with('/home/foo/.config/', 'foobar') def test_validate_rel_config_none(self, os_path, monkeypatch): """Test with a relative path and standarddir.config returning None.""" - monkeypatch.setattr('qutebrowser.config.configtypes.standarddir.config', - lambda: None) + monkeypatch.setattr( + 'qutebrowser.config.configtypes.standarddir.config', lambda: None) os_path.isabs.return_value = False with pytest.raises(configexc.ValidationError): self.t.validate('foobar') From 63c9e6a444f1a45a8970e3bfebc2c131bc1c9827 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Thu, 28 May 2015 13:20:00 +0200 Subject: [PATCH 023/226] Another indentation-related fix --- qutebrowser/config/configtypes.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 489dc456d..94bc278bf 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -821,9 +821,8 @@ class File(BaseType): try: if not os.path.isabs(value): cfgdir = standarddir.config() - if cfgdir: - if os.path.isfile(os.path.join(cfgdir, value)): - return + if cfgdir and os.path.isfile(os.path.join(cfgdir, value)): + return raise configexc.ValidationError(value, "must be an absolute path!") if not os.path.isfile(value): From 27fdf4903a5bffec6af39032c07bd8f22f255ca6 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 29 May 2015 18:36:39 +0200 Subject: [PATCH 024/226] Implement :jseval (Issue #334) TODO: - Tests - Doesn't show errors --- qutebrowser/misc/utilcmds.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py index ea6fdf1cc..1c7e40d99 100644 --- a/qutebrowser/misc/utilcmds.py +++ b/qutebrowser/misc/utilcmds.py @@ -111,6 +111,19 @@ def message_warning(win_id, text): message.warning(win_id, text) +@cmdutils.register(maxsplit=0, no_cmd_split=True) +def jseval(s): + """Evaluate a JavaScript string. + + Args: + s: The string to evaluate. + """ + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window='last-focused') + message_info(tabbed_browser.widget(0) + .page().mainFrame().evaluateJavaScript(s)) + + @cmdutils.register(debug=True) def debug_crash(typ: {'type': ('exception', 'segfault')}='exception'): """Crash for debugging purposes. From 7b5d2ace2485b91707ce03b79e76be6580c51d41 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Sat, 30 May 2015 15:21:34 -0400 Subject: [PATCH 025/226] Added assertion for parameterized download color picker. --- qutebrowser/browser/downloads.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index e30147e10..f10cd7aad 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -362,6 +362,7 @@ class DownloadItem(QObject): Args: position: The color type requested, can be 'fg' or 'bg'. """ + assert position in ("fg", "bg") start = config.get('colors', 'downloads.{}.start'.format(position)) stop = config.get('colors', 'downloads.{}.stop'.format(position)) system = config.get('colors', 'downloads.{}.system'.format(position)) From fed2cdad4ef138f44171a699d39a3eb7211b87ba Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Sat, 30 May 2015 15:22:00 -0400 Subject: [PATCH 026/226] Cleaned up download configuration options. --- qutebrowser/config/configdata.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index db16a2bbf..67f847865 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -935,31 +935,32 @@ def data(readonly=False): "Background color for the download bar."), ('downloads.fg.start', - SettingValue(typ.QtColor(), '#0000aa'), - "Color gradient start for downloads."), + SettingValue(typ.QtColor(), 'white'), + "Color gradient start for download foreground text."), ('downloads.bg.start', SettingValue(typ.QtColor(), '#0000aa'), - "Color gradient start for downloads."), + "Color gradient start for download background."), ('downloads.fg.stop', - SettingValue(typ.QtColor(), '#00aa00'), - "Color gradient end for downloads."), + SettingValue(typ.QtColor(), '${downloads.fg.start}'), + "Color gradient end for download foreground text."), ('downloads.bg.stop', SettingValue(typ.QtColor(), '#00aa00'), - "Color gradient end for downloads."), + "Color gradient stop for download background."), ('downloads.fg.system', SettingValue(typ.ColorSystem(), 'rgb'), - "Color gradient interpolation system for downloads."), + "Color gradient interpolation system for download foreground" + "text."), ('downloads.bg.system', SettingValue(typ.ColorSystem(), 'rgb'), - "Color gradient interpolation system for downloads."), + "Color gradient interpolation system for download background."), ('downloads.fg.error', - SettingValue(typ.QtColor(), 'red'), + SettingValue(typ.QtColor(), 'white'), "Foreground color for downloads with errors."), ('downloads.bg.error', From 5c599879f819e600d11bcf197f0a902a812fdde6 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Sat, 30 May 2015 16:03:36 -0400 Subject: [PATCH 027/226] Fixed a line-length error. --- qutebrowser/mainwindow/statusbar/bar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index 1e4ae3b84..9b1219b38 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -80,8 +80,8 @@ class StatusBar(QWidget): _command_active: If we're currently in command mode. - For some reason we need to have this as class attribute - so pyqtProperty works correctly. + For some reason we need to have this as class + attribute so pyqtProperty works correctly. _caret_mode: The current caret mode (off/on/selection). From 4d141f489f18d98e00df249a89356c87fef69361 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Wed, 3 Jun 2015 08:42:13 -0400 Subject: [PATCH 028/226] Added pylint workaround directive to quash rebellion. --- qutebrowser/browser/downloads.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 3a7c63fc0..22e8858af 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -362,6 +362,8 @@ class DownloadItem(QObject): Args: position: The color type requested, can be 'fg' or 'bg'. """ + # pylint: disable=bad-config-call + # WORKAROUND for https://bitbucket.org/logilab/astroid/issue/104/ assert position in ("fg", "bg") start = config.get('colors', 'downloads.{}.start'.format(position)) stop = config.get('colors', 'downloads.{}.stop'.format(position)) From 85eea17b183751a89ddc8bb4bb82a3a0ccdf5ba5 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Wed, 3 Jun 2015 22:31:15 +0200 Subject: [PATCH 029/226] Try to get the error ... not sure about this ... source is undefined when you type stuff in the console, I *think* this is the only scenario? But maybe not? --- qutebrowser/browser/commands.py | 20 ++++++++++++++++++++ qutebrowser/browser/webpage.py | 11 +++++++++++ qutebrowser/misc/utilcmds.py | 13 ------------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 0c01260d7..bc2159843 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1510,3 +1510,23 @@ class CommandDispatcher: view = self._current_widget() for _ in range(count): view.triggerPageAction(member) + + @cmdutils.register(instance='command-dispatcher', scope='window', + maxsplit=0, no_cmd_split=True) + def jseval(self, js): + """Evaluate a JavaScript string. + + Args: + s: The string to evaluate. + """ + tabbed_browser = objreg.get('tabbed-browser', scope='window', + window='last-focused') + out = tabbed_browser.widget(0).page().mainFrame().evaluateJavaScript( + 'window.__qute_jseval__ = true;\n' + js) + + if out is not None: + message.info(self._win_id, out) + elif tabbed_browser.widget(0).page().jseval_error: + message.error(self._win_id, + tabbed_browser.widget(0).page().jseval_error) + tabbed_browser.widget(0).page().jseval_error = None diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 005a6e300..9e49032df 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -63,6 +63,7 @@ class BrowserPage(QWebPage): def __init__(self, win_id, tab_id, parent=None): super().__init__(parent) self._win_id = win_id + self.jseval_error = None self._is_shutting_down = False self._extension_handlers = { QWebPage.ErrorPageExtension: self._handle_errorpage, @@ -497,6 +498,16 @@ class BrowserPage(QWebPage): def javaScriptConsoleMessage(self, msg, line, source): """Override javaScriptConsoleMessage to use debug log.""" + + jseval = self.mainFrame().evaluateJavaScript('window.__qute_jseval__') + if jseval: + self.mainFrame().evaluateJavaScript('window.__qute_jseval__ = undefined;') + if source == 'undefined' and jseval: + self.mainFrame().evaluateJavaScript('window.__qute_jseval__ = false;') + print('jseval errror ->', jseval) + self.jseval_error = 'Error on line {}: {}'.format(line, msg) + print('other js error ->', msg, line, source) + if config.get('general', 'log-javascript-console'): log.js.debug("[{}:{}] {}".format(source, line, msg)) diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py index 1c7e40d99..ea6fdf1cc 100644 --- a/qutebrowser/misc/utilcmds.py +++ b/qutebrowser/misc/utilcmds.py @@ -111,19 +111,6 @@ def message_warning(win_id, text): message.warning(win_id, text) -@cmdutils.register(maxsplit=0, no_cmd_split=True) -def jseval(s): - """Evaluate a JavaScript string. - - Args: - s: The string to evaluate. - """ - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window='last-focused') - message_info(tabbed_browser.widget(0) - .page().mainFrame().evaluateJavaScript(s)) - - @cmdutils.register(debug=True) def debug_crash(typ: {'type': ('exception', 'segfault')}='exception'): """Crash for debugging purposes. From 472071c0476f3d42d5767a6823194857aa7f240b Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Wed, 3 Jun 2015 23:59:24 +0200 Subject: [PATCH 030/226] Add setting: 'content.third-party-cookie-policy', fixes #607 This sets the third-party cookie policy. - I created a new ThirdPartyCookiePolicy() class, since this setting seems to be unique in the way it is set... - I set the default to 'never', which is the most secure/private setting, but *may* break *some* features of a (very) limited number of sites; these are usually "non-critical" features. For example, on Stack Exchange sites you're logged in all 200+ sites if you sign in on one of them, this features required 3rd party cookies. You can still sign in with out, but you have to do so 200+ times (this is actually the only example I've ever noticed). AFAIK all "major" browsers accept 3rd-party cookies by default, except for Safari. Firefox also made this change, but reversed it (see: https://brendaneich.com/2013/05/c-is-for-cookie/), but they don't offer any good arguments to *not* have it IMHO, at least not that I could find. In any case, in my humble opinion "secure and private by default" is the best way to ship. But you're of course free to change it if you disagree ;-) --- doc/help/settings.asciidoc | 13 +++++++++++++ qutebrowser/config/configdata.py | 4 ++++ qutebrowser/config/configtypes.py | 10 ++++++++++ qutebrowser/config/websettings.py | 21 +++++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index fc4802232..717a46d13 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -151,6 +151,7 @@ |<>|Whether locally loaded documents are allowed to access other local urls. |<>|Whether to accept cookies. |<>|Whether to store cookies. +|<>|Accept cookies from domains other than the main website |<>|List of URLs of lists which contain hosts to block. |<>|Whether host blocking is enabled. |============== @@ -1336,6 +1337,18 @@ Valid values: Default: +pass:[true]+ +[[content-third-party-cookie-policy]] +=== third-party-cookie-policy +Accept cookies from domains other than the main website + +Valid values: + + * +always+: Always accept. + * +never+: Never accept. + * +existing+: Only accept if we already have acookie stored for the domain + +Default: +pass:[never]+ + [[content-host-block-lists]] === host-block-lists List of URLs of lists which contain hosts to block. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index a3bbe2d48..9028d2c78 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -681,6 +681,10 @@ def data(readonly=False): SettingValue(typ.Bool(), 'true'), "Whether to store cookies."), + ('third-party-cookie-policy', + SettingValue(typ.ThirdPartyCookiePolicy(), 'never'), + "Accept cookies from domains other than the main website"), + ('host-block-lists', SettingValue( typ.UrlList(none_ok=True), diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 55d782202..b4d7319c6 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1329,6 +1329,16 @@ class AcceptCookies(BaseType): ('never', "Don't accept cookies at all.")) +class ThirdPartyCookiePolicy(BaseType): + + """Accept cookies from domains other than the main website.""" + + valid_values = ValidValues(('always', "Always accept."), + ('never', "Never accept."), + ('existing', "Only accept if we already have a" + "cookie stored for the domain.")) + + class ConfirmQuit(List): """Whether to display a confirmation when the window is closed.""" diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py index 117abbb26..edea4edeb 100644 --- a/qutebrowser/config/websettings.py +++ b/qutebrowser/config/websettings.py @@ -238,6 +238,25 @@ class GlobalSetter(Setter): self._setter(*args) +class ThirdPartyCookies(Base): + + """The ThirdPartyCookiePolicy setting is different from other settings.""" + + mapping = ( + ('always', QWebSettings.AlwaysAllowThirdPartyCookies), + ('never', QWebSettings.AlwaysBlockThirdPartyCookies), + ('existing', QWebSettings.AllowThirdPartyWithExistingCookies), + ) + + def get(self, qws=None): + policy = QWebSettings.globalSettings().thirdPartyCookiePolicy() + return tuple(filter(lambda i: i[1] == policy, self.mapping))[0][0] + + def _set(self, value, qws=None): + x = filter(lambda i: i[0] == value, self.mapping) + QWebSettings.globalSettings().setThirdPartyCookiePolicy(tuple(x)[0][1]) + + MAPPINGS = { 'content': { 'allow-images': @@ -264,6 +283,8 @@ MAPPINGS = { Attribute(QWebSettings.LocalContentCanAccessRemoteUrls), 'local-content-can-access-file-urls': Attribute(QWebSettings.LocalContentCanAccessFileUrls), + 'third-party-cookie-policy': + ThirdPartyCookies(), }, 'network': { 'dns-prefetch': From fc4c7bd2e449fe2fca2abbde9f49e96e458cdc24 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 5 Jun 2015 15:57:43 +0200 Subject: [PATCH 031/226] Merge the cookies-accept and third-party-cookie-policy settings --- doc/help/settings.asciidoc | 23 ++++++----------------- qutebrowser/config/configdata.py | 8 ++------ qutebrowser/config/configtypes.py | 19 +++++++------------ qutebrowser/config/websettings.py | 24 ++++++++++++------------ 4 files changed, 27 insertions(+), 47 deletions(-) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 717a46d13..da631e52f 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -149,9 +149,8 @@ |<>|Whether all javascript alerts should be ignored. |<>|Whether locally loaded documents are allowed to access remote urls. |<>|Whether locally loaded documents are allowed to access other local urls. -|<>|Whether to accept cookies. +|<>|Control which cookies to accept. |<>|Whether to store cookies. -|<>|Accept cookies from domains other than the main website |<>|List of URLs of lists which contain hosts to block. |<>|Whether host blocking is enabled. |============== @@ -1317,14 +1316,16 @@ Default: +pass:[true]+ [[content-cookies-accept]] === cookies-accept -Whether to accept cookies. +Control which cookies to accept. Valid values: - * +default+: Default QtWebKit behavior. + * +all+: Accept all cookies. + * +no-3rdparty+: Accept cookies from the same origin only. + * +no-unknown-3rdparty+: Accept cookies from the same origin only, unless a cookie is already set for the domain. * +never+: Don't accept cookies at all. -Default: +pass:[default]+ +Default: +pass:[no-3rdparty]+ [[content-cookies-store]] === cookies-store @@ -1337,18 +1338,6 @@ Valid values: Default: +pass:[true]+ -[[content-third-party-cookie-policy]] -=== third-party-cookie-policy -Accept cookies from domains other than the main website - -Valid values: - - * +always+: Always accept. - * +never+: Never accept. - * +existing+: Only accept if we already have acookie stored for the domain - -Default: +pass:[never]+ - [[content-host-block-lists]] === host-block-lists List of URLs of lists which contain hosts to block. diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 9028d2c78..7a8d3ea83 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -674,17 +674,13 @@ def data(readonly=False): "local urls."), ('cookies-accept', - SettingValue(typ.AcceptCookies(), 'default'), - "Whether to accept cookies."), + SettingValue(typ.AcceptCookies(), 'no-3rdparty'), + "Control which cookies to accept."), ('cookies-store', SettingValue(typ.Bool(), 'true'), "Whether to store cookies."), - ('third-party-cookie-policy', - SettingValue(typ.ThirdPartyCookiePolicy(), 'never'), - "Accept cookies from domains other than the main website"), - ('host-block-lists', SettingValue( typ.UrlList(none_ok=True), diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index b4d7319c6..6aaef90db 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1323,22 +1323,17 @@ class LastClose(BaseType): class AcceptCookies(BaseType): - """Whether to accept a cookie.""" + """Control which cookies to accept.""" - valid_values = ValidValues(('default', "Default QtWebKit behavior."), + valid_values = ValidValues(('all', "Accept all cookies."), + ('no-3rdparty', "Accept cookies from the same" + " origin only."), + ('no-unknown-3rdparty', "Accept cookies from " + "the same origin only, unless a cookie is " + "already set for the domain."), ('never', "Don't accept cookies at all.")) -class ThirdPartyCookiePolicy(BaseType): - - """Accept cookies from domains other than the main website.""" - - valid_values = ValidValues(('always', "Always accept."), - ('never', "Never accept."), - ('existing', "Only accept if we already have a" - "cookie stored for the domain.")) - - class ConfirmQuit(List): """Whether to display a confirmation when the window is closed.""" diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py index edea4edeb..c3216aae2 100644 --- a/qutebrowser/config/websettings.py +++ b/qutebrowser/config/websettings.py @@ -238,23 +238,23 @@ class GlobalSetter(Setter): self._setter(*args) -class ThirdPartyCookies(Base): +class CookiePolicy(Base): """The ThirdPartyCookiePolicy setting is different from other settings.""" - mapping = ( - ('always', QWebSettings.AlwaysAllowThirdPartyCookies), - ('never', QWebSettings.AlwaysBlockThirdPartyCookies), - ('existing', QWebSettings.AllowThirdPartyWithExistingCookies), - ) + MAPPING = { + 'all': QWebSettings.AlwaysAllowThirdPartyCookies, + 'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies, + 'never': QWebSettings.AlwaysBlockThirdPartyCookies, + 'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies, + } def get(self, qws=None): - policy = QWebSettings.globalSettings().thirdPartyCookiePolicy() - return tuple(filter(lambda i: i[1] == policy, self.mapping))[0][0] + return config.get('content', 'cookies-accept') def _set(self, value, qws=None): - x = filter(lambda i: i[0] == value, self.mapping) - QWebSettings.globalSettings().setThirdPartyCookiePolicy(tuple(x)[0][1]) + QWebSettings.globalSettings().setThirdPartyCookiePolicy( + self.MAPPING[value]) MAPPINGS = { @@ -283,8 +283,8 @@ MAPPINGS = { Attribute(QWebSettings.LocalContentCanAccessRemoteUrls), 'local-content-can-access-file-urls': Attribute(QWebSettings.LocalContentCanAccessFileUrls), - 'third-party-cookie-policy': - ThirdPartyCookies(), + 'cookies-accept': + CookiePolicy(), }, 'network': { 'dns-prefetch': From 94178c558abf0d5da0bdd6a5ec81348022d72a23 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 5 Jun 2015 20:07:47 +0200 Subject: [PATCH 032/226] Well, getting the error doesn't work... --- doc/help/commands.asciidoc | 14 ++++++++++++++ qutebrowser/browser/commands.py | 28 ++++++++++++++++++---------- qutebrowser/browser/webpage.py | 11 ----------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index c33bccaaf..287620867 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -20,6 +20,7 @@ |<>|Start hinting. |<>|Open main startpage in current tab. |<>|Toggle the web inspector. +|<>|Evaluate a JavaScript string. |<>|Execute a command after some time. |<>|Open typical prev/next links or navigate using the URL path. |<>|Open a URL in the current/[count]th tab. @@ -241,6 +242,19 @@ Open main startpage in current tab. === inspector Toggle the web inspector. +[[jseval]] +=== jseval +Syntax: +:jseval 'js_code'+ + +Evaluate a JavaScript string. + +==== positional arguments +* +'js_code'+: The string to evaluate. + +==== note +* This command does not split arguments after the last argument and handles quotes literally. +* With this command, +;;+ is interpreted literally instead of splitting off a second command. + [[later]] === later Syntax: +:later 'ms' 'command'+ diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index bc2159843..aa8430127 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1513,20 +1513,28 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', scope='window', maxsplit=0, no_cmd_split=True) - def jseval(self, js): + def jseval(self, js_code): """Evaluate a JavaScript string. Args: - s: The string to evaluate. + js_code: The string to evaluate. """ tabbed_browser = objreg.get('tabbed-browser', scope='window', window='last-focused') - out = tabbed_browser.widget(0).page().mainFrame().evaluateJavaScript( - 'window.__qute_jseval__ = true;\n' + js) + frame = tabbed_browser.widget(0).page().mainFrame() + out = frame.evaluateJavaScript(js_code) - if out is not None: - message.info(self._win_id, out) - elif tabbed_browser.widget(0).page().jseval_error: - message.error(self._win_id, - tabbed_browser.widget(0).page().jseval_error) - tabbed_browser.widget(0).page().jseval_error = None + if out is None: + # Getting the actual error (if any) seems to be difficult. The + # error does end up in BrowserPage.javaScriptConsoleMessage(), but + # distinguishing between :jseval errors and errors from the webpage + # is not trivial... + message.info(self._win_id, 'No output or error') + else: + # The output can be a string, number, dict, array, etc. But *don't* + # output too much data, as this will make qutebrowser hang + out = str(out) + if len(out) > 5000: + message.info(self._win_id, out[:5000] + ' [...trimmed...]') + else: + message.info(self._win_id, out) diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 9e49032df..005a6e300 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -63,7 +63,6 @@ class BrowserPage(QWebPage): def __init__(self, win_id, tab_id, parent=None): super().__init__(parent) self._win_id = win_id - self.jseval_error = None self._is_shutting_down = False self._extension_handlers = { QWebPage.ErrorPageExtension: self._handle_errorpage, @@ -498,16 +497,6 @@ class BrowserPage(QWebPage): def javaScriptConsoleMessage(self, msg, line, source): """Override javaScriptConsoleMessage to use debug log.""" - - jseval = self.mainFrame().evaluateJavaScript('window.__qute_jseval__') - if jseval: - self.mainFrame().evaluateJavaScript('window.__qute_jseval__ = undefined;') - if source == 'undefined' and jseval: - self.mainFrame().evaluateJavaScript('window.__qute_jseval__ = false;') - print('jseval errror ->', jseval) - self.jseval_error = 'Error on line {}: {}'.format(line, msg) - print('other js error ->', msg, line, source) - if config.get('general', 'log-javascript-console'): log.js.debug("[{}:{}] {}".format(source, line, msg)) From b0880df695867bc60a8ac9edd79bd8fee671a393 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 5 Jun 2015 23:24:47 +0200 Subject: [PATCH 033/226] Execute in the current tab, and not the first one --- qutebrowser/browser/commands.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index aa8430127..774cbaaa9 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1519,10 +1519,8 @@ class CommandDispatcher: Args: js_code: The string to evaluate. """ - tabbed_browser = objreg.get('tabbed-browser', scope='window', - window='last-focused') - frame = tabbed_browser.widget(0).page().mainFrame() - out = frame.evaluateJavaScript(js_code) + out = self._current_widget().page().mainFrame().evaluateJavaScript( + js_code) if out is None: # Getting the actual error (if any) seems to be difficult. The From de0686c50ab0a337ba94315a0c3a54ab97499e86 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Sat, 6 Jun 2015 14:04:45 +0200 Subject: [PATCH 034/226] Error messages and explicit test for None Error messages for validate() are more specific. Return of standarddir.conf() is explicitly tested for None to avoid ambiguity with other falsey values. --- qutebrowser/config/configtypes.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 267ae8789..ef23cbbbe 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -805,7 +805,7 @@ class File(BaseType): value = os.path.expanduser(value) value = os.path.expandvars(value) if not os.path.isabs(value): - if standarddir.config(): + if standarddir.config() is not None: abspath = os.path.join(standarddir.config(), value) if os.path.isfile(abspath): return abspath @@ -821,12 +821,16 @@ class File(BaseType): try: if not os.path.isabs(value): cfgdir = standarddir.config() - if cfgdir and os.path.isfile(os.path.join(cfgdir, value)): + if cfgdir is not None and os.path.isfile( + os.path.join(cfgdir, value)): return - raise configexc.ValidationError(value, - "must be an absolute path!") - if not os.path.isfile(value): - raise configexc.ValidationError(value, "must be a valid file!") + raise configexc.ValidationError( + value, "must be an absolute path when not using a config " + "directory!") + elif not os.path.isfile(value): + raise configexc.ValidationError( + value, "must be a valid path relative to the config " + "directory!") except UnicodeEncodeError as e: raise configexc.ValidationError(value, e) @@ -1195,7 +1199,7 @@ class UserStyleSheet(File): raise configexc.ValidationError(value, str(e)) return except UnicodeEncodeError as e: - raise configexc.ValidationError(value, e) + raise configexc.ValidationError(value, str(e)) class AutoSearch(BaseType): From 5bacbc9d3862c7b8225dd9ad3416a35b5fb6a090 Mon Sep 17 00:00:00 2001 From: Lamar Pavel Date: Sat, 6 Jun 2015 14:07:57 +0200 Subject: [PATCH 035/226] Remove obsolete try-except block --- qutebrowser/config/configtypes.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index ef23cbbbe..3b623e3ab 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -1193,11 +1193,7 @@ class UserStyleSheet(File): # FIXME We just try if it is encodable, maybe we should # validate CSS? # https://github.com/The-Compiler/qutebrowser/issues/115 - try: - value.encode('utf-8') - except UnicodeEncodeError as e: - raise configexc.ValidationError(value, str(e)) - return + value.encode('utf-8') except UnicodeEncodeError as e: raise configexc.ValidationError(value, str(e)) From 2fa6c952c26dfc387940f124aa5abd6de8c8b5e2 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sun, 7 Jun 2015 16:37:25 +0200 Subject: [PATCH 036/226] Use less CPU when downloading files When downloading a bunch (7 or 8) of files I noticed qutebrowser was using a lot of CPU (>60%). I did some looking, and in the `downloadProgress` callback qutebrower emits the updated signal which causes everything to be updated. We don't really need this, since _update_speed() calls it every 500ms anyway. I tested by downloading 3 copies of the 1GB file [on this page]( http://www.thinkbroadband.com/download.html ) qutebrowser consistently pulls about 25% CPU on my system. When removing this call, the system pulls about 17% CPU. Not a great amount, but still significant enough to warrant a pull request ;-) Some other notes: - wget uses about 1.5%-2% for each process when downloading. - When not doing any UI updates & speed calculations qutebrowser uses about 15%. - Doing some quick profiling and strategic commenting seems to indicate there isn't any other low hanging fruit to be improved on here. --- qutebrowser/browser/downloads.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 790459f6a..aa29fce9c 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -148,7 +148,7 @@ class DownloadItemStats(QObject): @pyqtSlot(int, int) def on_download_progress(self, bytes_done, bytes_total): - """Upload local variables when the download progress changed. + """Update local variables when the download progress changed. Args: bytes_done: How many bytes are downloaded. @@ -158,7 +158,6 @@ class DownloadItemStats(QObject): bytes_total = None self.done = bytes_done self.total = bytes_total - self.updated.emit() class DownloadItem(QObject): From da2ff6f3cb168cb4fe00161fbc3b8e8f587701be Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 7 Jun 2015 21:27:50 +0200 Subject: [PATCH 037/226] Update recommended Qt version in README. --- README.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.asciidoc b/README.asciidoc index 3a701fd76..4ff63f5a7 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -89,7 +89,7 @@ Requirements The following software and libraries are required to run qutebrowser: * http://www.python.org/[Python] 3.4 -* http://qt-project.org/[Qt] 5.2.0 or newer (5.4.1 recommended) +* http://qt-project.org/[Qt] 5.2.0 or newer (5.4.2 recommended) * QtWebKit * http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.2.0 or newer (5.4.1 recommended) for Python 3 From f85ca19cef3aa2d7eac3cecb73f806a0d75c740d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 7 Jun 2015 21:33:35 +0200 Subject: [PATCH 038/226] Use