{"id":15401132,"url":"https://github.com/sunfishcode/nameless","last_synced_at":"2025-04-05T07:01:14.844Z","repository":{"id":40793202,"uuid":"307599473","full_name":"sunfishcode/nameless","owner":"sunfishcode","description":"Full-service command-line parsing","archived":false,"fork":false,"pushed_at":"2025-03-07T05:56:03.000Z","size":320,"stargazers_count":70,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-04T06:07:21.562Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunfishcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-27T05:58:45.000Z","updated_at":"2025-03-30T00:47:25.000Z","dependencies_parsed_at":"2024-10-20T11:17:55.924Z","dependency_job_id":null,"html_url":"https://github.com/sunfishcode/nameless","commit_stats":{"total_commits":224,"total_committers":1,"mean_commits":224.0,"dds":0.0,"last_synced_commit":"7f683084a670569714d7e3f1f28dd60caedf770c"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunfishcode%2Fnameless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunfishcode%2Fnameless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunfishcode%2Fnameless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunfishcode%2Fnameless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunfishcode","download_url":"https://codeload.github.com/sunfishcode/nameless/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299828,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T15:56:34.662Z","updated_at":"2025-04-05T07:01:14.682Z","avatar_url":"https://github.com/sunfishcode.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\u003ccode\u003enameless\u003c/code\u003e\u003c/h1\u003e\n\n  \u003cp\u003e\n    \u003cstrong\u003eFull-service command-line parsing\u003c/strong\u003e\n  \u003c/p\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/sunfishcode/nameless/actions?query=workflow%3ACI\"\u003e\u003cimg src=\"https://github.com/sunfishcode/nameless/workflows/CI/badge.svg\" alt=\"Github Actions CI Status\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/nameless\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/nameless.svg\" alt=\"crates.io page\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/nameless\"\u003e\u003cimg src=\"https://docs.rs/nameless/badge.svg\" alt=\"docs.rs docs\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://bytecodealliance.zulipchat.com/#narrow/stream/219900-wasi\"\u003e\u003cimg src=\"https://img.shields.io/badge/zulip-join_chat-brightgreen.svg\" alt=\"zulip chat\" /\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n*This is currently an experimental project, and the API and command-line\nargument syntax are not currently stable.*\n\nNameless provides full-service command-line parsing. This means you just write\na `main` function with arguments with the types you want, add a [conventional]\ndocumentation comment, and it takes care of the rest:\n\nRust code:\n```rust\nuse nameless::{InputByteStream, OutputByteStream};\nuse std::io::{self, Read, Write};\n\n/// A simple program with input and output\n///\n/// # Arguments\n///\n/// * `input` - Input source\n/// * `output` - Output sink\n#[kommand::main]\nfn main(mut input: InputByteStream, mut output: OutputByteStream) -\u003e io::Result\u003c()\u003e {\n    let mut s = String::new();\n    input.read_to_string(\u0026mut s)?;\n    output.write_all(s.as_bytes())\n}\n```\n\nCargo.toml:\n```toml\n[dependencies]\nkommand = \"0\"\nnameless = \"0\"\n```\n\nNameless completely handles \"string to stream\" translation. And in doing so, it\ndoesn't just support files, but also gzipped files (`*.gz`),\nstdin/stdout (`-`), child processes (`$(...)`) (not yet on Windows tho), and\nURLs, including `http:`, `https:`, `scp:` (enable the \"ssh2\" feature), `file:`,\nand `data:`. And on output, nameless automatically takes care of piping data\nthrough [`bat`](https://crates.io/crates/bat) for syntax highlighting and\npaging. So while your code is busy doing one thing and doing it well, nameless\ntakes care of streaming the data in and out.\n\n\"Everything is a URL, and more\", on Linux, macOS, Windows, and more.\n\n`kommand::main` parses the documentation comment to extract the program\ndescription and the arguments. The command-line usage for the example above\nlooks like this:\n\n```\n$ cargo run -- --help\nsimple-filter 0.0.0\nA simple program with input and output\n\nUSAGE:\n    simple-filter \u003cinput\u003e \u003coutput\u003e\n\nFLAGS:\n    -h, --help       Prints help information\n    -V, --version    Prints version information\n\nARGS:\n    \u003cinput\u003e     Input source\n    \u003coutput\u003e    Output sink\n```\n\n## More features\n\n`kommand` is a wrapper around `clap_derive`, and supports the same attributes.\n\nTo add a flag, for example, `#[kommand(short = 'n', long)] number: u32` means\nan argument with type `i32` which can be specified with `-n` or `--number` on\nthe command line. The [grep example] and [basic example] show examples of this.\n\nThe [clap-v3 documentation] for the full list of available features.\n\n## What's inside\n\nThis library provides:\n\n - New stream types, [`InputByteStream`], [`OutputByteStream`], and\n   [`InteractiveByteStream`] for working with byte streams, and\n   [`InputTextStream`], [`OutputTextStream`], and [`InteractiveTextStream`]\n   for working with text streams. These implement [`Read`] and [`Write`] in\n   the usual way, so they interoperate with existing Rust code.\n\n   You can use all these types in type-aware command-line parsing packages\n   such as [`nameless-clap_derive`] or this library's own [`kommand`].\n   (`nameless-clap_derive` is a temporary fork of [`clap_derive`]; we are\n   in the process of upstreaming our patches).\n\n - A new command-line parsing package, [`kommand`], which is similar to\n   to [`paw`], but uses function argument syntax instead of having an options\n   struct. Command-line arguments can use any type which implements the standard\n   `FromStr` trait, including builtin types like `i32` or `bool` or library\n   types like [`Regex`] or [`Duration`]. See [the examples directory] for\n   more examples.\n\n## Why \"nameless\"?\n\nThe name \"nameless\" refers to how, from the program's perspective, the string\nnames of the inputs and outputs are hidden by the library.\n\nOf course, sometimes you do want to know the name of an input, such as to\ndisplay it in an error message. Nameless's [`pseudonym`] mechanism provides\nnames for [`InputByteStream`] and other stream types, which allow the name\nto be displayed without exposing it to the application.\n\nAnd sometimes you want to know an input file's extension, to determine what\ntype of input it is. [`InputByteStream`] and other stream types have a\n[`media_type`] function which returns the [media type] (aka MIME type). If the\ninput is a file, the type is inferred from the extension; if it's an HTTP\nstream, the type is inferred from the `Content-Type` header, and so on.\n\nWhy is it important to hide the name? On a theoretical level, most\ncomputations shouldn't care about where data is coming from or where it's\ngoing. This helps separate the concerns of what the program primarily does\nand how the program interacts with the local organization of resources.\nOn a practical level, this is what makes it possible for nameless to\ntransparently support URLs, child processes, and other things. And, it will\nsupport applications which are useful on conventional platforms, but which\nalso work on platforms that lack filesystems, such as embedded systems or\nsystems with new kinds of storage abstractions.\n\nHiding the names also helps programs avoid accidentally having behavior that\ndepends on the names of files it accesses, which is a common source of trouble\nin deterministic-build environments.\n\n## Data URLs\n\n[`data:` URLs] aren't as widely known, but are cool and deserve special\nmention. They carry a payload string in the URL itself which produced as the\ninput stream. For example, opening `data:,Hello%2C%20World!` produces an\ninput stream that reads the string \"Hello, World!\". Payloads can also be\nbase64 encoded, like this: `data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==`.\nSo you can pass a literal string directly into a program's input stream\ninstead of creating a temporary file.\n\n## Looking forward\n\nNameless is actively evolving! Watch this space for much more to come, and\n[chat with us in Zulip], if you're interested in where we're going.\n\n## Literary reference\n\n\u003e ‘This must be the wood,’ she said thoughtfully to herself, ‘where things\n\u003e have no names.’\n\n— \u003ccite\u003e\"Through the Looking Glass\", by Lewis Carroll\u003c/cite\u003e\n\n[conventional]: https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html\n[basic example]: https://github.com/sunfishcode/nameless/blob/main/examples/basic.rs\n[grep example]: https://github.com/sunfishcode/nameless/blob/main/examples/grep.rs\n[clap-v3 documentation]: https://docs.rs/clap-v3/latest/clap_v3/\n[`nameless-clap_derive`]: https://crates.io/crates/nameless-clap_derive\n[`clap_derive`]: https://crates.io/crates/clap_derive\n[`paw`]: https://crates.io/crates/paw\n[`kommand`]: https://crates.io/crates/kommand\n[`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html\n[`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html\n[`InputByteStream`]: https://docs.rs/nameless/latest/nameless/struct.InputByteStream.html\n[`OutputByteStream`]: https://docs.rs/nameless/latest/nameless/struct.OutputByteStream.html\n[`InteractiveByteStream`]: https://docs.rs/nameless/latest/nameless/struct.InteractiveByteStream.html\n[`InputTextStream`]: https://docs.rs/nameless/latest/nameless/struct.InputTextStream.html\n[`OutputTextStream`]: https://docs.rs/nameless/latest/nameless/struct.OutputTextStream.html\n[`InteractiveTextStream`]: https://docs.rs/nameless/latest/nameless/struct.InteractiveTextStream.html\n[`Regex`]: https://docs.rs/regex/latest/regex/struct.Regex.html\n[`Duration`]: https://docs.rs/humantime/latest/humantime/struct.Duration.html\n[the examples directory]: examples\n[`data:` URLs]: https://fetch.spec.whatwg.org/#data-urls\n[`pseudonym`]: https://docs.rs/nameless/latest/nameless/struct.InputByteStream.html#method.pseudonym\n[media type]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types\n[`media_type`]: https://docs.rs/nameless/latest/nameless/struct.InputByteStream.html#method.media_type\n[chat with us in Zulip]: https://bytecodealliance.zulipchat.com/#narrow/stream/219900-wasi\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunfishcode%2Fnameless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunfishcode%2Fnameless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunfishcode%2Fnameless/lists"}