merged in complex renderers from main and

This commit is contained in:
Valerie Wolfe 2023-07-10 13:44:14 -04:00
commit f769a65a6d
10 changed files with 530 additions and 104 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "pride" name = "pride"
version = "0.1.5" version = "0.2.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -3,14 +3,12 @@
A Rust utility to display pride flags in the terminal. A Rust utility to display pride flags in the terminal.
**This project is under heavy construction! It is subject to major structural and A list of currently implemented flags is available on the [project wiki](https://git.vwolfe.io/valerie/pride/wiki/Flags).
architectural changes. There are no issues with functionality, but I will continue
to make major changes and refactors until the main roadmap is complete.**
Currently supports a variety of stripe flags. ## Dependencies
Under Construction features: Some Complex renderers utilize [Powerline's](https://github.com/ryanoasis/powerline-extra-symbols)
- ["Complex" Flags](https://git.vwolfe.io/valerie/pride/src/branch/complex) slant symbols, and therefore require use of a Powerline font, such as [Fira Code](https://github.com/tonsky/FiraCode).
## Libraries ## Libraries

View file

@ -1,5 +1,5 @@
use termion::color::{ Fg, Rgb, Reset }; use termion::color::{ Bg, Fg, Rgb, Reset };
pub type Color = Fg<Rgb>; pub type Color = Fg<Rgb>;
pub type Colors = Vec<Fg<Rgb>>; pub type Colors = Vec<Fg<Rgb>>;
@ -8,8 +8,9 @@ pub static BLACK: Color = Fg(Rgb(0x00, 0x00, 0x00));
pub static WHITE: Color = Fg(Rgb(0xFF, 0xFF, 0xFF)); pub static WHITE: Color = Fg(Rgb(0xFF, 0xFF, 0xFF));
pub static RESET: Fg<Reset> = Fg(Reset); pub static RESET: Fg<Reset> = Fg(Reset);
pub static RESET_BG: Bg<Reset> = Bg(Reset);
/// converts a hex integer to Fg(Rgb) /// produces a termion foreground color from the provided integer
pub fn rgb(hex: u32) -> Color { pub fn rgb(hex: u32) -> Color {
// colors should be 0xrrggbb = 0x__rrggbb; drop the most significant byte // colors should be 0xrrggbb = 0x__rrggbb; drop the most significant byte
let [_, r, g, b] = hex.to_be_bytes(); let [_, r, g, b] = hex.to_be_bytes();
@ -17,3 +18,10 @@ pub fn rgb(hex: u32) -> Color {
Fg(Rgb(r, g, b)) 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))
}

292
src/complex.rs Normal file
View file

@ -0,0 +1,292 @@
//! flags that require more complex rendering than just scaling colored stripes
use termion::{
terminal_size,
color::{ Bg, Rgb }
};
use crate::{
color::*,
draw,
flag::{ self, Flag },
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(small: bool) -> 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) = if small { (18, 6) } else { terminal_size().unwrap() };
// 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;
/* ok, coming up with procedure:
* - can't rely on bg_stripes; line count, threshold, etc., will need to happen here
* - line count will always be the largest multiple of 6 smaller than height; c = h - (h % 6)
* - chevrons may have larger widths: TODO calc
* - depth will be funky; line depth will need to use "full" depth; (Df - Dl) / Wc = Ic (TODO verify?)
* - switch stripe index on *absolute* line number rather than n
* - chevron building will be BLOCK.repeat(width) + TRIANGLE_21[0] (fg Ic, bg Ic + 1)
* - chevrons[len - 1] will need unique handling to draw stripes
*/
// set up constraints
let linecount = height - (height % 6); // largest multiple of 6 smaller than height
let full_depth = width / 3;
let chevron_width = (full_depth / 6) - 1;
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 = display_length - start;
// take substring of chevron line...
let mut line = ansi_substr(&base, start as usize, base_length);
// ... and add the colored stripe
line += &format!(
"{stripe}{separator}{line}",
stripe = stripes[index],
separator = TRIANGLE_21[0],
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 = display_length - start;
let mut line = ansi_substr(&base, start, base_length);
line += &format!(
"{stripe}{separator}{line}",
stripe = stripes[index],
separator = 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(small: bool) -> 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) = if small { (60, 20) } else { terminal_size().unwrap() };
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);
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(small: bool) -> Flag {
let green = bg(0x3DA542);
let gray = bg(0xD2D2D2);
let (width, height) = if small { (15, 5) } else { terminal_size().unwrap() };
let lines = demi_orientation_render(green, gray, width, height);
Flag::Lines(lines)
}
pub fn demisexual(small: bool) -> Flag {
let purple = bg(0x832FA8);
let grey = bg(0x7B868C);
let (width, height) = if small { (15, 5) } else { terminal_size().unwrap() };
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 polyamorous() {
let blue = rgb(0x019FE3);
let magenta = rgb(0xE50051);
let purple = rgb(0x340C46);
let yellow = rgb(0x00FCBF);
// blue / magenta / purple vert
// WHITE isosceles cutin with yellow heart pointed right
}

View file

@ -4,76 +4,110 @@ use termion::{
terminal_size, terminal_size,
clear, clear,
color::{ Bg, Fg, Rgb },
cursor, cursor,
input::TermRead, input::TermRead,
raw::IntoRawMode raw::IntoRawMode
}; };
use crate::color::{ RESET, Colors }; use crate::{
use crate::flag::BLOCK; color::{ RESET, RESET_BG },
flag::Flag
};
/// draw a fullscreen stripe flag and hold for keypress pub static BLOCK: &str = "";
pub fn full(colors: Colors) { pub static UHALF: &str = "";
// prepare stdin and stdout
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();
let stdin = io::stdin();
// get constraints let count = lines.len() as u16;
let count = colors.len(); for _ in 0..count { write!(stdout, "\n").ok(); }
let (width, height) = terminal_size().unwrap(); write!(stdout, "{}", cursor::Up(count)).ok();
let thresh = height as usize / count;
// clear the terminal if hold { write!(stdout, "{}{}", cursor::Hide, clear::All).ok(); }
write!(stdout, "{}{}", cursor::Hide, clear::All).ok();
let down = cursor::Down(1);
for line in lines {
let left = cursor::Left(line.len() as u16);
write!(stdout, "{line}{left}{down}").ok();
}
write!(stdout, "{RESET}{RESET_BG}").ok();
stdout.flush().ok(); stdout.flush().ok();
if hold {
let stdin = io::stdin();
for _ in stdin.keys() { break; }
write!(stdout, "{}", clear::All).ok();
}
write!(stdout, "{}", cursor::Show).ok();
stdout.flush().ok();
}
// build terminal width stripe string pub fn fg_stripes(colors: Vec<Fg<Rgb>>, width: u16, height: u16) -> Vec<String> {
let stripe = BLOCK.repeat(width as usize); 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 // create our color index
let mut index = 0; let mut index = 0;
// for every terminal row... for n in 0..height {
for n in 0..(height as usize) {
// ... increment our index at color change threshold
if n != 0 && n % thresh == 0 { if n != 0 && n % thresh == 0 {
index += 1; index += 1;
// and break if out of bounds // and break if out of bounds
if index >= count { break; } if index >= count { break; }
} }
// ... draw the stripe with color at index let color = colors[index];
write!( output.push(format!("{color}{stripe}"));
stdout,
"{color}{stripe}{RESET}",
color = colors[index]
).ok();
}
// flush stdout
stdout.flush().ok();
// wait for keypress
for _ in stdin.keys() { break; }
write!(stdout, "{}{}", cursor::Show, clear::All).ok();
stdout.flush().ok();
} }
/// draws a small stripe flag output
pub fn small(colors: Colors) { }
// prepare stdout pub fn bg_stripes(colors: Vec<Bg<Rgb>>, width: u16, height: u16) -> Vec<String> {
let mut stdout = io::stdout(); let width = width as usize;
let height = height as usize;
// get constraints
let count = colors.len(); let count = colors.len();
let width = count * 3;
// build small stripe string let thresh = height / count;
let stripe = BLOCK.repeat(width);
// print a stripe for all colors let stripe = " ".repeat(width);
for color in colors { let mut output = Vec::new();
println!("{color}{stripe}");
let mut index = 0;
for n in 0..height {
if n != 0 && n % thresh == 0 {
index += 1;
if index >= count { break; }
}
let color = colors[index];
output.push(format!("{color}{stripe}"));
}
output
}
impl Flag {
pub fn draw(self, hold: bool) {
let lines = match self {
Flag::Stripes(colors)
=> {
let (width, height);
if hold { (width, height) = terminal_size().unwrap(); }
else {
height = colors.len() as u16;
width = height * 3;
}
fg_stripes(colors, width, height)
},
Flag::Lines(lines)
=> lines
};
draw_lines(lines, hold);
} }
// reset our foreground color to play nice and flush stdout
print!("{RESET}");
stdout.flush().ok();
} }

