diff --git a/Cargo.lock b/Cargo.lock index 6062b31..3c27e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,13 +2,30 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aargvark" +version = "0.6.5" +dependencies = [ + "aargvark_proc_macros 3.2.5", + "comfy-table", + "console", + "convert_case 0.6.0", + "http", + "serde", + "serde_json", + "serde_yaml", + "textwrap", + "unicode-width", + "url", +] + [[package]] name = "aargvark" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "648957b1bf8a8552588a78a957e2401f3ff5897dc506ef7b2a3c50613e290af9" dependencies = [ - "aargvark_proc_macros", + "aargvark_proc_macros 3.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "comfy-table", "console", "convert_case 0.6.0", @@ -16,6 +33,18 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "aargvark_proc_macros" +version = "3.2.5" +dependencies = [ + "convert_case 0.6.0", + "darling", + "genemichaels-lib 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "aargvark_proc_macros" version = "3.2.5" @@ -30,6 +59,13 @@ dependencies = [ "syn", ] +[[package]] +name = "aargvark_tests" +version = "0.0.0" +dependencies = [ + "aargvark 0.6.5", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -103,6 +139,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + [[package]] name = "cargo-manifest" version = "0.15.2" @@ -267,6 +309,17 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -295,11 +348,20 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "genemichaels" version = "0.5.7" dependencies = [ - "aargvark", + "aargvark 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "cargo-manifest", "console", "genemichaels-lib 0.5.4", @@ -364,6 +426,17 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -387,12 +460,151 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.6.0" @@ -447,6 +659,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -553,6 +771,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -716,6 +940,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "shlex" version = "1.3.0" @@ -734,6 +971,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -770,6 +1013,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "terminal_size" version = "0.2.6" @@ -821,6 +1075,16 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "toml" version = "0.8.19" @@ -886,6 +1150,35 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1175,8 +1468,87 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index e5670c8..e63cf24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,10 @@ [workspace] resolver = "2" -members = ["crates/genemichaels", "crates/genemichaels-lib"] +members = ["crates/*"] [workspace.package] edition = "2021" license = "ISC" -repository = "https://github.com/andrewbaxter/genemichaels" -readme = "readme.md" [workspace.dependencies] syn = { version = "2", features = ["full"] } diff --git a/crates/aargvark/.github/pull_request_template.md b/crates/aargvark/.github/pull_request_template.md deleted file mode 100644 index ded2f34..0000000 --- a/crates/aargvark/.github/pull_request_template.md +++ /dev/null @@ -1,4 +0,0 @@ - ---- - -I agree that when the request is merged I assign the copyright of the request to the repository owner. diff --git a/crates/aargvark/.github/workflows/copyright.yml b/crates/aargvark/.github/workflows/copyright.yml deleted file mode 100644 index b5b42d2..0000000 --- a/crates/aargvark/.github/workflows/copyright.yml +++ /dev/null @@ -1,18 +0,0 @@ -on: - pull_request: - types: [opened, edited, synchronize] - -jobs: - confirm_agreement: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BODY: ${{ github.event.pull_request.body }} - PR_ID: ${{ github.event.pull_request.number }} - run: | - set -xeu - if ! grep -F "$(tail -n 1 .github/pull_request_template.md)" <(echo "$BODY"); then - gh pr close --comment "All changes must include the provided agreement to the copyright assignment." --delete-branch "$PR_ID" - fi diff --git a/crates/aargvark/.gitignore b/crates/aargvark/.gitignore deleted file mode 100644 index cae3cbb..0000000 --- a/crates/aargvark/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/Cargo.lock -/.vscode diff --git a/crates/aargvark/Cargo.toml b/crates/aargvark/Cargo.toml index f9a305b..31d0d5d 100644 --- a/crates/aargvark/Cargo.toml +++ b/crates/aargvark/Cargo.toml @@ -1,11 +1,30 @@ -[workspace] -resolver = "2" -members = ["crates/*"] - -[workspace.package] -edition = "2021" -license = "ISC" +[package] +name = "aargvark" description = "Self-similar argument parsing" -homepage = "https://github.com/andrewbaxter/aargvark" +version = "0.6.5" +edition.workspace = true +license.workspace = true repository = "https://github.com/andrewbaxter/aargvark" -readme = "readme.md" +readme = "../../readme_aargvark.md" + +[package.metadata.docs.rs] +all-features = true + +[features] +default = [] +serde_json = ["dep:serde_json", "dep:serde"] +serde_yaml = ["dep:serde_yaml", "dep:serde"] +http_types = ["dep:http"] + +[dependencies] +aargvark_proc_macros = { path = "../aargvark_proc_macros", version = "=3.2.5" } +serde_json = { version = "1", optional = true } +serde_yaml = { version = "0", optional = true } +convert_case = "0.6" +comfy-table = { version = "7", features = ["custom_styling"] } +url = { version = "2", optional = true } +http = { version = "1", optional = true } +serde = { version = "1", optional = true } +console = "0.15" +textwrap = { version = "0.16", features = ["terminal_size"] } +unicode-width = "0.1" diff --git a/crates/aargvark/crates/aargvark/Cargo.toml b/crates/aargvark/crates/aargvark/Cargo.toml deleted file mode 100644 index e457595..0000000 --- a/crates/aargvark/crates/aargvark/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "aargvark" -description = "Self-similar argument parsing" -version = "0.6.5" -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -readme.workspace = true - -[package.metadata.docs.rs] -all-features = true - -[features] -default = [] -serde_json = ["dep:serde_json", "dep:serde"] -serde_yaml = ["dep:serde_yaml", "dep:serde"] -http_types = ["dep:http"] - -[dependencies] -aargvark_proc_macros = { path = "../aargvark_proc_macros", version = "=3.2.5" } -serde_json = { version = "1", optional = true } -serde_yaml = { version = "0", optional = true } -convert_case = "0.6" -comfy-table = { version = "7", features = ["custom_styling"] } -url = { version = "2", optional = true } -http = { version = "1", optional = true } -serde = { version = "1", optional = true } -console = "0.15" -textwrap = { version = "0.16", features = ["terminal_size"] } -unicode-width = "0.1" diff --git a/crates/aargvark/crates/aargvark/readme.md b/crates/aargvark/crates/aargvark/readme.md deleted file mode 120000 index 2e75a7b..0000000 --- a/crates/aargvark/crates/aargvark/readme.md +++ /dev/null @@ -1 +0,0 @@ -../../readme.md \ No newline at end of file diff --git a/crates/aargvark/license.txt b/crates/aargvark/license.txt deleted file mode 100644 index bd73668..0000000 --- a/crates/aargvark/license.txt +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (c) 2024 Andrew Baxter - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/crates/aargvark/readme.md b/crates/aargvark/readme.md deleted file mode 100644 index fbee4b6..0000000 --- a/crates/aargvark/readme.md +++ /dev/null @@ -1,138 +0,0 @@ - - - -
crates.iodocs.rs
- -A simple and consistent derive-based command line argument parsing, in the same genre as Clap-derive. It currently supports - -- Command line parsing -- Help - -Generally speaking this is intended to make CLI parsing simple by virtue of being simple and consistent, rather than poweruser-optimized keypress-minimizing parsing. - -This attempts to support parsing arbitrarily complex command line arguments. Like with Serde, you can combine structs, vecs, enums in any way you want. Just because you can doesn't mean you should. - -``` -$ ; This is an example help output, sans light ansi styling -$ spagh -h -Usage: spagh COMMAND [ ...FLAGS] - - A small CLI for querying, publishing, and administrating spaghettinuum. - - COMMAND: COMMAND - [--debug] - -COMMAND: ping | get | http | ssh | identity | publish | admin - - ping ... Simple liveness check - get ... Request values associated with provided identity and keys - from a resolver - http ... - ssh ... - identity ... Commands for managing identities - publish ... Commands for publishing data - admin ... Commands for node administration - -``` - -``` -$ spagh publish set -h -Usage: spagh publish set IDENTITY DATA - - IDENTITY: IDENTITY-SECRET-ARG Identity to publish as - DATA: | - Data to publish. Must be json in the - structure `{KEY: {"ttl": MINUTES, "value": - DATA}, ...}`. `KEY` is a string that's a - dotted list of key segments, with `/` to - escape dots and escape characters. - -IDENTITY-SECRET-ARG: local - - An identity with its associated secret. - - local A file containing a generated key - -``` - -# Why or why not - -Why this and not Clap? - -- It has a super-simple interface (just `#[derive(Aargvark)]` on any enum/structure) -- This parses more complex data types, like vectors of sub-structures, or enums -- It's more consistent - -Why not this? - -- It's newer, with fewer features and limited community ecosystem, extensions -- Some command line parsing conventions were discarded in order to simplify and maintain self-similarity. A lot of command line conventions are inconsistent or break down as you nest things, after all. -- Quirky CLI parsing generally isn't supported: Some tricks (like `-v` `-vv` `-vvv`) break patterns and probably won't ever be implemented. (Other things just haven't been implemented yet due to lack of time) - -# Conventions and usage - -To add it to your project, run - -```sh -cargo add aargvark -``` - -To parse command line arguments - -1. Define the data type you want to parse them into, like - - ```rust - /// General description for the command. - #[derive(Aargvark)] - struct MyArgs { - /// Field documentation. - velociraptor: String, - #[vark(flag = "-d", flag = "--deadly")] - deadly: bool, - color_pattern: Option, - } - ``` - -2. Vark it - ```rust - let args = vark::(); - ``` - -Non-optional fields become positional arguments unless you give them a flag with `#[vark(flag = "--flag")]`. Optional fields become optional (`--long`) arguments. If you want a `bool` flag that's enabled if the flag is specified (i.e. doesn't take a value), use `Option<()>`. - -You can derive structs, enums, and tuples, and there are implementations for `Vec`, `HashSet`, `Map` with `FromString` keys and values as `K=V` arguments, most `Ip` and `SocketAddr` types, and `PathBuf` built in. - -Some additional wrappers are provided for automatically loading (and parsing) files: - -- `AargvarkFile` -- `AargvarkJson` requires feature `serde_json` -- `AargvarkYaml` requires feature `serde_yaml` - -To parse your own types, implement `AargvarkTrait`, or if your type takes a single string argument you can implement `AargvarkFromStr` which is slightly simpler. - -# Advanced usage - -- Sequences, plural fields, Vecs - - Sequence elements are space separated. The way sequence parsing works is it attempts to parse as many elements as possible. When parsing one element fails, it rewinds to after it parsed the last successful element and proceeds from the next field after the sequence. - -- Use flags, replace flags, and add additional flags - - Add ex: `#[vark(flag="--target-machine", flag="-tm")]` to a _field_. - - If the field was optional, this will replace the default flag. If the field was non-optional, this will make it require a flag instead of being positional. - -- Rename enum variant keys - - Add ex: `#[vark(name="my-variant")]` to a _variant_. - - This changes the command line key used to select a variant. - -- Prevent recursion in help - - Add `#[vark(break_help)]` to a _type_, _field_, or _variant_ to prevent recursing into any of the children when displaying help. This is useful for subcommand enums - attach this to the enum and it will list the variants but not the variants' arguments (unless you do `-h` after specifying one on the command line). - -- Change the help placeholder string - - Add `#[vark(placeholder="TARGET-MACHINE")]` to a _type_, _field_, or _variant_. - - This is the capitalized text (like XYZ) after an option that basically means "see XYZ section for more details" diff --git a/crates/aargvark/readme.md b/crates/aargvark/readme.md new file mode 120000 index 0000000..2e75a7b --- /dev/null +++ b/crates/aargvark/readme.md @@ -0,0 +1 @@ +../../readme.md \ No newline at end of file diff --git a/crates/aargvark/crates/aargvark/src/base.rs b/crates/aargvark/src/base.rs similarity index 100% rename from crates/aargvark/crates/aargvark/src/base.rs rename to crates/aargvark/src/base.rs diff --git a/crates/aargvark/crates/aargvark/src/help.rs b/crates/aargvark/src/help.rs similarity index 100% rename from crates/aargvark/crates/aargvark/src/help.rs rename to crates/aargvark/src/help.rs diff --git a/crates/aargvark/crates/aargvark/src/lib.rs b/crates/aargvark/src/lib.rs similarity index 100% rename from crates/aargvark/crates/aargvark/src/lib.rs rename to crates/aargvark/src/lib.rs diff --git a/crates/aargvark/crates/aargvark/src/traits_impls.rs b/crates/aargvark/src/traits_impls.rs similarity index 100% rename from crates/aargvark/crates/aargvark/src/traits_impls.rs rename to crates/aargvark/src/traits_impls.rs diff --git a/crates/aargvark/crates/aargvark_proc_macros/Cargo.toml b/crates/aargvark_proc_macros/Cargo.toml similarity index 69% rename from crates/aargvark/crates/aargvark_proc_macros/Cargo.toml rename to crates/aargvark_proc_macros/Cargo.toml index 29f9d04..cc5dfbc 100644 --- a/crates/aargvark/crates/aargvark_proc_macros/Cargo.toml +++ b/crates/aargvark_proc_macros/Cargo.toml @@ -4,9 +4,8 @@ description = "Helper crate for aargvark" version = "3.2.5" edition.workspace = true license.workspace = true -homepage.workspace = true -repository.workspace = true -readme.workspace = true +repository = "https://github.com/andrewbaxter/aargvark" +readme = "../../readme_aargvark.md" [lib] proc-macro = true @@ -14,7 +13,7 @@ proc-macro = true [dependencies] convert_case = "0.6" darling = "0.20" -genemichaels-lib = "0.5" +genemichaels-lib = "=0.5.4" proc-macro2 = "1" quote = "1" syn = "2" diff --git a/crates/aargvark/crates/aargvark_proc_macros/src/lib.rs b/crates/aargvark_proc_macros/src/lib.rs similarity index 100% rename from crates/aargvark/crates/aargvark_proc_macros/src/lib.rs rename to crates/aargvark_proc_macros/src/lib.rs diff --git a/crates/aargvark/crates/aargvark_tests/Cargo.toml b/crates/aargvark_tests/Cargo.toml similarity index 80% rename from crates/aargvark/crates/aargvark_tests/Cargo.toml rename to crates/aargvark_tests/Cargo.toml index 5b8a110..7c2b71c 100644 --- a/crates/aargvark/crates/aargvark_tests/Cargo.toml +++ b/crates/aargvark_tests/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "aargvark_tests" publish = false +edition.workspace = true [dependencies] aargvark = { path = "../aargvark" } diff --git a/crates/aargvark/crates/aargvark_tests/tests/test.rs b/crates/aargvark_tests/tests/test.rs similarity index 100% rename from crates/aargvark/crates/aargvark_tests/tests/test.rs rename to crates/aargvark_tests/tests/test.rs diff --git a/crates/genemichaels-lib/Cargo.toml b/crates/genemichaels-lib/Cargo.toml index 6980370..53c23b2 100644 --- a/crates/genemichaels-lib/Cargo.toml +++ b/crates/genemichaels-lib/Cargo.toml @@ -4,8 +4,8 @@ description = "Makes your code formatty, the library" version = "0.5.4" edition.workspace = true license.workspace = true -repository.workspace = true -readme.workspace = true +repository = "https://github.com/andrewbaxter/genemichaels" +readme = "../../readme_genemichaels.md" [dependencies] markdown = { version = "=1.0.0-alpha.21" } diff --git a/crates/genemichaels-lib/src/lib.rs b/crates/genemichaels-lib/src/lib.rs index 777c7f1..eb39ebe 100644 --- a/crates/genemichaels-lib/src/lib.rs +++ b/crates/genemichaels-lib/src/lib.rs @@ -138,7 +138,7 @@ pub(crate) fn line_length(out: &MakeSegsState, lines: &Lines, line_i: LineIdx) - SegmentContent::Text(t) => len += t.chars().count(), SegmentContent::Break(b, _) => { if out.nodes.get(seg.node.0).unwrap().split { - len += b.get(); + len += b.get(&out.config); } }, SegmentContent::Whitespace(_) => { }, @@ -186,11 +186,11 @@ pub(crate) fn split_line_at( match &seg.content { SegmentContent::Break(a, activate) => { if *activate { - a.activate(); + a.activate(&out.config); } }, SegmentContent::Whitespace((a, _)) => { - a.activate(); + a.activate(&out.config); }, _ => { }, }; @@ -261,20 +261,20 @@ impl Alignment { }))) } - pub(crate) fn activate(&self) -> usize { + pub(crate) fn activate(&self, config: &FormatConfig) -> usize { self.0.borrow_mut().active = true; - self.get() + self.get(config) } - pub(crate) fn get(&self) -> usize { + pub(crate) fn get(&self, config: &FormatConfig) -> usize { let parent = match &self.0.as_ref().borrow().parent { - Some(p) => p.get(), + Some(p) => p.get(config), None => { return 0usize; }, }; if self.0.as_ref().borrow_mut().active { - 4usize + parent + config.indent_spaces + parent } else { parent } @@ -472,6 +472,7 @@ pub struct FormatConfig { pub comment_width: Option, pub comment_errors_fatal: bool, pub keep_max_blank_lines: usize, + pub indent_spaces: usize, } impl Default for FormatConfig { @@ -485,6 +486,7 @@ impl Default for FormatConfig { comment_width: Some(80usize), comment_errors_fatal: false, keep_max_blank_lines: 0, + indent_spaces: 4, } } } @@ -738,11 +740,11 @@ pub fn format_ast( break 'continue_lineloop; } if *activate { - b.activate(); + b.activate(&config); } if segs.len() > 1 { // if empty line (=just break), don't write indent - push!(&" ".repeat(b.get())); + push!(&" ".repeat(b.get(&config))); } }, SegmentContent::Whitespace((b, whitespaces)) => { @@ -760,7 +762,7 @@ pub fn format_ast( if comment_i > 0 { push!("\n"); } - let prefix = format!("{}//{} ", " ".repeat(b.get()), match comment.mode { + let prefix = format!("{}//{} ", " ".repeat(b.get(&config)), match comment.mode { CommentMode::Normal => "", CommentMode::DocInner => "!", CommentMode::DocOuter => "/", diff --git a/crates/genemichaels/Cargo.toml b/crates/genemichaels/Cargo.toml index 68d9922..763bcef 100644 --- a/crates/genemichaels/Cargo.toml +++ b/crates/genemichaels/Cargo.toml @@ -4,15 +4,15 @@ description = "Makes your code formatty" version = "0.5.7" edition.workspace = true license.workspace = true -repository.workspace = true -readme.workspace = true +repository = "https://github.com/andrewbaxter/genemichaels" +readme = "../../readme_genemichaels.md" [dependencies] syn = { workspace = true } walkdir = "2" threadpool = "1" cargo-manifest = "0.15" -aargvark = { version = "0.6" } +aargvark = { version = "=0.6.5" } console = "0.15" loga = "0.5" serde = { workspace = true } diff --git a/readme.md b/readme.md index a75d4a5..50063e2 100644 --- a/readme.md +++ b/readme.md @@ -1,151 +1,3 @@ -# Gene Michaels +This repo contains the Rust source code formatter [`genemichaels`](./readme_genemichaels.md) and [`aargvark`](./readme_aargvark.md). -Status: **Delta** (the one after gamma). I've been using it for years without major issue, and I've tested against various code bases and doesn't blow them up. I think other people might use it too! Right now post-formatting pre-writing it re-parses and confirms all comments are consumed as safety checks. Also files over 500kb may take all your memory and invoke the OOM killer. - -- formats everything -- doesn't not format some things -- this is a haiku - -Named after Gene Michaels. - -Everything includes macros and comments. Dog fooded in this repo. - -### Differences to Rustfmt - -- This formats all macros, Rustfmt only formats macros under certain conditions -- This is fully deterministic, Rustfmt keeps certain stylistic choices like -- Rustfmt has [several](https://github.com/rust-lang/rustfmt/issues/3863) [restrictions](https://github.com/rust-lang/rustfmt/issues/2896) in what it formats normally, this always formats everything (if it doesn't it's a bug) -- This also reformats comments per Markdown rules - -# Usage - -Run `cargo install genemichaels`. - -Running `genemichaels` will by default format all files in the current package (looking at `Cargo.toml` in the current directory). You can also pass in a list of filenames to format. - -## VS Code - -If you're using VS Code, add the setting: - -``` - "rust-analyzer.rustfmt.overrideCommand": [ - "${userHome}/.cargo/bin/genemichaels", "--stdin" - ] -``` - -to use it with reckless abandon. - -## Configuration - -The configuration file is optional with (I think) sane defaults if not provided. A default config file named `.genemichaels.json` in the same directory as `Cargo.toml` or the current directory if not in a project will be used. - -The config contains parameters that tweak the formatting output, suitable for establishing a convention for a project. Things that don't affect the output (thread count, verbosity, etc) are command line arguments instead. - -The configuration file is json, but it will strip lines starting with `//` first if you want to add comments. - -Here's the config file. All values shown are defaults and the keys can be omitted if the default works for you. - -```jsonc -{ - // Ideal maximum line width. If there's an unbreakable element the line won't be split. - "max_width": 120, - // When breaking a child element, also break all parent elements. - "root_splits": false, - // Break a `()` or `{}` if it has greater than this number of children. Set to `null` to - // disable breaking due to high child counts. - "split_brace_threshold": 1, - // Break a `#[]` on a separate line before the element it's associated with. - "split_attributes": true, - // Put the `where` clause on a new line. - "split_where": true, - // Maximum relative line length for comments (past the comment indentation level). Can be - // `null` to disable relative wrapping. If disabled, still wraps at `max_width`. - "comment_width": 80, - // If reformatting comments results in an error, abort formatting the document. - "comment_errors_fatal": false, - // Genemichaels will replace line breaks with it's own deterministic line breaks. You can - // use this to keep extra line breaks (1 will keep up to 1 extra line break) during comment - // extraction. This is unused during formatting. - "keep_max_blank_lines": 0 -} -``` - -## Disabling formatting for specific comments - -Since comments are assumed to be markdown they will be formatted per markdown rules. To disable this for certain comments, start the comment with `//.` like - -``` -//. fn main() { -//. println!("hi"); -//. } -``` - -## Disabling formatting for specific files - -To skip specific files, in the first 5 lines of the source add a comment containing `nogenemichaels`, ex: - -```rust -// nogenemichaels -... -``` - -# Programmatic usage - -Do `cargo add genemichaels` - -There are three main functions: - -- `genemichaels::format_str` - formats a string (full rust source file, doesn't support snippets at the moment). -- `genemichaels::format_ast` - formats AST element (implements `genemichaels::Formattable`, most `syn::*` structs do). Comments need to be passed in separately, if you have any. -- `genemichaels::extract_comments` - takes a string of source code and extracts comments, mapping each comment to the start of a syntax element - -If you want to format a `TokenStream`, parse it into an AST with `syn::parse2::(token_stream)` then call `format_ast`. - -The format functions also return lost comments - comments not formatted/added to the formatted source after processing. In an ideal world this wouldn't exist, but right now comments are added on a case by case basis and not all source tokens support comments. - -# How it works - -At a very high level: - -- The syntax tree is converted into a linear list of segments, where each segment is a member of exactly one "split group". A split group has a single boolean switch of state: split or not split. - - For instance, a split group for `match {}` might have segments `match` `{` `` and `}`. These segments are interleaved with other groups' segments, for instance other segments may come between `{` and `}`. - - All split groups start in the not split state. - - When a split group split state is toggled, `` and everything after it on that line are moved to a new line after the line they were on. - -The algorithm basically wraps nodes until all lines are less than the max line width. - -This was a simplified explanation; there are a few other factors: - -- Alignments -- Segments that change depending on whether their group is split or not (i.e. the `` above which only breaks the line when the group is split, vs unconditional breaks) - -## Multi-threading - -By default Gene Michaels formats multiple files on all available cores, but this uses proportionally more memory. If you have a project with particularly large files you can restrict to a smaller number of cores in the configuration. - -## Comments - -Comments deserve a special mention since they're handled out of band. - -`syn` doesn't parse comments (except sometimes) so all the comments are extracted at the start of processing. Generally comments are associated with the next syntax element, except for end of line `//` comments which get associated with the first syntax element on the current line. - -When building split groups, if the current syntax element has a token with a line/column matching an extracted comment, the comment is added to the split group. - -## Macros - -Macros are formatted with a couple tricks: - -1. If it parses as rust code (either an expression or statement list), it's formatted normally. -2. If it doesn't, it's split by `;` and `,` since those are usually separators, then the above is tried for each chunk. -3. Otherwise each token in the macro is concatenated with spaces (with a couple other per-case tweaks) - -Formatting end user use of macros is prioritized over formatting `macro_rules`, since macros are used more than they're defined. Most macros look like normalish Rust syntax so many of the normal formatting rules can be used. - -## Q&A - -See [this Reddit post](https://www.reddit.com/r/rust/comments/zo54gj/gene_michaels_alternative_rust_code_formatter/) for many questions and answers. - -For other questions or bug reports, etc. please use issues and/or discussions here. +They're colocated because of interwtined dependencies and having a single repo makes releasing easier. diff --git a/readme_aargvark.md b/readme_aargvark.md new file mode 100644 index 0000000..fbee4b6 --- /dev/null +++ b/readme_aargvark.md @@ -0,0 +1,138 @@ + + + +
crates.iodocs.rs
+ +A simple and consistent derive-based command line argument parsing, in the same genre as Clap-derive. It currently supports + +- Command line parsing +- Help + +Generally speaking this is intended to make CLI parsing simple by virtue of being simple and consistent, rather than poweruser-optimized keypress-minimizing parsing. + +This attempts to support parsing arbitrarily complex command line arguments. Like with Serde, you can combine structs, vecs, enums in any way you want. Just because you can doesn't mean you should. + +``` +$ ; This is an example help output, sans light ansi styling +$ spagh -h +Usage: spagh COMMAND [ ...FLAGS] + + A small CLI for querying, publishing, and administrating spaghettinuum. + + COMMAND: COMMAND + [--debug] + +COMMAND: ping | get | http | ssh | identity | publish | admin + + ping ... Simple liveness check + get ... Request values associated with provided identity and keys + from a resolver + http ... + ssh ... + identity ... Commands for managing identities + publish ... Commands for publishing data + admin ... Commands for node administration + +``` + +``` +$ spagh publish set -h +Usage: spagh publish set IDENTITY DATA + + IDENTITY: IDENTITY-SECRET-ARG Identity to publish as + DATA: | - Data to publish. Must be json in the + structure `{KEY: {"ttl": MINUTES, "value": + DATA}, ...}`. `KEY` is a string that's a + dotted list of key segments, with `/` to + escape dots and escape characters. + +IDENTITY-SECRET-ARG: local + + An identity with its associated secret. + + local A file containing a generated key + +``` + +# Why or why not + +Why this and not Clap? + +- It has a super-simple interface (just `#[derive(Aargvark)]` on any enum/structure) +- This parses more complex data types, like vectors of sub-structures, or enums +- It's more consistent + +Why not this? + +- It's newer, with fewer features and limited community ecosystem, extensions +- Some command line parsing conventions were discarded in order to simplify and maintain self-similarity. A lot of command line conventions are inconsistent or break down as you nest things, after all. +- Quirky CLI parsing generally isn't supported: Some tricks (like `-v` `-vv` `-vvv`) break patterns and probably won't ever be implemented. (Other things just haven't been implemented yet due to lack of time) + +# Conventions and usage + +To add it to your project, run + +```sh +cargo add aargvark +``` + +To parse command line arguments + +1. Define the data type you want to parse them into, like + + ```rust + /// General description for the command. + #[derive(Aargvark)] + struct MyArgs { + /// Field documentation. + velociraptor: String, + #[vark(flag = "-d", flag = "--deadly")] + deadly: bool, + color_pattern: Option, + } + ``` + +2. Vark it + ```rust + let args = vark::(); + ``` + +Non-optional fields become positional arguments unless you give them a flag with `#[vark(flag = "--flag")]`. Optional fields become optional (`--long`) arguments. If you want a `bool` flag that's enabled if the flag is specified (i.e. doesn't take a value), use `Option<()>`. + +You can derive structs, enums, and tuples, and there are implementations for `Vec`, `HashSet`, `Map` with `FromString` keys and values as `K=V` arguments, most `Ip` and `SocketAddr` types, and `PathBuf` built in. + +Some additional wrappers are provided for automatically loading (and parsing) files: + +- `AargvarkFile` +- `AargvarkJson` requires feature `serde_json` +- `AargvarkYaml` requires feature `serde_yaml` + +To parse your own types, implement `AargvarkTrait`, or if your type takes a single string argument you can implement `AargvarkFromStr` which is slightly simpler. + +# Advanced usage + +- Sequences, plural fields, Vecs + + Sequence elements are space separated. The way sequence parsing works is it attempts to parse as many elements as possible. When parsing one element fails, it rewinds to after it parsed the last successful element and proceeds from the next field after the sequence. + +- Use flags, replace flags, and add additional flags + + Add ex: `#[vark(flag="--target-machine", flag="-tm")]` to a _field_. + + If the field was optional, this will replace the default flag. If the field was non-optional, this will make it require a flag instead of being positional. + +- Rename enum variant keys + + Add ex: `#[vark(name="my-variant")]` to a _variant_. + + This changes the command line key used to select a variant. + +- Prevent recursion in help + + Add `#[vark(break_help)]` to a _type_, _field_, or _variant_ to prevent recursing into any of the children when displaying help. This is useful for subcommand enums - attach this to the enum and it will list the variants but not the variants' arguments (unless you do `-h` after specifying one on the command line). + +- Change the help placeholder string + + Add `#[vark(placeholder="TARGET-MACHINE")]` to a _type_, _field_, or _variant_. + + This is the capitalized text (like XYZ) after an option that basically means "see XYZ section for more details" diff --git a/readme_genemichaels.md b/readme_genemichaels.md new file mode 100644 index 0000000..93291d1 --- /dev/null +++ b/readme_genemichaels.md @@ -0,0 +1,153 @@ +# Gene Michaels + +Status: **Delta** (the one after gamma). I've been using it for years without major issue, and I've tested against various code bases and doesn't blow them up. I think other people might use it too! Right now post-formatting pre-writing it re-parses and confirms all comments are consumed as safety checks. Also files over 500kb may take all your memory and invoke the OOM killer. + +- formats everything +- doesn't not format some things +- this is a haiku + +Named after Gene Michaels. + +Everything includes macros and comments. Dog fooded in this repo. + +### Differences to Rustfmt + +- This formats all macros, Rustfmt only formats macros under certain conditions +- This is fully deterministic, Rustfmt keeps certain stylistic choices like +- Rustfmt has [several](https://github.com/rust-lang/rustfmt/issues/3863) [restrictions](https://github.com/rust-lang/rustfmt/issues/2896) in what it formats normally, this always formats everything (if it doesn't it's a bug) +- This also reformats comments per Markdown rules + +# Usage + +Run `cargo install genemichaels`. + +Running `genemichaels` will by default format all files in the current package (looking at `Cargo.toml` in the current directory). You can also pass in a list of filenames to format. + +## VS Code + +If you're using VS Code, add the setting: + +``` + "rust-analyzer.rustfmt.overrideCommand": [ + "${userHome}/.cargo/bin/genemichaels", "--stdin" + ] +``` + +to use it with reckless abandon. + +## Configuration + +The configuration file is optional with (I think) sane defaults if not provided. A default config file named `.genemichaels.json` in the same directory as `Cargo.toml` or the current directory if not in a project will be used. + +The config contains parameters that tweak the formatting output, suitable for establishing a convention for a project. Things that don't affect the output (thread count, verbosity, etc) are command line arguments instead. + +The configuration file is json, but it will strip lines starting with `//` first if you want to add comments. + +Here's the config file. All values shown are defaults and the keys can be omitted if the default works for you. + +```jsonc +{ + // Ideal maximum line width. If there's an unbreakable element the line won't be split. + "max_width": 120, + // When breaking a child element, also break all parent elements. + "root_splits": false, + // Break a `()` or `{}` if it has greater than this number of children. Set to `null` to + // disable breaking due to high child counts. + "split_brace_threshold": 1, + // Break a `#[]` on a separate line before the element it's associated with. + "split_attributes": true, + // Put the `where` clause on a new line. + "split_where": true, + // Maximum relative line length for comments (past the comment indentation level). Can be + // `null` to disable relative wrapping. If disabled, still wraps at `max_width`. + "comment_width": 80, + // If reformatting comments results in an error, abort formatting the document. + "comment_errors_fatal": false, + // Genemichaels will replace line breaks with it's own deterministic line breaks. You can + // use this to keep extra line breaks (1 will keep up to 1 extra line break) during comment + // extraction. This is unused during formatting. + "keep_max_blank_lines": 0, + // The number of spaces to indent by at each level. + "indent_spaces": 4, +} +``` + +## Disabling formatting for specific comments + +Since comments are assumed to be markdown they will be formatted per markdown rules. To disable this for certain comments, start the comment with `//.` like + +``` +//. fn main() { +//. println!("hi"); +//. } +``` + +## Disabling formatting for specific files + +To skip specific files, in the first 5 lines of the source add a comment containing `nogenemichaels`, ex: + +```rust +// nogenemichaels +... +``` + +# Programmatic usage + +Do `cargo add genemichaels` + +There are three main functions: + +- `genemichaels::format_str` - formats a string (full rust source file, doesn't support snippets at the moment). +- `genemichaels::format_ast` - formats AST element (implements `genemichaels::Formattable`, most `syn::*` structs do). Comments need to be passed in separately, if you have any. +- `genemichaels::extract_comments` - takes a string of source code and extracts comments, mapping each comment to the start of a syntax element + +If you want to format a `TokenStream`, parse it into an AST with `syn::parse2::(token_stream)` then call `format_ast`. + +The format functions also return lost comments - comments not formatted/added to the formatted source after processing. In an ideal world this wouldn't exist, but right now comments are added on a case by case basis and not all source tokens support comments. + +# How it works + +At a very high level: + +- The syntax tree is converted into a linear list of segments, where each segment is a member of exactly one "split group". A split group has a single boolean switch of state: split or not split. + + For instance, a split group for `match {}` might have segments `match` `{` `` and `}`. These segments are interleaved with other groups' segments, for instance other segments may come between `{` and `}`. + + All split groups start in the not split state. + + When a split group split state is toggled, `` and everything after it on that line are moved to a new line after the line they were on. + +The algorithm basically wraps nodes until all lines are less than the max line width. + +This was a simplified explanation; there are a few other factors: + +- Alignments +- Segments that change depending on whether their group is split or not (i.e. the `` above which only breaks the line when the group is split, vs unconditional breaks) + +## Multi-threading + +By default Gene Michaels formats multiple files on all available cores, but this uses proportionally more memory. If you have a project with particularly large files you can restrict to a smaller number of cores in the configuration. + +## Comments + +Comments deserve a special mention since they're handled out of band. + +`syn` doesn't parse comments (except sometimes) so all the comments are extracted at the start of processing. Generally comments are associated with the next syntax element, except for end of line `//` comments which get associated with the first syntax element on the current line. + +When building split groups, if the current syntax element has a token with a line/column matching an extracted comment, the comment is added to the split group. + +## Macros + +Macros are formatted with a couple tricks: + +1. If it parses as rust code (either an expression or statement list), it's formatted normally. +2. If it doesn't, it's split by `;` and `,` since those are usually separators, then the above is tried for each chunk. +3. Otherwise each token in the macro is concatenated with spaces (with a couple other per-case tweaks) + +Formatting end user use of macros is prioritized over formatting `macro_rules`, since macros are used more than they're defined. Most macros look like normalish Rust syntax so many of the normal formatting rules can be used. + +## Q&A + +See [this Reddit post](https://www.reddit.com/r/rust/comments/zo54gj/gene_michaels_alternative_rust_code_formatter/) for many questions and answers. + +For other questions or bug reports, etc. please use issues and/or discussions here.