Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate Command Tree in an easily parsable format. #41

Open
00JCIV00 opened this issue Nov 7, 2023 · 10 comments
Open

Generate Command Tree in an easily parsable format. #41

00JCIV00 opened this issue Nov 7, 2023 · 10 comments
Labels
enhancement New feature or request
Milestone

Comments

@00JCIV00
Copy link
Owner

00JCIV00 commented Nov 7, 2023

Per talks with @matu3ba:

  • The list should be easily parsable for all shell languages for selection by the user as shell script (for now) with listing most relevant items first.
  • The idea is to keep it compatible to shell scripts for completion, but also enable usage outside of shell scripts.

The easiest way to do this up front will be JSON, but other formats should be explored down the road.

@00JCIV00 00JCIV00 added this to the v0.9.0-beta milestone Nov 7, 2023
@00JCIV00 00JCIV00 added the enhancement New feature or request label Nov 7, 2023
@00JCIV00 00JCIV00 modified the milestones: v0.9.0-beta, v0.10.0-beta Dec 20, 2023
@00JCIV00
Copy link
Owner Author

00JCIV00 commented Jan 7, 2024

In addition to JSON generation, the KDL format proposed by @jdx for his nascent usage tool should be supported.

@00JCIV00
Copy link
Owner Author

00JCIV00 commented Feb 10, 2024

@matu3ba Finally got around to making this generator. If you get a chance, please look at the JSON output, basic-app-template.json, that's being generated for the basic-app example.

I tried to strip the output to only the data can be used for creating CLI completions or documentation. The user can also optionally toggle generation for Commands, Options, or Values if they don't need all three Argument Types.

I think this meets your intent from our original discussion on Discord, but I'm definitely willing to workshop it if you think it can be formatted better.

@00JCIV00
Copy link
Owner Author

@matu3ba Here's the json directly in case you don't want to download from that link:

"Meta Info": {
    "name": "basic-app",
    "description": "A basic user management application designed to highlight key features of the Cova library.",
    "version": "0.10.0",
    "author": "00JCIV00",
    "copyright": "Copyright info here"
},
"Arguments": {
    "name": "basic-app",
    "description": "A basic user management application designed to highlight key features of the Cova library.",
    "sub_cmds": [
        {
            "name": "new",
            "description": "Add a new user.",
            "group": "INTERACT",
            "opts": [
                {
                    "name": "first-name",
                    "description": "User's First Name.",
                    "type_name": "[]const u8",
                    "set_behavior": "Last",
                    "max_args": 1
                },
                {
                    "name": "last-name",
                    "description": "User's Last Name.",
                    "type_name": "[]const u8",
                    "set_behavior": "Last",
                    "max_args": 1
                },
                {
                    "name": "age",
                    "description": "User's Age.",
                    "type_name": "u8",
                    "set_behavior": "Last",
                    "max_args": 1
                },
                {
                    "name": "phone",
                    "description": "User's Phone #.",
                    "type_name": "[]const u8",
                    "set_behavior": "Last",
                    "max_args": 1
                },
                {
                    "name": "address",
                    "description": "User's Address.",
                    "type_name": "[]const u8",
                    "set_behavior": "Last",
                    "max_args": 1
                }
            ],
            "vals": [
                {
                    "name": "is-admin",
                    "description": "Add this user as an admin?",
                    "type_name": "bool",
                    "set_behavior": "Last",
                    "max_args": 1
                }
            ]
        },
        {
            "name": "open",
            "description": "Open or create a users file.",
            "group": "INTERACT",
            "vals": [
                {
                    "name": "val-00",
                    "description": "No description. (Descriptions cannot currently be generated from Function Parameters.)",
                    "type_name": "[]const u8",
                    "set_behavior": "Last",
                    "max_args": 1
                }
            ]
        },
        {
            "name": "list",
            "description": "List all current users.",
            "group": "VIEW",
            "sub_cmds": [
                {
                    "name": "filter",
                    "description": "List all current users matching the provided filter. Filters can be exactly ONE of any user field.",
                    "opts": [
                        {
                            "name": "id",
                            "description": "The 'id' Option of type '?u16'.",
                            "type_name": "u16",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "admin",
                            "description": "The 'admin' Option of type '?bool'.",
                            "type_name": "bool",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "age",
                            "description": "The 'age' Option of type '?u8'.",
                            "type_name": "u8",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "first-name",
                            "description": "The 'first_name' Option of type '?[]const u8'.",
                            "type_name": "[]const u8",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "last-name",
                            "description": "The 'last_name' Option of type '?[]const u8'.",
                            "type_name": "[]const u8",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "phone",
                            "description": "The 'phone' Option of type '?[]const u8'.",
                            "type_name": "[]const u8",
                            "set_behavior": "Last",
                            "max_args": 1
                        },
                        {
                            "name": "address",
                            "description": "The 'address' Option of type '?[]const u8'.",
                            "type_name": "[]const u8",
                            "set_behavior": "Last",
                            "max_args": 1
                        }
                    ]
                }
            ]
        },
        {
            "name": "clean",
            "description": "Clean (delete) the default users file (users.csv) and persistent variable file (.ba_persist).",
            "aliases": [
                "delete"
            ],
            "group": "INTERACT",
            "opts": [
                {
                    "name": "clean_file",
                    "description": "Specify a single file to be cleaned (deleted) instead of the defaults.",
                    "aliases": [
                        "delete_file"
                    ],
                    "type_name": "filepath",
                    "set_behavior": "Last",
                    "max_args": 1
                }
            ]
        },
        {
            "name": "view-lists",
            "description": "View all lists (csv files) in the current directory.",
            "group": "VIEW"
        }
    ]
}