View file

@ -3,9 +3,13 @@
use crate::color::*; 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 red = rgb(0xE50000);
let orange = rgb(0xFF8D00); let orange = rgb(0xFF8D00);
let yellow = rgb(0xFFEE00); let yellow = rgb(0xFFEE00);
@ -13,58 +17,58 @@ pub fn pride() -> Colors {
let blue = rgb(0x004CFF); let blue = rgb(0x004CFF);
let purple = rgb(0x770088); let purple = rgb(0x770088);
vec![red, orange, yellow, green, blue, purple] Flag::Stripes(vec![red, orange, yellow, green, blue, purple])
} }
pub fn transgender() -> Colors { pub fn transgender() -> Flag {
let pink = rgb(0x7ACBF5); let pink = rgb(0x7ACBF5);
let blue = rgb(0xEAACB8); let blue = rgb(0xEAACB8);
vec![pink, blue, WHITE, blue, pink] Flag::Stripes(vec![pink, blue, WHITE, blue, pink])
} }
// everything below here is alphabetical // everything below here is alphabetical
pub fn agender() -> Colors { pub fn agender() -> Flag {
let gray = rgb(0xB9B9B9); let gray = rgb(0xB9B9B9);
let green = rgb(0xB8F483); 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 green = rgb(0x3BA740);
let lime = rgb(0xA8D47A); let lime = rgb(0xA8D47A);
let grey = rgb(0xABABAB); 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 grey = rgb(0xA4A4A4);
let purple = rgb(0x810081); let purple = rgb(0x810081);
vec![BLACK, grey, WHITE, purple] Flag::Stripes(vec![BLACK, grey, WHITE, purple])
} }
pub fn bigender() -> Colors { pub fn bigender() -> Flag {
let pink = rgb(0xE676A6); let pink = rgb(0xE676A6);
let yellow = rgb(0xF9F04C); let yellow = rgb(0xF9F04C);
let purple = rgb(0xAB6BBB); let purple = rgb(0xAB6BBB);
let blue = rgb(0x6D96DC); 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 magenta = rgb(0xC42A6F);
let purple = rgb(0x915392); let purple = rgb(0x915392);
let blue = rgb(0x1437A2); let blue = rgb(0x1437A2);
vec![magenta, magenta, purple, blue, blue] Flag::Stripes(vec![magenta, magenta, purple, blue, blue])
} }
pub fn gay() -> Colors { pub fn gay() -> Flag {
let green1 = rgb(0x00906D); let green1 = rgb(0x00906D);
let green2 = rgb(0x00D1A7); let green2 = rgb(0x00D1A7);
let green3 = rgb(0x7EEBC1); let green3 = rgb(0x7EEBC1);
@ -72,68 +76,68 @@ pub fn gay() -> Colors {
let blue2 = rgb(0x5543D3); let blue2 = rgb(0x5543D3);
let blue3 = rgb(0x461280); let blue3 = rgb(0x461280);
vec![green1, green2, green3, WHITE, blue1, blue2, blue3] Flag::Stripes(vec![green1, green2, green3, WHITE, blue1, blue2, blue3])
} }
pub fn genderfluid() -> Colors { pub fn genderfluid() -> Flag {
let pink = rgb(0xFF75A2); let pink = rgb(0xFF75A2);
let violet = rgb(0xBE18D6); let violet = rgb(0xBE18D6);
let blue = rgb(0x333EBD); let blue = rgb(0x333EBD);
vec![pink, WHITE, violet, BLACK, blue] Flag::Stripes(vec![pink, WHITE, violet, BLACK, blue])
} }
pub fn gender_nonconforming() -> Colors { pub fn gender_nonconforming() -> Flag {
let purple = rgb(0x50284D); let purple = rgb(0x50284D);
let magenta = rgb(0x96467B); let magenta = rgb(0x96467B);
let blue = rgb(0x5C96F7); let blue = rgb(0x5C96F7);
vec![purple, purple, magenta, blue, WHITE, blue, magenta, purple, purple] Flag::Stripes(vec![purple, purple, magenta, blue, WHITE, blue, magenta, purple, purple])
} }
pub fn genderqueer() -> Colors { pub fn genderqueer() -> Flag {
let purple = rgb(0xB899DF); let purple = rgb(0xB899DF);
let green = rgb(0x6B8E3B); 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 navy = rgb(0x08114A);
let gray = rgb(0x4A484B); 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 red = rgb(0xD62800);
let orange = rgb(0xFF9B56); let orange = rgb(0xFF9B56);
let pink = rgb(0xD462A6); let pink = rgb(0xD462A6);
let magenta = rgb(0xA40062); 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 blue = rgb(0x3F47CC);
let ltblue = rgb(0x01A4E9); let ltblue = rgb(0x01A4E9);
let orange = rgb(0xFB7F27); let orange = rgb(0xFB7F27);
vec![blue, ltblue, orange, ltblue, blue] Flag::Stripes(vec![blue, ltblue, orange, ltblue, blue])
} }
pub fn nonbinary() -> Colors { pub fn nonbinary() -> Flag {
let yellow = rgb(0xFFF433); let yellow = rgb(0xFFF433);
let purple = rgb(0x9B59D0); 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 magenta = rgb(0xFF1B8D);
let yellow = rgb(0xFFDA00); let yellow = rgb(0xFFDA00);
let cyan = rgb(0x1BB3FF); let cyan = rgb(0x1BB3FF);
vec![magenta, yellow, cyan] Flag::Stripes(vec![magenta, yellow, cyan])
} }

View file

@ -29,6 +29,7 @@ pub fn list_text() {
flag list: flag list:
agender agender pride flag agender agender pride flag
aro, aromantic aromantic pride flag aro, aromantic aromantic pride flag
aroace aromantic-asexual pride flag
ace, asexual asexual pride flag ace, asexual asexual pride flag
bigender bigender pride flag bigender bigender pride flag
bi, bisexual bisexual pride flag bi, bisexual bisexual pride flag
@ -42,6 +43,7 @@ flag list:
nb, nonbinary nonbinary pride flag nb, nonbinary nonbinary pride flag
pan, pansexual pansexual pride flag pan, pansexual pansexual pride flag
pride, rainbow six-color rainbow flag pride, rainbow six-color rainbow flag
progress progress arrow rainbow flag
trans, transgender transgender pride flag"); trans, transgender transgender pride flag");
} }
@ -58,7 +60,8 @@ variants:
8-color Gilbert Baker's original 1978 flag with 8 stripes 8-color Gilbert Baker's original 1978 flag with 8 stripes
gilbert-baker gilbert-baker
sex-and-magic sex-and-magic
philadelphia The 2017 Philadelphia Pride flag with black and brown stripes"); philadelphia The 2017 Philadelphia Pride flag with black and brown stripes
progress The 2018 Progess rainbow pride flag designed by Daniel Quasar");
}, },
"transgender" | "trans" "transgender" | "trans"
@ -78,7 +81,9 @@ names:
variants: variants:
7-color 7-stripe flag, also designed in 2018 by Emily Gwen"); 7-color 7-stripe flag, also designed in 2018 by Emily Gwen");
} },
"progress"
=> { println!("Daniel Quasar's 2018 Progress rainbow pride flag.\n\nnames:\n 'progress'"); }
_ _
=> help_text() => help_text()

