multicall: auto-select MIME type more intelligently when not specified

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Idfd5ab25079161d694bda429e70500a16a6a6964
This commit is contained in:
raf 2025-12-23 10:09:47 +03:00
commit f2274aa524
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -358,12 +358,74 @@ fn execute_watch_command(
Ok(())
}
/// Select the best MIME type from available types when none is specified.
/// Prefers specific content types (image/*, application/*) over generic
/// text representations (TEXT, STRING, UTF8_STRING).
fn select_best_mime_type(
types: &std::collections::HashSet<String>,
) -> Option<String> {
if types.is_empty() {
return None;
}
// If only one type available, use it
if types.len() == 1 {
return types.iter().next().cloned();
}
// Prefer specific MIME types with slashes (e.g., image/png, application/pdf)
// over generic X11 selections (TEXT, STRING, UTF8_STRING)
let specific_types: Vec<_> =
types.iter().filter(|t| t.contains('/')).collect();
if !specific_types.is_empty() {
// Among specific types, prefer non-text types first
for mime in &specific_types {
if !mime.starts_with("text/") {
return Some((*mime).clone());
}
}
// If all are text types, prefer text/plain with charset
for mime in &specific_types {
if mime.starts_with("text/plain;charset=") {
return Some((*mime).clone());
}
}
// Otherwise return first specific type
return Some(specific_types[0].clone());
}
// Fall back to generic text selections in order of preference
for fallback in &["UTF8_STRING", "STRING", "TEXT"] {
if types.contains(*fallback) {
return Some((*fallback).to_string());
}
}
// Last resort: return any available type
types.iter().next().cloned()
}
fn handle_regular_paste(
args: &WlPasteArgs,
clipboard: PasteClipboardType,
seat: PasteSeat,
) -> Result<()> {
let mime_type = get_paste_mime_type(args.mime_type.as_deref());
// If no MIME type specified, select the best available MIME type
let available_types = if args.mime_type.is_none() {
get_mime_types(clipboard, seat).ok()
} else {
None
};
let selected_type = available_types.as_ref().and_then(select_best_mime_type);
let mime_type = if let Some(ref best) = selected_type {
log::debug!("Auto-selecting MIME type: {}", best);
PasteMimeType::Specific(best)
} else {
get_paste_mime_type(args.mime_type.as_deref())
};
match get_contents(clipboard, seat, mime_type) {
Ok((mut reader, types)) => {
@ -409,10 +471,12 @@ fn handle_regular_paste(
std::str::from_utf8(&buf).is_ok()
};
if !args.no_newline && is_text_content && !buf.ends_with(b"\n") {
if let Err(e) = out.write_all(b"\n") {
bail!("failed to write newline to stdout: {e}");
}
if !args.no_newline
&& is_text_content
&& !buf.ends_with(b"\n")
&& let Err(e) = out.write_all(b"\n")
{
bail!("failed to write newline to stdout: {e}");
}
},
Err(PasteError::NoSeats) => {