diff --git a/gen/go_code.py b/gen/go_code.py index a1203200f..80a670d05 100755 --- a/gen/go_code.py +++ b/gen/go_code.py @@ -29,11 +29,9 @@ from kittens.tui.operations import Mode from kittens.tui.spinners import spinners from kitty.actions import get_all_actions from kitty.cli import ( - CompletionSpec, GoOption, go_options_for_seq, parse_option_spec, - serialize_as_go_string, ) from kitty.conf.generate import gen_go_code from kitty.conf.types import Definition @@ -45,6 +43,7 @@ from kitty.options.types import Options from kitty.rc.base import RemoteCommand, all_command_names, command_for_name from kitty.remote_control import global_options_spec from kitty.rgb import color_names +from kitty.simple_cli_definitions import CompletionSpec, serialize_as_go_string if __name__ == '__main__' and not __package__: import __main__ diff --git a/kittens/clipboard/main.py b/kittens/clipboard/main.py index ad7e818d1..396d7771a 100644 --- a/kittens/clipboard/main.py +++ b/kittens/clipboard/main.py @@ -82,7 +82,7 @@ usage = '[files to copy to/from]' if __name__ == '__main__': raise SystemExit('This should be run as kitten clipboard') elif __name__ == '__doc__': - from kitty.cli import CompletionSpec + from kitty.simple_cli_definitions import CompletionSpec cd = sys.cli_docs # type: ignore cd['usage'] = usage cd['options'] = OPTIONS diff --git a/kittens/diff/main.py b/kittens/diff/main.py index b7fcff5e8..31eea9ff7 100644 --- a/kittens/diff/main.py +++ b/kittens/diff/main.py @@ -4,9 +4,9 @@ import sys from functools import partial -from kitty.cli import CONFIG_HELP, CompletionSpec from kitty.conf.types import Definition from kitty.constants import appname +from kitty.simple_cli_definitions import CONFIG_HELP, CompletionSpec def main(args: list[str]) -> None: diff --git a/kittens/icat/main.py b/kittens/icat/main.py index deaaf63f1..430c06b13 100644 --- a/kittens/icat/main.py +++ b/kittens/icat/main.py @@ -179,7 +179,7 @@ if __name__ == '__main__': elif __name__ == '__doc__': import sys - from kitty.cli import CompletionSpec + from kitty.simple_cli_definitions import CompletionSpec cd = sys.cli_docs # type: ignore cd['usage'] = usage cd['options'] = lambda: OPTIONS.format() diff --git a/kittens/pager/main.py b/kittens/pager/main.py index 8f7a0365d..27ebe1ca4 100644 --- a/kittens/pager/main.py +++ b/kittens/pager/main.py @@ -4,7 +4,7 @@ import sys -from kitty.cli import CompletionSpec +from kitty.simple_cli_definitions import CompletionSpec OPTIONS = ''' --role diff --git a/kittens/panel/main.py b/kittens/panel/main.py index 063e99f81..e785de96d 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -7,7 +7,7 @@ from contextlib import suppress from functools import partial from typing import Any, Mapping, Sequence -from kitty.cli import listen_on_defn, parse_args +from kitty.cli import parse_args from kitty.cli_stub import PanelCLIOptions from kitty.constants import appname, is_macos, is_wayland, kitten_exe from kitty.fast_data_types import ( @@ -29,6 +29,7 @@ from kitty.fast_data_types import ( toggle_os_window_visibility, ) from kitty.os_window_size import WindowSizeData, edge_spacing +from kitty.simple_cli_definitions import listen_on_defn from kitty.types import LayerShellConfig from kitty.typing import BossType, EdgeLiteral from kitty.utils import log_error diff --git a/kittens/themes/main.py b/kittens/themes/main.py index 2afd31f41..6ffa35e8d 100644 --- a/kittens/themes/main.py +++ b/kittens/themes/main.py @@ -3,7 +3,7 @@ import sys -from kitty.cli import CompletionSpec +from kitty.simple_cli_definitions import CompletionSpec help_text = ( 'Change the kitty theme. If no theme name is supplied, run interactively, otherwise' diff --git a/kittens/transfer/main.py b/kittens/transfer/main.py index 0168b4851..1a9ff2809 100644 --- a/kittens/transfer/main.py +++ b/kittens/transfer/main.py @@ -127,7 +127,7 @@ def main(args: list[str]) -> None: if __name__ == '__main__': main(sys.argv) elif __name__ == '__doc__': - from kitty.cli import CompletionSpec + from kitty.simple_cli_definitions import CompletionSpec cd = sys.cli_docs # type: ignore cd['usage'] = usage cd['options'] = option_text diff --git a/kitty/cli.py b/kitty/cli.py index 08697a160..7fa1c4777 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -5,8 +5,6 @@ import os import re import sys from collections.abc import Callable, Iterator, Sequence -from dataclasses import dataclass -from enum import Enum, auto from re import Match from typing import Any, NoReturn, TypeVar, Union, cast @@ -15,104 +13,11 @@ from .conf.utils import resolve_config from .constants import appname, clear_handled_signals, config_dir, default_pager_for_help, defconf, is_macos, str_version, website_url from .fast_data_types import parse_cli_from_spec, wcswidth from .options.types import Options as KittyOpts +from .simple_cli_definitions import CompletionSpec, CompletionType, OptionDict, kitty_options_spec, serialize_as_go_string from .types import run_once -from .typing import BadLineType, TypedDict -from .utils import shlex_split - - -class CompletionType(Enum): - file = auto() - directory = auto() - keyword = auto() - special = auto() - none = auto() - - -class CompletionRelativeTo(Enum): - cwd = auto() - config_dir = auto() - - -@dataclass -class CompletionSpec: - - type: CompletionType = CompletionType.none - kwds: tuple[str,...] = () - extensions: tuple[str,...] = () - mime_patterns: tuple[str,...] = () - group: str = '' - relative_to: CompletionRelativeTo = CompletionRelativeTo.cwd - - @staticmethod - def from_string(raw: str) -> 'CompletionSpec': - self = CompletionSpec() - for x in shlex_split(raw): - ck, vv = x.split(':', 1) - if ck == 'type': - self.type = getattr(CompletionType, vv) - elif ck == 'kwds': - self.kwds += tuple(vv.split(',')) - elif ck == 'ext': - self.extensions += tuple(vv.split(',')) - elif ck == 'group': - self.group = vv - elif ck == 'mime': - self.mime_patterns += tuple(vv.split(',')) - elif ck == 'relative': - if vv == 'conf': - self.relative_to = CompletionRelativeTo.config_dir - else: - raise ValueError(f'Unknown completion relative to value: {vv}') - else: - raise KeyError(f'Unknown completion property: {ck}') - return self - - def as_go_code(self, go_name: str, sep: str = ': ') -> Iterator[str]: - completers = [] - if self.kwds: - kwds = (f'"{serialize_as_go_string(x)}"' for x in self.kwds) - g = (self.group if self.type is CompletionType.keyword else '') or "Keywords" - completers.append(f'cli.NamesCompleter("{serialize_as_go_string(g)}", ' + ', '.join(kwds) + ')') - relative_to = 'CONFIG' if self.relative_to is CompletionRelativeTo.config_dir else 'CWD' - if self.type is CompletionType.file: - g = serialize_as_go_string(self.group or 'Files') - added = False - if self.extensions: - added = True - pats = (f'"*.{ext}"' for ext in self.extensions) - completers.append(f'cli.FnmatchCompleter("{g}", cli.{relative_to}, ' + ', '.join(pats) + ')') - if self.mime_patterns: - added = True - completers.append(f'cli.MimepatCompleter("{g}", cli.{relative_to}, ' + ', '.join(f'"{p}"' for p in self.mime_patterns) + ')') - if not added: - completers.append(f'cli.FnmatchCompleter("{g}", cli.{relative_to}, "*")') - if self.type is CompletionType.directory: - g = serialize_as_go_string(self.group or 'Directories') - completers.append(f'cli.DirectoryCompleter("{g}", cli.{relative_to})') - if self.type is CompletionType.special: - completers.append(self.group) - if len(completers) > 1: - yield f'{go_name}{sep}cli.ChainCompleters(' + ', '.join(completers) + ')' - elif completers: - yield f'{go_name}{sep}{completers[0]}' - - -class OptionDict(TypedDict): - dest: str - name: str - aliases: tuple[str, ...] - help: str - choices: tuple[str, ...] - type: str - default: str | None - condition: bool - completion: CompletionSpec - - -def serialize_as_go_string(x: str) -> str: - return x.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') - +from .typing import BadLineType +is_macos go_type_map = { 'bool-set': 'bool', 'bool-reset': 'bool', 'bool-unset': 'bool', 'int': 'int', 'float': 'float64', '': 'string', 'list': '[]string', 'choices': 'string', 'str': 'string'} @@ -201,31 +106,6 @@ def go_options_for_seq(seq: 'OptionSpecSeq') -> Iterator[GoOption]: yield GoOption(x) -CONFIG_HELP = '''\ -Specify a path to the configuration file(s) to use. All configuration files are -merged onto the builtin :file:`{conf_name}.conf`, overriding the builtin values. -This option can be specified multiple times to read multiple configuration files -in sequence, which are merged. Use the special value :code:`NONE` to not load -any config file. - -If this option is not specified, config files are searched for in the order: -:file:`$XDG_CONFIG_HOME/{appname}/{conf_name}.conf`, -:file:`~/.config/{appname}/{conf_name}.conf`,{macos_confpath} -:file:`$XDG_CONFIG_DIRS/{appname}/{conf_name}.conf`. The first one that exists -is used as the config file. - -If the environment variable :envvar:`KITTY_CONFIG_DIRECTORY` is specified, that -directory is always used and the above searching does not happen. - -If :file:`/etc/xdg/{appname}/{conf_name}.conf` exists, it is merged before (i.e. -with lower priority) than any user config files. It can be used to specify -system-wide defaults for all users. You can use either :code:`-` or -:file:`/dev/stdin` to read the config from STDIN. -'''.replace( - '{macos_confpath}', - (' :file:`~/Library/Preferences/{appname}/{conf_name}.conf`,' if is_macos else ''), 1 -) - def surround(x: str, start: int, end: int) -> str: if sys.stdout.isatty(): @@ -399,7 +279,7 @@ OptionSpecSeq = list[Union[str, OptionDict]] def parse_option_spec(spec: str | None = None) -> tuple[OptionSpecSeq, OptionSpecSeq]: if spec is None: - spec = options_spec() + spec = kitty_options_spec() NORMAL, METADATA, HELP = 'NORMAL', 'METADATA', 'HELP' state = NORMAL lines = spec.splitlines() @@ -867,202 +747,15 @@ def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str return leftover_args -listen_on_defn = f'''\ ---listen-on -completion=type:special group:complete_kitty_listen_on -Listen on the specified socket address for control messages. For example, -:option:`{appname} --listen-on`=unix:/tmp/mykitty or :option:`{appname} ---listen-on`=tcp:localhost:12345. On Linux systems, you can also use abstract -UNIX sockets, not associated with a file, like this: :option:`{appname} ---listen-on`=unix:@mykitty. Environment variables are expanded and relative -paths are resolved with respect to the temporary directory. To control kitty, -you can send commands to it with :italic:`kitten @` using the -:option:`kitten @ --to` option to specify this address. Note that if you run -:italic:`kitten @` within a kitty window, there is no need to specify the -:option:`kitten @ --to` option as it will automatically read from the -environment. Note that this will be ignored unless :opt:`allow_remote_control` -is set to either: :code:`yes`, :code:`socket` or :code:`socket-only`. This can -also be specified in :file:`kitty.conf`. -''' - - -def options_spec() -> str: - if not hasattr(options_spec, 'ans'): - OPTIONS = ''' ---class --app-id -dest=cls -default={appname} -condition=not is_macos -Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it -sets the app id. - - ---name -condition=not is_macos -Set the name part of the :italic:`WM_CLASS` property. Defaults to using the -value from :option:`{appname} --class`. - - ---title -T -Set the OS window title. This will override any title set by the program running -inside kitty, permanently fixing the OS window's title. So only use this if you -are running a program that does not set titles. - - ---config -c -type=list -completion=type:file ext:conf group:"Config files" kwds:none,NONE -{config_help} - - ---override -o -type=list -completion=type:special group:complete_kitty_override -Override individual configuration options, can be specified multiple times. -Syntax: :italic:`name=value`. For example: :option:`{appname} -o` font_size=20 - - ---directory --working-directory -d -default=. -completion=type:directory -Change to the specified directory when launching. - - ---detach -type=bool-set -Detach from the controlling terminal, if any. On macOS -use :code:`open -a kitty.app -n` instead. - - ---detached-log -Path to a log file to store STDOUT/STDERR when using :option:`--detach` - - ---session -completion=type:file ext:session relative:conf group:"Session files" -Path to a file containing the startup :italic:`session` (tabs, windows, layout, -programs). Use - to read from STDIN. See :ref:`sessions` for details and -an example. Environment variables in the file name are expanded, -relative paths are resolved relative to the kitty configuration directory. -The special value :code:`none` means no session will be used, even if -the :opt:`startup_session` option has been specified in kitty.conf. -Note that using this option means the command line arguments to kitty specifying -a program to run are ignored. - - ---hold -type=bool-set -Remain open, at a shell prompt, after child process exits. Note that this only -affects the first window. You can quit by either using the close window -shortcut or running the exit command. - - ---single-instance -1 -type=bool-set -If specified only a single instance of :italic:`{appname}` will run. New -invocations will instead create a new top-level window in the existing -:italic:`{appname}` instance. This allows :italic:`{appname}` to share a single -sprite cache on the GPU and also reduces startup time. You can also have -separate groups of :italic:`{appname}` instances by using the :option:`{appname} ---instance-group` option. - - ---instance-group -Used in combination with the :option:`{appname} --single-instance` option. All -:italic:`{appname}` invocations with the same :option:`{appname} ---instance-group` will result in new windows being created in the first -:italic:`{appname}` instance within that group. - - ---wait-for-single-instance-window-close -type=bool-set -Normally, when using :option:`{appname} --single-instance`, :italic:`{appname}` -will open a new window in an existing instance and quit immediately. With this -option, it will not quit till the newly opened window is closed. Note that if no -previous instance is found, then :italic:`{appname}` will wait anyway, -regardless of this option. - - -{listen_on_defn} To start in headless mode, -without an actual window, use :option:`{appname} --start-as`=hidden. - - ---start-as -type=choices -default=normal -choices=normal,fullscreen,maximized,minimized,hidden -Control how the initial kitty window is created. - - -# Debugging options - ---version -v -type=bool-set -The current {appname} version. - - ---dump-commands -type=bool-set -Output commands received from child process to STDOUT. - - ---replay-commands -Replay previously dumped commands. Specify the path to a dump file previously -created by :option:`{appname} --dump-commands`. You -can open a new kitty window to replay the commands with:: - - {appname} sh -c "{appname} --replay-commands /path/to/dump/file; read" - - ---dump-bytes -Path to file in which to store the raw bytes received from the child process. - - ---debug-rendering --debug-gl -type=bool-set -Debug rendering commands. This will cause all OpenGL calls to check for errors -instead of ignoring them. Also prints out miscellaneous debug information. -Useful when debugging rendering problems. - - ---debug-input --debug-keyboard -dest=debug_keyboard -type=bool-set -Print out key and mouse events as they are received. - - ---debug-font-fallback -type=bool-set -Print out information about the selection of fallback fonts for characters not -present in the main font. - - ---watcher -completion=type:file ext:py relative:conf group:"Watcher files" -This option is deprecated in favor of the :opt:`watcher` option in -:file:`{conf_name}.conf` and should not be used. - - ---execute -e -type=bool-set -! -''' - setattr(options_spec, 'ans', OPTIONS.format( - appname=appname, conf_name=appname, listen_on_defn=listen_on_defn, - config_help=CONFIG_HELP.format(appname=appname, conf_name=appname), - )) - ans: str = getattr(options_spec, 'ans') - return ans - def options_for_completion() -> OptionSpecSeq: raw = '--help -h\ntype=bool-set\nShow help for {appname} command line options\n\n{raw}'.format( - appname=appname, raw=options_spec()) + appname=appname, raw=kitty_options_spec()) return parse_option_spec(raw)[0] def option_spec_as_rst( - ospec: Callable[[], str] = options_spec, + ospec: Callable[[], str] = kitty_options_spec, usage: str | None = None, message: str | None = None, appname: str | None = None, heading_char: str = '-' ) -> str: @@ -1077,7 +770,7 @@ T = TypeVar('T') def parse_args( args: list[str] | None = None, - ospec: Callable[[], str] = options_spec, + ospec: Callable[[], str] = kitty_options_spec, usage: str | None = None, message: str | None = None, appname: str | None = None, diff --git a/kitty/conf/generate.py b/kitty/conf/generate.py index 787758ecc..0cece6e00 100644 --- a/kitty/conf/generate.py +++ b/kitty/conf/generate.py @@ -10,6 +10,7 @@ from collections.abc import Callable, Iterator from typing import Any, get_type_hints from kitty.conf.types import Definition, MultiOption, Option, ParserFuncType, unset +from kitty.simple_cli_definitions import serialize_as_go_string from kitty.types import _T @@ -579,7 +580,6 @@ def gen_go_code(defn: Definition) -> str: a('func NewConfig() *Config {') a('return &Config{') - from kitty.cli import serialize_as_go_string from kitty.fast_data_types import Color for name, pname in go_parsers.items(): if name in multiopts: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 95edcfbef..08708a1e9 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -2,12 +2,12 @@ import termios from typing import Any, Callable, Dict, Iterator, List, Literal, NewType, Optional, Tuple, TypedDict, Union, overload from kitty.boss import Boss -from kitty.cli import OptionDict from kitty.fonts import VariableData from kitty.fonts.render import FontObject from kitty.marks import MarkerFunc from kitty.notifications import MacOSNotificationCategory from kitty.options.types import Options +from kitty.simple_cli_definitions import OptionDict from kitty.types import LayerShellConfig, SignalInfo from kitty.typing import EdgeLiteral, NotRequired, ReadableBuffer, WriteableBuffer diff --git a/kitty/rc/base.py b/kitty/rc/base.py index 1c0b886a2..66c28355a 100644 --- a/kitty/rc/base.py +++ b/kitty/rc/base.py @@ -7,9 +7,10 @@ from dataclasses import dataclass, field from io import BytesIO from typing import TYPE_CHECKING, Any, NoReturn, Optional, Union, cast -from kitty.cli import CompletionSpec, get_defaults_from_seq, parse_args, parse_option_spec +from kitty.cli import get_defaults_from_seq, parse_args, parse_option_spec from kitty.cli_stub import RCOptions as R from kitty.constants import list_kitty_resources, running_in_kitty +from kitty.simple_cli_definitions import CompletionSpec from kitty.types import AsyncResponse if TYPE_CHECKING: diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py new file mode 100644 index 000000000..05832c9f0 --- /dev/null +++ b/kitty/simple_cli_definitions.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python +# License: GPLv3 Copyright: 2025, Kovid Goyal + +# This module must be runnable by a vanilla python interperter +# as it is used to generate C code when building kitty + +import os +import sys +from dataclasses import dataclass +from enum import Enum, auto +from typing import Iterator, TypedDict + +try: + from kitty.constants import appname, is_macos +except ImportError: + is_macos = 'darwin' in sys.platform.lower() + try: + appname + except NameError: + appname = os.environ['KITTY_APPNAME'] +try: + from kitty.utils import shlex_split as ksplit + def shlex_split(text: str) -> Iterator[str]: + yield from ksplit(text) +except ImportError: + from shlex import split as psplit + + def shlex_split(text: str) -> Iterator[str]: + yield from psplit(text) + + +def serialize_as_go_string(x: str) -> str: + return x.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') + + +class CompletionType(Enum): + file = auto() + directory = auto() + keyword = auto() + special = auto() + none = auto() + + +class CompletionRelativeTo(Enum): + cwd = auto() + config_dir = auto() + + +@dataclass +class CompletionSpec: + + type: CompletionType = CompletionType.none + kwds: tuple[str,...] = () + extensions: tuple[str,...] = () + mime_patterns: tuple[str,...] = () + group: str = '' + relative_to: CompletionRelativeTo = CompletionRelativeTo.cwd + + @staticmethod + def from_string(raw: str) -> 'CompletionSpec': + self = CompletionSpec() + for x in shlex_split(raw): + ck, vv = x.split(':', 1) + if ck == 'type': + self.type = getattr(CompletionType, vv) + elif ck == 'kwds': + self.kwds += tuple(vv.split(',')) + elif ck == 'ext': + self.extensions += tuple(vv.split(',')) + elif ck == 'group': + self.group = vv + elif ck == 'mime': + self.mime_patterns += tuple(vv.split(',')) + elif ck == 'relative': + if vv == 'conf': + self.relative_to = CompletionRelativeTo.config_dir + else: + raise ValueError(f'Unknown completion relative to value: {vv}') + else: + raise KeyError(f'Unknown completion property: {ck}') + return self + + def as_go_code(self, go_name: str, sep: str = ': ') -> Iterator[str]: + completers = [] + if self.kwds: + kwds = (f'"{serialize_as_go_string(x)}"' for x in self.kwds) + g = (self.group if self.type is CompletionType.keyword else '') or "Keywords" + completers.append(f'cli.NamesCompleter("{serialize_as_go_string(g)}", ' + ', '.join(kwds) + ')') + relative_to = 'CONFIG' if self.relative_to is CompletionRelativeTo.config_dir else 'CWD' + if self.type is CompletionType.file: + g = serialize_as_go_string(self.group or 'Files') + added = False + if self.extensions: + added = True + pats = (f'"*.{ext}"' for ext in self.extensions) + completers.append(f'cli.FnmatchCompleter("{g}", cli.{relative_to}, ' + ', '.join(pats) + ')') + if self.mime_patterns: + added = True + completers.append(f'cli.MimepatCompleter("{g}", cli.{relative_to}, ' + ', '.join(f'"{p}"' for p in self.mime_patterns) + ')') + if not added: + completers.append(f'cli.FnmatchCompleter("{g}", cli.{relative_to}, "*")') + if self.type is CompletionType.directory: + g = serialize_as_go_string(self.group or 'Directories') + completers.append(f'cli.DirectoryCompleter("{g}", cli.{relative_to})') + if self.type is CompletionType.special: + completers.append(self.group) + if len(completers) > 1: + yield f'{go_name}{sep}cli.ChainCompleters(' + ', '.join(completers) + ')' + elif completers: + yield f'{go_name}{sep}{completers[0]}' + + +class OptionDict(TypedDict): + dest: str + name: str + aliases: tuple[str, ...] + help: str + choices: tuple[str, ...] + type: str + default: str | None + condition: bool + completion: CompletionSpec + + + + +listen_on_defn = f'''\ +--listen-on +completion=type:special group:complete_kitty_listen_on +Listen on the specified socket address for control messages. For example, +:option:`{appname} --listen-on`=unix:/tmp/mykitty or :option:`{appname} +--listen-on`=tcp:localhost:12345. On Linux systems, you can also use abstract +UNIX sockets, not associated with a file, like this: :option:`{appname} +--listen-on`=unix:@mykitty. Environment variables are expanded and relative +paths are resolved with respect to the temporary directory. To control kitty, +you can send commands to it with :italic:`kitten @` using the +:option:`kitten @ --to` option to specify this address. Note that if you run +:italic:`kitten @` within a kitty window, there is no need to specify the +:option:`kitten @ --to` option as it will automatically read from the +environment. Note that this will be ignored unless :opt:`allow_remote_control` +is set to either: :code:`yes`, :code:`socket` or :code:`socket-only`. This can +also be specified in :file:`kitty.conf`. +''' + + +CONFIG_HELP = '''\ +Specify a path to the configuration file(s) to use. All configuration files are +merged onto the builtin :file:`{conf_name}.conf`, overriding the builtin values. +This option can be specified multiple times to read multiple configuration files +in sequence, which are merged. Use the special value :code:`NONE` to not load +any config file. + +If this option is not specified, config files are searched for in the order: +:file:`$XDG_CONFIG_HOME/{appname}/{conf_name}.conf`, +:file:`~/.config/{appname}/{conf_name}.conf`,{macos_confpath} +:file:`$XDG_CONFIG_DIRS/{appname}/{conf_name}.conf`. The first one that exists +is used as the config file. + +If the environment variable :envvar:`KITTY_CONFIG_DIRECTORY` is specified, that +directory is always used and the above searching does not happen. + +If :file:`/etc/xdg/{appname}/{conf_name}.conf` exists, it is merged before (i.e. +with lower priority) than any user config files. It can be used to specify +system-wide defaults for all users. You can use either :code:`-` or +:file:`/dev/stdin` to read the config from STDIN. +'''.replace( + '{macos_confpath}', + (' :file:`~/Library/Preferences/{appname}/{conf_name}.conf`,' if is_macos else ''), 1 +) + + +def kitty_options_spec() -> str: + if not hasattr(kitty_options_spec, 'ans'): + OPTIONS = ''' +--class --app-id +dest=cls +default={appname} +condition=not is_macos +Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it +sets the app id. + + +--name +condition=not is_macos +Set the name part of the :italic:`WM_CLASS` property. Defaults to using the +value from :option:`{appname} --class`. + + +--title -T +Set the OS window title. This will override any title set by the program running +inside kitty, permanently fixing the OS window's title. So only use this if you +are running a program that does not set titles. + + +--config -c +type=list +completion=type:file ext:conf group:"Config files" kwds:none,NONE +{config_help} + + +--override -o +type=list +completion=type:special group:complete_kitty_override +Override individual configuration options, can be specified multiple times. +Syntax: :italic:`name=value`. For example: :option:`{appname} -o` font_size=20 + + +--directory --working-directory -d +default=. +completion=type:directory +Change to the specified directory when launching. + + +--detach +type=bool-set +Detach from the controlling terminal, if any. On macOS +use :code:`open -a kitty.app -n` instead. + + +--detached-log +Path to a log file to store STDOUT/STDERR when using :option:`--detach` + + +--session +completion=type:file ext:session relative:conf group:"Session files" +Path to a file containing the startup :italic:`session` (tabs, windows, layout, +programs). Use - to read from STDIN. See :ref:`sessions` for details and +an example. Environment variables in the file name are expanded, +relative paths are resolved relative to the kitty configuration directory. +The special value :code:`none` means no session will be used, even if +the :opt:`startup_session` option has been specified in kitty.conf. +Note that using this option means the command line arguments to kitty specifying +a program to run are ignored. + + +--hold +type=bool-set +Remain open, at a shell prompt, after child process exits. Note that this only +affects the first window. You can quit by either using the close window +shortcut or running the exit command. + + +--single-instance -1 +type=bool-set +If specified only a single instance of :italic:`{appname}` will run. New +invocations will instead create a new top-level window in the existing +:italic:`{appname}` instance. This allows :italic:`{appname}` to share a single +sprite cache on the GPU and also reduces startup time. You can also have +separate groups of :italic:`{appname}` instances by using the :option:`{appname} +--instance-group` option. + + +--instance-group +Used in combination with the :option:`{appname} --single-instance` option. All +:italic:`{appname}` invocations with the same :option:`{appname} +--instance-group` will result in new windows being created in the first +:italic:`{appname}` instance within that group. + + +--wait-for-single-instance-window-close +type=bool-set +Normally, when using :option:`{appname} --single-instance`, :italic:`{appname}` +will open a new window in an existing instance and quit immediately. With this +option, it will not quit till the newly opened window is closed. Note that if no +previous instance is found, then :italic:`{appname}` will wait anyway, +regardless of this option. + + +{listen_on_defn} To start in headless mode, +without an actual window, use :option:`{appname} --start-as`=hidden. + + +--start-as +type=choices +default=normal +choices=normal,fullscreen,maximized,minimized,hidden +Control how the initial kitty window is created. + + +# Debugging options + +--version -v +type=bool-set +The current {appname} version. + + +--dump-commands +type=bool-set +Output commands received from child process to STDOUT. + + +--replay-commands +Replay previously dumped commands. Specify the path to a dump file previously +created by :option:`{appname} --dump-commands`. You +can open a new kitty window to replay the commands with:: + + {appname} sh -c "{appname} --replay-commands /path/to/dump/file; read" + + +--dump-bytes +Path to file in which to store the raw bytes received from the child process. + + +--debug-rendering --debug-gl +type=bool-set +Debug rendering commands. This will cause all OpenGL calls to check for errors +instead of ignoring them. Also prints out miscellaneous debug information. +Useful when debugging rendering problems. + + +--debug-input --debug-keyboard +dest=debug_keyboard +type=bool-set +Print out key and mouse events as they are received. + + +--debug-font-fallback +type=bool-set +Print out information about the selection of fallback fonts for characters not +present in the main font. + + +--watcher +completion=type:file ext:py relative:conf group:"Watcher files" +This option is deprecated in favor of the :opt:`watcher` option in +:file:`{conf_name}.conf` and should not be used. + + +--execute -e +type=bool-set +! +''' + setattr(kitty_options_spec, 'ans', OPTIONS.format( + appname=appname, conf_name=appname, listen_on_defn=listen_on_defn, + config_help=CONFIG_HELP.format(appname=appname, conf_name=appname), + )) + ans: str = getattr(kitty_options_spec, 'ans') + return ans + + +if __name__ == '__main__': + print(111111111, appname)