View file

@ -3,12 +3,17 @@ use std::process::exit;
use pico_args::Arguments; use pico_args::Arguments;
mod color; mod color;
mod complex;
mod draw; mod draw;
mod flag; mod flag;
<<<<<<< HEAD
mod help; mod help;
=======
mod util;
>>>>>>> main
mod variant; mod variant;
use crate::color::Colors; use crate::flag::Flag;
static VERSION: &str = env!("CARGO_PKG_VERSION"); static VERSION: &str = env!("CARGO_PKG_VERSION");
@ -42,7 +47,7 @@ fn main() {
let subcommand = args.subcommand().unwrap(); let subcommand = args.subcommand().unwrap();
// get color vec from matched flag // get color vec from matched flag
let colors: Colors = match subcommand.as_deref() { let flag: Flag = match subcommand.as_deref() {
Some("pride" | "rainbow") Some("pride" | "rainbow")
| None | None
=> { => {
@ -52,6 +57,8 @@ fn main() {
=> variant::gilbert_baker(), => variant::gilbert_baker(),
Some("philadelphia") Some("philadelphia")
=> variant::philadelphia(), => variant::philadelphia(),
Some("progress")
=> complex::progress(small),
_ _
=> flag::pride() => flag::pride()
} }
@ -70,12 +77,24 @@ fn main() {
Some("asexual" | "ace") Some("asexual" | "ace")
=> flag::asexual(), => flag::asexual(),
Some("aroace" | "aromantic-asexual")
=> complex::aroace(small),
Some("bigender") Some("bigender")
=> flag::bigender(), => flag::bigender(),
Some("bisexual" | "bi") Some("bisexual" | "bi")
=> flag::bisexual(), => flag::bisexual(),
Some("demiromantic")
=> complex::demiromantic(small),
Some("demisexual")
=> complex::demisexual(small),
// Some("disability")
// => complex::disability();
Some("gay" | "mlm") Some("gay" | "mlm")
=> flag::gay(), => flag::gay(),
@ -91,6 +110,9 @@ fn main() {
Some("gendervoid") Some("gendervoid")
=> flag::gendervoid(), => flag::gendervoid(),
Some("intersex")
=> complex::intersex(),
Some("lesbian") Some("lesbian")
=> { => {
let variant = args.subcommand().unwrap_or(None); let variant = args.subcommand().unwrap_or(None);
@ -111,11 +133,16 @@ fn main() {
Some("pansexual" | "pan") Some("pansexual" | "pan")
=> flag::pansexual(), => flag::pansexual(),
_ => { help::help_text(); exit(1) } // (or die) // Some("poly" | "polyamorous" | "polyamory")
// => complex::polyamorous(),
Some("progress")
=> flag::progress(),
_ => { help_text(); exit(1) }
}; };
if small { draw::small(colors); } flag.draw(!small);
else { draw::full(colors); }
} }

52
src/util.rs Normal file
View file

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

@ -3,10 +3,10 @@
use crate::{ use crate::{
color::*, color::*,
flag flag::{ self, Flag }
}; };
pub fn gilbert_baker() -> Colors { pub fn gilbert_baker() -> Flag {
let pink = rgb(0xFF69B4); // sex let pink = rgb(0xFF69B4); // sex
let red = rgb(0xFF0000); // life let red = rgb(0xFF0000); // life
let orange = rgb(0xFF8F00); // healing let orange = rgb(0xFF8F00); // healing
@ -16,20 +16,26 @@ pub fn gilbert_baker() -> Colors {
let indigo = rgb(0x3E0099); // serenity let indigo = rgb(0x3E0099); // serenity
let purple = rgb(0x8F008F); // spirit let purple = rgb(0x8F008F); // spirit
vec![pink, red, orange, yellow, green, cyan, indigo, purple] Flag::Stripes(vec![pink, red, orange, yellow, green, cyan, indigo, purple])
} }
pub fn philadelphia() -> Colors { pub fn philadelphia() -> Flag {
let brown = rgb(0x784F17); let brown = rgb(0x784F17);
let mut output = flag::pride(); let base = flag::pride();
output.insert(0, BLACK); let mut colors = match base {
output.insert(1, brown); Flag::Stripes(inner)
=> inner,
_
=> { panic!("impossible enum variant"); }
};
colors.insert(0, BLACK);
colors.insert(1, brown);
output Flag::Stripes(colors)
} }
pub fn lesbian_7() -> Colors { pub fn lesbian_7() -> Flag {
let orange1 = rgb(0xD52D00); // gender non-conformity let orange1 = rgb(0xD52D00); // gender non-conformity
let orange2 = rgb(0xEF7627); // independence let orange2 = rgb(0xEF7627); // independence
let orange3 = rgb(0xFF9A56); // community let orange3 = rgb(0xFF9A56); // community
@ -38,6 +44,6 @@ pub fn lesbian_7() -> Colors {
let pink2 = rgb(0xB55690); // love and sex let pink2 = rgb(0xB55690); // love and sex
let pink3 = rgb(0xA30262); // femininity let pink3 = rgb(0xA30262); // femininity
vec![orange1, orange2, orange3, WHITE, pink1, pink2, pink3] Flag::Stripes(vec![orange1, orange2, orange3, WHITE, pink1, pink2, pink3])
} }