1#!/usr/local/bin/python3.8
2# vim:fileencoding=utf-8
3# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
4
5import os
6import sys
7from typing import List
8
9
10def icat(args: List[str]) -> None:
11    from kittens.runner import run_kitten as rk
12    sys.argv = args
13    rk('icat')
14
15
16def list_fonts(args: List[str]) -> None:
17    from kitty.fonts.list import main as list_main
18    list_main(args)
19
20
21def remote_control(args: List[str]) -> None:
22    from kitty.remote_control import main as rc_main
23    rc_main(args)
24
25
26def runpy(args: List[str]) -> None:
27    if len(args) < 2:
28        raise SystemExit('Usage: kitty +runpy "some python code"')
29    sys.argv = ['kitty'] + args[2:]
30    exec(args[1])
31
32
33def hold(args: List[str]) -> None:
34    import subprocess
35    import tty
36    from contextlib import suppress
37    ret = subprocess.Popen(args[1:]).wait()
38    with suppress(BaseException):
39        print('\n\x1b[1;32mPress any key to exit', end='', flush=True)
40    with suppress(BaseException):
41        tty.setraw(sys.stdin.fileno())
42        sys.stdin.buffer.read(1)
43    raise SystemExit(ret)
44
45
46def complete(args: List[str]) -> None:
47    from kitty.complete import main as complete_main
48    complete_main(args[1:], entry_points, namespaced_entry_points)
49
50
51def launch(args: List[str]) -> None:
52    import runpy
53    sys.argv = args[1:]
54    try:
55        exe = args[1]
56    except IndexError:
57        raise SystemExit(
58            'usage: kitty +launch script.py [arguments to be passed to script.py ...]\n\n'
59            'script.py will be run with full access to kitty code. If script.py is '
60            'prefixed with a : it will be searched for in PATH'
61        )
62    if exe.startswith(':'):
63        import shutil
64        q = shutil.which(exe[1:])
65        if not q:
66            raise SystemExit(f'{exe[1:]} not found in PATH')
67        exe = q
68    if not os.path.exists(exe):
69        raise SystemExit(f'{exe} does not exist')
70    runpy.run_path(exe, run_name='__main__')
71
72
73def run_kitten(args: List[str]) -> None:
74    try:
75        kitten = args[1]
76    except IndexError:
77        from kittens.runner import list_kittens
78        list_kittens()
79        raise SystemExit(1)
80    sys.argv = args[1:]
81    from kittens.runner import run_kitten as rk
82    rk(kitten)
83
84
85def edit_config_file(args: List[str]) -> None:
86    from kitty.cli import create_default_opts
87    from kitty.fast_data_types import set_options
88    from kitty.utils import edit_config_file as f
89    set_options(create_default_opts())
90    f()
91
92
93def namespaced(args: List[str]) -> None:
94    try:
95        func = namespaced_entry_points[args[1]]
96    except KeyError:
97        pass
98    else:
99        func(args[1:])
100        return
101    raise SystemExit(f'{args[1]} is not a known entry point. Choices are: ' + ', '.join(namespaced_entry_points))
102
103
104entry_points = {
105    # These two are here for backwards compat
106    'icat': icat,
107    'list-fonts': list_fonts,
108    'runpy': runpy,
109    'launch': launch,
110    'kitten': run_kitten,
111    'edit-config': edit_config_file,
112
113    '@': remote_control,
114    '+': namespaced,
115}
116namespaced_entry_points = {k: v for k, v in entry_points.items() if k[0] not in '+@'}
117namespaced_entry_points['hold'] = hold
118namespaced_entry_points['complete'] = complete
119
120
121def setup_openssl_environment() -> None:
122    # Use our bundled CA certificates instead of the system ones, since
123    # many systems come with no certificates in a useable form or have various
124    # locations for the certificates.
125    d = os.path.dirname
126    ext_dir: str = getattr(sys, 'kitty_extensions_dir')
127    if 'darwin' in sys.platform.lower():
128        cert_file = os.path.join(d(d(d(ext_dir))), 'cacert.pem')
129    else:
130        cert_file = os.path.join(d(ext_dir), 'cacert.pem')
131    os.environ['SSL_CERT_FILE'] = cert_file
132    setattr(sys, 'kitty_ssl_env_var', 'SSL_CERT_FILE')
133
134
135def main() -> None:
136    if getattr(sys, 'frozen', False) and getattr(sys, 'kitty_extensions_dir', ''):
137        setup_openssl_environment()
138    first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
139    func = entry_points.get(first_arg)
140    if func is None:
141        if first_arg.startswith('@'):
142            remote_control(['@', first_arg[1:]] + sys.argv[2:])
143        elif first_arg.startswith('+'):
144            namespaced(['+', first_arg[1:]] + sys.argv[2:])
145        else:
146            from kitty.main import main as kitty_main
147            kitty_main()
148    else:
149        func(sys.argv[1:])
150
151
152if __name__ == '__main__':
153    main()
154