{"action":"created","issue":{"url":"https://api.github.com/repos/kbknapp/clap-rs/issues/259","labels_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/259/labels{/name}","comments_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/259/comments","events_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/259/events","html_url":"https://github.com/kbknapp/clap-rs/issues/259","id":107323674,"number":259,"title":"RFC: Clap2, from scratch re-write and redesign","user":{"login":"james-darkfox","id":637155,"avatar_url":"https://avatars.githubusercontent.com/u/637155?v=3","gravatar_id":"","url":"https://api.github.com/users/james-darkfox","html_url":"https://github.com/james-darkfox","followers_url":"https://api.github.com/users/james-darkfox/followers","following_url":"https://api.github.com/users/james-darkfox/following{/other_user}","gists_url":"https://api.github.com/users/james-darkfox/gists{/gist_id}","starred_url":"https://api.github.com/users/james-darkfox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/james-darkfox/subscriptions","organizations_url":"https://api.github.com/users/james-darkfox/orgs","repos_url":"https://api.github.com/users/james-darkfox/repos","events_url":"https://api.github.com/users/james-darkfox/events{/privacy}","received_events_url":"https://api.github.com/users/james-darkfox/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20app","name":"C: app","color":"fad8c7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20args","name":"C: args","color":"fad8c7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20matches","name":"C: matches","color":"fad8c7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20parsing","name":"C: parsing","color":"fad8c7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20subcommands","name":"C: subcommands","color":"fad8c7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/D:%20intermediate","name":"D: intermediate","color":"d4c5f9"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/E:%20breaking%20change","name":"E: breaking change","color":"fef2c0"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/E:%20tedious","name":"E: tedious","color":"fef2c0"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/P3:%20want%20to%20have","name":"P3: want to have","color":"bfe5bf"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/R:%20work%20in%20progress","name":"R: work in progress","color":"5319e7"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/T:%20enhancement","name":"T: enhancement","color":"bfd4f2"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/T:%20new%20feature","name":"T: new feature","color":"bfd4f2"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/T:%20RFC%20/%20question","name":"T: RFC / question","color":"bfd4f2"},{"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/W:%202.x","name":"W: 2.x","color":"bfdadc"}],"state":"open","locked":false,"assignee":{"login":"james-darkfox","id":637155,"avatar_url":"https://avatars.githubusercontent.com/u/637155?v=3","gravatar_id":"","url":"https://api.github.com/users/james-darkfox","html_url":"https://github.com/james-darkfox","followers_url":"https://api.github.com/users/james-darkfox/followers","following_url":"https://api.github.com/users/james-darkfox/following{/other_user}","gists_url":"https://api.github.com/users/james-darkfox/gists{/gist_id}","starred_url":"https://api.github.com/users/james-darkfox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/james-darkfox/subscriptions","organizations_url":"https://api.github.com/users/james-darkfox/orgs","repos_url":"https://api.github.com/users/james-darkfox/repos","events_url":"https://api.github.com/users/james-darkfox/events{/privacy}","received_events_url":"https://api.github.com/users/james-darkfox/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/kbknapp/clap-rs/milestones/3","html_url":"https://github.com/kbknapp/clap-rs/milestones/v2.0","labels_url":"https://api.github.com/repos/kbknapp/clap-rs/milestones/3/labels","id":1193970,"number":3,"title":"v2.0","description":"","creator":{"login":"kbknapp","id":6942134,"avatar_url":"https://avatars.githubusercontent.com/u/6942134?v=3","gravatar_id":"","url":"https://api.github.com/users/kbknapp","html_url":"https://github.com/kbknapp","followers_url":"https://api.github.com/users/kbknapp/followers","following_url":"https://api.github.com/users/kbknapp/following{/other_user}","gists_url":"https://api.github.com/users/kbknapp/gists{/gist_id}","starred_url":"https://api.github.com/users/kbknapp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kbknapp/subscriptions","organizations_url":"https://api.github.com/users/kbknapp/orgs","repos_url":"https://api.github.com/users/kbknapp/repos","events_url":"https://api.github.com/users/kbknapp/events{/privacy}","received_events_url":"https://api.github.com/users/kbknapp/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":0,"state":"open","created_at":"2015-07-06T01:23:01Z","updated_at":"2015-09-21T01:35:41Z","due_on":null,"closed_at":null},"comments":33,"created_at":"2015-09-19T10:37:19Z","updated_at":"2015-09-23T14:32:16Z","closed_at":null,"body":"**[Drafting; @kbknapp @sru please feel free to update this OP as you see fit. Please \"create a lock\" by posting a comment saying that you're editing - and then delete when done]**\r\n\r\nFeatures (partial checklist)\r\n---\r\n\r\n**Names could likely do with some renaming**\r\n\r\n- [ ] Automatic usage/help string (not yet)\r\n  - Filter, allow to hide options (and show with `help -v` command)\r\n- [ ] `App`\r\n  - [ ] Own metadata and a vector of argument rules\r\n- [x] `CollectionMatcher` trait implements the standard parser which `App` is currently the only implementer of.\r\n- [x] `Matcher`, purely internal. Applies `Rules` over the `Accumulator`, which 'accumulates' values.\r\n  - [x] During-parsing rules apply here (I.e. Limit occurrences, validate, etc)\r\n- [ ] Argument `Rules`\r\n  - [x] Define parser rules for runtime parsing by the `CollectionMatcher`\r\n  - [x] Arguments are positional when they have no `long` or `short` flags\r\n  - [x] Required\r\n  - [x] Occurrence limit (`-v ..3`, `short(v)` `max_occurrence(3)`, `-vvv` is good, `-vvvv` is bad)\r\n  - [x] Multiple is an alias to `max_occurrence(0)` (Default is 1 occurrence)\r\n  - [x] Take values, either named or unnamed; may specify how many times captured. `--option foo foo2`\r\n  - [ ] Requires, conflicts (not yet)\r\n- [x] Macro builder to ease consumption\r\n- [ ] Subcommands (not yet)\r\n- [ ] Argument groups (not yet)\r\n  - [ ] Conflict / require_one\r\n- [ ] `validation` functions including `possible_values` (not yet)\r\n- [ ] Suggestions \"`foo` not found. Did you mean: `foobaz` or `foobar`?\" (not yet)\r\n- [ ] Struct with `impl From<CollectedMatches>` for `app.verbose == 3` accesses\r\n  - [ ] Default values\r\n\r\nDeprecated\r\n---\r\n\r\n- Yaml parser ? Is there any suitable use-case now? The macro solves this issue with less overheads and is the fastest solution (compile time with constant folded builders). Additionally the yaml parser was runtime and if the file and program were out of sync, then the documentation becomes stale.\r\n- `from_usage_string`, this runtime cost isn't desired and with the macro there is no need for it. (Is there a need? A consumer could always use the builders if they want a mutable, interactive prompt in their application)\r\n\r\nMacro builder usage\r\n---\r\n\r\n```rust\r\nclap_app!{ TestApp;\r\n    (meta => author: \"James McGlashan\"\r\n             about:  \"Testing application\")\r\n    (args => config:  (--config conf {exists}) \"Configuration file\"\r\n             verbose: [-v --verbose..3]        \"Verbosity level\"\r\n             input:   (input_file)             \"Input file\"\r\n    )\r\n//  (@subcommands => TestApp) // recursion\r\n};\r\n```\r\nCargo count\r\n--- \r\n```\r\nGathering information...\r\n         Language  Files  Lines  Blanks  Comments  Code\r\n         --------  -----  -----  ------  --------  ----\r\n         TOML      1      4      0       0         4\r\n         Rust      5      458    64      31        363\r\n         --------  -----  -----  ------  --------  ----\r\nTotals:            6      462    64      31        367\r\n```\r\n\r\n<!--Quickly hacked together today. Incomplete and demonstrates a number of refactoring ideas.\r\n\r\nCurrent sample code: <https://gist.github.com/james-darkfox/c318258835114f3be4c9>\r\n\r\n**Notes**\r\n\r\n- This was **quickly hacked together**, and is **not** feature complete.\r\n- I'm **not** attempting to replace clap, just **demonstrating** some ideas.\r\n- I started this for the purpose of refactoring down clap as it is currently **HUGE** (10k total, 7k sloc)\r\n- There is no builder macro due to not having a stable builder API yet.\r\n- All meta for the application is not included in the `ArgCollection`, for a usage string to be generated; the meta would need to exist in an external struct.\r\n  - `fn arg_collection_as_usage(ac: &ArgCollection, meta_config: meta) -> String`\r\n  - Without panics, this also gives the consumer more control to opt for how low level or handheld they wish to be. Ranging from manually constructing the `ArgRules` to using the builder macro (with everything provided 'by default' or otherwise configurable)\r\n- The `ArgCollection` is just a `HashMap<Cow<'static, str>, ArgRules>` with a match function returning a similar map of `HashMap<Cow<'static, str>, ArgMatcher>`.\r\n- `ArgRules` is passed by reference to create the `ArgMatcher`, allowing for reuse.\r\n- #256 not an issue as respective ClapError's are returned.\r\n- #254 just needs to get the list of keys in the `HashMap`, which we do not consume when matching.\r\n- #235 can easily bring it's own usage format and have the matcher re-used without cloning.\r\n- #146 will require integration into the builder macro and may need some type tricks to extract the desired value types. (Associated types)\r\n- **BREAKING** change :wink: \r\n\r\n**Note**: The effort required to refactor the current state of clap would be more than adopting a redesign (like I've started).\r\n\r\n### Checklist\r\n\r\n- [x] ~~`Cow<'static, str>` for handling ownership of `&'static str` and String together~~\r\n- [ ] Clean user consumable interface\r\n  - [x] Builders factored down into rules, which are refereed to when matching\r\n  - [x] Error type with no `panic!`\r\n  - [ ] Builder macro\r\n  - [ ] Consumer uses `struct.field` instead of `matches.get(\"foo\")`\r\n- [ ] Pre matching asserts\r\n  - [ ] Positional requirements\r\n    - [x] Cannot capture multiple or repeat;\r\n    - [ ] Unless subcommand\r\n- [ ] Matching\r\n  - [x] Counting and limiting occurrences (multiple = unlimited = 0; default is 1)\r\n  - [x] Grab N values from the iterator (0 = flag, 1+ = argument)\r\n  - [x] Positional arguments\r\n  - [ ] Subcommand last positional argument, another `ArgCollection` fed the remaining of the iterator.\r\n  - [x] `--` to denote only positional arguments\r\n- [ ] Post matching asserts\r\n  - [ ] Requires and conflicts (including groups)\r\n  - [ ] Validation functions\r\n  - [x] Required\r\n- [x] **No `-o foo foo` to expand to `-o foo -o foo`**\r\n  - [x] Use `-oo foo foo` which allows for `-vvoo foo foo` to expand to `--verbose --verbose --option foo --option foo`\r\n- [ ] Usage string\r\n  - [ ] `description` on `ArgRule`\r\n  - [ ] Subcommands as last positional\r\n  - [ ] Called via trait such that consumers can create their own usage string formats to fit their context\r\n\r\n### Updated: Implementation notes\r\n\r\n- `multiple` is defined as `max_occurrences(0)`\r\n- `-o foo foo` is no more. Instead `-oo foo foo`; both equivalent to `-o foo -o foo`\r\n- `-abc 1 2 3` where a takes one argument, and c takes 2; results in `a: 1`, `b` `c: 2, 3`-->"},"comment":{"url":"https://api.github.com/repos/kbknapp/clap-rs/issues/comments/142619748","html_url":"https://github.com/kbknapp/clap-rs/issues/259#issuecomment-142619748","issue_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/259","id":142619748,"user":{"login":"sru","id":2485892,"avatar_url":"https://avatars.githubusercontent.com/u/2485892?v=3","gravatar_id":"","url":"https://api.github.com/users/sru","html_url":"https://github.com/sru","followers_url":"https://api.github.com/users/sru/followers","following_url":"https://api.github.com/users/sru/following{/other_user}","gists_url":"https://api.github.com/users/sru/gists{/gist_id}","starred_url":"https://api.github.com/users/sru/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sru/subscriptions","organizations_url":"https://api.github.com/users/sru/orgs","repos_url":"https://api.github.com/users/sru/repos","events_url":"https://api.github.com/users/sru/events{/privacy}","received_events_url":"https://api.github.com/users/sru/received_events","type":"User","site_admin":false},"created_at":"2015-09-23T14:32:16Z","updated_at":"2015-09-23T14:32:16Z","body":"@james-darkfox \r\n\r\nFirst, you spelled \"chore\" wrong.\r\n\r\nIs there reason behind the naming choice? I think that `Accumulator` could be named to `Match`, and the `CollectedMatches` to just `Matches`.\r\n\r\nThe clap user needs to import `CollectionMatcher` every time along with `App`, which can be quite misleading if we do not emphasize that `CollectionMatcher` needs to be imported as well. I am unsure of splitting `CollectionMatcher` and `App`. `CollectionMatcher` sounds a bit weird to me and is too long... (although it is only my opinion)\r\n\r\n`OsStr`?"}}