Dont maintain ref_map manually

This commit is contained in:
Kovid Goyal 2022-08-19 11:20:50 +05:30
parent 6f6e23bf61
commit 5deed81737
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 100 additions and 28 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
*.pyo
*_stub.pyi
*_generated.go
*_generated.h
/.dmypy.json
/tags
/build/

35
docs/extract-rst-targets.py Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re
from typing import Dict, Iterator
tgt_pat = re.compile(r'^.. _(\S+?):$', re.MULTILINE)
def find_explicit_targets(text: str) -> Iterator[str]:
for m in tgt_pat.finditer(text):
yield m.group(1)
def main() -> Dict[str, str]:
refs = {'github_discussions': 'https://github.com/kovidgoyal/kitty/discussions'}
base = os.path.dirname(os.path.abspath(__file__))
for dirpath, dirnames, filenames in os.walk(base):
if 'generated' in dirnames:
dirnames.remove('generated')
for f in filenames:
if f.endswith('.rst'):
with open(os.path.join(dirpath, f)) as stream:
raw = stream.read()
href = os.path.relpath(stream.name, base).replace(os.sep, '/')
href = href.rpartition('.')[0] + '/'
for explicit_target in find_explicit_targets(raw):
refs[explicit_target] = href + f'#{explicit_target}'
return {'ref': refs}
if __name__ == '__main__':
import json
print(json.dumps(main(), indent=2))

View File

