🌈 Support custom ASCII art file path (#429)

* Feature: Add custom ascii file saving to python version of hyfetch

* Feature: Add custom ascii file saving to rust version of hyfetch

* [-] Remove test ascii

---------

Co-authored-by: Azalea <22280294+hykilpikonna@users.noreply.github.com>
This commit is contained in:
ObsoleteDev 2025-10-01 16:12:05 +01:00 committed by GitHub
parent 3f41cb40e2
commit fc9292be3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 126 additions and 3 deletions

View file

@ -149,7 +149,14 @@ fn main() -> Result<()> {
}; };
debug!(?color_profile, "lightened color profile"); debug!(?color_profile, "lightened color profile");
let asc = if let Some(path) = options.ascii_file { let asc = if let Some(path_str) = config.custom_ascii_path {
let path = PathBuf::from(path_str);
RawAsciiArt {
asc: fs::read_to_string(&path)
.with_context(|| format!("failed to read ascii from {path:?}"))?,
fg: Vec::new(),
}
} else if let Some(path) = options.ascii_file {
RawAsciiArt { RawAsciiArt {
asc: fs::read_to_string(&path) asc: fs::read_to_string(&path)
.with_context(|| format!("failed to read ascii from {path:?}"))?, .with_context(|| format!("failed to read ascii from {path:?}"))?,
@ -1078,6 +1085,73 @@ fn create_config(
backend.as_ref(), backend.as_ref(),
); );
//////////////////////////////
// 8. Custom ASCII file
let mut custom_ascii_path: Option<String> = None;
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
let choice = literal_input(
"Do you want to specify a custom ASCII file?",
&["y", "n"],
"n",
true,
color_mode,
)
.context("failed to ask for choice input")?;
if choice == "y" {
loop {
let path_input = input(Some("Path to custom ASCII file (must be .txt and UTF-8 encoded): "))
.context("failed to read input")?
.trim()
.to_owned();
if path_input.is_empty() {
printc("&cNo path entered. Skipping custom ASCII file.", color_mode).context("failed to print message")?;
break;
}
let custom_path = PathBuf::from(&path_input);
if !custom_path.is_file() {
printc(format!("&cError: File not found at {path_input}"), color_mode).context("failed to print message")?;
let try_again = literal_input("Try again?", &["y", "n"], "y", true, color_mode).context("failed to ask for choice input")?;
if try_again == "n" {
break;
}
continue;
}
if custom_path.extension().map_or(true, |ext| ext != "txt") {
printc(format!("&cError: File must have a .txt extension. Found {:?}", custom_path.extension()), color_mode).context("failed to print message")?;
let try_again = literal_input("Try again?", &["y", "n"], "y", true, color_mode).context("failed to ask for choice input")?;
if try_again == "n" {
break;
}
continue;
}
match fs::read_to_string(&custom_path) {
Ok(_) => {
custom_ascii_path = Some(path_input);
update_title(
&mut title,
&mut option_counter,
"Custom ASCII file",
custom_ascii_path.as_ref().unwrap(),
);
break;
}
Err(e) => {
printc(format!("&cError: File is not UTF-8 encoded or an unexpected error occurred: {e}"), color_mode).context("failed to print message")?;
let try_again = literal_input("Try again?", &["y", "n"], "y", true, color_mode).context("failed to ask for choice input")?;
if try_again == "n" {
break;
}
continue;
}
}
}
}
// Create config // Create config
clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?; clear_screen(Some(&title), color_mode, debug_mode).context("failed to clear screen")?;
let config = Config { let config = Config {
@ -1091,6 +1165,7 @@ fn create_config(
args: None, args: None,
distro: logo_chosen, distro: logo_chosen,
pride_month_disable: false, pride_month_disable: false,
custom_ascii_path,
}; };
debug!(?config, "created config"); debug!(?config, "created config");

View file

@ -19,6 +19,7 @@ pub struct Config {
pub args: Option<Vec<String>>, pub args: Option<Vec<String>>,
pub distro: Option<String>, pub distro: Option<String>,
pub pride_month_disable: bool, pub pride_month_disable: bool,
pub custom_ascii_path: Option<String>,
} }
impl Config { impl Config {

View file

@ -5,6 +5,7 @@ import argparse
import datetime import datetime
import importlib.util import importlib.util
import json import json
import os
import random import random
import traceback import traceback
from itertools import permutations, islice from itertools import permutations, islice
@ -318,9 +319,49 @@ def create_config() -> Config:
backend = select_backend() backend = select_backend()
update_title('Selected backend', backend) update_title('Selected backend', backend)
##############################
# 7. Custom ASCII file
custom_ascii_path = None
clear_screen(title)
if literal_input('Do you want to specify a custom ASCII file?', ['y', 'n'], 'n') == 'y':
while True:
path_input = input('Path to custom ASCII file (must be .txt and UTF-8 encoded): ').strip()
if not path_input:
printc('&cNo path entered. Skipping custom ASCII file.')
break
custom_path = Path(path_input)
if not custom_path.is_file():
printc(f'&cError: File not found at {path_input}')
if literal_input('Try again?', ['y', 'n'], 'y') == 'n':
break
continue
if not custom_path.suffix == '.txt':
printc(f'&cError: File must have a .txt extension. Found {custom_path.suffix}')
if literal_input('Try again?', ['y', 'n'], 'y') == 'n':
break
continue
try:
custom_path.read_text('utf-8')
custom_ascii_path = str(custom_path)
update_title('Custom ASCII file', custom_ascii_path)
break
except UnicodeDecodeError:
printc(f'&cError: File is not UTF-8 encoded.')
if literal_input('Try again?', ['y', 'n'], 'y') == 'n':
break
continue
except Exception as e:
printc(f'&cAn unexpected error occurred: {e}')
if literal_input('Try again?', ['y', 'n'], 'y') == 'n':
break
continue
# Create config # Create config
clear_screen(title) clear_screen(title)
c = Config(preset, color_system, light_dark, lightness, color_alignment, backend) c = Config(preset, color_system, light_dark, lightness, color_alignment, backend, custom_ascii_path=custom_ascii_path)
# Save config # Save config
print() print()
@ -463,7 +504,12 @@ def run():
# Run # Run
try: try:
asc = get_distro_ascii() if not args.ascii_file else Path(args.ascii_file).read_text("utf-8") if config.custom_ascii_path:
asc = Path(config.custom_ascii_path).read_text("utf-8")
elif args.ascii_file:
asc = Path(args.ascii_file).read_text("utf-8")
else:
asc = get_distro_ascii()
asc = config.color_align.recolor_ascii(asc, preset) asc = config.color_align.recolor_ascii(asc, preset)
asc = '\n'.join(asc.split('\n')[1:]) asc = '\n'.join(asc.split('\n')[1:])
neofetch_util.run(asc, config.backend, config.args or '') neofetch_util.run(asc, config.backend, config.args or '')

View file

@ -20,6 +20,7 @@ class Config:
distro: str | None = None distro: str | None = None
pride_month_shown: list[int] = field(default_factory=list) # This is deprecated, see issue #136 pride_month_shown: list[int] = field(default_factory=list) # This is deprecated, see issue #136
pride_month_disable: bool = False pride_month_disable: bool = False
custom_ascii_path: str | None = None
@classmethod @classmethod
def from_dict(cls, d: dict): def from_dict(cls, d: dict):