Files
ElyOffice/crates/ely-platform/src/user.rs
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

69 lines
2.1 KiB
Rust

//! The name documents sign new comments and changes with.
use std::io;
/// The author name from settings, else the account's.
pub fn name() -> io::Result<String> {
let set = crate::settings::Shared::load()?.author;
if !set.is_empty() {
return Ok(set);
}
account()
}
/// The account's full name, else its login name.
pub fn account() -> io::Result<String> {
let full = full_name()?;
if !full.trim().is_empty() {
return Ok(full.trim().to_string());
}
let key = if cfg!(windows) { "USERNAME" } else { "USER" };
log::info!("user: no full name; the login name signs");
std::env::var(key).map_err(|error| io::Error::other(format!("no {key}: {error}")))
}
#[cfg(target_os = "macos")]
fn full_name() -> io::Result<String> {
Ok(objc2_foundation::NSFullUserName().to_string())
}
#[cfg(target_os = "linux")]
fn full_name() -> io::Result<String> {
// The first comma field of the passwd comment.
let entry = unsafe { libc::getpwuid(libc::getuid()) };
if entry.is_null() {
return Err(io::Error::last_os_error());
}
let gecos = unsafe { (*entry).pw_gecos };
if gecos.is_null() {
return Ok(String::new());
}
let text = unsafe { std::ffi::CStr::from_ptr(gecos) }.to_string_lossy();
Ok(text.split(',').next().unwrap_or_default().to_string())
}
#[cfg(windows)]
fn full_name() -> io::Result<String> {
use windows_sys::Win32::Security::Authentication::Identity::{GetUserNameExW, NameDisplay};
let mut size = 0u32;
unsafe { GetUserNameExW(NameDisplay, std::ptr::null_mut(), &mut size) };
// Accounts outside a domain have no display name.
if size == 0 {
return Ok(String::new());
}
let mut buffer = vec![0u16; size as usize];
if unsafe { GetUserNameExW(NameDisplay, buffer.as_mut_ptr(), &mut size) } == 0 {
return Err(io::Error::last_os_error());
}
Ok(String::from_utf16_lossy(&buffer[..size as usize]))
}
#[cfg(test)]
mod tests {
#[test]
fn the_account_has_a_name() {
let name = super::name().expect("a name");
assert!(!name.is_empty());
}
}