{"id":13636633,"url":"https://github.com/etienne-napoleone/spinach","last_synced_at":"2025-10-30T20:48:03.812Z","repository":{"id":42633839,"uuid":"472748856","full_name":"etienne-napoleone/spinach","owner":"etienne-napoleone","description":"🥬 Practical spinner for Rust","archived":false,"fork":false,"pushed_at":"2025-10-20T09:25:01.000Z","size":147,"stargazers_count":116,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-20T11:25:05.782Z","etag":null,"topics":["cli","no-dependencies","rust","spinner","terminal-ui"],"latest_commit_sha":null,"homepage":"https://docs.rs/spinach/latest/spinach/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/etienne-napoleone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-03-22T12:03:03.000Z","updated_at":"2025-10-20T09:25:04.000Z","dependencies_parsed_at":"2025-05-06T23:46:18.938Z","dependency_job_id":"4e78de37-b2cb-4b5a-b255-218fe422ee3b","html_url":"https://github.com/etienne-napoleone/spinach","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/etienne-napoleone/spinach","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etienne-napoleone%2Fspinach","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etienne-napoleone%2Fspinach/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etienne-napoleone%2Fspinach/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etienne-napoleone%2Fspinach/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/etienne-napoleone","download_url":"https://codeload.github.com/etienne-napoleone/spinach/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etienne-napoleone%2Fspinach/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281881917,"owners_count":26577704,"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","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cli","no-dependencies","rust","spinner","terminal-ui"],"created_at":"2024-08-02T00:01:03.539Z","updated_at":"2025-10-30T20:48:03.804Z","avatar_url":"https://github.com/etienne-napoleone.png","language":"Rust","funding_links":[],"categories":["Libraries","库 Libraries"],"sub_categories":["Command-line","命令行 Command-line"],"readme":"# 🥬 spinach\n\n[![Crates.io](https://img.shields.io/crates/v/spinach)](https://crates.io/crates/spinach)\n[![Docs.rs](https://img.shields.io/docsrs/spinach)](https://docs.rs/spinach)\n[![License](https://img.shields.io/crates/l/spinach)](LICENSE)\n[![CI](https://github.com/etienne-napoleone/spinach/actions/workflows/ci.yml/badge.svg)](https://github.com/etienne-napoleone/spinach/actions/workflows/ci.yml)\n\n\u003e Practical spinner for Rust — `v3` now with method chaining\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"https://raw.githubusercontent.com/etienne-napoleone/spinach/main/assets/screenshot.gif\" width=\"550px\" height=\"399px\"\u003e\n\u003c/p\u003e\n\n## Install\n\nAdd as a dependency to your `Cargo.toml`.\n\n```toml\n[dependencies]\nspinach = \"3\"\n```\n\n## Usage\n\nBasic example.\n\n```rust\nuse spinach::Spinner;\n\nfn main() {\n\t// Cut spinaches\n    let s = Spinner::new(\"Cutting spinaches...\").start();\n\t// Cut tomatoes\n    s.text(\"Cutting tomatoes...\").update();\n\t// We're done!\n\ts.text(\"Vegetables cut\").symbol(\"🔪\").stop();\n}\n```\n\n### Starting\n\n```rust\nuse spinach::{Color, Spinner};\n\n// With custom text\nlet s = Spinner::new(\"workin'...\").start();\n\n// With custom text, spinner, spinner speed and spinner color\nlet symbols = vec![\"▮\",\"▯\"];\nlet s = Spinner::new(\"blip... blop...\")\n    .color(Color::Red)\n    .symbols(symbols)\n    .frames_duration(80)\n    .start();\n```\n\n### Updating\n\n```rust\nuse spinach::{Color, Spinner};\n\nlet s = Spinner::new(\"workin'...\").start();\n\n// Updating text\ns.text(\"new text\").update();\n\n// Updating color\ns.color(Color::White).update();\n\n// Updating spinner symbols\ns.symbols(vec![\"◐\", \"◓\", \"◑\", \"◒\"]).update();\n\n// Updating spinner speed\ns.frames_duration(80).update();\n\n// Updating multiple at once\ns.text(\"new text\").color(Color::Red).update();\n```\n\n### Stopping\n\n```rust\nuse spinach::{Color, Spinner};\n\nlet s = Spinner::new(\"workin'...\").start();\n\n// Stop with final `✔` frame and green color.\ns.text(\"gg!\").success();\n\n// Stop with final `✖` frame and red color.\ns.text(\"ups\").failure();\n\n// Stop with final `⚠` frame and yellow color.\ns.text(\"something may have happened?\").warn();\n\n// Stop with without further modification (outside of chained updates).\ns.text(\"notice\").stop();\n\n// Stop current spinner (sends update at the same time)\ns.stop(); // freeze\ns.text(\"spinach'd\").symbol(\"🥬\").stop(); // stop with the text \"spinach'd\" and a vegetable as the spinner\n```\n\n## FAQ\n\n### How to avoid leaving terminal without prompt on interupt (ctrl^c)?\n\nYou can use a library like [`ctrlc`](https://crates.io/crates/ctrlc) to handle interupts.\n\nThe most basic way to handle it would be in conjuction with this lib QoL `show_cursor` function like this:\n\n```rust\nuse spinach::{show_cursor, Spinner};\n\nfn main() {\n    ctrlc::set_handler(|| {\n        show_cursor();\n        std::process::exit(0);\n    })\n    .expect(\"Error setting Ctrl-C handler\");\n\n    let s = Spinner::new(\"workin'...\").start();\n    // ...\n```\n\n## Related\n\nInspired by:\n\n- [ora](https://github.com/sindresorhus/ora)\n- [spinners](https://github.com/FGRibreau/spinners)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetienne-napoleone%2Fspinach","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fetienne-napoleone%2Fspinach","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetienne-napoleone%2Fspinach/lists"}