Compare commits

...

69 commits

Author SHA1 Message Date
05e1bd48e0 errors now write to stderr instead of stdout 2024-07-12 10:49:46 -04:00
6a9bbe664a updated README 2024-07-06 21:18:15 -04:00
b1c32ff6f0 removed unused imports 2024-07-06 21:14:41 -04:00
d7fb635a74 updated sbom 2024-07-05 16:17:46 -04:00
d4cee3ed10 added 'wlw' alias to lesbian flag 2024-07-05 16:15:14 -04:00
1e8c7b2a1c added horizontal bound to progress flag 2024-07-05 14:08:52 -04:00
6f320b65fb fixed progress flag misbehaving at certain sizes 2024-07-05 14:07:36 -04:00
0c1c1148c2 made size flag change non-breaking and adjusted version 2024-07-05 10:40:24 -04:00
7cecac36ee fixed flags not matching and removed hard terminal requirement 2024-07-05 10:31:42 -04:00
fc326344f2 updated help text 2024-07-05 10:19:02 -04:00
c871781cc9 added new arbirtrary '--size' flag; removed '--small' flag 2024-07-05 10:17:31 -04:00
a4027ee475 created manual 2024-07-04 12:23:11 -04:00
0347462359 updated termion 2024-03-14 17:15:30 -04:00
3b1a6e6a36 updated Cargo.toml 2024-03-14 17:11:24 -04:00
9f225c540c added files for auditing tools 2024-03-14 17:10:38 -04:00
9f82e65a8a consistency changes to README 2024-02-22 14:12:17 -05:00
33fc042fb6 organized README 2024-02-22 14:11:26 -05:00
7942f7b035 updated gitignore 2024-02-15 20:52:22 -05:00
b7b6bd23b9 set binary name for crates.io package 2024-02-13 17:02:52 -05:00
5ee70eec05 added cargo install instructions 2024-02-11 20:08:04 -05:00
11ca93834d added neutrois pride flag 2024-02-11 19:41:01 -05:00
fd2009d1fd changed release profile 2024-02-04 18:30:27 -05:00
19c1eb1c39 updated README with installation section 2024-02-04 18:14:31 -05:00
577e39d3b2 fixed multisexual flag colors and multi/polysexual not appearing in list 2024-02-04 17:25:05 -05:00
5602bf5841 added more package information and license file 2024-02-04 16:48:03 -05:00
f2cddde6be error output is now descriptive for invalid names 2024-01-16 15:42:27 -05:00
3b13b1f470 corrected variant behavior for lesbian flag 2023-12-07 11:15:11 -05:00
d9f0dd92b7 version bump and added '-v' as a version flag 2023-12-07 11:10:46 -05:00
797a22324b added more useful messaging for flags without extended help text 2023-12-07 11:09:52 -05:00
98095c1e6b added documentation to help module 2023-12-07 11:03:17 -05:00
7f9a8aad97 merge changes from main 2023-12-06 11:14:15 -05:00
ab4b459004 added documentation for several files 2023-12-06 11:10:26 -05:00
f300979b3a version bump and formatting 2023-12-06 11:00:44 -05:00
a792b057cc added demigender, demiboy, and demigirl flags 2023-12-06 10:59:01 -05:00
7df02965aa added multisexual, polysexual flags; fixed polyamory flag scaling 2023-09-27 18:08:01 -04:00
d18b918b44 fixed aroace flag help text notes 2023-09-03 16:07:21 -04:00
552b2e40a9 added uncommitted change 2023-09-03 16:05:56 -04:00
f94bbcb042 merged in changes from main 2023-09-03 16:04:47 -04:00
992b07edcc minor structure changes and added a variant of the aroace flag 2023-09-03 15:58:48 -04:00
af86aada24 fixed a typo in help match arms 2023-08-18 09:50:42 -04:00
515f6da05c version bump 2023-08-14 11:51:29 -04:00
02d06b68ef added terminal check 2023-08-14 11:51:13 -04:00
2617c19227 partial implementation for polyamory flag; blank cutin and stripes 2023-07-16 13:46:55 -04:00
18b7b7424a updated README 2023-07-16 13:45:13 -04:00
930e26a037 fixed a typo 2023-07-10 14:33:04 -04:00
9c03142153 list now shows one name for each flag 2023-07-10 14:20:34 -04:00
031bd39e16 added help text for all flags with multiple names 2023-07-10 14:18:32 -04:00
f769a65a6d merged in complex renderers from main and 2023-07-10 13:44:14 -04:00
b303f3197a fixed progress not being a top-level flag 2023-07-10 13:36:07 -04:00
d6370da9e2 merged in flags and features from main 2023-07-10 13:03:25 -04:00
b238dbeecb finished progress flag 2023-07-10 12:39:40 -04:00
b318c96734 moved Flag enum to flag module, added first iteration of aroace flag 2023-07-07 13:36:17 -04:00
b0678542ef introduced Flag enum to unify main control flow; no more exits in complex renderers 2023-07-07 12:36:31 -04:00
d18db743ee fixed trans flag help formatting and added 7-color lesbian variant 2023-07-04 13:18:03 -04:00
2802f6dd42 groundwork for progress flag 2023-07-03 23:07:37 -04:00
bd00a2813f demiromantic and demisexual flags now have proper, scalable rendering 2023-07-03 17:43:54 -04:00
f7afc30f2e added to README 2023-07-03 13:11:58 -04:00
07ee54024d shifted complex rendering architecture, created by-line draw method 2023-07-03 13:11:45 -04:00
1332a306bc updated README 2023-07-03 11:14:44 -04:00
4749f1a0aa moved user help functions to a new module, added flag help for rainbow and trans flags 2023-07-02 11:28:05 -04:00
6488a40905 added gnc flag 2023-07-02 11:02:49 -04:00
47d63cd7f5 added more documentation 2023-06-26 11:34:07 -04:00
2748d7e273 added 'rainbow' name for rainbow pride flag 2023-06-26 11:17:21 -04:00
dd7adca3d0 version bump 2023-06-26 11:08:11 -04:00
b60ad4bb72 added mlm pride flag, made null subcommand display rainbow pride flag 2023-06-26 11:07:34 -04:00
3b7bc08ff0 added libraries section to README 2023-06-23 14:19:18 -04:00
f8e02e06fb groundwork for complex flags 2023-06-22 20:20:45 -04:00
766b07c1f4 corrected 8-color flag colors 2023-06-22 11:25:16 -04:00
314cc28fa3 version bump & README repairs 2023-06-22 10:46:29 -04:00
17 changed files with 1458 additions and 151 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
Cargo.lock
/target
/packages

View file

