open_editor/
editor.rs

1use std::{ffi::OsString, path::PathBuf};
2
3use crate::{editor_kind::EditorKind, errors::OpenEditorError};
4
5#[derive(Debug, Clone)]
6/// Represents an editor instance with its type and binary path.
7pub struct Editor {
8    pub(crate) editor_type: EditorKind,
9    pub(crate) binary_path: PathBuf,
10}
11
12impl Editor {
13    /// Creates a new `Editor` instance from a binary path. The editor type is set to `UnknownEditor`.
14    #[must_use]
15    pub fn from_bin_path(binary_path: PathBuf) -> Self {
16        Self {
17            editor_type: EditorKind::UnknownEditor,
18            binary_path,
19        }
20    }
21    /// Creates a new `Editor` instance from an editor kind. The binary path is determined using the `which` crate.
22    #[must_use]
23    pub fn from_editor_kind(editor_type: EditorKind) -> Self {
24        let binary_path = Self::get_full_path(editor_type.to_string().into());
25        Self {
26            editor_type,
27            binary_path,
28        }
29    }
30    /// Creates a new `Editor` instance with the specified editor type and binary path.
31    #[must_use]
32    pub fn new(editor_type: EditorKind, binary_path: PathBuf) -> Self {
33        Self {
34            editor_type,
35            binary_path,
36        }
37    }
38    /// Gets the full path of the editor binary based on the provided editor name.
39    pub(crate) fn get_full_path(editor_name: OsString) -> PathBuf {
40        match which::which(editor_name.clone()) {
41            Ok(path) => path,
42            Err(_) => PathBuf::from(editor_name), // Fallback to just the name but that's weird
43        }
44    }
45    /// Validates that the binary path exists and is executable.
46    /// Returns `Ok(())` if the binary is valid, or an `OpenEditorError` if it is not.
47    pub(crate) fn validate_executable(&self) -> Result<(), OpenEditorError> {
48        if !self.binary_path.exists() || !self.binary_path.is_file() {
49            return Err(OpenEditorError::EditorNotFound {
50                binary_path: self.binary_path.clone(),
51            });
52        }
53        #[cfg(unix)]
54        {
55            use std::os::unix::fs::PermissionsExt;
56            let metadata = std::fs::metadata(&self.binary_path).map_err(|e| {
57                OpenEditorError::EditorNotExecutable {
58                    binary_path: self.binary_path.clone(),
59                    error: Some(e),
60                }
61            })?;
62            let permissions = metadata.permissions();
63            if permissions.mode() & 0o111 == 0 {
64                return Err(OpenEditorError::EditorNotExecutable {
65                    binary_path: self.binary_path.clone(),
66                    error: None,
67                });
68            }
69        }
70
71        Ok(())
72    }
73}