diff --git a/src/tab.rs b/src/tab.rs index 93e95e2..86c4524 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -9,11 +9,14 @@ use cosmic_text::{Attrs, Buffer, Cursor, Edit, Selection, Shaping, SyntaxEditor, use notify::Watcher; use regex::Regex; use std::{ + io::Write, fs, path::PathBuf, + process::{Command, Stdio}, sync::{Arc, Mutex}, }; + use crate::{fl, git::GitDiff, Config, SYNTAX_SYSTEM}; pub enum Tab { @@ -45,7 +48,7 @@ pub struct EditorTab { impl EditorTab { pub fn new(config: &Config) -> Self { //TODO: do not repeat, used in App::init - let attrs = cosmic_text::Attrs::new().family(cosmic_text::Family::Monospace); + let attrs = Attrs::new().family(cosmic_text::Family::Monospace); let mut buffer = Buffer::new_empty(config.metrics()); buffer.set_text( @@ -144,26 +147,65 @@ impl EditorTab { } pub fn save(&mut self) { - if let Some(path) = &self.path_opt { - let mut editor = self.editor.lock().unwrap(); - let mut text = String::new(); - editor.with_buffer(|buffer| { - for line in buffer.lines.iter() { - text.push_str(line.text()); - text.push_str(line.ending().as_str()); - } - }); - match fs::write(path, text) { - Ok(()) => { - editor.save_point(); - log::info!("saved {:?}", path); - } - Err(err) => { - log::error!("failed to save {:?}: {}", path, err); + if let Some(path) = &self.path_opt { + let mut editor = self.editor.lock().unwrap(); + let mut text = String::new(); + + editor.with_buffer(|buffer| { + for line in buffer.lines.iter() { + text.push_str(line.text()); + text.push_str(line.ending().as_str()); + } + }); + + match fs::write(path, &text) { + Ok(()) => { + editor.save_point(); + log::info!("saved {:?}", path); + } + Err(err) => { + if err.kind() == std::io::ErrorKind::PermissionDenied { + log::warn!("Permission denied. Attempting to save with pkexec."); + + if let Ok(mut output) = Command::new("pkexec") + .arg("tee") + .arg(path) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) // Redirect stdout to /dev/null + .stderr(Stdio::inherit()) // Retain stderr for error visibility + .spawn() + { + if let Some(mut stdin) = output.stdin.take() { + if let Err(e) = stdin.write_all(text.as_bytes()) { + log::error!("Failed to write to stdin: {}", e); + } + } else { + log::error!("Failed to access stdin of pkexec process."); + } + + // Ensure the child process is reaped + match output.wait() { + Ok(status) => { + if status.success() { + // Mark the editor's state as saved if the process succeeds + editor.save_point(); + log::info!("File saved successfully with pkexec."); + } else { + log::error!("pkexec process exited with a non-zero status: {:?}", status); + } + } + Err(e) => { + log::error!("Failed to wait on pkexec process: {}", e); + } + } + } else { + log::error!("Failed to spawn pkexec process. Check permissions or path."); + } } } - } else { - log::warn!("tab has no path yet"); + } + } else { + log::warn!("tab has no path yet"); } }