Add, use, and require auto docs for all keybindings

develop
PeridexisErrant 2016-08-25 10:28:07 +10:00
parent e3ff89ba03
commit 951d293050
3 changed files with 123 additions and 18 deletions

@ -72,6 +72,8 @@ Fixes
Misc Improvements Misc Improvements
----------------- -----------------
- Documented all default keybindings (from :file:`dfhack.init-example`) in the
docs for the relevant commands; updates enforced by build system.
- `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) - `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.)
- `remotefortressreader`: Added support for - `remotefortressreader`: Added support for

@ -15,15 +15,70 @@ serve to show the default.
# pylint:disable=redefined-builtin # pylint:disable=redefined-builtin
import fnmatch
from io import open from io import open
from itertools import starmap
import os import os
import re import re
import shlex # pylint:disable=unused-import import shlex # pylint:disable=unused-import
import sys import sys
# -- Support :dfhack-keybind:`command` ------------------------------------
# this is a custom directive that pulls info from dfhack.init-example
from docutils import nodes
from docutils.parsers.rst import roles
def get_keybinds():
"""Get the implemented keybinds, and return a dict of
{tool: [(full_command, keybinding, context), ...]}.
"""
with open('dfhack.init-example') as f:
lines = [l.replace('keybinding add', '').strip() for l in f.readlines()
if l.startswith('keybinding add')]
keybindings = dict()
for k in lines:
first, command = k.split(' ', maxsplit=1)
bind, context = (first.split('@') + [''])[:2]
if ' ' not in command:
command = command.replace('"', '')
tool = command.split(' ')[0].replace('"', '')
keybindings[tool] = keybindings.get(tool, []) + [
(command, bind.split('-'), context)]
return keybindings
KEYBINDS = get_keybinds()
# pylint:disable=unused-argument,dangerous-default-value,too-many-arguments
def dfhack_keybind_role_func(role, rawtext, text, lineno, inliner,
options={}, content=[]):
"""Custom role parser for DFHack default keybinds."""
roles.set_classes(options)
if text not in KEYBINDS:
msg = inliner.reporter.error(
'no keybinding for {} in dfhack.init-example'.format(text),
line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
newnode = nodes.paragraph()
for cmd, key, ctx in KEYBINDS[text]:
n = nodes.paragraph()
newnode += n
n += nodes.strong('Keybinding: ', 'Keybinding: ')
for k in key:
n += nodes.inline(k, k, classes=['kbd'])
if cmd != text:
n += nodes.inline(' -> ', ' -> ')
n += nodes.literal(cmd, cmd, classes=['guilabel'])
if ctx:
n += nodes.inline(' in ', ' in ')
n += nodes.literal(ctx, ctx)
return [newnode], []
roles.register_canonical_role('dfhack-keybind', dfhack_keybind_role_func)
# -- Autodoc for DFhack scripts ------------------------------------------- # -- Autodoc for DFhack scripts -------------------------------------------
def doc_dir(dirname, files): def doc_dir(dirname, files):
@ -46,28 +101,41 @@ def doc_dir(dirname, files):
command = line command = line
def doc_all_dirs():
"""Collect the commands and paths to include in our docs."""
scripts = []
for root, _, files in os.walk('scripts'):
scripts.extend(doc_dir(root, files))
return tuple(scripts)
DOC_ALL_DIRS = doc_all_dirs()
def document_scripts(): def document_scripts():
"""Autodoc for files with the magic script documentation marker strings. """Autodoc for files with the magic script documentation marker strings.
Returns a dict of script-kinds to lists of .rst include directives. Returns a dict of script-kinds to lists of .rst include directives.
""" """
# First, we collect the commands and paths to include in our docs
scripts = []
for root, _, files in os.walk('scripts'):
scripts.extend(doc_dir(root, files))
# Next we split by type and create include directives sorted by command # Next we split by type and create include directives sorted by command
kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []} kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []}
for s in scripts: for s in DOC_ALL_DIRS:
k_fname = s[0].split('/', 1) k_fname = s[0].split('/', 1)
if len(k_fname) == 1: if len(k_fname) == 1:
kinds['base'].append(s) kinds['base'].append(s)
else: else:
kinds[k_fname[0]].append(s) kinds[k_fname[0]].append(s)
template = '.. _{}:\n\n.. include:: /{}\n' +\
def template(arg):
tmp = '.. _{}:\n\n.. include:: /{}\n' +\
' :start-after: {}\n :end-before: {}\n' ' :start-after: {}\n :end-before: {}\n'
return {key: '\n\n'.join(starmap(template.format, sorted(value))) if arg[0] in KEYBINDS:
tmp += '\n:dfhack-keybind:`{}`\n'.format(arg[0])
return tmp.format(*arg)
return {key: '\n\n'.join(map(template, sorted(value)))
for key, value in kinds.items()} for key, value in kinds.items()}
def write_script_docs(): def write_script_docs():
""" """
Creates a file for eack kind of script (base/devel/fix/gui/modtools) Creates a file for eack kind of script (base/devel/fix/gui/modtools)
@ -97,10 +165,23 @@ def write_script_docs():
outfile.write(kinds[k]) outfile.write(kinds[k])
# Actually call the docs generator def all_keybinds_documented():
write_script_docs() """Check that all keybindings are documented with the :dfhack-keybind:
directive somewhere."""
configured_binds = set(KEYBINDS)
script_commands = set(i[0] for i in DOC_ALL_DIRS)
with open('./docs/Plugins.rst') as f:
plugin_binds = set(re.findall(':dfhack-keybind:`(.*?)`', f.read()))
undocumented_binds = configured_binds - script_commands - plugin_binds
if undocumented_binds:
raise ValueError('The following DFHack commands have undocumented'
'keybindings: {}'.format(sorted(undocumented_binds)))
# Actually call the docs generator and run test
write_script_docs()
all_keybinds_documented()
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.

