mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-11-10 13:04:03 +03:00
3c7df680cf
No need to update multiple places when bumping the go version.
570 lines
21 KiB
Python
570 lines
21 KiB
Python
#!/usr/bin/env python3
|
|
# vim:fileencoding=utf-8
|
|
#
|
|
# Configuration file for the Sphinx documentation builder.
|
|
#
|
|
# This file does only contain a selection of the most common options. For a
|
|
# full list see the documentation:
|
|
# https://www.sphinx-doc.org/en/master/config
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from functools import partial
|
|
from typing import Any, Callable, Dict, Iterable, List, Tuple
|
|
|
|
from docutils import nodes
|
|
from docutils.parsers.rst.roles import set_classes
|
|
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
|
from pygments.token import Comment, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
|
|
from sphinx import addnodes, version_info
|
|
from sphinx.util.logging import getLogger
|
|
|
|
kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
if kitty_src not in sys.path:
|
|
sys.path.insert(0, kitty_src)
|
|
|
|
from kitty.conf.types import Definition, expand_opt_references # noqa
|
|
from kitty.constants import str_version, website_url # noqa
|
|
|
|
# config {{{
|
|
# -- Project information -----------------------------------------------------
|
|
|
|
project = 'kitty'
|
|
copyright = time.strftime('%Y, Kovid Goyal')
|
|
author = 'Kovid Goyal'
|
|
building_man_pages = 'man' in sys.argv
|
|
|
|
# The short X.Y version
|
|
version = str_version
|
|
# The full version, including alpha/beta/rc tags
|
|
release = str_version
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
# -- General configuration ---------------------------------------------------
|
|
|
|
# If your documentation needs a minimal Sphinx version, state it here.
|
|
#
|
|
needs_sphinx = '1.7'
|
|
|
|
# Add any Sphinx extension module names here, as strings. They can be
|
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
# ones.
|
|
extensions = [
|
|
'sphinx.ext.ifconfig',
|
|
'sphinx.ext.viewcode',
|
|
'sphinx.ext.githubpages',
|
|
'sphinx.ext.extlinks',
|
|
'sphinx_copybutton',
|
|
'sphinx_inline_tabs',
|
|
"sphinxext.opengraph",
|
|
]
|
|
|
|
# URL for OpenGraph tags
|
|
ogp_site_url = website_url()
|
|
# OGP needs a PNG image because of: https://github.com/wpilibsuite/sphinxext-opengraph/issues/96
|
|
ogp_social_cards = {
|
|
'image': '../logo/kitty.png'
|
|
}
|
|
|
|
# Add any paths that contain templates here, relative to this directory.
|
|
templates_path = ['_templates']
|
|
|
|
# The suffix(es) of source filenames.
|
|
# You can specify multiple suffix as a list of string:
|
|
#
|
|
# source_suffix = ['.rst', '.md']
|
|
source_suffix = '.rst'
|
|
|
|
# The master toctree document.
|
|
master_doc = 'index'
|
|
|
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
# for a list of supported languages.
|
|
#
|
|
# This is also used if you do content translation via gettext catalogs.
|
|
# Usually you set "language" from the command line for these cases.
|
|
language: str = 'en'
|
|
|
|
# List of patterns, relative to source directory, that match files and
|
|
# directories to ignore when looking for source files.
|
|
# This pattern also affects html_static_path and html_extra_path .
|
|
exclude_patterns = [
|
|
'_build', 'Thumbs.db', '.DS_Store', 'basic.rst',
|
|
'generated/cli-*.rst', 'generated/conf-*.rst', 'generated/actions.rst'
|
|
]
|
|
|
|
rst_prolog = '''
|
|
.. |kitty| replace:: *kitty*
|
|
.. |version| replace:: VERSION
|
|
.. _tarball: https://github.com/kovidgoyal/kitty/releases/download/vVERSION/kitty-VERSION.tar.xz
|
|
.. role:: italic
|
|
|
|
'''.replace('VERSION', str_version)
|
|
smartquotes_action = 'qe' # educate quotes and ellipses but not dashes
|
|
|
|
def go_version(go_mod_path: str) -> str: # {{{
|
|
with open(go_mod_path) as f:
|
|
for line in f:
|
|
if line.startswith('go '):
|
|
return line.strip().split()[1]
|
|
raise SystemExit(f'No Go version in {go_mod_path}')
|
|
# }}}
|
|
|
|
string_replacements = {
|
|
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
|
|
'_build_go_version': go_version('../go.mod'),
|
|
}
|
|
|
|
|
|
# -- Options for HTML output -------------------------------------------------
|
|
|
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
# a list of builtin themes.
|
|
#
|
|
html_theme = 'furo'
|
|
html_title = 'kitty'
|
|
|
|
# Theme options are theme-specific and customize the look and feel of a theme
|
|
# further. For a list of options available for each theme, see the
|
|
# documentation.
|
|
github_icon_path = 'M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z' # noqa
|
|
|
|
html_theme_options: Dict[str, Any] = {
|
|
'sidebar_hide_name': True,
|
|
'navigation_with_keys': True,
|
|
'footer_icons': [
|
|
{
|
|
"name": "GitHub",
|
|
"url": "https://github.com/kovidgoyal/kitty",
|
|
"html": f"""
|
|
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
|
<path fill-rule="evenodd" d="{github_icon_path}"></path>
|
|
</svg>
|
|
""",
|
|
"class": "",
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
# Add any paths that contain custom static files (such as style sheets) here,
|
|
# relative to this directory. They are copied after the builtin static files,
|
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
html_static_path = ['_static']
|
|
html_favicon = html_logo = '../logo/kitty.svg'
|
|
html_css_files = ['custom.css']
|
|
html_js_files = ['custom.js']
|
|
|
|
# Custom sidebar templates, must be a dictionary that maps document names
|
|
# to template names.
|
|
#
|
|
# The default sidebars (for documents that don't match any pattern) are
|
|
# defined by theme itself. Builtin themes are using these templates by
|
|
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
|
# 'searchbox.html']``.
|
|
#
|
|
html_show_sourcelink = False
|
|
html_show_sphinx = False
|
|
manpages_url = 'https://man7.org/linux/man-pages/man{section}/{page}.{section}.html'
|
|
|
|
# -- Options for manual page output ------------------------------------------
|
|
|
|
# One entry per manual page. List of tuples
|
|
# (source start file, name, description, authors, manual section).
|
|
man_pages = [
|
|
('invocation', 'kitty', 'kitty Documentation', [author], 1),
|
|
('conf', 'kitty.conf', 'kitty.conf Documentation', [author], 5)
|
|
]
|
|
|
|
|
|
# -- Options for Texinfo output ----------------------------------------------
|
|
|
|
# Grouping the document tree into Texinfo files. List of tuples
|
|
# (source start file, target name, title, author,
|
|
# dir menu entry, description, category)
|
|
texinfo_documents = [
|
|
(master_doc, 'kitty', 'kitty Documentation',
|
|
author, 'kitty', 'Cross-platform, fast, feature-rich, GPU based terminal',
|
|
'Miscellaneous'),
|
|
]
|
|
# }}}
|
|
|
|
|
|
# GitHub linking inline roles {{{
|
|
|
|
extlinks = {
|
|
'iss': ('https://github.com/kovidgoyal/kitty/issues/%s', '#%s'),
|
|
'pull': ('https://github.com/kovidgoyal/kitty/pull/%s', '#%s'),
|
|
'disc': ('https://github.com/kovidgoyal/kitty/discussions/%s', '#%s'),
|
|
}
|
|
|
|
|
|
def commit_role(
|
|
name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []
|
|
) -> Tuple[List[nodes.reference], List[nodes.problematic]]:
|
|
' Link to a github commit '
|
|
try:
|
|
commit_id = subprocess.check_output(
|
|
f'git rev-list --max-count=1 --skip=# {text}'.split()).decode('utf-8').strip()
|
|
except Exception:
|
|
msg = inliner.reporter.error(
|
|
f'GitHub commit id "{text}" not recognized.', line=lineno)
|
|
prb = inliner.problematic(rawtext, rawtext, msg)
|
|
return [prb], [msg]
|
|
url = f'https://github.com/kovidgoyal/kitty/commit/{commit_id}'
|
|
set_classes(options)
|
|
short_id = subprocess.check_output(
|
|
f'git rev-list --max-count=1 --abbrev-commit --skip=# {commit_id}'.split()).decode('utf-8').strip()
|
|
node = nodes.reference(rawtext, f'commit: {short_id}', refuri=url, **options)
|
|
return [node], []
|
|
# }}}
|
|
|
|
|
|
# CLI docs {{{
|
|
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
|
from kittens.ssh.copy import option_text
|
|
from kittens.ssh.options.definition import copy_message
|
|
from kitty.cli import option_spec_as_rst
|
|
from kitty.launch import options_spec as launch_options_spec
|
|
with open('generated/ssh-copy.rst', 'w') as f:
|
|
f.write(option_spec_as_rst(
|
|
appname='copy', ospec=option_text, heading_char='^',
|
|
usage='file-or-dir-to-copy ...', message=copy_message
|
|
))
|
|
with open('generated/launch.rst', 'w') as f:
|
|
f.write(option_spec_as_rst(
|
|
appname='launch', ospec=launch_options_spec, heading_char='_',
|
|
message='''\
|
|
Launch an arbitrary program in a new kitty window/tab. Note that
|
|
if you specify a program-to-run you can use the special placeholder
|
|
:code:`@selection` which will be replaced by the current selection.
|
|
'''
|
|
))
|
|
with open('generated/cli-kitty.rst', 'w') as f:
|
|
f.write(option_spec_as_rst(appname='kitty').replace(
|
|
'kitty --to', 'kitty @ --to'))
|
|
as_rst = partial(option_spec_as_rst, heading_char='_')
|
|
from kitty.rc.base import all_command_names, command_for_name
|
|
from kitty.remote_control import cli_msg, global_options_spec
|
|
with open('generated/cli-kitty-at.rst', 'w') as f:
|
|
p = partial(print, file=f)
|
|
p('kitty @')
|
|
p('-' * 80)
|
|
p('.. program::', 'kitty @')
|
|
p('\n\n' + as_rst(
|
|
global_options_spec, message=cli_msg, usage='command ...', appname='kitty @'))
|
|
from kitty.rc.base import cli_params_for
|
|
for cmd_name in sorted(all_command_names()):
|
|
func = command_for_name(cmd_name)
|
|
p(f'.. _at-{func.name}:\n')
|
|
p('kitty @', func.name)
|
|
p('-' * 120)
|
|
p('.. program::', 'kitty @', func.name)
|
|
p('\n\n' + as_rst(*cli_params_for(func)))
|
|
from kittens.runner import get_kitten_cli_docs
|
|
from kitty.fast_data_types import wrapped_kitten_names
|
|
|
|
for kitten in all_kitten_names:
|
|
data = get_kitten_cli_docs(kitten)
|
|
if data:
|
|
with open(f'generated/cli-kitten-{kitten}.rst', 'w') as f:
|
|
p = partial(print, file=f)
|
|
p('.. program::', 'kitty +kitten', kitten)
|
|
p('\nSource code for', kitten)
|
|
p('-' * 72)
|
|
if kitten in wrapped_kitten_names():
|
|
scurl = f'https://github.com/kovidgoyal/kitty/tree/master/tools/cmd/{kitten}'
|
|
else:
|
|
scurl = f'https://github.com/kovidgoyal/kitty/tree/master/kittens/{kitten}'
|
|
p(f'\nThe source code for this kitten is `available on GitHub <{scurl}>`_.')
|
|
p('\nCommand Line Interface')
|
|
p('-' * 72)
|
|
p('\n\n' + option_spec_as_rst(
|
|
data['options'], message=data['help_text'], usage=data['usage'], appname=f'kitty +kitten {kitten}',
|
|
heading_char='^'))
|
|
|
|
# }}}
|
|
|
|
|
|
def write_remote_control_protocol_docs() -> None: # {{{
|
|
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
|
|
field_pat = re.compile(r'\s*([^:]+?)\s*:\s*(.+)')
|
|
|
|
def format_cmd(p: Callable[..., None], name: str, cmd: RemoteCommand) -> None:
|
|
p(name)
|
|
p('-' * 80)
|
|
lines = (cmd.__doc__ or '').strip().splitlines()
|
|
fields = []
|
|
for line in lines:
|
|
m = field_pat.match(line)
|
|
if m is None:
|
|
p(line)
|
|
else:
|
|
fields.append((m.group(1).split('/')[0], m.group(2)))
|
|
if fields:
|
|
p('\nFields are:\n')
|
|
for (name, desc) in fields:
|
|
if '+' in name:
|
|
title = name.replace('+', ' (required)')
|
|
else:
|
|
title = name
|
|
defval = cmd.get_default(name.replace('-', '_'), cmd)
|
|
if defval is not cmd:
|
|
title = f'{title} (default: {defval})'
|
|
else:
|
|
title = f'{title} (optional)'
|
|
p(f':code:`{title}`')
|
|
p(' ', desc), p()
|
|
p(), p()
|
|
|
|
with open('generated/rc.rst', 'w') as f:
|
|
p = partial(print, file=f)
|
|
for name in sorted(all_command_names()):
|
|
cmd = command_for_name(name)
|
|
if not cmd.__doc__:
|
|
continue
|
|
name = name.replace('_', '-')
|
|
format_cmd(p, name, cmd)
|
|
# }}}
|
|
|
|
|
|
def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
|
|
src = source[0]
|
|
for k, v in app.config.string_replacements.items():
|
|
src = src.replace(k, v)
|
|
source[0] = src
|
|
# }}}
|
|
|
|
# config file docs {{{
|
|
|
|
|
|
class ConfLexer(RegexLexer): # type: ignore
|
|
name = 'Conf'
|
|
aliases = ['conf']
|
|
filenames = ['*.conf']
|
|
|
|
tokens = {
|
|
'root': [
|
|
(r'#.*?$', Comment.Single),
|
|
(r'\s+$', Whitespace),
|
|
(r'\s+', Whitespace),
|
|
(r'(include)(\s+)(.+?)$', bygroups(Comment.Preproc, Whitespace, Name.Namespace)),
|
|
(r'(map)(\s+)(\S+)(\s+)', bygroups(
|
|
Keyword.Declaration, Whitespace, String, Whitespace), 'action'),
|
|
(r'(mouse_map)(\s+)(\S+)(\s+)(\S+)(\s+)(\S+)(\s+)', bygroups(
|
|
Keyword.Declaration, Whitespace, String, Whitespace, Name.Variable, Whitespace, String, Whitespace), 'action'),
|
|
(r'(symbol_map)(\s+)(\S+)(\s+)(.+?)$', bygroups(
|
|
Keyword.Declaration, Whitespace, String, Whitespace, Literal)),
|
|
(r'([a-zA-Z_0-9]+)(\s+)', bygroups(
|
|
Name.Variable, Whitespace), 'args'),
|
|
],
|
|
'action': [
|
|
(r'[a-z_0-9]+$', Name.Function, 'root'),
|
|
(r'[a-z_0-9]+', Name.Function, 'args'),
|
|
],
|
|
'args': [
|
|
(r'\s+', Whitespace, 'args'),
|
|
(r'\b(yes|no)\b$', Number.Bin, 'root'),
|
|
(r'\b(yes|no)\b', Number.Bin, 'args'),
|
|
(r'[+-]?[0-9]+\s*$', Number.Integer, 'root'),
|
|
(r'[+-]?[0-9.]+\s*$', Number.Float, 'root'),
|
|
(r'[+-]?[0-9]+', Number.Integer, 'args'),
|
|
(r'[+-]?[0-9.]+', Number.Float, 'args'),
|
|
(r'#[a-fA-F0-9]{3,6}\s*$', String, 'root'),
|
|
(r'#[a-fA-F0-9]{3,6}\s*', String, 'args'),
|
|
(r'.+', String, 'root'),
|
|
],
|
|
}
|
|
|
|
|
|
class SessionLexer(RegexLexer): # type: ignore
|
|
name = 'Session'
|
|
aliases = ['session']
|
|
filenames = ['*.session']
|
|
|
|
tokens = {
|
|
'root': [
|
|
(r'#.*?$', Comment.Single),
|
|
(r'[a-z][a-z0-9_]+', Name.Function, 'args'),
|
|
],
|
|
'args': [
|
|
(r'.*?$', Literal, 'root'),
|
|
]
|
|
}
|
|
|
|
|
|
def link_role(
|
|
name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []
|
|
) -> Tuple[List[nodes.reference], List[nodes.problematic]]:
|
|
text = text.replace('\n', ' ')
|
|
m = re.match(r'(.+)\s+<(.+?)>', text)
|
|
if m is None:
|
|
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
|
prb = inliner.problematic(rawtext, rawtext, msg)
|
|
return [prb], [msg]
|
|
text, url = m.group(1, 2)
|
|
url = url.replace(' ', '')
|
|
set_classes(options)
|
|
node = nodes.reference(rawtext, text, refuri=url, **options)
|
|
return [node], []
|
|
|
|
|
|
opt_aliases: Dict[str, str] = {}
|
|
shortcut_slugs: Dict[str, Tuple[str, str]] = {}
|
|
|
|
|
|
def parse_opt_node(env: Any, sig: str, signode: Any) -> str:
|
|
"""Transform an option description into RST nodes."""
|
|
count = 0
|
|
firstname = ''
|
|
for potential_option in sig.split(', '):
|
|
optname = potential_option.strip()
|
|
if count:
|
|
signode += addnodes.desc_addname(', ', ', ')
|
|
text = optname.split('.', 1)[-1]
|
|
signode += addnodes.desc_name(text, text)
|
|
if not count:
|
|
firstname = optname
|
|
signode['allnames'] = [optname]
|
|
else:
|
|
signode['allnames'].append(optname)
|
|
opt_aliases[optname] = firstname
|
|
count += 1
|
|
if not firstname:
|
|
raise ValueError(f'{sig} is not a valid opt')
|
|
return firstname
|
|
|
|
|
|
def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
|
|
"""Transform a shortcut description into RST nodes."""
|
|
conf_name, text = sig.split('.', 1)
|
|
signode += addnodes.desc_name(text, text)
|
|
return sig
|
|
|
|
|
|
def parse_action_node(env: Any, sig: str, signode: Any) -> str:
|
|
"""Transform an action description into RST nodes."""
|
|
signode += addnodes.desc_name(sig, sig)
|
|
return sig
|
|
|
|
|
|
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
|
conf_name, opt = target.partition('.')[::2]
|
|
if not opt:
|
|
conf_name, opt = 'kitty', conf_name
|
|
full_name = f'{conf_name}.{opt}'
|
|
return title, opt_aliases.get(full_name, full_name)
|
|
|
|
|
|
def process_action_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
|
return title, target
|
|
|
|
|
|
def process_shortcut_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
|
conf_name, slug = target.partition('.')[::2]
|
|
if not slug:
|
|
conf_name, slug = 'kitty', conf_name
|
|
full_name = f'{conf_name}.{slug}'
|
|
try:
|
|
target, stitle = shortcut_slugs[full_name]
|
|
except KeyError:
|
|
logger.warning(f'Unknown shortcut: {target}', location=refnode)
|
|
else:
|
|
if not has_explicit_title:
|
|
title = stitle
|
|
return title, target
|
|
|
|
|
|
def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
|
app.add_lexer('conf', ConfLexer() if version_info[0] < 3 else ConfLexer)
|
|
app.add_object_type(
|
|
'opt', 'opt',
|
|
indextemplate="pair: %s; Config Setting",
|
|
parse_node=parse_opt_node,
|
|
)
|
|
# Warn about opt references that could not be resolved
|
|
opt_role = app.registry.domain_roles['std']['opt']
|
|
opt_role.warn_dangling = True
|
|
opt_role.process_link = process_opt_link
|
|
|
|
app.add_object_type(
|
|
'shortcut', 'sc',
|
|
indextemplate="pair: %s; Keyboard Shortcut",
|
|
parse_node=parse_shortcut_node,
|
|
)
|
|
sc_role = app.registry.domain_roles['std']['sc']
|
|
sc_role.warn_dangling = True
|
|
sc_role.process_link = process_shortcut_link
|
|
shortcut_slugs.clear()
|
|
|
|
app.add_object_type(
|
|
'action', 'ac',
|
|
indextemplate="pair: %s; Action",
|
|
parse_node=parse_action_node,
|
|
)
|
|
ac_role = app.registry.domain_roles['std']['ac']
|
|
ac_role.warn_dangling = True
|
|
ac_role.process_link = process_action_link
|
|
|
|
def generate_default_config(definition: Definition, name: str) -> None:
|
|
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
|
print('.. highlight:: conf\n', file=f)
|
|
f.write('\n'.join(definition.as_rst(name, shortcut_slugs)))
|
|
|
|
conf_name = re.sub(r'^kitten-', '', name) + '.conf'
|
|
with open(f'generated/conf/{conf_name}', 'w', encoding='utf-8') as f:
|
|
text = '\n'.join(definition.as_conf(commented=True))
|
|
print(text, file=f)
|
|
|
|
from kitty.options.definition import definition
|
|
generate_default_config(definition, 'kitty')
|
|
|
|
from kittens.runner import get_kitten_conf_docs
|
|
for kitten in all_kitten_names:
|
|
definition = get_kitten_conf_docs(kitten)
|
|
if definition:
|
|
generate_default_config(definition, f'kitten-{kitten}')
|
|
|
|
from kitty.actions import as_rst
|
|
with open('generated/actions.rst', 'w', encoding='utf-8') as f:
|
|
f.write(as_rst())
|
|
# }}}
|
|
|
|
|
|
def add_html_context(app: Any, pagename: str, templatename: str, context: Any, doctree: Any, *args: Any) -> None:
|
|
context['analytics_id'] = app.config.analytics_id
|
|
if 'toctree' in context:
|
|
# this is needed with furo to use all titles from pages
|
|
# in the sidebar (global) toc
|
|
original_toctee_function = context['toctree']
|
|
|
|
def include_sub_headings(**kwargs: Any) -> Any:
|
|
kwargs['titles_only'] = False
|
|
return original_toctee_function(**kwargs)
|
|
|
|
context['toctree'] = include_sub_headings
|
|
|
|
|
|
def setup(app: Any) -> None:
|
|
os.makedirs('generated/conf', exist_ok=True)
|
|
from kittens.runner import all_kitten_names
|
|
kn = all_kitten_names()
|
|
write_cli_docs(kn)
|
|
write_remote_control_protocol_docs()
|
|
write_conf_docs(app, kn)
|
|
app.add_config_value('string_replacements', {}, True)
|
|
app.connect('source-read', replace_string)
|
|
app.add_config_value('analytics_id', '', 'env')
|
|
app.connect('html-page-context', add_html_context)
|
|
app.add_lexer('session', SessionLexer() if version_info[0] < 3 else SessionLexer)
|
|
app.add_role('link', link_role)
|
|
app.add_role('commit', commit_role)
|
|
# monkey patch sphinx_inline_tabs to avoid a warning about parallel reads
|
|
# see https://github.com/pradyunsg/sphinx-inline-tabs/issues/26
|
|
inline_tabs = app.extensions['sphinx_inline_tabs']
|
|
inline_tabs.parallel_read_safe = inline_tabs.parallel_write_safe = True
|