Replace ambiguous-width icons that shift sidebar/file rows right
⬆ (U+2B06), 🖼 (U+1F5BC) and ⚙ (U+2699) are East-Asian-Width Neutral: unicode-width measures 1 column but emoji fonts draw 2, so every row containing them shifted right by one column. Replaced with 真 Wide emoji (📷, 🔩, ⚡) or pure text glyphs (↑, ≡), plus a regression test asserting every emoji icon measures 2 columns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,19 +30,24 @@ impl FileEntry {
|
||||
.unwrap_or("")
|
||||
.to_lowercase();
|
||||
match ext.as_str() {
|
||||
// OBS: alla emoji-ikoner MÅSTE vara East-Asian-Width Wide
|
||||
// (mäts som 2 kolumner av unicode-width). Tecken med
|
||||
// EAW=Neutral/Ambiguous (t.ex. 🖼 U+1F5BC, ⚙ U+2699)
|
||||
// mäts som 1 men ritas 2 breda av emoji-fonter →
|
||||
// raden förskjuts åt höger. Se icon_widths-testet.
|
||||
"rs" => "🦀",
|
||||
"png" | "jpg" | "jpeg" | "gif" | "bmp" | "svg" | "webp" | "ico" => "🖼",
|
||||
"png" | "jpg" | "jpeg" | "gif" | "bmp" | "svg" | "webp" | "ico" => "📷",
|
||||
"mp4" | "mkv" | "avi" | "mov" | "webm" => "🎬",
|
||||
"mp3" | "flac" | "ogg" | "wav" | "aac" => "🎵",
|
||||
"zip" | "tar" | "gz" | "bz2" | "xz" | "7z" | "rar" => "📦",
|
||||
"pdf" => "📕",
|
||||
"txt" | "md" | "log" => "📄",
|
||||
"json" | "yaml" | "yml" | "toml" | "xml" => "⚙",
|
||||
"json" | "yaml" | "yml" | "toml" | "xml" => "🔩",
|
||||
"sh" | "bash" | "zsh" | "fish" => "🐚",
|
||||
"py" => "🐍",
|
||||
"js" | "ts" => "📜",
|
||||
"c" | "cpp" | "h" | "hpp" => "🔧",
|
||||
"exe" | "bin" | "out" | "run" => "⚙",
|
||||
"exe" | "bin" | "out" | "run" => "⚡",
|
||||
_ => "📎",
|
||||
}
|
||||
}
|
||||
@@ -294,3 +299,56 @@ pub fn get_root_dirs() -> Vec<PathBuf> {
|
||||
drives
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
fn entry(name: &str, ft: FileType) -> FileEntry {
|
||||
FileEntry {
|
||||
name: name.to_string(),
|
||||
path: PathBuf::from(name),
|
||||
file_type: ft,
|
||||
size: 0,
|
||||
is_hidden: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Alla emoji-ikoner måste vara East-Asian-Width Wide (mäts som
|
||||
/// 2 kolumner av unicode-width). En ikon med EAW=Neutral/Ambiguous
|
||||
/// (t.ex. 🖼 U+1F5BC eller ⚙ U+2699) mäts som 1 men ritas 2 bred av
|
||||
/// emoji-fonter — då förskjuts allt efter ikonen åt höger i UI:t.
|
||||
#[test]
|
||||
fn emoji_icons_are_wide() {
|
||||
let mut samples: Vec<FileEntry> = vec![
|
||||
entry("dir", FileType::Directory),
|
||||
entry("link", FileType::Symlink),
|
||||
];
|
||||
for ext in [
|
||||
"rs", "png", "mp4", "mp3", "zip", "pdf", "txt", "json", "sh",
|
||||
"py", "js", "c", "exe", "unknown",
|
||||
] {
|
||||
samples.push(entry(&format!("f.{}", ext), FileType::File));
|
||||
}
|
||||
for e in &samples {
|
||||
let icon = e.icon();
|
||||
assert_eq!(
|
||||
UnicodeWidthStr::width(icon), 2,
|
||||
"ikonen {:?} (för {:?}) är inte EAW Wide — den kommer \
|
||||
förskjuta raden åt höger i terminaler med emoji-font",
|
||||
icon, e.name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// ASCII-fallback-ikonerna ska alltid vara exakt 3 tecken ([/],
|
||||
/// [s], ...) så att kolumnerna ligger fast i ASCII-läge.
|
||||
#[test]
|
||||
fn ascii_icons_are_three_cols() {
|
||||
let e = entry("f.rs", FileType::File);
|
||||
assert_eq!(UnicodeWidthStr::width(e.icon_ascii()), 3);
|
||||
let d = entry("dir", FileType::Directory);
|
||||
assert_eq!(UnicodeWidthStr::width(d.icon_ascii()), 3);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user