Skip to content

Commit

Permalink
Add, use, and require auto docs for all keybindings
Browse files Browse the repository at this point in the history
  • Loading branch information
PeridexisErrant committed Oct 20, 2016
1 parent e3ff89b commit 951d293
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 18 deletions.
2 changes: 2 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ Fixes

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.)
- `remotefortressreader`: Added support for

Expand Down
105 changes: 93 additions & 12 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,70 @@

# pylint:disable=redefined-builtin

import fnmatch
from io import open
from itertools import starmap
import os
import re
import shlex # pylint:disable=unused-import
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 -------------------------------------------

def doc_dir(dirname, files):
Expand All @@ -46,28 +101,41 @@ def doc_dir(dirname, files):
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():
"""Autodoc for files with the magic script documentation marker strings.
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
kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []}
for s in scripts:
for s in DOC_ALL_DIRS:
k_fname = s[0].split('/', 1)
if len(k_fname) == 1:
kinds['base'].append(s)
else:
kinds[k_fname[0]].append(s)
template = '.. _{}:\n\n.. include:: /{}\n' +\
' :start-after: {}\n :end-before: {}\n'
return {key: '\n\n'.join(starmap(template.format, sorted(value)))

def template(arg):
tmp = '.. _{}:\n\n.. include:: /{}\n' +\
' :start-after: {}\n :end-before: {}\n'
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()}


def write_script_docs():
"""
Creates a file for eack kind of script (base/devel/fix/gui/modtools)
Expand Down Expand Up @@ -97,10 +165,23 @@ def write_script_docs():
outfile.write(kinds[k])


# Actually call the docs generator
write_script_docs()
def all_keybinds_documented():
"""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 ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
Expand Down
34 changes: 28 additions & 6 deletions docs/Plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ This plugin adds an option to the :kbd:`q` menu when `enabled <enable>`.
command-prompt
==============
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]``

Expand All @@ -372,13 +373,11 @@ Otherwise somewhat similar to `gui/quickcmd`.
hotkeys
=======
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

Type ``hotkeys`` into the DFHack console to open the screen,
or bind the command to a globally active hotkey. The default
keybinding is :kbd:`Ctrl`:kbd:`F1`. See also `hotkey-notes`.
:dfhack-keybind:`hotkeys`

.. _rb:

Expand Down Expand Up @@ -659,12 +658,16 @@ Unit order examples::

The orderings are defined in ``hack/lua/plugins/sort/*.lua``

:dfhack-keybind:`sort-units`

.. _stocks:

stocks
======
Replaces the DF stocks screen with an improved version.

:dfhack-keybind:`stocks`

.. _stocksettings:
.. _stockpiles:

Expand All @@ -676,6 +679,7 @@ See `gui/stockpiles` for an in-game interface.
:copystock: Copies the parameters of the currently highlighted stockpile to the custom
stockpile settings and switches to custom stockpile placement mode, effectively
allowing you to copy/paste stockpiles easily.
:dfhack-keybind:`copystock`

: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
Expand Down Expand Up @@ -874,7 +878,7 @@ Invoked as::

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,
changes the material of the job. Only inorganic materials can be used
Expand All @@ -887,6 +891,8 @@ job-duplicate
In :kbd:`q` mode, when a job is highlighted within a workshop or furnace
building, calling ``job-duplicate`` instantly duplicates the job.

:dfhack-keybind:`job-duplicate`

.. _autogems:

autogems
Expand Down Expand Up @@ -1076,6 +1082,8 @@ spotclean
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.

:dfhack-keybind:`spotclean`

.. _autodump:

autodump
Expand All @@ -1098,10 +1106,16 @@ Options:
:destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list,
or inside a container.
Alias ``autodump-destroy-here``, for keybindings.
:dfhack-keybind:`autodump-destroy-here`
:visible: Only process items that are not hidden.
:hidden: Only process hidden items.
: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
==========
Expand Down Expand Up @@ -1139,6 +1153,8 @@ Options:
:prefs: Show dwarf preferences summary
:reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``)

:dfhack-keybind:`dwarfmonitor`

Widget configuration:

The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`)
Expand Down Expand Up @@ -1264,6 +1280,8 @@ zone
====
Helps a bit with managing activity zones (pens, pastures and pits) and cages.

:dfhack-keybind:`zone`

Options:

:set: Set zone or cage under cursor as default for future assigns.
Expand Down Expand Up @@ -1738,6 +1756,8 @@ Basic commands:
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``.

:dfhack-keybind:`digv`

.. _digexp:

digexp
Expand Down Expand Up @@ -2209,6 +2229,8 @@ Usage:
* When viewing unit details, body-swaps into that unit.
* In the main adventure mode screen, reverts transient swap.

:dfhack-keybind:`adv-bodyswap`

.. _createitem:

createitem
Expand Down

0 comments on commit 951d293

Please sign in to comment.