Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/IPC/WindServiceHandlers/NativeHost/
InstallShellCommand.rs

1#![allow(non_snake_case)]
2
3//! `nativeHost:installShellCommand` - create a `land` (or `code`) symlink in
4//! `/usr/local/bin` pointing at the running executable so the user can launch
5//! the editor from a terminal. Mirrors VS Code's "Install 'code' command in
6//! PATH" command. Uses `pkexec`/`osascript` to acquire elevated privileges
7//! when `/usr/local/bin` is not writable by the current user.
8
9use std::path::PathBuf;
10
11use serde_json::Value;
12
13use crate::dev_log;
14
15const CLI_NAME:&str = "land";
16
17const SYMLINK_DIR:&str = "/usr/local/bin";
18
19pub async fn InstallShellCommand(_Arguments:Vec<Value>) -> Result<Value, String> {
20	let ExePath = std::env::current_exe().map_err(|E| format!("installShellCommand: cannot get exe path: {E}"))?;
21
22	let Target = PathBuf::from(SYMLINK_DIR).join(CLI_NAME);
23
24	dev_log!("shell-cmd", "installShellCommand: {} → {}", Target.display(), ExePath.display());
25
26	// Remove stale link first (ignore errors - may not exist yet).
27	let _ = std::fs::remove_file(&Target);
28
29	match std::os::unix::fs::symlink(&ExePath, &Target) {
30		Ok(()) => {
31			dev_log!("shell-cmd", "installShellCommand: symlink created");
32
33			Ok(Value::Bool(true))
34		},
35
36		Err(E) if E.kind() == std::io::ErrorKind::PermissionDenied => {
37			// Retry with osascript-elevated write on macOS.
38			#[cfg(target_os = "macos")]
39			{
40				let Script = format!(
41					"do shell script \"ln -sf '{}' '{}'\" with administrator privileges",
42					ExePath.display(),
43					Target.display()
44				);
45
46				let Status = tokio::process::Command::new("osascript")
47					.args(["-e", &Script])
48					.status()
49					.await
50					.map_err(|E| format!("installShellCommand: osascript failed: {E}"))?;
51
52				if Status.success() {
53					dev_log!("shell-cmd", "installShellCommand: symlink created (elevated)");
54
55					return Ok(Value::Bool(true));
56				}
57			}
58
59			Err(format!("installShellCommand: permission denied and elevation failed"))
60		},
61
62		Err(E) => Err(format!("installShellCommand: {E}")),
63	}
64}