diff --git a/.gitignore b/.gitignore index bd174ba27..68c326fc7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ /link_commands.json /glad/out/ /kitty/launcher/kitty* +/tools/cmd/at/*_generated.go /*.dSYM/ __pycache__/ /glfw/wayland-*-client-protocol.[ch] diff --git a/gen-rc-go.py b/gen-rc-go.py new file mode 100755 index 000000000..e8d6c617c --- /dev/null +++ b/gen-rc-go.py @@ -0,0 +1,45 @@ +#!./kitty/launcher/kitty +launch +# License: GPLv3 Copyright: 2022, Kovid Goyal + +import os +import subprocess +import sys +from typing import Any + +from kitty.rc.base import ( + RemoteCommand, all_command_names, command_for_name, parse_subcommand_cli +) + + +def serialize_as_go_string(x: str) -> str: + return x.replace('\n', '\\n').replace('"', '\\"') + + +def build_go_code(name: str, cmd: RemoteCommand, opts: Any, template: str) -> str: + template = template[len('//go:build exclude'):] + ans = template.replace('CMD_NAME', name).replace('__FILE__', __file__).replace('CLI_NAME', name.replace('_', '-')).replace( + 'SHORT_DESC', serialize_as_go_string(cmd.short_desc)).replace('LONG_DESC', serialize_as_go_string(cmd.desc)) + return ans + + +def main() -> None: + if 'prewarmed' in getattr(sys, 'kitty_run_data'): + os.environ.pop('KITTY_PREWARM_SOCKET') + os.execlp(sys.executable, sys.executable, '+launch', __file__, *sys.argv[1:]) + with open('tools/cmd/at/template.go') as f: + template = f.read() + for name in all_command_names(): + cmd = command_for_name(name) + args = ['xxx' for i in range((cmd.args_count or 0) + 1)] + opts = parse_subcommand_cli(cmd, args)[0] + code = build_go_code(name, cmd, opts, template) + dest = f'tools/cmd/at/{name}_generated.go' + if os.path.exists(dest): + os.remove(dest) + with open(dest, 'w') as f: + f.write(code) + subprocess.check_call('gofmt -s -w tools/cmd/at'.split()) + + +if __name__ == '__main__': + main() diff --git a/tools/cli/infrastructure.go b/tools/cli/infrastructure.go index a2c418937..bcfa67181 100644 --- a/tools/cli/infrastructure.go +++ b/tools/cli/infrastructure.go @@ -250,7 +250,7 @@ func format_with_indent(output io.Writer, text string, indent string, screen_wid func full_command_name(cmd *cobra.Command) string { var parent_names []string cmd.VisitParents(func(p *cobra.Command) { - parent_names = append(parent_names, p.Name()) + parent_names = append([]string{p.Name()}, parent_names...) }) parent_names = append(parent_names, cmd.Name()) return strings.Join(parent_names, " ") @@ -284,7 +284,7 @@ func show_usage(cmd *cobra.Command) error { } fmt.Fprintln(&output) format_with_indent(&output, "Get help for an individual command by running:", "", screen_width) - fmt.Fprintln(&output, " ", cmd.Name(), italic_fmt("command"), "-h") + fmt.Fprintln(&output, " ", full_command_name(cmd), italic_fmt("command"), "-h") } if cmd.HasAvailableFlags() { options_title := cmd.Annotations["options_title"] diff --git a/tools/cmd/at/main.go b/tools/cmd/at/main.go index e8928e068..7aaca6eac 100644 --- a/tools/cmd/at/main.go +++ b/tools/cmd/at/main.go @@ -69,9 +69,13 @@ func get_password(password string, password_file string, password_env string, us return ans, nil } +var all_commands map[string]func(*cobra.Command) *cobra.Command = make(map[string]func(*cobra.Command) *cobra.Command) +var command_objects map[string]*cobra.Command = make(map[string]*cobra.Command) + func EntryPoint(tool_root *cobra.Command) *cobra.Command { + var at_root_command *cobra.Command var to, password, password_file, password_env, use_password *string - var root = cli.CreateCommand(&cobra.Command{ + at_root_command = cli.CreateCommand(&cobra.Command{ Use: "@ [global options] command [command options] [command args]", Short: "Control kitty remotely", Long: "Control kitty by sending it commands. Set the allow_remote_control option in :file:`kitty.conf` or use a password, for this to work.", @@ -87,30 +91,36 @@ func EntryPoint(tool_root *cobra.Command) *cobra.Command { return err }, }) - root.Annotations["options_title"] = "Global options" + at_root_command.Annotations["options_title"] = "Global options" - to = root.PersistentFlags().String("to", "", + to = at_root_command.PersistentFlags().String("to", "", "An address for the kitty instance to control. Corresponds to the address given"+ " to the kitty instance via the :option:`kitty --listen-on` option or the :opt:`listen_on` setting in :file:`kitty.conf`. If not"+ " specified, the environment variable :envvar:`KITTY_LISTEN_ON` is checked. If that"+ " is also not found, messages are sent to the controlling terminal for this"+ " process, i.e. they will only work if this process is run within a kitty window.") - password = root.PersistentFlags().String("password", "", + password = at_root_command.PersistentFlags().String("password", "", "A password to use when contacting kitty. This will cause kitty to ask the user"+ " for permission to perform the specified action, unless the password has been"+ " accepted before or is pre-configured in :file:`kitty.conf`.") - password_file = root.PersistentFlags().String("password-file", "rc-pass", + password_file = at_root_command.PersistentFlags().String("password-file", "rc-pass", "A file from which to read the password. Trailing whitespace is ignored. Relative"+ " paths are resolved from the kitty configuration directory. Use - to read from STDIN."+ " Used if no :option:`--password` is supplied. Defaults to checking for the"+ " :file:`rc-pass` file in the kitty configuration directory.") - password_env = root.PersistentFlags().String("password-env", "KITTY_RC_PASSWORD", + password_env = at_root_command.PersistentFlags().String("password-env", "KITTY_RC_PASSWORD", "The name of an environment variable to read the password from."+ " Used if no :option:`--password-file` or :option:`--password` is supplied.") - use_password = cli.PersistentChoices(root, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never") - return root + use_password = cli.PersistentChoices(at_root_command, "use-password", "If no password is available, kitty will usually just send the remote control command without a password. This option can be used to force it to always or never use the supplied password.", "if-available", "always", "never") + + for cmd_name, reg_func := range all_commands { + c := reg_func(at_root_command) + at_root_command.AddCommand(c) + command_objects[cmd_name] = c + } + return at_root_command } diff --git a/tools/cmd/at/template.go b/tools/cmd/at/template.go new file mode 100644 index 000000000..3aa3ffdea --- /dev/null +++ b/tools/cmd/at/template.go @@ -0,0 +1,25 @@ +//go:build exclude + +// this file is autogenerated by __FILE__ do not edit + +package at + +import ( + "github.com/spf13/cobra" + + "kitty/tools/cli" +) + +func setup_CMD_NAME(root *cobra.Command) *cobra.Command { + ans := cli.CreateCommand(&cobra.Command{ + Use: "CLI_NAME [options]", + Short: "SHORT_DESC", + Long: "LONG_DESC", + }) + + return ans +} + +func init() { + all_commands["CMD_NAME"] = setup_CMD_NAME +}