@ -1,13 +1,26 @@
[package]
name = "pride"
version = "0.1.2"
version = "0.4.1"
edition = "2021"
authors = [ "Valerie Wolfe <sleeplessval@gmail.com>" ]
description = "Pride flags in the terminal."
homepage = "https://git.vwolfe.io/valerie/pride"
repository = "https://git.vwolfe.io/valerie/pride"
license = "MIT"
categories = [ "command-line-utilities" ]
keywords = [ "lgbt", "pride", "cli" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[package.metadata.aur]
name = "pride"
source = "archive/v$pkgver.tar.gz"
[[bin]]
name = "pride"
path = "src/main.rs"
[dependencies]
pico-args = "0.5.0"
termion = "2.0.1"
termion = "3.0.0"
[profile.release]
opt-level = 's'
@ -15,5 +28,5 @@ codegen-units = 1
debug = false
lto = true
panic = "abort"
strip = "debuginfo"
strip = "symbols"

19
LICENSE Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2024 Valerie Wolfe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -3,15 +3,58 @@
A Rust utility to display pride flags in the terminal.
**This project is under heavy construction! It is subject to major structural and
architectural changes. There are no issues with functionality, but I will continue
to make major changes and refactors until the main roadmap is complete.**
A list of currently implemented flags is available on the [project wiki](https://git.vwolfe.io/valerie/pride/wiki/Flags).
Currently supports a variety of stripe flags.
## Dependencies
## Variant Flag Branch
Some Complex renderers utilize [Powerline's](https://github.com/ryanoasis/powerline-extra-symbols)
slant symbols, and therefore require use of a Powerline font, such as [Fira Code](https://github.com/tonsky/FiraCode).
This branch adds flag variants. Currently, it adds two for the rainbow pride flag:
- Gilbert Baker/Sex and Magic: original 1978 eight-color rainbow flag
- Philadelphia: 2017 rainbow flag with black and brown stripes
## Installation
### Manual Install
<details>
<summary>Release Binary</summary>
Copy the compiled binary from the <a href="https://git.vwolfe.io/valerie/pride/releases/">releases page</a>
to a directory in <code>$PATH</code>, such as <code>/usr/bin/</code>.
</details>
<details>
<summary>Compile from Source</summary>
Compile using cargo with the command <code>cargo build --release</code> and
copy the file from <code>target/release/</code> to a directory in
<code>$PATH</code>, such as <code>/usr/bin/</code>.
</details>
<details>
<summary>makepkg (AUR)</summary>
Clone the <a href="https://aur.archlinux.org/pride.git">AUR Repository</a> and
run the command <code>makepkg --install</code>.
</details>
### Package Managers
<details>
<summary>Arch Linux (AUR): <code>pride</code></summary>
Install the package from the <a href="https://aur.archlinux.org/packages/pride"><code>pride</code> AUR Package</a>
using an AUR package manager such as <a href="https://github.com/Morganamilo/paru"><code>paru</code></a>.
</details>
<details>
<summary>Cargo: <code>pride-term</code></summary>
Install the package using Cargo with the command <code>cargo install pride-term</code>.
</details>
### Man Page
<details>
<summary>Section 6</summary>
Copy <code>man/pride.6</code> into <code>/usr/share/man/man6/</code>.
</details>
## Libraries
- [pico-args](https://crates.io/crates/pico-args) — argument parsing
- [termion](https://crates.io/crates/termion) — ANSI formatting

4
deny.toml Normal file
View file

@ -0,0 +1,4 @@
[licenses]
allow = [ "MIT" ]

106
man/pride.6 Normal file
View file

@ -0,0 +1,106 @@
.Dd $Mdocdate$
.Dt PRIDE 6
.Os
.Sh NAME
.Nm pride
.Nd shows pride flags in the terminal
.Sh SYNOPSIS
.Nm
.Op Fl hlv
.Op Fl s Op Ar size
.Op Ar flag
.Sh DESCRIPTION
.Nm
displays pride flags in the terminal using ANSI truecolor sequences.
.Ss OPTIONS
.Bl -tag -width Ds
.It Fl h , Fl -help
Shows a brief help text.
.It Fl l , Fl -list
Shows a list of available pride flags.
.It Fl s , Fl -size Op Ar size
Scales the flag to the given size: no value or 'small' will produce the minimum size; one number sets the width; and two numbers separated by 'x' sets width and height respectively.
.It Fl v , Fl -version
Shows version information.
.It Ar flag
The name of the flag to display. Defaults to 'rainbow'.
.El
.Sh FLAGS
.Bl -tag -width Ds
.It Ic agender
.It Ic aromantic, aro
.It Ic aroace, aromantic-asexual
The aromantic-asexual pride flag by @aroaesflags@tumblr.com.
.Pp
VARIANTS
.Bl -tag -width Ds -compact
.It Ic halves, side-by-side, sbs
.El
.It Ic bigender
.It Ic bisexual, bi
The bisexual pride flag designed by Michael Page in 1998.
.It Ic demiboy
.It Ic demigender
.It Ic demigirl
.It Ic demiromantic
.It Ic demisexual
.It Ic gay, mlm
The gay men pride flag designed by @gayflagblog@tumblr.com in 2019.
.It Ic genderfluid
.It Ic gender-nonconforming, gendernonconforming, gnc
.It Ic genderqueer
.It Ic gendervoid
.It Ic lesbian, wlw
The 5-stripe lesbian pride flag designed by Emily Gwen in 2018.
.Pp
VARIANTS
.Bl -tag -width Ds -compact
.It Ic 7-color
The 7-stripe lesbian pride flag designed by Emily Gwen in 2018.
.El
.It Ic multisexual, m-spec, mspec
.It Ic multigender
.It Ic neutrois
.It Ic nonbinary, nb
The nonbinary pride flag designed by Kyle Rowan in 2014.
.It Ic pansexual, pan
The pansexual pride flag designed by Jasper V circa 2010.
.It Ic polysexual
.It Ic progress
The progress rainbow pride flag designed by Daniel Quasar in 2018.
.It Ic rainbow, pride
The 1979 6-stripe revision of Gilbert Baker's rainbow pride flag.
.Pp
VARIANTS
.Bl -tag -width Ds -compact
.It Ic 8-color, gilbert-baker, sex-and-magic
Gilbert Baker's original 8-stripe rainbow pride flag from 1978.
.It Ic philadelphia
The rainbow flag designed for 2017 Philadelphia Pride.
.It Ic progress
.El
.It Ic transgender, trans
The transgender pride flag designed by Monica Helms in 1999.
.El
.Sh EXIT STATUS
.Bl -tag -width Ds
.It 1
Unmatched
.Ar flag
name.
.It 2
Failed to parse
.Ar size .
.It 3
The provided
.Ar size
is too small to render.
.El
.Sh EXAMPLES
Create a full-width banner flag using tput:
.Pp
.Dl $ pride -s `tput cols`
.Pp
.Sh AUTHORS
.An -nosplit
.An Valerie Wolfe Aq Mt sleeplessval@gmail.com

239
sbom.xml Normal file
View file

@ -0,0 +1,239 @@
{
"SPDXID": "SPDXRef-DOCUMENT",
"creationInfo": {
"created": "2024-07-05T20:16:51.403Z",
"creators": [
"Tool: cargo-sbom-v0.8.4"
]
},
"dataLicense": "CC0-1.0",
"documentNamespace": "https://spdx.org/spdxdocs/pride-6150510e-b518-43f0-aa53-3e2795909cc2",
"files": [
{
"SPDXID": "SPDXRef-File-pride",
"checksums": [],
"fileName": "pride",
"fileTypes": [
"BINARY"
]
}
],
"name": "pride",
"packages": [
{
"SPDXID": "SPDXRef-Package-redox_syscall-0.4.1",
"description": "A Rust library to access raw Redox system calls",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/redox_syscall@0.4.1",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "redox_syscall",
"versionInfo": "0.4.1"
},
{
"SPDXID": "SPDXRef-Package-libredox-0.0.2",
"description": "Redox stable ABI",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/libredox@0.0.2",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "libredox",
"versionInfo": "0.0.2"
},
{
"SPDXID": "SPDXRef-Package-libc-0.2.155",
"description": "Raw FFI bindings to platform libraries like libc.\n",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/libc@0.2.155",
"referenceType": "purl"
}
],
"homepage": "https://github.com/rust-lang/libc",
"licenseConcluded": "MIT OR Apache-2.0",
"licenseDeclared": "MIT OR Apache-2.0",
"name": "libc",
"versionInfo": "0.2.155"
},
{
"SPDXID": "SPDXRef-Package-bitflags-1.3.2",
"description": "A macro to generate structures which behave like bitflags.\n",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/bitflags@1.3.2",
"referenceType": "purl"
}
],
"homepage": "https://github.com/bitflags/bitflags",
"licenseConcluded": "MIT OR Apache-2.0",
"licenseDeclared": "MIT/Apache-2.0",
"name": "bitflags",
"versionInfo": "1.3.2"
},
{
"SPDXID": "SPDXRef-Package-redox_termios-0.1.3",
"description": "A Rust library to access Redox termios functions",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/redox_termios@0.1.3",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "redox_termios",
"versionInfo": "0.1.3"
},
{
"SPDXID": "SPDXRef-Package-numtoa-0.1.0",
"description": "Convert numbers into stack-allocated byte arrays",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/numtoa@0.1.0",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT OR Apache-2.0",
"licenseDeclared": "MIT OR Apache-2.0",
"name": "numtoa",
"versionInfo": "0.1.0"
},
{
"SPDXID": "SPDXRef-Package-termion-3.0.0",
"description": "A bindless library for manipulating terminals.",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/termion@3.0.0",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "termion",
"versionInfo": "3.0.0"
},
{
"SPDXID": "SPDXRef-Package-bitflags-2.5.0",
"description": "A macro to generate structures which behave like bitflags.\n",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/bitflags@2.5.0",
"referenceType": "purl"
}
],
"homepage": "https://github.com/bitflags/bitflags",
"licenseConcluded": "MIT OR Apache-2.0",
"licenseDeclared": "MIT OR Apache-2.0",
"name": "bitflags",
"versionInfo": "2.5.0"
},
{
"SPDXID": "SPDXRef-Package-pride-0.4.1",
"description": "Pride flags in the terminal.",
"downloadLocation": "NONE",
"homepage": "https://git.vwolfe.io/valerie/pride",
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "pride",
"versionInfo": "0.4.1"
},
{
"SPDXID": "SPDXRef-Package-pico-args-0.5.0",
"description": "An ultra simple CLI arguments parser.",
"downloadLocation": "registry+https://github.com/rust-lang/crates.io-index",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:cargo/pico-args@0.5.0",
"referenceType": "purl"
}
],
"licenseConcluded": "MIT",
"licenseDeclared": "MIT",
"name": "pico-args",
"versionInfo": "0.5.0"
}
],
"relationships": [
{
"relatedSpdxElement": "SPDXRef-Package-numtoa-0.1.0",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-termion-3.0.0"
},
{
"relatedSpdxElement": "SPDXRef-Package-pico-args-0.5.0",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-pride-0.4.1"
},
{
"relatedSpdxElement": "SPDXRef-Package-libc-0.2.155",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-termion-3.0.0"
},
{
"relatedSpdxElement": "SPDXRef-Package-termion-3.0.0",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-pride-0.4.1"
},
{
"relatedSpdxElement": "SPDXRef-Package-bitflags-1.3.2",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-redox_syscall-0.4.1"
},
{
"relatedSpdxElement": "SPDXRef-Package-pride-0.4.1",
"relationshipType": "GENERATED_FROM",
"spdxElementId": "SPDXRef-File-pride"
},
{
"relatedSpdxElement": "SPDXRef-Package-libredox-0.0.2",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-termion-3.0.0"
},
{
"relatedSpdxElement": "SPDXRef-Package-redox_syscall-0.4.1",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-libredox-0.0.2"
},
{
"relatedSpdxElement": "SPDXRef-Package-redox_termios-0.1.3",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-termion-3.0.0"
},
{
"relatedSpdxElement": "SPDXRef-Package-libc-0.2.155",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-libredox-0.0.2"
},
{
"relatedSpdxElement": "SPDXRef-Package-bitflags-2.5.0",
"relationshipType": "DEPENDS_ON",
"spdxElementId": "SPDXRef-Package-libredox-0.0.2"
}
],
"spdxVersion": "SPDX-2.3"
}

View file

@ -1,5 +1,6 @@
//! utility types and functions for color operations
use termion::color::{ Fg, Rgb, Reset };
use termion::color::{ Bg, Fg, Rgb, Reset };
pub type Color = Fg<Rgb>;
pub type Colors = Vec<Fg<Rgb>>;
@ -8,10 +9,20 @@ pub static BLACK: Color = Fg(Rgb(0x00, 0x00, 0x00));
pub static WHITE: Color = Fg(Rgb(0xFF, 0xFF, 0xFF));
pub static RESET: Fg<Reset> = Fg(Reset);
pub static RESET_BG: Bg<Reset> = Bg(Reset);
/// produces a termion foreground color from the provided integer
pub fn rgb(hex: u32) -> Color {
// colors should be 0xrrggbb = 0x__rrggbb; drop the most significant byte
let [_, r, g, b] = hex.to_be_bytes();
Fg(Rgb(r, g, b))
}
/// produces a termion background color from the provided integer
pub fn bg(hex: u32) -> Bg<Rgb> {
let [_, r, g, b] = hex.to_be_bytes();
Bg(Rgb(r, g, b))
}

331
src/complex.rs Normal file
View file

@ -0,0 +1,331 @@
//! flags that require more complex rendering than just scaling colored stripes
use termion::color::{ Bg, Rgb };
use crate::{
color::*,
draw,
error,
flag::{ self, Flag },
state::State,
util::{ ansi_len, ansi_substr }
};
/// vertically stacking eighths
pub static V_EIGHTH: [char; 7] = ['▁', '▂', '▃', '▄', '▅', '▆', '▇'];
/// horizontally stacking eighths
pub static H_EIGHTH: [char; 7] = ['▏', '▎', '▍', '▌', '▋', '▊', '▉'];
/// shading by intensity
pub static SHADING: [char; 3] = ['░', '▒', '▓'];
/// 2/1 slope triangle cut in
pub static TRIANGLE_21: [char; 3] = ['', '🭬', ''];
/// 2/3 slope slant
pub static SLANT_23: [char; 2] = ['🭒', '🭏'];
pub fn progress(state: &State) -> Flag {
let red = bg(0xE50000);
let orange = bg(0xFF8D00);
let yellow = bg(0xFFEE00);
let green = bg(0x028121);
let blue = bg(0x004CFF);
let purple = bg(0x770088);
// we need these colors in both fg & bg; just hold the integers for now
let black: u32 = 0;
let brown: u32 = 0x784F17;
let ltblue: u32 = 0xEAACB8;
let pink: u32 = 0x7ACBF5;
let white: u32 = 0xFFFFFF;
let (width, height) = state.size.get(18, 6);
if height < 6 || width < 6 { error::too_small(width, height); }
// create color slices and line buffer
let stripes = [red, orange, yellow, green, blue, purple];
let chevrons = [white, ltblue, pink, brown, black];
let mut lines: Vec<String> = Vec::new();
// set up stripe index
let mut index = 0;
// set up constraints
let linecount = height - (height % 6); // largest multiple of 6 smaller than height
let full_depth = width / 3;
let chevron_width = if full_depth > 6 { (full_depth / 6) - 1 } else { 0 };
let direction_thresh = linecount / 2;
let corner = linecount % 2 == 1;
let thresh = linecount / 6; // stripe threshold; no bg_stripes call!
let mut line_no = 0; // absolute line number; n is relative
// chevron helper
let build_chevron = | separator: char | -> String {
let mut output = format!(
"{fg}{bg}{stripe}{separator}",
fg = rgb(chevrons[0]),
bg = bg(chevrons[1]),
stripe = draw::BLOCK.repeat( usize::max(chevron_width as usize * 2, 1) )
);
let stripe = draw::BLOCK.repeat(chevron_width as usize);
for i in 1..4 {
output += &format!(
"{fg}{bg}{stripe}{separator}",
fg = rgb(chevrons[i]),
bg = bg(chevrons[i + 1])
);
}
output += &format!(
"{fg}{stripe}",
fg = rgb(chevrons[4])
);
output
};
// piecewise functions: ascent -> peak -> descent
let mut base = build_chevron(TRIANGLE_21[0]);
let base_length = base.len();
let display_length = ansi_len(&base) + 1; // chevron width will always stay the same; add 1 for the last separator
for n in 0..direction_thresh {
// advance stripe color at stripe threshold by line number
if line_no != 0 && line_no % thresh == 0 { index += 1; }
// grab our substring constraints
let start = (direction_thresh - n) as usize - 1;
let diff = if display_length >= start { display_length - start } else { 0 };
// take substring of chevron line...
let mut line = ansi_substr(&base, start as usize, base_length);
line += &stripes[index].to_string();
if diff > 0 { line.push(TRIANGLE_21[0]); }
// ... and add the colored stripe
line += &" ".repeat(width as usize - diff);
lines.push(line);
line_no += 1;
}
if corner {
if line_no % thresh == 0 { index += 1; }
let base = build_chevron(TRIANGLE_21[1]);
let mut line = ansi_substr(&base, 0, base_length);
line += &format!(
"{stripe}{separator}{line}",
stripe = stripes[index],
separator = TRIANGLE_21[1],
line = " ".repeat(width as usize - display_length)
);
lines.push(line);
line_no += 1;
}
base = build_chevron(TRIANGLE_21[2]);
for n in 0..direction_thresh {
if line_no % thresh == 0 { index += 1; }
if index > 5 { break; }
let start = n as usize;
let diff = if display_length >= start { display_length - start } else { 0 };
let mut line = ansi_substr(&base, start, base_length);
line += &stripes[index].to_string();
if diff > 0 { line.push(TRIANGLE_21[2]); }
line += &" ".repeat(width as usize - diff);
lines.push(line);
line_no += 1;
}
Flag::Lines(lines)
}
// everything below this point is in alphabetical order
pub fn aroace_halves(state: &State) -> Flag {
// pull colors from aro & ace stripe flags
let Flag::Stripes(aro) = flag::aromantic() else { panic!() };
let Flag::Stripes(ace) = flag::asexual() else { panic!() };
let (width, height) = state.size.get(60, 20);
if height < 20 { error::too_small(width, height); }
let mut lines: Vec<String> = Vec::new();
// set up constraints
let linecount = height - (height % 20);
let aro_thresh = linecount / 5; // threshold for aromantic colors
let ace_thresh = linecount / 4; // threshold for asexual colors
let stripe = draw::BLOCK.repeat((width / 2) as usize);
let mut aro_index = 0;
let mut ace_index = 0;
for n in 0..linecount {
// switch colors on thresholds
if n != 0 {
if n % aro_thresh == 0 { aro_index += 1; }
if n % ace_thresh == 0 { ace_index += 1; }
}
let line = format!("{}{stripe}{}{stripe}", aro[aro_index], ace[ace_index]);
lines.push(line);
}
Flag::Lines(lines)
}
fn demi_orientation_render(middle: Bg<Rgb>, bottom: Bg<Rgb>, width: u16, height: u16) -> Vec<String> {
let white = bg(0xFFFFFF);
if height < 5 { error::too_small(width, height); }
let stripes = vec![white, white, middle, bottom, bottom];
// initial stripe output buffer
let mut lines: Vec<String> = draw::bg_stripes(stripes, width, height);
// assemble triangle cut-in
let linecount = lines.len();
let depth = linecount / 2;
let corner = linecount % 2 == 1;
// piecewise functions: ascending -> peak -> descending
for n in 0..depth {
let line = lines[n].clone();
let replacement = format!("{BLACK}{}{}", draw::BLOCK.repeat(n), TRIANGLE_21[0]);
lines[n] = line.replacen(&" ".repeat(n + 1), &replacement, 1);
}
if corner {
let line = lines[depth].clone();
let replacement = format!("{BLACK}{}{}", draw::BLOCK.repeat(depth), TRIANGLE_21[1]);
lines[depth] = line.replacen(&" ".repeat(depth + 1), &replacement, 1);
}
let start = depth + (linecount % 2);
for n in 0..depth {
let line = lines[start + n].clone();
let size = depth - n - 1;
let replacement = format!("{BLACK}{}{}", draw::BLOCK.repeat(size), TRIANGLE_21[2]);
lines[start + n] = line.replacen(&" ".repeat(size + 1), &replacement, 1);
}
lines
}
pub fn demiromantic(state: &State) -> Flag {
let green = bg(0x3DA542);
let gray = bg(0xD2D2D2);
let (width, height) = state.size.get(15, 5);
let lines = demi_orientation_render(green, gray, width, height);
Flag::Lines(lines)
}
pub fn demisexual(state: &State) -> Flag {
let purple = bg(0x832FA8);
let grey = bg(0x7B868C);
let (width, height) = state.size.get(15, 5);
let lines = demi_orientation_render(purple, grey, width, height);
Flag::Lines(lines)
}
pub fn disability() {
let gray = bg(0x575757);
let green: u32 = 0x3AAD7D;
let blue: u32 = 0x79BFE0;
let white: u32 = 0xE8E8E8;
let yellow: u32 = 0xEDDB76;
let red: u32 = 0xCD7281;
let stripes = [red, yellow, white, blue, green];
// 2/3 slant stripes with gray background
}
pub fn intersex() -> Flag {
let yellow = bg(0xFFDA00);
let purple = rgb(0x7A00AC);
let block = " ";
let stripe = block.repeat(9);
let part = block.repeat(4);
let lines = vec![
format!("{yellow}{stripe}"),
format!("{part}{purple}O{part}"),
format!("{stripe}")
];
Flag::Lines(lines)
}
pub fn polyamory(state: &State) -> Flag {
let blue = rgb(0x019FE3);
let magenta = rgb(0xE50051);
let purple = rgb(0x340C46);
let yellow = rgb(0xFCBF00);
let white = bg(0xFFFFFF);
// special characters
let semicircle = '\u{E0B6}';
let separators = ['\u{E0BE}', '\u{E0BA}'];
let (width, height) = state.size.get(18, 6);
if height < 6 { error::too_small(width, height); }
// create stripe array and line buffer
let stripes = [magenta, purple]; // only stripes 2 and 3 need tracked
let mut lines: Vec<String> = Vec::new();
// constraints
let linecount = height - (height % 3); // largest multiple of 3 smaller than height
let full_depth = linecount;
let thresh = linecount / 3; // stripe & direction thresh
let start = 2 * full_depth / 3;
// piecewise function: ascent -> descent
let mut separator = separators[0];
for n in 0..thresh {
let size = start + n;
let line = format!(
"{white}{yellow}{cutin}{blue}{separator}{stripe}",
cutin = " ".repeat(size as usize),
stripe = draw::BLOCK.repeat((width - (size + 1)) as usize)
);
lines.push(line);
}
// first piece goes until the end of stripes[0]
let mut index = 0; // stripe index
separator = separators[1];
for n in thresh..linecount {
// advance index at threshold
if n == (thresh * 2) { index = 1; }
let size = (2 * start) - n - 1;
let color = stripes[index];
let line = format!(
"{white}{yellow}{cutin}{color}{separator}{stripe}",
cutin = " ".repeat(size as usize),
stripe = draw::BLOCK.repeat((width - (size + 1)) as usize)
);
lines.push(line);
}
Flag::Lines(lines)
}

View file

@ -1,61 +1,131 @@
use std::io::{ self, Write };
//! render handling code
use std::io::{
self,
Write
};
use termion::{
terminal_size,
clear,
color::{ Bg, Fg, Rgb },
cursor,
input::TermRead,
raw::IntoRawMode
};
use crate::color::{ RESET, Colors };
use crate::flag::BLOCK;
use crate::{
color::{ RESET, RESET_BG },
error,
flag::Flag,
state::{ Size, State }
};
pub fn full(colors: Colors) {
pub static BLOCK: &str = "";
pub static UHALF: &str = "";
/// prints a provided vec of lines to stdout
pub fn draw_full(lines: Vec<String>) {
let mut stdout = io::stdout().into_raw_mode().unwrap();
let stdin = io::stdin();
let count = colors.len();
let (width, height) = terminal_size().unwrap();
let thresh = height as usize / count;
// get in position for draw
let count = lines.len() as u16;
for _ in 0..count { write!(stdout, "\n").ok(); }
write!(stdout, "{}", cursor::Up(count)).ok();
// clear screen and hide cursor
write!(stdout, "{}{}", cursor::Hide, clear::All).ok();
// write lines
let down = cursor::Down(1);
for line in lines {
let left = cursor::Left(line.len() as u16);
write!(stdout, "{line}{left}{down}").ok();
}
// clear formatting and flush buffer
write!(stdout, "{RESET}{RESET_BG}").ok();
stdout.flush().ok();
let stripe = BLOCK.repeat(width as usize);
// hold for input
let stdin = io::stdin();
for _ in stdin.keys() { break; }
// clear and show cursor
write!(stdout, "{}{}", clear::All, cursor::Show).ok();
stdout.flush().ok();
}
pub fn draw_lines(lines: Vec<String>, state: &State) {
match state.size {
Size::Full => draw_full(lines),
_ => for line in lines { println!("{line}{RESET}{RESET_BG}") }
}
}
/// generates lines for foreground colors provided as a vec of strings for the draw_lines method
pub fn fg_stripes(colors: Vec<Fg<Rgb>>, width: u16, height: u16) -> Vec<String> {
let width = width as usize;
let height = height as usize;
let count = colors.len();
let thresh = height / count;
let stripe = BLOCK.repeat(width);
let mut output = Vec::new();
// create our color index
let mut index = 0;
for n in 0..height {
if n != 0 && n % thresh == 0 {
index += 1;
// and break if out of bounds
if index >= count { break; }
}
let color = colors[index];
output.push(format!("{color}{stripe}"));
}
output
}
/// generates lines for background colors provided as a vec of strings for the draw_lines method
pub fn bg_stripes(colors: Vec<Bg<Rgb>>, width: u16, height: u16) -> Vec<String> {
let width = width as usize;
let height = height as usize;
let count = colors.len();
let thresh = height / count;
let stripe = " ".repeat(width);
let mut output = Vec::new();
let mut index = 0;
for n in 0..(height as usize) {
for n in 0..height {
if n != 0 && n % thresh == 0 {
index += 1;
if index >= count { break; }
}
write!(
stdout,
"{color}{stripe}{RESET}",
color = colors[index]
).ok();
let color = colors[index];
output.push(format!("{color}{stripe}"));
}
stdout.flush().ok();
for _ in stdin.keys() { break; }
write!(stdout, "{}{}", cursor::Show, clear::All).ok();
stdout.flush().ok();
output
}
pub fn small(colors: Colors) {
let mut stdout = io::stdout();
let count = colors.len();
let width = count * 3;
let stripe = BLOCK.repeat(width);
for color in colors {
println!("{color}{stripe}");
impl Flag {
/// renders a flag to stdout
pub fn draw(self, state: &State) {
let lines = match self {
Flag::Stripes(colors)
=> {
let count = colors.len() as u16;
let (width, height) = state.size.get(count * 3, count);
if height < count { error::too_small(width, height); }
fg_stripes(colors, width, height)
},
Flag::Lines(lines)
=> lines
};
draw_lines(lines, &state);
}
print!("{RESET}");
stdout.flush().ok();
}

24
src/error.rs Normal file
View file

@ -0,0 +1,24 @@
use std::process::exit;
pub fn unmatched_flag(target: String) {
eprintln!("pride: no flag {target}");
exit(1);
}
pub fn size_missing() {
eprintln!("pride: size flag requires a value");
exit(2);
}
pub fn size_error(value: &str) {
eprintln!("pride: size '{value}' is invalid");
exit(2);
}
pub fn too_small(width: u16, height: u16) {
eprintln!("pride: this flag must be bigger than {width}x{height}");
exit(3);
}

View file

@ -1,9 +1,15 @@
//! stripe pride flag color functions.
//! all of these return a Vec of colors to be drawn from first to last.
use crate::color::*;
pub static BLOCK: &str = "";
pub enum Flag {
Stripes(Colors),
Lines(Vec<String>)
}
pub fn pride() -> Colors {
pub fn pride() -> Flag {
let red = rgb(0xE50000);
let orange = rgb(0xFF8D00);
let yellow = rgb(0xFFEE00);
@ -11,108 +17,190 @@ pub fn pride() -> Colors {
let blue = rgb(0x004CFF);
let purple = rgb(0x770088);
vec![red, orange, yellow, green, blue, purple]
}
pub fn transgender() -> Colors {
let pink = rgb(0x7ACBF5);
let blue = rgb(0xEAACB8);
vec![pink, blue, WHITE, blue, pink]
Flag::Stripes(vec![red, orange, yellow, green, blue, purple])
}
// everything below here is alphabetical
pub fn agender() -> Colors {
pub fn agender() -> Flag {
let gray = rgb(0xB9B9B9);
let green = rgb(0xB8F483);
vec![BLACK, gray, WHITE, green, WHITE, gray, BLACK]
Flag::Stripes(vec![BLACK, gray, WHITE, green, WHITE, gray, BLACK])
}
pub fn aromantic() -> Colors {
pub fn aromantic() -> Flag {
let green = rgb(0x3BA740);
let lime = rgb(0xA8D47A);
let grey = rgb(0xABABAB);
vec![green, lime, WHITE, grey, BLACK]
Flag::Stripes(vec![green, lime, WHITE, grey, BLACK])
}
pub fn asexual() -> Colors {
pub fn asexual() -> Flag {
let grey = rgb(0xA4A4A4);
let purple = rgb(0x810081);
vec![BLACK, grey, WHITE, purple]
Flag::Stripes(vec![BLACK, grey, WHITE, purple])
}
pub fn bigender() -> Colors {
pub fn aroace() -> Flag {
let orange = rgb(0xE28D00);
let yellow = rgb(0xEBE200);
let blue = rgb(0x67B7E8);
let navy = rgb(0x203756);
Flag::Stripes(vec![orange, yellow, WHITE, blue, navy])
}
pub fn bigender() -> Flag {
let pink = rgb(0xE676A6);
let yellow = rgb(0xF9F04C);
let purple = rgb(0xAB6BBB);
let blue = rgb(0x6D96DC);
vec![pink, yellow, WHITE, purple, blue]
Flag::Stripes(vec![pink, yellow, WHITE, purple, blue])
}
pub fn bisexual() -> Colors {
pub fn bisexual() -> Flag {
let magenta = rgb(0xC42A6F);
let purple = rgb(0x915392);
let blue = rgb(0x1437A2);
vec![magenta, magenta, purple, blue, blue]
Flag::Stripes(vec![magenta, magenta, purple, blue, blue])
}
pub fn genderfluid() -> Colors {
fn demigender_base(color: Color) -> Colors {
let grey = rgb(0x7F7F7F);
let gray = rgb(0xC3C3C3);
vec![grey, gray, color, WHITE, color, gray, grey]
}
pub fn demiboy() -> Flag {
let blue = rgb(0x7ACBF5);
Flag::Stripes(demigender_base(blue))
}
pub fn demigender() -> Flag {
let yellow = rgb(0xFBFF74);
Flag::Stripes(demigender_base(yellow))
}
pub fn demigirl() -> Flag {
let pink = rgb(0xEAACB8);
Flag::Stripes(demigender_base(pink))
}
pub fn gay() -> Flag {
let green1 = rgb(0x00906D);
let green2 = rgb(0x00D1A7);
let green3 = rgb(0x7EEBC1);
let blue1 = rgb(0x6CAEE8);
let blue2 = rgb(0x5543D3);
let blue3 = rgb(0x461280);
Flag::Stripes(vec![green1, green2, green3, WHITE, blue1, blue2, blue3])
}
pub fn genderfluid() -> Flag {
let pink = rgb(0xFF75A2);
let violet = rgb(0xBE18D6);
let blue = rgb(0x333EBD);
vec![pink, WHITE, violet, BLACK, blue]
Flag::Stripes(vec![pink, WHITE, violet, BLACK, blue])
}
pub fn genderqueer() -> Colors {
pub fn gender_nonconforming() -> Flag {
let purple = rgb(0x50284D);
let magenta = rgb(0x96467B);
let blue = rgb(0x5C96F7);
Flag::Stripes(vec![purple, purple, magenta, blue, WHITE, blue, magenta, purple, purple])
}
pub fn genderqueer() -> Flag {
let purple = rgb(0xB899DF);
let green = rgb(0x6B8E3B);
vec![purple, WHITE, green]
Flag::Stripes(vec![purple, WHITE, green])
}
pub fn gendervoid() -> Colors {
pub fn gendervoid() -> Flag {
let navy = rgb(0x08114A);
let gray = rgb(0x4A484B);
vec![navy, gray, BLACK, gray, navy]
Flag::Stripes(vec![navy, gray, BLACK, gray, navy])
}
pub fn lesbian() -> Colors {
pub fn lesbian() -> Flag {
let red = rgb(0xD62800);
let orange = rgb(0xFF9B56);
let pink = rgb(0xD462A6);
let magenta = rgb(0xA40062);
vec![red, orange, WHITE, pink, magenta]
Flag::Stripes(vec![red, orange, WHITE, pink, magenta])
}
pub fn multigender() -> Colors {
pub fn multigender() -> Flag {
let blue = rgb(0x3F47CC);
let ltblue = rgb(0x01A4E9);
let orange = rgb(0xFB7F27);
vec![blue, ltblue, orange, ltblue, blue]
Flag::Stripes(vec![blue, ltblue, orange, ltblue, blue])
}
pub fn nonbinary() -> Colors {
pub fn multisexual() -> Flag {
let purple = rgb(0x724DC9);
let blue = rgb(0xA0EFFE);
let pink = rgb(0xFF3D9B);
Flag::Stripes(vec![purple, WHITE, blue, pink])
}
pub fn neutrois() -> Flag {
let green = rgb(0x2D9A1B);
Flag::Stripes(vec![WHITE, green, BLACK])
}
pub fn nonbinary() -> Flag {
let yellow = rgb(0xFFF433);
let purple = rgb(0x9B59D0);
vec![yellow, WHITE, purple, BLACK]
Flag::Stripes(vec![yellow, WHITE, purple, BLACK])
}
pub fn pansexual() -> Colors {
pub fn pansexual() -> Flag {
let magenta = rgb(0xFF1B8D);
let yellow = rgb(0xFFDA00);
let cyan = rgb(0x1BB3FF);
vec![magenta, yellow, cyan]
Flag::Stripes(vec![magenta, yellow, cyan])
}
pub fn polysexual() -> Flag {
let pink = rgb(0xF61CB9);
let green = rgb(0x07D569);
let blue = rgb(0x1C92F6);
Flag::Stripes(vec![pink, green, blue])
}
pub fn transgender() -> Flag {
let pink = rgb(0x7ACBF5);
let blue = rgb(0xEAACB8);
Flag::Stripes(vec![pink, blue, WHITE, blue, pink])
}

171
src/help.rs Normal file
View file

@ -0,0 +1,171 @@
//! help and list text
use std::process::exit;
use crate::VERSION;
/// displays the program's help text
pub fn help_text() {
println!("pride v{VERSION}
Valerie Wolfe <sleeplessval@gmail.com>
Display pride flags in the terminal.
usage: pride [flags] [name]
args:
<name> The pride flag to display
flags:
-h, --help Shows this help text
--version Show version information
-l, --list Prints a list of printable flags
-s, --size [size] Sets the size of the output flag.
Use 'pride --list' to see a list of printable flags
~ You're loved and you matter ");
}
/// shows a list of all flags
pub fn list_text() {
println!("pride v{VERSION}
flag list:
agender agender pride flag
aromantic aromantic pride flag
aroace aromantic-asexual pride flag
asexual asexual pride flag
bigender bigender pride flag
bisexual bisexual pride flag
demiboy demiboy pride flag
demigender demigender pride flag
demigirl demigirl pride flag
demiromantic demiromantic pride flag
demisexual demisexual pride flag
gay gay men pride flag
genderfluid genderfluid pride flag
gender-nonconforming gender nonconforming pride flag
genderqueer genderqueer pride flag
gendervoid gendervoid pride flag
lesbian lesbian pride flag
multigender multigender pride flag
multisexual multisexual pride flag
neutrois neutrois pride flag
nonbinary nonbinary pride flag
pansexual pansexual pride flag
polysexual polysexual pride flag
rainbow six-color rainbow flag
progress progress arrow rainbow flag
transgender transgender pride flag");
}
/// handle help details by flag
pub fn flag_help(flag: &str) {
match flag {
"pride" | "rainbow" | "-"
=> {
println!("The ubiquitous 1979 6-color rainbow pride flag, representing the larger queer community.
names:
'pride', 'rainbow', '-'
variants:
8-color Gilbert Baker's original 1978 flag with 8 stripes
gilbert-baker
sex-and-magic
philadelphia The 2017 Philadelphia Pride flag with black and brown stripes
progress The 2018 Progess rainbow pride flag designed by Daniel Quasar");
},
"progress"
=> { println!("Daniel Quasar's 2018 Progress rainbow pride flag.\n\nnames:\n 'progress'"); }
"transgender" | "trans"
=> {
println!("The transgender pride flag designed by Monica Helms in 1999.
names:
'transgender', 'trans'");
},
// alphabetical below this point
"aromantic" | "aro"
=> { println!("The aromantic pride flag.\n\nnames:\n 'aromantic', 'aro'"); }
"asexual" | "ace"
=> { println!("The asexual pride flag.\n\nnames:\n 'asexual', 'ace'"); }
"aroace" | "aromantic-asexual"
=> {
println!("The aromantic-asexual pride flag designed by aroaesflags on tumblr.
names:
'aroace', 'aromantic-asexual'
variants:
halves The side-by-side aromantic and asexual aroace flag
side-by-side
sbs
notes:
Side-by-side flag currently only displays in terminals 20 lines or taller.");
},
"bisexual" | "bi"
=> {
println!("The bisexual flag designed by Michael Page in 1998.
names:
'bisexual', 'bi'");
},
"gay" | "mlm"
=> {
println!("The 7-stripe gay men pride flag designed by @gayflagblog on tumblr in 2019.
names:
'gay', 'mlm'");
},
"gender-nonconforming" | "gendernonconforming" | "gnc"
=> { println!("The gender-nonconforming pride flag.\n\nnames:\n 'gender-nonconforming', 'gendernonconforming', 'gnc'"); },
"lesbian"
=> {
println!("The 5-stripe lesbian flag designed by Emily Gwen in 2018.
names:
'lesbian', 'wlw'
variants:
7-color 7-stripe flag, also designed in 2018 by Emily Gwen");
},
"nonbinary" | "nb"
=> {
println!("The nonbinary pride flag designed by Kyle Rowan in 2014.
names:
'nonbinary', 'nb'");
},
"pansexual" | "pan"
=> {
println!("The pansexual pride flag designed by Jasper V around 2010
names:
'pansexual', 'pan'");
},
_
=> {
println!("pride: no help found for {flag}!\n");
help_text();
exit(1);
}
}
}

View file

@ -1,58 +1,77 @@
use std::process::exit;
//! main method module
use pico_args::Arguments;
mod color;
mod complex;
mod draw;
mod error;
mod flag;
mod help;
mod state;
mod util;
mod variant;
use crate::color::Colors;
use crate::{
flag::Flag,
state::State
};
static VERSION: &str = env!("CARGO_PKG_VERSION");
pub const FLAG_HELP: [&str;2] = [ "-h", "--help" ];
pub const FLAG_LIST: [&str;2] = [ "-l", "--list" ];
pub const FLAG_SIZE: [&str;2] = [ "-s", "--size"];
pub const FLAG_VERSION: [&str;2] = [ "-v", "--version" ];
fn main() {
// collect args
let mut args = Arguments::from_env();
// handle help flag
if args.contains(["-h", "--help"]) {
help_text();
if args.contains(FLAG_HELP) {
let target = args.subcommand().unwrap();
if target.is_some() { help::flag_help(&target.unwrap()); }
else { help::help_text(); }
return;
}
// handle list flag
if args.contains(["-l", "--list"]) {
list_text();
if args.contains(FLAG_LIST) {
help::list_text();
return;
}
// handle version flag
if args.contains("--version") {
if args.contains(FLAG_VERSION) {
println!("pride v{VERSION}");
return;
}
// get small flag
let small = args.contains(["-s", "--small"]);
let state = State::new(&mut args);
let subcommand = args.subcommand().unwrap();
let variant = args.subcommand().unwrap();
let colors: Colors = match subcommand.as_deref() {
Some("pride" | "gay")
// get color vec from matched flag
let flag: Flag = match subcommand.as_deref() {
Some("pride" | "rainbow")
| None
=> {
let variant = args.subcommand().unwrap_or(None);
match variant.as_deref() {
Some("8-color" | "gilbert-baker" | "sex-and-magic")
=> variant::gilbert_baker(),
Some("philadelphia")
=> variant::philadelphia(),
Some("progress")
=> complex::progress(&state),
_
=> flag::pride()
}
},
Some("transgender" | "trans")
=> flag::transgender(),
Some("progress")
=> complex::progress(&state),
Some("agender")
@ -64,78 +83,105 @@ fn main() {
Some("asexual" | "ace")
=> flag::asexual(),
Some("aroace" | "aromantic-asexual")
=> {
match variant.as_deref() {
Some("halves" | "side-by-side" | "sbs")
=> complex::aroace_halves(&state),
_
=> flag::aroace()
}
},
Some("bigender")
=> flag::bigender(),
Some("bisexual" | "bi")
=> flag::bisexual(),
Some("demiboy")
=> flag::demiboy(),
Some("demigender")
=> flag::demigender(),
Some("demigirl")
=> flag::demigirl(),
Some("demiromantic")
=> complex::demiromantic(&state),
Some("demisexual")
=> complex::demisexual(&state),
// Some("disability")
// => complex::disability();
Some("gay" | "mlm")
=> flag::gay(),
Some("genderfluid")
=> flag::genderfluid(),
Some("gender-nonconforming" | "gnc" | "gendernonconforming")
=> flag::gender_nonconforming(),
Some("genderqueer")
=> flag::genderqueer(),
Some("gendervoid")
=> flag::gendervoid(),
Some("lesbian")
=> flag::lesbian(),
// Some("intersex")
// => complex::intersex(),
Some("lesbian" | "wlw")
=> {
match variant.as_deref() {
Some("7-color")
=> variant::lesbian_7(),
_
=> flag::lesbian()
}
}
Some("multisexual" | "m-spec" | "mspec")
=> flag::multisexual(),
Some("multigender")
=> flag::multigender(),
Some("neutrois")
=> flag::neutrois(),
Some("nonbinary" | "nb")
=> flag::nonbinary(),
Some("pansexual" | "pan")
=> flag::pansexual(),
_ => { help_text(); exit(1) }
// Some("polyamory" | "polyamorous" | "poly")
// => complex::polyamory(small),
Some("polysexual")
=> flag::polysexual(),
Some("transgender" | "trans")
=> flag::transgender(),
_
=> { error::unmatched_flag(subcommand.unwrap()); panic!() }
};
if small { draw::small(colors); }
else { draw::full(colors); }
// draw flag
flag.draw(&state);
}
fn help_text() {
println!("pride v{VERSION}");
println!("Valerie Wolfe <sleeplessval@gmail.com>");
println!("Show pride flags in the terminal.\n");
println!("usage: pride [flags] <name>\n");
println!("args:");
println!(" <name> The pride flag to display\n");
println!("flags:");
println!(" -h, --help Shows this help text");
println!(" --version Show version information");
println!(" -l, --list Prints a list of printable flags");
println!(" -s, --small Prints a small version without holding");
println!("\nUse 'pride --list' to see a list of printable flags");
println!("\n~ You're loved and you matter ♥");
}
fn list_text() {
println!("pride v{}", env!("CARGO_PKG_VERSION"));
println!("\nFlag list:");
println!(" agender agender pride flag");
println!(" aro, aromantic aromantic pride flag");
println!(" ace, asexual asexual pride flag");
println!(" bigender bigender pride flag");
println!(" bi, bisexual bisexual pride flag");
println!(" gay, pride six-color rainbow flag");
println!(" genderfluid genderfluid pride flag");
println!(" genderqueer genderqueer pride flag");
println!(" gendervoid gendervoid pride flag");
println!(" lesbian lesbian pride flag");
println!(" multigender multigender pride flag");
println!(" nb, nonbinary nonbinary pride flag");
println!(" pan, pansexual pansexual pride flag");
// println!(" progress progress arrow flag");
println!(" trans, transgender transgender pride flag");
}

66
src/state.rs Normal file
View file

@ -0,0 +1,66 @@
use std::io::{ stdout, IsTerminal };
use pico_args::{ Arguments, Error };
use termion::terminal_size;
use crate::{ FLAG_SIZE, error };
#[derive(PartialEq)]
pub enum Size {
Full,
Small,
Set(u16, u16),
Wide(u16)
}
impl Size {
pub fn from(value: &str) -> Size {
if value == "small" { return Size::Small; }
let split: Vec<&str> = value.split('x').collect();
let len = split.len();
if len == 2 {
if let (Ok(width), Ok(height)) = (str::parse::<u16>(split.get(0).unwrap()), str::parse::<u16>(split.get(1).unwrap())) {
return Size::Set(width, height);
}
} else if len == 1 {
if let Ok(width) = str::parse::<u16>(split.get(0).unwrap()) {
return Size::Wide(width);
}
}
error::size_error(value);
panic!();
}
pub fn get(&self, width: u16, height: u16) -> (u16, u16) {
match self {
Size::Full => terminal_size().unwrap(),
Size::Set(width, height) => (width.clone(), height.clone()),
Size::Small => (width, height),
Size::Wide(width) => (width.clone(), height)
}
}
}
pub struct State {
pub size: Size,
pub is_terminal: bool,
}
impl State {
pub fn new(args: &mut Arguments) -> State {
let is_terminal = stdout().is_terminal();
let size = match args.value_from_str::<[&str;2], String>(FLAG_SIZE).as_deref() {
Ok(value) => Size::from(value),
Err(Error::MissingOption(_)) |
Err(Error::MissingArgument) => if is_terminal { Size::Full } else { Size::Small },
Err(Error::OptionWithoutAValue(_)) => Size::Small,
_ => { error::size_missing(); panic!() }
};
State { size, is_terminal }
}
}

53
src/util.rs Normal file
View file

@ -0,0 +1,53 @@
//! utility functions for working with ansi strings
/// gets the substring of displayed characters of an ANSI formatted string
pub fn ansi_substr(source: &str, start: usize, end: usize) -> String {
// init output string
let mut output = String::new();
// trackers
let mut escaped = false;
let mut index = 0;
for character in source.chars() {
// escape character delimits start and end of ansi sequences
if character == '\u{1B}' {
escaped = true;
output.push(character);
}
// push ALL escaped characters
if escaped {
output.push(character);
// and unset esc on m
if character == 'm' { escaped = false; }
}
// non-escaped characters must obey bounds
else {
if index < start {
index += 1;
continue;
}
output.push(character);
index += 1;
if index > end { break; }
}
}
output
}
/// gets the number of displayed characters in an ANSI formatted string
pub fn ansi_len(source: &str) -> usize {
let mut output = 0;
let mut escaped = false;
for character in source.chars() {
if character == '\u{1B}' { escaped = true; }
if !escaped { output += 1; }
else if character == 'm' { escaped = false; }
}
output
}

View file

@ -1,27 +1,49 @@
//! variant pride flags
//! these aren't in the flag module for organizational reasons.
use crate::{
color::*,
flag
flag::{ self, Flag }
};
pub fn gilbert_baker() -> Colors {
pub fn gilbert_baker() -> Flag {
let pink = rgb(0xFF69B4); // sex
let red = rgb(0xFF0000); // life
let orange = rgb(0xFF8F00); // healing
let yellow = rgb(0xFFFF00); // sunlight
let green = rgb(0x008F00); // nature
let cyan = rgb(0x00C0C0); // magic
let indigo = rgb(0x3E0099); // serenity
let purple = rgb(0x8F008F); // spirit
let mut output = flag::pride();
output.insert(0, pink);
output.insert(5, cyan);
output
Flag::Stripes(vec![pink, red, orange, yellow, green, cyan, indigo, purple])
}
pub fn philadelphia() -> Colors {
pub fn philadelphia() -> Flag {
let brown = rgb(0x784F17);
let mut output = flag::pride();
output.insert(0, BLACK);
output.insert(1, brown);
let base = flag::pride();
let mut colors = match base {
Flag::Stripes(inner)
=> inner,
_
=> panic!("impossible enum variant")
};
colors.insert(0, BLACK);
colors.insert(1, brown);
output
Flag::Stripes(colors)
}
pub fn lesbian_7() -> Flag {
let orange1 = rgb(0xD52D00); // gender non-conformity
let orange2 = rgb(0xEF7627); // independence
let orange3 = rgb(0xFF9A56); // community
// white // unique relationships with womanhood
let pink1 = rgb(0xD162A4); // serenity and peace
let pink2 = rgb(0xB55690); // love and sex
let pink3 = rgb(0xA30262); // femininity
Flag::Stripes(vec![orange1, orange2, orange3, WHITE, pink1, pink2, pink3])
}