@ -353,7 +353,8 @@ This plugin adds an option to the :kbd:`q` menu when `enabled <enable>`.
command-prompt command-prompt
============== ==============
An in-game DFHack terminal, where you can enter other commands. An in-game DFHack terminal, where you can enter other commands.
Best used from a keybinding; by default :kbd:`Ctrl`:kbd:`Shift`:kbd:`P`.
:dfhack-keybind:`command-prompt`
Usage: ``command-prompt [entry]`` Usage: ``command-prompt [entry]``
@ -372,13 +373,11 @@ Otherwise somewhat similar to `gui/quickcmd`.
hotkeys hotkeys
======= =======
Opens an in-game screen showing which DFHack keybindings are Opens an in-game screen showing which DFHack keybindings are
active in the current context. active in the current context. See also `hotkey-notes`.
.. image:: images/hotkeys.png .. image:: images/hotkeys.png
Type ``hotkeys`` into the DFHack console to open the screen, :dfhack-keybind:`hotkeys`
or bind the command to a globally active hotkey. The default
keybinding is :kbd:`Ctrl`:kbd:`F1`. See also `hotkey-notes`.
.. _rb: .. _rb:
@ -659,12 +658,16 @@ Unit order examples::
The orderings are defined in ``hack/lua/plugins/sort/*.lua`` The orderings are defined in ``hack/lua/plugins/sort/*.lua``
:dfhack-keybind:`sort-units`
.. _stocks: .. _stocks:
stocks stocks
====== ======
Replaces the DF stocks screen with an improved version. Replaces the DF stocks screen with an improved version.
:dfhack-keybind:`stocks`
.. _stocksettings: .. _stocksettings:
.. _stockpiles: .. _stockpiles:
@ -676,6 +679,7 @@ See `gui/stockpiles` for an in-game interface.
:copystock: Copies the parameters of the currently highlighted stockpile to the custom :copystock: Copies the parameters of the currently highlighted stockpile to the custom
stockpile settings and switches to custom stockpile placement mode, effectively stockpile settings and switches to custom stockpile placement mode, effectively
allowing you to copy/paste stockpiles easily. allowing you to copy/paste stockpiles easily.
:dfhack-keybind:`copystock`
:savestock: Saves the currently highlighted stockpile's settings to a file in your Dwarf :savestock: Saves the currently highlighted stockpile's settings to a file in your Dwarf
Fortress folder. This file can be used to copy settings between game saves or Fortress folder. This file can be used to copy settings between game saves or
@ -874,7 +878,7 @@ Invoked as::
job-material <inorganic-token> job-material <inorganic-token>
Intended to be used as a keybinding: :dfhack-keybind:`job-material`
* In :kbd:`q` mode, when a job is highlighted within a workshop or furnace, * In :kbd:`q` mode, when a job is highlighted within a workshop or furnace,
changes the material of the job. Only inorganic materials can be used changes the material of the job. Only inorganic materials can be used
@ -887,6 +891,8 @@ job-duplicate
In :kbd:`q` mode, when a job is highlighted within a workshop or furnace In :kbd:`q` mode, when a job is highlighted within a workshop or furnace
building, calling ``job-duplicate`` instantly duplicates the job. building, calling ``job-duplicate`` instantly duplicates the job.
:dfhack-keybind:`job-duplicate`
.. _autogems: .. _autogems:
autogems autogems
@ -1076,6 +1082,8 @@ spotclean
Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal
if you want to keep that bloody entrance ``clean map`` would clean up. if you want to keep that bloody entrance ``clean map`` would clean up.
:dfhack-keybind:`spotclean`
.. _autodump: .. _autodump:
autodump autodump
@ -1098,10 +1106,16 @@ Options:
:destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list, :destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list,
or inside a container. or inside a container.
Alias ``autodump-destroy-here``, for keybindings. Alias ``autodump-destroy-here``, for keybindings.
:dfhack-keybind:`autodump-destroy-here`
:visible: Only process items that are not hidden. :visible: Only process items that are not hidden.
:hidden: Only process hidden items. :hidden: Only process hidden items.
:forbidden: Only process forbidden items (default: only unforbidden). :forbidden: Only process forbidden items (default: only unforbidden).
``autodump-destroy-item`` destroys the selected item, which may be selected
in the :kbd:`k` list, or inside a container. If called again before the game
is resumed, cancels destruction of the item.
:dfhack-keybind:`autodump-destroy-item`
cleanowned cleanowned
========== ==========
@ -1139,6 +1153,8 @@ Options:
:prefs: Show dwarf preferences summary :prefs: Show dwarf preferences summary
:reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``) :reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``)
:dfhack-keybind:`dwarfmonitor`
Widget configuration: Widget configuration:
The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`) The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`)
@ -1264,6 +1280,8 @@ zone
==== ====
Helps a bit with managing activity zones (pens, pastures and pits) and cages. Helps a bit with managing activity zones (pens, pastures and pits) and cages.
:dfhack-keybind:`zone`
Options: Options:
:set: Set zone or cage under cursor as default for future assigns. :set: Set zone or cage under cursor as default for future assigns.
@ -1738,6 +1756,8 @@ Basic commands:
to remove designations, for if you accidentally set 50 levels at once. to remove designations, for if you accidentally set 50 levels at once.
:diglx: Also cross z-levels, digging stairs as needed. Alias for ``digl x``. :diglx: Also cross z-levels, digging stairs as needed. Alias for ``digl x``.
:dfhack-keybind:`digv`
.. _digexp: .. _digexp:
digexp digexp
@ -2209,6 +2229,8 @@ Usage:
* When viewing unit details, body-swaps into that unit. * When viewing unit details, body-swaps into that unit.
* In the main adventure mode screen, reverts transient swap. * In the main adventure mode screen, reverts transient swap.
:dfhack-keybind:`adv-bodyswap`
.. _createitem: .. _createitem:
createitem createitem