feat(io): FILEASSOC command to toggle file association on/off (#205)
`FILEASSOC 1` (re)registers the app as a .dwg/.dxf/.bak handler; `FILEASSOC 0` unregisters it (removes the .desktop + CAD mime package on Linux, the per-user registry keys on Windows); bare `FILEASSOC` reports the current state. The choice persists (file_assoc_enabled) and gates the every-launch re-registration, so turning it off stays off across restarts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
962268e16e
commit
9ea800f049
5 changed files with 113 additions and 4 deletions
|
|
@ -60,6 +60,27 @@ pub fn register_as_handler() -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Remove this app's file-handler registration (the inverse of
|
||||
/// [`register_as_handler`]) so it no longer claims .dwg/.dxf/.bak. Best-effort.
|
||||
pub fn unregister_handler() -> Result<(), String> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
windows_impl::unregister_handler()
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
linux_impl::unregister_handler()
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to make this app the default handler for .dwg and .dxf. Returns a short
|
||||
/// human-readable status string on success, or an error message on failure.
|
||||
pub async fn set_default_app() -> Result<String, String> {
|
||||
|
|
@ -189,10 +210,29 @@ mod windows_impl {
|
|||
}
|
||||
|
||||
use windows_sys::Win32::System::Registry::{
|
||||
RegCloseKey, RegCreateKeyExW, RegSetValueExW, HKEY, HKEY_CURRENT_USER,
|
||||
RegCloseKey, RegCreateKeyExW, RegDeleteTreeW, RegSetValueExW, HKEY, HKEY_CURRENT_USER,
|
||||
KEY_WRITE, REG_OPTION_NON_VOLATILE, REG_SZ,
|
||||
};
|
||||
|
||||
/// Remove the per-user keys this app created — undoes [`register_handler`].
|
||||
/// Best-effort: leaves the shared `.dwg/.dxf/.bak` OpenWithProgids values
|
||||
/// (they point at now-deleted ProgIDs, which Windows simply ignores).
|
||||
pub(super) fn unregister_handler() -> Result<(), String> {
|
||||
for key in [
|
||||
r"Software\Classes\Applications\OpenCADStudio.exe",
|
||||
r"Software\Classes\OpenCADStudio.DWG",
|
||||
r"Software\Classes\OpenCADStudio.DXF",
|
||||
r"Software\Classes\OpenCADStudio.BAK",
|
||||
r"Software\Open CAD Studio",
|
||||
] {
|
||||
let w = wide(key);
|
||||
unsafe {
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, w.as_ptr());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wide(s: &str) -> Vec<u16> {
|
||||
std::ffi::OsStr::new(s).encode_wide().chain(Some(0)).collect()
|
||||
}
|
||||
|
|
@ -395,6 +435,23 @@ mod linux_impl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the .desktop entry and the CAD mime package, then refresh the
|
||||
/// caches — undoes [`register_handler`]. Best-effort; missing files are fine.
|
||||
pub(super) fn unregister_handler() -> Result<(), String> {
|
||||
let apps = data_home()?.join("applications");
|
||||
let _ = std::fs::remove_file(apps.join(format!("{APP_ID}.desktop")));
|
||||
let _ = std::process::Command::new("update-desktop-database")
|
||||
.arg(&apps)
|
||||
.status();
|
||||
|
||||
let home = data_home()?;
|
||||
let _ = std::fs::remove_file(home.join("mime/packages").join(format!("{APP_ID}-cad.xml")));
|
||||
let _ = std::process::Command::new("update-mime-database")
|
||||
.arg(home.join("mime"))
|
||||
.status();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Install a high-priority shared-mime-info magic rule so DWG/DXF *content*
|
||||
/// is recognised regardless of extension. Without it a `.bak` copy matches
|
||||
/// the freedesktop `*.bak` glob (application/x-trash) and never reaches us;
|
||||
|
|
|
|||
Loading…
Reference in a new issue