From ddbb1f052d1ddbee1b44186b3f358559f8dd54f8 Mon Sep 17 00:00:00 2001 From: Newbyte Date: Tue, 6 Sep 2022 15:20:40 +0200 Subject: [PATCH] Use host shell in terminal when running inside Flatpak --- lapce-proxy/src/terminal.rs | 83 ++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/lapce-proxy/src/terminal.rs b/lapce-proxy/src/terminal.rs index fb712a19..f9866151 100644 --- a/lapce-proxy/src/terminal.rs +++ b/lapce-proxy/src/terminal.rs @@ -55,14 +55,38 @@ pub fn new( BaseDirs::new().map(|d| PathBuf::from(d.home_dir())) }; let shell = shell.trim(); - if !shell.is_empty() { + let inside_flatpak = is_inside_flatpak(); + + if !shell.is_empty() || inside_flatpak { let mut parts = shell.split(' '); - let program = parts.next().unwrap(); - if let Ok(p) = which::which(program) { + + if inside_flatpak { + let flatpak_spawn_path = "/usr/bin/flatpak-spawn".to_string(); + let host_shell = flatpak_get_default_host_shell(); + + let args = if shell.is_empty() { + vec!["--host".to_string(), host_shell] + } else { + vec![ + "--host".to_string(), + host_shell, + "-c".to_string(), + shell.to_string(), + ] + }; + config.pty_config.shell = Some(Program::WithArgs { - program: p.to_str().unwrap().to_string(), - args: parts.map(|p| p.to_string()).collect::>(), + program: flatpak_spawn_path, + args, }) + } else { + let program = parts.next().unwrap(); + if let Ok(p) = which::which(program) { + config.pty_config.shell = Some(Program::WithArgs { + program: p.to_str().unwrap().to_string(), + args: parts.map(|p| p.to_string()).collect::>(), + }) + } } } setup_env(&config); @@ -307,3 +331,52 @@ fn set_locale_environment() { .replace('-', "_"); std::env::set_var("LC_ALL", locale + ".UTF-8"); } + +#[cfg(not(target_os = "linux"))] +fn flatpak_get_default_host_shell() -> String { + panic!( + "This should never be reached. If it is, ensure you don't have a file + called .flatpak-info in your root directory" + ); +} + +#[cfg(target_os = "linux")] +fn flatpak_get_default_host_shell() -> String { + use std::process::Command; + + let env_string = Command::new("flatpak-spawn") + .arg("--host") + .arg("printenv") + .output() + .unwrap() + .stdout; + + let env_string = String::from_utf8(env_string).unwrap(); + + for env_pair in env_string.split('\n') { + let name_value: Vec<&str> = env_pair.split('=').collect(); + + if name_value[0] == "SHELL" { + return name_value[1].to_string(); + } + } + + // In case SHELL isn't set for whatever reason, fall back to this + "/bin/sh".to_string() +} + +#[cfg(not(target_os = "linux"))] +fn is_inside_flatpak() -> bool { + false // Flatpak is only available on Linux +} + +#[cfg(target_os = "linux")] +fn is_inside_flatpak() -> bool { + use std::path::Path; + + const FLATPAK_INFO_PATH: &str = "/.flatpak-info"; + + /* The de-facto way of checking whether one is inside of a Flatpak container is by checking for + the presence of /.flatpak-info in the filesystem */ + Path::new(FLATPAK_INFO_PATH).exists() +}