diff --git a/README.asciidoc b/README.asciidoc index 4d3b5c8b7..a330fab03 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -1,15 +1,13 @@ -qutebrowser readme -================== +qutebrowser +=========== -About qutebrowser ------------------ +_A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit._ -qutebrowser is a browser based on PyQt5 which aims to be keyboard-focused with -an input similar to vim. +qutebrowser is a keyboard-focused browser with with a minimal GUI. It's based +on Python, PyQt5 and QtWebKit and free software, licensed under the GPL. It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl. - Getting help ------------ @@ -21,7 +19,33 @@ message to the https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[mailinglist] at mailto:qutebrowser@lists.qutebrowser.org[]. +Running qutebrowser +------------------- +After installing the <>, you have these options: + +* Run qutebrowser directly via `python3 -m qutebrowser`. Note executing +qutebrowser.py directly as script won't work, as Python won't recognize the +module. +* Run `python3 setup.py install` to install qutebrowser, then call +`qutebrowser`. + +Contributions / Bugs +-------------------- + +You want to contribute to qutebrowser? Awesome! Please read +link:doc/HACKING.asciidoc[HACKING] for details and useful hints. + +If you found a bug or have a feature request, you can report it in several +ways: + +* Use the built-in `:report` command or the automatic crash dialog. +* Open an issue in the Github issue tracker. +* Write a mail to the +https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[mailinglist] at +mailto:qutebrowser@lists.qutebrowser.org[]. + +[[requirements]] Requirements ------------ @@ -33,27 +57,92 @@ The following software and libraries are required to run qutebrowser: * http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.2 or newer (5.3.1 recommended) for Python 3 * https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools] +* https://github.com/g2p/rfc6266[rfc6266] The following libraries are optional and provide better debugging: * https://pypi.python.org/pypi/colorlog/[colorlog] * On Windows: https://pypi.python.org/pypi/colorama/[colorama] -.On Debian: +On Debian +~~~~~~~~~ - apt-get install python3-pyqt5 python3-pyqt5.qtwebkit python3-pkg-resources +---- +# apt-get install python3-pyqt5 python3-pyqt5.qtwebkit python3-pkg-resources +# pip3 install rfc6266 +---- -.On Archlinux: +On Archlinux +~~~~~~~~~~~~ - pacman -S python-pyqt5 qt5-webkit python-setuptools +Install https://aur.archlinux.org/packages/qutebrowser-git/[qutebrowser-git] +from the AUR. -Note an Archlinux AUR package is available. - -.On Windows: +On Windows +~~~~~~~~~~ Use the installer from http://www.python.org/downloads[python.org] to get Python 3 and the installer from http://www.riverbankcomputing.com/software/pyqt/download5[Riverbank computing] to get Qt and PyQt5. Run `scripts/ez_setup.py` to get setuptools. -Note a standalone .EXE is available. +Note a standalone .exe is available. + +Authors +------- + +include::doc/AUTHORS.asciidoc[] + +Thanks / Similiar projects +-------------------------- + +Many projects with a similiar goal as qutebrowser exist: + +* http://portix.bitbucket.org/dwb/[dwb] +* https://github.com/fanglingsu/vimb[vimb] +* http://sourceforge.net/projects/vimprobable/[vimprobable] +* https://mason-larobina.github.io/luakit/[luakit] +* http://pwmt.org/projects/jumanji/[jumanji] +* http://conkeror.org/[conkeror] +* http://surf.suckless.org/[surf] +* http://www.uzbl.org/[uzbl] +* http://www.vimperator.org/[Vimperator] (Firefox addon) +* http://5digits.org/pentadactyl/[Pentadactyl] (Firefox addon) +* https://github.com/akhodakivskiy/VimFx[VimFx] (Firefox addon) +* http://vimium.github.io/[vimium] (Chrome/Chromium addon) + +Most of them were inspirations for qutebrowser in some way, thanks for that! + +Thanks as well to the following projects and people for helping me with +problems and helpful hints: + +* http://eric-ide.python-projects.org/[eric5] / Detlev Offenbach +* https://code.google.com/p/devicenzo/[devicenzo] +* portix +* seir +* nitroxleecher + +Also, thanks to: + +* Everyone who had the patience to test qutebrowser before v0.1. +* Everyone triaging/fixing my bugs in the +https://bugreports.qt-project.org/secure/Dashboard.jspa[Qt bugtracker] +* Everyone answering my questions on http://stackoverflow.com/[Stack Overflow] +and in IRC. +* All the projects which were a great help while developing qutebrowser. + +License +------- + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/doc/AUTHORS.asciidoc b/doc/AUTHORS.asciidoc index 2c07aa61f..a091ae32d 100644 --- a/doc/AUTHORS.asciidoc +++ b/doc/AUTHORS.asciidoc @@ -1,3 +1,3 @@ Contributors, sorted by the number of commits in descending order: -Florian Bruhin +* Florian Bruhin diff --git a/doc/HACKING.asciidoc b/doc/HACKING.asciidoc index 4d1df37d2..374907bc6 100644 --- a/doc/HACKING.asciidoc +++ b/doc/HACKING.asciidoc @@ -346,6 +346,11 @@ http://legacy.python.org/dev/peps/pep-0008/[PEP8] and the https://google-stylegu http://legacy.python.org/dev/peps/pep-0257/[PEP257] and the google guidelines. * Class docstrings have additional _Attributes:_, _Class attributes:_ and _Signals:_ sections, method/function docstrings have an _Emit:_ section. +* In docstrings of command handlers (registered via `@cmdutils.register`), the +description should be split into two parts by using `//` - the first part is +the description of the command like it will appear in the documentation, the +second part is "internal" documentation only relevant to people reading the +sourcecode. + Example for a class docstring: + @@ -368,6 +373,12 @@ Example for a method/function docstring: ---- """Do something special. +This will do something. + +// + +It is based on http://example.com/. + Args: foo: ... diff --git a/doc/THANKS.asciidoc b/doc/THANKS.asciidoc deleted file mode 100644 index 405596064..000000000 --- a/doc/THANKS.asciidoc +++ /dev/null @@ -1,53 +0,0 @@ -Thanks -====== - -Thanks to the following projects, which were a source for great inspiration: - -* http://eric-ide.python-projects.org/[eric5] -* http://portix.bitbucket.org/dwb/[dwb] -* http://www.vimperator.org/[Vimperator] -* http://5digits.org/pentadactyl/[Pentadactyl] -* https://github.com/fanglingsu/vimb[vimb] -* http://vimium.github.io/[vimium] -* https://code.google.com/p/devicenzo/[devicenzo] - -Thanks to the following people for helping me with problems big and small: - -* portix -* Detlev Offenbach -* seir -* nitroxleecher - -Thanks to the following people for early testing: - -* V155 -* eto -* portix -* iggy -* meisterT_ -* hrnz -* pedromj -* china -* Tsutsukakushi -* seir -* raven_ch -* rieper -* thorsten` - -Thanks to everone answering my and other questions on Stackoverflow and the IRC. - -Thanks to the people triaging bugs in the Qt bugtracker. - -Thanks to these projects which were essential while developing qutebrowser, and -all their contributors: - -* http://www.python.org/[Python] -* http://www.vim.org/[vim] -* http://git-scm.com/[git] -* http://qt-project.org/[Qt] -* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] -* http://www.pylint.org/[pylint] -* https://pypi.python.org/pypi/pyflakes[pyflakes] -* https://pypi.python.org/pypi/pep8/[pep8] -* https://github.com/GreenSteam/pep257/[pep257] -* https://pypi.python.org/pypi/flake8[flake8] diff --git a/qutebrowser/app.py b/qutebrowser/app.py index d61a1f087..4827b76a9 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -616,6 +616,8 @@ class Application(QApplication): def debug_pyeval(self, s): """Evaluate a python string and display the results as a webpage. + // + We have this here rather in utils.debug so the context of eval makes more sense and because we don't want to import much stuff in the utils. diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index b856b7717..e0d8690f3 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -619,6 +619,8 @@ class CommandDispatcher: The command will be run in a shell, so you can use shell features like redirections. + // + We use subprocess rather than Qt's QProcess here because of it's shell=True argument and because we really don't care about the process anymore as soon as it's spawned. @@ -706,6 +708,8 @@ class CommandDispatcher: def open_editor(self): """Open an external editor with the current form field. + // + We use QProcess rather than subprocess here because it makes it a lot easier to execute some code as soon as the process has been finished and do everything async. diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index f92acb134..0568e3791 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -287,6 +287,8 @@ class ConfigManager(QObject): def get_wrapper(self, sectname, optname): """Get the value from a section/option. + // + Wrapper for the get-command to output the value in the status bar. """ try: @@ -331,6 +333,8 @@ class ConfigManager(QObject): def set_wrapper(self, sectname, optname, value): """Set an option. + // + Wrapper for self.set() to output exceptions in the status bar. """ try: @@ -344,6 +348,8 @@ class ConfigManager(QObject): def set_temp_wrapper(self, sectname, optname, value): """Set a temporary option. + // + Wrapper for self.set() to output exceptions in the status bar. """ try: diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 9cd29f3b5..8b9fb064e 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -74,38 +74,39 @@ SECTION_DESC = { 'searchengines': ( "Definitions of search engines which can be used via the address " "bar.\n" - "The searchengine named DEFAULT is used when general.auto-search " - "is true and something else than a URL was entered to be opened. " - "Other search engines can be used via the bang-syntax, e.g. " - '"qutebrowser !google". The string "{}" will be replaced by the ' - 'search term, use "{{" and "}}" for literal {/} signs.'), + "The searchengine named `DEFAULT` is used when " + "`general -> auto-search` is true and something else than a URL was " + "entered to be opened. Other search engines can be used via the " + "bang-syntax, e.g. `:open qutebrowser !google`. The string `{}` will " + "be replaced by the search term, use `{{` and `}}` for literal " + "`{`/`}` signs."), 'keybind': ( "Bindings from a key(chain) to a command.\n" "For special keys (can't be part of a keychain), enclose them in " - "<...>. For modifiers, you can use either - or + as delimiters, and " - "these names:\n" - " Control: Control, Ctrl\n" - " Meta: Meta, Windows, Mod4\n" - " Alt: Alt, Mod1\n" - " Shift: Shift\n" - "For simple keys (no <>-signs), a capital letter means the key is " - "pressed with Shift. For special keys (with <>-signs), you need " - 'to explicitely add "Shift-" to match a key pressed with shift. ' - 'You can bind multiple commands by separating them with ";;".'), + "`<`...`>`. For modifiers, you can use either `-` or `+` as " + "delimiters, and these names:\n\n" + " * Control: `Control`, `Ctrl`\n" + " * Meta: `Meta`, `Windows`, `Mod4`\n" + " * Alt: `Alt`, `Mod1`\n" + " * Shift: `Shift`\n\n" + "For simple keys (no `<>`-signs), a capital letter means the key is " + "pressed with Shift. For special keys (with `<>`-signs), you need " + "to explicitely add `Shift-` to match a key pressed with shift. " + "You can bind multiple commands by separating them with `;;`."), 'keybind.insert': ( "Keybindings for insert mode.\n" "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" - "Useful hidden commands to map in this section:\n" - " open-editor: Open a texteditor with the focused field.\n" - " leave-mode: Leave the command mode."), + "Useful hidden commands to map in this section:\n\n" + " * `open-editor`: Open a texteditor with the focused field.\n" + " * `leave-mode`: Leave the command mode."), 'keybind.hint': ( "Keybindings for hint mode.\n" "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" - "Useful hidden commands to map in this section:\n" - " follow-hint: Follow the currently selected hint.\n" - " leave-mode: Leave the command mode."), + "Useful hidden commands to map in this section:\n\n" + " * `follow-hint`: Follow the currently selected hint.\n" + " * `leave-mode`: Leave the command mode."), 'keybind.passthrough': ( "Keybindings for passthrough mode.\n" "Since normal keypresses are passed through, only special keys are " @@ -115,53 +116,54 @@ SECTION_DESC = { "Keybindings for command mode.\n" "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" - "Useful hidden commands to map in this section:\n" - " command-history-prev: Switch to previous command in history.\n" - " command-history-next: Switch to next command in history.\n" - " completion-item-prev: Select previous item in completion.\n" - " completion-item-next: Select next item in completion.\n" - " command-accept: Execute the command currently in the commandline.\n" - " leave-mode: Leave the command mode."), + "Useful hidden commands to map in this section:\n\n" + " * `command-history-prev`: Switch to previous command in history.\n" + " * `command-history-next`: Switch to next command in history.\n" + " * `completion-item-prev`: Select previous item in completion.\n" + " * `completion-item-next`: Select next item in completion.\n" + " * `command-accept`: Execute the command currently in the " + "commandline.\n" + " * `leave-mode`: Leave the command mode."), 'keybind.prompt': ( "Keybindings for prompts in the status line.\n" "You can bind normal keys in this mode, but they will be only active " "when a yes/no-prompt is asked. For other prompt modes, you can only " "bind special keys.\n" - "Useful hidden commands to map in this section:\n" - " prompt-accept: Confirm the entered value.\n" - " prompt-yes: Answer yes to a yes/no question.\n" - " prompt-no: Answer no to a yes/no question.\n" - " leave-mode: Leave the prompt mode."), + "Useful hidden commands to map in this section:\n\n" + " * `prompt-accept`: Confirm the entered value.\n" + " * `prompt-yes`: Answer yes to a yes/no question.\n" + " * `prompt-no`: Answer no to a yes/no question.\n" + " * `leave-mode`: Leave the prompt mode."), 'aliases': ( "Aliases for commands.\n" "By default, no aliases are defined. Example which adds a new command " - ":qtb to open qutebrowsers website:\n" - " qtb = open http://www.qutebrowser.org/"), + "`:qtb` to open qutebrowsers website:\n\n" + "`qtb = open http://www.qutebrowser.org/`"), 'colors': ( "Colors used in the UI.\n" - "A value can be in one of the following format:\n" - " - #RGB/#RRGGBB/#RRRGGGBBB/#RRRRGGGGBBBB\n" - " - A SVG color name as specified in [1].\n" - " - transparent (no color)\n" - " - rgb(r, g, b) / rgba(r, g, b, a) (values 0-255 or " + "A value can be in one of the following format:\n\n" + " * `#RGB`/`#RRGGBB`/`#RRRGGGBBB`/`#RRRRGGGGBBBB`\n" + " * A SVG color name as specified in http://www.w3.org/TR/SVG/" + "types.html#ColorKeywords[the W3C specification].\n" + " * transparent (no color)\n" + " * `rgb(r, g, b)` / `rgba(r, g, b, a)` (values 0-255 or " "percentages)\n" - " - hsv(h, s, v) / hsva(h, s, v, a) (values 0-255, hue 0-359)\n" - ' - A gradient as explained at [2] under "Gradient"\n' - " [1] http://www.w3.org/TR/SVG/types.html#ColorKeywords\n" - " [2] http://qt-project.org/doc/qt-4.8/stylesheet-reference.html" - "#list-of-property-types\n" - 'The "hints.*" values are a special case as they\'re real CSS ' + " * `hsv(h, s, v)` / `hsva(h, s, v, a)` (values 0-255, hue 0-359)\n" + " * 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" + "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 [3].\n" - " [3] https://www.webkit.org/blog/175/introducing-css-gradients/"), + "`-webkit-gradient`, see https://www.webkit.org/blog/175/introducing-" + "css-gradients/[the WebKit documentation].\n"), 'fonts': ( - "Fonts used for the UI, with optional style/weight/size.\n" - " Style: normal/italic/oblique\n" - " Weight: normal, bold, 100..900\n" - " Size: Number + px/pt\n" + "Fonts used for the UI, with optional style/weight/size.\n\n" + " * Style: `normal`/`italic`/`oblique`\n" + " * Weight: `normal`, `bold`, 100..900\n" + " * Size: _number_ `px`/`pt`\n\n" "Note: The font for hints is a true CSS font, not a Qt-CSS one, " - 'because of that, a general "Monospace" family is enough and we ' - 'don\'t use "${_monospace}" there.'), + "because of that, a general ``Monospace'' family is enough and we " + "don't use `${_monospace}` there."), } @@ -200,7 +202,7 @@ DATA = OrderedDict([ ('editor', SettingValue(types.ShellCommand(placeholder=True), 'gvim -f "{}"'), "The editor (and arguments) to use for the open-editor binding. " - "Use {} for the filename. Gets split via shutils."), + "Use `{}` for the filename. Gets split via shutils."), ('private-browsing', SettingValue(types.Bool(), 'false'), diff --git a/qutebrowser/config/value.py b/qutebrowser/config/value.py index 98453cccb..c0e8ad294 100644 --- a/qutebrowser/config/value.py +++ b/qutebrowser/config/value.py @@ -55,6 +55,11 @@ class SettingValue: """Get the currently valid value.""" return self.get_first_value() + @property + def default(self): + """Get the default value.""" + return self._values['default'] + @property def values(self): """Readonly property for _values.""" diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py index c8b3f443a..e9d998e3f 100644 --- a/qutebrowser/utils/debug.py +++ b/qutebrowser/utils/debug.py @@ -34,7 +34,9 @@ import qutebrowser.commands.utils as cmdutils @cmdutils.register(debug=True, name='debug-set-trace') def set_trace(): - """Set a tracepoint in the Python debugger that works with Qt. + """Break into the debugger in the shell. + + // Based on http://stackoverflow.com/a/1745965/2085149 """ diff --git a/qutebrowser/widgets/mainwindow.py b/qutebrowser/widgets/mainwindow.py index 09d47bb5f..173c408bd 100644 --- a/qutebrowser/widgets/mainwindow.py +++ b/qutebrowser/widgets/mainwindow.py @@ -148,7 +148,12 @@ class MainWindow(QWidget): @cmdutils.register(instance='mainwindow', name=['quit', 'q'], nargs=0) def close(self): - """Extend close() so we can register it as a command.""" + """Quit qutebrowser. + + // + + Extend close() so we can register it as a command. + """ super().close() def resizeEvent(self, e): diff --git a/qutebrowser/widgets/statusbar/prompter.py b/qutebrowser/widgets/statusbar/prompter.py index 7250c4aac..b4b63b49f 100644 --- a/qutebrowser/widgets/statusbar/prompter.py +++ b/qutebrowser/widgets/statusbar/prompter.py @@ -171,7 +171,9 @@ class Prompter: @cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True, modes=['prompt']) def prompt_accept(self): - """Accept the prompt. + """Accept the current prompt. + + // This executes the next action depending on the question mode, e.g. asks for the password or leaves the mode. diff --git a/scripts/generate_authors.py b/scripts/generate_authors.py index cd3ac4ac4..999e5e148 100644 --- a/scripts/generate_authors.py +++ b/scripts/generate_authors.py @@ -27,9 +27,9 @@ from collections import Counter commits = subprocess.check_output(['git', 'log', '--format=%aN']) cnt = Counter(commits.decode('utf-8').splitlines()) -with open('AUTHORS', 'w', newline='\n', encoding='utf-8') as f: +with open('doc/AUTHORS.asciidoc', 'w', newline='\n', encoding='utf-8') as f: f.write("Contributors, sorted by the number of commits in descending " "order:\n\n") for author in sorted(cnt, key=lambda k: cnt[k]): - f.write(author) + f.write('* ' + author) f.write('\n') diff --git a/scripts/generate_manpage.py b/scripts/generate_manpage.py new file mode 100644 index 000000000..e8ccb4803 --- /dev/null +++ b/scripts/generate_manpage.py @@ -0,0 +1,253 @@ +# Copyright 2014 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Generate asciidoc source for qutebrowser based on docstrings.""" + +import os +import sys +import cgi +import inspect + +sys.path.insert(0, os.getcwd()) + +import qutebrowser.app +import qutebrowser.commands.utils as cmdutils +import qutebrowser.config.configdata as configdata +from qutebrowser.utils.usertypes import enum + + +def parse_docstring(func): + """Generates documentation based on a docstring of a command handler. + + The docstring needs to follow the format described in HACKING. + + Args: + func: The function to generate the docstring for. + + Return: + A (short_desc, long_desc, arg_descs) tuple. + """ + State = enum('short', 'desc', 'desc_hidden', 'arg_start', 'arg_inside', + 'misc') + doc = inspect.getdoc(func) + lines = doc.splitlines() + + cur_state = State.short + + short_desc = [] + long_desc = [] + arg_descs = {} + cur_arg_name = None + + for line in lines: + if cur_state == State.short: + if not line: + cur_state = State.desc + else: + short_desc.append(line.strip()) + elif cur_state == State.desc: + if line.startswith('Args:'): + cur_state = State.arg_start + elif line.startswith('Emit:') or line.startswith('Raise:'): + cur_state = State.misc + elif line.strip() == '//': + cur_state = State.desc_hidden + elif line.strip(): + long_desc.append(line.strip()) + elif cur_state == State.misc: + if line.startswith('Args:'): + cur_state = State.arg_start + else: + pass + elif cur_state == State.desc_hidden: + if line.startswith('Args:'): + cur_state = State.arg_start + elif cur_state == State.arg_start: + cur_arg_name, argdesc = line.split(':', maxsplit=1) + cur_arg_name = cur_arg_name.strip() + arg_descs[cur_arg_name] = [argdesc.strip()] + cur_state = State.arg_inside + elif cur_state == State.arg_inside: + if not line: + break + elif line[4:].startswith(' '): + arg_descs[cur_arg_name].append(line.strip()) + else: + cur_arg_name, argdesc = line.split(':', maxsplit=1) + cur_arg_name = cur_arg_name.strip() + arg_descs[cur_arg_name] = [argdesc.strip()] + + return (short_desc, long_desc, arg_descs) + + +def get_cmd_syntax(name, cmd): + words = [] + argspec = inspect.getfullargspec(cmd.handler) + if argspec.defaults is not None: + defaults = dict(zip(reversed(argspec.args), reversed(list(argspec.defaults)))) + else: + defaults = {} + words.append(name) + minargs, maxargs = cmd.nargs + i = 1 + for arg in argspec.args: + if arg in ['self', 'count']: + continue + if minargs is not None and i <= minargs: + words.append('<{}>'.format(arg)) + elif maxargs is None or i <= maxargs: + words.append('[<{}>]'.format(arg)) + i += 1 + return (' '.join(words), defaults) + + +def get_command_quickref(cmds): + out = [] + out.append('[options="header",width="75%",cols="25%,75%"]') + out.append('|==============') + out.append('|Command|Description') + for name, cmd in cmds: + desc = inspect.getdoc(cmd.handler).splitlines()[0] + out.append('|<>|{}'.format(name, name, desc)) + out.append('|==============') + return '\n'.join(out) + + +def get_setting_quickref(): + out = [] + for sectname, sect in configdata.DATA.items(): + if not getattr(sect, 'descriptions'): + continue + out.append(".Quick reference for section ``{}''".format(sectname)) + out.append('[options="header",width="75%",cols="25%,75%"]') + out.append('|==============') + out.append('|Setting|Description') + for optname, option in sect.items(): + desc = sect.descriptions[optname] + out.append('|<>|{}'.format( + sectname, optname, optname, desc)) + out.append('|==============') + return '\n'.join(out) + + +def get_command_doc(name, cmd): + output = ['[[cmd-{}]]'.format(name)] + output += ['==== {}'.format(name)] + syntax, defaults = get_cmd_syntax(name, cmd) + output.append('+:{}+'.format(syntax)) + output.append("") + short_desc, long_desc, arg_descs = parse_docstring(cmd.handler) + output.append(' '.join(short_desc)) + output.append("") + output.append(' '.join(long_desc)) + if arg_descs: + output.append("") + for arg, desc in arg_descs.items(): + item = "* +{}+: {}".format(arg, ' '.join(desc)) + if arg in defaults: + item += " (default: +{}+)".format(defaults[arg]) + output.append(item) + output.append("") + output.append("") + return '\n'.join(output) + + +def generate_header(): + print('= qutebrowser manpage') + print('Florian Bruhin ') + print(':toc:') + print(':homepage: http://www.qutebrowser.org/') + print("== NAME") + + +def generate_commands(): + print() + print("== Commands") + normal_cmds = [] + hidden_cmds = [] + debug_cmds = [] + for name, cmd in cmdutils.cmd_dict.items(): + if cmd.hide: + hidden_cmds.append((name, cmd)) + elif cmd.debug: + debug_cmds.append((name, cmd)) + else: + normal_cmds.append((name, cmd)) + normal_cmds.sort() + hidden_cmds.sort() + debug_cmds.sort() + print() + print("=== Normal commands") + print(".Quick reference") + print(get_command_quickref(normal_cmds)) + for name, cmd in normal_cmds: + print(get_command_doc(name, cmd)) + print() + print("=== Hidden commands") + print(".Quick reference") + print(get_command_quickref(hidden_cmds)) + for name, cmd in hidden_cmds: + print(get_command_doc(name, cmd)) + print() + print("=== Debugging commands") + print("These commands are mainly intended for debugging. They are hidden " + "if qutebrowser was started without the `--debug`-flag.") + print() + print(".Quick reference") + print(get_command_quickref(debug_cmds)) + for name, cmd in debug_cmds: + print(get_command_doc(name, cmd)) + + +def generate_settings(): + print() + print("== Settings") + print(get_setting_quickref()) + for sectname, sect in configdata.DATA.items(): + print() + print("=== {}".format(sectname)) + print(configdata.SECTION_DESC[sectname]) + if not getattr(sect, 'descriptions'): + pass + else: + for optname, option in sect.items(): + print() + print('[[setting-{}-{}]]'.format(sectname, optname)) + print("==== {}".format(optname)) + print(sect.descriptions[optname]) + print() + valid_values = option.typ.valid_values + if valid_values is not None: + print("Valid values:") + print() + for val in valid_values: + try: + desc = valid_values.descriptions[val] + print(" * +{}+: {}".format(val, desc)) + except KeyError: + print(" * +{}+".format(val)) + print() + if option.default: + print("Default: +pass:[{}]+".format(cgi.escape( + option.default))) + else: + print("Default: empty") + + +generate_header() +generate_settings() +generate_commands()