Start work on porting docs generation
This commit is contained in:
parent
3e598a17cf
commit
46b3f71b8f
109
docs/conf.py
109
docs/conf.py
@ -32,10 +32,9 @@ kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
if kitty_src not in sys.path:
|
if kitty_src not in sys.path:
|
||||||
sys.path.insert(0, kitty_src)
|
sys.path.insert(0, kitty_src)
|
||||||
|
|
||||||
from kitty.conf.definition import Option, Shortcut, OptionOrAction, MouseAction # noqa
|
from kitty.conf.types import Definition # noqa
|
||||||
from kitty.constants import str_version # noqa
|
from kitty.constants import str_version # noqa
|
||||||
|
|
||||||
|
|
||||||
# config {{{
|
# config {{{
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
@ -248,8 +247,8 @@ def add_html_context(app: Any, pagename: str, templatename: str, context: Any, *
|
|||||||
|
|
||||||
# CLI docs {{{
|
# CLI docs {{{
|
||||||
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||||
from kitty.launch import options_spec as launch_options_spec
|
|
||||||
from kitty.cli import option_spec_as_rst
|
from kitty.cli import option_spec_as_rst
|
||||||
|
from kitty.launch import options_spec as launch_options_spec
|
||||||
with open('generated/launch.rst', 'w') as f:
|
with open('generated/launch.rst', 'w') as f:
|
||||||
f.write(option_spec_as_rst(
|
f.write(option_spec_as_rst(
|
||||||
appname='launch', ospec=launch_options_spec, heading_char='_',
|
appname='launch', ospec=launch_options_spec, heading_char='_',
|
||||||
@ -264,7 +263,7 @@ if you specify a program-to-run you can use the special placeholder
|
|||||||
'kitty --to', 'kitty @ --to'))
|
'kitty --to', 'kitty @ --to'))
|
||||||
as_rst = partial(option_spec_as_rst, heading_char='_')
|
as_rst = partial(option_spec_as_rst, heading_char='_')
|
||||||
from kitty.rc.base import all_command_names, command_for_name
|
from kitty.rc.base import all_command_names, command_for_name
|
||||||
from kitty.remote_control import global_options_spec, cli_msg
|
from kitty.remote_control import cli_msg, global_options_spec
|
||||||
with open('generated/cli-kitty-at.rst', 'w') as f:
|
with open('generated/cli-kitty-at.rst', 'w') as f:
|
||||||
p = partial(print, file=f)
|
p = partial(print, file=f)
|
||||||
p('kitty @\n' + '-' * 80)
|
p('kitty @\n' + '-' * 80)
|
||||||
@ -293,7 +292,9 @@ if you specify a program-to-run you can use the special placeholder
|
|||||||
|
|
||||||
|
|
||||||
def write_remote_control_protocol_docs() -> None: # {{{
|
def write_remote_control_protocol_docs() -> None: # {{{
|
||||||
from kitty.rc.base import all_command_names, command_for_name, RemoteCommand
|
from kitty.rc.base import (
|
||||||
|
RemoteCommand, all_command_names, command_for_name
|
||||||
|
)
|
||||||
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
||||||
|
|
||||||
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
|
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
|
||||||
@ -447,87 +448,6 @@ def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
|
|||||||
return sig
|
return sig
|
||||||
|
|
||||||
|
|
||||||
def render_conf(conf_name: str, all_options: Iterable[OptionOrAction]) -> str:
|
|
||||||
from kitty.conf.definition import merged_opts, Group
|
|
||||||
ans = ['.. default-domain:: conf', '']
|
|
||||||
a = ans.append
|
|
||||||
current_group: Optional[Group] = None
|
|
||||||
all_options_ = list(all_options)
|
|
||||||
kitty_mod = 'kitty_mod'
|
|
||||||
|
|
||||||
def render_group(group: Group) -> None:
|
|
||||||
a('')
|
|
||||||
a(f'.. _conf-{conf_name}-{group.name}:')
|
|
||||||
a('')
|
|
||||||
a(group.short_text)
|
|
||||||
heading_level = '+' if '.' in group.name else '^'
|
|
||||||
a(heading_level * (len(group.short_text) + 20))
|
|
||||||
a('')
|
|
||||||
if group.start_text:
|
|
||||||
a(group.start_text)
|
|
||||||
a('')
|
|
||||||
|
|
||||||
def handle_group_end(group: Group) -> None:
|
|
||||||
if group.end_text:
|
|
||||||
assert current_group is not None
|
|
||||||
a(''), a(current_group.end_text)
|
|
||||||
|
|
||||||
def handle_group(new_group: Group, new_group_is_shortcut: bool = False) -> None:
|
|
||||||
nonlocal current_group
|
|
||||||
if new_group is not current_group:
|
|
||||||
if current_group:
|
|
||||||
handle_group_end(current_group)
|
|
||||||
current_group = new_group
|
|
||||||
render_group(current_group)
|
|
||||||
|
|
||||||
def handle_option(i: int, opt: Option) -> None:
|
|
||||||
nonlocal kitty_mod
|
|
||||||
if not opt.long_text or not opt.add_to_docs:
|
|
||||||
return
|
|
||||||
handle_group(opt.group)
|
|
||||||
if opt.name == 'kitty_mod':
|
|
||||||
kitty_mod = opt.defval_as_string
|
|
||||||
mopts = list(merged_opts(all_options_, opt, i))
|
|
||||||
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
|
||||||
a('.. code-block:: conf')
|
|
||||||
a('')
|
|
||||||
sz = max(len(x.name) for x in mopts)
|
|
||||||
for mo in mopts:
|
|
||||||
a((' {:%ds} {}' % sz).format(mo.name, mo.defval_as_string))
|
|
||||||
a('')
|
|
||||||
if opt.long_text:
|
|
||||||
a(expand_opt_references(conf_name, opt.long_text))
|
|
||||||
a('')
|
|
||||||
|
|
||||||
def handle_shortcuts(shortcuts: Sequence[Union[Shortcut, MouseAction]]) -> None:
|
|
||||||
sc = shortcuts[0]
|
|
||||||
handle_group(sc.group, True)
|
|
||||||
sc_text = f'{conf_name}.{sc.short_text}'
|
|
||||||
a('.. shortcut:: ' + sc_text)
|
|
||||||
shortcuts = [s for s in shortcuts if s.add_to_default]
|
|
||||||
shortcut_slugs[f'{conf_name}.{sc.name}'] = (sc_text, sc.key.replace('kitty_mod', kitty_mod))
|
|
||||||
if shortcuts:
|
|
||||||
a('.. code-block:: conf')
|
|
||||||
a('')
|
|
||||||
for x in shortcuts:
|
|
||||||
if x.add_to_default:
|
|
||||||
a(' ' + x.line.replace('kitty_mod', kitty_mod))
|
|
||||||
a('')
|
|
||||||
if sc.long_text:
|
|
||||||
a(expand_opt_references(conf_name, sc.long_text))
|
|
||||||
a('')
|
|
||||||
|
|
||||||
for i, opt in enumerate(all_options_):
|
|
||||||
if isinstance(opt, Option):
|
|
||||||
handle_option(i, opt)
|
|
||||||
else:
|
|
||||||
handle_shortcuts(opt)
|
|
||||||
|
|
||||||
if current_group:
|
|
||||||
handle_group_end(current_group)
|
|
||||||
return '\n'.join(ans)
|
|
||||||
|
|
||||||
|
|
||||||
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
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]
|
conf_name, opt = target.partition('.')[::2]
|
||||||
if not opt:
|
if not opt:
|
||||||
@ -572,25 +492,24 @@ def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
|||||||
sc_role.warn_dangling = True
|
sc_role.warn_dangling = True
|
||||||
sc_role.process_link = process_shortcut_link
|
sc_role.process_link = process_shortcut_link
|
||||||
|
|
||||||
def generate_default_config(all_options: Dict[str, OptionOrAction], name: str) -> None:
|
def generate_default_config(definition: Definition, name: str) -> None:
|
||||||
from kitty.conf.definition import as_conf_file
|
|
||||||
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
||||||
print('.. highlight:: conf\n', file=f)
|
print('.. highlight:: conf\n', file=f)
|
||||||
f.write(render_conf(name, all_options.values()))
|
f.write('\n'.join(definition.as_rst(name, shortcut_slugs)))
|
||||||
|
|
||||||
conf_name = re.sub(r'^kitten-', '', name) + '.conf'
|
conf_name = re.sub(r'^kitten-', '', name) + '.conf'
|
||||||
with open(f'generated/conf/{conf_name}', 'w', encoding='utf-8') as f:
|
with open(f'generated/conf/{conf_name}', 'w', encoding='utf-8') as f:
|
||||||
text = '\n'.join(as_conf_file(all_options.values()))
|
text = '\n'.join(definition.as_conf())
|
||||||
print(text, file=f)
|
print(text, file=f)
|
||||||
|
|
||||||
from kitty.config_data import all_options
|
from kitty.options.definition import definition
|
||||||
generate_default_config(all_options, 'kitty')
|
generate_default_config(definition, 'kitty')
|
||||||
|
|
||||||
from kittens.runner import get_kitten_conf_docs
|
from kittens.runner import get_kitten_conf_docs
|
||||||
for kitten in all_kitten_names:
|
for kitten in all_kitten_names:
|
||||||
all_options = get_kitten_conf_docs(kitten)
|
definition = get_kitten_conf_docs(kitten)
|
||||||
if all_options:
|
if definition:
|
||||||
generate_default_config(all_options, f'kitten-{kitten}')
|
generate_default_config(definition, f'kitten-{kitten}')
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,11 +7,15 @@ import importlib
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, Dict, FrozenSet, List
|
from typing import Any, Dict, FrozenSet, List, TYPE_CHECKING, cast
|
||||||
|
|
||||||
from kitty.types import run_once
|
from kitty.types import run_once
|
||||||
|
|
||||||
aliases = {'url_hints': 'hints'}
|
aliases = {'url_hints': 'hints'}
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from kitty.conf.types import Definition
|
||||||
|
else:
|
||||||
|
Definition = object
|
||||||
|
|
||||||
|
|
||||||
def resolved_kitten(k: str) -> str:
|
def resolved_kitten(k: str) -> str:
|
||||||
@ -151,12 +155,12 @@ def get_kitten_cli_docs(kitten: str) -> Any:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def get_kitten_conf_docs(kitten: str) -> Any:
|
def get_kitten_conf_docs(kitten: str) -> Definition:
|
||||||
setattr(sys, 'all_options', None)
|
setattr(sys, 'options_definition', None)
|
||||||
run_kitten(kitten, run_name='__conf__')
|
run_kitten(kitten, run_name='__conf__')
|
||||||
ans = getattr(sys, 'all_options')
|
ans = getattr(sys, 'options_definition')
|
||||||
delattr(sys, 'all_options')
|
delattr(sys, 'options_definition')
|
||||||
return ans
|
return cast(Definition, ans)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|||||||
@ -27,6 +27,19 @@ class Unset:
|
|||||||
unset = Unset()
|
unset = Unset()
|
||||||
|
|
||||||
|
|
||||||
|
def expand_opt_references(conf_name: str, text: str) -> str:
|
||||||
|
conf_name += '.'
|
||||||
|
|
||||||
|
def expand(m: Match) -> str:
|
||||||
|
ref = m.group(1)
|
||||||
|
if '<' not in ref and '.' not in ref:
|
||||||
|
full_ref = conf_name + ref
|
||||||
|
return ':opt:`{} <{}>`'.format(ref, full_ref)
|
||||||
|
return str(m.group())
|
||||||
|
|
||||||
|
return re.sub(r':opt:`(.+?)`', expand, text)
|
||||||
|
|
||||||
|
|
||||||
def remove_markup(text: str) -> str:
|
def remove_markup(text: str) -> str:
|
||||||
|
|
||||||
def sub(m: Match) -> str:
|
def sub(m: Match) -> str:
|
||||||
@ -122,6 +135,27 @@ class Option:
|
|||||||
a('')
|
a('')
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def as_rst(
|
||||||
|
self, conf_name: str, shortcut_slugs: Dict[str, Tuple[str, str]],
|
||||||
|
kitty_mod: str, level: int = 0, option_group: List['Option'] = []
|
||||||
|
) -> List[str]:
|
||||||
|
ans: List[str] = []
|
||||||
|
a = ans.append
|
||||||
|
if not self.documented:
|
||||||
|
return ans
|
||||||
|
mopts = [self] + option_group
|
||||||
|
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
||||||
|
a('.. code-block:: conf')
|
||||||
|
a('')
|
||||||
|
sz = max(len(x.name) for x in mopts)
|
||||||
|
for mo in mopts:
|
||||||
|
a((' {:%ds} {}' % sz).format(mo.name, mo.defval_as_string))
|
||||||
|
a('')
|
||||||
|
if self.long_text:
|
||||||
|
a(expand_opt_references(conf_name, self.long_text))
|
||||||
|
a('')
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
class MultiVal:
|
class MultiVal:
|
||||||
|
|
||||||
@ -160,17 +194,38 @@ class MultiOption:
|
|||||||
a('')
|
a('')
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def as_rst(self, conf_name: str, shortcut_slugs: Dict[str, Tuple[str, str]], kitty_mod: str, level: int = 0) -> List[str]:
|
||||||
|
ans: List[str] = []
|
||||||
|
a = ans.append
|
||||||
|
a(f'.. opt:: {conf_name}.{self.name}')
|
||||||
|
a('.. code-block:: conf')
|
||||||
|
a('')
|
||||||
|
for k in self.items:
|
||||||
|
if k.documented:
|
||||||
|
a(f' {self.name:s} {k.defval_as_str}')
|
||||||
|
a('')
|
||||||
|
if self.long_text:
|
||||||
|
a(expand_opt_references(conf_name, self.long_text))
|
||||||
|
a('')
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
class Mapping:
|
class Mapping:
|
||||||
add_to_default: bool
|
add_to_default: bool
|
||||||
|
short_text: str
|
||||||
long_text: str
|
long_text: str
|
||||||
documented: bool
|
documented: bool
|
||||||
setting_name: str
|
setting_name: str
|
||||||
|
name: str
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parseable_text(self) -> str:
|
def parseable_text(self) -> str:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_text(self) -> str:
|
||||||
|
return ''
|
||||||
|
|
||||||
def as_conf(self, commented: bool = False, level: int = 0) -> List[str]:
|
def as_conf(self, commented: bool = False, level: int = 0) -> List[str]:
|
||||||
ans: List[str] = []
|
ans: List[str] = []
|
||||||
if self.documented:
|
if self.documented:
|
||||||
@ -181,6 +236,24 @@ class Mapping:
|
|||||||
a(''), a(render_block(self.long_text.strip())), a('')
|
a(''), a(render_block(self.long_text.strip())), a('')
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def as_rst(self, conf_name: str, shortcut_slugs: Dict[str, Tuple[str, str]], kitty_mod: str, level: int = 0) -> List[str]:
|
||||||
|
ans: List[str] = []
|
||||||
|
sc_text = f'{conf_name}.{self.short_text}'
|
||||||
|
shortcut_slugs[f'{conf_name}.{self.name}'] = (sc_text, self.key_text.replace('kitty_mod', kitty_mod))
|
||||||
|
if self.documented:
|
||||||
|
a = ans.append
|
||||||
|
a('.. shortcut:: ' + sc_text)
|
||||||
|
if self.add_to_default:
|
||||||
|
a('.. code-block:: conf')
|
||||||
|
a('')
|
||||||
|
a(' ' + self.setting_name + ' ' + self.parseable_text.replace('kitty_mod', kitty_mod))
|
||||||
|
a('')
|
||||||
|
if self.long_text:
|
||||||
|
a(expand_opt_references(conf_name, self.long_text))
|
||||||
|
a('')
|
||||||
|
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
class ShortcutMapping(Mapping):
|
class ShortcutMapping(Mapping):
|
||||||
setting_name: str = 'map'
|
setting_name: str = 'map'
|
||||||
@ -202,6 +275,10 @@ class ShortcutMapping(Mapping):
|
|||||||
def parseable_text(self) -> str:
|
def parseable_text(self) -> str:
|
||||||
return f'{self.key} {self.action_def}'
|
return f'{self.key} {self.action_def}'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_text(self) -> str:
|
||||||
|
return self.key
|
||||||
|
|
||||||
|
|
||||||
class MouseMapping(Mapping):
|
class MouseMapping(Mapping):
|
||||||
setting_name: str = 'mouse_map'
|
setting_name: str = 'mouse_map'
|
||||||
@ -226,6 +303,10 @@ class MouseMapping(Mapping):
|
|||||||
def parseable_text(self) -> str:
|
def parseable_text(self) -> str:
|
||||||
return f'{self.button} {self.event} {self.modes} {self.action_def}'
|
return f'{self.button} {self.event} {self.modes} {self.action_def}'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_text(self) -> str:
|
||||||
|
return self.button
|
||||||
|
|
||||||
|
|
||||||
NonGroups = Union[Option, MultiOption, ShortcutMapping, MouseMapping]
|
NonGroups = Union[Option, MultiOption, ShortcutMapping, MouseMapping]
|
||||||
GroupItem = Union[NonGroups, 'Group']
|
GroupItem = Union[NonGroups, 'Group']
|
||||||
@ -251,6 +332,7 @@ class Group:
|
|||||||
return len(self.items)
|
return len(self.items)
|
||||||
|
|
||||||
def iter_all_with_coalesced_options(self) -> Iterator[Union[Tuple, GroupItem]]:
|
def iter_all_with_coalesced_options(self) -> Iterator[Union[Tuple, GroupItem]]:
|
||||||
|
self.kitty_mod = 'kitty_mod'
|
||||||
option_groups = {}
|
option_groups = {}
|
||||||
current_group: List[Option] = []
|
current_group: List[Option] = []
|
||||||
coalesced = set()
|
coalesced = set()
|
||||||
@ -283,6 +365,42 @@ class Group:
|
|||||||
else:
|
else:
|
||||||
yield x
|
yield x
|
||||||
|
|
||||||
|
def as_rst(self, conf_name: str, shortcut_slugs: Dict[str, Tuple[str, str]], kitty_mod: str = 'kitty_mod', level: int = 0) -> List[str]:
|
||||||
|
ans: List[str] = []
|
||||||
|
a = ans.append
|
||||||
|
if level:
|
||||||
|
a('')
|
||||||
|
a(f'.. _conf-{conf_name}-{self.name}:')
|
||||||
|
a('')
|
||||||
|
a(self.title)
|
||||||
|
heading_level = '+' if level > 1 else '^'
|
||||||
|
a(heading_level * (len(self.title) + 20))
|
||||||
|
a('')
|
||||||
|
if self.start_text:
|
||||||
|
a(self.start_text)
|
||||||
|
a('')
|
||||||
|
else:
|
||||||
|
ans.extend(('.. default-domain:: conf', ''))
|
||||||
|
|
||||||
|
if not level:
|
||||||
|
for opt in self.iter_all_non_groups():
|
||||||
|
if isinstance(opt, Option) and opt.name == 'kitty_mod':
|
||||||
|
kitty_mod = opt.defval_as_string
|
||||||
|
break
|
||||||
|
for item in self.iter_all_with_coalesced_options():
|
||||||
|
if isinstance(item, tuple):
|
||||||
|
option, option_group = item
|
||||||
|
lines = option.as_rst(conf_name, shortcut_slugs, kitty_mod, option_group=option_group)
|
||||||
|
else:
|
||||||
|
lines = item.as_rst(conf_name, shortcut_slugs, kitty_mod, level + 1)
|
||||||
|
ans.extend(lines)
|
||||||
|
|
||||||
|
if level:
|
||||||
|
if self.end_text:
|
||||||
|
a('')
|
||||||
|
a(self.end_text)
|
||||||
|
return ans
|
||||||
|
|
||||||
def as_conf(self, commented: bool = False, level: int = 0) -> List[str]:
|
def as_conf(self, commented: bool = False, level: int = 0) -> List[str]:
|
||||||
ans: List[str] = []
|
ans: List[str] = []
|
||||||
a = ans.append
|
a = ans.append
|
||||||
@ -470,3 +588,6 @@ class Definition:
|
|||||||
|
|
||||||
def as_conf(self, commented: bool = False) -> List[str]:
|
def as_conf(self, commented: bool = False) -> List[str]:
|
||||||
return self.root_group.as_conf(commented)
|
return self.root_group.as_conf(commented)
|
||||||
|
|
||||||
|
def as_rst(self, conf_name: str, shortcut_slugs: Dict[str, Tuple[str, str]]) -> List[str]:
|
||||||
|
return self.root_group.as_rst(conf_name, shortcut_slugs)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user