@matu3ba
Copy link

matu3ba commented Feb 11, 2024

Wow @00JCIV00, thanks a lot. This looks like an exciting first iteration.

I think practical usage might be needed to decide, if this satisfies sufficiently (formally) the necessary cases of 1. "required dependencies D_1,D_2,..,D_N (being group/value/argument) for group/value/argument T" and 2. "T (group/value/argument) implies to be satisfied dependencies D_A, D_B, .. (group/value/argument)".

What you specified for now looks semantically comparable to Powershell input args, see https://stackoverflow.com/questions/2157554/how-to-handle-command-line-arguments-in-powershell.

00JCIV00 added a commit that referenced this issue Feb 12, 2024
- Implemented the KDL template generator based on @jdx's spec found [here](https://sr.ht/~jdx/usage/).
- #41.
@00JCIV00
Copy link
Owner Author

@matu3ba Thank you for suggesting the idea!

Regarding your feedback, I want to make sure I'm understanding your terminology correctly. When you say "dependency" in this context, what are you referring to specifically?

The semantic comparison to PowerShell makes sense. I tried to include all of the details I needed when making the Bash, Zsh, and PowerShell completion script generators, plus a few extras that could be useful for generating documentation.

Ultimately though, I think you're spot on in that practical usage will be the greatest driver for changes to this generator.

@matu3ba
Copy link

matu3ba commented Feb 25, 2024

When you say "dependency" in this context, what are you referring to specifically?

Sorry for the super late response. I've not been too well the last 2-3 weeks.
A command or flag may imply dependencies and conflicts to other flags, which have to be resolved/uphold.
However, bear in mind that this is a (very) advanced use cas and can become arbitrary complex, so most likely the user should have a way to encode that, ideally in an debuggable way to the other non-manual things.

Does this make sense to you?
Personally I think it does not make sense to design/implement this without concrete use cases for testing, because this is open-ended complexity.

@00JCIV00
Copy link
Owner Author

00JCIV00 commented Feb 25, 2024

Hey! No worries. Hopefully you're feeling better now.

If I'm understanding correctly, you've proposed an interesting challenge, but one that I think might be (at least partially) solvable earlier in the process.

I'm going to attempt two use-case examples just to make sure I'm not way off in my thinking. Then I'll explain how I think they can be solved.

Dependencies

some-app --some-flag --some-dep-flag

In this example, Cova can already ensure that the --some-dep-flag Option is provided for the some-app Command during Runtime Parsing if it's marked as mandatory. This mandatory field will be reflected for the Option in the generated JSON template, so the same kind of parsing can be set up wherever the template is used.

However, if you're saying that --some-dep-flag is only mandatory if --some-flag is active (so a same-level dependency) Cova does not have a direct way to check for or denote that, though it provides all of the tools needed for the library user to do so in runtime code. I could potentially look to support this, but that introduces more complexity as you said.

Conflicts

some-app --some-flag --some-flag

In this example, we see the same Option provided twice. There's actually only one way this can happen in Cova, and that's if a single Option is created with .set_behavior = .Multi, meaning it can be provided by the end user a set number of times, with all inputs being collated into that single Option for the library user.

If the library user attempts to create two Options with the same name within a single Command (like some-flag here) that will be caught during Comptime Validation. As such, the JSON template (along with all of the other Meta Docs) would never be generated since there would be a comptime error.


Does this accurately capture what you mean? And, more importantly, are the current solutions sufficient for your theoretical use case?

@00JCIV00
Copy link
Owner Author

@matu3ba Just wanted to circle back and see if you had any additional feedback on this. Issue #56 may also be of interest to you.

@matu3ba
Copy link

matu3ba commented May 21, 2024

Does this accurately capture what you mean? And, more importantly, are the current solutions sufficient for your theoretical use case?

Yes. LGTM and powerful enough.

Sidenode: There was a talk on SYSYCL Italy by someone who has a Python library with similar/related goals to this project, but I was at work so I could not take notes etc.

@00JCIV00
Copy link
Owner Author

Appreciate the feedback and the heads up! Hopefully a video of that talk is also made available online.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants