use anyhow::{anyhow, Result};
pub fn install(binary_path: &str) -> Result<()> {
#[cfg(target_os = "linux")]
return linux::install(binary_path);
#[cfg(target_os = "macos")]
return macos::install(binary_path);
#[cfg(target_os = "windows")]
return windows::install(binary_path);
#[allow(unreachable_code)]
Err(anyhow!("OS non supporté pour l'installation automatique"))
}
pub fn uninstall() -> Result<()> {
#[cfg(target_os = "linux")]
return linux::uninstall();
#[cfg(target_os = "macos")]
return macos::uninstall();
#[cfg(target_os = "windows")]
return windows::uninstall();
#[allow(unreachable_code)]
Err(anyhow!("OS non supporté"))
}
#[cfg(target_os = "linux")]
mod linux {
use anyhow::{anyhow, Result};
use std::path::PathBuf;
fn apps_dir() -> PathBuf {
dirs::data_dir()
.unwrap_or_else(|| {
PathBuf::from(std::env::var("HOME").unwrap_or_default()).join(".local/share")
})
.join("applications")
}
fn desktop_path() -> PathBuf {
apps_dir().join("portal-nvim-handler.desktop")
}
pub fn install(binary: &str) -> Result<()> {
let dir = apps_dir();
std::fs::create_dir_all(&dir)?;
let content = format!(
"[Desktop Entry]\n\
Name=Neovim URI Handler (portal.nvim)\n\
Comment=Ouvre des fichiers dans Neovim via nvim:// URIs\n\
Exec={} open %u\n\
Type=Application\n\
NoDisplay=true\n\
MimeType=x-scheme-handler/nvim;\n",
binary
);
std::fs::write(desktop_path(), &content)?;
std::process::Command::new("xdg-mime")
.args([
"default",
"portal-nvim-handler.desktop",
"x-scheme-handler/nvim",
])
.status()
.map_err(|e| anyhow!("xdg-mime échoué : {}", e))?;
std::process::Command::new("update-desktop-database")
.arg(&dir)
.status()
.ok();
Ok(())
}
pub fn uninstall() -> Result<()> {
let _ = std::fs::remove_file(desktop_path());
std::process::Command::new("update-desktop-database")
.arg(apps_dir())
.status()
.ok();
Ok(())
}
}
#[cfg(target_os = "macos")]
mod macos {
use anyhow::{anyhow, Result};
use std::path::PathBuf;
fn app_path() -> PathBuf {
PathBuf::from(std::env::var("HOME").unwrap_or_default())
.join("Applications/PortalNvimHandler.app")
}
fn lsregister() -> &'static str {
"/System/Library/Frameworks/CoreServices.framework\
/Versions/A/Frameworks/LaunchServices.framework\
/Versions/A/Support/lsregister"
}
pub fn install(binary: &str) -> Result<()> {
let app = app_path();
std::fs::create_dir_all(app.join("Contents/MacOS"))?;
let launcher = app.join("Contents/MacOS/PortalNvimHandler");
std::fs::write(
&launcher,
format!("#!/bin/sh\nexec \"{}\" open \"$@\"\n", binary),
)?;
std::process::Command::new("chmod")
.args(["+x", launcher.to_str().unwrap_or("")])
.status()?;
let plist = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key><string>com.portal-nvim-handler</string>
<key>CFBundleName</key><string>PortalNvimHandler</string>
<key>CFBundleExecutable</key><string>PortalNvimHandler</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleURLTypes</key>
<array><dict>
<key>CFBundleURLName</key><string>Neovim URI</string>
<key>CFBundleURLSchemes</key><array><string>nvim</string></array>
</dict></array>
<key>LSUIElement</key><true/>
</dict>
</plist>"#
);
std::fs::write(app.join("Contents/Info.plist"), plist)?;
std::process::Command::new(lsregister())
.args(["-f", app.to_str().unwrap_or("")])
.status()
.map_err(|e| anyhow!("lsregister échoué : {}", e))?;
Ok(())
}
pub fn uninstall() -> Result<()> {
let app = app_path();
std::process::Command::new(lsregister())
.args(["-u", app.to_str().unwrap_or("")])
.status()
.ok();
let _ = std::fs::remove_dir_all(&app);
Ok(())
}
}
#[cfg(target_os = "windows")]
mod windows {
use anyhow::{anyhow, Result};
pub fn install(binary: &str) -> Result<()> {
let entries = [
(
"HKCU\\Software\\Classes\\nvim",
vec!["/ve", "/d", "URL:nvim Protocol"],
),
(
"HKCU\\Software\\Classes\\nvim",
vec!["/v", "URL Protocol", "/d", ""],
),
];
for (key, args) in &entries {
let mut cmd = std::process::Command::new("reg");
cmd.args(["add", key, "/f"]);
for a in args {
cmd.arg(a);
}
let status = cmd.status().map_err(|e| anyhow!("reg.exe : {}", e))?;
if !status.success() {
return Err(anyhow!("reg.exe a échoué pour {}", key));
}
}
let open_value = format!("\"{}\" open \"%1\"", binary);
std::process::Command::new("reg")
.args([
"add",
"HKCU\\Software\\Classes\\nvim\\shell\\open\\command",
"/f",
"/ve",
"/d",
&open_value,
])
.status()
.map_err(|e| anyhow!("reg.exe : {}", e))?;
Ok(())
}
pub fn uninstall() -> Result<()> {
std::process::Command::new("reg")
.args(["delete", "HKCU\\Software\\Classes\\nvim", "/f"])
.status()
.ok();
Ok(())
}
}