Last active
November 15, 2021 16:44
-
-
Save ansaso/55d2a66b4fcb0820493d721d4727af46 to your computer and use it in GitHub Desktop.
Fish completion from json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
######################### | |
#### fish completion #### | |
######################### | |
# in /path/to/fish/completions/{mycommand}.fish | |
# store json completion for command as environment variable | |
# to be passed down to python script | |
set -x json_completion (cat "path/to/mycommand.json") | |
# pipe current arguments to python script stdin | |
# (make sure python script is executable and in path) | |
complete -f -c mycommand -a "(__fish_print_cmd_args_without_options | json_to_fish_completion.py)" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"option1": null, | |
"option2": {}, | |
"option3": { | |
"description": null | |
}, | |
"option4": "some description", | |
"option5": { | |
"description": "some description" | |
}, | |
"subcommand1": [ | |
"option1.1", | |
"option1.2" | |
], | |
"subcommand2": { | |
"option2.1": "some description", | |
"option2.2": null | |
}, | |
"subcommand3": { | |
"options": { | |
"option3.1": "some description", | |
"option3.2": null | |
} | |
}, | |
"subcommand4": { | |
"options": [ | |
"option4.1", | |
"option4.2" | |
] | |
}, | |
"subcommand5": { | |
"description": "some description", | |
"options": { | |
"option5.1": null, | |
"subcommand5.1": { | |
"description": "some description", | |
"options": [ | |
"option5.1.1", | |
"option5.1.2" | |
] | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
"option1", | |
"option2", | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
####################### | |
#### python script #### | |
####################### | |
import sys | |
from typing import Union, List, Dict, Any, Optional | |
import os | |
import json | |
# get content of json file read and stored as environment variable | |
# in fish completion file which calls this script | |
JSON_COMPLETION = os.getenv("json_completion") | |
if not JSON_COMPLETION: | |
raise OSError("json_completion environment variable not set") | |
# type | |
Options = Union[List[str], Dict[str, Any]] | |
def option_string( | |
option: str, | |
description: Optional[str] = None, | |
is_subcommand: bool = False | |
): | |
# fish parses tab as separator between option and description | |
option = option + '\t' | |
# apply formatting to distinguish subcommands | |
if is_subcommand: | |
option = option + "* " | |
if description: | |
option = option + description | |
return option | |
def is_simple_dict(props) -> bool: | |
return ( | |
("options" not in props) and | |
("description" not in props) and | |
(len(props) > 0) | |
) | |
# translate json schema to fish options | |
def get_options(options: Options): | |
new_options = [] | |
if isinstance(options, list): | |
for option in options: | |
new_options.append(option_string(option, description=None)) | |
elif isinstance(options, dict): | |
for option, props in options.items(): | |
if isinstance(props, str): | |
new_options.append(option_string(option, description=props, is_subcommand=False)) | |
elif props is None: | |
new_options.append(option_string(option, description=None, is_subcommand=False)) | |
elif isinstance(props, dict): | |
desc = props.get("description", None) | |
is_subcommand = ("options" in props) or is_simple_dict(props) | |
new_options.append(option_string(option, description=desc, is_subcommand=is_subcommand)) | |
elif isinstance(props, list): | |
is_subcommand = len(props) > 0 | |
new_options.append(option_string(option, description=None, is_subcommand=is_subcommand)) | |
return new_options | |
if __name__ == "__main__": | |
lines = sys.stdin.readlines() | |
indexes = lines[1:] | |
options = json.loads(JSON_COMPLETION) | |
depth = 0 | |
for index in indexes: | |
props = options.get(index.strip()) | |
if isinstance(props, dict): | |
if "options" in props: | |
options = props["options"] | |
elif is_simple_dict(props): | |
options = props | |
elif isinstance(props, list): | |
if len(props) > 0: | |
options = props | |
else: | |
break | |
depth += 1 | |
if len(indexes) >= depth: | |
sys.stdout.write('\n'.join(get_options(options))) | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment