Compare commits

..

No commits in common. "main" and "ext-help" have entirely different histories.

15 changed files with 91 additions and 649 deletions

1
.gitignore vendored
View file

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

View file

@ -1,26 +1,13 @@
[package] [package]
name = "pride" name = "pride"
version = "0.4.2" version = "0.3.0"
edition = "2021" 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" ]
[package.metadata.aur] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
name = "pride"
source = "archive/v$pkgver.tar.gz"
[[bin]]
name = "pride"
path = "src/main.rs"
[dependencies] [dependencies]
pico-args = "0.5.0" pico-args = "0.5.0"
termion = "4.0.3" termion = "2.0.1"
[profile.release] [profile.release]
opt-level = 's' opt-level = 's'
@ -28,5 +15,5 @@ codegen-units = 1
debug = false debug = false
lto = true lto = true
panic = "abort" panic = "abort"
strip = "symbols" strip = "debuginfo"

19
LICENSE
View file

@ -1,19 +0,0 @@
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

@ -10,49 +10,6 @@ A list of currently implemented flags is available on the [project wiki](https:/
Some Complex renderers utilize [Powerline's](https://github.com/ryanoasis/powerline-extra-symbols) 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). slant symbols, and therefore require use of a Powerline font, such as [Fira Code](https://github.com/tonsky/FiraCode).
## 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 ## Libraries
- [pico-args](https://crates.io/crates/pico-args) — argument parsing - [pico-args](https://crates.io/crates/pico-args) — argument parsing

View file

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

View file

@ -1,113 +0,0 @@
.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, 7-color, 7-stripe
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 ENVIRONMENT
.Bl -tag -width Ds
.It PRIDE_DEFAULT
A string containing the name of a flag to use as the default when no
.Ar flag
argument is provided.
.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
View file

@ -1,239 +0,0 @@
{
"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,13 +1,15 @@
//! flags that require more complex rendering than just scaling colored stripes //! flags that require more complex rendering than just scaling colored stripes
use termion::color::{ Bg, Rgb }; use termion::{
terminal_size,
color::{ Bg, Rgb }
};
use crate::{ use crate::{
color::*, color::*,
draw, draw,
error,
flag::{ self, Flag }, flag::{ self, Flag },
state::State,
util::{ ansi_len, ansi_substr } util::{ ansi_len, ansi_substr }
}; };
@ -25,7 +27,7 @@ pub static TRIANGLE_21: [char; 3] = ['', '🭬', ''];
/// 2/3 slope slant /// 2/3 slope slant
pub static SLANT_23: [char; 2] = ['🭒', '🭏']; pub static SLANT_23: [char; 2] = ['🭒', '🭏'];
pub fn progress(state: &State) -> Flag { pub fn progress(small: bool) -> Flag {
let red = bg(0xE50000); let red = bg(0xE50000);
let orange = bg(0xFF8D00); let orange = bg(0xFF8D00);
let yellow = bg(0xFFEE00); let yellow = bg(0xFFEE00);
@ -40,8 +42,7 @@ pub fn progress(state: &State) -> Flag {
let pink: u32 = 0x7ACBF5; let pink: u32 = 0x7ACBF5;
let white: u32 = 0xFFFFFF; let white: u32 = 0xFFFFFF;
let (width, height) = state.size.get(18, 6); let (width, height) = if small { (18, 6) } else { terminal_size().unwrap() };
if height < 6 || width < 6 { error::too_small(width, height); }
// create color slices and line buffer // create color slices and line buffer
let stripes = [red, orange, yellow, green, blue, purple]; let stripes = [red, orange, yellow, green, blue, purple];
@ -54,7 +55,7 @@ pub fn progress(state: &State) -> Flag {
// set up constraints // set up constraints
let linecount = height - (height % 6); // largest multiple of 6 smaller than height let linecount = height - (height % 6); // largest multiple of 6 smaller than height
let full_depth = width / 3; let full_depth = width / 3;
let chevron_width = if full_depth > 6 { (full_depth / 6) - 1 } else { 0 }; let chevron_width = (full_depth / 6) - 1;
let direction_thresh = linecount / 2; let direction_thresh = linecount / 2;
let corner = linecount % 2 == 1; let corner = linecount % 2 == 1;
@ -95,14 +96,17 @@ pub fn progress(state: &State) -> Flag {
// grab our substring constraints // grab our substring constraints
let start = (direction_thresh - n) as usize - 1; let start = (direction_thresh - n) as usize - 1;
let diff = if display_length >= start { display_length - start } else { 0 }; let diff = display_length - start;
// take substring of chevron line... // take substring of chevron line...
let mut line = ansi_substr(&base, start as usize, base_length); 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 // ... and add the colored stripe
line += &" ".repeat(width as usize - diff); line += &format!(
"{stripe}{separator}{line}",
stripe = stripes[index],
separator = TRIANGLE_21[0],
line = " ".repeat(width as usize - diff)
);
lines.push(line); lines.push(line);
line_no += 1; line_no += 1;
@ -128,12 +132,15 @@ pub fn progress(state: &State) -> Flag {
if index > 5 { break; } if index > 5 { break; }
let start = n as usize; let start = n as usize;
let diff = if display_length >= start { display_length - start } else { 0 }; let diff = display_length - start;
let mut line = ansi_substr(&base, start, base_length); let mut line = ansi_substr(&base, start, base_length);
line += &stripes[index].to_string(); line += &format!(
if diff > 0 { line.push(TRIANGLE_21[2]); } "{stripe}{separator}{line}",
line += &" ".repeat(width as usize - diff); stripe = stripes[index],
separator = TRIANGLE_21[2],
line = " ".repeat(width as usize - diff)
);
lines.push(line); lines.push(line);
line_no += 1; line_no += 1;
@ -144,13 +151,12 @@ pub fn progress(state: &State) -> Flag {
// everything below this point is in alphabetical order // everything below this point is in alphabetical order
pub fn aroace_halves(state: &State) -> Flag { pub fn aroace(small: bool) -> Flag {
// pull colors from aro & ace stripe flags // pull colors from aro & ace stripe flags
let Flag::Stripes(aro) = flag::aromantic() else { panic!() }; let Flag::Stripes(aro) = flag::aromantic() else { panic!() };
let Flag::Stripes(ace) = flag::asexual() else { panic!() }; let Flag::Stripes(ace) = flag::asexual() else { panic!() };
let (width, height) = state.size.get(60, 20); let (width, height) = if small { (60, 20) } else { terminal_size().unwrap() };
if height < 20 { error::too_small(width, height); }
let mut lines: Vec<String> = Vec::new(); let mut lines: Vec<String> = Vec::new();
@ -179,8 +185,6 @@ pub fn aroace_halves(state: &State) -> Flag {
fn demi_orientation_render(middle: Bg<Rgb>, bottom: Bg<Rgb>, width: u16, height: u16) -> Vec<String> { fn demi_orientation_render(middle: Bg<Rgb>, bottom: Bg<Rgb>, width: u16, height: u16) -> Vec<String> {
let white = bg(0xFFFFFF); let white = bg(0xFFFFFF);
if height < 5 { error::too_small(width, height); }
let stripes = vec![white, white, middle, bottom, bottom]; let stripes = vec![white, white, middle, bottom, bottom];
// initial stripe output buffer // initial stripe output buffer
@ -215,21 +219,21 @@ fn demi_orientation_render(middle: Bg<Rgb>, bottom: Bg<Rgb>, width: u16, height:
lines lines
} }
pub fn demiromantic(state: &State) -> Flag { pub fn demiromantic(small: bool) -> Flag {
let green = bg(0x3DA542); let green = bg(0x3DA542);
let gray = bg(0xD2D2D2); let gray = bg(0xD2D2D2);
let (width, height) = state.size.get(15, 5); let (width, height) = if small { (15, 5) } else { terminal_size().unwrap() };
let lines = demi_orientation_render(green, gray, width, height); let lines = demi_orientation_render(green, gray, width, height);
Flag::Lines(lines) Flag::Lines(lines)
} }
pub fn demisexual(state: &State) -> Flag { pub fn demisexual(small: bool) -> Flag {
let purple = bg(0x832FA8); let purple = bg(0x832FA8);
let grey = bg(0x7B868C); let grey = bg(0x7B868C);
let (width, height) = state.size.get(15, 5); let (width, height) = if small { (15, 5) } else { terminal_size().unwrap() };
let lines = demi_orientation_render(purple, grey, width, height); let lines = demi_orientation_render(purple, grey, width, height);
Flag::Lines(lines) Flag::Lines(lines)
@ -270,7 +274,7 @@ pub fn intersex() -> Flag {
} }
pub fn polyamory(state: &State) -> Flag { pub fn polyamory(small: bool) -> Flag {
let blue = rgb(0x019FE3); let blue = rgb(0x019FE3);
let magenta = rgb(0xE50051); let magenta = rgb(0xE50051);
let purple = rgb(0x340C46); let purple = rgb(0x340C46);
@ -281,8 +285,7 @@ pub fn polyamory(state: &State) -> Flag {
let semicircle = '\u{E0B6}'; let semicircle = '\u{E0B6}';
let separators = ['\u{E0BE}', '\u{E0BA}']; let separators = ['\u{E0BE}', '\u{E0BA}'];
let (width, height) = state.size.get(18, 6); let (width, height) = if small { (18, 6) } else { terminal_size().unwrap() };
if height < 6 { error::too_small(width, height); }
// create stripe array and line buffer // create stripe array and line buffer
let stripes = [magenta, purple]; // only stripes 2 and 3 need tracked let stripes = [magenta, purple]; // only stripes 2 and 3 need tracked

View file

@ -1,11 +1,10 @@
//! render handling code //! render handling code
use std::io::{ use std::io::{ self, Write };
self,
Write
};
use termion::{ use termion::{
terminal_size,
clear, clear,
color::{ Bg, Fg, Rgb }, color::{ Bg, Fg, Rgb },
cursor, cursor,
@ -15,53 +14,39 @@ use termion::{
use crate::{ use crate::{
color::{ RESET, RESET_BG }, color::{ RESET, RESET_BG },
error, flag::Flag
flag::Flag,
state::{ Size, State }
}; };
pub static BLOCK: &str = ""; pub static BLOCK: &str = "";
pub static UHALF: &str = ""; pub static UHALF: &str = "";
/// prints a provided vec of lines to stdout /// prints a provided vec of lines to stdout
pub fn draw_full(lines: Vec<String>) { pub fn draw_lines(lines: Vec<String>, hold: bool) {
let mut stdout = io::stdout().into_raw_mode().unwrap(); let mut stdout = io::stdout().into_raw_mode().unwrap();
// get in position for draw
let count = lines.len() as u16; let count = lines.len() as u16;
for _ in 0..count { write!(stdout, "\n").ok(); } for _ in 0..count { write!(stdout, "\n").ok(); }
write!(stdout, "{}", cursor::Up(count)).ok(); write!(stdout, "{}", cursor::Up(count)).ok();
// clear screen and hide cursor if hold { write!(stdout, "{}{}", cursor::Hide, clear::All).ok(); }
write!(stdout, "{}{}", cursor::Hide, clear::All).ok();
// write lines
let down = cursor::Down(1); let down = cursor::Down(1);
for line in lines { for line in lines {
let left = cursor::Left(line.len() as u16); let left = cursor::Left(line.len() as u16);
write!(stdout, "{line}{left}{down}").ok(); write!(stdout, "{line}{left}{down}").ok();
} }
// clear formatting and flush buffer
write!(stdout, "{RESET}{RESET_BG}").ok(); write!(stdout, "{RESET}{RESET_BG}").ok();
stdout.flush().ok(); stdout.flush().ok();
if hold {
// hold for input
let stdin = io::stdin(); let stdin = io::stdin();
for _ in stdin.keys() { break; } for _ in stdin.keys() { break; }
write!(stdout, "{}", clear::All).ok();
// clear and show cursor }
write!(stdout, "{}{}", clear::All, cursor::Show).ok(); write!(stdout, "{}", cursor::Show).ok();
stdout.flush().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 /// 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> { pub fn fg_stripes(colors: Vec<Fg<Rgb>>, width: u16, height: u16) -> Vec<String> {
let width = width as usize; let width = width as usize;
@ -113,19 +98,22 @@ pub fn bg_stripes(colors: Vec<Bg<Rgb>>, width: u16, height: u16) -> Vec<String>
impl Flag { impl Flag {
/// renders a flag to stdout /// renders a flag to stdout
pub fn draw(self, state: &State) { pub fn draw(self, hold: bool) {
let lines = match self { let lines = match self {
Flag::Stripes(colors) Flag::Stripes(colors)
=> { => {
let count = colors.len() as u16; let (width, height);
let (width, height) = state.size.get((count * 20 + 3) / 6, count); if hold { (width, height) = terminal_size().unwrap(); }
if height < count { error::too_small(width, height); } else {
height = colors.len() as u16;
width = height * 3;
}
fg_stripes(colors, width, height) fg_stripes(colors, width, height)
}, },
Flag::Lines(lines) Flag::Lines(lines)
=> lines => lines
}; };
draw_lines(lines, &state); draw_lines(lines, hold);
} }
} }

View file

@ -1,24 +0,0 @@
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

@ -158,19 +158,13 @@ pub fn multigender() -> Flag {
pub fn multisexual() -> Flag { pub fn multisexual() -> Flag {
let purple = rgb(0x724DC9); let purple = rgb(0x724DC9);
let blue = rgb(0xA0EFFE); let blue = rgb(0xFF3D9B);
let pink = rgb(0xFF3D9B); let pink = rgb(0xFF3D9B);
Flag::Stripes(vec![purple, WHITE, blue, pink]) 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 { pub fn nonbinary() -> Flag {
let yellow = rgb(0xFFF433); let yellow = rgb(0xFFF433);
let purple = rgb(0x9B59D0); let purple = rgb(0x9B59D0);

View file

@ -19,7 +19,7 @@ flags:
-h, --help Shows this help text -h, --help Shows this help text
--version Show version information --version Show version information
-l, --list Prints a list of printable flags -l, --list Prints a list of printable flags
-s, --size [size] Sets the size of the output flag. -s, --small Prints a small version without holding
Use 'pride --list' to see a list of printable flags Use 'pride --list' to see a list of printable flags
@ -49,11 +49,8 @@ flag list:
gendervoid gendervoid pride flag gendervoid gendervoid pride flag
lesbian lesbian pride flag lesbian lesbian pride flag
multigender multigender pride flag multigender multigender pride flag
multisexual multisexual pride flag
neutrois neutrois pride flag
nonbinary nonbinary pride flag nonbinary nonbinary pride flag
pansexual pansexual pride flag pansexual pansexual pride flag
polysexual polysexual pride flag
rainbow six-color rainbow flag rainbow six-color rainbow flag
progress progress arrow rainbow flag progress progress arrow rainbow flag
transgender transgender pride flag"); transgender transgender pride flag");
@ -130,17 +127,15 @@ names:
=> { println!("The gender-nonconforming pride flag.\n\nnames:\n 'gender-nonconforming', 'gendernonconforming', 'gnc'"); }, => { println!("The gender-nonconforming pride flag.\n\nnames:\n 'gender-nonconforming', 'gendernonconforming', 'gnc'"); },
"lesbian" | "wlw" "lesbian"
=> { => {
println!("The 5-stripe lesbian flag designed by Emily Gwen in 2018. println!("The 5-stripe lesbian flag designed by Emily Gwen in 2018.
names: names:
'lesbian', 'wlw' 'lesbian'
variants: variants:
7 7-stripe flag, also designed in 2018 by Emily Gwen 7-color 7-stripe flag, also designed in 2018 by Emily Gwen");
7-color
7-stripe");
}, },

View file

@ -1,36 +1,30 @@
//! main method module //! main method module
use std::env::var;
use std::{
io::{ stdout, IsTerminal },
process::exit
};
use pico_args::Arguments; use pico_args::Arguments;
mod color; mod color;
mod complex; mod complex;
mod draw; mod draw;
mod error;
mod flag; mod flag;
mod help; mod help;
mod state;
mod util; mod util;
mod variant; mod variant;
use crate::{ use crate::flag::Flag;
flag::Flag,
state::State
};
static VERSION: &str = env!("CARGO_PKG_VERSION"); 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() { fn main() {
// collect args // collect args
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
// handle help flag // handle help flag
if args.contains(FLAG_HELP) { if args.contains(["-h", "--help"]) {
let target = args.subcommand().unwrap(); let target = args.subcommand().unwrap();
if target.is_some() { help::flag_help(&target.unwrap()); } if target.is_some() { help::flag_help(&target.unwrap()); }
else { help::help_text(); } else { help::help_text(); }
@ -38,26 +32,27 @@ fn main() {
} }
// handle list flag // handle list flag
if args.contains(FLAG_LIST) { if args.contains(["-l", "--list"]) {
help::list_text(); help::list_text();
return; return;
} }
// handle version flag // handle version flag
if args.contains(FLAG_VERSION) { if args.contains(["-v", "--version"]) {
println!("pride v{VERSION}"); println!("pride v{VERSION}");
return; return;
} }
let state = State::new(&mut args); if !stdout().is_terminal() {
println!("pride: output must be a terminal");
exit(2);
}
let subcommand = // get small flag
if let Ok(Some(subcommand)) = args.subcommand() { Some(subcommand) } let small = args.contains(["-s", "--small"]);
else if let Ok(default) = var("PRIDE_DEFAULT") {
if default.is_empty() { None } let subcommand = args.subcommand().unwrap();
else { Some(default) } let variant = args.subcommand().unwrap_or(None);
} else { None };
let variant = args.subcommand().unwrap();
// get color vec from matched flag // get color vec from matched flag
let flag: Flag = match subcommand.as_deref() { let flag: Flag = match subcommand.as_deref() {
@ -70,14 +65,14 @@ fn main() {
Some("philadelphia") Some("philadelphia")
=> variant::philadelphia(), => variant::philadelphia(),
Some("progress") Some("progress")
=> complex::progress(&state), => complex::progress(small),
_ _
=> flag::pride() => flag::pride()
} }
}, },
Some("progress") Some("progress")
=> complex::progress(&state), => complex::progress(small),
Some("agender") Some("agender")
@ -93,7 +88,7 @@ fn main() {
=> { => {
match variant.as_deref() { match variant.as_deref() {
Some("halves" | "side-by-side" | "sbs") Some("halves" | "side-by-side" | "sbs")
=> complex::aroace_halves(&state), => complex::aroace(small),
_ _
=> flag::aroace() => flag::aroace()
} }
@ -114,15 +109,14 @@ fn main() {
=> flag::demigirl(), => flag::demigirl(),
Some("demiromantic") Some("demiromantic")
=> complex::demiromantic(&state), => complex::demiromantic(small),
Some("demisexual") Some("demisexual")
=> complex::demisexual(&state), => complex::demisexual(small),
// Some("disability") // Some("disability")
// => complex::disability(); // => complex::disability();
Some("gay" | "mlm") Some("gay" | "mlm")
=> flag::gay(), => flag::gay(),
@ -138,36 +132,28 @@ fn main() {
Some("gendervoid") Some("gendervoid")
=> flag::gendervoid(), => flag::gendervoid(),
// Some("intersex") // Some("intersex")
// => complex::intersex(), // => complex::intersex(),
Some("lesbian")
Some("lesbian" | "wlw")
=> { => {
match variant.as_deref() { match variant.as_deref() {
Some("7" | "7-color" | "7-stripe") Some("7-color")
=> variant::lesbian_7(), => variant::lesbian_7(),
_ _
=> flag::lesbian() => flag::lesbian()
} }
} }
Some("multisexual" | "m-spec" | "mspec") Some("multisexual" | "m-spec" | "mspec")
=> flag::multisexual(), => flag::multisexual(),
Some("multigender") Some("multigender")
=> flag::multigender(), => flag::multigender(),
Some("neutrois")
=> flag::neutrois(),
Some("nonbinary" | "nb") Some("nonbinary" | "nb")
=> flag::nonbinary(), => flag::nonbinary(),
Some("pansexual" | "pan") Some("pansexual" | "pan")
=> flag::pansexual(), => flag::pansexual(),
@ -177,17 +163,15 @@ fn main() {
Some("polysexual") Some("polysexual")
=> flag::polysexual(), => flag::polysexual(),
Some("transgender" | "trans") Some("transgender" | "trans")
=> flag::transgender(), => flag::transgender(),
_ _ => { help::help_text(); exit(1) }
=> { error::unmatched_flag(subcommand.unwrap()); panic!() }
}; };
// draw flag // draw flag
flag.draw(&state); flag.draw(!small);
} }

View file

@ -1,66 +0,0 @@
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 }
}
}

View file

@ -27,7 +27,7 @@ pub fn philadelphia() -> Flag {
Flag::Stripes(inner) Flag::Stripes(inner)
=> inner, => inner,
_ _
=> panic!("impossible enum variant") => { panic!("impossible enum variant"); }
}; };
colors.insert(0, BLACK); colors.insert(0, BLACK);
colors.insert(1, brown); colors.insert(1, brown);