[F] Custom flags - Fix preset search filter collision and selection issues
Some checks failed
Shellcheck / check (push) Has been cancelled

This commit is contained in:
Azalea
2026-10-15 22:45:47 +00:00
parent 371c1356a9
commit 520f3799f1
2 changed files with 82 additions and 30 deletions

View File

@@ -371,7 +371,7 @@ fn prompt_custom_flag(
debug_mode: bool,
) -> Result<String> {
let mut input_text = String::new();
let mut hint: Option<&str> = None;
let mut hint: Option<String> = None;
let mut raw_mode = RawModeGuard::new().context("failed to initialize raw input mode")?;
loop {
@@ -419,13 +419,12 @@ fn prompt_custom_flag(
}
println!("Press Enter to select this flag, or Esc to cancel.");
if let Some(ref h) = hint {
printc(&format!("&c{h}&r\n"), color_mode)?;
}
print!("> {input_text}");
io::stdout().flush().context("failed to flush custom flag prompt")?;
if let Some(h) = hint {
println!("\n{h}");
}
raw_mode
.enable()
.context("failed to enable raw mode for key input")?;
@@ -442,14 +441,36 @@ fn prompt_custom_flag(
match key.code {
KeyCode::Enter => {
let colors = parse_hex_colors(&input_text);
if !colors.is_empty() {
raw_mode
.disable()
.context("failed to disable raw mode after custom flag")?;
return Ok(colors.join(","));
let tokens: Vec<&str> = input_text
.split(|c: char| c.is_whitespace() || c == ',' || c == ';')
.filter(|s| !s.is_empty())
.collect();
if tokens.is_empty() {
hint = Some("Please enter at least one valid hex color (e.g. ff0000).".to_string());
} else {
hint = Some("Please enter at least one valid hex color (e.g. ff0000).");
let mut colors = Vec::new();
let mut invalid_tokens = Vec::new();
for tok in tokens {
let hex = tok.strip_prefix('#').unwrap_or(tok);
if (hex.len() == 3 || hex.len() == 6) && hex.chars().all(|c| c.is_ascii_hexdigit()) {
colors.push(format!("#{hex}"));
} else {
invalid_tokens.push(tok);
}
}
if !invalid_tokens.is_empty() {
hint = Some(format!(
"Invalid hex color(s): {}. Use 3 or 6 hex digits (e.g. ff0000 or #f00).",
invalid_tokens.join(", ")
));
} else {
raw_mode
.disable()
.context("failed to disable raw mode after custom flag")?;
return Ok(colors.join(","));
}
}
}
KeyCode::Backspace => {
@@ -846,7 +867,6 @@ fn create_config(
};
let selected_preset_names: Vec<String>;
let color_profile;
let mut page: usize = 0;
let mut filter = String::new();
@@ -887,17 +907,27 @@ fn create_config(
if parts.is_empty() {
// Default to Rainbow if nothing is entered
resolved_presets.push(Preset::Rainbow.as_ref().to_owned());
} else if filter.contains('#') && !parts.iter().any(|p| flags.iter().any(|(name, _, lower, _)| name.eq_ignore_ascii_case(p) || lower == *p)) {
// Direct hex color input (e.g. "#ff0000, #00ff00" or "#ff0000 #00ff00")
let hex_colors = parse_hex_colors(&filter);
if !hex_colors.is_empty() {
resolved_presets.push(hex_colors.join(","));
} else {
hint = Some("One or more hex colors are invalid.");
}
} else {
for part in parts.iter() {
let hex_colors = parse_hex_colors(part);
if !hex_colors.is_empty() {
resolved_presets.push(hex_colors.join(","));
continue;
if part.contains('#') {
let hex_colors = parse_hex_colors(part);
if !hex_colors.is_empty() {
resolved_presets.push(hex_colors.join(","));
continue;
}
}
let selection = flags
.iter()
.find(|(_, _, name, _)| name == part)
.find(|(name, _, lower, _)| name.eq_ignore_ascii_case(part) || lower == *part)
.map(|(name, _, _, _)| name.clone())
.or_else(|| {
// Fuzzy match each part
@@ -978,13 +1008,13 @@ fn create_config(
PresetValue::Single(selected_preset_names.first().cloned().unwrap_or_else(|| Preset::Rainbow.as_ref().to_owned()))
};
color_profile = {
let color_profile = {
let first_name = selected_preset_names.first().cloned().unwrap_or_else(|| Preset::Rainbow.as_ref().to_owned());
if first_name.contains('#') {
let colors: Vec<String> = first_name.split(',').map(|s| s.trim().to_owned()).collect();
build_hex_color_profile(&colors).expect("hex colors should be valid")
} else {
flags.iter().find(|(_, _, name, _)| name == &first_name).map(|(_, _, _, p)| p.clone()).unwrap_or_else(|| Preset::Rainbow.color_profile())
flags.iter().find(|(name, _, lower, _)| name == &first_name || lower.eq_ignore_ascii_case(&first_name)).map(|(_, _, _, p)| p.clone()).unwrap_or_else(|| Preset::Rainbow.color_profile())
}
};
@@ -994,7 +1024,7 @@ fn create_config(
let colors: Vec<String> = name.split(',').map(|s| s.trim().to_owned()).collect();
build_hex_color_profile(&colors).expect("hex colors should be valid")
} else {
flags.iter().find(|(_, _, n, _)| n == name).map(|(_, _, _, p)| p.clone()).unwrap_or_else(|| Preset::Rainbow.color_profile())
flags.iter().find(|(n, _, lower, _)| n == name || lower.eq_ignore_ascii_case(name)).map(|(_, _, _, p)| p.clone()).unwrap_or_else(|| Preset::Rainbow.color_profile())
};
profile.with_lightness_adaptive(default_lightness, theme)
.color_text(name, color_mode, ForegroundBackground::Foreground, false)

View File

@@ -273,9 +273,10 @@ def create_config() -> Config:
if selection == 'custom':
return 'custom'
parsed = parse_hex_colors(selection)
if parsed:
return ','.join(parsed)
if '#' in selection:
parsed = parse_hex_colors(selection)
if parsed:
return ','.join(parsed)
filtered_indices = filter_flag_indices(selection)
if selection in PRESETS:
@@ -291,6 +292,7 @@ def create_config() -> Config:
from prompt_toolkit.key_binding import KeyBindings
last_input = ''
hint: str | None = None
kb = KeyBindings()
@kb.add('escape')
@@ -326,6 +328,8 @@ def create_config() -> Config:
lines.append("")
lines.append("")
lines.append("Press Enter to select this flag, or Esc / Ctrl+C to cancel.")
if hint:
lines.append(color(f"&c{hint}&r"))
return lines
def prompt_message():
@@ -336,11 +340,12 @@ def create_config() -> Config:
lines = build_custom_lines(raw_input)
return ANSI('\n'.join(lines) + '\n> ')
clear_screen(title)
session = PromptSession(key_bindings=kb)
default_val = ''
while True:
clear_screen(title)
try:
line = session.prompt(prompt_message).strip()
line = session.prompt(prompt_message, default=default_val).strip()
except KeyboardInterrupt:
clear_screen(title)
for l in build_custom_lines(last_input):
@@ -351,10 +356,27 @@ def create_config() -> Config:
if line == '__cancel__':
return 'rainbow'
colors = parse_hex_colors(line)
if colors:
return ','.join(colors)
printc("&cPlease enter at least one valid hex color (e.g. ff0000).")
tokens = [t for t in re.split(r'[,;\s]+', line.strip()) if t]
if not tokens:
hint = "Please enter at least one valid hex color (e.g. ff0000)."
default_val = ''
continue
colors = []
invalid_tokens = []
for tok in tokens:
c = tok.lstrip('#')
if len(c) in (3, 6) and all(ch in '0123456789abcdefABCDEF' for ch in c):
colors.append(f'#{c}')
else:
invalid_tokens.append(tok)
if invalid_tokens:
hint = f"Invalid hex color(s): {', '.join(invalid_tokens)}. Use 3 or 6 hex digits (e.g. ff0000 or #f00)."
default_val = line
continue
return ','.join(colors)
preset = select_preset_prompt_toolkit()
if preset == 'custom':