@ -11,7 +11,7 @@ from typing import (
)
from .cli_stub import CLIOptions
from .conf.types import ref_map
from .conf.types import resolve_ref
from .conf.utils import resolve_config
from .constants import (
appname, clear_handled_signals, defconf, is_macos, str_version, website_url
@ -131,9 +131,15 @@ def code(x: str) -> str:
return cyan(x)
def text_and_target(x: str) -> Tuple[str, str]:
parts = x.split('<')
return parts[0].strip(), parts[-1].rstrip('>')
@role
def term(x: str) -> str:
return italic(x.split('<', 1)[0])
t, q = text_and_target(x)
return italic(t)
@role
@ -165,11 +171,10 @@ def doc(x: str) -> str:
@role
def ref(x: str) -> str:
parts = x.split('<')
t = parts[0].strip()
q = parts[-1].rstrip('>')
if q in ref_map():
return hyperlink_for_url(ref_map()[q], t)
t, q = text_and_target(x)
url = resolve_ref(q)
if url:
return hyperlink_for_url(url, t)
return t

View File

@ -45,24 +45,29 @@ def expand_opt_references(conf_name: str, text: str) -> str:
@run_once
def ref_map() -> Dict[str, str]:
from kitty.actions import get_all_actions
ref_map = {
'layouts': f'{website_url("overview")}#layouts',
'include': f'{website_url("conf")}#include',
'watchers': f'{website_url("launch")}#watchers',
'sessions': f'{website_url("overview")}#startup-sessions',
'functional': f'{website_url("keyboard-protocol")}#functional-key-definitions',
'ssh_copy_command': f'{website_url("kittens/ssh")}#ssh-copy-command',
'shell_integration': website_url("shell-integration"),
'rc_custom_auth': f'{website_url("remote-control")}#rc-custom-auth',
'clone_shell': f'{website_url("shell-integration")}#clone-shell',
'github_discussions': 'https://github.com/kovidgoyal/kitty/discussions',
}
for actions in get_all_actions().values():
for ac in actions:
ref_map[f'action-{ac.name}'] = f'{website_url("actions")}#' + ac.name.replace('_', '-')
return ref_map
def ref_map() -> Dict[str, Dict[str, str]]:
import json
from ..fast_data_types import get_docs_ref_map
ans: Dict[str, Dict[str, str]] = json.loads(get_docs_ref_map())
return ans
def resolve_ref(ref: str) -> str:
m = ref_map()
href = m['ref'].get(ref, '')
if href:
return href
if ref.startswith('conf-'):
base = 'generated/' + ref.rpartition('-')[0]
href = f'{website_url(base)}#{ref}'
elif ref.startswith('at_'):
href = f'{website_url("generated/cli-kitty-at")}#{ref}'
elif ref.startswith('action-group-'):
href = f'{website_url("generated/actions")}#{ref}'
elif ref.startswith('action-'):
frag = ref.partition('-')[-1]
href = f'{website_url("generated/actions")}#{frag}'
return href
def remove_markup(text: str) -> str:
@ -76,7 +81,10 @@ def remove_markup(text: str) -> str:
def sub(m: 'Match[str]') -> str:
if m.group(1) == 'ref':
t, q = extract(m)
return f'{t} <{ref_map()[q]}>'
url = resolve_ref(q)
if not url:
raise KeyError(f'Failed to resolve :ref: {q}')
return f'{t} <{url}>'
if m.group(1) == 'doc':
t, q = extract(m)
return f'{t} <{website_url(q.lstrip("/"))}>'
@ -91,7 +99,7 @@ def remove_markup(text: str) -> str:
return t
if m.group(1) == 'disc':
t, q = extract(m)
return f'{t} {ref_map()["github_discussions"]}/{q}'
return f'{t} {resolve_ref("github_discussions")}/{q}'
return str(m.group(2))
return re.sub(r':([a-zA-Z0-9]+):`(.+?)`', sub, text, flags=re.DOTALL)

View File

@ -209,10 +209,16 @@ py_getpeereid(PyObject *self UNUSED, PyObject *args) {
return Py_BuildValue("ii", u, g);
}
#include "docs_ref_map_generated.h"
static PyObject*
get_docs_ref_map(PyObject *self UNUSED, PyObject *args UNUSED) {
return PyBytes_FromStringAndSize(docs_ref_map, sizeof(docs_ref_map));
}
static PyMethodDef module_methods[] = {
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
{"get_docs_ref_map", (PyCFunction)get_docs_ref_map, METH_NOARGS, ""},
{"getpeereid", (PyCFunction)py_getpeereid, METH_VARARGS, ""},
{"wcswidth", (PyCFunction)wcswidth_std, METH_O, ""},
{"open_tty", open_tty, METH_VARARGS, ""},

View File

@ -1486,3 +1486,4 @@ class SingleKey:
def set_use_os_log(yes: bool) -> None: ...
def get_docs_ref_map() -> bytes: ...

View File

@ -14,6 +14,7 @@ import subprocess
import sys
import sysconfig
import tempfile
import textwrap
import time
from contextlib import suppress
from functools import lru_cache, partial
@ -839,10 +840,25 @@ def init_env_from_args(args: Options, native_optimizations: bool = False) -> Non
)
def build_ref_map() -> str:
m = runpy.run_path('docs/extract-rst-targets.py')
d = m['main']()
h = 'static const char docs_ref_map[] = {\n' + textwrap.fill(', '.join(map(str, bytearray(json.dumps(d).encode('utf-8'))))) + '\n};'
dest = 'kitty/docs_ref_map_generated.h'
q = ''
with suppress(FileNotFoundError), open(dest) as f:
q = f.read()
if q != h:
with open(dest, 'w') as f:
f.write(h)
return dest
def build(args: Options, native_optimizations: bool = True, call_init: bool = True) -> None:
if call_init:
init_env_from_args(args, native_optimizations)
sources, headers = find_c_files()
headers.append(build_ref_map())
compile_c_extension(
kitty_env(), 'kitty/fast_data_types', args.compilation_database, sources, headers
)
@ -1375,7 +1391,7 @@ def clean() -> None:
safe_remove(
'build', 'compile_commands.json', 'link_commands.json',
'linux-package', 'kitty.app', 'asan-launcher',
'kitty-profile')
'kitty-profile', 'docs/generated')
clean_launcher_dir('kitty/launcher')
def excluded(root: str, d: str) -> bool: