use crate::define_tool;
use crate::tools::common::{InstallError, has, run};
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
use crate::tools::pinned_binary_installer::AppImagePin;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
const CURSOR_LINUX_X64_URL: &str = "https://downloads.cursor.com/production/e56ad3440df06d22ca7501e65fd518e905486ef7/linux/x64/Cursor-3.8.11-x86_64.AppImage";
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
const CURSOR_LINUX_X64_SHA256: &str =
"2bc3003ea81ce99a2458101478b15409c4cb8271577bd9cb941e8aaeae8a391a";
define_tool!(CURSOR, {
command: "cursor",
macos: { cask: "cursor" },
windows: { winget: "Cursor.Cursor" },
custom_install: install_cursor,
});
fn install_cursor(_min_hint: &str) -> Result<(), InstallError> {
if has("cursor") {
return Ok(());
}
#[cfg(target_os = "macos")]
{
if !has("brew") {
return Err(InstallError::Prereq(
"Homebrew not found. Install https://brew.sh and re-run.",
));
}
run("brew", &["install", "--cask", "cursor"])?;
return Ok(());
}
#[cfg(target_os = "linux")]
{
#[cfg(not(target_arch = "x86_64"))]
{
return Err(InstallError::Unsupported);
}
#[cfg(target_arch = "x86_64")]
{
let installer = AppImagePin {
name: "cursor",
url: CURSOR_LINUX_X64_URL,
sha256: CURSOR_LINUX_X64_SHA256,
};
run("sh", &["-c", &installer.shell_command()])?;
return Ok(());
}
}
#[cfg(target_os = "windows")]
{
if !has("winget") {
return Err(InstallError::Prereq(
"winget not found. Install Windows Package Manager, then re-run.",
));
}
run("winget", &["install", "-e", "--id", "Cursor.Cursor"])?;
return Ok(());
}
#[allow(unreachable_code)]
Err(InstallError::Unsupported)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cursor_registration_shape() {
assert_eq!(CURSOR.command, "cursor");
let mac = CURSOR.macos.expect("must support macOS");
assert_eq!(mac.cask, Some("cursor"));
let win = CURSOR.windows.expect("must support Windows");
assert_eq!(win.winget, Some("Cursor.Cursor"));
assert!(CURSOR.linux.is_none());
assert!(CURSOR.custom_install.is_some());
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[test]
fn linux_pin_is_well_formed() {
assert_eq!(CURSOR_LINUX_X64_SHA256.len(), 64);
assert!(
CURSOR_LINUX_X64_SHA256
.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase())
);
assert!(CURSOR_LINUX_X64_URL.starts_with("https://"));
assert!(!CURSOR_LINUX_X64_URL.contains("/latest/"));
}
}