mirror of
https://github.com/hykilpikonna/hyfetch.git
synced 2026-10-24 07:22:55 -05:00
[+] Add option to generate random alignment every execution (#550)
Some checks failed
Shellcheck / check (push) Has been cancelled
Some checks failed
Shellcheck / check (push) Has been cancelled
* ft: random alignment python * ft: random alignment rust * fx: printlns * [O] Optimize random selection & wording --------- Co-authored-by: djairoh <djairoh@mykolab.com> Co-authored-by: Azalea <noreply@aza.moe>
This commit is contained in:
@@ -4,12 +4,12 @@ use std::ops::Range;
|
||||
|
||||
use aho_corasick::AhoCorasick;
|
||||
use anyhow::{Context as _, Result};
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use tracing::debug;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use crate::color_util::{
|
||||
color, ForegroundBackground, NeofetchAsciiIndexedColor, ToAnsiString as _,
|
||||
color, ForegroundBackground, NeofetchAsciiIndexedColor, PresetIndexedColor, ToAnsiString as _,
|
||||
};
|
||||
use crate::neofetch_util::{
|
||||
ascii_size, ColorAlignment, NEOFETCH_COLORS_AC, NEOFETCH_COLOR_PATTERNS,
|
||||
@@ -68,6 +68,53 @@ impl RawAsciiArt {
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a random color alignment for the given ascii art.
|
||||
pub fn get_random_alignment(preset: &ColorProfile, asc: &NormalizedAsciiArt) -> ColorAlignment {
|
||||
let slots: IndexSet<NeofetchAsciiIndexedColor> = {
|
||||
let asc = asc.lines.join("\n");
|
||||
let ac =
|
||||
NEOFETCH_COLORS_AC.get_or_init(|| AhoCorasick::new(NEOFETCH_COLOR_PATTERNS).unwrap());
|
||||
ac.find_iter(&asc)
|
||||
.map(|m| {
|
||||
let ai_start = m.start().checked_add(3).unwrap();
|
||||
let ai_end = m.end().checked_sub(1).unwrap();
|
||||
asc[ai_start..ai_end]
|
||||
.parse()
|
||||
.expect("neofetch ascii color index should not be invalid")
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
if slots.is_empty() {
|
||||
return ColorAlignment::Custom {
|
||||
colors: IndexMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let num_colors = preset.unique_colors().colors.len();
|
||||
if num_colors == 0 {
|
||||
return ColorAlignment::Custom {
|
||||
colors: IndexMap::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut preset_indices: Vec<PresetIndexedColor> =
|
||||
(0..num_colors).map(|x| (x as u8).into()).collect();
|
||||
while preset_indices.len() < slots.len() {
|
||||
preset_indices.extend((0..num_colors).map(|x| PresetIndexedColor::from(x as u8)));
|
||||
}
|
||||
|
||||
let mut rng = fastrand::Rng::new();
|
||||
rng.shuffle(&mut preset_indices);
|
||||
|
||||
let colors = slots
|
||||
.into_iter()
|
||||
.zip(preset_indices)
|
||||
.collect();
|
||||
|
||||
ColorAlignment::Custom { colors }
|
||||
}
|
||||
|
||||
impl NormalizedAsciiArt {
|
||||
/// Uses a color alignment to recolor the ascii art.
|
||||
#[tracing::instrument(level = "debug", skip(self), fields(self.w = self.w, self.h = self.h))]
|
||||
@@ -91,6 +138,10 @@ impl NormalizedAsciiArt {
|
||||
let reset = color("&~&*", color_mode).expect("color reset should not be invalid");
|
||||
|
||||
let lines = match (color_align, self) {
|
||||
(ColorAlignment::Random, _) => {
|
||||
let resolved = get_random_alignment(color_profile, self);
|
||||
return self.to_recolored(&resolved, color_profile, color_mode, theme);
|
||||
},
|
||||
(ColorAlignment::Horizontal, Self { fg, .. }) => {
|
||||
let Self { lines, .. } = self
|
||||
.fill_starting()
|
||||
@@ -394,3 +445,4 @@ impl NormalizedAsciiArt {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ use terminal_size::{terminal_size, Height, Width};
|
||||
use time::{Month, OffsetDateTime};
|
||||
use tracing::debug;
|
||||
|
||||
pub use hyfetch::ascii::get_random_alignment;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
add_pkg_path().expect("failed to add pkg path");
|
||||
|
||||
@@ -245,7 +247,11 @@ fn main() -> Result<()> {
|
||||
get_distro_ascii(distro, backend).context("failed to get distro ascii")?
|
||||
};
|
||||
let asc = asc.to_normalized().context("failed to normalize ascii")?;
|
||||
let color_align = config.color_align;
|
||||
let color_align = if options.random_alignment || config.color_align == ColorAlignment::Random {
|
||||
get_random_alignment(&color_profile, &asc)
|
||||
} else {
|
||||
config.color_align
|
||||
};
|
||||
let asc = asc
|
||||
.to_recolored(&color_align, &color_profile, color_mode, theme)
|
||||
.context("failed to recolor ascii")?;
|
||||
@@ -731,7 +737,7 @@ fn create_config(
|
||||
let filtered = filter_flag_indices(part, &flags);
|
||||
filtered.first().map(|&idx| flags[idx].0.as_ref().to_owned())
|
||||
});
|
||||
|
||||
|
||||
if let Some(p) = selection {
|
||||
resolved_presets.push(p);
|
||||
} else {
|
||||
@@ -1178,8 +1184,8 @@ fn create_config(
|
||||
}
|
||||
|
||||
print_title_prompt(option_counter, "Let's choose a color arrangement!");
|
||||
println!("You can choose standard horizontal or vertical alignment, or use one of the random color schemes.\nYou can type \"roll\" to randomize again.\n");
|
||||
let mut opts: Vec<Cow<str>> = ["horizontal", "vertical", "roll"].map(Into::into).into();
|
||||
println!("You can choose standard horizontal or vertical alignment, or use one of the random color schemes. You can type \"roll\" to randomize again. Additionally, 'truerandom' will generate a fresh random color scheme every time hyfetch runs.\n");
|
||||
let mut opts: Vec<Cow<str>> = ["horizontal", "vertical", "roll", "truerandom"].map(Into::into).into();
|
||||
opts.extend((0..random_count).map(|i| format!("random{i}").into()));
|
||||
let choice = literal_input("Your choice?", &opts[..], "horizontal", true, color_mode)
|
||||
.context("failed to ask for choice input")
|
||||
@@ -1193,6 +1199,7 @@ fn create_config(
|
||||
// Save choice
|
||||
color_align = if choice == "horizontal" { ColorAlignment::Horizontal }
|
||||
else if choice == "vertical" { ColorAlignment::Vertical }
|
||||
else if choice == "truerandom" { ColorAlignment::Random }
|
||||
else {
|
||||
arrangements.into_iter()
|
||||
.find_map(|(k, ca)| {
|
||||
|
||||
@@ -36,6 +36,7 @@ pub struct Options {
|
||||
pub palette_glyph: Option<String>,
|
||||
#[cfg(feature = "macchina")]
|
||||
pub palette_type: Option<String>,
|
||||
pub random_alignment: bool,
|
||||
}
|
||||
|
||||
pub fn options() -> OptionParser<Options> {
|
||||
@@ -156,6 +157,7 @@ BACKEND={{{backends}}}",
|
||||
.help("Enables hyfetch to detect light/dark terminal background in runtime")
|
||||
.argument("BOOL")
|
||||
.optional();
|
||||
let random_alignment = long("random-alignment").help("Use a fresh random color alignment every time, independent of config").short('r').switch();
|
||||
|
||||
#[cfg(feature = "macchina")]
|
||||
let palette_glyph = long("palette-glyph")
|
||||
@@ -188,7 +190,8 @@ BACKEND={{{backends}}}",
|
||||
ask_exit,
|
||||
auto_detect_light_dark,
|
||||
palette_glyph,
|
||||
palette_type
|
||||
palette_type,
|
||||
random_alignment
|
||||
})
|
||||
.to_options()
|
||||
.header(
|
||||
@@ -218,7 +221,8 @@ BACKEND={{{backends}}}",
|
||||
// hidden
|
||||
test_print,
|
||||
ask_exit,
|
||||
auto_detect_light_dark
|
||||
auto_detect_light_dark,
|
||||
random_alignment
|
||||
})
|
||||
.to_options()
|
||||
.header(
|
||||
|
||||
@@ -73,6 +73,7 @@ pub enum ColorAlignment {
|
||||
#[serde(deserialize_with = "crate::utils::index_map_serde::deserialize")]
|
||||
colors: IndexMap<NeofetchAsciiIndexedColor, PresetIndexedColor>,
|
||||
},
|
||||
Random,
|
||||
}
|
||||
|
||||
/// Asks the user to provide an input among a list of options.
|
||||
|
||||
@@ -22,6 +22,7 @@ from .neofetch_util import *
|
||||
from .presets import PRESETS, ColorProfile
|
||||
|
||||
|
||||
|
||||
def check_config(path) -> Config:
|
||||
"""
|
||||
Check if the configuration exists. Return the config object if it exists. If not, call the
|
||||
@@ -316,7 +317,7 @@ def create_config() -> Config:
|
||||
# later iterations
|
||||
hv_arrangements = [
|
||||
('Horizontal', ColorAlignment('horizontal', fore_back=fore_back)),
|
||||
('Vertical', ColorAlignment('vertical'))
|
||||
('Vertical', ColorAlignment('vertical')),
|
||||
]
|
||||
arrangements = hv_arrangements.copy()
|
||||
|
||||
@@ -348,17 +349,16 @@ def create_config() -> Config:
|
||||
print()
|
||||
|
||||
print_title_prompt("Let's choose a color arrangement!")
|
||||
printc(f'You can choose standard horizontal or vertical alignment, or use one of the random color schemes.')
|
||||
print('You can type "roll" to randomize again.')
|
||||
printc(f'You can choose standard horizontal or vertical alignment, or use one of the random color schemes. You can type "roll" to randomize again. Additionally, \'truerandom\' will generate a fresh random color scheme every time hyfetch runs.')
|
||||
print()
|
||||
choice = literal_input(f'Your choice?', ['horizontal', 'vertical', 'roll'] + [f'random{i}' for i in range(random_count)], 'horizontal')
|
||||
choice = literal_input(f'Your choice?', ['horizontal', 'vertical', 'roll', 'truerandom'] + [f'random{i}' for i in range(random_count)], 'horizontal')
|
||||
|
||||
if choice == 'roll':
|
||||
arrangements = []
|
||||
continue
|
||||
|
||||
# Save choice
|
||||
arrangement_index = {k.lower(): ca for k, ca in hv_arrangements + arrangements}
|
||||
arrangement_index = {k.lower(): ca for k, ca in hv_arrangements + arrangements + [("TrueRandom", ColorAlignment('random'))]}
|
||||
if choice in arrangement_index:
|
||||
color_alignment = arrangement_index[choice]
|
||||
else:
|
||||
@@ -466,6 +466,7 @@ def create_parser() -> argparse.ArgumentParser:
|
||||
parser.add_argument('-V', '--version', dest='version', action='store_true', help=f'Check version')
|
||||
parser.add_argument('--june', action='store_true', help=f'Show pride month easter egg')
|
||||
parser.add_argument('--debug', action='store_true', help=f'Debug mode')
|
||||
parser.add_argument('-r', '--random-alignment', action='store_true', help=color(f'Use a fresh random color alignment every time, independent of config'))
|
||||
|
||||
parser.add_argument('--distro', '--test-distro', dest='distro', help=f'Test for a specific distro')
|
||||
parser.add_argument('--ascii-file', help='Use a specific file for the ascii art')
|
||||
@@ -612,7 +613,8 @@ def run():
|
||||
asc = Path(args.ascii_file).read_text("utf-8")
|
||||
else:
|
||||
asc = get_distro_ascii()
|
||||
asc = config.color_align.recolor_ascii(asc, preset)
|
||||
color_align: ColorAlignment = get_random_alignment(preset, asc) if (args.random_alignment or config.color_align.mode == "random") else config.color_align
|
||||
asc = color_align.recolor_ascii(asc, preset)
|
||||
neofetch_util.run(asc, config.backend, config.args or '')
|
||||
except Exception as e:
|
||||
print(f'Error: {e}')
|
||||
|
||||
@@ -116,6 +116,28 @@ def fill_starting(asc: str) -> str:
|
||||
return '\n'.join(new)
|
||||
|
||||
|
||||
def get_random_alignment(preset: ColorProfile, asc: str) -> ColorAlignment:
|
||||
"""
|
||||
Generate a fresh random color alignment for the given ascii art.
|
||||
"""
|
||||
slots = sorted(set(map(int, re.findall(r'(?<=\${c)[0-9](?=})', asc))))
|
||||
if not slots:
|
||||
return ColorAlignment("custom", custom_colors={})
|
||||
|
||||
colors = preset.unique_colors().colors
|
||||
if not colors:
|
||||
return ColorAlignment("custom", custom_colors={})
|
||||
|
||||
import random
|
||||
pis = list(range(len(colors)))
|
||||
while len(pis) < len(slots):
|
||||
pis.extend(range(len(colors)))
|
||||
|
||||
random.shuffle(pis)
|
||||
choice = {slot: pis[i] for i, slot in enumerate(slots)}
|
||||
return ColorAlignment("custom", custom_colors=choice)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ColorAlignment:
|
||||
mode: ColorAlignMode
|
||||
@@ -145,6 +167,9 @@ class ColorAlignment:
|
||||
|
||||
:return Colored ascii, Uncolored lines
|
||||
"""
|
||||
if self.mode == 'random':
|
||||
return get_random_alignment(preset, asc).recolor_ascii(asc, preset)
|
||||
|
||||
asc = fill_starting(asc)
|
||||
|
||||
if self.fore_back and self.mode in ['horizontal', 'vertical']:
|
||||
|
||||
@@ -6,5 +6,5 @@ except ImportError:
|
||||
AnsiMode = Literal['default', 'ansi', '8bit', 'rgb']
|
||||
LightDark = Literal['light', 'dark']
|
||||
BackendLiteral = Literal["neofetch", "fastfetch"]
|
||||
ColorAlignMode = Literal['horizontal', 'vertical', 'custom']
|
||||
ColorAlignMode = Literal['horizontal', 'vertical', 'custom', 'random']
|
||||
ColorSpacing = Literal['equal', 'weighted']
|
||||
|
||||
Reference in New Issue
Block a user