Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e64f7efca6 | |||
| 7bfb750f63 | |||
| 7433df5d74 | |||
| 2361be73ba | |||
| 5f8a34142e | |||
| 36c081c2ce | |||
| 4ee3cd6b85 | |||
| 5b9865382e | |||
| 6241531ce9 | |||
| 2196517709 | |||
| 7a2b2ba744 | |||
| 4b7c92ba4b | |||
| 9cf9985973 | |||
| 18bb479415 | |||
| b667cc8ad6 | |||
| e838166b16 | |||
| 43e1dc1067 | |||
| cc5d7570fb | |||
| b05d9c44b4 | |||
| 2995c78e66 | |||
| 1d89f237db | |||
| 75cde60494 | |||
| fa71dfb84e | |||
| c147a2ffc6 | |||
| 9cc0f9a111 | |||
| 0aa7731c17 | |||
| 255dd3e630 | |||
| 7100f7a682 | |||
| 68cb804ccf | |||
| e9b65287a3 | |||
| 5ff0a8d49a | |||
| 635fbfff01 | |||
| 13e56f621b | |||
| 9500e8c0aa | |||
| e5ba2b3be9 | |||
| e78e60da3d | |||
| 809b9c34f4 | |||
| 352a1ba086 | |||
| b81d5fed1b | |||
| f32e2df4fa | |||
| abcc1d265b | |||
| 25824da0e0 | |||
| 5e0f1ee909 | |||
| 62b0fd959f | |||
| 9a66c10afd | |||
| 62fdc22c00 | |||
| 1fdcfa66b8 | |||
| d08a0745a5 | |||
| 4ee5344209 | |||
| 26030b0628 | |||
| 9b376f97c0 | |||
| 2dc18050ca | |||
| e816235637 | |||
| 8046e9bab3 | |||
| e03cda1475 | |||
| 20e5fb3f89 | |||
| e253a75924 | |||
| 2252fc36e7 | |||
| 4e23243384 | |||
| f6dc68d7dc | |||
| f947373a23 | |||
| 5b745cde01 | |||
| 1afbd66355 | |||
| 2fe21deea8 | |||
| 37a19901bb | |||
| 063679b72d | |||
| 264cf11690 | |||
| 6280d370bc | |||
| 6cfc337d83 | |||
| 533de96e80 | |||
| dee984f931 | |||
| 959d42ee9c | |||
| eb349aa1aa | |||
| d5751e06af | |||
| 981602b690 | |||
| a8d752aa9f | |||
| c57e8a4a49 | |||
| 67ae918ae8 | |||
| e788f93c2b | |||
| 75a2e9d8d3 | |||
| 23888c0e3e | |||
| e5ad9e564d | |||
| 328381b336 | |||
| 28a181d97b | |||
| bb514f8fd9 | |||
| b585ee1e26 | |||
| de2141347e | |||
| ba88581ed4 | |||
| 932042b62c | |||
| f5c5e31691 | |||
| 15ca855a04 | |||
| 666d2dc90a | |||
| 34583294c6 | |||
| 03615ab4ee | |||
| c722c73e79 | |||
| 8f5199974b | |||
| 8168877fb1 | |||
| 4e20b18d45 | |||
| 5dc1709f58 | |||
| fb1e35172e | |||
| fc9292be3f | |||
| 3f41cb40e2 | |||
| 729024a45f | |||
| ef1407d00e | |||
| 075fc467d2 |
Generated
+310
-351
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "2.0.2"
|
version = "2.1.0"
|
||||||
authors = ["Azalea Gui <azalea@hydev.org>"]
|
authors = ["Azalea Gui <azalea@hydev.org>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.75.0"
|
rust-version = "1.75.0"
|
||||||
@@ -17,14 +17,14 @@ ansi_colours = { version = "1.2.2", default-features = false }
|
|||||||
anstream = { version = "0.6.14", default-features = false }
|
anstream = { version = "0.6.14", default-features = false }
|
||||||
anyhow = { version = "1.0.86", default-features = false }
|
anyhow = { version = "1.0.86", default-features = false }
|
||||||
bpaf = { version = "0.9.12", default-features = false }
|
bpaf = { version = "0.9.12", default-features = false }
|
||||||
crossterm = { version = "0.27.0", default-features = false }
|
crossterm = { version = "0.29.0", default-features = false }
|
||||||
deranged = { version = "0.3.11", default-features = false }
|
deranged = { version = "0.3.11", default-features = false }
|
||||||
directories = { version = "5.0.1", default-features = false }
|
directories = { version = "6.0.0", default-features = false }
|
||||||
enable-ansi-support = { version = "0.2.1", default-features = false }
|
enable-ansi-support = { version = "0.2.1", default-features = false }
|
||||||
enterpolation = { version = "0.2.1", default-features = false }
|
enterpolation = { version = "0.2.1", default-features = false }
|
||||||
fastrand = { version = "2.1.0", default-features = false }
|
fastrand = { version = "2.1.0", default-features = false }
|
||||||
indexmap = { version = "2.2.6", default-features = false }
|
indexmap = { version = "2.2.6", default-features = false }
|
||||||
itertools = { version = "0.13.0", default-features = false }
|
itertools = { version = "0.14.0", default-features = false }
|
||||||
normpath = { version = "1.2.0", default-features = false }
|
normpath = { version = "1.2.0", default-features = false }
|
||||||
palette = { version = "0.7.6", default-features = false }
|
palette = { version = "0.7.6", default-features = false }
|
||||||
regex = { version = "1.10.5", default-features = false }
|
regex = { version = "1.10.5", default-features = false }
|
||||||
@@ -33,14 +33,14 @@ serde = { version = "1.0.203", default-features = false }
|
|||||||
serde_json = { version = "1.0.118", default-features = false }
|
serde_json = { version = "1.0.118", default-features = false }
|
||||||
serde_path_to_error = { version = "0.1.16", default-features = false }
|
serde_path_to_error = { version = "0.1.16", default-features = false }
|
||||||
shell-words = { version = "1.1.0", default-features = false }
|
shell-words = { version = "1.1.0", default-features = false }
|
||||||
strum = { version = "0.26.3", default-features = false }
|
strum = { version = "0.27.2", default-features = false }
|
||||||
supports-color = { version = "3.0.0", default-features = false }
|
supports-color = { version = "3.0.0", default-features = false }
|
||||||
tempfile = { version = "3.10.1", default-features = false }
|
tempfile = { version = "3.10.1", default-features = false }
|
||||||
terminal-colorsaurus = { version = "0.4.3", default-features = false }
|
terminal-colorsaurus = { version = "1.0.0", default-features = false }
|
||||||
terminal_size = { version = "0.3.0", default-features = false }
|
terminal_size = { version = "0.4.3", default-features = false }
|
||||||
thiserror = { version = "1.0.61", default-features = false }
|
thiserror = { version = "1.0.61", default-features = false }
|
||||||
time = { version = "0.3.36", default-features = false }
|
time = { version = "0.3.36", default-features = false }
|
||||||
toml_edit = { version = "0.22.16", default-features = false }
|
toml_edit = { version = "0.23.6", default-features = false }
|
||||||
tracing = { version = "0.1.40", default-features = false }
|
tracing = { version = "0.1.40", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3.18", default-features = false }
|
tracing-subscriber = { version = "0.3.18", default-features = false }
|
||||||
unicode-normalization = { version = "0.1.23", default-features = false }
|
unicode-normalization = { version = "0.1.23", default-features = false }
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
include hyfetch/scripts/*
|
|
||||||
|
|
||||||
recursive-exclude tools *
|
|
||||||
recursive-exclude .github *
|
|
||||||
recursive-exclude .vscode *
|
|
||||||
exclude .gitignore
|
|
||||||
exclude .gitattributes
|
|
||||||
exclude package.json
|
|
||||||
exclude CONTRIBUTING.md
|
|
||||||
@@ -37,7 +37,7 @@ Currently, these distributions have existing packages for HyFetch:
|
|||||||
* Nix: `nix-env -i hyfetch` (Thanks to [@YisuiDenghua](https://github.com/YisuiDenghua))
|
* Nix: `nix-env -i hyfetch` (Thanks to [@YisuiDenghua](https://github.com/YisuiDenghua))
|
||||||
* Nix Profile: `nix profile install nixpkgs#hyfetch`
|
* Nix Profile: `nix profile install nixpkgs#hyfetch`
|
||||||
* Guix: `guix install hyfetch` (Thanks to [@WammKD](https://github.com/WammKD))
|
* Guix: `guix install hyfetch` (Thanks to [@WammKD](https://github.com/WammKD))
|
||||||
* Slackware: `sbopkg -b hyfetch` [Slackbuild](https://slackbuilds.org/repository/15.0/desktop/hyfetch/?search=hyfetch) (Thanks to [@bittin](https://github.com/bittin) , willysr (https://github.com/willysr), jebrhansen and Urchlay)
|
* Slackware: `sbopkg -b hyfetch` [Slackbuild](https://slackbuilds.org/repository/15.0/desktop/hyfetch/?search=hyfetch) (Thanks to [@bittin](https://github.com/bittin) , willysr (https://github.com/willysr), jebrhansen and Urchlay and new maintainer MDKDIO)
|
||||||
* Homebrew: `brew install hyfetch` (Thanks to [@catumin](https://github.com/catumin) and [@osalbahr](https://github.com/osalbahr))
|
* Homebrew: `brew install hyfetch` (Thanks to [@catumin](https://github.com/catumin) and [@osalbahr](https://github.com/osalbahr))
|
||||||
* openSUSE Tumbleweed: `zypper in python311-hyfetch` (Thanks to [@catumin](https://github.com/catumin))
|
* openSUSE Tumbleweed: `zypper in python311-hyfetch` (Thanks to [@catumin](https://github.com/catumin))
|
||||||
* Gentoo: `emerge --ask app-misc/hyfetch` (Thanks to [@catumin](https://github.com/catumin))
|
* Gentoo: `emerge --ask app-misc/hyfetch` (Thanks to [@catumin](https://github.com/catumin))
|
||||||
@@ -109,16 +109,6 @@ You can also install your version locally by running `pip install .` in the repo
|
|||||||
|
|
||||||
## Change Log
|
## Change Log
|
||||||
|
|
||||||
### About Notation
|
|
||||||
|
|
||||||
Updates to HyFetch begins with the emoji 🌈
|
|
||||||
Updates to `neowofetch` begins with the emoji 🖼️
|
|
||||||
|
|
||||||
### TODO
|
|
||||||
|
|
||||||
* [ ] (Important!) Refactor flag storage & coloring to support non-stride patterns
|
|
||||||
* [ ] Config menu: Allow left-right arrow keys for pagination
|
|
||||||
|
|
||||||
### Nightly
|
### Nightly
|
||||||
|
|
||||||
Note: You can install the latest nightly version by using:
|
Note: You can install the latest nightly version by using:
|
||||||
@@ -129,6 +119,98 @@ cargo install --git https://github.com/hykilpikonna/hyfetch
|
|||||||
|
|
||||||
<!-- CHANGELOG STARTS HERE --->
|
<!-- CHANGELOG STARTS HERE --->
|
||||||
|
|
||||||
|
### 2.1.0
|
||||||
|
|
||||||
|
### 2.1.0-rc1
|
||||||
|
|
||||||
|
### 2.1.0
|
||||||
|
|
||||||
|
(changelog is generated by Gemini from commit history)
|
||||||
|
|
||||||
|
**✨ Features & Enhancements**
|
||||||
|
|
||||||
|
* Random Preset: Now can select multiple presets and let it randomly choose one on each run ([#487](https://github.com/hykilpikonna/hyfetch/issues/487)).
|
||||||
|
* Distro as Data: Migrated distribution ASCII art and metadata to a unified JSON-header format, enabling shared usage across Python and Rust implementations.
|
||||||
|
* Distro Parity: Added missing ASCII art and distros from [fastfetch](https://github.com/fastfetch-cli/fastfetch).
|
||||||
|
* New OS Support: Added support for QNX/Blackberry 10 ([#480](https://github.com/hykilpikonna/hyfetch/issues/480)).
|
||||||
|
* Custom Presets: Added `custom_presets` configuration option to allow user-defined color presets ([#481](https://github.com/hykilpikonna/hyfetch/issues/481)).
|
||||||
|
* Interactive Filtering: Added live filter for preset selection in the configuration menu ([#482](https://github.com/hykilpikonna/hyfetch/issues/482)).
|
||||||
|
* New Distros: Added support for Codex Linux ([#477](https://github.com/hykilpikonna/hyfetch/issues/477)) and Zirconium ([#468](https://github.com/hykilpikonna/hyfetch/issues/468)).
|
||||||
|
* New Flags: Added Peter Griffin pride flag ([#489](https://github.com/hykilpikonna/hyfetch/issues/489)), Rubber flag ([#479](https://github.com/hykilpikonna/hyfetch/issues/479)), and Haruhi Suzumiya flag ([#486](https://github.com/hykilpikonna/hyfetch/issues/486)).
|
||||||
|
|
||||||
|
**🐛 Bug Fixes**
|
||||||
|
|
||||||
|
* Windows/MSYS2: Fixed bash path detection and execution in MINGW64 environment ([#488](https://github.com/hykilpikonna/hyfetch/issues/488)).
|
||||||
|
* Backend Fixes: Fixed issues with the `macchina` backend crashing or reporting incorrect distribution ([#491](https://github.com/hykilpikonna/hyfetch/issues/491)).
|
||||||
|
* Terminal Fixes: Fixed terminal font output issues in Kitty terminal ([#484](https://github.com/hykilpikonna/hyfetch/issues/484)).
|
||||||
|
* Reliability:
|
||||||
|
* Improved path detection to continue even when current path is not found ([#426](https://github.com/hykilpikonna/hyfetch/issues/426)).
|
||||||
|
* Added fallback for operating systems unsupported by the Rust implementation ([#474](https://github.com/hykilpikonna/hyfetch/issues/474)).
|
||||||
|
* Fixed prioritization of CLI-specified ASCII art to ensure it correctly overrides configuration ([#475](https://github.com/hykilpikonna/hyfetch/issues/475)).
|
||||||
|
* Shell Detection: Switched to `os.execv` for more reliable shell detection and transition ([#469](https://github.com/hykilpikonna/hyfetch/issues/469)).
|
||||||
|
* Background Detection Timeout: Prevent crash due to timeout in background color detection ([#453](https://github.com/hykilpikonna/hyfetch/issues/453)).
|
||||||
|
|
||||||
|
|
||||||
|
### 2.0.5
|
||||||
|
|
||||||
|
**✨ Features & Enhancements**
|
||||||
|
|
||||||
|
* Added support for Secureblue ([#434](https://github.com/hykilpikonna/hyfetch/pull/434)).
|
||||||
|
* Added `void_old` logo variant ([#457](https://github.com/hykilpikonna/hyfetch/pull/457)).
|
||||||
|
* Added Femme flag ([#456](https://github.com/hykilpikonna/hyfetch/pull/456)).
|
||||||
|
|
||||||
|
**🐛 Bug Fixes**
|
||||||
|
|
||||||
|
* Fixed a panic when entering an invalid alignment option after rolling ([#460](https://github.com/hykilpikonna/hyfetch/issues/460)).
|
||||||
|
* Fixed Traceback printing on KeyboardInterrupt ([#462](https://github.com/hykilpikonna/hyfetch/issues/462)).
|
||||||
|
* Restored flags lost during Python/Rust presets merge ([#466](https://github.com/hykilpikonna/hyfetch/pull/466)).
|
||||||
|
* Fixed a panic with file metadata access ([#465](https://github.com/hykilpikonna/hyfetch/issues/465)).
|
||||||
|
|
||||||
|
### 2.0.4
|
||||||
|
|
||||||
|
**🔧 Building Pipeline Refactoring**
|
||||||
|
|
||||||
|
* Modernize Python building toolchain from `setup.py` to `pyproject.toml`
|
||||||
|
* Fixed a bug where Windows binaries are mistakenly built into Unix packages.
|
||||||
|
* Fixed a bug where `presets.json` was not being included in the built package.
|
||||||
|
|
||||||
|
### 2.0.3
|
||||||
|
|
||||||
|
(changelog is generated by Gemini from commit history)
|
||||||
|
|
||||||
|
This update brings a significant internal refactor to how color presets are managed, along with a new batch of pride flags and several important bug fixes.
|
||||||
|
|
||||||
|
**✨ Features & Enhancements**
|
||||||
|
|
||||||
|
* **Custom ASCII Art**: You can now specify a file path for custom ASCII art ([#429](https://github.com/hykilpikonna/hyfetch/pull/429)).
|
||||||
|
* **Hex Color Presets**: Added the ability to pass a custom comma-separated hex color string list (e.g., `#RRGGBB,#RRGGBB`) directly as a preset ([#435](https://github.com/hykilpikonna/hyfetch/pull/435)).
|
||||||
|
|
||||||
|
**🏳️🌈 New Flags**
|
||||||
|
|
||||||
|
* Added Transbian flag ([#449](https://github.com/hykilpikonna/hyfetch/pull/449))
|
||||||
|
* Added Autism Pride flag ([#450](https://github.com/hykilpikonna/hyfetch/pull/450))
|
||||||
|
* Added Transneutral & Cenelian flags ([#452](https://github.com/hykilpikonna/hyfetch/pull/452))
|
||||||
|
* Added Fluidflux flags ([#437](https://github.com/hykilpikonna/hyfetch/pull/437))
|
||||||
|
* Added Libragender flags ([#433](https://github.com/hykilpikonna/hyfetch/pull/433))
|
||||||
|
|
||||||
|
**🐛 Bug Fixes**
|
||||||
|
|
||||||
|
* **Crash Fix**: Fixed a panic that could occur if hyfetch was run on a distro with no defined ASCII art ([#455](https://github.com/hykilpikonna/hyfetch/pull/455)).
|
||||||
|
* **OS Support**: Added support for iOS 1.x ([#444](https://github.com/hykilpikonna/hyfetch/pull/444)) and old Apple TV models ([#438](https://github.com/hykilpikonna/hyfetch/pull/438)).
|
||||||
|
* **Python**:
|
||||||
|
* Fixed a bug where 3-length hex codes (e.g., `#FFF`) does not work properly ([#443](https://github.com/hykilpikonna/hyfetch/pull/443)).
|
||||||
|
* Fixed a string formatting issue for python 3.11 and earlier versions ([#442](https://github.com/hykilpikonna/hyfetch/pull/442)).
|
||||||
|
* Fixed a bug where extra top padding would appear above output ascii art ([#428](https://github.com/hykilpikonna/hyfetch/pull/428)).
|
||||||
|
* **Rust**:
|
||||||
|
* Fixed the logic for the pride month easter egg so it only marks itself as "displayed" during June ([#430](https://github.com/hykilpikonna/hyfetch/pull/430)).
|
||||||
|
* Fixed a build issue on Windows ([#439](https://github.com/hykilpikonna/hyfetch/pull/439)).
|
||||||
|
|
||||||
|
**🔧 Maintenance & Refactoring**
|
||||||
|
|
||||||
|
* **Preset Refactor**: Color presets are now stored in a central `presets.json` file. ([#451](https://github.com/hykilpikonna/hyfetch/issues/451)).
|
||||||
|
* **Dependency Updates**: Upgraded various Rust crates and other dependencies to their latest versions.
|
||||||
|
* **Code Cleanup**: General code shortening and readability improvements.
|
||||||
|
|
||||||
### 2.0.2
|
### 2.0.2
|
||||||
|
|
||||||
This is a small patch release that adds more flags and fixes some bugs from the recent Rust rewrite.
|
This is a small patch release that adds more flags and fixes some bugs from the recent Rust rewrite.
|
||||||
@@ -187,6 +269,11 @@ This is a massive update, rewriting the entire hyfetch core from Python to Rust
|
|||||||
|
|
||||||
This version would be the last version of HyFetch on Python as we migrate to Rust (Huge thanks to everyone on [#317](https://github.com/hykilpikonna/hyfetch/pull/317)!). It will also be an effort to start a transition that phases out the neowofetch/neofetch backend in favor of FastFetch, since the time needed to maintain the NF backend currently exceed our capacity. If you are willing to help maintaining it, please let us know!
|
This version would be the last version of HyFetch on Python as we migrate to Rust (Huge thanks to everyone on [#317](https://github.com/hykilpikonna/hyfetch/pull/317)!). It will also be an effort to start a transition that phases out the neowofetch/neofetch backend in favor of FastFetch, since the time needed to maintain the NF backend currently exceed our capacity. If you are willing to help maintaining it, please let us know!
|
||||||
|
|
||||||
|
### About Notation
|
||||||
|
|
||||||
|
Updates to HyFetch begins with the emoji 🌈
|
||||||
|
Updates to `neowofetch` begins with the emoji 🖼️
|
||||||
|
|
||||||
* 🌈 **Improve Windows support**
|
* 🌈 **Improve Windows support**
|
||||||
* 🌈 **Include FastFetch into HyFetch PyPI package**
|
* 🌈 **Include FastFetch into HyFetch PyPI package**
|
||||||
* 🌈 Detached our fork from neofetch
|
* 🌈 Detached our fork from neofetch
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ ansi_colours = { workspace = true, features = [] }
|
|||||||
anstream = { workspace = true, features = [], optional = true }
|
anstream = { workspace = true, features = [], optional = true }
|
||||||
anyhow = { workspace = true, features = ["std"] }
|
anyhow = { workspace = true, features = ["std"] }
|
||||||
bpaf = { workspace = true, features = [] }
|
bpaf = { workspace = true, features = [] }
|
||||||
crossterm = { workspace = true, features = [] }
|
crossterm = { workspace = true, features = ["events"] }
|
||||||
deranged = { workspace = true, features = ["serde", "std"] }
|
deranged = { workspace = true, features = ["serde", "std"] }
|
||||||
directories = { workspace = true, features = [] }
|
directories = { workspace = true, features = [] }
|
||||||
enterpolation = { workspace = true, features = ["bspline", "std"] }
|
enterpolation = { workspace = true, features = ["bspline", "std"] }
|
||||||
@@ -41,10 +41,14 @@ unicode-segmentation = { workspace = true, features = [] }
|
|||||||
which = { workspace = true, features = [] }
|
which = { workspace = true, features = [] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
indexmap = { workspace = true, features = ["std"] }
|
indexmap = { workspace = true, features = ["std", "serde"] }
|
||||||
regex = { workspace = true, features = ["perf", "std", "unicode"] }
|
regex = { workspace = true, features = ["perf", "std", "unicode"] }
|
||||||
unicode-normalization = { workspace = true, features = ["std"] }
|
unicode-normalization = { workspace = true, features = ["std"] }
|
||||||
fs_extra = "1.3.0"
|
fs_extra = "1.3.0"
|
||||||
|
serde = { workspace = true, features = ["derive", "std"] }
|
||||||
|
serde_json = { workspace = true, features = ["std"] }
|
||||||
|
anyhow = { workspace = true, features = ["std"] }
|
||||||
|
heck = "0.5.0"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
enable-ansi-support = { workspace = true, features = [] }
|
enable-ansi-support = { workspace = true, features = [] }
|
||||||
|
|||||||
+212
-114
@@ -1,19 +1,33 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use anyhow::{Context, Result};
|
||||||
use fs_extra::dir::{CopyOptions};
|
use fs_extra::dir::CopyOptions;
|
||||||
|
use heck::ToUpperCamelCase;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use regex::Regex;
|
use serde::Deserialize;
|
||||||
use unicode_normalization::UnicodeNormalization as _;
|
use unicode_normalization::UnicodeNormalization as _;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct AsciiDistro {
|
struct AsciiDistro {
|
||||||
pattern: String,
|
pattern: String,
|
||||||
|
color: String,
|
||||||
|
foreground: Vec<u8>,
|
||||||
|
background: Option<u8>,
|
||||||
art: String,
|
art: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct DistroHeader {
|
||||||
|
#[serde(rename = "match")]
|
||||||
|
pattern: String,
|
||||||
|
color: serde_json::Value,
|
||||||
|
foreground: Option<Vec<u8>>,
|
||||||
|
background: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
impl AsciiDistro {
|
impl AsciiDistro {
|
||||||
fn friendly_name(&self) -> String {
|
fn friendly_name(&self) -> String {
|
||||||
self.pattern
|
self.pattern
|
||||||
@@ -29,35 +43,40 @@ fn anything_that_exist(paths: &[&Path]) -> Option<PathBuf> {
|
|||||||
paths.iter().copied().find(|p| p.exists()).map(Path::to_path_buf)
|
paths.iter().copied().find(|p| p.exists()).map(Path::to_path_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<()> {
|
||||||
// Path hack to make file paths work in both workspace and manifest directory
|
// Path hack to make file paths work in both workspace and manifest directory
|
||||||
let dir = PathBuf::from(env::var_os("CARGO_WORKSPACE_DIR").unwrap_or_else(|| env::var_os("CARGO_MANIFEST_DIR").unwrap()));
|
let dir = PathBuf::from(env::var_os("CARGO_WORKSPACE_DIR").unwrap_or_else(|| env::var_os("CARGO_MANIFEST_DIR").unwrap()));
|
||||||
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
|
||||||
for file in &["neofetch", "hyfetch"] {
|
let data_dir = anything_that_exist(&[
|
||||||
let src = anything_that_exist(&[
|
&dir.join("hyfetch/data"),
|
||||||
&dir.join(file),
|
&dir.join("../../hyfetch/data"),
|
||||||
&dir.join("../../").join(file),
|
]).context("couldn't find hyfetch/data")?;
|
||||||
]).expect("couldn't find neofetch");
|
|
||||||
let dst = o.join(file);
|
|
||||||
println!("cargo:rerun-if-changed={}", src.display());
|
|
||||||
|
|
||||||
// Copy either file or directory
|
let dst_root = o.join("hyfetch");
|
||||||
if src.is_dir() {
|
fs::create_dir_all(&dst_root)?;
|
||||||
let opt = CopyOptions { overwrite: true, copy_inside: true, ..CopyOptions::default() };
|
|
||||||
fs_extra::dir::copy(&src, &dst, &opt).expect("Failed to copy directory to OUT_DIR");
|
|
||||||
}
|
|
||||||
else { fs::copy(&src, &dst).expect("Failed to copy file to OUT_DIR"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export_distros(&o.join("neofetch"), &o);
|
// Copy hyfetch/data
|
||||||
|
let opt = CopyOptions { overwrite: true, copy_inside: true, ..CopyOptions::default() };
|
||||||
|
fs_extra::dir::copy(&data_dir, &dst_root, &opt)?;
|
||||||
|
|
||||||
|
// Copy neofetch
|
||||||
|
let neofetch_src = anything_that_exist(&[
|
||||||
|
&dir.join("neofetch"),
|
||||||
|
&dir.join("../../neofetch"),
|
||||||
|
]).context("couldn't find neofetch")?;
|
||||||
|
fs::copy(&neofetch_src, o.join("neofetch"))?;
|
||||||
|
|
||||||
|
preset_codegen(&o.join("hyfetch/data/presets.json"), &o.join("presets.rs"))?;
|
||||||
|
|
||||||
|
let distros_dir = data_dir.join("distros");
|
||||||
|
export_distros(&distros_dir, &o)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_distros<P>(neofetch_path: P, out_path: &Path)
|
fn export_distros(distro_dir: &Path, out_path: &Path) -> Result<()>
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
{
|
||||||
let distros = parse_ascii_distros(neofetch_path);
|
let distros = parse_ascii_distros(distro_dir)?;
|
||||||
let mut variants = IndexMap::with_capacity(distros.len());
|
let mut variants = IndexMap::with_capacity(distros.len());
|
||||||
|
|
||||||
for distro in &distros {
|
for distro in &distros {
|
||||||
@@ -80,18 +99,13 @@ where
|
|||||||
let mut buf = r###"
|
let mut buf = r###"
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum Distro {
|
pub enum Distro {
|
||||||
"###
|
"###.to_string();
|
||||||
.to_owned();
|
|
||||||
|
|
||||||
for (variant, AsciiDistro { pattern, .. }) in &variants {
|
for (variant, AsciiDistro { pattern, .. }) in &variants {
|
||||||
write!(
|
write!(buf, r###"
|
||||||
buf,
|
|
||||||
r###"
|
|
||||||
// {pattern})
|
// {pattern})
|
||||||
{variant},
|
{variant},
|
||||||
"###,
|
"###)?;
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(
|
buf.push_str(
|
||||||
@@ -132,9 +146,7 @@ impl Distro {
|
|||||||
|
|
||||||
// Both sides are *
|
// Both sides are *
|
||||||
if m.starts_with('*') && m.ends_with('*') {
|
if m.starts_with('*') && m.ends_with('*') {
|
||||||
conds.push(format!(
|
conds.push(format!(r#"name.contains("{stripped}")"#));
|
||||||
r#"name.starts_with("{stripped}") || name.ends_with("{stripped}")"#
|
|
||||||
));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,15 +165,11 @@ impl Distro {
|
|||||||
|
|
||||||
let condition = conds.join(" || ");
|
let condition = conds.join(" || ");
|
||||||
|
|
||||||
write!(
|
write!(buf, r###"
|
||||||
buf,
|
|
||||||
r###"
|
|
||||||
if {condition} {{
|
if {condition} {{
|
||||||
return Some(Self::{variant});
|
return Some(Self::{variant});
|
||||||
}}
|
}}
|
||||||
"###
|
"###)?;
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(
|
buf.push_str(
|
||||||
@@ -169,6 +177,66 @@ impl Distro {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn color(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
"###,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (variant, AsciiDistro { color, .. }) in &variants {
|
||||||
|
write!(buf, r###"
|
||||||
|
Self::{variant} => {color:?},
|
||||||
|
"###, color = color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(
|
||||||
|
r###"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foreground(&self) -> &[u8] {
|
||||||
|
match self {
|
||||||
|
"###,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (variant, AsciiDistro { foreground, .. }) in &variants {
|
||||||
|
if foreground.is_empty() {
|
||||||
|
write!(buf, r###"
|
||||||
|
Self::{variant} => &[],
|
||||||
|
"###)?;
|
||||||
|
} else {
|
||||||
|
write!(buf, r###"
|
||||||
|
Self::{variant} => &{:?},
|
||||||
|
"###, foreground)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(
|
||||||
|
r###"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn background(&self) -> Option<u8> {
|
||||||
|
match self {
|
||||||
|
"###,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (variant, AsciiDistro { background, .. }) in &variants {
|
||||||
|
if let Some(b) = background {
|
||||||
|
write!(buf, r###"
|
||||||
|
Self::{variant} => Some({b}),
|
||||||
|
"###)?;
|
||||||
|
} else {
|
||||||
|
write!(buf, r###"
|
||||||
|
Self::{variant} => None,
|
||||||
|
"###)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str(
|
||||||
|
r###"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ascii_art(&self) -> &str {
|
pub fn ascii_art(&self) -> &str {
|
||||||
let art = match self {
|
let art = match self {
|
||||||
"###,
|
"###,
|
||||||
@@ -176,15 +244,11 @@ impl Distro {
|
|||||||
|
|
||||||
let quotes = "#".repeat(80);
|
let quotes = "#".repeat(80);
|
||||||
for (variant, AsciiDistro { art, .. }) in &variants {
|
for (variant, AsciiDistro { art, .. }) in &variants {
|
||||||
write!(
|
write!(buf, r###"
|
||||||
buf,
|
|
||||||
r###"
|
|
||||||
Self::{variant} => r{quotes}"
|
Self::{variant} => r{quotes}"
|
||||||
{art}
|
{art}
|
||||||
"{quotes},
|
"{quotes},
|
||||||
"###,
|
"###)?;
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(
|
buf.push_str(
|
||||||
@@ -196,78 +260,112 @@ impl Distro {
|
|||||||
"###,
|
"###,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs::write(out_path.join("distros.rs"), buf).expect("couldn't write distros.rs");
|
fs::write(out_path.join("distros.rs"), buf)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses ascii distros from neofetch script.
|
fn parse_ascii_distros(distro_dir: &Path) -> Result<Vec<AsciiDistro>>
|
||||||
fn parse_ascii_distros<P>(neofetch_path: P) -> Vec<AsciiDistro>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
{
|
||||||
let neofetch_path = neofetch_path.as_ref();
|
let mut distros = Vec::new();
|
||||||
|
let mut paths: Vec<_> = fs::read_dir(distro_dir)?
|
||||||
|
.filter_map(|e| e.ok())
|
||||||
|
.map(|e| e.path())
|
||||||
|
.collect();
|
||||||
|
// Sort by name length descending, then name descending.
|
||||||
|
// This ensures that more specific distros (e.g. windows_11, arch_small) are
|
||||||
|
// checked before more general ones (e.g. windows, arch).
|
||||||
|
paths.sort_by(|a, b| {
|
||||||
|
b.to_str()
|
||||||
|
.map_or(0, |s| s.len())
|
||||||
|
.cmp(&a.to_str().map_or(0, |s| s.len()))
|
||||||
|
.then(b.cmp(a))
|
||||||
|
});
|
||||||
|
|
||||||
let nf = {
|
for path in paths {
|
||||||
let nf = fs::read_to_string(neofetch_path).expect("couldn't read neofetch script");
|
if path.extension().and_then(|s| s.to_str()) == Some("ascii") {
|
||||||
|
let content = fs::read_to_string(&path)?;
|
||||||
// Get the content of "get_distro_ascii" function
|
let (header_line, art) = content.split_once('\n').context("invalid distro file")?;
|
||||||
let (_, nf) = nf
|
let header: DistroHeader = serde_json::from_str(header_line)?;
|
||||||
.split_once("get_distro_ascii() {\n")
|
let color = match header.color {
|
||||||
.expect("couldn't find get_distro_ascii function");
|
serde_json::Value::String(s) => s,
|
||||||
let (nf, _) = nf
|
serde_json::Value::Number(n) => n.to_string(),
|
||||||
.split_once("\n}\n")
|
_ => "7".to_owned(),
|
||||||
.expect("couldn't find end of get_distro_ascii function");
|
};
|
||||||
|
distros.push(AsciiDistro {
|
||||||
let mut nf = nf.replace('\t', &" ".repeat(4));
|
pattern: header.pattern,
|
||||||
|
color,
|
||||||
// Remove trailing spaces
|
foreground: header.foreground.unwrap_or_default(),
|
||||||
while nf.contains(" \n") {
|
background: header.background,
|
||||||
nf = nf.replace(" \n", "\n");
|
art: art.to_owned(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
nf
|
|
||||||
};
|
|
||||||
|
|
||||||
let case_re = Regex::new(r"case .*? in\n").expect("couldn't compile case regex");
|
|
||||||
let eof_re = Regex::new(r"EOF[ \n]*?;;").expect("couldn't compile eof regex");
|
|
||||||
|
|
||||||
// Split by blocks
|
|
||||||
let mut blocks = Vec::new();
|
|
||||||
for b in case_re.split(&nf) {
|
|
||||||
blocks.extend(eof_re.split(b).map(|sub| sub.trim()));
|
|
||||||
}
|
}
|
||||||
|
Ok(distros)
|
||||||
// Parse blocks
|
}
|
||||||
fn parse_block(block: &str) -> Option<AsciiDistro> {
|
|
||||||
let (block, art) = block.split_once("'EOF'\n")?;
|
// Preset parsing
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
// Join \
|
#[serde(untagged)]
|
||||||
//
|
enum PresetEntry {
|
||||||
// > A <backslash> that is not quoted shall preserve the literal value of the
|
Simple(Vec<String>),
|
||||||
// > following character, with the exception of a <newline>. If a <newline>
|
Complex { colors: Vec<String>, weights: Option<Vec<u32>> },
|
||||||
// > follows the <backslash>, the shell shall interpret this as line
|
}
|
||||||
// > continuation. The <backslash> and <newline> shall be removed before
|
|
||||||
// > splitting the input into tokens. Since the escaped <newline> is removed
|
type PresetMap = IndexMap<String, PresetEntry>;
|
||||||
// > entirely from the input and is not replaced by any white space, it cannot
|
|
||||||
// > serve as a token separator.
|
fn preset_codegen(json_path: &Path, out_path: &Path) -> Result<()> {
|
||||||
// See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_01
|
// 1. Read and parse the JSON file
|
||||||
let block = block.replace("\\\n", "");
|
let json_str = fs::read_to_string(json_path)?;
|
||||||
|
let map: PresetMap = serde_json::from_str(&json_str)?;
|
||||||
// Get case pattern
|
let mut f = BufWriter::new(fs::File::create(&out_path)?);
|
||||||
let pattern = block
|
|
||||||
.split('\n')
|
// 2. Build the code string
|
||||||
.next()
|
let mut code_decl = String::new();
|
||||||
.and_then(|pattern| pattern.trim().strip_suffix(')'))?;
|
let mut code_match = String::new();
|
||||||
|
for (key, data) in map.iter() {
|
||||||
// Unescape backslashes here because backslashes are escaped in neofetch
|
let colors = match data {
|
||||||
// for printf
|
PresetEntry::Simple(c) => c,
|
||||||
let art = art.replace(r"\\", r"\");
|
PresetEntry::Complex { colors, .. } => colors,
|
||||||
|
};
|
||||||
Some(AsciiDistro {
|
let colors = colors.iter().map(|s| format!("\"{}\"", s)).collect::<Vec<_>>().join(", ");
|
||||||
pattern: pattern.to_owned(),
|
let uck = key.to_upper_camel_case();
|
||||||
art,
|
|
||||||
})
|
code_decl += &format!(r#"
|
||||||
}
|
#[serde(rename = "{key}")]
|
||||||
blocks
|
#[strum(serialize = "{key}")]
|
||||||
.iter()
|
{uck},
|
||||||
.filter_map(|block| parse_block(block))
|
"#);
|
||||||
.collect()
|
|
||||||
|
let w = if let PresetEntry::Complex { weights: Some(w), .. } = data {
|
||||||
|
format!(".and_then(|c| c.with_weights(vec![{}]))", w.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", "))
|
||||||
|
} else { "".to_string() };
|
||||||
|
|
||||||
|
code_match += &format!(r#"
|
||||||
|
Preset::{uck} => ColorProfile::from_hex_colors(vec![{colors}]){w},
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Write the static map to the generated file
|
||||||
|
writeln!(f, r#"
|
||||||
|
pub use crate::color_profile::ColorProfile;
|
||||||
|
use serde::{{Deserialize, Serialize}};
|
||||||
|
use strum::{{AsRefStr, EnumCount, EnumString, VariantArray, VariantNames}};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Hash, Debug, AsRefStr, Deserialize, EnumCount, EnumString, Serialize, VariantArray, VariantNames)]
|
||||||
|
pub enum Preset {{
|
||||||
|
{code_decl}
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Preset {{
|
||||||
|
pub fn color_profile(&self) -> ColorProfile {{
|
||||||
|
(match self {{
|
||||||
|
{code_match}
|
||||||
|
}})
|
||||||
|
.expect("preset color profiles should be valid")
|
||||||
|
}}
|
||||||
|
}}"#)?;
|
||||||
|
|
||||||
|
f.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ impl RawAsciiArt {
|
|||||||
|
|
||||||
Ok(NormalizedAsciiArt {
|
Ok(NormalizedAsciiArt {
|
||||||
lines,
|
lines,
|
||||||
w,
|
w: w.try_into().context("width does not fit in u8")?,
|
||||||
h,
|
h: h.try_into().context("height does not fit in u8")?,
|
||||||
fg: self.fg.clone(),
|
fg: self.fg.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -372,12 +372,7 @@ impl NormalizedAsciiArt {
|
|||||||
// Line starts with neofetch color code
|
// Line starts with neofetch color code
|
||||||
last = Some(&line[m.span()]);
|
last = Some(&line[m.span()]);
|
||||||
},
|
},
|
||||||
Some(_) => {
|
_ => {
|
||||||
new.push_str(last.context(
|
|
||||||
"failed to find neofetch color code from a previous line",
|
|
||||||
)?);
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
new.push_str(last.unwrap_or(NEOFETCH_COLOR_PATTERNS[0]));
|
new.push_str(last.unwrap_or(NEOFETCH_COLOR_PATTERNS[0]));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -385,7 +380,6 @@ impl NormalizedAsciiArt {
|
|||||||
|
|
||||||
// Get the last placeholder for the next line
|
// Get the last placeholder for the next line
|
||||||
if let Some(m) = matches.last() {
|
if let Some(m) = matches.last() {
|
||||||
last.context("non-space character seen before first color code")?;
|
|
||||||
last = Some(&line[m.span()]);
|
last = Some(&line[m.span()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+457
-256
@@ -1,14 +1,18 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::{self, IsTerminal as _, Read as _, Write as _};
|
use std::io::{self, IsTerminal as _, Read as _, Write};
|
||||||
|
use std::iter;
|
||||||
use std::iter::zip;
|
use std::iter::zip;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZeroU8;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use aho_corasick::AhoCorasick;
|
use aho_corasick::AhoCorasick;
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
|
use crossterm::event::{self, Event, KeyCode, KeyEventKind, KeyModifiers};
|
||||||
|
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||||
use deranged::RangedU8;
|
use deranged::RangedU8;
|
||||||
use enterpolation::bspline::BSpline;
|
use enterpolation::bspline::BSpline;
|
||||||
use enterpolation::{Curve as _, Generator as _};
|
use enterpolation::{Curve as _, Generator as _};
|
||||||
@@ -20,12 +24,13 @@ use hyfetch::color_util::{
|
|||||||
NeofetchAsciiIndexedColor, PresetIndexedColor, Theme as _, ToAnsiString as _,
|
NeofetchAsciiIndexedColor, PresetIndexedColor, Theme as _, ToAnsiString as _,
|
||||||
};
|
};
|
||||||
use hyfetch::distros::Distro;
|
use hyfetch::distros::Distro;
|
||||||
use hyfetch::models::Config;
|
use hyfetch::models::{build_hex_color_profile, Config, PresetValue};
|
||||||
#[cfg(feature = "macchina")]
|
#[cfg(feature = "macchina")]
|
||||||
use hyfetch::neofetch_util::macchina_path;
|
use hyfetch::neofetch_util::macchina_path;
|
||||||
use hyfetch::neofetch_util::{self, add_pkg_path, fastfetch_path, get_distro_ascii, get_distro_name, literal_input, ColorAlignment, NEOFETCH_COLORS_AC, NEOFETCH_COLOR_PATTERNS, TEST_ASCII};
|
use hyfetch::neofetch_util::{self, add_pkg_path, fastfetch_path, get_distro_ascii, get_distro_name, literal_input, ColorAlignment, NEOFETCH_COLORS_AC, NEOFETCH_COLOR_PATTERNS, TEST_ASCII};
|
||||||
use hyfetch::presets::{AssignLightness, Preset};
|
use hyfetch::color_profile::{AssignLightness, ColorProfile};
|
||||||
use hyfetch::pride_month;
|
use hyfetch::presets::{Preset};
|
||||||
|
use hyfetch::{pride_month, printc};
|
||||||
use hyfetch::types::{AnsiMode, Backend, TerminalTheme};
|
use hyfetch::types::{AnsiMode, Backend, TerminalTheme};
|
||||||
use hyfetch::utils::{get_cache_path, input};
|
use hyfetch::utils::{get_cache_path, input};
|
||||||
use hyfetch::font_logo::get_font_logo;
|
use hyfetch::font_logo::get_font_logo;
|
||||||
@@ -50,6 +55,16 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
let options = options().run();
|
let options = options().run();
|
||||||
|
|
||||||
|
// Read ascii file first to avoid any issues with file descriptors being closed by other operations, and to allow CLI arguments to override config. (https://github.com/hykilpikonna/hyfetch/issues/475)
|
||||||
|
let cli_ascii = if let Some(path) = &options.ascii_file {
|
||||||
|
Some(RawAsciiArt {
|
||||||
|
asc: fs::read_to_string(path).with_context(|| format!("failed to read ascii from {path:?}"))?,
|
||||||
|
fg: Vec::new(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let debug_mode = options.debug;
|
let debug_mode = options.debug;
|
||||||
|
|
||||||
init_tracing_subsriber(debug_mode).context("failed to init tracing subscriber")?;
|
init_tracing_subsriber(debug_mode).context("failed to init tracing subscriber")?;
|
||||||
@@ -64,15 +79,12 @@ fn main() -> Result<()> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if options.test_print {
|
if options.test_print {
|
||||||
let asc = get_distro_ascii(distro, backend).context("failed to get distro ascii")?;
|
println!("{asc}", asc = get_distro_ascii(distro, backend)?.asc);
|
||||||
writeln!(io::stdout(), "{asc}", asc = asc.asc)
|
|
||||||
.context("failed to write ascii to stdout")?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.print_font_logo {
|
if options.print_font_logo {
|
||||||
let logo = get_font_logo(backend).context("failed to get font logo")?;
|
println!("{}", get_font_logo(backend)?);
|
||||||
writeln!(io::stdout(), "{}", logo).context("failed to write logo to stdout")?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,14 +122,9 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
if show_pride_month && !config.pride_month_disable {
|
if show_pride_month && !config.pride_month_disable {
|
||||||
pride_month::start_animation(color_mode).context("failed to draw pride month animation")?;
|
pride_month::start_animation(color_mode).context("failed to draw pride month animation")?;
|
||||||
writeln!(
|
println!("\nHappy pride month!\n(You can always view the animation again with `hyfetch --june`)\n");
|
||||||
io::stdout(),
|
|
||||||
"\nHappy pride month!\n(You can always view the animation again with `hyfetch \
|
|
||||||
--june`)\n"
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
|
|
||||||
if !june_path.is_file() {
|
if !june_path.is_file() && !options.june {
|
||||||
File::create(&june_path)
|
File::create(&june_path)
|
||||||
.with_context(|| format!("failed to create file {june_path:?}"))?;
|
.with_context(|| format!("failed to create file {june_path:?}"))?;
|
||||||
}
|
}
|
||||||
@@ -129,9 +136,61 @@ fn main() -> Result<()> {
|
|||||||
let backend = options.backend.unwrap_or(config.backend);
|
let backend = options.backend.unwrap_or(config.backend);
|
||||||
let args = options.args.as_ref().or(config.args.as_ref());
|
let args = options.args.as_ref().or(config.args.as_ref());
|
||||||
|
|
||||||
|
fn parse_preset_string(preset_string: &str, config: &Config) -> Result<ColorProfile> {
|
||||||
|
if preset_string.contains('#') {
|
||||||
|
let colors: Vec<String> = preset_string
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.trim().to_owned())
|
||||||
|
.collect();
|
||||||
|
let color_profile = build_hex_color_profile(&colors)
|
||||||
|
.context("failed to create color profile from hex")?;
|
||||||
|
return Ok(color_profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut preset_profiles: HashMap<String, ColorProfile> = <Preset as VariantArray>::VARIANTS
|
||||||
|
.iter()
|
||||||
|
.map(|preset| (preset.as_ref().to_owned(), preset.color_profile()))
|
||||||
|
.collect();
|
||||||
|
preset_profiles.extend(config.custom_preset_profiles()?);
|
||||||
|
|
||||||
|
if preset_string.contains(',') {
|
||||||
|
let presets: Vec<&str> = preset_string.split(',').map(|s| s.trim()).collect();
|
||||||
|
let mut rng = fastrand::Rng::new();
|
||||||
|
let selected_index = rng.usize(0..presets.len());
|
||||||
|
return parse_preset_string(presets[selected_index], config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if preset_string == "random" {
|
||||||
|
let presets: Vec<ColorProfile> = preset_profiles.values().cloned().collect();
|
||||||
|
if presets.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("preset iterator should not be empty"));
|
||||||
|
}
|
||||||
|
let mut rng = fastrand::Rng::new();
|
||||||
|
let selected_index = rng.usize(0..presets.len());
|
||||||
|
return Ok(presets[selected_index].clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(color_profile) = preset_profiles.get(preset_string) {
|
||||||
|
Ok(color_profile.clone())
|
||||||
|
} else {
|
||||||
|
let presets = preset_profiles
|
||||||
|
.keys()
|
||||||
|
.map(String::as_str)
|
||||||
|
.chain(iter::once("random"))
|
||||||
|
.sorted()
|
||||||
|
.join(",");
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"PRESET should be comma-separated hex colors or one of {{{presets}}}"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get preset
|
// Get preset
|
||||||
let preset = options.preset.unwrap_or(config.preset);
|
let preset_string = options
|
||||||
let color_profile = preset.color_profile();
|
.preset
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| config.preset.get_random_if_multiple());
|
||||||
|
let color_profile = parse_preset_string(&preset_string, &config)?;
|
||||||
debug!(?color_profile, "color profile");
|
debug!(?color_profile, "color profile");
|
||||||
|
|
||||||
// Lighten
|
// Lighten
|
||||||
@@ -149,7 +208,10 @@ fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
debug!(?color_profile, "lightened color profile");
|
debug!(?color_profile, "lightened color profile");
|
||||||
|
|
||||||
let asc = if let Some(path) = options.ascii_file {
|
let asc = if let Some(asc) = cli_ascii {
|
||||||
|
asc
|
||||||
|
} else if let Some(path_str) = config.custom_ascii_path {
|
||||||
|
let path = PathBuf::from(path_str);
|
||||||
RawAsciiArt {
|
RawAsciiArt {
|
||||||
asc: fs::read_to_string(&path)
|
asc: fs::read_to_string(&path)
|
||||||
.with_context(|| format!("failed to read ascii from {path:?}"))?,
|
.with_context(|| format!("failed to read ascii from {path:?}"))?,
|
||||||
@@ -206,15 +268,15 @@ fn det_bg() -> Result<Option<Srgb<u8>>, terminal_colorsaurus::Error> {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
background_color(QueryOptions::default())
|
match background_color(QueryOptions::default()) {
|
||||||
.map(|terminal_colorsaurus::Color { r, g, b }| Some(Srgb::new(r, g, b).into_format()))
|
Ok(terminal_colorsaurus::Color { r, g, b, .. }) => {
|
||||||
.or_else(|err| {
|
Ok(Some(Srgb::new(r, g, b).into_format()))
|
||||||
if matches!(err, terminal_colorsaurus::Error::UnsupportedTerminal) {
|
}
|
||||||
Ok(None)
|
Err(err) => {
|
||||||
} else {
|
debug!(?err, "failed to detect background color");
|
||||||
Err(err)
|
Ok(None)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates config interactively.
|
/// Creates config interactively.
|
||||||
@@ -236,10 +298,6 @@ fn create_config(
|
|||||||
} else if color_level.has_256 {
|
} else if color_level.has_256 {
|
||||||
AnsiMode::Ansi256
|
AnsiMode::Ansi256
|
||||||
} else if color_level.has_basic {
|
} else if color_level.has_basic {
|
||||||
// unimplemented!(
|
|
||||||
// "{mode} color mode not supported",
|
|
||||||
// mode = AnsiMode::Ansi16.as_ref()
|
|
||||||
// );
|
|
||||||
AnsiMode::Ansi256
|
AnsiMode::Ansi256
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -279,13 +337,8 @@ fn create_config(
|
|||||||
.expect("`option_counter` should not overflow `u8`");
|
.expect("`option_counter` should not overflow `u8`");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_title_prompt(
|
fn print_title_prompt(option_counter: NonZeroU8, prompt: &str) {
|
||||||
option_counter: NonZeroU8,
|
printc!("&a{option_counter}. {prompt}");
|
||||||
prompt: &str,
|
|
||||||
color_mode: AnsiMode,
|
|
||||||
) -> Result<()> {
|
|
||||||
printc(format!("&a{option_counter}. {prompt}"), color_mode)
|
|
||||||
.context("failed to print prompt")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@@ -295,14 +348,8 @@ fn create_config(
|
|||||||
let (Width(term_w), Height(term_h)) = terminal_size().context("failed to get terminal size")?;
|
let (Width(term_w), Height(term_h)) = terminal_size().context("failed to get terminal size")?;
|
||||||
let (term_w_min, term_h_min) = ((asc.w as u32 * 2 + 4).clamp(0, u16::MAX.into()) as u16, 30);
|
let (term_w_min, term_h_min) = ((asc.w as u32 * 2 + 4).clamp(0, u16::MAX.into()) as u16, 30);
|
||||||
if term_w < term_w_min || term_h < term_h_min {
|
if term_w < term_w_min || term_h < term_h_min {
|
||||||
printc(
|
printc!("&cWarning: Your terminal is too small ({term_w} * {term_h}).\n\
|
||||||
format!(
|
Please resize it to at least ({term_w_min} * {term_h_min}) for better experience.");
|
||||||
"&cWarning: Your terminal is too small ({term_w} * {term_h}).\nPlease resize \
|
|
||||||
it to at least ({term_w_min} * {term_h_min}) for better experience."
|
|
||||||
),
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print message")?;
|
|
||||||
input(Some("Press enter to continue...")).context("failed to read input")?;
|
input(Some("Press enter to continue...")).context("failed to read input")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,18 +394,14 @@ fn create_config(
|
|||||||
(t - a) * ((d - c) / (b - a)) + c
|
(t - a) * ((d - c) / (b - a)) + c
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let print_color_testing = |label: &str, mode: AnsiMode| {
|
||||||
let label = format!(
|
let label = format!("{label:^term_w$}", term_w = usize::from(term_w));
|
||||||
"{label:^term_w$}",
|
|
||||||
label = "8bit Color Testing",
|
|
||||||
term_w = usize::from(term_w)
|
|
||||||
);
|
|
||||||
let line = zip(gradient.iter(), label.chars()).fold(
|
let line = zip(gradient.iter(), label.chars()).fold(
|
||||||
String::new(),
|
String::new(),
|
||||||
|mut s, (&rgb_f32_color, t)| {
|
|mut s, (&rgb_f32_color, t)| {
|
||||||
let rgb_u8_color = Srgb::<u8>::from_linear(rgb_f32_color);
|
let rgb_u8_color = Srgb::<u8>::from_linear(rgb_f32_color);
|
||||||
let back = rgb_u8_color
|
let back = rgb_u8_color
|
||||||
.to_ansi_string(AnsiMode::Ansi256, ForegroundBackground::Background);
|
.to_ansi_string(mode, ForegroundBackground::Background);
|
||||||
let fore = rgb_u8_color
|
let fore = rgb_u8_color
|
||||||
.contrast_grayscale()
|
.contrast_grayscale()
|
||||||
.to_ansi_string(AnsiMode::Ansi256, ForegroundBackground::Foreground);
|
.to_ansi_string(AnsiMode::Ansi256, ForegroundBackground::Foreground);
|
||||||
@@ -366,42 +409,15 @@ fn create_config(
|
|||||||
s
|
s
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
printc(line, AnsiMode::Ansi256).context("failed to print 8-bit color test line")?;
|
printc!("{line}");
|
||||||
}
|
};
|
||||||
{
|
|
||||||
let label = format!(
|
|
||||||
"{label:^term_w$}",
|
|
||||||
label = "RGB Color Testing",
|
|
||||||
term_w = usize::from(term_w)
|
|
||||||
);
|
|
||||||
let line = zip(gradient.iter(), label.chars()).fold(
|
|
||||||
String::new(),
|
|
||||||
|mut s, (&rgb_f32_color, t)| {
|
|
||||||
let rgb_u8_color = Srgb::<u8>::from_linear(rgb_f32_color);
|
|
||||||
let back = rgb_u8_color
|
|
||||||
.to_ansi_string(AnsiMode::Rgb, ForegroundBackground::Background);
|
|
||||||
let fore = rgb_u8_color
|
|
||||||
.contrast_grayscale()
|
|
||||||
.to_ansi_string(AnsiMode::Ansi256, ForegroundBackground::Foreground);
|
|
||||||
write!(s, "{back}{fore}{t}").unwrap();
|
|
||||||
s
|
|
||||||
},
|
|
||||||
);
|
|
||||||
printc(line, AnsiMode::Rgb).context("failed to print RGB color test line")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
print_color_testing("8bit Color Testing", AnsiMode::Ansi256);
|
||||||
print_title_prompt(
|
print_color_testing("RGB Color Testing", AnsiMode::Rgb);
|
||||||
option_counter,
|
|
||||||
"Which &bcolor system &ado you want to use?",
|
println!();
|
||||||
color_mode,
|
print_title_prompt(option_counter, "Which &bcolor system &ado you want to use?");
|
||||||
)
|
println!("(If you can't see colors under \"RGB Color Testing\", please choose 8bit)\n");
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
writeln!(
|
|
||||||
io::stdout(),
|
|
||||||
"(If you can't see colors under \"RGB Color Testing\", please choose 8bit)\n"
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
|
|
||||||
let choice = literal_input(
|
let choice = literal_input(
|
||||||
"Your choice?",
|
"Your choice?",
|
||||||
@@ -434,20 +450,14 @@ fn create_config(
|
|||||||
|
|
||||||
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
|
|
||||||
print_title_prompt(
|
print_title_prompt(option_counter, "Is your terminal in &blight mode&~ or &4dark mode&~?");
|
||||||
option_counter,
|
|
||||||
"Is your terminal in &blight mode&~ or &4dark mode&~?",
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
let choice = literal_input(
|
let choice = literal_input(
|
||||||
"",
|
"",
|
||||||
TerminalTheme::VARIANTS,
|
TerminalTheme::VARIANTS,
|
||||||
TerminalTheme::Dark.as_ref(),
|
TerminalTheme::Dark.as_ref(),
|
||||||
true,
|
true,
|
||||||
color_mode,
|
color_mode,
|
||||||
)
|
)?;
|
||||||
.context("failed to ask for choice input")?;
|
|
||||||
Ok((
|
Ok((
|
||||||
choice.parse().expect("selected theme should be valid"),
|
choice.parse().expect("selected theme should be valid"),
|
||||||
"Selected background color",
|
"Selected background color",
|
||||||
@@ -464,6 +474,40 @@ fn create_config(
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// 3. Choose preset
|
// 3. Choose preset
|
||||||
|
|
||||||
|
struct RawModeGuard {
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawModeGuard {
|
||||||
|
fn new() -> Result<Self> {
|
||||||
|
Ok(Self { enabled: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable(&mut self) -> Result<()> {
|
||||||
|
if !self.enabled {
|
||||||
|
enable_raw_mode().context("failed to enable terminal raw mode")?;
|
||||||
|
self.enabled = true;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable(&mut self) -> Result<()> {
|
||||||
|
if self.enabled {
|
||||||
|
disable_raw_mode().context("failed to disable terminal raw mode")?;
|
||||||
|
self.enabled = false;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RawModeGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.enabled {
|
||||||
|
let _ = disable_raw_mode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create flag lines
|
// Create flag lines
|
||||||
let mut flags = Vec::with_capacity(Preset::COUNT);
|
let mut flags = Vec::with_capacity(Preset::COUNT);
|
||||||
let spacing = {
|
let spacing = {
|
||||||
@@ -490,7 +534,11 @@ fn create_config(
|
|||||||
name = preset.as_ref(),
|
name = preset.as_ref(),
|
||||||
spacing = usize::from(spacing)
|
spacing = usize::from(spacing)
|
||||||
);
|
);
|
||||||
flags.push([name, flag.clone(), flag.clone(), flag]);
|
flags.push((
|
||||||
|
preset.clone(),
|
||||||
|
[name, flag.clone(), flag.clone(), flag],
|
||||||
|
preset.as_ref().to_ascii_lowercase(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate flags per row
|
// Calculate flags per row
|
||||||
@@ -500,40 +548,28 @@ fn create_config(
|
|||||||
let rows_per_page = (term_h.saturating_sub(13) / 5).clamp(1, u8::MAX.into()) as u8;
|
let rows_per_page = (term_h.saturating_sub(13) / 5).clamp(1, u8::MAX.into()) as u8;
|
||||||
(flags_per_row, rows_per_page)
|
(flags_per_row, rows_per_page)
|
||||||
};
|
};
|
||||||
let num_pages = (Preset::COUNT.div_ceil(flags_per_row as usize * rows_per_page as usize)).clamp(0, u8::MAX.into()) as u8;
|
let flags_per_page = usize::from(flags_per_row) * usize::from(rows_per_page);
|
||||||
|
|
||||||
// Create pages
|
fn filter_flag_indices(query: &str, flags: &[(Preset, [String; 4], String)]) -> Vec<usize> {
|
||||||
let mut pages = Vec::with_capacity(usize::from(num_pages));
|
if query.is_empty() {
|
||||||
for flags in flags.chunks(usize::from(
|
return (0..flags.len()).collect();
|
||||||
u16::from(flags_per_row)
|
|
||||||
.checked_mul(u16::from(rows_per_page))
|
|
||||||
.unwrap(),
|
|
||||||
)) {
|
|
||||||
let mut page = Vec::with_capacity(usize::from(rows_per_page));
|
|
||||||
for flags in flags.chunks(usize::from(flags_per_row)) {
|
|
||||||
page.push(flags);
|
|
||||||
}
|
}
|
||||||
pages.push(page);
|
|
||||||
|
let mut matched = flags
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(idx, (_, _, preset_name))| {
|
||||||
|
let position = preset_name.find(query)?;
|
||||||
|
Some((idx, preset_name.starts_with(query), position))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Prefix matches are shown first, then other substring matches ordered by earliest index.
|
||||||
|
matched.sort_by_key(|&(idx, is_prefix, position)| (!is_prefix, position, idx));
|
||||||
|
matched.into_iter().map(|(idx, _, _)| idx).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
let print_flag_page = |page, page_num: u8| -> Result<()> {
|
fn print_flag_row(row: &[&[String; 4]], color_mode: AnsiMode) -> Result<()> {
|
||||||
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
|
||||||
print_title_prompt(option_counter, "Let's choose a flag!", color_mode)
|
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
writeln!(
|
|
||||||
io::stdout(),
|
|
||||||
"Available flag presets:\nPage: {page_num} of {num_pages}\n",
|
|
||||||
page_num = page_num.checked_add(1).unwrap()
|
|
||||||
)
|
|
||||||
.context("failed to write header to stdout")?;
|
|
||||||
for &row in page {
|
|
||||||
print_flag_row(row, color_mode).context("failed to print flag row")?;
|
|
||||||
}
|
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
fn print_flag_row(row: &[[String; 4]], color_mode: AnsiMode) -> Result<()> {
|
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
let mut line = Vec::new();
|
let mut line = Vec::new();
|
||||||
for flag in row {
|
for flag in row {
|
||||||
@@ -541,7 +577,7 @@ fn create_config(
|
|||||||
}
|
}
|
||||||
printc(line.join(" "), color_mode).context("failed to print line")?;
|
printc(line.join(" "), color_mode).context("failed to print line")?;
|
||||||
}
|
}
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
println!();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,57 +592,214 @@ fn create_config(
|
|||||||
)
|
)
|
||||||
.expect("coloring text with default preset should not fail");
|
.expect("coloring text with default preset should not fail");
|
||||||
|
|
||||||
let preset: Preset;
|
let print_flag_page = |filtered_indices: &[usize],
|
||||||
let color_profile;
|
page_num: usize,
|
||||||
|
filter: &str,
|
||||||
|
hint: Option<&str>|
|
||||||
|
-> Result<()> {
|
||||||
|
let num_pages = filtered_indices.len().div_ceil(flags_per_page).max(1);
|
||||||
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
|
print_title_prompt(option_counter, "Let's choose a flag!");
|
||||||
|
println!(
|
||||||
|
"Available flag presets:\nPage: {page} of {num_pages}\n",
|
||||||
|
page = page_num + 1
|
||||||
|
);
|
||||||
|
|
||||||
let mut page: u8 = 0;
|
let start = page_num * flags_per_page;
|
||||||
loop {
|
let end = (start + flags_per_page).min(filtered_indices.len());
|
||||||
print_flag_page(&pages[usize::from(page)], page).context("failed to print flag page")?;
|
let mut visible_rows: usize = 0;
|
||||||
|
if start >= end {
|
||||||
|
println!("No presets matched this filter.");
|
||||||
|
} else {
|
||||||
|
for row in filtered_indices[start..end].chunks(usize::from(flags_per_row)) {
|
||||||
|
let row = row
|
||||||
|
.iter()
|
||||||
|
.map(|&idx| &flags[idx].1)
|
||||||
|
.collect::<Vec<&[String; 4]>>();
|
||||||
|
print_flag_row(&row, color_mode).context("failed to print flag row")?;
|
||||||
|
visible_rows += 1;
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
// Keep the prompt anchored by reserving a full page worth of flag rows.
|
||||||
|
for _ in visible_rows..usize::from(rows_per_page) {
|
||||||
|
for _ in 0..5 {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut opts: Vec<&str> = <Preset as VariantNames>::VARIANTS.into();
|
println!(
|
||||||
opts.extend(["next", "n", "prev", "p"]);
|
"Use the up/down arrow keys to go to the previous/next page. Type to filter and press Enter to select."
|
||||||
|
);
|
||||||
writeln!(
|
printc(
|
||||||
io::stdout(),
|
|
||||||
"Enter '[n]ext' to go to the next page and '[p]rev' to go to the previous page."
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
let selection = literal_input(
|
|
||||||
format!(
|
format!(
|
||||||
"Which {preset} do you want to use? ",
|
"Which {preset_default_colored} do you want to use? (default: {}, comma-separated for multiple at random)",
|
||||||
preset = preset_default_colored
|
Preset::Rainbow.as_ref()
|
||||||
),
|
),
|
||||||
&opts[..],
|
|
||||||
Preset::Rainbow.as_ref(),
|
|
||||||
false,
|
|
||||||
color_mode,
|
color_mode,
|
||||||
)
|
)
|
||||||
.context("failed to ask for choice input")
|
.context("failed to print preset prompt")?;
|
||||||
.context("failed to select preset")?;
|
print!("> {filter}");
|
||||||
if selection == "next" || selection == "n" {
|
io::stdout().flush().context("failed to flush preset prompt")?;
|
||||||
page = (page + 1) % num_pages;
|
|
||||||
} else if selection == "prev" || selection == "p" {
|
if let Some(hint) = hint {
|
||||||
page = (page + num_pages - 1) % num_pages;
|
println!("\n{hint}");
|
||||||
} else {
|
|
||||||
preset = selection.parse().expect("selected preset should be valid");
|
|
||||||
debug!(?preset, "selected preset");
|
|
||||||
color_profile = preset.color_profile();
|
|
||||||
update_title(
|
|
||||||
&mut title,
|
|
||||||
&mut option_counter,
|
|
||||||
"Selected flag",
|
|
||||||
&color_profile
|
|
||||||
.with_lightness_adaptive(default_lightness, theme)
|
|
||||||
.color_text(
|
|
||||||
preset.as_ref(),
|
|
||||||
color_mode,
|
|
||||||
ForegroundBackground::Foreground,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.expect("coloring text with selected preset should not fail"),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
let selected_preset_names: Vec<String>;
|
||||||
|
let color_profile;
|
||||||
|
|
||||||
|
let mut page: usize = 0;
|
||||||
|
let mut filter = String::new();
|
||||||
|
let mut hint: Option<&str> = None;
|
||||||
|
let mut raw_mode = RawModeGuard::new().context("failed to initialize raw input mode")?;
|
||||||
|
loop {
|
||||||
|
raw_mode
|
||||||
|
.disable()
|
||||||
|
.context("failed to disable raw mode for rendering")?;
|
||||||
|
let filter_lower = filter.to_ascii_lowercase();
|
||||||
|
let parts: Vec<&str> = filter_lower.split(',').collect();
|
||||||
|
let current_query = parts.last().cloned().unwrap_or("");
|
||||||
|
let filtered_indices = filter_flag_indices(current_query, &flags);
|
||||||
|
let num_pages = filtered_indices.len().div_ceil(flags_per_page).max(1);
|
||||||
|
page = page.min(num_pages - 1);
|
||||||
|
|
||||||
|
print_flag_page(&filtered_indices, page, &filter, hint)
|
||||||
|
.context("failed to print flag page")?;
|
||||||
|
hint = None;
|
||||||
|
|
||||||
|
raw_mode
|
||||||
|
.enable()
|
||||||
|
.context("failed to enable raw mode for key input")?;
|
||||||
|
let event = event::read().context("failed to read keyboard event")?;
|
||||||
|
let Event::Key(key) = event else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !matches!(key.kind, KeyEventKind::Press | KeyEventKind::Repeat) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Enter => {
|
||||||
|
let filter_lower = filter.to_ascii_lowercase();
|
||||||
|
let parts: Vec<&str> = filter_lower.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()).collect();
|
||||||
|
let mut resolved_presets = Vec::new();
|
||||||
|
|
||||||
|
if parts.is_empty() {
|
||||||
|
// Default to Rainbow if nothing is entered
|
||||||
|
resolved_presets.push(Preset::Rainbow.as_ref().to_owned());
|
||||||
|
} else {
|
||||||
|
for part in parts.iter() {
|
||||||
|
let selection = flags
|
||||||
|
.iter()
|
||||||
|
.find(|(_, _, name)| name == part)
|
||||||
|
.map(|(preset, _, _)| preset.as_ref().to_owned())
|
||||||
|
.or_else(|| {
|
||||||
|
// Fuzzy match each part
|
||||||
|
let filtered = filter_flag_indices(part, &flags);
|
||||||
|
filtered.first().map(|&idx| flags[idx].0.as_ref().to_owned())
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(p) = selection {
|
||||||
|
resolved_presets.push(p);
|
||||||
|
} else {
|
||||||
|
hint = Some("One or more presets could not be found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hint.is_none() {
|
||||||
|
selected_preset_names = resolved_presets;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
KeyCode::Up => {
|
||||||
|
page = (page + num_pages - 1) % num_pages;
|
||||||
|
},
|
||||||
|
KeyCode::Down => {
|
||||||
|
page = (page + 1) % num_pages;
|
||||||
|
},
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
filter.pop();
|
||||||
|
page = 0;
|
||||||
|
},
|
||||||
|
KeyCode::Esc => {
|
||||||
|
filter.clear();
|
||||||
|
page = 0;
|
||||||
|
},
|
||||||
|
KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||||
|
raw_mode
|
||||||
|
.disable()
|
||||||
|
.context("failed to disable raw mode before interrupting")?;
|
||||||
|
println!();
|
||||||
|
return Err(anyhow::anyhow!("interrupted by user"));
|
||||||
|
},
|
||||||
|
KeyCode::Char(c)
|
||||||
|
if !key.modifiers.contains(KeyModifiers::CONTROL)
|
||||||
|
&& !key.modifiers.contains(KeyModifiers::ALT) =>
|
||||||
|
{
|
||||||
|
filter.push(c);
|
||||||
|
page = 0;
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raw_mode
|
||||||
|
.disable()
|
||||||
|
.context("failed to disable raw mode after preset selection")?;
|
||||||
|
|
||||||
|
let selected_presets = if selected_preset_names.len() > 1 {
|
||||||
|
PresetValue::Multiple(selected_preset_names.clone())
|
||||||
|
} else {
|
||||||
|
PresetValue::Single(selected_preset_names.first().cloned().unwrap_or_else(|| Preset::Rainbow.as_ref().to_owned()))
|
||||||
|
};
|
||||||
|
|
||||||
|
color_profile = {
|
||||||
|
let first_name = selected_preset_names.first().cloned().unwrap_or_else(|| Preset::Rainbow.as_ref().to_owned());
|
||||||
|
if first_name.contains('#') {
|
||||||
|
let colors: Vec<String> = first_name.split(',').map(|s| s.trim().to_owned()).collect();
|
||||||
|
build_hex_color_profile(&colors).expect("hex colors should be valid")
|
||||||
|
} else {
|
||||||
|
flags.iter().find(|(_, _, name)| name == &first_name).map(|(p, _, _)| p.color_profile()).unwrap_or_else(|| Preset::Rainbow.color_profile())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let colored_names = selected_preset_names.iter().map(|name| {
|
||||||
|
let profile = if name.contains('#') {
|
||||||
|
let colors: Vec<String> = name.split(',').map(|s| s.trim().to_owned()).collect();
|
||||||
|
build_hex_color_profile(&colors).expect("hex colors should be valid")
|
||||||
|
} else {
|
||||||
|
flags.iter().find(|(_, _, n)| n == name).map(|(p, _, _)| p.color_profile()).unwrap_or_else(|| Preset::Rainbow.color_profile())
|
||||||
|
};
|
||||||
|
profile.with_lightness_adaptive(default_lightness, theme)
|
||||||
|
.color_text(name, color_mode, ForegroundBackground::Foreground, false)
|
||||||
|
.expect("coloring text should not fail")
|
||||||
|
}).join(", ");
|
||||||
|
|
||||||
|
let label = if selected_preset_names.len() > 1 {
|
||||||
|
"Selected flags (random)"
|
||||||
|
} else {
|
||||||
|
"Selected flag"
|
||||||
|
};
|
||||||
|
|
||||||
|
update_title(
|
||||||
|
&mut title,
|
||||||
|
&mut option_counter,
|
||||||
|
label,
|
||||||
|
&colored_names,
|
||||||
|
);
|
||||||
|
|
||||||
|
printc(
|
||||||
|
format!(
|
||||||
|
"Which {preset_default_colored} do you want to use? {}\n",
|
||||||
|
colored_names
|
||||||
|
),
|
||||||
|
color_mode,
|
||||||
|
)
|
||||||
|
.context("failed to print preset selection summary")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@@ -624,22 +817,15 @@ fn create_config(
|
|||||||
|
|
||||||
let select_lightness = || -> Result<Lightness> {
|
let select_lightness = || -> Result<Lightness> {
|
||||||
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
print_title_prompt(
|
print_title_prompt(option_counter, "Let's adjust the color brightness!");
|
||||||
option_counter,
|
println!(
|
||||||
"Let's adjust the color brightness!",
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
writeln!(
|
|
||||||
io::stdout(),
|
|
||||||
"The colors might be a little bit too {bright_dark} for {light_dark} mode.\n",
|
"The colors might be a little bit too {bright_dark} for {light_dark} mode.\n",
|
||||||
bright_dark = match theme {
|
bright_dark = match theme {
|
||||||
TerminalTheme::Light => "bright",
|
TerminalTheme::Light => "bright",
|
||||||
TerminalTheme::Dark => "dark",
|
TerminalTheme::Dark => "dark",
|
||||||
},
|
},
|
||||||
light_dark = theme.as_ref()
|
light_dark = theme.as_ref()
|
||||||
)
|
);
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
|
|
||||||
let color_align = ColorAlignment::Horizontal;
|
let color_align = ColorAlignment::Horizontal;
|
||||||
|
|
||||||
@@ -697,14 +883,10 @@ fn create_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
writeln!(
|
println!("\nWhich brightness level looks the best? (Default: {default:.0}% for {light_dark} mode)",
|
||||||
io::stdout(),
|
|
||||||
"\nWhich brightness level looks the best? (Default: {default:.0}% for \
|
|
||||||
{light_dark} mode)",
|
|
||||||
default = f32::from(default_lightness) * 100.0,
|
default = f32::from(default_lightness) * 100.0,
|
||||||
light_dark = theme.as_ref()
|
light_dark = theme.as_ref()
|
||||||
)
|
);
|
||||||
.context("failed to write prompt to stdout")?;
|
|
||||||
let lightness = input(Some("> "))
|
let lightness = input(Some("> "))
|
||||||
.context("failed to read input")?
|
.context("failed to read input")?
|
||||||
.trim()
|
.trim()
|
||||||
@@ -716,12 +898,7 @@ fn create_config(
|
|||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!(%err, "could not parse lightness");
|
debug!(%err, "could not parse lightness");
|
||||||
printc(
|
printc!("&cUnable to parse lightness value, please enter a lightness value such as 45%, .45, or 45");
|
||||||
"&cUnable to parse lightness value, please enter a lightness value such \
|
|
||||||
as 45%, .45, or 45",
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print message")?;
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -769,8 +946,11 @@ fn create_config(
|
|||||||
// get distro string and convert it into the enum, neofetch friendly format, so we can check for small logos with the {distro}_small neofetch naming scheme.
|
// get distro string and convert it into the enum, neofetch friendly format, so we can check for small logos with the {distro}_small neofetch naming scheme.
|
||||||
let tmp_dst = get_distro_name(backend).or_else(|_| get_distro_name(Backend::Neofetch)).context("failed to get distro name")?;
|
let tmp_dst = get_distro_name(backend).or_else(|_| get_distro_name(Backend::Neofetch)).context("failed to get distro name")?;
|
||||||
let detected_dst = Some(distro.map_or_else(
|
let detected_dst = Some(distro.map_or_else(
|
||||||
|| format!("{:?}", Distro::detect(tmp_dst).unwrap()),
|
|| {
|
||||||
|d| d.to_string(),
|
Distro::detect(&tmp_dst)
|
||||||
|
.map_or("".to_string(), |d| format!("{:?}", d).to_lowercase())
|
||||||
|
},
|
||||||
|
|d| d.to_string().to_lowercase(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// in case someone specified {distro}_small already in the --distro arg
|
// in case someone specified {distro}_small already in the --distro arg
|
||||||
@@ -846,15 +1026,10 @@ fn create_config(
|
|||||||
printc(line.join(" "), color_mode).context("failed to print ascii line")?;
|
printc(line.join(" "), color_mode).context("failed to print ascii line")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
print_title_prompt(
|
print_title_prompt(option_counter, "Do you want the default logo, or the small logo?");
|
||||||
option_counter,
|
|
||||||
"Do you want the default logo, or the small logo?",
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
let opts: Vec<Cow<str>> = ["default", "small"].map(Into::into).into();
|
let opts: Vec<Cow<str>> = ["default", "small"].map(Into::into).into();
|
||||||
let choice = literal_input("Your choice?", &opts[..], "default", true, color_mode)
|
let choice = literal_input("Your choice?", &opts[..], "default", true, color_mode)
|
||||||
.context("failed to ask for choice input")
|
.context("failed to ask for choice input")
|
||||||
@@ -969,21 +1144,11 @@ fn create_config(
|
|||||||
}
|
}
|
||||||
printc(line.join(" "), color_mode).context("failed to print ascii line")?;
|
printc(line.join(" "), color_mode).context("failed to print ascii line")?;
|
||||||
}
|
}
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
print_title_prompt(
|
print_title_prompt(option_counter, "Let's choose a color arrangement!");
|
||||||
option_counter,
|
println!("You can choose standard horizontal or vertical alignment, or use one of the random color schemes.\nYou can type \"roll\" to randomize again.\n");
|
||||||
"Let's choose a color arrangement!",
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
writeln!(
|
|
||||||
io::stdout(),
|
|
||||||
"You can choose standard horizontal or vertical alignment, or use one of the random \
|
|
||||||
color schemes.\nYou can type \"roll\" to randomize again.\n"
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
let mut opts: Vec<Cow<str>> = ["horizontal", "vertical", "roll"].map(Into::into).into();
|
let mut opts: Vec<Cow<str>> = ["horizontal", "vertical", "roll"].map(Into::into).into();
|
||||||
opts.extend((0..random_count).map(|i| format!("random{i}").into()));
|
opts.extend((0..random_count).map(|i| format!("random{i}").into()));
|
||||||
let choice = literal_input("Your choice?", &opts[..], "horizontal", true, color_mode)
|
let choice = literal_input("Your choice?", &opts[..], "horizontal", true, color_mode)
|
||||||
@@ -996,16 +1161,19 @@ fn create_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save choice
|
// Save choice
|
||||||
color_align = arrangements
|
color_align = if choice == "horizontal" { ColorAlignment::Horizontal }
|
||||||
.into_iter()
|
else if choice == "vertical" { ColorAlignment::Vertical }
|
||||||
.find_map(|(k, ca)| {
|
else {
|
||||||
if k.to_lowercase() == choice {
|
arrangements.into_iter()
|
||||||
Some(ca)
|
.find_map(|(k, ca)| {
|
||||||
} else {
|
if k.to_lowercase() == choice {
|
||||||
None
|
Some(ca)
|
||||||
}
|
} else {
|
||||||
})
|
None
|
||||||
.expect("selected color alignment should be valid");
|
}
|
||||||
|
})
|
||||||
|
.expect("selected color alignment is not valid") // TODO: it sould ask the user to retry instead of panicking
|
||||||
|
};
|
||||||
debug!(?color_align, "selected color alignment");
|
debug!(?color_align, "selected color alignment");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1022,42 +1190,27 @@ fn create_config(
|
|||||||
|
|
||||||
let select_backend = || -> Result<Backend> {
|
let select_backend = || -> Result<Backend> {
|
||||||
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
print_title_prompt(option_counter, "Select a *fetch backend", color_mode)
|
print_title_prompt(option_counter, "Select a *fetch backend");
|
||||||
.context("failed to print title prompt")?;
|
|
||||||
|
|
||||||
// Check if fastfetch is installed
|
// Check if fastfetch is installed
|
||||||
let fastfetch_path = fastfetch_path().ok();
|
let fastfetch_path = fastfetch_path().ok();
|
||||||
|
|
||||||
// Check if macchina is installed
|
// Check if macchina is installed
|
||||||
#[cfg(feature = "macchina")]
|
#[cfg(feature = "macchina")]
|
||||||
let macchina_path = macchina_path().context("failed to get macchina path")?;
|
let macchina_path = macchina_path().unwrap_or(None);
|
||||||
|
|
||||||
printc(
|
printc!("- &bneofetch&r: Written in bash, &nbest compatibility&r on Unix systems");
|
||||||
"- &bneofetch&r: Written in bash, &nbest compatibility&r on Unix systems",
|
printc!("- &bfastfetch&r: Written in C, &nbest performance&r {}",
|
||||||
color_mode,
|
fastfetch_path
|
||||||
)
|
.map(|path| format!("&a(Installed at {path})", path = path.display()))
|
||||||
.context("failed to print message")?;
|
.unwrap_or_else(|| "&c(Not installed)".to_owned())
|
||||||
printc(
|
);
|
||||||
format!(
|
|
||||||
"- &bfastfetch&r: Written in C, &nbest performance&r {installed_not_installed}",
|
|
||||||
installed_not_installed = fastfetch_path
|
|
||||||
.map(|path| format!("&a(Installed at {path})", path = path.display()))
|
|
||||||
.unwrap_or_else(|| "&c(Not installed)".to_owned())
|
|
||||||
),
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print message")?;
|
|
||||||
#[cfg(feature = "macchina")]
|
#[cfg(feature = "macchina")]
|
||||||
printc(
|
printc!("- &bmacchina&r: Written in Rust, &nbest performance&r {}\n",
|
||||||
format!(
|
macchina_path
|
||||||
"- &bmacchina&r: Written in Rust, &nbest performance&r {installed_not_installed}\n",
|
.map(|path| format!("&a(Installed at {path})", path = path.display()))
|
||||||
installed_not_installed = macchina_path
|
.unwrap_or_else(|| "&c(Not installed)".to_owned())
|
||||||
.map(|path| format!("&a(Installed at {path})", path = path.display()))
|
);
|
||||||
.unwrap_or_else(|| "&c(Not installed)".to_owned())
|
|
||||||
),
|
|
||||||
color_mode,
|
|
||||||
)
|
|
||||||
.context("failed to print message")?;
|
|
||||||
|
|
||||||
let choice = literal_input(
|
let choice = literal_input(
|
||||||
"Your choice?",
|
"Your choice?",
|
||||||
@@ -1078,10 +1231,56 @@ fn create_config(
|
|||||||
backend.as_ref(),
|
backend.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// 8. Custom ASCII file
|
||||||
|
let mut custom_ascii_path: Option<String> = None;
|
||||||
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
|
let choice = literal_input(
|
||||||
|
"Do you want to specify a custom ASCII file?",
|
||||||
|
&["y", "n"],
|
||||||
|
"n",
|
||||||
|
true,
|
||||||
|
color_mode,
|
||||||
|
)
|
||||||
|
.context("failed to ask for choice input")?;
|
||||||
|
|
||||||
|
if choice == "y" {
|
||||||
|
loop {
|
||||||
|
let pth = input(Some("Path to custom ASCII file (must be UTF-8 encoded, empty to skip): "))?.trim().to_owned();
|
||||||
|
if pth.is_empty() {
|
||||||
|
printc!("&cNo path entered. Skipping custom ASCII file.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pth_buf = PathBuf::from(&pth);
|
||||||
|
if !pth_buf.is_file() {
|
||||||
|
printc!("&cError: File not found at {pth}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match fs::read_to_string(&pth_buf) {
|
||||||
|
Ok(_) => {
|
||||||
|
custom_ascii_path = Some(pth);
|
||||||
|
update_title(
|
||||||
|
&mut title,
|
||||||
|
&mut option_counter,
|
||||||
|
"Custom ASCII file",
|
||||||
|
custom_ascii_path.as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
printc!("&cError: File is not UTF-8 encoded or an unexpected error occurred: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create config
|
// Create config
|
||||||
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
|
||||||
let config = Config {
|
let config = Config {
|
||||||
preset,
|
preset: selected_presets,
|
||||||
mode: color_mode,
|
mode: color_mode,
|
||||||
light_dark: Some(theme),
|
light_dark: Some(theme),
|
||||||
auto_detect_light_dark: Some(det_bg.is_some()),
|
auto_detect_light_dark: Some(det_bg.is_some()),
|
||||||
@@ -1091,6 +1290,8 @@ fn create_config(
|
|||||||
args: None,
|
args: None,
|
||||||
distro: logo_chosen,
|
distro: logo_chosen,
|
||||||
pride_month_disable: false,
|
pride_month_disable: false,
|
||||||
|
custom_ascii_path,
|
||||||
|
custom_presets: None,
|
||||||
};
|
};
|
||||||
debug!(?config, "created config");
|
debug!(?config, "created config");
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use bpaf::ShellComp;
|
|||||||
use bpaf::{construct, long, OptionParser, Parser as _};
|
use bpaf::{construct, long, OptionParser, Parser as _};
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use strum::{VariantArray, VariantNames};
|
use strum::VariantNames;
|
||||||
|
|
||||||
use crate::color_util::{color, Lightness};
|
use crate::color_util::{color, Lightness};
|
||||||
use crate::presets::Preset;
|
use crate::presets::Preset;
|
||||||
@@ -18,7 +18,7 @@ use crate::types::{AnsiMode, Backend};
|
|||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub config: bool,
|
pub config: bool,
|
||||||
pub config_file: PathBuf,
|
pub config_file: PathBuf,
|
||||||
pub preset: Option<Preset>,
|
pub preset: Option<String>,
|
||||||
pub mode: Option<AnsiMode>,
|
pub mode: Option<AnsiMode>,
|
||||||
pub backend: Option<Backend>,
|
pub backend: Option<Backend>,
|
||||||
pub args: Option<Vec<String>>,
|
pub args: Option<Vec<String>>,
|
||||||
@@ -55,7 +55,7 @@ pub fn options() -> OptionParser<Options> {
|
|||||||
let preset = long("preset")
|
let preset = long("preset")
|
||||||
.short('p')
|
.short('p')
|
||||||
.help(&*format!(
|
.help(&*format!(
|
||||||
"Use preset
|
"Use preset or comma-separated color list or comma-separated hex colors (e.g., \"#ff0000,#00ff00,#0000ff\"). Comma-separated preset names will pick one randomly.
|
||||||
PRESET={{{presets}}}",
|
PRESET={{{presets}}}",
|
||||||
presets = <Preset as VariantNames>::VARIANTS
|
presets = <Preset as VariantNames>::VARIANTS
|
||||||
.iter()
|
.iter()
|
||||||
@@ -65,30 +65,7 @@ PRESET={{{presets}}}",
|
|||||||
.argument::<String>("PRESET");
|
.argument::<String>("PRESET");
|
||||||
#[cfg(feature = "autocomplete")]
|
#[cfg(feature = "autocomplete")]
|
||||||
let preset = preset.complete(complete_preset);
|
let preset = preset.complete(complete_preset);
|
||||||
let preset = preset
|
let preset = preset.optional();
|
||||||
.parse(|s| {
|
|
||||||
Preset::from_str(&s)
|
|
||||||
.or_else(|e| {
|
|
||||||
if s == "random" {
|
|
||||||
let mut rng = fastrand::Rng::new();
|
|
||||||
Ok(*rng
|
|
||||||
.choice(<Preset as VariantArray>::VARIANTS)
|
|
||||||
.expect("preset iterator should not be empty"))
|
|
||||||
} else {
|
|
||||||
Err(e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"PRESET should be one of {{{presets}}}",
|
|
||||||
presets = <Preset as VariantNames>::VARIANTS
|
|
||||||
.iter()
|
|
||||||
.chain(iter::once(&"random"))
|
|
||||||
.join(",")
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.optional();
|
|
||||||
let mode = long("mode")
|
let mode = long("mode")
|
||||||
.short('m')
|
.short('m')
|
||||||
.help(&*format!(
|
.help(&*format!(
|
||||||
|
|||||||
@@ -0,0 +1,232 @@
|
|||||||
|
use std::iter;
|
||||||
|
use std::num::{NonZeroU8, NonZeroUsize};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result, Context as _};
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
use palette::num::ClampAssign as _;
|
||||||
|
use palette::{IntoColorMut as _, LinSrgb, Okhsl, Srgb};
|
||||||
|
use tracing::debug;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation as _;
|
||||||
|
|
||||||
|
use crate::color_util::{ForegroundBackground, Lightness, ToAnsiString as _};
|
||||||
|
use crate::types::{AnsiMode, TerminalTheme};
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub struct ColorProfile {
|
||||||
|
pub colors: Vec<Srgb<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum AssignLightness {
|
||||||
|
Replace(Lightness),
|
||||||
|
ClampMax(Lightness),
|
||||||
|
ClampMin(Lightness),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorProfile {
|
||||||
|
pub fn new(colors: Vec<Srgb<u8>>) -> Self {
|
||||||
|
Self { colors }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_hex_colors<S>(hex_colors: Vec<S>) -> Result<Self>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let colors = hex_colors
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| s.as_ref().parse())
|
||||||
|
.collect::<Result<_, _>>()
|
||||||
|
.context("failed to parse hex colors")?;
|
||||||
|
Ok(Self::new(colors))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps colors based on weights.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `weights` - Weights of each color (`weights[i]` = how many times
|
||||||
|
/// `colors[i]` appears)
|
||||||
|
pub fn with_weights(&self, weights: Vec<u8>) -> Result<Self> {
|
||||||
|
if weights.len() != self.colors.len() {
|
||||||
|
debug!(?weights, ?self.colors, "length mismatch between `weights` and `colors`");
|
||||||
|
return Err(anyhow!(
|
||||||
|
"`weights` should have the same number of elements as `colors`"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut weighted_colors = Vec::new();
|
||||||
|
|
||||||
|
for (i, w) in weights.into_iter().enumerate() {
|
||||||
|
weighted_colors.extend(iter::repeat(self.colors[i]).take(usize::from(w)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self::new(weighted_colors))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new color profile, with the colors spread to the specified
|
||||||
|
/// length.
|
||||||
|
pub fn with_length(&self, length: NonZeroU8) -> Result<Self> {
|
||||||
|
let orig_len = self.colors.len();
|
||||||
|
let orig_len: NonZeroUsize = orig_len.try_into().expect("`colors` should not be empty");
|
||||||
|
let orig_len: NonZeroU8 = orig_len
|
||||||
|
.try_into()
|
||||||
|
.expect("`colors` should not have more than 255 elements");
|
||||||
|
// TODO: I believe weird things can happen because of this...
|
||||||
|
// if length < orig_len {
|
||||||
|
// unimplemented!("compressing length of color profile not implemented");
|
||||||
|
// }
|
||||||
|
let center_i = usize::from(orig_len.get() / 2);
|
||||||
|
|
||||||
|
// How many copies of each color should be displayed at least?
|
||||||
|
let repeats = length.get().div_euclid(orig_len.get());
|
||||||
|
let mut weights = vec![repeats; NonZeroUsize::from(orig_len).get()];
|
||||||
|
|
||||||
|
// How many extra spaces left?
|
||||||
|
let mut extras = length.get().rem_euclid(orig_len.get());
|
||||||
|
|
||||||
|
// If there is an odd space left, extend the center by one space
|
||||||
|
if extras % 2 == 1 {
|
||||||
|
weights[center_i] = weights[center_i].checked_add(1).unwrap();
|
||||||
|
extras = extras.checked_sub(1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add weight to border until there's no space left (extras must be even at this
|
||||||
|
// point)
|
||||||
|
let weights_len = weights.len();
|
||||||
|
for border_i in 0..usize::from(extras / 2) {
|
||||||
|
weights[border_i] = weights[border_i].checked_add(1).unwrap();
|
||||||
|
let border_opp = weights_len
|
||||||
|
.checked_sub(border_i)
|
||||||
|
.unwrap()
|
||||||
|
.checked_sub(1)
|
||||||
|
.unwrap();
|
||||||
|
weights[border_opp] = weights[border_opp].checked_add(1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.with_weights(weights)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Colors a text.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `foreground_background` - Whether the color is shown on the foreground
|
||||||
|
/// text or the background block
|
||||||
|
/// * `space_only` - Whether to only color spaces
|
||||||
|
pub fn color_text<S>(
|
||||||
|
&self,
|
||||||
|
txt: S,
|
||||||
|
color_mode: AnsiMode,
|
||||||
|
foreground_background: ForegroundBackground,
|
||||||
|
space_only: bool,
|
||||||
|
) -> Result<String>
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let txt = txt.as_ref();
|
||||||
|
|
||||||
|
let txt: Vec<&str> = txt.graphemes(true).collect();
|
||||||
|
|
||||||
|
let ColorProfile { colors } = {
|
||||||
|
let length = txt.len();
|
||||||
|
let length: NonZeroUsize = length.try_into().context("`txt` should not be empty")?;
|
||||||
|
let length: NonZeroU8 = length.try_into().with_context(|| {
|
||||||
|
format!(
|
||||||
|
"`txt` should not have more than {limit} characters",
|
||||||
|
limit = u8::MAX
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
self.with_length(length)
|
||||||
|
.with_context(|| format!("failed to spread color profile to length {length}"))?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
for (i, &gr) in txt.iter().enumerate() {
|
||||||
|
if space_only && gr != " " {
|
||||||
|
if i > 0 && txt[i.checked_sub(1).unwrap()] == " " {
|
||||||
|
buf.push_str("\x1b[39;49m");
|
||||||
|
}
|
||||||
|
buf.push_str(gr);
|
||||||
|
} else {
|
||||||
|
buf.push_str(&colors[i].to_ansi_string(color_mode, foreground_background));
|
||||||
|
buf.push_str(gr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push_str("\x1b[39;49m");
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new color profile, with the colors lightened by a multiplier.
|
||||||
|
pub fn lighten(&self, multiplier: f32) -> Self {
|
||||||
|
let mut rgb_f32_colors: Vec<LinSrgb> =
|
||||||
|
self.colors.iter().map(|c| c.into_linear()).collect();
|
||||||
|
|
||||||
|
{
|
||||||
|
let okhsl_f32_colors: &mut [Okhsl] = &mut rgb_f32_colors.into_color_mut();
|
||||||
|
|
||||||
|
for okhsl_f32_color in okhsl_f32_colors {
|
||||||
|
okhsl_f32_color.lightness *= multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rgb_u8_colors: Vec<_> = rgb_f32_colors
|
||||||
|
.into_iter()
|
||||||
|
.map(Srgb::<u8>::from_linear)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
colors: rgb_u8_colors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new color profile, with the colors set to the specified
|
||||||
|
/// [`Okhsl`] lightness value.
|
||||||
|
pub fn with_lightness(&self, assign_lightness: AssignLightness) -> Self {
|
||||||
|
let mut rgb_f32_colors: Vec<LinSrgb> =
|
||||||
|
self.colors.iter().map(|c| c.into_linear()).collect();
|
||||||
|
|
||||||
|
{
|
||||||
|
let okhsl_f32_colors: &mut [Okhsl] = &mut rgb_f32_colors.into_color_mut();
|
||||||
|
|
||||||
|
for okhsl_f32_color in okhsl_f32_colors {
|
||||||
|
match assign_lightness {
|
||||||
|
AssignLightness::Replace(lightness) => {
|
||||||
|
okhsl_f32_color.lightness = lightness.into();
|
||||||
|
},
|
||||||
|
AssignLightness::ClampMax(lightness) => {
|
||||||
|
okhsl_f32_color.lightness.clamp_max_assign(lightness.into());
|
||||||
|
},
|
||||||
|
AssignLightness::ClampMin(lightness) => {
|
||||||
|
okhsl_f32_color.lightness.clamp_min_assign(lightness.into());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rgb_u8_colors: Vec<Srgb<u8>> = rgb_f32_colors
|
||||||
|
.into_iter()
|
||||||
|
.map(Srgb::<u8>::from_linear)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
colors: rgb_u8_colors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new color profile, with the colors set to the specified
|
||||||
|
/// [`Okhsl`] lightness value, adapted to the terminal theme.
|
||||||
|
pub fn with_lightness_adaptive(&self, lightness: Lightness, theme: TerminalTheme) -> Self {
|
||||||
|
match theme {
|
||||||
|
TerminalTheme::Dark => self.with_lightness(AssignLightness::ClampMin(lightness)),
|
||||||
|
TerminalTheme::Light => self.with_lightness(AssignLightness::ClampMax(lightness)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates another color profile with only the unique colors.
|
||||||
|
pub fn unique_colors(&self) -> Self {
|
||||||
|
let unique_colors: IndexSet<[u8; 3]> = self.colors.iter().map(|&c| c.into()).collect();
|
||||||
|
let unique_colors: Vec<Srgb<u8>> = unique_colors.into_iter().map(|c| c.into()).collect();
|
||||||
|
Self::new(unique_colors)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -403,18 +403,20 @@ where
|
|||||||
Ok(dst)
|
Ok(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! printc {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
println!("{}", color(format!("{}&r", format!($($arg)*)), AnsiMode::Rgb).expect("failed to color message"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Prints with color.
|
/// Prints with color.
|
||||||
pub fn printc<S>(msg: S, mode: AnsiMode) -> Result<()>
|
pub fn printc<S>(msg: S, mode: AnsiMode) -> Result<()>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
writeln!(
|
println!("{msg}", msg = color(format!("{msg}&r", msg = msg.as_ref()), mode).context("failed to color message")?);
|
||||||
io::stdout(),
|
Ok(())
|
||||||
"{msg}",
|
|
||||||
msg = color(format!("{msg}&r", msg = msg.as_ref()), mode)
|
|
||||||
.context("failed to color message")?
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears screen using ANSI escape codes.
|
/// Clears screen using ANSI escape codes.
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ pub mod presets;
|
|||||||
pub mod pride_month;
|
pub mod pride_month;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod color_profile;
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::{Context as _, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::color_profile::ColorProfile;
|
||||||
use crate::color_util::Lightness;
|
use crate::color_util::Lightness;
|
||||||
use crate::neofetch_util::ColorAlignment;
|
use crate::neofetch_util::ColorAlignment;
|
||||||
use crate::presets::Preset;
|
|
||||||
use crate::types::{AnsiMode, Backend, TerminalTheme};
|
use crate::types::{AnsiMode, Backend, TerminalTheme};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub preset: Preset,
|
pub preset: PresetValue,
|
||||||
pub mode: AnsiMode,
|
pub mode: AnsiMode,
|
||||||
pub auto_detect_light_dark: Option<bool>,
|
pub auto_detect_light_dark: Option<bool>,
|
||||||
pub light_dark: Option<TerminalTheme>,
|
pub light_dark: Option<TerminalTheme>,
|
||||||
@@ -19,6 +22,8 @@ pub struct Config {
|
|||||||
pub args: Option<Vec<String>>,
|
pub args: Option<Vec<String>>,
|
||||||
pub distro: Option<String>,
|
pub distro: Option<String>,
|
||||||
pub pride_month_disable: bool,
|
pub pride_month_disable: bool,
|
||||||
|
pub custom_ascii_path: Option<String>,
|
||||||
|
pub custom_presets: Option<HashMap<String, Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -32,6 +37,40 @@ impl Config {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn custom_preset_profiles(&self) -> Result<HashMap<String, ColorProfile>> {
|
||||||
|
let mut profiles = HashMap::new();
|
||||||
|
if let Some(custom_presets) = &self.custom_presets {
|
||||||
|
for (preset_name, colors) in custom_presets {
|
||||||
|
if preset_name == "random" {
|
||||||
|
return Err(anyhow::anyhow!("custom preset key `random` is reserved"));
|
||||||
|
}
|
||||||
|
let color_profile = build_hex_color_profile(colors).with_context(|| {
|
||||||
|
format!("failed to validate custom preset key `{preset_name}`")
|
||||||
|
})?;
|
||||||
|
profiles.insert(preset_name.clone(), color_profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(profiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_hex_color_profile(hex_colors: &[String]) -> Result<ColorProfile> {
|
||||||
|
if hex_colors.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("hex color list cannot be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for color in hex_colors {
|
||||||
|
if !color.starts_with('#')
|
||||||
|
|| (color.len() != 4 && color.len() != 7)
|
||||||
|
|| !color[1..].chars().all(|c| c.is_ascii_hexdigit())
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!("invalid hex color: {color}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorProfile::from_hex_colors(hex_colors.to_vec())
|
||||||
|
.context("failed to create color profile from hex")
|
||||||
}
|
}
|
||||||
|
|
||||||
mod args_serde {
|
mod args_serde {
|
||||||
@@ -117,3 +156,33 @@ mod args_serde {
|
|||||||
deserializer.deserialize_option(OptionVisitor)
|
deserializer.deserialize_option(OptionVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum PresetValue {
|
||||||
|
Single(String),
|
||||||
|
Multiple(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for PresetValue {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
PresetValue::Single(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PresetValue {
|
||||||
|
pub fn get_random_if_multiple(&self) -> String {
|
||||||
|
match self {
|
||||||
|
PresetValue::Single(s) => s.clone(),
|
||||||
|
PresetValue::Multiple(v) => {
|
||||||
|
if v.is_empty() {
|
||||||
|
"random".to_owned()
|
||||||
|
} else {
|
||||||
|
let mut rng = fastrand::Rng::new();
|
||||||
|
let selected_index = rng.usize(0..v.len());
|
||||||
|
v[selected_index].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
#[cfg(feature = "macchina")]
|
#[cfg(feature = "macchina")]
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Write as _};
|
use std::io::{Write as _};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
@@ -113,16 +113,12 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(selected) = find_selection(&selection, options) {
|
if let Some(selected) = find_selection(&selection, options) {
|
||||||
writeln!(io::stdout()).context("failed to write to stdout")?;
|
println!();
|
||||||
|
|
||||||
return Ok(selected);
|
return Ok(selected);
|
||||||
} else {
|
} else {
|
||||||
let options_text = options.iter().map(AsRef::as_ref).join("|");
|
let options_text = options.iter().map(AsRef::as_ref).join("|");
|
||||||
writeln!(
|
println!("Invalid selection! {selection} is not one of {options_text}");
|
||||||
io::stdout(),
|
|
||||||
"Invalid selection! {selection} is not one of {options_text}"
|
|
||||||
)
|
|
||||||
.context("failed to write message to stdout")?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +153,13 @@ pub fn add_pkg_path() -> Result<()> {
|
|||||||
// Get PATH
|
// Get PATH
|
||||||
let pv = &env::var_os("PATH").context("`PATH` env var is not set or invalid")?;
|
let pv = &env::var_os("PATH").context("`PATH` env var is not set or invalid")?;
|
||||||
let mut path = env::split_paths(pv).collect::<Vec<_>>();
|
let mut path = env::split_paths(pv).collect::<Vec<_>>();
|
||||||
let exe = env::current_exe().context("failed to get path of current running executable")?;
|
let exe = match env::current_exe() {
|
||||||
|
Ok(exe) => exe,
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Failed to get path of current running executable: {}", e);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
let base = exe.parent().unwrap();
|
let base = exe.parent().unwrap();
|
||||||
|
|
||||||
// Add from bin: ../git, ../fastfetch, ../scripts
|
// Add from bin: ../git, ../fastfetch, ../scripts
|
||||||
@@ -237,27 +239,27 @@ pub fn get_distro_ascii<S>(distro: Option<S>, backend: Backend) -> Result<RawAsc
|
|||||||
where
|
where
|
||||||
S: AsRef<str> + fmt::Debug,
|
S: AsRef<str> + fmt::Debug,
|
||||||
{
|
{
|
||||||
let distro: Cow<_> = if let Some(distro) = distro.as_ref() {
|
let distro_name: Cow<_> = if let Some(distro) = distro.as_ref() {
|
||||||
distro.as_ref().into()
|
distro.as_ref().into()
|
||||||
} else {
|
} else {
|
||||||
get_distro_name(backend)
|
get_distro_name(backend)
|
||||||
.context("failed to get distro name")?
|
.context("failed to get distro name")?
|
||||||
.into()
|
.into()
|
||||||
};
|
};
|
||||||
debug!(%distro, "distro name");
|
debug!(%distro_name, "distro name");
|
||||||
|
|
||||||
// Try new codegen-based detection method
|
// Try new codegen-based detection method
|
||||||
if let Some(distro) = Distro::detect(&distro) {
|
if let Some(distro) = Distro::detect(&distro_name) {
|
||||||
let asc = distro.ascii_art().to_owned();
|
let asc = distro.ascii_art().to_owned();
|
||||||
let fg = ascii_foreground(&distro);
|
let fg = ascii_foreground(&distro);
|
||||||
|
|
||||||
return Ok(RawAsciiArt { asc, fg });
|
return Ok(RawAsciiArt { asc, fg });
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(%distro, "could not find a match for distro; falling back to neofetch");
|
debug!(%distro_name, "could not find a match for distro; falling back to neofetch");
|
||||||
|
|
||||||
// Old detection method that calls neofetch
|
// Old detection method that calls neofetch
|
||||||
let asc = run_neofetch_command_piped(&["print_ascii", "--ascii_distro", distro.as_ref()])
|
let asc = run_neofetch_command_piped(&["print_ascii", "--ascii_distro", distro_name.as_ref()])
|
||||||
.context("failed to get ascii art from neofetch")?;
|
.context("failed to get ascii art from neofetch")?;
|
||||||
|
|
||||||
// Unescape backslashes here because backslashes are escaped in neofetch for
|
// Unescape backslashes here because backslashes are escaped in neofetch for
|
||||||
@@ -285,7 +287,7 @@ pub fn run(asc: RecoloredAsciiArt, backend: Backend, args: Option<&Vec<String>>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets distro ascii width and height, ignoring color code.
|
/// Gets distro ascii width and height, ignoring color code.
|
||||||
pub fn ascii_size<S>(asc: S) -> Result<(u8, u8)>
|
pub fn ascii_size<S>(asc: S) -> Result<(u16, u16)>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
@@ -307,56 +309,64 @@ where
|
|||||||
return Ok((0, 0));
|
return Ok((0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = asc
|
let width = asc.lines()
|
||||||
.lines()
|
.map(|line| line.graphemes(true).count()).max()
|
||||||
.map(|line| line.graphemes(true).count())
|
|
||||||
.max()
|
|
||||||
.expect("line iterator should not be empty");
|
.expect("line iterator should not be empty");
|
||||||
let width: u8 = width.try_into().with_context(|| {
|
let width: u16 = width.try_into().context("ascii art width should fit in u16")?;
|
||||||
format!(
|
let height: u16 = asc.lines().count().try_into().context("ascii art height should fit in u16")?;
|
||||||
"`asc` should not have more than {limit} characters per line",
|
|
||||||
limit = u8::MAX
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let height = asc.lines().count();
|
|
||||||
let height: u8 = height.try_into().with_context(|| {
|
|
||||||
format!(
|
|
||||||
"`asc` should not have more than {limit} lines",
|
|
||||||
limit = u8::MAX
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok((width, height))
|
Ok((width, height))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the absolute path of the bash command.
|
/// Gets the absolute path of the bash command.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn bash_path() -> Result<PathBuf> {
|
fn bash_path() -> Result<PathBuf> {
|
||||||
// Find `bash.exe` in `PATH`, but exclude the known bad paths
|
// 1. Try to find a good bash.exe in PATH
|
||||||
if let Some(bash_path) = find_in_path("bash.exe").context("bash.exe not found")? {
|
let bash_in_path = find_in_path("bash.exe").unwrap_or(None);
|
||||||
// Check if it's not MSYS bash https://stackoverflow.com/a/58418686/1529493
|
if let Some(pth) = &bash_in_path {
|
||||||
if !bash_path.ends_with(r"Git\usr\bin\bash.exe") {
|
// Check if it's not WSL bash
|
||||||
// Check if it's not WSL bash
|
// See https://github.com/hykilpikonna/hyfetch/issues/233
|
||||||
// See https://github.com/hykilpikonna/hyfetch/issues/233
|
let is_wsl = (|| {
|
||||||
let windir = env::var_os("windir").context("`windir` environ not found")?;
|
let windir = env::var_os("windir")?;
|
||||||
match is_same_file(&bash_path, Path::new(&windir).join(r"System32\bash.exe")) {
|
let wsl_bash = Path::new(&windir).join(r"System32\bash.exe");
|
||||||
Ok(false) => return Ok(bash_path),
|
Some(is_same_file(pth, &wsl_bash).unwrap_or(false))
|
||||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(bash_path),
|
})()
|
||||||
_ => {}
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_wsl {
|
||||||
|
// Check if it's not MSYS bash https://stackoverflow.com/a/58418686/1529493
|
||||||
|
// We prefer the Git wrapper bash if possible, but we'll accept this if it's all we have.
|
||||||
|
if !pth.ends_with(r"Git\usr\bin\bash.exe") {
|
||||||
|
return Ok(pth.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(bash_path) = find_in_path("git.exe").context("failed to find `git.exe` in `PATH`")? {
|
// 2. Try to find git.exe in PATH and look for bash.exe relative to it
|
||||||
if bash_path.ends_with(r"Git\cmd\git.exe") {
|
if let Ok(Some(git_path)) = find_in_path("git.exe") {
|
||||||
let pth = bash_path.parent().unwrap().parent().unwrap().join(r"bin\bash.exe");
|
let mut current = git_path.clone();
|
||||||
if pth.is_file() {
|
for _ in 0..3 {
|
||||||
return Ok(pth);
|
if let Some(parent) = current.parent() {
|
||||||
|
let bin_bash = parent.join(r"bin\bash.exe");
|
||||||
|
if bin_bash.is_file() {
|
||||||
|
return Ok(bin_bash);
|
||||||
|
}
|
||||||
|
let usr_bin_bash = parent.join(r"usr\bin\bash.exe");
|
||||||
|
if usr_bin_bash.is_file() {
|
||||||
|
return Ok(usr_bin_bash);
|
||||||
|
}
|
||||||
|
current = parent.to_path_buf();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(anyhow!("bash.exe not found"))
|
// 3. Fallback to whatever bash we found in PATH (even if it was the MSYS one)
|
||||||
|
if let Some(pth) = bash_in_path {
|
||||||
|
return Ok(pth);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow!("bash.exe not found. Please ensure Git for Windows is installed and in your PATH."))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs neofetch command, returning the piped stdout output.
|
/// Runs neofetch command, returning the piped stdout output.
|
||||||
@@ -399,8 +409,14 @@ where
|
|||||||
{
|
{
|
||||||
let bash_path = bash_path().context("failed to get bash path")?;
|
let bash_path = bash_path().context("failed to get bash path")?;
|
||||||
let mut command = Command::new(bash_path);
|
let mut command = Command::new(bash_path);
|
||||||
command.arg(neofetch_path);
|
|
||||||
command.args(args);
|
// Convert path to use forward slashes because bash will interpret backslashes as escapes
|
||||||
|
command.arg(neofetch_path.to_string_lossy().replace('\\', "/"));
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
// Also convert any backslashes in arguments to forward slashes for bash
|
||||||
|
command.arg(arg.as_ref().to_string_lossy().replace('\\', "/"));
|
||||||
|
}
|
||||||
Ok(command)
|
Ok(command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +535,7 @@ pub fn get_distro_name(backend: Backend) -> Result<String> {
|
|||||||
doc["spacing"] = value(0);
|
doc["spacing"] = value(0);
|
||||||
doc["padding"] = value(0);
|
doc["padding"] = value(0);
|
||||||
// See https://github.com/Macchina-CLI/macchina/issues/319
|
// See https://github.com/Macchina-CLI/macchina/issues/319
|
||||||
// doc["hide_ascii"] = value(true);
|
doc["hide_ascii"] = value(false);
|
||||||
doc["separator"] = value("");
|
doc["separator"] = value("");
|
||||||
doc["custom_ascii"] = Item::Table(Table::from_iter([(
|
doc["custom_ascii"] = Item::Table(Table::from_iter([(
|
||||||
"path",
|
"path",
|
||||||
@@ -550,8 +566,11 @@ pub fn get_distro_name(backend: Backend) -> Result<String> {
|
|||||||
];
|
];
|
||||||
run_macchina_command_piped(&args[..])
|
run_macchina_command_piped(&args[..])
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
anstream::adapter::strip_str(&s)
|
let s = anstream::adapter::strip_str(&s).to_string();
|
||||||
.to_string()
|
let s = s.trim();
|
||||||
|
s.splitn(2, '-')
|
||||||
|
.last()
|
||||||
|
.expect("splitn with 2 should always have at least 1 element")
|
||||||
.trim()
|
.trim()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
})
|
})
|
||||||
@@ -671,6 +690,7 @@ fn run_macchina(asc: String, args: Option<&Vec<String>>) -> Result<()> {
|
|||||||
.context("failed to create temp file for macchina theme")?;
|
.context("failed to create temp file for macchina theme")?;
|
||||||
let theme_doc = {
|
let theme_doc = {
|
||||||
let mut doc = DocumentMut::new();
|
let mut doc = DocumentMut::new();
|
||||||
|
doc["hide_ascii"] = value(false);
|
||||||
doc["custom_ascii"] = Item::Table(Table::from_iter([(
|
doc["custom_ascii"] = Item::Table(Table::from_iter([(
|
||||||
"path",
|
"path",
|
||||||
&*asc_file_path.to_string_lossy(),
|
&*asc_file_path.to_string_lossy(),
|
||||||
@@ -712,65 +732,8 @@ fn run_macchina(asc: String, args: Option<&Vec<String>>) -> Result<()> {
|
|||||||
/// Gets the color indices that should be considered as foreground, for a
|
/// Gets the color indices that should be considered as foreground, for a
|
||||||
/// particular distro's ascii art.
|
/// particular distro's ascii art.
|
||||||
fn ascii_foreground(distro: &Distro) -> Vec<NeofetchAsciiIndexedColor> {
|
fn ascii_foreground(distro: &Distro) -> Vec<NeofetchAsciiIndexedColor> {
|
||||||
let fg: Vec<u8> = match distro {
|
distro.foreground()
|
||||||
Distro::Anarchy => vec![2],
|
.iter()
|
||||||
Distro::Android => vec![2],
|
.map(|&f| f.try_into().expect("neofetch color index should be valid"))
|
||||||
Distro::Antergos => vec![1],
|
|
||||||
Distro::ArchStrike => vec![2],
|
|
||||||
Distro::Arkane => vec![1],
|
|
||||||
Distro::Asahi => vec![5],
|
|
||||||
Distro::Astra_Linux => vec![2],
|
|
||||||
Distro::BlackArch => vec![3],
|
|
||||||
Distro::CelOS => vec![3],
|
|
||||||
Distro::Chapeau => vec![2],
|
|
||||||
Distro::Chrom => vec![5],
|
|
||||||
Distro::Clear_Linux_OS => vec![2],
|
|
||||||
Distro::Container_Linux_by_CoreOS => vec![3],
|
|
||||||
Distro::CRUX => vec![3],
|
|
||||||
Distro::EuroLinux => vec![2],
|
|
||||||
Distro::eweOS => vec![3],
|
|
||||||
Distro::Fedora => vec![2],
|
|
||||||
Distro::Fedora_Sericea => vec![2],
|
|
||||||
Distro::Fedora_Silverblue => vec![2],
|
|
||||||
Distro::GalliumOS => vec![2],
|
|
||||||
Distro::Gentoo => vec![1],
|
|
||||||
Distro::HarDClanZ => vec![2],
|
|
||||||
Distro::Kibojoe => vec![3],
|
|
||||||
Distro::KrassOS => vec![2],
|
|
||||||
Distro::Kubuntu => vec![2],
|
|
||||||
Distro::Linux => vec![1],
|
|
||||||
Distro::LinuxFromScratch => vec![1, 3],
|
|
||||||
Distro::Lubuntu => vec![2],
|
|
||||||
Distro::openEuler => vec![2],
|
|
||||||
Distro::orchid => vec![1],
|
|
||||||
Distro::Panwah => vec![1],
|
|
||||||
Distro::Peppermint => vec![2],
|
|
||||||
Distro::PNM_Linux => vec![2],
|
|
||||||
Distro::Pop__OS => vec![2],
|
|
||||||
Distro::Reborn_OS => vec![1],
|
|
||||||
Distro::SalentOS => vec![4],
|
|
||||||
Distro::Septor => vec![2],
|
|
||||||
Distro::Ubuntu_Cinnamon => vec![2],
|
|
||||||
Distro::Ubuntu_Kylin => vec![2],
|
|
||||||
Distro::Ubuntu_MATE => vec![2],
|
|
||||||
Distro::Ubuntu_old => vec![2],
|
|
||||||
Distro::Ubuntu_Studio => vec![2],
|
|
||||||
Distro::Ubuntu_Sway => vec![2],
|
|
||||||
Distro::Ultramarine_Linux => vec![2],
|
|
||||||
Distro::Univention => vec![2],
|
|
||||||
Distro::uwuntu => vec![2],
|
|
||||||
Distro::Vanilla => vec![2],
|
|
||||||
Distro::VNux => vec![3, 5],
|
|
||||||
Distro::Void => vec![2],
|
|
||||||
Distro::Xray_OS => vec![2, 3],
|
|
||||||
Distro::Xubuntu => vec![2],
|
|
||||||
_ => Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
fg.into_iter()
|
|
||||||
.map(|fore| {
|
|
||||||
fore.try_into()
|
|
||||||
.expect("`fore` should be a valid neofetch color index")
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,901 +1,3 @@
|
|||||||
use std::iter;
|
#![allow(non_camel_case_types)]
|
||||||
use std::num::{NonZeroU8, NonZeroUsize};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
include!(concat!(env!("OUT_DIR"), "/presets.rs"));
|
||||||
use indexmap::IndexSet;
|
|
||||||
use palette::num::ClampAssign as _;
|
|
||||||
use palette::{IntoColorMut as _, LinSrgb, Okhsl, Srgb};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use strum::{AsRefStr, EnumCount, EnumString, VariantArray, VariantNames};
|
|
||||||
use tracing::debug;
|
|
||||||
use unicode_segmentation::UnicodeSegmentation as _;
|
|
||||||
|
|
||||||
use crate::color_util::{ForegroundBackground, Lightness, ToAnsiString as _};
|
|
||||||
use crate::types::{AnsiMode, TerminalTheme};
|
|
||||||
|
|
||||||
#[derive(
|
|
||||||
Copy,
|
|
||||||
Clone,
|
|
||||||
Hash,
|
|
||||||
Debug,
|
|
||||||
AsRefStr,
|
|
||||||
Deserialize,
|
|
||||||
EnumCount,
|
|
||||||
EnumString,
|
|
||||||
Serialize,
|
|
||||||
VariantArray,
|
|
||||||
VariantNames,
|
|
||||||
)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
#[strum(serialize_all = "kebab-case")]
|
|
||||||
pub enum Preset {
|
|
||||||
Rainbow,
|
|
||||||
|
|
||||||
Transgender,
|
|
||||||
|
|
||||||
Nonbinary,
|
|
||||||
|
|
||||||
Xenogender,
|
|
||||||
|
|
||||||
Agender,
|
|
||||||
|
|
||||||
Queer,
|
|
||||||
|
|
||||||
Genderfluid,
|
|
||||||
|
|
||||||
Bisexual,
|
|
||||||
|
|
||||||
Pansexual,
|
|
||||||
|
|
||||||
Polysexual,
|
|
||||||
|
|
||||||
Omnisexual,
|
|
||||||
|
|
||||||
Omniromantic,
|
|
||||||
|
|
||||||
GayMen,
|
|
||||||
|
|
||||||
Lesbian,
|
|
||||||
|
|
||||||
Abrosexual,
|
|
||||||
|
|
||||||
Asexual,
|
|
||||||
|
|
||||||
Aromantic,
|
|
||||||
|
|
||||||
Fictosexual,
|
|
||||||
|
|
||||||
Aroace1,
|
|
||||||
|
|
||||||
Aroace2,
|
|
||||||
|
|
||||||
Aroace3,
|
|
||||||
|
|
||||||
Greysexual,
|
|
||||||
|
|
||||||
Autosexual,
|
|
||||||
|
|
||||||
Intergender,
|
|
||||||
|
|
||||||
Greygender,
|
|
||||||
|
|
||||||
Akiosexual,
|
|
||||||
|
|
||||||
Bigender,
|
|
||||||
|
|
||||||
Demigender,
|
|
||||||
|
|
||||||
Demiboy,
|
|
||||||
|
|
||||||
Demigirl,
|
|
||||||
|
|
||||||
Transmasculine,
|
|
||||||
|
|
||||||
Transfeminine,
|
|
||||||
|
|
||||||
Genderfaun,
|
|
||||||
|
|
||||||
Demifaun,
|
|
||||||
|
|
||||||
Genderfae,
|
|
||||||
|
|
||||||
Demifae,
|
|
||||||
|
|
||||||
Neutrois,
|
|
||||||
|
|
||||||
Biromantic1,
|
|
||||||
|
|
||||||
Autoromantic,
|
|
||||||
|
|
||||||
Boyflux2,
|
|
||||||
|
|
||||||
Girlflux,
|
|
||||||
|
|
||||||
Genderflux,
|
|
||||||
|
|
||||||
Nullflux,
|
|
||||||
|
|
||||||
Hypergender, Hyperboy, Hypergirl, Hyperandrogyne, Hyperneutrois,
|
|
||||||
|
|
||||||
Finsexual,
|
|
||||||
|
|
||||||
Unlabeled1,
|
|
||||||
|
|
||||||
Unlabeled2,
|
|
||||||
|
|
||||||
Pangender,
|
|
||||||
|
|
||||||
/// High-contrast version of pangender flag
|
|
||||||
#[serde(rename = "pangender.contrast")]
|
|
||||||
#[strum(serialize = "pangender.contrast")]
|
|
||||||
PangenderContrast,
|
|
||||||
|
|
||||||
#[serde(rename = "gendernonconforming1")]
|
|
||||||
#[strum(serialize = "gendernonconforming1")]
|
|
||||||
GenderNonconforming1,
|
|
||||||
|
|
||||||
#[serde(rename = "gendernonconforming2")]
|
|
||||||
#[strum(serialize = "gendernonconforming2")]
|
|
||||||
GenderNonconforming2,
|
|
||||||
|
|
||||||
Femboy,
|
|
||||||
|
|
||||||
Tomboy,
|
|
||||||
|
|
||||||
Gynesexual,
|
|
||||||
|
|
||||||
Androsexual,
|
|
||||||
|
|
||||||
Gendervoid,
|
|
||||||
|
|
||||||
Voidgirl,
|
|
||||||
|
|
||||||
Voidboy,
|
|
||||||
|
|
||||||
NonhumanUnity,
|
|
||||||
|
|
||||||
/// For all the dogs
|
|
||||||
Caninekin,
|
|
||||||
|
|
||||||
Plural,
|
|
||||||
|
|
||||||
Fraysexual,
|
|
||||||
|
|
||||||
Bear,
|
|
||||||
|
|
||||||
Butch,
|
|
||||||
|
|
||||||
Leather,
|
|
||||||
|
|
||||||
Otter,
|
|
||||||
|
|
||||||
Twink,
|
|
||||||
|
|
||||||
Adipophilia,
|
|
||||||
|
|
||||||
Kenochoric,
|
|
||||||
|
|
||||||
Veldian,
|
|
||||||
|
|
||||||
Solian,
|
|
||||||
|
|
||||||
Lunian,
|
|
||||||
|
|
||||||
Polyam,
|
|
||||||
|
|
||||||
Sapphic,
|
|
||||||
|
|
||||||
Androgyne,
|
|
||||||
|
|
||||||
Interprogress,
|
|
||||||
|
|
||||||
Progress,
|
|
||||||
|
|
||||||
Intersex,
|
|
||||||
|
|
||||||
OldPolyam,
|
|
||||||
|
|
||||||
EqualRights,
|
|
||||||
|
|
||||||
Drag,
|
|
||||||
|
|
||||||
Pronounfluid,
|
|
||||||
|
|
||||||
Pronounflux,
|
|
||||||
|
|
||||||
Exipronoun,
|
|
||||||
|
|
||||||
Neopronoun,
|
|
||||||
|
|
||||||
Neofluid,
|
|
||||||
|
|
||||||
Genderqueer,
|
|
||||||
|
|
||||||
Cisgender,
|
|
||||||
|
|
||||||
/// Colors from Gilbert Baker's original 1978 flag design
|
|
||||||
Baker,
|
|
||||||
|
|
||||||
/// Meme flag
|
|
||||||
Beiyang,
|
|
||||||
|
|
||||||
/// Meme flag
|
|
||||||
Burger,
|
|
||||||
|
|
||||||
/// Meme flag
|
|
||||||
#[serde(rename = "throatlozenges")]
|
|
||||||
#[strum(serialize = "throatlozenges")]
|
|
||||||
ThroatLozenges,
|
|
||||||
|
|
||||||
/// Meme flag
|
|
||||||
Band,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
|
||||||
pub struct ColorProfile {
|
|
||||||
pub colors: Vec<Srgb<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
pub enum AssignLightness {
|
|
||||||
Replace(Lightness),
|
|
||||||
ClampMax(Lightness),
|
|
||||||
ClampMin(Lightness),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Preset {
|
|
||||||
pub fn color_profile(&self) -> ColorProfile {
|
|
||||||
(match self {
|
|
||||||
Self::Rainbow => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#E50000", "#FF8D00", "#FFEE00", "#028121", "#004CFF", "#770088",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Transgender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#55CDFD", "#F6AAB7", "#FFFFFF", "#F6AAB7", "#55CDFD",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Nonbinary => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#FCF431", "#FCFCFC", "#9D59D2", "#282828"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://commons.wikimedia.org/wiki/File:Xenogender_pride_flag.svg
|
|
||||||
Self::Xenogender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FF6692", "#FF9A98", "#FFB883", "#FBFFA8", "#85BCFF", "#9D85FF", "#A510FF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Agender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#000000", "#BABABA", "#FFFFFF", "#BAF484", "#FFFFFF", "#BABABA", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Queer => ColorProfile::from_hex_colors(vec!["#B57FDD", "#FFFFFF", "#49821E"]),
|
|
||||||
|
|
||||||
Self::Genderfluid => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FE76A2", "#FFFFFF", "#BF12D7", "#000000", "#303CBE",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Bisexual => ColorProfile::from_hex_colors(vec!["#D60270", "#9B4F96", "#0038A8"]),
|
|
||||||
|
|
||||||
Self::Pansexual => ColorProfile::from_hex_colors(vec!["#FF1C8D", "#FFD700", "#1AB3FF"]),
|
|
||||||
|
|
||||||
Self::Polysexual => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#F714BA", "#01D66A", "#1594F6"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/omnisexual
|
|
||||||
Self::Omnisexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FE9ACE", "#FF53BF", "#200044", "#6760FE", "#8EA6FF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Omniromantic => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FEC8E4", "#FDA1DB", "#89739A", "#ABA7FE", "#BFCEFF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/gay-men
|
|
||||||
Self::GayMen => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#078D70", "#98E8C1", "#FFFFFF", "#7BADE2", "#3D1A78",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Lesbian => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#D62800", "#FF9B56", "#FFFFFF", "#D462A6", "#A40062",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used colorpicker to source from https://fyeahaltpride.tumblr.com/post/151704251345/could-you-guys-possibly-make-an-abrosexual-pride
|
|
||||||
Self::Abrosexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#46D294", "#A3E9CA", "#FFFFFF", "#F78BB3", "#EE1766",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Asexual => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#000000", "#A4A4A4", "#FFFFFF", "#810081"])
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Aromantic => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#3BA740", "#A8D47A", "#FFFFFF", "#ABABAB", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// https://orientation.fandom.com/wiki/Fictosexual
|
|
||||||
Self::Fictosexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#000000", "#C4C4C4", "#A349A5", "#C4C4C4", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://flag.library.lgbt/flags/aroace/
|
|
||||||
Self::Aroace1 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#E28C00", "#ECCD00", "#FFFFFF", "#62AEDC", "#203856",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://flag.library.lgbt/flags/aroace/
|
|
||||||
Self::Aroace2 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#000000", "#810081", "#A4A4A4", "#FFFFFF", "#A8D47A", "#3BA740",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://flag.library.lgbt/flags/aroace/
|
|
||||||
Self::Aroace3 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#3BA740", "#A8D47A", "#FFFFFF", "#ABABAB", "#000000", "#A4A4A4", "#FFFFFF",
|
|
||||||
"#810081",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/greysexual
|
|
||||||
Self::Greysexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#740194", "#AEB1AA", "#FFFFFF", "#AEB1AA", "#740194",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/autosexual
|
|
||||||
Self::Autosexual => ColorProfile::from_hex_colors(vec!["#99D9EA", "#7F7F7F"]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/intergender
|
|
||||||
Self::Intergender => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#900DC2", "#FFE54F", "#900DC2"])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 1, 2]))
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/greygender
|
|
||||||
Self::Greygender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#B3B3B3", "#FFFFFF", "#062383", "#FFFFFF", "#535353",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 1, 2, 1, 2])),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/akiosexual
|
|
||||||
Self::Akiosexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#F9485E", "#FEA06A", "#FEF44C", "#FFFFFF", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/bigender
|
|
||||||
Self::Bigender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#C479A2", "#EDA5CD", "#D6C7E8", "#FFFFFF", "#D6C7E8", "#9AC7E8", "#6D82D1",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// yellow sourced from https://lgbtqia.fandom.com/f/p/4400000000000041031
|
|
||||||
// other colors sourced from demiboy and demigirl flags
|
|
||||||
Self::Demigender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#7F7F7F", "#C4C4C4", "#FBFF75", "#FFFFFF", "#FBFF75", "#C4C4C4", "#7F7F7F",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/demiboy
|
|
||||||
Self::Demiboy => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#7F7F7F", "#C4C4C4", "#9DD7EA", "#FFFFFF", "#9DD7EA", "#C4C4C4", "#7F7F7F",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/demigirl
|
|
||||||
Self::Demigirl => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#7F7F7F", "#C4C4C4", "#FDADC8", "#FFFFFF", "#FDADC8", "#C4C4C4", "#7F7F7F",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/transmasculine
|
|
||||||
Self::Transmasculine => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FF8ABD", "#CDF5FE", "#9AEBFF", "#74DFFF", "#9AEBFF", "#CDF5FE", "#FF8ABD",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used colorpicker to source from https://www.deviantart.com/pride-flags/art/Trans-Woman-Transfeminine-1-543925985
|
|
||||||
// linked from https://gender.fandom.com/wiki/Transfeminine
|
|
||||||
Self::Transfeminine => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#73DEFF", "#FFE2EE", "#FFB5D6", "#FF8DC0", "#FFB5D6", "#FFE2EE", "#73DEFF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/genderfaun
|
|
||||||
Self::Genderfaun => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FCD689", "#FFF09B", "#FAF9CD", "#FFFFFF", "#8EDED9", "#8CACDE", "#9782EC",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/demifaun
|
|
||||||
Self::Demifaun => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#7F7F7F", "#C6C6C6", "#FCC688", "#FFF19C", "#FFFFFF", "#8DE0D5", "#9682EC",
|
|
||||||
"#C6C6C6", "#7F7F7F",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 2, 1, 1, 1, 1, 1, 2, 2])),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/genderfae
|
|
||||||
Self::Genderfae => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#97C3A5", "#C3DEAE", "#F9FACD", "#FFFFFF", "#FCA2C4", "#DB8AE4", "#A97EDD",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used colorpicker to source form https://www.deviantart.com/pride-flags/art/Demifae-870194777
|
|
||||||
Self::Demifae => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#7F7F7F", "#C5C5C5", "#97C3A4", "#C4DEAE", "#FFFFFF", "#FCA2C5", "#AB7EDF",
|
|
||||||
"#C5C5C5", "#7F7F7F",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 2, 1, 1, 1, 1, 1, 2, 2])),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/neutrois
|
|
||||||
Self::Neutrois => ColorProfile::from_hex_colors(vec!["#FFFFFF", "#1F9F00", "#000000"]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/biromantic-alternate-2
|
|
||||||
Self::Biromantic1 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#8869A5", "#D8A7D8", "#FFFFFF", "#FDB18D", "#151638",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/autoromantic
|
|
||||||
Self::Autoromantic => ColorProfile::from_hex_colors(
|
|
||||||
// symbol interpreted
|
|
||||||
vec!["#99D9EA", "#3DA542", "#7F7F7F"],
|
|
||||||
)
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 1, 2])),
|
|
||||||
|
|
||||||
// sourced from https://www.flagcolorcodes.com/boyflux-alternate-2
|
|
||||||
Self::Boyflux2 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#E48AE4", "#9A81B4", "#55BFAB", "#FFFFFF", "#A8A8A8", "#81D5EF", "#69ABE5",
|
|
||||||
"#5276D4",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![1, 1, 1, 1, 1, 5, 5, 5])),
|
|
||||||
|
|
||||||
// sourced from https://commons.wikimedia.org/wiki/File:Girlflux_Pride_Flag.jpg
|
|
||||||
Self::Girlflux => ColorProfile::from_hex_colors(vec![
|
|
||||||
"f9e6d7", "f2526c", "bf0311", "e9c587", "bf0311", "f2526c", "f9e6d7",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://www.deviantart.com/pride-flags/art/Genderflux-1-543925589
|
|
||||||
Self::Genderflux => ColorProfile::from_hex_colors(vec![
|
|
||||||
"f47694", "f2a2b9", "cecece", "7ce0f7", "3ecdf9", "fff48d",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Nullflux => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#0B0C0E", "#A28DB9", "#E1D4EF", "#F0E6DD", "#665858",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Hypergender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#EFEFEF", "#FFFFFF", "#FBFF75", "#000000", "#FBFF75", "#FFFFFF", "#EFEFEF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Hyperboy => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#EFEFEF", "#FFFFFF", "#74D7FE", "#000000", "#74D7FE", "#FFFFFF", "#EFEFEF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Hypergirl => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#EFEFEF", "#FFFFFF", "#FC76D3", "#000000", "#FC76D3", "#FFFFFF", "#EFEFEF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Hyperandrogyne => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#EFEFEF", "#FFFFFF", "#BB83FF", "#000000", "#BB83FF", "#FFFFFF", "#EFEFEF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Hyperneutrois => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#EFEFEF", "#FFFFFF", "#BAFA74", "#000000", "#BAFA74", "#FFFFFF", "#EFEFEF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://lgbtqia.wiki/wiki/Finsexual
|
|
||||||
Self::Finsexual => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#B18EDF", "#D7B1E2", "#F7CDE9", "#F39FCE", "#EA7BB3",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://web.archive.org/web/20221002181913/https://unlabeledinfo.carrd.co/#flags
|
|
||||||
Self::Unlabeled1 => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#EAF8E4", "#FDFDFB", "#E1EFF7", "#F4E2C4"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://web.archive.org/web/20221002181913/https://unlabeledinfo.carrd.co/#flags
|
|
||||||
Self::Unlabeled2 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#250548", "#FFFFFF", "#F7DCDA", "#EC9BEE", "#9541FA", "#7D2557",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Pangender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFF798", "#FEDDCD", "#FFEBFB", "#FFFFFF", "#FFEBFB", "#FEDDCD", "#FFF798",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// high-contrast version of pangender flag
|
|
||||||
Self::PangenderContrast => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#ffe87f", "#fcbaa6", "#fbc9f3", "#FFFFFF", "#fbc9f3", "#fcbaa6", "#ffe87f",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::GenderNonconforming1 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#50284d", "#96467b", "#5c96f7", "#ffe6f7", "#5c96f7", "#96467b", "#50284d",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![4, 1, 1, 1, 1, 1, 4])),
|
|
||||||
|
|
||||||
Self::GenderNonconforming2 => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#50284d", "#96467b", "#5c96f7", "#ffe6f7", "#5c96f7", "#96467b", "#50284d",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Femboy => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#d260a5", "#e4afcd", "#fefefe", "#57cef8", "#fefefe", "#e4afcd", "#d260a5",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Tomboy => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2f3fb9", "#613a03", "#fefefe", "#f1a9b7", "#fefefe", "#613a03", "#2f3fb9",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from https://lgbtqia.fandom.com/wiki/Gynesexual
|
|
||||||
Self::Gynesexual => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#F4A9B7", "#903F2B", "#5B953B"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://lgbtqia.fandom.com/wiki/Androsexual
|
|
||||||
Self::Androsexual => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#01CCFF", "#603524", "#B799DE"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from: https://gender.fandom.com/wiki/Gendervoid
|
|
||||||
Self::Gendervoid => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#081149", "#4B484B", "#000000", "#4B484B", "#081149",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from: https://gender.fandom.com/wiki/Gendervoid
|
|
||||||
Self::Voidgirl => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#180827", "#7A5A8B", "#E09BED", "#7A5A8B", "#180827",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sourced from: https://gender.fandom.com/wiki/Gendervoid
|
|
||||||
Self::Voidboy => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#0B130C", "#547655", "#66B969", "#547655", "#0B130C",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used https://twitter.com/foxbrained/status/1667621855518236674/photo/1 as source and colorpicked
|
|
||||||
Self::NonhumanUnity => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#177B49", "#FFFFFF", "#593C90"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// used https://www.tumblr.com/zombpawcoins/745062851267493888/caninekin-canine-therian-flag
|
|
||||||
Self::Caninekin => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2d2822", "#543d25", "#9c754d", "#e8dac2", "#cfad8c", "#b77b55", "#954e31",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used https://pluralpedia.org/w/Plurality#/media/File:Plural-Flag-1.jpg as source and colorpicked
|
|
||||||
Self::Plural => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2D0625", "#543475", "#7675C3", "#89C7B0", "#F3EDBD",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// sampled from https://es.m.wikipedia.org/wiki/Archivo:Fraysexual_flag.jpg
|
|
||||||
Self::Fraysexual => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#226CB5", "#94E7DD", "#FFFFFF", "#636363"])
|
|
||||||
},
|
|
||||||
|
|
||||||
// sourced from https://commons.wikimedia.org/wiki/File:Bear_Brotherhood_flag.svg
|
|
||||||
Self::Bear => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#623804", "#D56300", "#FEDD63", "#FEE6B8", "#FFFFFF", "#555555",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// colorpicked from https://commons.wikimedia.org/wiki/File:Butch_Flag.png
|
|
||||||
Self::Butch => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#D72800", "#F17623", "#FF9C56", "#FFFDF6", "#FFCE89", "#FEAF02", "#A37000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// colorpicked from https://commons.wikimedia.org/wiki/File:Leather,_Latex,_and_BDSM_pride_-_Light.svg
|
|
||||||
Self::Leather => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#000000", "#252580", "#000000", "#252580", "#FFFFFF", "#252580", "#000000",
|
|
||||||
"#252580", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// colorpicked from https://commons.wikimedia.org/wiki/File:Official_Otter_Pride_Flag_by_Bearbackgear.jpg
|
|
||||||
Self::Otter => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#263881", "#5C9DC9", "#FFFFFF", "#3A291D", "#5C9DC9", "#263881",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// colorpicked from https://commons.wikimedia.org/wiki/File:Twink_Pride_Flag_(proposed).svg
|
|
||||||
Self::Twink => ColorProfile::from_hex_colors(vec!["#FFB2FF", "#FFFFFF", "#FFFF81"]),
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/File:FatFetishFlag.png
|
|
||||||
Self::Adipophilia => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#000000", "#E16180", "#FFF9BE", "#603E41", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Kenochoric => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#000000", "#2E1569", "#824DB7", "#C7A1D6"])
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Veldian => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#D182A8", "#FAF6E0", "#69ACBE", "#5D448F", "#3A113E",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Solian => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFF8ED", "#FFE7A8", "#F1B870", "#A56058", "#46281E",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Lunian => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2F0E62", "#6F41B1", "#889FDF", "#7DDFD5", "#D2F2E2",
|
|
||||||
]),
|
|
||||||
|
|
||||||
// pulled from https://polyamproud.com/flag
|
|
||||||
Self::Polyam => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFFFFF", "#FCBF00", "#009FE3", "#E50051", "#340C46",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Sapphic => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FD8BA8", "#FBF2FF", "#C76BC5", "#FDD768", "#C76BC5", "#FBF2FF", "#FD8BA8",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Androgyne => ColorProfile::from_hex_colors(vec!["#FE007F", "#9832FF", "#00B8E7"]),
|
|
||||||
|
|
||||||
Self::Interprogress => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFD800", "#7902AA", "#FFFFFF", "#FFAFC8", "#74D7EE", "#613915", "#000000",
|
|
||||||
"#E50000", "#FF8D00", "#FFEE00", "#028121", "#004CFF", "#770088",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Progress => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFFFFF", "#FFAFC8", "#74D7EE", "#613915", "#000000", "#E50000", "#FF8D00",
|
|
||||||
"#FFEE00", "#028121", "#004CFF", "#770088",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Intersex => ColorProfile::from_hex_colors(vec!["#FFD800", "#7902AA", "#FFD800"])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 1, 2])),
|
|
||||||
|
|
||||||
Self::OldPolyam => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#0000FF", "#FF0000", "#FFFF00", "#FF0000", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::EqualRights => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#0000FF", "#FFFF00", "#0000FF", "#FFFF00", "#0000FF",
|
|
||||||
])
|
|
||||||
.and_then(|c| c.with_weights(vec![2, 1, 2, 1, 2])),
|
|
||||||
|
|
||||||
Self::Drag => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#CC67FF", "#FFFFFF", "#FFA3E3", "#FFFFFF", "#3366FF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Pronounfluid => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFB3F9", "#FFFFFF", "#D1FDCB", "#C7B0FF", "#000000", "#B8CCFF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Pronounflux => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FDB3F8", "#B6CCFA", "#18DDD3", "#64FF89", "#FF7690", "#FFFFFF",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Exipronoun => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#1C3D34", "#FFFFFF", "#321848", "#000000"])
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Neopronoun => {
|
|
||||||
ColorProfile::from_hex_colors(vec!["#BCEC64", "#FFFFFF", "#38077A"])
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Neofluid => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#FFECA0", "#FFFFFF", "#FFECA0", "#38087A", "#BCEC64",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Genderqueer => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#B57EDC", "#FFFFFF", "#4A8123"
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Cisgender => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#D70270", "#0038A7"
|
|
||||||
]),
|
|
||||||
|
|
||||||
// used https://gilbertbaker.com/rainbow-flag-color-meanings/ as source and colorpicked
|
|
||||||
Self::Baker => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#F23D9E", "#F80A24", "#F78022", "#F9E81F", "#1E972E", "#1B86BC", "#243897", "#6F0A82",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Beiyang => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#DF1B12", "#FFC600", "#01639D", "#FFFFFF", "#000000",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Burger => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#F3A26A", "#498701", "#FD1C13", "#7D3829", "#F3A26A",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::ThroatLozenges => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2759DA", "#03940D", "#F5F100", "#F59B00", "#B71212",
|
|
||||||
]),
|
|
||||||
|
|
||||||
Self::Band => ColorProfile::from_hex_colors(vec![
|
|
||||||
"#2670C0", "#F5BD00", "#DC0045", "#E0608E"
|
|
||||||
]),
|
|
||||||
|
|
||||||
})
|
|
||||||
.expect("preset color profiles should be valid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColorProfile {
|
|
||||||
pub fn new(colors: Vec<Srgb<u8>>) -> Self {
|
|
||||||
Self { colors }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_hex_colors<S>(hex_colors: Vec<S>) -> Result<Self>
|
|
||||||
where
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
let colors = hex_colors
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.as_ref().parse())
|
|
||||||
.collect::<Result<_, _>>()
|
|
||||||
.context("failed to parse hex colors")?;
|
|
||||||
Ok(Self::new(colors))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps colors based on weights.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `weights` - Weights of each color (`weights[i]` = how many times
|
|
||||||
/// `colors[i]` appears)
|
|
||||||
pub fn with_weights(&self, weights: Vec<u8>) -> Result<Self> {
|
|
||||||
if weights.len() != self.colors.len() {
|
|
||||||
debug!(?weights, ?self.colors, "length mismatch between `weights` and `colors`");
|
|
||||||
return Err(anyhow!(
|
|
||||||
"`weights` should have the same number of elements as `colors`"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut weighted_colors = Vec::new();
|
|
||||||
|
|
||||||
for (i, w) in weights.into_iter().enumerate() {
|
|
||||||
weighted_colors.extend(iter::repeat(self.colors[i]).take(usize::from(w)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self::new(weighted_colors))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new color profile, with the colors spread to the specified
|
|
||||||
/// length.
|
|
||||||
pub fn with_length(&self, length: NonZeroU8) -> Result<Self> {
|
|
||||||
let orig_len = self.colors.len();
|
|
||||||
let orig_len: NonZeroUsize = orig_len.try_into().expect("`colors` should not be empty");
|
|
||||||
let orig_len: NonZeroU8 = orig_len
|
|
||||||
.try_into()
|
|
||||||
.expect("`colors` should not have more than 255 elements");
|
|
||||||
// TODO: I believe weird things can happen because of this...
|
|
||||||
// if length < orig_len {
|
|
||||||
// unimplemented!("compressing length of color profile not implemented");
|
|
||||||
// }
|
|
||||||
let center_i = usize::from(orig_len.get() / 2);
|
|
||||||
|
|
||||||
// How many copies of each color should be displayed at least?
|
|
||||||
let repeats = length.get().div_euclid(orig_len.get());
|
|
||||||
let mut weights = vec![repeats; NonZeroUsize::from(orig_len).get()];
|
|
||||||
|
|
||||||
// How many extra spaces left?
|
|
||||||
let mut extras = length.get().rem_euclid(orig_len.get());
|
|
||||||
|
|
||||||
// If there is an odd space left, extend the center by one space
|
|
||||||
if extras % 2 == 1 {
|
|
||||||
weights[center_i] = weights[center_i].checked_add(1).unwrap();
|
|
||||||
extras = extras.checked_sub(1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add weight to border until there's no space left (extras must be even at this
|
|
||||||
// point)
|
|
||||||
let weights_len = weights.len();
|
|
||||||
for border_i in 0..usize::from(extras / 2) {
|
|
||||||
weights[border_i] = weights[border_i].checked_add(1).unwrap();
|
|
||||||
let border_opp = weights_len
|
|
||||||
.checked_sub(border_i)
|
|
||||||
.unwrap()
|
|
||||||
.checked_sub(1)
|
|
||||||
.unwrap();
|
|
||||||
weights[border_opp] = weights[border_opp].checked_add(1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.with_weights(weights)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Colors a text.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `foreground_background` - Whether the color is shown on the foreground
|
|
||||||
/// text or the background block
|
|
||||||
/// * `space_only` - Whether to only color spaces
|
|
||||||
pub fn color_text<S>(
|
|
||||||
&self,
|
|
||||||
txt: S,
|
|
||||||
color_mode: AnsiMode,
|
|
||||||
foreground_background: ForegroundBackground,
|
|
||||||
space_only: bool,
|
|
||||||
) -> Result<String>
|
|
||||||
where
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
let txt = txt.as_ref();
|
|
||||||
|
|
||||||
let txt: Vec<&str> = txt.graphemes(true).collect();
|
|
||||||
|
|
||||||
let ColorProfile { colors } = {
|
|
||||||
let length = txt.len();
|
|
||||||
let length: NonZeroUsize = length.try_into().context("`txt` should not be empty")?;
|
|
||||||
let length: NonZeroU8 = length.try_into().with_context(|| {
|
|
||||||
format!(
|
|
||||||
"`txt` should not have more than {limit} characters",
|
|
||||||
limit = u8::MAX
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
self.with_length(length)
|
|
||||||
.with_context(|| format!("failed to spread color profile to length {length}"))?
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut buf = String::new();
|
|
||||||
for (i, &gr) in txt.iter().enumerate() {
|
|
||||||
if space_only && gr != " " {
|
|
||||||
if i > 0 && txt[i.checked_sub(1).unwrap()] == " " {
|
|
||||||
buf.push_str("\x1b[39;49m");
|
|
||||||
}
|
|
||||||
buf.push_str(gr);
|
|
||||||
} else {
|
|
||||||
buf.push_str(&colors[i].to_ansi_string(color_mode, foreground_background));
|
|
||||||
buf.push_str(gr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.push_str("\x1b[39;49m");
|
|
||||||
Ok(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new color profile, with the colors lightened by a multiplier.
|
|
||||||
pub fn lighten(&self, multiplier: f32) -> Self {
|
|
||||||
let mut rgb_f32_colors: Vec<LinSrgb> =
|
|
||||||
self.colors.iter().map(|c| c.into_linear()).collect();
|
|
||||||
|
|
||||||
{
|
|
||||||
let okhsl_f32_colors: &mut [Okhsl] = &mut rgb_f32_colors.into_color_mut();
|
|
||||||
|
|
||||||
for okhsl_f32_color in okhsl_f32_colors {
|
|
||||||
okhsl_f32_color.lightness *= multiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rgb_u8_colors: Vec<_> = rgb_f32_colors
|
|
||||||
.into_iter()
|
|
||||||
.map(Srgb::<u8>::from_linear)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
colors: rgb_u8_colors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new color profile, with the colors set to the specified
|
|
||||||
/// [`Okhsl`] lightness value.
|
|
||||||
pub fn with_lightness(&self, assign_lightness: AssignLightness) -> Self {
|
|
||||||
let mut rgb_f32_colors: Vec<LinSrgb> =
|
|
||||||
self.colors.iter().map(|c| c.into_linear()).collect();
|
|
||||||
|
|
||||||
{
|
|
||||||
let okhsl_f32_colors: &mut [Okhsl] = &mut rgb_f32_colors.into_color_mut();
|
|
||||||
|
|
||||||
for okhsl_f32_color in okhsl_f32_colors {
|
|
||||||
match assign_lightness {
|
|
||||||
AssignLightness::Replace(lightness) => {
|
|
||||||
okhsl_f32_color.lightness = lightness.into();
|
|
||||||
},
|
|
||||||
AssignLightness::ClampMax(lightness) => {
|
|
||||||
okhsl_f32_color.lightness.clamp_max_assign(lightness.into());
|
|
||||||
},
|
|
||||||
AssignLightness::ClampMin(lightness) => {
|
|
||||||
okhsl_f32_color.lightness.clamp_min_assign(lightness.into());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rgb_u8_colors: Vec<Srgb<u8>> = rgb_f32_colors
|
|
||||||
.into_iter()
|
|
||||||
.map(Srgb::<u8>::from_linear)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
colors: rgb_u8_colors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new color profile, with the colors set to the specified
|
|
||||||
/// [`Okhsl`] lightness value, adapted to the terminal theme.
|
|
||||||
pub fn with_lightness_adaptive(&self, lightness: Lightness, theme: TerminalTheme) -> Self {
|
|
||||||
match theme {
|
|
||||||
TerminalTheme::Dark => self.with_lightness(AssignLightness::ClampMin(lightness)),
|
|
||||||
TerminalTheme::Light => self.with_lightness(AssignLightness::ClampMax(lightness)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates another color profile with only the unique colors.
|
|
||||||
pub fn unique_colors(&self) -> Self {
|
|
||||||
let unique_colors: IndexSet<[u8; 3]> = self.colors.iter().map(|&c| c.into()).collect();
|
|
||||||
let unique_colors: Vec<Srgb<u8>> = unique_colors.into_iter().map(|c| c.into()).collect();
|
|
||||||
Self::new(unique_colors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -47,58 +47,32 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let text = &TEXT_ASCII[1..TEXT_ASCII.len().checked_sub(1).unwrap()];
|
let text = &TEXT_ASCII[1..TEXT_ASCII.len().checked_sub(1).unwrap()];
|
||||||
let (text_width, text_height) =
|
let (text_w, text_h) = ascii_size(text)?;
|
||||||
ascii_size(text).expect("text ascii should have valid width and height");
|
|
||||||
let (text, text_width, text_height) = {
|
let (text, text_width, text_height) = {
|
||||||
const TEXT_BORDER_WIDTH: u16 = 2;
|
const TEXT_BORDER_WIDTH: u16 = 2;
|
||||||
const NOTICE_BORDER_WIDTH: u16 = 1;
|
const NOTICE_BORDER_WIDTH: u16 = 1;
|
||||||
const VERTICAL_MARGIN: u16 = 1;
|
const VERTICAL_MARGIN: u16 = 1;
|
||||||
let notice_w = NOTICE.len();
|
let notice_w: u16 = NOTICE.len().try_into()?;
|
||||||
let notice_w: u8 = notice_w
|
let notice_h: u16 = NOTICE.lines().count().try_into()?;
|
||||||
.try_into()
|
|
||||||
.expect("`NOTICE` width should fit in `u8`");
|
|
||||||
let notice_h = NOTICE.lines().count();
|
|
||||||
let notice_h: u8 = notice_h
|
|
||||||
.try_into()
|
|
||||||
.expect("`NOTICE` height should fit in `u8`");
|
|
||||||
let term_w_min = cmp::max(
|
let term_w_min = cmp::max(
|
||||||
u16::from(text_width)
|
text_w + TEXT_BORDER_WIDTH * 2,
|
||||||
.checked_add(TEXT_BORDER_WIDTH.checked_mul(2).unwrap())
|
notice_w + NOTICE_BORDER_WIDTH * 2,
|
||||||
.unwrap(),
|
|
||||||
u16::from(notice_w)
|
|
||||||
.checked_add(NOTICE_BORDER_WIDTH.checked_mul(2).unwrap())
|
|
||||||
.unwrap(),
|
|
||||||
);
|
);
|
||||||
let term_h_min = u16::from(text_height)
|
let term_h_min = u16::from(text_h) + notice_h + VERTICAL_MARGIN * 2;
|
||||||
.checked_add(notice_h.into())
|
|
||||||
.unwrap()
|
|
||||||
.checked_add(VERTICAL_MARGIN.checked_mul(2).unwrap())
|
|
||||||
.unwrap();
|
|
||||||
if w.get() >= term_w_min && h.get() >= term_h_min {
|
if w.get() >= term_w_min && h.get() >= term_h_min {
|
||||||
(text, text_width, text_height)
|
(text, text_w, text_h)
|
||||||
} else {
|
} else {
|
||||||
let text = &TEXT_ASCII_SMALL[1..TEXT_ASCII_SMALL.len().checked_sub(1).unwrap()];
|
let text = &TEXT_ASCII_SMALL[1..TEXT_ASCII_SMALL.len().checked_sub(1).unwrap()];
|
||||||
let (text_width, text_height) =
|
let (text_w, text_h) = ascii_size(text)?;
|
||||||
ascii_size(text).expect("text ascii should have valid width and height");
|
|
||||||
let term_w_min = cmp::max(
|
let term_w_min = cmp::max(
|
||||||
u16::from(text_width)
|
text_w + TEXT_BORDER_WIDTH * 2,
|
||||||
.checked_add(TEXT_BORDER_WIDTH.checked_mul(2).unwrap())
|
notice_w + NOTICE_BORDER_WIDTH * 2,
|
||||||
.unwrap(),
|
|
||||||
u16::from(notice_w)
|
|
||||||
.checked_add(NOTICE_BORDER_WIDTH.checked_mul(2).unwrap())
|
|
||||||
.unwrap(),
|
|
||||||
);
|
);
|
||||||
let term_h_min = u16::from(text_height)
|
let term_h_min = text_h + notice_h + VERTICAL_MARGIN * 2;
|
||||||
.checked_add(notice_h.into())
|
|
||||||
.unwrap()
|
|
||||||
.checked_add(VERTICAL_MARGIN.checked_mul(2).unwrap())
|
|
||||||
.unwrap();
|
|
||||||
if w.get() < term_w_min || h.get() < term_h_min {
|
if w.get() < term_w_min || h.get() < term_h_min {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!("terminal size should be at least ({term_w_min} * {term_h_min})"));
|
||||||
"terminal size should be at least ({term_w_min} * {term_h_min})"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
(text, text_width, text_height)
|
(text, text_w, text_h)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let text_lines: Vec<&str> = text.lines().collect();
|
let text_lines: Vec<&str> = text.lines().collect();
|
||||||
@@ -165,8 +139,7 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
.rem_euclid(colors.len())]
|
.rem_euclid(colors.len())]
|
||||||
.to_ansi_string(color_mode, ForegroundBackground::Background),
|
.to_ansi_string(color_mode, ForegroundBackground::Background),
|
||||||
fg = fg.to_ansi_string(color_mode, ForegroundBackground::Foreground)
|
fg = fg.to_ansi_string(color_mode, ForegroundBackground::Foreground)
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Loop over the width
|
// Loop over the width
|
||||||
for x in 0..w.get() {
|
for x in 0..w.get() {
|
||||||
@@ -176,27 +149,11 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
.wrapping_add_signed((2.0 * (y as f64 + 0.5 * frame as f64).sin()) as isize);
|
.wrapping_add_signed((2.0 * (y as f64 + 0.5 * frame as f64).sin()) as isize);
|
||||||
let y_text = text_start_y <= y && y < text_end_y;
|
let y_text = text_start_y <= y && y < text_end_y;
|
||||||
|
|
||||||
let border = 1u16
|
let border = 1u16 + if y == text_start_y || y == (text_end_y - 1) { 0 } else { 1 };
|
||||||
.checked_add(
|
let text_bounds_x1 = text_start_x - border;
|
||||||
if y == text_start_y || y == text_end_y.checked_sub(1).unwrap() {
|
let text_bounds_x2 = text_end_x - border;
|
||||||
0
|
let notice_bounds_x1 = notice_start_x - 1;
|
||||||
} else {
|
let notice_bounds_x2 = notice_end_x - 1;
|
||||||
1
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let text_bounds_x1 = text_start_x
|
|
||||||
.checked_sub(border)
|
|
||||||
.expect("`text_start_x - border` should not underflow `u16`");
|
|
||||||
let text_bounds_x2 = text_end_x
|
|
||||||
.checked_add(border)
|
|
||||||
.expect("`text_end_x + border` should not overflow `u16`");
|
|
||||||
let notice_bounds_x1 = notice_start_x
|
|
||||||
.checked_sub(1)
|
|
||||||
.expect("`notice_start_x - 1` should not underflow `u16`");
|
|
||||||
let notice_bounds_x2 = notice_end_x
|
|
||||||
.checked_add(1)
|
|
||||||
.expect("`notice_end_x + 1` should not overflow `u16`");
|
|
||||||
|
|
||||||
// If it's a switching point
|
// If it's a switching point
|
||||||
if idx.rem_euclid(NonZeroUsize::from(block_width).get()) == 0
|
if idx.rem_euclid(NonZeroUsize::from(block_width).get()) == 0
|
||||||
@@ -215,19 +172,9 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
{
|
{
|
||||||
let c: LinSrgba = c.with_alpha(1.0).into_linear();
|
let c: LinSrgba = c.with_alpha(1.0).into_linear();
|
||||||
let c = Srgb::<u8>::from_linear(c.overlay(black).without_alpha());
|
let c = Srgb::<u8>::from_linear(c.overlay(black).without_alpha());
|
||||||
write!(
|
write!(buf, "{bg}", bg = c.to_ansi_string(color_mode, ForegroundBackground::Background))?;
|
||||||
buf,
|
|
||||||
"{bg}",
|
|
||||||
bg = c.to_ansi_string(color_mode, ForegroundBackground::Background),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(buf, "{bg}", bg = c.to_ansi_string(color_mode, ForegroundBackground::Background))?;
|
||||||
buf,
|
|
||||||
"{bg}",
|
|
||||||
bg = c.to_ansi_string(color_mode, ForegroundBackground::Background),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +187,7 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
.chars()
|
.chars()
|
||||||
.nth(usize::from(x.checked_sub(text_start_x).unwrap()))
|
.nth(usize::from(x.checked_sub(text_start_x).unwrap()))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
} else if y == notice_y && notice_start_x <= x && x < notice_end_x {
|
} else if y == notice_y && notice_start_x <= x && x < notice_end_x {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
@@ -250,21 +196,15 @@ pub fn start_animation(color_mode: AnsiMode) -> Result<()> {
|
|||||||
.chars()
|
.chars()
|
||||||
.nth(usize::from(x.checked_sub(notice_start_x).unwrap()))
|
.nth(usize::from(x.checked_sub(notice_start_x).unwrap()))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
write!(buf, " ").unwrap();
|
write!(buf, " ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New line if it isn't the last line
|
// New line if it isn't the last line
|
||||||
if y != h.get().checked_sub(1).unwrap() {
|
if y != h.get().checked_sub(1).unwrap() {
|
||||||
writeln!(
|
writeln!(buf, "{reset}", reset = color("&r", color_mode)?)?;
|
||||||
buf,
|
|
||||||
"{reset}",
|
|
||||||
reset = color("&r", color_mode).expect("reset should be valid"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,12 +85,7 @@ where
|
|||||||
|
|
||||||
let metadata = match fs::metadata(path) {
|
let metadata = match fs::metadata(path) {
|
||||||
Ok(metadata) => metadata,
|
Ok(metadata) => metadata,
|
||||||
Err(err) if err.kind() == io::ErrorKind::NotFound => {
|
Err(_) => return Ok(None)
|
||||||
return Ok(None);
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
return Err(err).with_context(|| format!("failed to get metadata for {path:?}"));
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !metadata.is_file() {
|
if !metadata.is_file() {
|
||||||
|
|||||||
+6
-4
@@ -1,7 +1,7 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
||||||
.TH VERSION: "1" "September 2025" "Version: 2.0.2" "User Commands"
|
.TH VERSION: "1" "April 2026" "Version: 2.1.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
Version: \- manual page for Version: 2.0.2
|
Version: \- manual page for Version: 2.1.0
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B hyfetch
|
.B hyfetch
|
||||||
[\fI\,-c\/\fR] [\fI\,-C=CONFIG_FILE\/\fR] [\fI\,-p=PRESET\/\fR] [\fI\,-m=MODE\/\fR] [\fI\,-b=BACKEND\/\fR] [\fI\,--args=ARGS\/\fR] [\fI\,--c-scale=\/\fR
|
[\fI\,-c\/\fR] [\fI\,-C=CONFIG_FILE\/\fR] [\fI\,-p=PRESET\/\fR] [\fI\,-m=MODE\/\fR] [\fI\,-b=BACKEND\/\fR] [\fI\,--args=ARGS\/\fR] [\fI\,--c-scale=\/\fR
|
||||||
@@ -20,8 +20,10 @@ Use another config file
|
|||||||
[default: "/home/azalea/.config/hyfetch.json"]
|
[default: "/home/azalea/.config/hyfetch.json"]
|
||||||
.TP
|
.TP
|
||||||
\fB\-p\fR, \fB\-\-preset\fR=\fI\,PRESET\/\fR
|
\fB\-p\fR, \fB\-\-preset\fR=\fI\,PRESET\/\fR
|
||||||
Use preset
|
Use preset or comma\-separated color list or comma\-separated hex colors
|
||||||
PRESET={rainbow,transgender,nonbinary,xenogender,agender,queer,genderfluid,bisexual,pansexual,polysexual,omnisexual,omniromantic,gay\-men,lesbian,abrosexual,asexual,aromantic,fictosexual,aroace1,aroace2,aroace3,greysexual,autosexual,intergender,greygender,akiosexual,bigender,demigender,demiboy,demigirl,transmasculine,transfeminine,genderfaun,demifaun,genderfae,demifae,neutrois,biromantic1,autoromantic,boyflux2,girlflux,genderflux,nullflux,hypergender,hyperboy,hypergirl,hyperandrogyne,hyperneutrois,finsexual,unlabeled1,unlabeled2,pangender,pangender.contrast,gendernonconforming1,gendernonconforming2,femboy,tomboy,gynesexual,androsexual,gendervoid,voidgirl,voidboy,nonhuman\-unity,caninekin,plural,fraysexual,bear,butch,leather,otter,twink,adipophilia,kenochoric,veldian,solian,lunian,polyam,sapphic,androgyne,interprogress,progress,intersex,old\-polyam,equal\-rights,drag,pronounfluid,pronounflux,exipronoun,neopronoun,neofluid,genderqueer,cisgender,baker,beiyang,burger,throatlozenges,band,random}
|
(e.g., "#ff0000,#00ff00,#0000ff"). Comma\-separated preset names will
|
||||||
|
pick one randomly.
|
||||||
|
PRESET={rainbow,transgender,nonbinary,xenogender,agender,queer,genderfluid,bisexual,pansexual,polysexual,omnisexual,omniromantic,gay\-men,lesbian,abrosexual,asexual,aromantic,fictosexual,aroace1,aroace2,aroace3,autosexual,intergender,greygender,akiosexual,bigender,demigender,demiboy,demigirl,transmasculine,transfeminine,genderfaun,demifaun,genderfae,demifae,neutrois,biromantic1,biromantic2,autoromantic,boyflux2,girlflux,genderflux,nullflux,hypergender,hyperboy,hypergirl,hyperandrogyne,hyperneutrois,finsexual,unlabeled1,unlabeled2,pangender,pangender.contrast,gendernonconforming1,gendernonconforming2,femboy,tomboy,gynesexual,androsexual,gendervoid,voidgirl,voidboy,nonhuman\-unity,plural,fraysexual,bear,butch,femme,leather,otter,twink,adipophilia,kenochoric,veldian,solian,lunian,polyam,sapphic,androgyne,interprogress,progress,intersex,old\-polyam,equal\-rights,drag,pronounfluid,pronounflux,exipronoun,neopronoun,neofluid,genderqueer,cisgender,baker,caninekin,libragender,librafeminine,libramasculine,libraandrogyne,libranonbinary,fluidflux1,fluidflux2,transbian,autism,cenelian,transneutral,beiyang,burger,throatlozenges,band,petergriffin,rubber,haruhi,random}
|
||||||
.TP
|
.TP
|
||||||
\fB\-m\fR, \fB\-\-mode\fR=\fI\,MODE\/\fR
|
\fB\-m\fR, \fB\-\-mode\fR=\fI\,MODE\/\fR
|
||||||
Color mode MODE={8bit,rgb}
|
Color mode MODE={8bit,rgb}
|
||||||
|
|||||||
+23
-21
@@ -1,7 +1,7 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
||||||
.TH NEOFETCH "1" "September 2025" "Neofetch 8.0.2" "User Commands"
|
.TH NEOFETCH "1" "April 2026" "Neofetch 8.1.0" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
Neofetch \- manual page for Neofetch 8.0.2
|
Neofetch \- manual page for Neofetch 8.1.0
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B neofetch
|
.B neofetch
|
||||||
\fI\,func_name --option "value" --option "value"\/\fR
|
\fI\,func_name --option "value" --option "value"\/\fR
|
||||||
@@ -326,13 +326,13 @@ BigLinux_large, Bitrig, BlackArch, BlackMesa, blackPanther, BLAG,
|
|||||||
BlankOn, BlueLight, Bodhi, bonsai, BSD, BunsenLabs, CachyOS,
|
BlankOn, BlueLight, Bodhi, bonsai, BSD, BunsenLabs, CachyOS,
|
||||||
Calculate, CalinixOS, Carbs, CBL\-Mariner, CelOS, Center, CentOS,
|
Calculate, CalinixOS, Carbs, CBL\-Mariner, CelOS, Center, CentOS,
|
||||||
Chakra, ChaletOS, Chapeau, Chimera, ChonkySealOS, Chrom, Cleanjaro,
|
Chakra, ChaletOS, Chapeau, Chimera, ChonkySealOS, Chrom, Cleanjaro,
|
||||||
Clear Linux OS, ClearOS, Clover, Cobalt, Condres, Container Linux by
|
Clear Linux OS, ClearOS, Clover, Cobalt, Codex Linux, Condres,
|
||||||
CoreOS, CRUX, Crystal Linux, Cucumber, CutefishOS, CuteOS, CyberOS,
|
Container Linux by CoreOS, CRUX, Crystal Linux, Cucumber,
|
||||||
dahlia, DarkOs, Darwin, Debian, Deepin, DesaOS, Devuan, DietPi,
|
CutefishOS, CuteOS, CyberOS, dahlia, DarkOs, Darwin, Debian, Deepin,
|
||||||
digital UNIX, DracOS, DragonFly, Drauger, Droidian, Elementary,
|
DesaOS, Devuan, DietPi, digital UNIX, DracOS, DragonFly, Drauger,
|
||||||
Elive, EncryptOS, EndeavourOS, Endless, Enso, EuroLinux,
|
Droidian, Elementary, Elive, EncryptOS, EndeavourOS, Endless, Enso,
|
||||||
EvolutionOS, eweOS, Exherbo, Exodia Predator OS, Fedora, Fedora
|
EuroLinux, EvolutionOS, eweOS, Exherbo, Exodia Predator OS, Fedora,
|
||||||
Kinoite, Fedora Sericea, Fedora Silverblue, Fedora_unicode,
|
Fedora Kinoite, Fedora Sericea, Fedora Silverblue, Fedora_unicode,
|
||||||
FemboyOS, Feren, Finnix, Floflis, FreeBSD, FreeMiNT, Frugalware,
|
FemboyOS, Feren, Finnix, Floflis, FreeBSD, FreeMiNT, Frugalware,
|
||||||
Funtoo, Furreto, GalliumOS, Garuda, Gentoo, GhostBSD, glaucus,
|
Funtoo, Furreto, GalliumOS, Garuda, Gentoo, GhostBSD, glaucus,
|
||||||
Gloire, gNewSense, GNOME, GNU, GoboLinux, GrapheneOS, Grombyang,
|
Gloire, gNewSense, GNOME, GNU, GoboLinux, GrapheneOS, Grombyang,
|
||||||
@@ -352,22 +352,24 @@ Tumbleweed, openSUSE Tumbleweed\-Slowroll, OPNsense, Oracle, orchid,
|
|||||||
OS Elbrus, PacBSD, Panwah, Parabola, parch, Pardus, Parrot, Parsix,
|
OS Elbrus, PacBSD, Panwah, Parabola, parch, Pardus, Parrot, Parsix,
|
||||||
PCBSD, PCLinuxOS, pearOS, Pengwin, Pentoo, Peppermint, Peropesis,
|
PCBSD, PCLinuxOS, pearOS, Pengwin, Pentoo, Peppermint, Peropesis,
|
||||||
phyOS, PikaOS, Pisi, PNM Linux, Pop!_OS, Porteus, PostMarketOS,
|
phyOS, PikaOS, Pisi, PNM Linux, Pop!_OS, Porteus, PostMarketOS,
|
||||||
Profelis SambaBOX, Proxmox, PuffOS, Puppy, PureOS, Q4OS, Qubes,
|
Profelis SambaBOX, Proxmox, PuffOS, Puppy, PureOS, Q4OS, QNX, Qubes,
|
||||||
Qubyt, Quibian, Radix, Raspbian, ravynOS, Reborn OS, Red Star,
|
Qubyt, Quibian, Radix, Raspbian, ravynOS, Reborn OS, Red Star,
|
||||||
Redcore, Redhat, Refracted Devuan, Regata, Regolith, RhaymOS, Rhino
|
Redcore, Redhat, Refracted Devuan, Regata, Regolith, RhaymOS, Rhino
|
||||||
Linux, rocky, Rosa, Sabayon, sabotage, Sailfish, SalentOS, Salient
|
Linux, rocky, Rosa, Sabayon, sabotage, Sailfish, SalentOS, Salient
|
||||||
OS, Salix, Sasanqua, Scientific, semc, Septor, Serene, SharkLinux,
|
OS, Salix, Sasanqua, Scientific, secureblue, semc, Septor, Serene,
|
||||||
ShastraOS, Siduction, SkiffOS, Slackel, Slackware, SliTaz, SmartOS,
|
SharkLinux, ShastraOS, Siduction, SkiffOS, Slackel, Slackware,
|
||||||
Soda, Solus, Source Mage, Sparky, Star, SteamOS, Stock Linux, Sulin,
|
SliTaz, SmartOS, Soda, Solus, Source Mage, Sparky, Star, SteamOS,
|
||||||
SunOS, SwagArch, t2, Tails, Tatra, TeArch, TorizonCore, Trisquel,
|
Stock Linux, Sulin, SunOS, SwagArch, t2, Tails, Tatra, TeArch,
|
||||||
Twister, Ubuntu, Ubuntu Budgie, Ubuntu Cinnamon, Ubuntu Kylin,
|
TorizonCore, Trisquel, Twister, Ubuntu, Ubuntu Budgie, Ubuntu
|
||||||
Ubuntu MATE, Ubuntu Studio, Ubuntu Sway, Ubuntu Touch, Ubuntu\-GNOME,
|
Cinnamon, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Sway,
|
||||||
ubuntu_old02, Ultramarine Linux, unicodearch, Univalent, Univention,
|
Ubuntu Touch, Ubuntu\-GNOME, ubuntu_old02, Ultramarine Linux,
|
||||||
Uos, UrukOS, uwuntu, Vanilla, Venom, VNux, Void, VzLinux, wii\-linuxngx, Windows, Windows 10, Windows 11, Windows95, Wrt, Xenia, Xenia2,
|
unicodearch, Univalent, Univention, Uos, UrukOS, uwuntu, Vanilla,
|
||||||
XFerience, Xray_OS, Xubuntu, yiffOS, Zorin have ascii logos.
|
Venom, VNux, Void, VzLinux, wii\-linux\-ngx, Windows, Windows 10,
|
||||||
|
Windows 11, Windows95, Wrt, Xenia, Xenia2, XFerience, Xray_OS,
|
||||||
|
Xubuntu, yiffOS, Zirconium, Zorin have ascii logos.
|
||||||
.TP
|
.TP
|
||||||
NOTE: arch, dragonfly, Fedora, LangitKetujuh, nixos, redhat, Ubuntu
|
NOTE: arch, dragonfly, Fedora, LangitKetujuh, nixos, redhat, Ubuntu,
|
||||||
have 'old' logo variants, use {distro}_old to use them.
|
void have 'old' logo variants, use {distro}_old to use them.
|
||||||
.TP
|
.TP
|
||||||
NOTE: alpine, android, arch, arcolinux, artix, CalinixOS, centos,
|
NOTE: alpine, android, arch, arcolinux, artix, CalinixOS, centos,
|
||||||
cleanjaro, crux, debian, dragonfly, elementary, endeavouros, fedora,
|
cleanjaro, crux, debian, dragonfly, elementary, endeavouros, fedora,
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from .py import run_py
|
from .py import run_py
|
||||||
from .rs import run_rust
|
from .rs import run_rust
|
||||||
|
|
||||||
|
|
||||||
|
def run_neofetch():
|
||||||
|
from .neofetch_util import run_neofetch_cmd
|
||||||
|
import sys
|
||||||
|
run_neofetch_cmd(sys.argv[1:])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if os.environ.get('HYFETCH_PY', False):
|
if os.environ.get('HYFETCH_PY', False):
|
||||||
run_py()
|
run_py()
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
VERSION = '2.0.2'
|
from __future__ import annotations
|
||||||
|
|
||||||
|
VERSION = '2.1.0'
|
||||||
|
|||||||
+11
-3
@@ -135,9 +135,17 @@ class RGB:
|
|||||||
:return: RGB object
|
:return: RGB object
|
||||||
"""
|
"""
|
||||||
hex = hex.lstrip("#")
|
hex = hex.lstrip("#")
|
||||||
r = int(hex[0:2], 16)
|
|
||||||
g = int(hex[2:4], 16)
|
if len(hex) == 6:
|
||||||
b = int(hex[4:6], 16)
|
r = int(hex[0:2], 16)
|
||||||
|
g = int(hex[2:4], 16)
|
||||||
|
b = int(hex[4:6], 16)
|
||||||
|
elif len(hex) == 3:
|
||||||
|
r = int(hex[0] * 2, 16)
|
||||||
|
g = int(hex[1] * 2, 16)
|
||||||
|
b = int(hex[2] * 2, 16)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Error: invalid hex length")
|
||||||
return cls(r, g, b)
|
return cls(r, g, b)
|
||||||
|
|
||||||
def to_ansi_rgb(self, foreground: bool = True) -> str:
|
def to_ansi_rgb(self, foreground: bool = True) -> str:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from .types import LightDark
|
|||||||
from .__version__ import VERSION
|
from .__version__ import VERSION
|
||||||
|
|
||||||
CONFIG_PATH = Path.home() / '.config/hyfetch.json'
|
CONFIG_PATH = Path.home() / '.config/hyfetch.json'
|
||||||
|
SRC = Path(__file__).parent
|
||||||
|
|
||||||
|
|
||||||
TEST_ASCII = r"""
|
TEST_ASCII = r"""
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Ad\u00e9lie\"* | \"Adelie\"*", "color": "4 7 6"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
adelie = AsciiArt(match=r'''"Adélie"* | "Adelie"*''', color='4 7 6', ascii=r"""
|
|
||||||
${c1} ${c3} ,-^-___
|
${c1} ${c3} ,-^-___
|
||||||
${c3} /\\\///
|
${c3} /\\\///
|
||||||
${c2}refined.${c1} /\\\\//
|
${c2}refined.${c1} /\\\\//
|
||||||
@@ -19,5 +15,3 @@ ${c1} ///////${c3}\\\\\\\\\\//
|
|||||||
/\\\\//
|
/\\\\//
|
||||||
//////
|
//////
|
||||||
/// ${c3}\\\\\
|
/// ${c3}\\\\\
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{"match": "\"Aeon\"*", "color": "38;5;36 38;5;36"}
|
||||||
|
⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷
|
||||||
|
⣿⡇ ⢸⣿
|
||||||
|
⣿⡇ ⢀⣀ ⣀⡀ ⢸⣿
|
||||||
|
⣿⣇ ⠸⣿⣄ ⣠⣿⠇ ⣸⣿
|
||||||
|
⢹⣿⡄ ⠙⠻⠿⠿⠟⠋ ⢠⣿⡏
|
||||||
|
⠹⣿⣦⡀ ⢀⣴⣿⠏
|
||||||
|
⠈⠛⢿⣶⣤⣄ ⣠⣤⣶⡿⠛⠁
|
||||||
|
${c2} ⣠⣴⡿⠿⠛ ⠛⠿⢿⣦⣄
|
||||||
|
⣠⣾⠟⠉ ⠉⠻⣷⣄
|
||||||
|
⢰⣿⠏ ⢀⣤⣶⣶⣤⡀ ⠹⣿⡆
|
||||||
|
⣿⡟ ⢰⣿⠏⠁⠈⠹⣿⡆ ⢿⣿
|
||||||
|
⣿⡇ ⠈⠋ ⠙⠁ ⢸⣿
|
||||||
|
⣿⡇ ⢸⣿
|
||||||
|
⣿⣷⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"aerOS\"*", "color": "fg 0 0 0"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
aeros = AsciiArt(match=r'''"aerOS"*''', color='fg 0 0 0', ascii=r"""
|
|
||||||
${c1}
|
${c1}
|
||||||
ooo OOO OOO ooo
|
ooo OOO OOO ooo
|
||||||
oOO OOo
|
oOO OOo
|
||||||
@@ -25,5 +21,3 @@ ${c1}
|
|||||||
oOO OOo
|
oOO OOo
|
||||||
oOO OOo
|
oOO OOo
|
||||||
ooo OOO OOO ooo
|
ooo OOO OOO ooo
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{"match": "\"AerynOS\"*", "color": "7 5"}
|
||||||
|
;llll.
|
||||||
|
0MMMMMM:
|
||||||
|
NMMMMMMMMd
|
||||||
|
.@ .cccccccccoWMMMMMMMMMM0
|
||||||
|
@@ .MMMMMMMMMMMMMMMMMMMMMMMN
|
||||||
|
OMMMMMMMMMMMMMMMW.
|
||||||
|
.@ .MMMMMMMMMMMMMMMMMMM.
|
||||||
|
.@ dMMMMMMMMMMMMMMMMMMl OMMMMMMMMk
|
||||||
|
.OWMMMMM; dMMMMMMMMMk
|
||||||
|
.MMMMMMMMMk
|
||||||
|
@@ ooooooooooooooooooo .MMMMMMMMMN
|
||||||
|
.@ oooooMMMMMMMMMMMMP NMMMMMMMMW.
|
||||||
|
KMMMMMMMMMM. 0MMMMMMMMM:
|
||||||
|
NMMMMMMMMM. dMMMMMMMMMd
|
||||||
|
.WMMMMMMMW. XMMMMMMMMO
|
||||||
|
.MMMMMMMk. xMMMMMMMMX
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Afterglow\"*", "color": "5 1 3 4"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
afterglow = AsciiArt(match=r'''"Afterglow"*''', color='5 1 3 4', ascii=r"""
|
|
||||||
${c2} .
|
${c2} .
|
||||||
${c1}. ${c2}.{!
|
${c1}. ${c2}.{!
|
||||||
${c1}.L! ${c2}J@||*
|
${c1}.L! ${c2}J@||*
|
||||||
@@ -18,5 +14,3 @@ ${c2} .
|
|||||||
${c3}_@FFFFF ${c4}VLLLP`
|
${c3}_@FFFFF ${c4}VLLLP`
|
||||||
${c3}J@@LL@" ${c4}`"
|
${c3}J@@LL@" ${c4}`"
|
||||||
${c3}V@@"
|
${c3}V@@"
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AIX\"*", "color": "2 7"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
aix = AsciiArt(match=r'''"AIX"*''', color='2 7', ascii=r"""
|
|
||||||
${c1} `:+ssssossossss+-`
|
${c1} `:+ssssossossss+-`
|
||||||
.oys///oyhddddhyo///sy+.
|
.oys///oyhddddhyo///sy+.
|
||||||
/yo:+hNNNNNNNNNNNNNNNNh+:oy/
|
/yo:+hNNNNNNNNNNNNNNNNh+:oy/
|
||||||
@@ -23,5 +19,3 @@ h//NNNNh ossss` +h md- .hm/ `sNNNNN:+y
|
|||||||
:ys:/yNNNNNNNNNNNNNNNmy/:sy:
|
:ys:/yNNNNNNNNNNNNNNNmy/:sy:
|
||||||
.+ys///osyhhhhys+///sy+.
|
.+ys///osyhhhhys+///sy+.
|
||||||
-/osssossossso/-
|
-/osssossossso/-
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AlmaLinux\"*", "color": "1 3 4 2 6"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
almalinux = AsciiArt(match=r'''"AlmaLinux"*''', color='1 3 4 2 6', ascii=r"""
|
|
||||||
${c1} 'c:.
|
${c1} 'c:.
|
||||||
${c1} lkkkx, .. ${c2}.. ,cc,
|
${c1} lkkkx, .. ${c2}.. ,cc,
|
||||||
${c1} okkkk:ckkx' ${c2}.lxkkx.okkkkd
|
${c1} okkkk:ckkx' ${c2}.lxkkx.okkkkd
|
||||||
@@ -23,5 +19,3 @@ ${c3} ..... ${c5}.;dk:. ${c5}lkk. ${c4}:;,
|
|||||||
;kkkkl...
|
;kkkkl...
|
||||||
;kkkkl
|
;kkkkl
|
||||||
,od;
|
,od;
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Alpine\"*", "color": "4 5 7 6"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
alpine = AsciiArt(match=r'''"Alpine"*''', color='4 5 7 6', ascii=r"""
|
|
||||||
${c1} .hddddddddddddddddddddddh.
|
${c1} .hddddddddddddddddddddddh.
|
||||||
:dddddddddddddddddddddddddd:
|
:dddddddddddddddddddddddddd:
|
||||||
/dddddddddddddddddddddddddddd/
|
/dddddddddddddddddddddddddddd/
|
||||||
@@ -23,5 +19,3 @@ hdddyo+ohddyosdddddddddho+oydddy++ohdddh
|
|||||||
/dddddddddddddddddddddddddddd/
|
/dddddddddddddddddddddddddddd/
|
||||||
:dddddddddddddddddddddddddd:
|
:dddddddddddddddddddddddddd:
|
||||||
.hddddddddddddddddddddddh.
|
.hddddddddddddddddddddddh.
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{"match": "\"Alpine2\"*", "color": "4 7"}
|
||||||
|
.:::::::::::::::::::::.
|
||||||
|
.:::::::::::::::::::::::.
|
||||||
|
.:::::::::::::::::::::::::.
|
||||||
|
.:::::::::::::::::::::::::::.
|
||||||
|
.:::::::::${c2},db,${c1}::::::::::::::::.
|
||||||
|
.::::::::${c2},d%%%%b,${c1}::${c2},db,${c1}:::::::::.
|
||||||
|
.:::::::${c2},%%%%P'%%%b,d%%%b,${c1}::::::::.
|
||||||
|
.::::::${c2},%%%%P,${c1}:::${c2}`%%%b'^q%%b,${c1}:::::::.
|
||||||
|
'::::${c2},%%%%P,d|${c1}:::::${c2}`%%%b:'^%%b,${c1}:::::'
|
||||||
|
'::${c2}`%%%'${c1}:${c2}'q$|${c1}:::::::${c2}'q%%b'`q%%b'${c1}::'
|
||||||
|
':::::::::::::::::::::::::::::::'
|
||||||
|
':::::::::::::::::::::::::::::'
|
||||||
|
':::::::::::::::::::::::::::'
|
||||||
|
':::::::::::::::::::::::::'
|
||||||
|
':::::::::::::::::::::::'
|
||||||
|
':::::::::::::::::::::'
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{"match": "\"alpine2_small\"*", "color": "4 7"}
|
||||||
|
${c1} /\ /\
|
||||||
|
/${c2}/ ${c1}\ \
|
||||||
|
/${c2}// ${c1}\ \
|
||||||
|
/${c2}// ${c1}\ \
|
||||||
|
${c2}// ${c1}\ \
|
||||||
|
\
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{"match": "\"alpine3_small\"*", "color": "7"}
|
||||||
|
,db,
|
||||||
|
,d%%%%b, ,db,
|
||||||
|
,%%%%P'%%%b,d%%%b,
|
||||||
|
,%%%%P, `%%%b'^q%%b,
|
||||||
|
,%%%%P,d| `%%%b '^%%b,
|
||||||
|
`%%%' 'q$| 'q%%b'`q%%b
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{"match": "\"alpine_small\"", "color": "4 7"}
|
||||||
|
${c1} /\ /\
|
||||||
|
/${c2}/ ${c1}\ \
|
||||||
|
/${c2}/ ${c1}\ \
|
||||||
|
/${c2}// ${c1}\ \
|
||||||
|
${c2}// ${c1}\ \
|
||||||
|
\
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Alter\"*", "color": "6 6"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
alter = AsciiArt(match=r'''"Alter"*''', color='6 6', ascii=r"""
|
|
||||||
${c1} %,
|
${c1} %,
|
||||||
^WWWw
|
^WWWw
|
||||||
'wwwwww
|
'wwwwww
|
||||||
@@ -23,5 +19,3 @@ ${c1} %,
|
|||||||
8~~:~~:~~~~:~~~~_1ltltu ,www
|
8~~:~~:~~~~:~~~~_1ltltu ,www
|
||||||
5~~:~~:~~:~~:~~:~~~_1ltq N,,
|
5~~:~~:~~:~~:~~:~~~_1ltq N,,
|
||||||
g~:~~:~~~:~~:~~:~:~~~~1q N,
|
g~:~~:~~~:~~:~~:~:~~~~1q N,
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{"match": "\"ALTLinux\"*", "color": "3 8 7"}
|
||||||
|
##############
|
||||||
|
######################
|
||||||
|
##########################
|
||||||
|
##+${c2}####${c1}#######################
|
||||||
|
#####${c2}#${c1}*${c2}###%+${c1}######################
|
||||||
|
########${c2}%${c1}*#${c2}%#####${c1}###################
|
||||||
|
##########${c2}##${c1}*#*${c2}#######%+${c1}##############
|
||||||
|
#############${c2}%#############%${c1}############
|
||||||
|
#############${c2}+################${c1}##########
|
||||||
|
##############${c2}################*${c1}#########
|
||||||
|
##############${c2}+################+${c1}########
|
||||||
|
###############${c2}##########${c1}###${c2}+##%${c1}########
|
||||||
|
###############${c2}+########${c1}######${c2}###${c1}#######
|
||||||
|
#############${c2}*####${c1}############${c2}%#+${c1}#######
|
||||||
|
############${c2}+###${c3}####${c1}##########${c2}%#*${c1}#######
|
||||||
|
##########${c2}###*${c3}######${c2}+#+${c1}#####${c2}+##*${c1}######
|
||||||
|
#########${c2}##%${c3}#####${c2}:%#####${c1}###${c2}###*${c1}#####
|
||||||
|
########${c2}%#+${c3}######${c2}#############${c1}####
|
||||||
|
#####${c2}##%:${c3}######${c2}:############${c1}##
|
||||||
|
##${c2}+##*${c3}########${c2}############${c1}
|
||||||
|
${c2}###${c3}#########${c2}##########${c1}
|
||||||
|
${c3}########${c2}######
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Amazon\"*", "color": "3 7"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
amazon = AsciiArt(match=r'''"Amazon"*''', color='3 7', ascii=r"""
|
|
||||||
${c1} `-/oydNNdyo:.`
|
${c1} `-/oydNNdyo:.`
|
||||||
`.:+shmMMMMMMMMMMMMMMmhs+:.`
|
`.:+shmMMMMMMMMMMMMMMmhs+:.`
|
||||||
-+hNNMMMMMMMMMMMMMMMMMMMMMMNNho-
|
-+hNNMMMMMMMMMMMMMMMMMMMMMMNNho-
|
||||||
@@ -22,5 +18,3 @@ dMMMMMMMMMMMMMMMMh yMMMMMMMMMMMMMMMMd
|
|||||||
.:+ydNMMMMMMMMMMMh yMMMMMMMMMMMNdy+:.
|
.:+ydNMMMMMMMMMMMh yMMMMMMMMMMMNdy+:.
|
||||||
`.:+shNMMMMMh yMMMMMNhs+:``
|
`.:+shNMMMMMh yMMMMMNhs+:``
|
||||||
`-+shy shs+:`
|
`-+shy shs+:`
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{"match": "\"Amazon Linux\"*|\"amzn\"*", "color": "7 38;5;178"}
|
||||||
|
, ${c2}#_${c1}
|
||||||
|
~\_ ${c2}####_${c1}
|
||||||
|
~~ \_${c2}#####\${c1}
|
||||||
|
~~ \${c2}###|${c1}
|
||||||
|
~~ \${c2}#/${c1} ___
|
||||||
|
~~ V~' '->
|
||||||
|
~~~ /
|
||||||
|
~~._. _/
|
||||||
|
_/ _/
|
||||||
|
_/m/'
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{"match": "\"Amiga\"*", "color": "1 1 3 4 6 3 2"}
|
||||||
|
----.---
|
||||||
|
:-==.-==-
|
||||||
|
${c2} -=== ===:
|
||||||
|
===-:===.
|
||||||
|
${c3} -+++:=++=
|
||||||
|
=+++ +++.
|
||||||
|
${c6} .+++-=++=
|
||||||
|
${c4}.::. ::: ${c6} :**+ +**-
|
||||||
|
${c4} :--:.---. ${c6} .+**=-***.
|
||||||
|
${c5} :--- ---::${c6}***:***+
|
||||||
|
${c5} .---::-${c6}=##*.*##-
|
||||||
|
${c7} ----+${c6}##=:##*.
|
||||||
|
${c7} :-${c6}###-*##+
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AmogOS\"*", "color": "15 6"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
amogos = AsciiArt(match=r'''"AmogOS"*''', color='15 6', ascii=r"""
|
|
||||||
${c1} ___________
|
${c1} ___________
|
||||||
/ \
|
/ \
|
||||||
/ ${c2}______${c1} \
|
/ ${c2}______${c1} \
|
||||||
@@ -22,5 +18,3 @@ ${c1} ___________
|
|||||||
\_________/ / |
|
\_________/ / |
|
||||||
\ __/
|
\ __/
|
||||||
\_______/
|
\_______/
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Anarchy\"*", "color": "7 4", "foreground": [2]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
anarchy = AsciiArt(match=r'''"Anarchy"*''', color='7 4', ascii=r"""
|
|
||||||
${c2}..${c1}
|
${c2}..${c1}
|
||||||
${c2}..${c1}
|
${c2}..${c1}
|
||||||
${c2}:..${c1}
|
${c2}:..${c1}
|
||||||
@@ -31,5 +27,3 @@ anarchy = AsciiArt(match=r'''"Anarchy"*''', color='7 4', ascii=r"""
|
|||||||
${c2}.:${c1}:
|
${c2}.:${c1}:
|
||||||
${c2}..${c1}
|
${c2}..${c1}
|
||||||
${c2}..${c1}
|
${c2}..${c1}
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Android\"*", "color": "2 7", "foreground": [2]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
android = AsciiArt(match=r'''"Android"*''', color='2 7', ascii=r"""
|
|
||||||
${c1} -o o-
|
${c1} -o o-
|
||||||
+hydNNNNdyh+
|
+hydNNNNdyh+
|
||||||
+mMMMMMMMMMMMMm+
|
+mMMMMMMMMMMMMm+
|
||||||
@@ -21,5 +17,3 @@ ${c1} -o o-
|
|||||||
MMMMo oMMMM
|
MMMMo oMMMM
|
||||||
MMMMo oMMMM
|
MMMMo oMMMM
|
||||||
oNMm- -mMNs
|
oNMm- -mMNs
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{"match": "\"android_small\"*", "color": "2 7"}
|
||||||
|
${c1} ;, ,;
|
||||||
|
';,.-----.,;'
|
||||||
|
,' ',
|
||||||
|
/ O O \
|
||||||
|
| |
|
||||||
|
'-----------------'
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{"match": "\"anduinos\"*", "color": "6 4"}
|
||||||
|
${c1}+++++++++++
|
||||||
|
+++++++++++++++++++++
|
||||||
|
+++++++++++++++++++++++++++++++
|
||||||
|
=+++++++++++++++++++++++++++++++++++++++=
|
||||||
|
+++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
=++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
==+++++++++++++++++++++++++++++++++==
|
||||||
|
+++++++++++++++++++++++++++
|
||||||
|
${c2}**** ${c1}++=+++++++++++=++ ${c2}****
|
||||||
|
********** ${c1}+++++++ ${c2}**********
|
||||||
|
************** **************
|
||||||
|
**************** ****************
|
||||||
|
***********************
|
||||||
|
****** ************* ******
|
||||||
|
*********** *** ***********
|
||||||
|
*************** ***************
|
||||||
|
*************** ***************
|
||||||
|
*********************
|
||||||
|
***********
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Antergos\"*", "color": "4 6", "foreground": [1]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
antergos = AsciiArt(match=r'''"Antergos"*''', color='4 6', ascii=r"""
|
|
||||||
${c2} `.-/::/-``
|
${c2} `.-/::/-``
|
||||||
.-/osssssssso/.
|
.-/osssssssso/.
|
||||||
:osyysssssssyyys+-
|
:osyysssssssyyys+-
|
||||||
@@ -22,5 +18,3 @@ dmmmdddddddhhhyso${c1}++++++${c2}shhhhhddddddmmmmh
|
|||||||
.smmmmddddddddhhhhhhhhhdddddddddmmmms.
|
.smmmmddddddddhhhhhhhhhdddddddddmmmms.
|
||||||
`+ydmmmdddddddddddddddddddmmmmdy/.
|
`+ydmmmdddddddddddddddddddmmmmdy/.
|
||||||
`.:+ooyyddddddddddddyyso+:.`
|
`.:+ooyyddddddddddddyyso+:.`
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"antiX\"*", "color": "1 7 3"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
antix = AsciiArt(match=r'''"antiX"*''', color='1 7 3', ascii=r"""
|
|
||||||
${c1}
|
${c1}
|
||||||
\
|
\
|
||||||
, - ~ ^ ~ - \ /
|
, - ~ ^ ~ - \ /
|
||||||
@@ -16,5 +12,3 @@ ${c1}
|
|||||||
, / ,\
|
, / ,\
|
||||||
, / , ' \
|
, / , ' \
|
||||||
' - , _ _ _ , '
|
' - , _ _ _ , '
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{"match": "\"AnushOS\"*", "color": "7 8 3 6 1"}
|
||||||
|
${c4}#######################
|
||||||
|
${c4}# ${c2}##### ${c4}#
|
||||||
|
${c4}# ${c2}####### ${c4}#
|
||||||
|
${c4}# ${c2}##${c5}O${c2}#${c5}O${c2}## ${c4}#
|
||||||
|
${c4}# ${c2}#${c3}#####${c2}# ${c4}#
|
||||||
|
${c4}# ${c2}##${c1}##${c3}###${c1}##${c2}## ${c4}#
|
||||||
|
${c4}# ${c2}#${c1}##########${c2}## ${c4}#
|
||||||
|
${c4}# ${c2}#${c1}############${c2}## ${c4}#
|
||||||
|
${c4}# ${c2}#${c1}######${c5}A_O${c1}####${c2}### ${c4}#
|
||||||
|
${c4}# ${c3}##${c2}#${c1}############${c2}##${c3}## ${c4}#
|
||||||
|
${c4}#${c3}######${c2}#${c1}#######${c2}#${c3}######${c4}#
|
||||||
|
${c4}#${c3}#######${c2}#${c1}#####${c2}#${c3}#######${c4}#
|
||||||
|
${c4}# ${c3}#####${c2}#######${c3}##### ${c4}#
|
||||||
|
${c4}#######################
|
||||||
|
${c4}#${c5}╔═╗╔╗╔╦ ╦╔═╗╦ ╦╔═╗╔═╗${c4}#
|
||||||
|
${c4}#${c5}╠═╣║║║║ ║╚═╗╠═╣║ ║╚═╗${c4}#
|
||||||
|
${c4}#${c5}╩ ╩╝╚╝╚═╝╚═╝╩ ╩╚═╝╚═╝${c4}#
|
||||||
|
${c4}#######################
|
||||||
|
${c4}# ${c3}WWW.ANUSHOS.ORG ${c4}#
|
||||||
|
${c4}#######################
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AOSC OS\"*", "color": "4 0 1 3"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
aosc_os = AsciiArt(match=r'''"AOSC OS"*''', color='4 0 1 3', ascii=r'''
|
|
||||||
${c2} __
|
${c2} __
|
||||||
${c2}gpBBBBBBBBBP
|
${c2}gpBBBBBBBBBP
|
||||||
${c2}_gBBBBBBBBBRP
|
${c2}_gBBBBBBBBBRP
|
||||||
@@ -20,5 +16,3 @@ ${c2} __
|
|||||||
${c3}_wNNNNNNNNNNNNNNNNNNNM^
|
${c3}_wNNNNNNNNNNNNNNNNNNNM^
|
||||||
${c3}""Y^^MNNNNNNNNNNNNP`
|
${c3}""Y^^MNNNNNNNNNNNNP`
|
||||||
${c3}`"""""""
|
${c3}`"""""""
|
||||||
''')
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{"match": "\"Aosc OS_old\"*|\"aoscos_old\"*", "color": "7"}
|
||||||
|
.:+syhhhhys+:.
|
||||||
|
.ohNMMMMMMMMMMMMMMNho.
|
||||||
|
`+mMMMMMMMMMMmdmNMMMMMMMMm+`
|
||||||
|
+NMMMMMMMMMMMM/ `./smMMMMMN+
|
||||||
|
.mMMMMMMMMMMMMMMo -yMMMMMm.
|
||||||
|
:NMMMMMMMMMMMMMMMs .hMMMMN:
|
||||||
|
.NMMMMhmMMMMMMMMMMm+/- oMMMMN.
|
||||||
|
dMMMMs ./ymMMMMMMMMMMNy. sMMMMd
|
||||||
|
-MMMMN` oMMMMMMMMMMMN: `NMMMM-
|
||||||
|
/MMMMh NMMMMMMMMMMMMm hMMMM/
|
||||||
|
/MMMMh NMMMMMMMMMMMMm hMMMM/
|
||||||
|
-MMMMN` :MMMMMMMMMMMMy. `NMMMM-
|
||||||
|
dMMMMs .yNMMMMMMMMMMMNy/. sMMMMd
|
||||||
|
.NMMMMo -/+sMMMMMMMMMMMmMMMMN.
|
||||||
|
:NMMMMh. .MMMMMMMMMMMMMMMN:
|
||||||
|
.mMMMMMy- NMMMMMMMMMMMMMm.
|
||||||
|
+NMMMMMms/.` mMMMMMMMMMMMN+
|
||||||
|
`+mMMMMMMMMNmddMMMMMMMMMMm+`
|
||||||
|
.ohNMMMMMMMMMMMMMMNho.
|
||||||
|
.:+syhhhhys+:.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{"match": "\"Aosc OS/Retro\"*|\"aoscosretro\"*", "color": "4 7"}
|
||||||
|
${c2} .........
|
||||||
|
...................
|
||||||
|
.....................${c1}################${c2}
|
||||||
|
.............. ....${c1}################${c2}
|
||||||
|
.............. ...${c1}################${c2}
|
||||||
|
............. ..${c1}****************${c2}
|
||||||
|
............ . .${c1}****************${c2}
|
||||||
|
........... ... ${c1}................${c2}
|
||||||
|
.......... ..... ${c1}...............${c2}
|
||||||
|
......... ....... ...
|
||||||
|
.${c3}...... ${c2}.
|
||||||
|
${c3}..... .....${c2}.... ${c4}...........
|
||||||
|
${c3}.... ......${c2}. ${c4}...........
|
||||||
|
${c3}... ....... ${c4}...........
|
||||||
|
${c3}................ ${c4}***********
|
||||||
|
${c3}................ ${c4}###########
|
||||||
|
${c3}****************
|
||||||
|
${c3}################
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{"match": "\"Aosc OS/Retro_small\"*|\"aoscosretro_small\"*", "color": "4 7"}
|
||||||
|
${c2} _____ ${c1}_____${c2}
|
||||||
|
-' '-${c1}| |${c2}
|
||||||
|
/ ___ ${c1}| |${c2}
|
||||||
|
| / _ \${c1}|_____|${c2}
|
||||||
|
' / /_\ \
|
||||||
|
\ / _____ \${c4}___
|
||||||
|
${c3}|${c2}/_/ ${c3}| ${c4}| |
|
||||||
|
${c3}| | ${c4}|___|
|
||||||
|
${c3}|_____|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{"match": "\"Aperio GNU/Linux\"*", "color": "255"}
|
||||||
|
${c2}
|
||||||
|
_.._ _ ._.. _
|
||||||
|
(_][_)(/,[ |(_)
|
||||||
|
| GNU/Linux
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Aperture\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
aperture = AsciiArt(match=r'''"Aperture"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} .,-:;//;:=,
|
${c1} .,-:;//;:=,
|
||||||
. :H@@@MM@M#H/.,+%;,
|
. :H@@@MM@M#H/.,+%;,
|
||||||
,/X+ +M@@M@MM%=,-%HMMM@X/,
|
,/X+ +M@@M@MM%=,-%HMMM@X/,
|
||||||
@@ -23,5 +19,3 @@ ${c1} .,-:;//;:=,
|
|||||||
=%@M@M#@$-.=$@MM@@@M; %M%=
|
=%@M@M#@$-.=$@MM@@@M; %M%=
|
||||||
,:+$+-,/H#MMMMMMM@= =,
|
,:+$+-,/H#MMMMMMM@= =,
|
||||||
=++%%%%+/:-.
|
=++%%%%+/:-.
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{"match": "\"Apple\"*", "color": "2 3 1 1 5 4"}
|
||||||
|
..'
|
||||||
|
,xNMM.
|
||||||
|
.OMMMMo
|
||||||
|
lMM"
|
||||||
|
.;loddo:. .olloddol;.
|
||||||
|
cKMMMMMMMMMMNWMMMMMMMMMM0:
|
||||||
|
${c2}.KMMMMMMMMMMMMMMMMMMMMMMMWd.
|
||||||
|
XMMMMMMMMMMMMMMMMMMMMMMMX.
|
||||||
|
${c3};MMMMMMMMMMMMMMMMMMMMMMMM:
|
||||||
|
:MMMMMMMMMMMMMMMMMMMMMMMM:
|
||||||
|
${c4}.MMMMMMMMMMMMMMMMMMMMMMMMX.
|
||||||
|
kMMMMMMMMMMMMMMMMMMMMMMMMWd.
|
||||||
|
${c5}'XMMMMMMMMMMMMMMMMMMMMMMMMMMk
|
||||||
|
'XMMMMMMMMMMMMMMMMMMMMMMMMK.
|
||||||
|
${c6}kMMMMMMMMMMMMMMMMMMMMMMd
|
||||||
|
;KMMMMMMMWXXWMMMMMMMk.
|
||||||
|
"cooc*" "*coo'"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{"match": "\"Apple_small\"*", "color": "2 3 1 5 4"}
|
||||||
|
${c1} .:'
|
||||||
|
__ :'__
|
||||||
|
${c2} .'`__`-'__``.
|
||||||
|
${c3}:__________.-'
|
||||||
|
${c4}:_________:
|
||||||
|
:_________`-;
|
||||||
|
${c5} `.__.-.__.'
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Apricity\"*", "color": "4 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
apricity = AsciiArt(match=r'''"Apricity"*''', color='4 7 1', ascii=r"""
|
|
||||||
${c2} ./o-
|
${c2} ./o-
|
||||||
``...`` `:. -/:
|
``...`` `:. -/:
|
||||||
`-+ymNMMMMMNmho-` :sdNNm/
|
`-+ymNMMMMMNmho-` :sdNNm/
|
||||||
@@ -21,5 +17,3 @@ MMMMMMNmNNMMMMMMMMmo.
|
|||||||
MMMMMMMMMMMMMMMms:`
|
MMMMMMMMMMMMMMMms:`
|
||||||
MMMMMMMMMMNds/.
|
MMMMMMMMMMNds/.
|
||||||
dhhyys+/-`
|
dhhyys+/-`
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Arch\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arch = AsciiArt(match=r'''"Arch"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} -`
|
${c1} -`
|
||||||
.o+`
|
.o+`
|
||||||
`ooo/
|
`ooo/
|
||||||
@@ -22,5 +18,3 @@ ${c2} .oossssso-````/ossssss+`
|
|||||||
`+sso+:-` `.-/+oso:
|
`+sso+:-` `.-/+oso:
|
||||||
`++:. `-/+/
|
`++:. `-/+/
|
||||||
.` `/
|
.` `/
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{"match": "\"arch2\"*", "color": "6 6"}
|
||||||
|
▄
|
||||||
|
▟█▙
|
||||||
|
▟███▙
|
||||||
|
▟█████▙
|
||||||
|
▟███████▙
|
||||||
|
▂▔▀▜██████▙
|
||||||
|
▟██▅▂▝▜█████▙
|
||||||
|
▟█████████████▙
|
||||||
|
▟███████████████▙
|
||||||
|
▟█████████████████▙
|
||||||
|
▟███████████████████▙
|
||||||
|
${c2} ▟█████████▛▀▀▜████████▙
|
||||||
|
▟████████▛ ▜███████▙
|
||||||
|
▟█████████ ████████▙
|
||||||
|
▟██████████ █████▆▅▄▃▂
|
||||||
|
▟██████████▛ ▜█████████▙
|
||||||
|
▟██████▀▀▀ ▀▀██████▙
|
||||||
|
▟███▀▘ ▝▀███▙
|
||||||
|
▟▛▀ ▀▜▙
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{"match": "\"arch3\"*", "color": "6 6"}
|
||||||
|
.
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/>, \
|
||||||
|
/ `*. \
|
||||||
|
/ ` \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
${c2} / ,.-+-.. \
|
||||||
|
/ ,/' `\. \
|
||||||
|
/ .|' `|. _ \
|
||||||
|
/ :|. ,|; `+.\
|
||||||
|
/ .\: ;/, "<\
|
||||||
|
/ __,--+" "+--.__ \
|
||||||
|
/ _,+'" "'+._ \
|
||||||
|
/,-' `-.\
|
||||||
|
' '
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"arch_old\"", "color": "6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arch_old = AsciiArt(match=r'''"arch_old"''', color='6 7 1', ascii=r"""
|
|
||||||
${c1} __
|
${c1} __
|
||||||
_=(SDGJT=_
|
_=(SDGJT=_
|
||||||
_GTDJHGGFCVS)
|
_GTDJHGGFCVS)
|
||||||
@@ -19,5 +15,3 @@ ${c1}HELK['${c2} __,=OFFXCBGHC${c1}\FD)
|
|||||||
${c1}?KGHE ${c2}\_-#DASDFLSV='${c1} 'EF
|
${c1}?KGHE ${c2}\_-#DASDFLSV='${c1} 'EF
|
||||||
'EHTI !H
|
'EHTI !H
|
||||||
`0F' '!
|
`0F' '!
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{"match": "\"arch_small\"", "color": "6 7 1"}
|
||||||
|
${c1} /\
|
||||||
|
/ \
|
||||||
|
/\ \
|
||||||
|
${c2} / \
|
||||||
|
/ ,, \
|
||||||
|
/ | | -\
|
||||||
|
/_-'' ''-_\
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ArchBox\"*", "color": "2 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archbox = AsciiArt(match=r'''"ArchBox"*''', color='2 7 1', ascii=r"""
|
|
||||||
${c1} ...:+oh/:::..
|
${c1} ...:+oh/:::..
|
||||||
..-/oshhhhhh` `::::-.
|
..-/oshhhhhh` `::::-.
|
||||||
.:/ohhhhhhhhhhhh` `-::::.
|
.:/ohhhhhhhhhhhh` `-::::.
|
||||||
@@ -22,5 +18,3 @@ ${c1} ...:+oh/:::..
|
|||||||
`--/:` /: `hhhhhhhhhhhho/-
|
`--/:` /: `hhhhhhhhhhhho/-
|
||||||
-/:. `hhhhhhs+:-`
|
-/:. `hhhhhhs+:-`
|
||||||
::::/ho/-`
|
::::/ho/-`
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Archcraft\"*", "color": "6 1 2 3 4 5"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archcraft = AsciiArt(match=r'''"Archcraft"*''', color='6 1 2 3 4 5', ascii=r"""
|
|
||||||
${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢰⡆${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢰⡆${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||||
${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢠⣿⣿⡄${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢠⣿⣿⡄${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||||
${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢀⣾⣿⣿⣿⡀${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢀⣾⣿⣿⣿⡀${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||||
@@ -23,5 +19,3 @@ ${c5}⠄⠄⠄${c1}⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏${c5}⠄⠄⠄⠄⠄⠄
|
|||||||
${c6}⠄⠄${c1}⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄${c6}⠄⠄
|
${c6}⠄⠄${c1}⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄${c6}⠄⠄
|
||||||
${c1}⠄${c1}⣠⣿⣿⣿⣿⠿⠛⠋⠁${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠻⢿⣿⣿⣿⣿⣆${c1}⠄
|
${c1}⠄${c1}⣠⣿⣿⣿⣿⠿⠛⠋⠁${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠻⢿⣿⣿⣿⣿⣆${c1}⠄
|
||||||
${c1}⡰⠟⠛⠉⠁${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠛⠿⢆
|
${c1}⡰⠟⠛⠉⠁${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠛⠿⢆
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Archcraft2\"*", "color": "6"}
|
||||||
|
-o\
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archcraft_ascii = AsciiArt(match=r'''"archcraft_ascii"*''', color='6 1 2 3 4 5', ascii=r"""
|
|
||||||
${c1} -o\
|
|
||||||
:ooo:
|
:ooo:
|
||||||
.ooooo.
|
.ooooo.
|
||||||
ooooooo.
|
ooooooo.
|
||||||
@@ -23,5 +19,3 @@ ${c1} -o\
|
|||||||
.+osossos+-` `-+osososs+.
|
.+osossos+-` `-+osososs+.
|
||||||
:sss+=-:` `:-=+ssss:
|
:sss+=-:` `:-=+ssss:
|
||||||
:=-:` `-=+:
|
:=-:` `-=+:
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{"match": "\"archcraft_ascii\"*", "color": "6 1 2 3 4 5"}
|
||||||
|
${c1} -o\
|
||||||
|
:ooo:
|
||||||
|
.ooooo.
|
||||||
|
ooooooo.
|
||||||
|
+oooooooo.
|
||||||
|
-oooooooooo.
|
||||||
|
--:-+oooooooo.
|
||||||
|
yooo+=+sooooooo.
|
||||||
|
yoooooosooooooooo.
|
||||||
|
y+ooooooooooooooooo.
|
||||||
|
yoooooooooooooooooooo`
|
||||||
|
yoooooo+oo= :oo++ooooo`
|
||||||
|
:oooooo. +ooooo-
|
||||||
|
-ooooooo. .::. +ooosoo=
|
||||||
|
-oooooo` .oooo` +os-=o=
|
||||||
|
=ooooooo=: `oo+ :=ooo=--`.
|
||||||
|
+ooooooooos. .=sooooooo+-
|
||||||
|
.+osossos+-` `-+osososs+.
|
||||||
|
:sss+=-:` `:-=+ssss:
|
||||||
|
:=-:` `-=+:
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"archcraft_minimal\"*", "color": "6 1 2 3 4 5"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archcraft_minimal = AsciiArt(match=r'''"archcraft_minimal"*''', color='6 1 2 3 4 5', ascii=r"""
|
|
||||||
${c1} ⢰⡆
|
${c1} ⢰⡆
|
||||||
⢠⣿⣿⡄
|
⢠⣿⣿⡄
|
||||||
⢀⣾⣿⣿⣿⡀
|
⢀⣾⣿⣿⣿⡀
|
||||||
@@ -23,5 +19,3 @@ ${c1} ⢰⡆
|
|||||||
⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁ ⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄
|
⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁ ⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄
|
||||||
⣠⣿⣿⣿⣿⠿⠛⠋⠁ ⠉⠙⠻⢿⣿⣿⣿⣿⣆
|
⣠⣿⣿⣿⣿⠿⠛⠋⠁ ⠉⠙⠻⢿⣿⣿⣿⣿⣆
|
||||||
⡰⠟⠛⠉⠁ ⠉⠙⠛⠿⢆
|
⡰⠟⠛⠉⠁ ⠉⠙⠛⠿⢆
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ARCHlabs\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archlabs = AsciiArt(match=r'''"ARCHlabs"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} 'c'
|
${c1} 'c'
|
||||||
'kKk,
|
'kKk,
|
||||||
.dKKKx.
|
.dKKKx.
|
||||||
@@ -24,5 +20,3 @@ ${c1} 'c'
|
|||||||
'xKK0koc,.. ${c4}'c, ${c1} ..,cok0KKk,
|
'xKK0koc,.. ${c4}'c, ${c1} ..,cok0KKk,
|
||||||
,xko:'. ${c4}.. ${c1} .':okx;
|
,xko:'. ${c4}.. ${c1} .':okx;
|
||||||
.,'. .',.
|
.,'. .',.
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ArchMerge\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archmerge = AsciiArt(match=r'''"ArchMerge"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} y:
|
${c1} y:
|
||||||
sMN-
|
sMN-
|
||||||
+MMMm`
|
+MMMm`
|
||||||
@@ -23,5 +19,3 @@ ${c1} y:
|
|||||||
/NMMMNds+:.` `-/oymMMMm.
|
/NMMMNds+:.` `-/oymMMMm.
|
||||||
+Mmy/. `:smN:
|
+Mmy/. `:smN:
|
||||||
/+. -o.
|
/+. -o.
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ArchStrike\"*", "color": "8 6", "foreground": [2]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
archstrike = AsciiArt(match=r'''"ArchStrike"*''', color='8 6', ascii=r"""
|
|
||||||
${c1} *
|
${c1} *
|
||||||
**.
|
**.
|
||||||
****
|
****
|
||||||
@@ -20,5 +16,3 @@ ${c1} *
|
|||||||
******${c2}/${c1}*** ${c2}//// ${c1}**${c2}/${c1}******
|
******${c2}/${c1}*** ${c2}//// ${c1}**${c2}/${c1}******
|
||||||
********${c2}/${c1}* ${c2}/// ${c1}*${c2}/${c1}********
|
********${c2}/${c1}* ${c2}/// ${c1}*${c2}/${c1}********
|
||||||
,****** ${c2}// ______ / ${c1}******,
|
,****** ${c2}// ______ / ${c1}******,
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{"match": "\"arco\"*|\"arcolinux\"*", "color": "4 7"}
|
||||||
|
/-
|
||||||
|
ooo:
|
||||||
|
yoooo/
|
||||||
|
yooooooo
|
||||||
|
yooooooooo
|
||||||
|
yooooooooooo
|
||||||
|
.yooooooooooooo
|
||||||
|
.oooooooooooooooo
|
||||||
|
.oooooooarcoooooooo
|
||||||
|
.ooooooooo-oooooooooo
|
||||||
|
.ooooooooo- oooooooooo
|
||||||
|
:ooooooooo. :ooooooooo
|
||||||
|
:ooooooooo. :ooooooooo
|
||||||
|
:oooarcooo .oooarcooo
|
||||||
|
:ooooooooy .ooooooooo
|
||||||
|
${c1}:ooooooooo ${c2}/ooooooooooooooooooo
|
||||||
|
${c1}:ooooooooo ${c2}.-ooooooooooooooooo.
|
||||||
|
${c1}ooooooooo- ${c2}-ooooooooooooo.
|
||||||
|
${c1}ooooooooo- ${c2}.-oooooooooo.
|
||||||
|
${c1}ooooooooo. ${c2}-ooooooooo
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{"match": "\"arco_small\"*|\"arcolinux_small\"*", "color": "4 7"}
|
||||||
|
A
|
||||||
|
ooo
|
||||||
|
ooooo
|
||||||
|
ooooooo
|
||||||
|
ooooooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ${c2}<oooooooo>${c1}
|
||||||
|
ooooo ${c2}<oooooo>${c1}
|
||||||
|
ooooo ${c2}<oooo>
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ArcoLinux\"*", "color": "7 4"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arcolinux = AsciiArt(match=r'''"ArcoLinux"*''', color='7 4', ascii=r"""
|
|
||||||
${c2} /-
|
${c2} /-
|
||||||
ooo:
|
ooo:
|
||||||
yoooo/
|
yoooo/
|
||||||
@@ -23,5 +19,3 @@ ${c2} /-
|
|||||||
ooooooooo- ${c1}-ooooooooooooo.${c2}
|
ooooooooo- ${c1}-ooooooooooooo.${c2}
|
||||||
ooooooooo- ${c1}.-oooooooooo.${c2}
|
ooooooooo- ${c1}.-oooooooooo.${c2}
|
||||||
ooooooooo. ${c1}-ooooooooo${c2}
|
ooooooooo. ${c1}-ooooooooo${c2}
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{"match": "\"arcolinux_small\"*", "color": "7 4"}
|
||||||
|
${c2} A
|
||||||
|
ooo
|
||||||
|
ooooo
|
||||||
|
ooooooo
|
||||||
|
ooooooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ooooo
|
||||||
|
ooooo ${c1}<oooooooo>${c2}
|
||||||
|
ooooo ${c1}<oooooo>${c2}
|
||||||
|
ooooo ${c1}<oooo>${c2}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Arkane\"*", "color": "7 130 237", "foreground": [1]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arkane = AsciiArt(match=r'''"Arkane"*''', color='7 130 237', ascii=r"""
|
|
||||||
${c3} .:..
|
${c3} .:..
|
||||||
..:::......
|
..:::......
|
||||||
${c2}.${c3} .${c2}.${c3}.....
|
${c2}.${c3} .${c2}.${c3}.....
|
||||||
@@ -26,5 +22,3 @@ ${c2}.-==+++***++*${c1}*#########${c3}=:::.
|
|||||||
${c2}.:==++++++**${c1}#############${c3}:
|
${c2}.:==++++++**${c1}#############${c3}:
|
||||||
${c2}.${c3}-+*++*+++==${c1}###${c3}+
|
${c2}.${c3}-+*++*+++==${c1}###${c3}+
|
||||||
-${c1}*+${c3}:
|
-${c1}*+${c3}:
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{"match": "\"Armbian\"*", "color": "7 1"}
|
||||||
|
..
|
||||||
|
`:]x**j-,'
|
||||||
|
.,+t***********z\<"
|
||||||
|
?******************;
|
||||||
|
'*n` .'`^,;;,^`'. ,cc.
|
||||||
|
-<. .[l
|
||||||
|
// ^^ ^^ \
|
||||||
|
!^ ${c2}^^${c1} ":
|
||||||
|
'tt}` ${c2}!~]rj_${c1} ")t/.
|
||||||
|
Itttt?' ${c2}~~]rr]${c1} `{tttt,
|
||||||
|
\tttttt!""I${c2}_]r(${c1}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{"match": "\"Armbian2\"*", "color": "1"}
|
||||||
|
█ █ █ █ █ █ █ █ █ █ █
|
||||||
|
███████████████████████
|
||||||
|
▄▄██ ██▄▄
|
||||||
|
▄▄██ ███████████ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ █████████████ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ ██ ██ ██▄▄
|
||||||
|
▄▄██ ██▄▄
|
||||||
|
███████████████████████
|
||||||
|
█ █ █ █ █ █ █ █ █ █ █
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{"match": "\"arse\"*|\"arselinux\"*|\"arse-linux\"*", "color": "4 7"}
|
||||||
|
⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⣶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⣴⣶⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣄⠀⠀⠀⠀⣼⠟⠁⠀⠀⢀⣀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⢀⣤⡀⠀⠀⠀⠉⢻⣷⡄⠀⠀⠁⠀⢀⣤⣾⡿⠟⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣷⣿⠏⠀⠀⠀⠀⠀⠀⠹⣿⡄⠀⠀⠀⠙⠉⠁⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⡄⠀⠀⠀⠀⠀⠀⠀⢹⣿⠀⠀⠀⠀⠠⣶⣶⣶⡶
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⢠⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠂⠀⠀⠀⠀⠀⢀⣾⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠇⠀⠀⠀⠀⠀⣠⣾⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣿⣇⣀⣀⣀⣠⣴⣾⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⢸⣿⠀⠀⠀⠀⠀⣤⣤⣴⣶⣾⠿⠟⣿⡏⠙⠛⠛⠛⠋⠉⢀⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⣿⡄⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⠇⠀⠀⠀⠀⠀⠀⠘⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"ArseLinux\"*", "color": "4 7"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arselinux = AsciiArt(match=r'''"ArseLinux"*''', color='4 7', ascii=r"""
|
|
||||||
${c1}
|
${c1}
|
||||||
⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⣶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⣴⣶⠀⠀⠀⠀⠀
|
⠀⣶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⣴⣶⠀⠀⠀⠀⠀
|
||||||
@@ -19,5 +15,3 @@ ${c1}
|
|||||||
⠀⣿⡄⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⣿⡄⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⠇⠀⠀⠀⠀⠀⠀⠘⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⠇⠀⠀⠀⠀⠀⠀⠘⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Artix\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
artix = AsciiArt(match=r'''"Artix"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} '
|
${c1} '
|
||||||
'o'
|
'o'
|
||||||
'ooo'
|
'ooo'
|
||||||
@@ -23,5 +19,3 @@ ${c1} '
|
|||||||
'ooooi:'` `'';ioxxo'
|
'ooooi:'` `'';ioxxo'
|
||||||
'i:'` '':io'
|
'i:'` '':io'
|
||||||
'` `'
|
'` `'
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{"match": "\"artix2_small\"*", "color": "6"}
|
||||||
|
/\
|
||||||
|
/ \
|
||||||
|
/`'.,\
|
||||||
|
/ ',
|
||||||
|
/ ,`\
|
||||||
|
/ ,.'`. \
|
||||||
|
/.,'` `'.\
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"artix_small\"*", "color": "6 6 7 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
artix_small = AsciiArt(match=r'''"artix_small"*''', color='6 6 7 1', ascii=r"""
|
|
||||||
${c1} '
|
${c1} '
|
||||||
'A'
|
'A'
|
||||||
'ooo'
|
'ooo'
|
||||||
@@ -16,5 +12,3 @@ ${c1} '
|
|||||||
'ooxoo'` .:ooxxo'
|
'ooxoo'` .:ooxxo'
|
||||||
'io'` `'oo'
|
'io'` `'oo'
|
||||||
'` `'
|
'` `'
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Arya\"*", "color": "2 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
arya = AsciiArt(match=r'''"Arya"*''', color='2 1', ascii=r"""
|
|
||||||
${c1} `oyyy/${c2}-yyyyyy+
|
${c1} `oyyy/${c2}-yyyyyy+
|
||||||
${c1} -syyyy/${c2}-yyyyyy+
|
${c1} -syyyy/${c2}-yyyyyy+
|
||||||
${c1} .syyyyy/${c2}-yyyyyy+
|
${c1} .syyyyy/${c2}-yyyyyy+
|
||||||
@@ -18,5 +14,3 @@ ${c1} .oyyyyyyo. :yyyyyy/${c2}-yyyyyy+ ---------
|
|||||||
${c1} .syyyyyy+` :yyyyyy/${c2}-yyyyy+-+syyyyyyyy
|
${c1} .syyyyyy+` :yyyyyy/${c2}-yyyyy+-+syyyyyyyy
|
||||||
${c1} -syyyyyy/ :yyyyyy/${c2}-yyys:.syyyyyyyyyy
|
${c1} -syyyyyy/ :yyyyyy/${c2}-yyys:.syyyyyyyyyy
|
||||||
${c1}:syyyyyy/ :yyyyyy/${c2}-yyo.:syyyyyyyyyyy
|
${c1}:syyyyyy/ :yyyyyy/${c2}-yyo.:syyyyyyyyyyy
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Asahi\"*", "color": "3 2 1 8 7 6 4", "foreground": [5]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
asahi = AsciiArt(match=r'''"Asahi"*''', color='3 2 1 8 7 6 4', ascii=r"""
|
|
||||||
${c1} ## ${c2}**
|
${c1} ## ${c2}**
|
||||||
${c1}*####${c2}****.
|
${c1}*####${c2}****.
|
||||||
${c1}###${c2},
|
${c1}###${c2},
|
||||||
@@ -21,5 +17,3 @@ ${c3}(((((((((((((((((((((${c5}@@@${c6}&%&${c5}@@@%${c4},..........
|
|||||||
${c3}.(((((((((${c5}@@@@(${c4}....
|
${c3}.(((((((((${c5}@@@@(${c4}....
|
||||||
${c3}/(((((${c5}@@#${c4}...
|
${c3}/(((((${c5}@@#${c4}...
|
||||||
${c3}.((${c4}&,
|
${c3}.((${c4}&,
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{"match": "\"asahi2\"*|\"asahi-linux2\"*", "color": "3 6 1 1 7 8 6"}
|
||||||
|
${c1}_wwM ${c2}_ww
|
||||||
|
${c1}MMM${c2}MMMM
|
||||||
|
${c1}MM
|
||||||
|
${c3}_ww##############yy_
|
||||||
|
${c4}wMMMMM${c3}###########${c4}MMMMm
|
||||||
|
${c4},MMMMMMMMM${c3}######${c4}MMMMMMMM0_
|
||||||
|
${c4}wMMMMMMMMMMMMM${c5}MM${c6}0MMMMMMMMMMm
|
||||||
|
${c4},MMMMMMMMMMMMMMM${c5}MMMM${c6}0MMMMMMMMM0,
|
||||||
|
${c4}wMMMMMMMMMMMMMMMM${c5}MMMMM0${c6}MMMMMMMMMMb
|
||||||
|
${c4}_MMMMMMMMMMMMMMMMMM${c5}MMMMMMM0${c6}MMMMMMMMM0,
|
||||||
|
${c4}_MMMMMMMMMMMMMMMMMMM${c5}MMMM${c7}M${c5}MMMW${c6}MMMMMMMMMM_
|
||||||
|
${c4}_MMMMMMMMMMMMMMMMMMMM${c5}MMMM${c7}M0${c5}MMMW${c6}MMMMMMMMMM_
|
||||||
|
${c4}~MMMMMMMMMMMMMMMMM${c5}MMMM${c7}M${c5}MMMW${c6}MMMMM00~
|
||||||
|
${c4}~MMMMMMMMMMMMM${c5}MMMWMMM${c6}0MM${c5}MMM${c6}~
|
||||||
|
${c4}~MMMMMMMMMM${c5}MMMMM${c6}0MMM~~
|
||||||
|
${c4}~MMMMMM${c5}MMM${c6}0MM~
|
||||||
|
${c4}~MM${c5}M${c6}@~
|
||||||
|
${c4}M
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{"match": "\"aster\"*", "color": "6"}
|
||||||
|
...''...
|
||||||
|
.;oOXWMWNXXXNMMN0d:.
|
||||||
|
.oXMWOo;.. ..:oO;
|
||||||
|
;KMWx, co,
|
||||||
|
'KMNl dMMW.
|
||||||
|
oMMx xMMMMk
|
||||||
|
xMM: dMMMMMM;
|
||||||
|
cMMl dMMMMMMMW
|
||||||
|
NMK xMMMx::dXMx
|
||||||
|
,MMl xMMN' .o.
|
||||||
|
cMM; dMMW'
|
||||||
|
;MMc oMMW,
|
||||||
|
WMK dMMW, ccccccc.
|
||||||
|
lMMl oMMM; ooooooo.
|
||||||
|
OMMc ...
|
||||||
|
xMMx
|
||||||
|
;XMN:
|
||||||
|
,.
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AsteroidOS\"*", "color": "160 208 202 214"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
asteroidos = AsciiArt(match=r'''"AsteroidOS"*''', color='160 208 202 214', ascii=r"""
|
|
||||||
${c1} ***
|
${c1} ***
|
||||||
${c1} *****
|
${c1} *****
|
||||||
${c1} **********
|
${c1} **********
|
||||||
@@ -20,5 +16,3 @@ ${c4} #######%#######
|
|||||||
${c4} (#%%%%%%%#
|
${c4} (#%%%%%%%#
|
||||||
${c4} %%%%%
|
${c4} %%%%%
|
||||||
${c4} %%%
|
${c4} %%%
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"astOS\"*", "color": "8"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
astos = AsciiArt(match=r'''"astOS"*''', color='8', ascii=r"""
|
|
||||||
${c1} oQA#$%UMn
|
${c1} oQA#$%UMn
|
||||||
H 9
|
H 9
|
||||||
G #
|
G #
|
||||||
@@ -26,5 +22,3 @@ uURF$##Bv nKWB$%ABc aM@3R@D@b
|
|||||||
% & G U @ @
|
% & G U @ @
|
||||||
& @ # % % #
|
& @ # % % #
|
||||||
!HGN@MNCf t&$9#%HQr ?@G#6S@QP
|
!HGN@MNCf t&$9#%HQr ?@G#6S@QP
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{"match": "\"Astra\"*|\"Astra Linux\"*|\"astralinux\"*", "color": "1 7"}
|
||||||
|
AA
|
||||||
|
AaaA
|
||||||
|
Aa${c2}/\${c1}aA
|
||||||
|
${c1} Aa${c2}/${c1}aa${c2}\${c1}aA
|
||||||
|
${c1} Aa${c2}/${c1}aAAa${c2}\${c1}aA
|
||||||
|
${c1} aA${c2}/${c1}aaAAaa${c2}\${c1}Aa
|
||||||
|
${c1} aA${c2}/${c1}aaAAAAaa${c2}\${c1}Aa
|
||||||
|
${c1} aaaaaaAAAAa${c2}/${c1}aaAAAAAAaa${c2}\${c1}aAAAAaaaaa
|
||||||
|
${c1}aAAa${c2}-----${c1}aaaaaAAAAAAAAAAaaaaa${c2}-----${c1}aAAa
|
||||||
|
${c1} aAA${c2}\ ${c1}aAAAAAAAAAAAAAAAAAAAAAAa${c2} /${c1}AAa
|
||||||
|
${c1} aAa${c2}\${c1}aAAA${c2}\${c1}AAAA${c2}\${c1}AAAA${c2}\${c1}AAA${c2}\${c1}AAa${c2}/${c1}aAa
|
||||||
|
${c1} aAa${c2}\${c1}aA${c2}\${c1}AAA${c2}\${c1}AAA${c2}\${c1}AA${c2}\/${c1}aAa
|
||||||
|
${c1} aAA${c2}\${c1}aA${c2}\${c1}AAA${c2}\${c1}AAA${c2}\${c1}Aa${c2}/${c1}AAa
|
||||||
|
${c1} aA${c2}\${c1}aA${c2}\${c1}AAA${c2}\${c1}AAA${c2}\/${c1}Aa
|
||||||
|
${c1} aA${c2}/${c1}AA${c2}\\${c1}AA${c2}\\${c1}AA${c2}\\${c1}Aa
|
||||||
|
${c1} aA${c2}/\${c1}AAa${c2}\\${c1}Aa${c2}\\${c1}Aa${c2}\\${c1}Aa
|
||||||
|
${c1} aA${c2}/\${c1}AAa${c2}\/\${c1}a${c2}\\${c1}Aa${c2}\${c1}Aa
|
||||||
|
${c1} aA${c2}/${c1}a${c2}\\${c1}Aa${c2}\/${c1}AA${c2}\\\${c1}Aa${c2}\${c1}Aa
|
||||||
|
${c1} aA${c2}/${c1}aA${c2}\/${c1}aAa aAa${c2}\\${c1}Aa${c2}\${c1}Aa
|
||||||
|
${c1} aA${c2}/\${c1}A${c2}\/${c1}Aa aA${c2}\${c1}A${c2}\${c1}Aa
|
||||||
|
${c1} A${c2}|/${c1}aaAa aAaa${c2}\|${c1}A
|
||||||
|
${c1} aAaa aaAa
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Astra Linux\"*", "color": "160 231", "foreground": [2]}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
astra_linux = AsciiArt(match=r'''"Astra Linux"*''', color='160 231', ascii=r"""
|
|
||||||
${c1} AA
|
${c1} AA
|
||||||
${c1} AaaA
|
${c1} AaaA
|
||||||
${c1} Aa${c2}/\${c1}aA
|
${c1} Aa${c2}/\${c1}aA
|
||||||
@@ -25,5 +21,3 @@ ${c1} aA${c2}/${c1}aA${c2}\\/${c1}aAa aAa${c2}\\\${c1}Aa${c2}\${c1}Aa
|
|||||||
${c1} aA${c2}/\${c1}A${c2}\/${c1}Aa aA${c2}\\${c1}A${c2}\\${c1}Aa
|
${c1} aA${c2}/\${c1}A${c2}\/${c1}Aa aA${c2}\\${c1}A${c2}\\${c1}Aa
|
||||||
${c1} A${c2}|/${c1}aaAa aAaa${c2}\|${c1}A
|
${c1} A${c2}|/${c1}aaAa aAaa${c2}\|${c1}A
|
||||||
${c1} aAaa aaAa
|
${c1} aAaa aaAa
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Ataraxia Linux\"*|\"Ataraxia\"*", "color": "4 5"}
|
||||||
|
'l:
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
januslinux = AsciiArt(match=r'''"januslinux"*|"janus"*|"Ataraxia Linux"*|"Ataraxia"*''', color='4 5 6 2', ascii=r"""
|
|
||||||
${c1} 'l:
|
|
||||||
loooooo
|
loooooo
|
||||||
loooo coooool
|
loooo coooool
|
||||||
looooooooooooooooooool
|
looooooooooooooooooool
|
||||||
@@ -27,5 +23,3 @@ ${c1} cooo: ${c2}coooooooooooooooooool
|
|||||||
:oooool, coool:, looool:,
|
:oooool, coool:, looool:,
|
||||||
looool: ooooooooooooooo:
|
looool: ooooooooooooooo:
|
||||||
cooolc .ooooooooooool
|
cooolc .ooooooooooool
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{"match": "\"Athena\"*", "color": "7 3"}
|
||||||
|
${c1} . ..
|
||||||
|
${c1} :####: ####.
|
||||||
|
${c1} .################
|
||||||
|
${c1} :##################
|
||||||
|
${c1}.###################.
|
||||||
|
${c1}######## #######
|
||||||
|
${c1}####### ${c2}####${c1} #####
|
||||||
|
${c1}:#######. ####
|
||||||
|
${c1} ######### ${c2}#${c1} ## #
|
||||||
|
${c1} ####### ${c2}##${c1} ####
|
||||||
|
${c1}######## ${c2}####${c1} #######
|
||||||
|
${c1}######## ${c2}#####${c1} ########
|
||||||
|
${c1}######## ${c2}#######${c1} #######
|
||||||
|
${c1} ####### ${c2}########${c1} #######
|
||||||
|
${c1} ######## ${c2}#########${c1} ######
|
||||||
|
${c1} ######## ${c2}#########${c1} #####
|
||||||
|
${c1} ####### ${c2}#########${c1} ####
|
||||||
|
${c1} ####### ${c2}#########${c1} ##
|
||||||
|
${c1} ####### ${c2}########${c1} ##
|
||||||
|
${c1} ###### ${c2}########${c1} #
|
||||||
|
${c1} ### ${c2}#######${c1}
|
||||||
|
${c1} ${c2}######${c1}
|
||||||
|
${c1} ${c2}####${c1}
|
||||||
|
${c1} ${c2}##${c1}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{"match": "\"AthenaOS\"*", "color": "4 4"}
|
||||||
|
u.
|
||||||
|
..:Y
|
||||||
|
.Y..1
|
||||||
|
..::i::.. .br7S.
|
||||||
|
.::::...::::. 5dDr:
|
||||||
|
..:::.. .:i::.. Y7:
|
||||||
|
..:::::.. ..::::.
|
||||||
|
...:i:i:i:.. ${c2}... ${c1}:.:..:i:::...
|
||||||
|
::i:. ${c2}.USL Yr ${c1}..i::.
|
||||||
|
.:::. ${c2}:K :u. ${c1}.::.
|
||||||
|
:... ${c2}jB. .:vUi: 77 KB: ${c1}..::
|
||||||
|
...: ${c2}iBR vP::5X5PgSKXvLjS. iBB ${c1}.::.
|
||||||
|
:i:: ${c2}BBQr jgDIuj1UuJjXbbi 2BBP ${c1}:::;
|
||||||
|
'i:: ${c2}sQBg: i2S55121XSSU. YBQZ: ${c1}.:::
|
||||||
|
r::: ${c2}r:JgBMu. Q :BqEqZEB: Q :qBBK7i: ${c1}:i:i
|
||||||
|
.rir. ${c2}IBqPDgQBDr P rB :q 1QBRgEqgB ${c1}.::i.
|
||||||
|
:i:i ${c2}:JsXPDDRQQPBL P qQXBQRDDPIYY ${c1}rir:
|
||||||
|
:iii ${c2}5qvLUDDMgMgBB5 :DBQZRgMDdJ7Ygi ${c1}iir:
|
||||||
|
iri: ${c2}MBRgdZZggQgRBMIBQQRRggdZdMBBr ${c1}riri
|
||||||
|
irii ${c2}IBQgdZbDDRRRgQgQQMZDdZdgBB. ${c1}iiri
|
||||||
|
i7rr ${c2}.BBQZZbEEMQQDBQMEZdDDBBP ${c1}.rir:
|
||||||
|
:7ir. ${c2}7BBQMDMQSbB5ZBggQBBQ. ${c1}ivr7.
|
||||||
|
:r7r. ${c2}7BBBB:rBbQ.1BBBM. ${c1}:r7vi
|
||||||
|
::rLrr. ${c2}.b:rBQ7QB uU. ${c1}:7vLi.
|
||||||
|
.BB .iLYv: ${c1}idL B1 ${c1}:r77r.
|
||||||
|
LBB :vrvvr rvu7r:
|
||||||
|
ZB. ':7v177Lsvurr:'
|
||||||
|
.d2 ''::r:''
|
||||||
|
:'
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"AthenaOS_old\"*", "color": "7 3"}
|
||||||
|
. ..
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
athena = AsciiArt(match=r'''"Athena"*''', color='7 3', ascii=r"""
|
|
||||||
${c1} . ..
|
|
||||||
${c1} :####: ####.
|
${c1} :####: ####.
|
||||||
${c1} .################
|
${c1} .################
|
||||||
${c1} :##################
|
${c1} :##################
|
||||||
@@ -27,5 +23,3 @@ ${c1} ### ${c2}#######${c1}
|
|||||||
${c1} ${c2}######${c1}
|
${c1} ${c2}######${c1}
|
||||||
${c1} ${c2}####${c1}
|
${c1} ${c2}####${c1}
|
||||||
${c1} ${c2}##${c1}
|
${c1} ${c2}##${c1}
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{"match": "\"Aurora\"*", "color": "4 5 1 7"}
|
||||||
|
+++++++++
|
||||||
|
+++++${c4}+${c1}++++++${c4}+${c1}++
|
||||||
|
++++++${c4}+${c1}+++ +++++++++++
|
||||||
|
+++++++++++ ${c2}+${c1} +++++${c4}+${c1}+++++
|
||||||
|
++++++${c4}+${c1}++++ ${c4}+++${c1} +++++++++++
|
||||||
|
++++++++++${c4} + +++++ ++ ${c2}+++++${c4}+${c2}++++
|
||||||
|
+++${c4}+${c1}++++${c4} + + + +++++++ + + ${c2}+++++${c4}+${c2}++
|
||||||
|
++++++${c4} ${c2}+${c4} +++ +++++++++ +++ ${c2}++++++++
|
||||||
|
+++${c4}+${c1}++${c4} + +++++ +++++ +
|
||||||
|
++++++${c4} ${c2}+${c4} +++++ +++++ +++++
|
||||||
|
++${c4}+${c2}+++${c4} + +++++ ++++++ ++++++++++
|
||||||
|
++++++${c4} +++++ +++++ + +++++++++++++++++++
|
||||||
|
++++++${c4} + +++++ + +++++++++++++++
|
||||||
|
+++${c4}++${c2}+${c4} ++++++ +++++++++++++
|
||||||
|
++++++${c4} + ++++++ +++++++++++++ ${c2}+++ ${c4}++
|
||||||
|
++++++${c4} ++++++++++++++++ ${c2}++${c4}+${c2}+ ${c4}++ ${c1}+
|
||||||
|
++++++${c4} ++++++++++++++ ${c3}+ ${c2}++++
|
||||||
|
++++++${c4} +++++++++++ + ${c4}+ ${c3}++++++
|
||||||
|
++${c4}+${c3}+++${c4} ++++++++++ +++ ${c3}+++++++++++++
|
||||||
|
+++++ ${c4}+++++++++ + ${c3}+++++++++++++
|
||||||
|
+++ ${c4}++++++++ ${c2}++${c4} + ${c3}++++++++++++++ ++++
|
||||||
|
++ ${c4}++++++++ ${c3}+ ++++++++++++++ +++++++
|
||||||
|
${c4}++++++ ${c2}+ ${c3}+++++++++++++ +++++++${c2}++
|
||||||
|
${c4}++++ ${c3}+++++++++++++ ++++++${c2}+++
|
||||||
|
+++++++++++ ++++++${c2}+++
|
||||||
|
+++++ ++++++${c2}+++
|
||||||
|
++++++${c2}++
|
||||||
|
+++++
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{"match": "\"AxOS\"*", "color": "38;2;222;6;255 38;2;222;6;255"}
|
||||||
|
▂🬭⎻⎻🬭▂
|
||||||
|
▁▂━▂🬭🬭🭗 🬁🬭🬭▂▁━▂▁
|
||||||
|
🬂🬂🮂━🮂▔ ▔🮂━🮂🬂🬂🬿
|
||||||
|
🭄🬨▍ 🬜🮂▔ ▁▂▂🬭🬭▂▂▁ ▔🮂🬪 🮈🬕
|
||||||
|
🭄🭙▐▎ 🭃██████████🭎 🭢🮇▌🭤
|
||||||
|
🭄🭙 ▐🭄🭙 🭋█████🭜█████🭀 🭤🭏▌ 🭤🭏
|
||||||
|
🭗 🮉🭛 🭃███🭝🭙 🭥🭒███🭎 🭦▋ 🭢
|
||||||
|
▟🬮━🭷🭘 🭋████▄▂ ▂▄████🭀 🭣━🬯🭏
|
||||||
|
🭕╾🭺🬽 🭃██🭡 🭖██🭐 🭈╼🬡🭠
|
||||||
|
🬼 🮉🭀 🭋███΄ 🭤███🭀 🭋▊ 🭇
|
||||||
|
🬾 ▐🬾▁▁ 🭃██ ██🭐 ▁▁🭉🭫▌ 🭉🭠
|
||||||
|
🬾🮈▎ ▔🮂🬂▀🬎🬎 🮅🬎▀🬂🮂▔ 🮇▌🭉
|
||||||
|
🭿▍ ▂▁ ▁▂🬜΄🮈🬲
|
||||||
|
🭥🬭🬭▂▁━▂▁ ▁▂━▂🬭🬭🭚
|
||||||
|
▔⎺━▔🮂🬂🬂🬼 🭇🬂🬂🮂▔━⎺▔
|
||||||
|
⠈🮂🭷╾🭄╼🬂🮂΄
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"azos\"*", "color": "6 1"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
azos = AsciiArt(match=r'''"azos"*''', color='6 1', ascii=r"""
|
|
||||||
${c1} ////. ${c2} (((((
|
${c1} ////. ${c2} (((((
|
||||||
${c1} //////// ${c2} @((((((((
|
${c1} //////// ${c2} @((((((((
|
||||||
${c1} //////// ${c2} @((((((((
|
${c1} //////// ${c2} @((((((((
|
||||||
@@ -20,5 +16,3 @@ ${c1} //////// ////// ${c2} @(((( @((((((((
|
|||||||
${c1} //////// ${c2} @((((((((
|
${c1} //////// ${c2} @((((((((
|
||||||
${c1} //////// ${c2} @((((((((
|
${c1} //////// ${c2} @((((((((
|
||||||
${c1} ///// ${c2} (((((
|
${c1} ///// ${c2} (((((
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Bazzite\"*", "color": "5 5"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
bazzite = AsciiArt(match=r'''"Bazzite"*''', color='5 5', ascii=r"""
|
|
||||||
${c1} %%%%%%====%%%%%%%%%%
|
${c1} %%%%%%====%%%%%%%%%%
|
||||||
%%%%%%%% %%%%%%%%%%%%%%
|
%%%%%%%% %%%%%%%%%%%%%%
|
||||||
%%%%%%%%% %%%%%%%%%%%%%%%%
|
%%%%%%%%% %%%%%%%%%%%%%%%%
|
||||||
@@ -22,5 +18,3 @@ ${c1} %%%%%%====%%%%%%%%%%
|
|||||||
#######################
|
#######################
|
||||||
###################
|
###################
|
||||||
###########
|
###########
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
# This file is automatically generated. Please do not modify.
|
{"match": "\"Bedrock\"*", "color": "8 7"}
|
||||||
|
|
||||||
from . import AsciiArt
|
|
||||||
|
|
||||||
bedrock = AsciiArt(match=r'''"Bedrock"*''', color='8 7', ascii=r"""
|
|
||||||
${c1}--------------------------------------
|
${c1}--------------------------------------
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
@@ -20,5 +16,3 @@ ${c1}--------------------------------------
|
|||||||
--------------------------------------
|
--------------------------------------
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
""")
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{"match": "\"bedrock_small\"*", "color": "8 7"}
|
||||||
|
_________
|
||||||
|
| ${c2}__ ${c1} |
|
||||||
|
| ${c2}\ \___ ${c1} |
|
||||||
|
| ${c2} \ _ \${c1} |
|
||||||
|
| ${c2} \___/${c1} |
|
||||||
|
|_________|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user