Merge #474: M7: find Unix user fonts under XDG_DATA_HOME (@IanHollow)

This commit is contained in:
bflatastic
2026-10-15 19:33:06 +07:00
3 changed files with 47 additions and 4 deletions
+17 -4
View File
@@ -696,14 +696,27 @@ fn system_font_dirs() -> Vec<std::path::PathBuf> {
{
v.push("/usr/share/fonts".into());
v.push("/usr/local/share/fonts".into());
if let Some(h) = std::env::var_os("HOME") {
v.push(std::path::PathBuf::from(&h).join(".fonts"));
v.push(std::path::PathBuf::from(h).join(".local/share/fonts"));
}
v.extend(unix_user_font_dirs(std::env::var_os("HOME"), std::env::var_os("XDG_DATA_HOME")));
}
v
}
// Fontconfig's default configuration uses $XDG_DATA_HOME/fonts for user fonts.
// Ignore relative XDG paths, as required by the XDG Base Directory Specification.
#[cfg(all(unix, not(target_os = "macos")))]
fn unix_user_font_dirs(home: Option<std::ffi::OsString>, data_home: Option<std::ffi::OsString>) -> Vec<std::path::PathBuf> {
let home = home.map(std::path::PathBuf::from);
let data = data_home.map(std::path::PathBuf::from).filter(|p| p.is_absolute()).or_else(|| home.as_ref().map(|h| h.join(".local/share")));
let mut dirs = Vec::new();
if let Some(home) = home {
dirs.push(home.join(".fonts"));
}
if let Some(data) = data {
dirs.push(data.join("fonts"));
}
dirs
}
fn scan_dir(dir: &std::path::Path, depth: usize, out: &mut BTreeMap<String, (String, Vec<Pending>)>) {
if depth > 6 {
return;
+26
View File
@@ -67,3 +67,29 @@ fn the_scan_reads_names_like_a_whole_file_read() {
assert_eq!(faces_in(&index_bytes(&p, whole.len()).unwrap()), faces_in(&whole), "{}", p.display());
}
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn user_font_dirs_follow_xdg_data_home() {
use std::ffi::OsString;
use std::path::PathBuf;
let dirs = |home: Option<&str>, data: Option<&str>| unix_user_font_dirs(home.map(OsString::from), data.map(OsString::from));
let paths = |items: &[&str]| items.iter().map(PathBuf::from).collect::<Vec<_>>();
assert_eq!(dirs(Some("/home/user"), Some("/custom user data")), paths(&["/home/user/.fonts", "/custom user data/fonts"]));
for data in [None, Some(""), Some("relative/data")] {
assert_eq!(dirs(Some("/home/user"), data), paths(&["/home/user/.fonts", "/home/user/.local/share/fonts"]));
}
assert_eq!(dirs(None, Some("/custom-data")), paths(&["/custom-data/fonts"]));
assert_eq!(dirs(None, None), paths(&[]));
assert_eq!(dirs(None, Some("relative")), paths(&[]));
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn user_font_dirs_preserve_non_utf8_paths() {
use std::ffi::OsString;
use std::os::unix::ffi::{OsStrExt, OsStringExt};
let dirs = unix_user_font_dirs(Some(OsString::from_vec(b"/home/\xff".to_vec())), Some(OsString::from_vec(b"/data/\xfe".to_vec())));
assert_eq!(dirs[0].as_os_str().as_bytes(), b"/home/\xff/.fonts");
assert_eq!(dirs[1].as_os_str().as_bytes(), b"/data/\xfe/fonts");
}
+4
View File
@@ -15,6 +15,10 @@ Every subcommand takes `--no-system-fonts` (or set `FIGCRAFT_NO_SYSTEM_FONTS=1`,
app honours too) to use only the built-in fonts, for renders that come out the same on every
machine, e.g. in CI.
On Linux and other Unix systems except macOS, user fonts are read from
`$XDG_DATA_HOME/fonts`, or `$HOME/.local/share/fonts` when `XDG_DATA_HOME` is unset,
empty or relative. The legacy `$HOME/.fonts` directory is also scanned.
The collaboration server is a binary of its own, `figcraft-server` (`cargo build --release -p
figcraft-server`): it keeps files with share links and serves their live sessions, and its
`key`, `files`, `links`, `reports`, `block-ip` and `check` subcommands manage them (a server can