Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
45 changes: 38 additions & 7 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 @@ -1226,7 +1242,16 @@ Options:

workNow
=======
Force all dwarves to look for a job immediately, or as soon as the game is unpaused.
Don't allow dwarves to idle if any jobs are available.

When workNow is active, every time the game pauses, DF will make dwarves
perform any appropriate available jobs. This includes when you one step
through the game using the pause menu. Usage:

:workNow: print workNow status
:workNow 0: deactivate workNow
:workNow 1: activate workNow (look for jobs on pause, and only then)
:workNow 2: make dwarves look for jobs whenever a job completes

.. _seedwatch:

Expand Down Expand Up @@ -1264,6 +1289,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 +1765,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 +2238,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