From a3e4c74f5d22d757dff1bb173936bef98fc621d5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 30 May 2018 15:14:07 +0530 Subject: [PATCH] Add command line API reference --- .gitignore | 1 + docs/_static/custom.css | 22 +++++++++++ docs/conf.py | 17 ++++++++- docs/index.rst | 4 ++ docs/invocation.rst | 4 ++ kitty/cli.py | 82 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 docs/invocation.rst diff --git a/.gitignore b/.gitignore index 676a98024..e4706db04 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ dev __pycache__ glfw/wayland-*-client-protocol.[ch] docs/_build +docs/generated diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 3053eb1c7..e2c170288 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -82,3 +82,25 @@ div.sphinxsidebar { #sidebartoc a[href]:hover { color: red; } + + +.green { + color: green; +} + +.cyan { + color: blue; +} + +.italic { + font-style: italic; +} + +.bold { + font-weight: bold; +} + +.title { + font-size: larger; + font-weight: bold +} diff --git a/docs/conf.py b/docs/conf.py index dcbdf1a76..8f6931dc6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -78,7 +78,7 @@ language = None # 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'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'generated/cli-*'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -86,6 +86,11 @@ pygments_style = 'sphinx' rst_prolog = ''' .. |kitty.conf| replace:: :doc:`kitty.conf ` .. |kitty| replace:: *kitty* +.. role:: green +.. role:: italic +.. role:: bold +.. role:: cyan +.. role:: title ''' + create_shortcut_defs() @@ -258,7 +263,17 @@ def add_html_context(app, pagename, templatename, context, *args): # }}} +# CLI docs {{{ +def write_cli_docs(): + from kitty.cli import option_spec_as_rst + with open('generated/cli-kitty.rst', 'w') as f: + f.write(option_spec_as_rst(appname='kitty')) + +# }}} + + def setup(app): + write_cli_docs() app.add_role('iss', issue_role) app.add_role('commit', commit_role) app.connect('html-page-context', add_html_context) diff --git a/docs/index.rst b/docs/index.rst index 078e3fcfc..6741cb5dc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -60,6 +60,10 @@ packages are available for: `Fedora `_. +See :doc:`Configuring kitty ` for help on configuring kitty and +:doc:`Invocation ` for the command line arguments kitty supports. + + .. contents:: diff --git a/docs/invocation.rst b/docs/invocation.rst new file mode 100644 index 000000000..98d932b25 --- /dev/null +++ b/docs/invocation.rst @@ -0,0 +1,4 @@ +The kitty command line interface +==================================== + +.. include:: generated/cli-kitty.rst diff --git a/kitty/cli.py b/kitty/cli.py index 696e5e3c1..261160453 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -103,6 +103,7 @@ to specify this address. Note that this option will be ignored, unless you set # Debugging options --version -v +type=bool-set The current {appname} version @@ -246,6 +247,25 @@ def prettify(text): return text +def prettify_rst(text): + + def roled(role): + def f(x): + if x.startswith(':'): + return x + return ':{}:`{}`'.format(role, x.replace('`', r'\`')) + return f + + def sub(m): + t = m.group(2) + for ch in m.group(1): + t = {'C': roled('cyan'), '_': roled('italic'), '*': roled('bold'), 'G': roled('green'), 'T': roled('title')}[ch](t) + return t + + text = re.sub(r'[|]([a-zA-Z_*]+?) (.+?)[|]', sub, text) + return text + + def version(add_rev=False): rev = '' from . import fast_data_types @@ -354,6 +374,61 @@ def print_help_for_seq(seq, usage, message, appname): print_help_for_seq.allow_pager = True +def seq_as_rst(seq, usage, message, appname): + import textwrap + blocks = [] + a = blocks.append + + usage = '[program-to-run ...]' if usage is None else usage + optstring = '[options] ' if seq else '' + a('.. highlight:: sh') + a('.. code-block:: sh') + a('') + a(' {} {}{}'.format(appname, optstring, usage)) + a('') + message = message or ( + 'Run the |G {appname}| terminal emulator. You can also specify the |_ program| to run inside |_ {appname}| as normal' + ' arguments following the |_ options|. For example: {appname} /bin/sh' + ).format(appname=appname) + a(prettify_rst(message)) + a('') + if seq: + a('Options') + a('----------------') + for opt in seq: + if isinstance(opt, str): + a(opt) + a('~' * (len(opt) + 10)) + continue + help_text = opt['help'] + if help_text == '!': + continue # hidden option + defn = '.. option:: ' + if not opt.get('type', '').startswith('bool-'): + val_name = ' <{}>'.format(opt['dest'].upper()) + else: + val_name = '' + a(defn + ', '.join(o + val_name for o in sorted(opt['aliases']))) + if opt.get('help'): + defval = opt.get('default') + t = help_text.replace('%default', str(defval)).strip() + a('') + t = re.sub(r':$', '::', t, flags=re.MULTILINE) + t = t.replace('::\n\n\t ', '::\n \n ') + t = t.replace('\n\n\t ', '\n \n') + t = re.sub(r'(--[a-zA-Z0-9-]+)', r':option:`\1` ', t) + t = re.sub('"(.+?)"', r'``\1``', t) + a(textwrap.indent(prettify_rst(t), ' ' * 4)) + if defval is not None: + a(textwrap.indent('Default: {}'.format(defval), ' ' * 4)) + if 'choices' in opt: + a(textwrap.indent('Choices: {}'.format(', '.join(opt['choices'])), ' ' * 4)) + a('') + + text = '\n'.join(blocks) + return text + + def defval_for_opt(opt): dv = opt.get('default') typ = opt.get('type', '') @@ -489,6 +564,13 @@ def options_spec(): return options_spec.ans +def option_spec_as_rst(ospec=options_spec, usage=None, message=None, appname=None): + options = parse_option_spec(ospec()) + seq, disabled = options + oc = Options(seq, usage, message, appname) + return seq_as_rst(oc.seq, oc.usage, oc.message, oc.appname) + + def parse_args(args=None, ospec=options_spec, usage=None, message=None, appname=None): options = parse_option_spec(ospec()) seq, disabled = options