|
3 | 3 | # https://www.sphinx-doc.org/en/master/development/tutorials/recipe.html |
4 | 4 | # https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#rst-directives |
5 | 5 |
|
| 6 | +import os |
6 | 7 | from typing import List |
7 | 8 |
|
8 | 9 | import docutils.nodes as nodes |
|
13 | 14 |
|
14 | 15 | import dfhack.util |
15 | 16 |
|
| 17 | + |
| 18 | +_KEYBINDS = {} |
| 19 | + |
| 20 | +def scan_keybinds(root, files, keybindings): |
| 21 | + """Add keybindings in the specified files to the |
| 22 | + given keybindings dict. |
| 23 | + """ |
| 24 | + for file in files: |
| 25 | + with open(os.path.join(root, file)) as f: |
| 26 | + lines = [l.replace('keybinding add', '').strip() for l in f.readlines() |
| 27 | + if l.startswith('keybinding add')] |
| 28 | + for k in lines: |
| 29 | + first, command = k.split(' ', 1) |
| 30 | + bind, context = (first.split('@') + [''])[:2] |
| 31 | + if ' ' not in command: |
| 32 | + command = command.replace('"', '') |
| 33 | + tool = command.split(' ')[0].replace('"', '') |
| 34 | + keybindings[tool] = keybindings.get(tool, []) + [ |
| 35 | + (command, bind.split('-'), context)] |
| 36 | + |
| 37 | +def scan_all_keybinds(root_dir): |
| 38 | + """Get the implemented keybinds, and return a dict of |
| 39 | + {tool: [(full_command, keybinding, context), ...]}. |
| 40 | + """ |
| 41 | + keybindings = dict() |
| 42 | + for root, _, files in os.walk(root_dir): |
| 43 | + scan_keybinds(root, files, keybindings) |
| 44 | + return keybindings |
| 45 | + |
| 46 | + |
| 47 | +def render_dfhack_keybind(command) -> List[nodes.paragraph]: |
| 48 | + if command not in _KEYBINDS: |
| 49 | + return [] |
| 50 | + newnode = nodes.paragraph() |
| 51 | + for keycmd, key, ctx in _KEYBINDS[command]: |
| 52 | + n = nodes.paragraph() |
| 53 | + newnode += n |
| 54 | + n += nodes.strong('Keybinding:', 'Keybinding:') |
| 55 | + n += nodes.inline(' ', ' ') |
| 56 | + for k in key: |
| 57 | + n += nodes.inline(k, k, classes=['kbd']) |
| 58 | + if keycmd != command: |
| 59 | + n += nodes.inline(' -> ', ' -> ') |
| 60 | + n += nodes.literal(keycmd, keycmd, classes=['guilabel']) |
| 61 | + if ctx: |
| 62 | + n += nodes.inline(' in ', ' in ') |
| 63 | + n += nodes.literal(ctx, ctx) |
| 64 | + return [newnode] |
| 65 | + |
| 66 | + |
| 67 | +# pylint:disable=unused-argument,dangerous-default-value,too-many-arguments |
| 68 | +def dfhack_keybind_role(role, rawtext, text, lineno, inliner, |
| 69 | + options={}, content=[]): |
| 70 | + """Custom role parser for DFHack default keybinds.""" |
| 71 | + return render_dfhack_keybind(text), [] |
| 72 | + |
| 73 | + |
16 | 74 | class DFHackToolDirectiveBase(sphinx.directives.ObjectDescription): |
17 | 75 | has_content = False |
18 | 76 | required_arguments = 0 |
@@ -77,14 +135,20 @@ def run(self): |
77 | 135 |
|
78 | 136 | class DFHackCommandDirective(DFHackToolDirectiveBase): |
79 | 137 | def render_content(self) -> List[nodes.Node]: |
| 138 | + command = self.get_name_or_docname() |
80 | 139 | return [ |
81 | | - self.make_labeled_paragraph('Command', self.get_name_or_docname(), content_class=nodes.literal), |
| 140 | + self.make_labeled_paragraph('Command', command, content_class=nodes.literal), |
| 141 | + *render_dfhack_keybind(command), |
82 | 142 | ] |
83 | 143 |
|
84 | 144 |
|
85 | 145 | def register(app): |
86 | 146 | app.add_directive('dfhack-tool', DFHackToolDirective) |
87 | 147 | app.add_directive('dfhack-command', DFHackCommandDirective) |
| 148 | + app.add_role('dfhack-keybind', dfhack_keybind_role) |
| 149 | + |
| 150 | + _KEYBINDS.update(scan_all_keybinds(os.path.join(dfhack.util.DFHACK_ROOT, 'data', 'init'))) |
| 151 | + |
88 | 152 |
|
89 | 153 | def setup(app): |
90 | 154 | app.connect('builder-inited', register) |
|
0 commit comments